Compare commits

..

184 Commits
0.35 ... 0.39

Author SHA1 Message Date
Karl Tauber
368fbcdeb0 release 0.39 2020-08-03 16:20:57 +02:00
Karl Tauber
30747b7776 UIScale: added system property "flatlaf.uiScale.enabled" (replaces "hidpi" property) to disable user scaling mode 2020-08-02 14:08:18 +02:00
Karl Tauber
4eb4ddf5d8 FlatTestFrame: do not use sun.java2d.uiScale for user scale factor 2020-08-02 11:43:46 +02:00
Karl Tauber
b1d24680b2 ToolTip: fixed truncated text in HTML formatted tooltip on HiDPI displays (issue #142) 2020-08-01 22:53:09 +02:00
Karl Tauber
ef38f3805e IntelliJ Themes: fixed text colors in ProgressBar (issue #138) 2020-08-01 00:31:20 +02:00
Karl Tauber
2f5ca20ca4 fixed compile error caused by previous checkin (issue #143) 2020-07-31 19:28:58 +02:00
Karl Tauber
f29d3d84d4 FileChooser: fixed too small text field when renaming a file/directory in Flat IntelliJ/Darcula themes (issue #143) 2020-07-31 19:17:49 +02:00
Karl Tauber
02132c5fcd MenuItem on macOS: removed plus characters from accelerator text and made modifier key order conform with macOS standard (issue #141) 2020-07-31 13:02:01 +02:00
Karl Tauber
7057e3c6ad IntelliJ Themes: added "Carbon" and "Cobalt 2" themes 2020-07-30 23:11:37 +02:00
Karl Tauber
a8f4c8e843 Demo: added combo box above themes list to show only light or dark themes 2020-07-30 19:41:56 +02:00
Karl Tauber
a2b6e66a13 CHANGELOG.md: split change log of last version into "New features" and "Fixed bugs" sections 2020-07-30 19:26:50 +02:00
Karl Tauber
e3b3cc2896 IntelliJ Themes: replaced "Solarized" themes with much better ones from 4lex4 2020-07-30 16:30:56 +02:00
Karl Tauber
a5b2c50f24 IntelliJ Themes:
- added "Arc Dark" and "Arc Dark - Orange" themes
- updated themes to newest versions (used IJThemesUpdater)
2020-07-30 15:00:31 +02:00
Karl Tauber
5ebdf64d30 ComboBox: fixed width of popup, which was too small if popup is wider than combo box and vertical scroll bar is visible (issue #137) 2020-07-30 13:30:50 +02:00
Karl Tauber
2640ab2e8b ComboBox: changed maximum row count of popup list to 15 (was 20) (issue #124) 2020-07-30 12:11:15 +02:00
Karl Tauber
e29436da04 Button: support specifying button border width 2020-07-28 23:51:02 +02:00
Karl Tauber
7b35325f9a Flat IntelliJ theme: use color functions for selected checkbox/radio button hover/pressed background 2020-07-28 22:14:08 +02:00
Karl Tauber
f2ab7fafcf ToolTip: do not show empty tooltip component if tooltip text is an empty string (issue #134) 2020-07-28 11:10:34 +02:00
Karl Tauber
e3cda9905a Table: allow disabling swapped behavior of Home/End and Ctrl+Home/End with Table.consistentHomeEndKeyBehavior=false (issue #95) 2020-07-27 17:55:31 +02:00
Karl Tauber
a8423f7741 ScrollBar: increased minimum thumb size on macOS and Linux to 18px and on Windows to 10px; also include ScrollBar.thumbInsets in minimum size calculation (issue #131) 2020-07-27 14:41:01 +02:00
Karl Tauber
5a9e620c17 Animator: added constructor that allows passing a runnable that is invoked at the end of the animation, which allows using lambdas in most cases 2020-07-25 10:53:06 +02:00
Karl Tauber
9f41ec3986 ScrollPane: support disabling smooth scrolling per component via client property "JScrollPane.smoothScrolling" 2020-07-25 10:27:06 +02:00
Karl Tauber
5a2c0672d4 Window decorations: avoid possible endless restore/maximize in WindowStateListener in case of behavior changes in Java (issue #129) 2020-07-23 10:43:24 +02:00
Karl Tauber
38d853b5b2 Window decorations: fixed maximized window bounds with Java 11.0.8 and 13.0.4, which has fixes backported from Java 15 (issue #129) 2020-07-22 23:23:46 +02:00
Karl Tauber
5166d4bb0f SystemInfo:
- renamed public fields from upper-case to mixed-case
- added public fields for osVersion and javaVersion
- fixed Mac -> MacOS
- added orLater to Mojave
2020-07-22 22:01:19 +02:00
Karl Tauber
2ffd5437a9 animated Laf changing added to flatlaf-extras, used in Demo 2020-07-22 12:56:42 +02:00
Karl Tauber
797830ff96 InternalFrame: title pane height was too small when iconify, maximize and close buttons are hidden (issue #132) 2020-07-21 18:23:57 +02:00
Karl Tauber
008ecabd21 animator and cubic bezier easing classes added (for future animations) (issue #66) 2020-07-21 17:53:53 +02:00
Karl Tauber
2cdcde8a5e Window decorations: fixed maximized window bounds when programmatically maximizing window before showing window (issue #129) 2020-07-18 14:21:19 +02:00
Karl Tauber
e7ec3988e2 Window decorations: fixed maximized window bounds when programmatically maximizing window (issue #129) 2020-07-17 00:08:21 +02:00
Karl Tauber
093dd9f3ef README.md: added jAlbum to list of projects that use FlatLaf 2020-07-15 19:37:47 +02:00
Karl Tauber
b491202ec7 UIDefaultsLoader: fixed NPE on syntax error in color function 2020-07-15 11:57:40 +02:00
Karl Tauber
8603ca827e Theme Editor: auto-completion improvements:
- include reference completions in value completions (if already entered text is empty)
- order completions: 1st color functions, 2nd @refs, 3rd $refs
- exclude platform specific keys from reference provider
2020-07-11 13:35:59 +02:00
Karl Tauber
6b148a59da Theme Editor: added auto-completion for "amount" and "options" parameters of color functions 2020-07-11 13:01:59 +02:00
Karl Tauber
de6d45fee6 Theme Editor: fixed NPE in FlatCompletionProvider.isAutoActivateOkay() 2020-07-10 16:10:43 +02:00
Karl Tauber
65e2071937 CHANGELOG.md: added regression note 2020-07-10 15:58:04 +02:00
Karl Tauber
8a6242d9ea release 0.38 2020-07-10 15:45:35 +02:00
Karl Tauber
82294b68eb CheckBox: fixed colors in light IntelliJ themes (issue #126) 2020-07-10 15:35:02 +02:00
Karl Tauber
c232de1996 Window decorations: fixed cursor of components (issue #125) 2020-07-10 11:39:17 +02:00
Karl Tauber
dc18c8178d Theme Editor: fixed typo 2020-07-10 10:54:09 +02:00
Karl Tauber
6662714277 Theme Editor: auto-completion improved:
- reference completion shows all keys defined in current and base files
- support auto-activate for value provider
- do not auto-complete single choices
2020-07-10 10:33:10 +02:00
Karl Tauber
c404a0d1a9 Theme Editor:
- auto-activate key completion on any letter
- special completion provider for references
2020-07-08 19:15:52 +02:00
Karl Tauber
990da2b412 Theme Editor:
- auto-activate completion popup when '$' is pressed
- use keys auto-complete in value if value contains '$'
- more fine grained detection what completion provider should be used
2020-07-08 18:07:37 +02:00
Karl Tauber
1b974379c8 UIDefaultsLoader: check for endless recursion in resolveValue() 2020-07-08 17:57:40 +02:00
Karl Tauber
835faf9773 Theme Editor: auto-completion depending on caret position (none for comments, keys and values); added color functions 2020-07-08 14:29:11 +02:00
Karl Tauber
80deecb73e Theme Editor: close input streams when reading base properties files 2020-07-08 10:59:40 +02:00
Karl Tauber
64328ab9cc UIDefaultsLoader: trim value in resolveValue() to ignore spaces at the end of references/variables 2020-07-08 10:47:36 +02:00
Karl Tauber
eafad942e7 Theme Editor: added basic auto-complete for keys 2020-07-08 10:43:24 +02:00
Karl Tauber
eb5a3168b9 Theme Editor: support loading/resolving base properties 2020-07-07 21:42:10 +02:00
Karl Tauber
ac8225d8fb Theme Editor: support saving file; added inspector 2020-07-07 16:17:31 +02:00
Karl Tauber
6f71e4ada0 Theme Editor: use deferred properties loading 2020-07-07 14:21:31 +02:00
Karl Tauber
7ed90cddf8 Theme Editor: support color preview for color functions
UIDefaultsLoader: made some private methods package private and return parsed valued type
2020-07-07 14:03:39 +02:00
Karl Tauber
283ba83cef Window decorations: use derived color for RootPane.inactiveBorderColor in FlatLightLaf.properties to be consistent with FlatDarkLaf.properties 2020-07-06 15:47:44 +02:00
Karl Tauber
468c66e842 Window decorations: hide window icon if InternalFrame.icon is null or its width or height is zero 2020-07-06 14:45:52 +02:00
Karl Tauber
f22862b0a4 InternalFrame: use default icon in internal frames (issue #122) 2020-07-06 14:41:17 +02:00
Karl Tauber
9e731cb67a Tree: fixed cell editor border 2020-07-06 12:01:53 +02:00
Karl Tauber
7f911b61a2 Window decorations: no longer honor minimum size of frames on resizing window, but still do for dialogs 2020-07-06 11:30:49 +02:00
Karl Tauber
cace4a9bfd Window decorations: center title if menu bar is embedded 2020-07-05 11:01:58 +02:00
Karl Tauber
0992e97a1a README.md: added Mapton, Pseudo Assembler IDE, Sound Analysis and RemoteLight to list of projects that use FlatLaf 2020-07-04 23:47:47 +02:00
Karl Tauber
eee101f279 Merge remote-tracking branch 'uwemock/patch-1' 2020-07-04 21:46:08 +02:00
Karl Tauber
4b9f204951 Tree: fixed selection colors when used as cell renderer in another component (e.g. in Rhino JavaScript debugger) (issue #120) 2020-07-04 17:51:13 +02:00
Karl Tauber
019804407b Window decorations: hide window border if window is maximized 2020-07-01 12:11:53 +02:00
Karl Tauber
65b54ced7a Window decorations: made most fields protected for extending/subclassing 2020-07-01 10:49:18 +02:00
Karl Tauber
a308114b2f Window decorations:
- use window border color from UI defaults
- support "active" and "inactive" window border colors
- better window border colors for dark themes
2020-07-01 10:37:08 +02:00
Karl Tauber
41da023bdd hide focus indicator when the containing window became inactive 2020-07-01 00:21:22 +02:00
Karl Tauber
19fcb6a82c refactored some anonymous classes into nested classes for easier extending/subclassing 2020-06-30 17:02:48 +02:00
Karl Tauber
14c837ad05 release 0.37 2020-06-29 17:03:06 +02:00
Karl Tauber
9da634e225 CHANGELOG.md: added custom window decorations 2020-06-29 17:00:28 +02:00
Karl Tauber
0d91116e62 Merge branch 'origin/custom-window-decorations' into master
# Conflicts:
#	flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
2020-06-29 15:59:38 +02:00
Karl Tauber
a31a8a03c1 Window decorations: made most classes/methods public/protected for extending/subclassing 2020-06-29 15:45:26 +02:00
Karl Tauber
e8d5210606 Window decorations: use default icon if no icon set on window 2020-06-29 12:20:57 +02:00
Karl Tauber
7b11e29122 Button and ToggleButton: support making buttons square (issue #118) 2020-06-29 10:49:07 +02:00
Karl Tauber
df7f693cf4 Demo: new window icon 2020-06-28 23:59:28 +02:00
Karl Tauber
14ddc2f629 Demo: use window decorations by default and added "Options > Window decorations" to menu 2020-06-28 12:12:58 +02:00
Karl Tauber
6669d0e59d Window decorations: support enabling/disabling embedding menu bar via UI value at runtime 2020-06-28 11:34:30 +02:00
Karl Tauber
8d80176a79 IntelliJ Themes: fixed menu bar and menu item margins in all Material UI Lite themes 2020-06-28 00:28:02 +02:00
Karl Tauber
e1dc302592 IntelliJ Themes: updated themes to newest versions (used IJThemesUpdater) 2020-06-27 23:09:00 +02:00
Karl Tauber
84dbe39185 FileChooser: increase maximum row count of directory combobox popup list to 20 (was 8) 2020-06-27 22:49:22 +02:00
Karl Tauber
4af2c31dab Eclipse code formatter: insert space in casts 2020-06-27 22:26:49 +02:00
Karl Tauber
332f05b6e1 Window decorations: allow enabling/disabling custom window decorations via system properties "flatlaf.useWindowDecorations", "flatlaf.useJetBrainsCustomDecorations" and "flatlaf.menuBarEmbedded" (all boolean) 2020-06-27 19:36:36 +02:00
Karl Tauber
8b4786ad18 added class FlatSystemProperties to define/document own system properties used in FlatLaf 2020-06-27 17:57:59 +02:00
Karl Tauber
7e8aaffb92 Window decorations:
- double-click on icon closes window
- after switching LaF is was not possible to move window when running in JetBrains Runtime
2020-06-26 10:49:49 +02:00
Karl Tauber
7720d42584 Window decorations: reworked/fixed initialization when running in JetBrains Runtime 2020-06-26 00:22:28 +02:00
Karl Tauber
293b76f04b Window decorations: FlatWindowDecorationsTest: added "undecorated" checkbox 2020-06-25 17:55:42 +02:00
Karl Tauber
a1b0c0bbd4 ComboBox: increase maximum row count of popup list to 20 (was 8) 2020-06-25 17:00:10 +02:00
Karl Tauber
46d3204bc3 MenuBar:
- use derived colors for menu bar hover
- use derived colors for menu item selected background
- top-level JMenu now uses foreground color from parent JMenuBar

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

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

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

also show current font in bottom control bar

(issue #105)
2020-05-21 12:24:40 +02:00
Karl Tauber
c900c9cc82 reduce derived colors calculations 2020-05-20 14:49:56 +02:00
Karl Tauber
87b73f26f5 replaced FlatUIUtils.setColor() with deriveColor() for more flexibility 2020-05-20 14:24:22 +02:00
uwemock
221a18c119 Update README.md
Added my project that uses FlatLaf
2020-05-20 07:20:42 +02:00
Karl Tauber
be529655d6 UIDefaultsLoader: on color functions use "autoInverse" option by default if "derived" option is set 2020-05-20 00:40:05 +02:00
Karl Tauber
2a0403a988 support CompoundBorder as component border with FlatBorder on the outside 2020-05-19 23:24:00 +02:00
Karl Tauber
815e23b930 ScrollBar: make hoverTrack and hoverThumb fields protected to allow subclasses implement own painting (issue #103) 2020-05-19 19:24:48 +02:00
Karl Tauber
f1c08e7769 FlatTestFrame: added Substance Business skin for testing light UI 2020-05-19 18:42:22 +02:00
Karl Tauber
571f028ca3 FlatComponentsTest: moved components that change something into own "control" panel 2020-05-19 11:31:52 +02:00
Karl Tauber
16d51fe6b4 ComboBox and Spinner: move arrow slightly to the left if round borders are used on the component 2020-05-18 23:26:34 +02:00
211 changed files with 19256 additions and 2257 deletions

View File

@@ -1,6 +1,108 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 0.39
#### New features
- Animated theme change (see [FlatLaf Extras](flatlaf-extras)). Used in Demo.
- Demo: Added combo box above themes list to show only light or dark themes.
- IntelliJ Themes:
- Added "Arc Dark", "Arc Dark - Orange", "Carbon" and "Cobalt 2" themes.
- Replaced "Solarized" themes with much better ones from 4lex4.
- Updated "Arc", "One Dark" and "Vuesion" themes.
- ScrollPane: Enable/disable smooth scrolling per component if client property
"JScrollPane.smoothScrolling" is set to a `Boolean` on `JScrollPane`.
- ScrollBar: Increased minimum thumb size on macOS and Linux from 8 to 18
pixels. On Windows, it is now 10 pixels. (issue #131)
- Button: Support specifying button border width.
- ComboBox: Changed maximum row count of popup list to 15 (was 20). Set UI value
`ComboBox.maximumRowCount` to any integer to use a different value.
#### Fixed bugs
- Custom window decorations: Fixed maximized window bounds when programmatically
maximizing window. E.g. restoring window state at startup. (issue #129)
- InternalFrame: Title pane height was too small when iconify, maximize and
close buttons are hidden. (issue #132)
- ToolTip: Do not show empty tooltip component if tooltip text is an empty
string. (issue #134)
- ToolTip: Fixed truncated text in HTML formatted tooltip on HiDPI displays.
(issue #142)
- ComboBox: Fixed width of popup, which was too small if popup is wider than
combo box and vertical scroll bar is visible. (issue #137)
- MenuItem on macOS: Removed plus characters from accelerator text and made
modifier key order conform with macOS standard. (issue #141)
- FileChooser: Fixed too small text field when renaming a file/directory in Flat
IntelliJ/Darcula themes. (issue #143)
- IntelliJ Themes: Fixed text colors in ProgressBar. (issue #138)
## 0.38
- Hide focus indicator when window is inactive.
- Custom window decorations: Improved/fixed window border color in dark themes.
- Custom window decorations: Hide window border if window is maximized.
- Custom window decorations: Center title if menu bar is embedded.
- Custom window decorations: Cursor of components (e.g. TextField) was not
changed. (issue #125)
- CheckBox: Fixed colors in light IntelliJ themes. (issue #126; regression in
0.37)
- InternalFrame: Use default icon in internal frames. (issue #122)
## 0.37
- Custom window decorations (Windows 10 only; PR #108; issues #47 and #82)
support:
- dark window title panes
- embedding menu bar into window title pane
- native Windows 10 borders and behavior when running in
[JetBrains Runtime 11](https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime)
or later (the JRE that IntelliJ IDEA uses)
- CheckBox and RadioButton: Support changing selected icon style from outline to
filled (as in FlatLaf IntelliJ theme) with `UIManager.put(
"CheckBox.icon.style", "filled" );`.
- Button and ToggleButton: Support disabled background color (use UI values
`Button.disabledBackground` and `ToggleButton.disabledBackground`). (issue
#112)
- Button and ToggleButton: Support making buttons square (set client property
`JButton.squareSize` to `true`). (issue #118)
- ScrollBar: Support pressed track, thumb and button colors (use UI values
`ScrollBar.pressedTrackColor`, `ScrollBar.pressedThumbColor` and
`ScrollBar.pressedButtonBackground`). (issue #115)
- ComboBox: Support changing arrow button style (set UI value
`ComboBox.buttonStyle` to `auto` (default), `button` or `none`). (issue #114)
- Spinner: Support changing arrows button style (set UI value
`Spinner.buttonStyle` to `button` (default) or `none`).
- TableHeader: Support top/bottom/left positioned sort arrow when using
[Glazed Lists](https://github.com/glazedlists/glazedlists). (issue #113)
- Button, CheckBox, RadioButton and ToggleButton: Do not paint focus indicator
if `AbstractButton.isFocusPainted()` returns `false`.
- ComboBox: Increase maximum row count of popup list to 20 (was 8). Set UI value
`ComboBox.maximumRowCount` to any integer to use a different value.
- Fixed/improved vertical position of text when scaled on HiDPI screens on
Windows.
- IntelliJ Themes: Updated Gradianto Themes.
- IntelliJ Themes: Fixed menu bar and menu item margins in all Material UI Lite
themes.
## 0.36
- ScrollBar: Made styling more flexible by supporting insets and arc for track
and thumb. (issue #103)
- ScrollBar: Use round thumb on macOS and Linux to make it look similar to
native platform scroll bars. (issue #103)
- ComboBox: Minimum width is now 72 pixels (was ~50 for non-editable and ~130
for editable comboboxes).
- ComboBox: Support custom borders in combobox editors. (issue #102)
- Button: Support non-square icon-only buttons. (issue #110)
- Ubuntu Linux: Fixed poorly rendered font. (issue #105)
- macOS Catalina: Use Helvetica Neue font.
- `FlatInspector` added (see [FlatLaf Extras](flatlaf-extras)).
## 0.35 ## 0.35
- Added drop shadows to popup menus, combobox popups, tooltips and internal - Added drop shadows to popup menus, combobox popups, tooltips and internal

View File

@@ -82,6 +82,7 @@ Projects using FlatLaf
- [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5 - [jclasslib bytecode viewer](https://github.com/ingokegel/jclasslib) 5.5
- [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3 - [KeyStore Explorer](https://keystore-explorer.org/) 5.4.3
- [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases) - [OWASP Zed Attack Proxy (ZAP)](https://www.zaproxy.org/) (in weekly releases)
- ![New](images/new.svg) [jAlbum](https://jalbum.net/) 21 (commercial)
- [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (commercial) - [XMLmind XML Editor](https://www.xmlmind.com/xmleditor/) 9.3 (commercial)
- [Total Validator](https://www.totalvalidator.com/) 15 (commercial) - [Total Validator](https://www.totalvalidator.com/) 15 (commercial)
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org)
@@ -98,8 +99,15 @@ Projects using FlatLaf
[mendelson AS2](https://mendelson-e-c.com/as2/), [mendelson AS2](https://mendelson-e-c.com/as2/),
[AS4](https://mendelson-e-c.com/as4/) and [AS4](https://mendelson-e-c.com/as4/) and
[OFTP2](https://mendelson-e-c.com/oftp2) (commercial) [OFTP2](https://mendelson-e-c.com/oftp2) (commercial)
- [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.1.6 - [MeteoInfo](https://github.com/meteoinfo/MeteoInfo) 2.2
- [lsfusion platform](https://github.com/lsfusion/platform) - [lsfusion platform](https://github.com/lsfusion/platform)
- [Jes - Die Java-EÜR](https://www.jes-eur.de)
- [Mapton](https://mapton.org/) 2.0
([source code](https://github.com/trixon/mapton)) based on NetBeans platform
- [Pseudo Assembler IDE](https://github.com/tomasz-herman/PseudoAssemblerIDE)
- [Sound Analysis](https://github.com/tomasz-herman/SoundAnalysis)
- [RemoteLight](https://github.com/Drumber/RemoteLight) - Multifunctional LED
Control Software
- and more... - and more...

View File

@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
val releaseVersion = "0.35" val releaseVersion = "0.39"
val developmentVersion = "0.36-SNAPSHOT" val developmentVersion = "0.40-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion

View File

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

View File

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

View File

@@ -38,6 +38,7 @@ tasks {
javadoc { javadoc {
options { options {
this as StandardJavadocDocletOptions this as StandardJavadocDocletOptions
use( true )
tags = listOf( "uiDefault", "clientProperty" ) tags = listOf( "uiDefault", "clientProperty" )
addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" ) addStringOption( "Xdoclint:all,-missing", "-Xdoclint:all,-missing" )
} }

View File

@@ -96,10 +96,19 @@ public interface FlatClientProperties
*/ */
String SELECTED_STATE_INDETERMINATE = "indeterminate"; String SELECTED_STATE_INDETERMINATE = "indeterminate";
/**
* Specifies whether the button preferred size will be made square (quadratically).
* <p>
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String SQUARE_SIZE = "JButton.squareSize";
/** /**
* Specifies minimum width of a component. * Specifies minimum width of a component.
* <p> * <p>
* <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton} and {@link javax.swing.text.JTextComponent}<br> * <strong>Component</strong> {@link javax.swing.JButton}, {@link javax.swing.JToggleButton},
* {@link javax.swing.JComboBox}, {@link javax.swing.JSpinner} and {@link javax.swing.text.JTextComponent}<br>
* <strong>Value type</strong> {@link java.lang.Integer}<br> * <strong>Value type</strong> {@link java.lang.Integer}<br>
*/ */
String MINIMUM_WIDTH = "JComponent.minimumWidth"; String MINIMUM_WIDTH = "JComponent.minimumWidth";
@@ -174,6 +183,15 @@ public interface FlatClientProperties
*/ */
String PROGRESS_BAR_SQUARE = "JProgressBar.square"; String PROGRESS_BAR_SQUARE = "JProgressBar.square";
/**
* Specifies whether the menu bar is embedded into the title pane if custom
* window decorations are enabled. Default is {@code true}.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/** /**
* Specifies whether the decrease/increase arrow buttons of a scrollbar are shown. * Specifies whether the decrease/increase arrow buttons of a scrollbar are shown.
* <p> * <p>
@@ -182,6 +200,14 @@ public interface FlatClientProperties
*/ */
String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons"; String SCROLL_BAR_SHOW_BUTTONS = "JScrollBar.showButtons";
/**
* Specifies whether the scroll pane uses smooth scrolling.
* <p>
* <strong>Component</strong> {{@link javax.swing.JScrollPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*/
String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling";
/** /**
* Specifies whether separators are shown between tabs. * Specifies whether separators are shown between tabs.
* <p> * <p>

View File

@@ -22,9 +22,11 @@ import javax.swing.KeyStroke;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIDefaults.LazyValue; import javax.swing.UIDefaults.LazyValue;
import javax.swing.UIManager;
import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.InputMapUIResource;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import static javax.swing.text.DefaultEditorKit.*; import static javax.swing.text.DefaultEditorKit.*;
import java.util.function.BooleanSupplier;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -35,7 +37,7 @@ class FlatInputMaps
initBasicInputMaps( defaults ); initBasicInputMaps( defaults );
initTextComponentInputMaps( defaults ); initTextComponentInputMaps( defaults );
if( SystemInfo.IS_MAC ) if( SystemInfo.isMacOS )
initMacInputMaps( defaults ); initMacInputMaps( defaults );
} }
@@ -59,7 +61,7 @@ class FlatInputMaps
mac( "alt KP_DOWN", null ), "togglePopup" mac( "alt KP_DOWN", null ), "togglePopup"
); );
if( !SystemInfo.IS_MAC ) { if( !SystemInfo.isMacOS ) {
modifyInputMap( defaults, "FileChooser.ancestorInputMap", modifyInputMap( defaults, "FileChooser.ancestorInputMap",
"F2", "editFileName", "F2", "editFileName",
"BACK_SPACE", "Go Up" "BACK_SPACE", "Go Up"
@@ -81,8 +83,11 @@ class FlatInputMaps
"shift ctrl TAB", "navigatePrevious" "shift ctrl TAB", "navigatePrevious"
); );
modifyInputMap( defaults, "Table.ancestorInputMap", // swap Home/End with Ctrl+Home/End to make it consistent with List and Tree
// swap to make it consistent with List and Tree modifyInputMap( () -> {
return UIManager.getBoolean( "Table.consistentHomeEndKeyBehavior" );
},
defaults, "Table.ancestorInputMap",
"HOME", "selectFirstRow", "HOME", "selectFirstRow",
"END", "selectLastRow", "END", "selectLastRow",
"shift HOME", "selectFirstRowExtendSelection", "shift HOME", "selectFirstRowExtendSelection",
@@ -93,7 +98,7 @@ class FlatInputMaps
mac( "shift ctrl END", null ), "selectLastColumnExtendSelection" mac( "shift ctrl END", null ), "selectLastColumnExtendSelection"
); );
if( !SystemInfo.IS_MAC ) { if( !SystemInfo.isMacOS ) {
modifyInputMap( defaults, "Tree.focusInputMap", modifyInputMap( defaults, "Tree.focusInputMap",
"ADD", "expand", "ADD", "expand",
"SUBTRACT", "collapse" "SUBTRACT", "collapse"
@@ -164,7 +169,7 @@ class FlatInputMaps
"control shift O", "toggle-componentOrientation", // DefaultEditorKit.toggleComponentOrientation "control shift O", "toggle-componentOrientation", // DefaultEditorKit.toggleComponentOrientation
}; };
Object[] macCommonTextComponentBindings = SystemInfo.IS_MAC ? new Object[] { Object[] macCommonTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret one character (without selecting text) // move caret one character (without selecting text)
"ctrl B", backwardAction, "ctrl B", backwardAction,
"ctrl F", forwardAction, "ctrl F", forwardAction,
@@ -211,7 +216,7 @@ class FlatInputMaps
"ENTER", JTextField.notifyAction, "ENTER", JTextField.notifyAction,
}; };
Object[] macSingleLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] { Object[] macSingleLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret to line begin/end (without selecting text) // move caret to line begin/end (without selecting text)
"UP", beginLineAction, "UP", beginLineAction,
"DOWN", endLineAction, "DOWN", endLineAction,
@@ -289,7 +294,7 @@ class FlatInputMaps
mac( "ctrl SPACE", "meta SPACE" ), "activate-link-action", mac( "ctrl SPACE", "meta SPACE" ), "activate-link-action",
}; };
Object[] macMultiLineTextComponentBindings = SystemInfo.IS_MAC ? new Object[] { Object[] macMultiLineTextComponentBindings = SystemInfo.isMacOS ? new Object[] {
// move caret one line (without selecting text) // move caret one line (without selecting text)
"ctrl N", downAction, "ctrl N", downAction,
"ctrl P", upAction, "ctrl P", upAction,
@@ -574,12 +579,16 @@ class FlatInputMaps
} }
private static void modifyInputMap( UIDefaults defaults, String key, Object... bindings ) { private static void modifyInputMap( UIDefaults defaults, String key, Object... bindings ) {
// Note: not using `defaults.get(key)` here because this would resolve the lazy value modifyInputMap( null, defaults, key, bindings );
defaults.put( key, new LazyModifyInputMap( defaults.remove( key ), bindings ) ); }
private static void modifyInputMap( BooleanSupplier condition, UIDefaults defaults, String key, Object... bindings ) {
// Note: not using `defaults.get(key)` here because this would resolve a lazy value
defaults.put( key, new LazyModifyInputMap( condition, defaults.remove( key ), bindings ) );
} }
private static <T> T mac( T value, T macValue ) { private static <T> T mac( T value, T macValue ) {
return SystemInfo.IS_MAC ? macValue : value; return SystemInfo.isMacOS ? macValue : value;
} }
//---- class LazyInputMapEx ----------------------------------------------- //---- class LazyInputMapEx -----------------------------------------------
@@ -614,10 +623,12 @@ class FlatInputMaps
private static class LazyModifyInputMap private static class LazyModifyInputMap
implements LazyValue implements LazyValue
{ {
private final BooleanSupplier condition;
private final Object baseInputMap; private final Object baseInputMap;
private final Object[] bindings; private final Object[] bindings;
LazyModifyInputMap( Object baseInputMap, Object[] bindings ) { LazyModifyInputMap( BooleanSupplier condition, Object baseInputMap, Object[] bindings ) {
this.condition = condition;
this.baseInputMap = baseInputMap; this.baseInputMap = baseInputMap;
this.bindings = bindings; this.bindings = bindings;
} }
@@ -629,6 +640,9 @@ class FlatInputMaps
? (InputMap) ((LazyValue)baseInputMap).createValue( table ) ? (InputMap) ((LazyValue)baseInputMap).createValue( table )
: (InputMap) baseInputMap; : (InputMap) baseInputMap;
if( condition != null && !condition.getAsBoolean() )
return inputMap;
// modify input map (replace or remove) // modify input map (replace or remove)
for( int i = 0; i < bindings.length; i += 2 ) { for( int i = 0; i < bindings.length; i += 2 ) {
KeyStroke keyStroke = KeyStroke.getKeyStroke( (String) bindings[i] ); KeyStroke keyStroke = KeyStroke.getKeyStroke( (String) bindings[i] );

View File

@@ -43,6 +43,8 @@ import javax.swing.BorderFactory;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
@@ -57,6 +59,7 @@ 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.FlatPopupFactory; import com.formdev.flatlaf.ui.FlatPopupFactory;
import com.formdev.flatlaf.ui.JBRCustomDecorations;
import com.formdev.flatlaf.util.GrayFilter; import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -74,6 +77,7 @@ public abstract class FlatLaf
private static final String DESKTOPFONTHINTS = "awt.font.desktophints"; private static final String DESKTOPFONTHINTS = "awt.font.desktophints";
private String desktopPropertyName; private String desktopPropertyName;
private String desktopPropertyName2;
private PropertyChangeListener desktopPropertyListener; private PropertyChangeListener desktopPropertyListener;
private static boolean aquaLoaded; private static boolean aquaLoaded;
@@ -84,6 +88,9 @@ public abstract class FlatLaf
private Consumer<UIDefaults> postInitialization; private Consumer<UIDefaults> postInitialization;
private Boolean oldFrameWindowDecorated;
private Boolean oldDialogWindowDecorated;
public static boolean install( LookAndFeel newLookAndFeel ) { public static boolean install( LookAndFeel newLookAndFeel ) {
try { try {
UIManager.setLookAndFeel( newLookAndFeel ); UIManager.setLookAndFeel( newLookAndFeel );
@@ -109,6 +116,45 @@ public abstract class FlatLaf
public abstract boolean isDark(); public abstract boolean isDark();
/**
* Checks whether the current look and feel is dark.
*/
public static boolean isLafDark() {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
return lookAndFeel instanceof FlatLaf && ((FlatLaf)lookAndFeel).isDark();
}
/**
* Returns whether FlatLaf supports custom window decorations.
* This depends on the operating system and on the used Java runtime.
* <p>
* To use custom window decorations in your application, enable them with
* following code (before creating any frames or dialogs). Then custom window
* decorations are only enabled if this method returns {@code true}.
* <pre>
* JFrame.setDefaultLookAndFeelDecorated( true );
* JDialog.setDefaultLookAndFeelDecorated( true );
* </pre>
* <p>
* Returns {@code true} on Windows 10, {@code false} otherwise.
* <p>
* Return also {@code false} if running on Windows 10 in
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
* and JBR supports custom window decorations. In this case, JBR custom decorations
* are enabled if {@link JFrame#isDefaultLookAndFeelDecorated()} or
* {@link JDialog#isDefaultLookAndFeelDecorated()} return {@code true}.
*/
@Override
public boolean getSupportsWindowDecorations() {
if( SystemInfo.isJetBrainsJVM_11_orLater &&
SystemInfo.isWindows_10_orLater &&
JBRCustomDecorations.isSupported() )
return false;
return SystemInfo.isWindows_10_orLater;
}
@Override @Override
public boolean isNativeLookAndFeel() { public boolean isNativeLookAndFeel() {
return false; return false;
@@ -141,7 +187,7 @@ public abstract class FlatLaf
@Override @Override
public void initialize() { public void initialize() {
if( SystemInfo.IS_MAC ) if( SystemInfo.isMacOS )
initializeAqua(); initializeAqua();
super.initialize(); super.initialize();
@@ -155,20 +201,24 @@ public abstract class FlatLaf
mnemonicHandler.install(); mnemonicHandler.install();
// listen to desktop property changes to update UI if system font or scaling changes // listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.IS_WINDOWS ) { if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling: // Windows 10 allows increasing font size independent of scaling:
// Settings > Ease of Access > Display > Make text bigger (100% - 225%) // Settings > Ease of Access > Display > Make text bigger (100% - 225%)
desktopPropertyName = "win.messagebox.font"; desktopPropertyName = "win.messagebox.font";
} else if( SystemInfo.IS_LINUX ) { } else if( SystemInfo.isLinux ) {
// Linux/Gnome allows changing font in "Tweaks" app
desktopPropertyName = "gnome.Gtk/FontName";
// Linux/Gnome allows extra scaling and larger text: // Linux/Gnome allows extra scaling and larger text:
// Settings > Devices > Displays > Scale (100% or 200%) // Settings > Devices > Displays > Scale (100% or 200%)
// Settings > Universal access > Large Text (off or on, 125%) // Settings > Universal access > Large Text (off or on, 125%)
desktopPropertyName = "gnome.Xft/DPI"; // "Tweaks" app > Fonts > Scaling Factor (0,5 - 3)
desktopPropertyName2 = "gnome.Xft/DPI";
} }
if( desktopPropertyName != null ) { if( desktopPropertyName != null ) {
desktopPropertyListener = e -> { desktopPropertyListener = e -> {
String propertyName = e.getPropertyName(); String propertyName = e.getPropertyName();
if( desktopPropertyName.equals( propertyName ) ) if( desktopPropertyName.equals( propertyName ) || propertyName.equals( desktopPropertyName2 ) )
reSetLookAndFeel(); reSetLookAndFeel();
else if( DESKTOPFONTHINTS.equals( propertyName ) ) { else if( DESKTOPFONTHINTS.equals( propertyName ) ) {
if( UIManager.getLookAndFeel() instanceof FlatLaf ) { if( UIManager.getLookAndFeel() instanceof FlatLaf ) {
@@ -179,6 +229,8 @@ public abstract class FlatLaf
}; };
Toolkit toolkit = Toolkit.getDefaultToolkit(); Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener ); toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
if( desktopPropertyName2 != null )
toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
toolkit.addPropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener ); toolkit.addPropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
} }
@@ -193,6 +245,16 @@ public abstract class FlatLaf
String.format( "a { color: #%06x; }", linkColor.getRGB() & 0xffffff ) ); String.format( "a { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
} }
}; };
// enable/disable window decorations, but only if system property is either
// "true" or "false"; in other cases it is not changed
Boolean useWindowDecorations = FlatSystemProperties.getBooleanStrict( FlatSystemProperties.USE_WINDOW_DECORATIONS, null );
if( useWindowDecorations != null ) {
oldFrameWindowDecorated = JFrame.isDefaultLookAndFeelDecorated();
oldDialogWindowDecorated = JDialog.isDefaultLookAndFeelDecorated();
JFrame.setDefaultLookAndFeelDecorated( useWindowDecorations );
JDialog.setDefaultLookAndFeelDecorated( useWindowDecorations );
}
} }
@Override @Override
@@ -201,8 +263,11 @@ public abstract class FlatLaf
if( desktopPropertyListener != null ) { if( desktopPropertyListener != null ) {
Toolkit toolkit = Toolkit.getDefaultToolkit(); Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.removePropertyChangeListener( desktopPropertyName, desktopPropertyListener ); toolkit.removePropertyChangeListener( desktopPropertyName, desktopPropertyListener );
if( desktopPropertyName2 != null )
toolkit.removePropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
toolkit.removePropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener ); toolkit.removePropertyChangeListener( DESKTOPFONTHINTS, desktopPropertyListener );
desktopPropertyName = null; desktopPropertyName = null;
desktopPropertyName2 = null;
desktopPropertyListener = null; desktopPropertyListener = null;
} }
@@ -222,6 +287,14 @@ public abstract class FlatLaf
new HTMLEditorKit().getStyleSheet().addRule( "a { color: blue; }" ); new HTMLEditorKit().getStyleSheet().addRule( "a { color: blue; }" );
postInitialization = null; postInitialization = null;
// restore enable/disable window decorations
if( oldFrameWindowDecorated != null ) {
JFrame.setDefaultLookAndFeelDecorated( oldFrameWindowDecorated );
JDialog.setDefaultLookAndFeelDecorated( oldDialogWindowDecorated );
oldFrameWindowDecorated = null;
oldDialogWindowDecorated = null;
}
super.uninitialize(); super.uninitialize();
} }
@@ -242,7 +315,7 @@ public abstract class FlatLaf
String aquaLafClassName = "com.apple.laf.AquaLookAndFeel"; String aquaLafClassName = "com.apple.laf.AquaLookAndFeel";
BasicLookAndFeel aquaLaf; BasicLookAndFeel aquaLaf;
try { try {
if( SystemInfo.IS_JAVA_9_OR_LATER ) { if( SystemInfo.isJava_9_orLater ) {
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
@@ -274,6 +347,7 @@ public abstract class FlatLaf
// initialize some defaults (for overriding) that are used in UI delegates, // initialize some defaults (for overriding) that are used in UI delegates,
// but are not set in BasicLookAndFeel // but are not set in BasicLookAndFeel
putDefaults( defaults, defaults.getColor( "control" ), putDefaults( defaults, defaults.getColor( "control" ),
"Button.disabledBackground",
"EditorPane.disabledBackground", "EditorPane.disabledBackground",
"EditorPane.inactiveBackground", "EditorPane.inactiveBackground",
"FormattedTextField.disabledBackground", "FormattedTextField.disabledBackground",
@@ -283,7 +357,8 @@ public abstract class FlatLaf
"TextArea.inactiveBackground", "TextArea.inactiveBackground",
"TextField.disabledBackground", "TextField.disabledBackground",
"TextPane.disabledBackground", "TextPane.disabledBackground",
"TextPane.inactiveBackground" ); "TextPane.inactiveBackground",
"ToggleButton.disabledBackground" );
putDefaults( defaults, defaults.getColor( "textInactiveText" ), putDefaults( defaults, defaults.getColor( "textInactiveText" ),
"Button.disabledText", "Button.disabledText",
"CheckBox.disabledText", "CheckBox.disabledText",
@@ -316,7 +391,7 @@ public abstract class FlatLaf
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults ); UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults );
// use Aqua MenuBarUI if Mac screen menubar is enabled // use Aqua MenuBarUI if Mac screen menubar is enabled
if( SystemInfo.IS_MAC && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) { if( SystemInfo.isMacOS && Boolean.getBoolean( "apple.laf.useScreenMenuBar" ) ) {
defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" ); defaults.put( "MenuBarUI", "com.apple.laf.AquaMenuBarUI" );
// add defaults necessary for AquaMenuBarUI // add defaults necessary for AquaMenuBarUI
@@ -360,14 +435,17 @@ public abstract class FlatLaf
private void initFonts( UIDefaults defaults ) { private void initFonts( UIDefaults defaults ) {
FontUIResource uiFont = null; FontUIResource uiFont = null;
if( SystemInfo.IS_WINDOWS ) { if( SystemInfo.isWindows ) {
Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" ); Font winFont = (Font) Toolkit.getDefaultToolkit().getDesktopProperty( "win.messagebox.font" );
if( winFont != null ) if( winFont != null )
uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() ); uiFont = createCompositeFont( winFont.getFamily(), winFont.getStyle(), winFont.getSize() );
} else if( SystemInfo.IS_MAC ) { } else if( SystemInfo.isMacOS ) {
String fontName; String fontName;
if( SystemInfo.IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER ) { if( SystemInfo.isMacOS_10_15_Catalina_orLater ) {
// use Helvetica Neue font
fontName = "Helvetica Neue";
} else if( SystemInfo.isMacOS_10_11_ElCapitan_orLater ) {
// use San Francisco Text font // use San Francisco Text font
fontName = ".SF NS Text"; fontName = ".SF NS Text";
} else { } else {
@@ -377,7 +455,7 @@ public abstract class FlatLaf
uiFont = createCompositeFont( fontName, Font.PLAIN, 13 ); uiFont = createCompositeFont( fontName, Font.PLAIN, 13 );
} else if( SystemInfo.IS_LINUX ) { } else if( SystemInfo.isLinux ) {
Font font = LinuxFontPolicy.getFont(); Font font = LinuxFontPolicy.getFont();
uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font ); uiFont = (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
} }
@@ -409,7 +487,7 @@ public abstract class FlatLaf
// using StyleContext.getFont() here because it uses // using StyleContext.getFont() here because it uses
// sun.font.FontUtilities.getCompositeFontUIResource() // sun.font.FontUtilities.getCompositeFontUIResource()
// and creates a composite font that is able to display all Unicode characters // and creates a composite font that is able to display all Unicode characters
Font font = new StyleContext().getFont( family, style, size ); Font font = StyleContext.getDefaultStyleContext().getFont( family, style, size );
return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font ); return (font instanceof FontUIResource) ? (FontUIResource) font : new FontUIResource( font );
} }
@@ -437,7 +515,7 @@ public abstract class FlatLaf
} }
private void putAATextInfo( UIDefaults defaults ) { private void putAATextInfo( UIDefaults defaults ) {
if( SystemInfo.IS_JAVA_9_OR_LATER ) { if( SystemInfo.isJava_9_orLater ) {
Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS ); Object desktopHints = Toolkit.getDefaultToolkit().getDesktopProperty( DESKTOPFONTHINTS );
if( desktopHints instanceof Map ) { if( desktopHints instanceof Map ) {
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import javax.swing.JDialog;
import javax.swing.JFrame;
/**
* Defines/documents own system properties used in FlatLaf.
*
* @author Karl Tauber
*/
public interface FlatSystemProperties
{
/**
* Specifies a custom scale factor used to scale the UI.
* <p>
* If Java runtime scales (Java 9 or later), this scale factor is applied on top
* of the Java system scale factor. Java 8 does not scale and this scale factor
* replaces the user scale factor that FlatLaf computes based on the font.
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
* which has the same syntax as this one.
* <p>
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
*/
String UI_SCALE = "flatlaf.uiScale";
/**
* Specifies whether user scaling mode is enabled.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled";
/**
* Specifies whether Ubuntu font should be used on Ubuntu Linux.
* By default, if not running in a JetBrains Runtime, the Liberation Sans font
* is used because there are rendering issues (in Java) with Ubuntu fonts.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code false}
*/
String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont";
/**
* Specifies whether custom look and feel window decorations should be used
* when creating {@code JFrame} or {@code JDialog}.
* <p>
* If this system property is set, FlatLaf invokes {@link JFrame#setDefaultLookAndFeelDecorated(boolean)}
* and {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} on LaF initialization.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> none
*/
String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations";
/**
* Specifies whether JetBrains Runtime custom window decorations should be used
* when creating {@code JFrame} or {@code JDialog}.
* Requires that the application runs in a
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime</a>
* (based on OpenJDK).
* <p>
* Setting this to {@code true} forces using JetBrains Runtime custom window decorations
* even if they are not enabled by the application.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations";
/**
* Specifies whether menubar is embedded into custom window decorations.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded";
/**
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
* <p>
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
* <strong>Default</strong> {@code true}
*/
String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection";
/**
* Checks whether a system property is set and returns {@code true} if its value
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
* If the system property is not set, {@code defaultValue} is returned.
*/
static boolean getBoolean( String key, boolean defaultValue ) {
String value = System.getProperty( key );
return (value != null) ? Boolean.parseBoolean( value ) : defaultValue;
}
/**
* Checks whether a system property is set and returns {@code Boolean.TRUE} if its value
* is {@code "true"} (case-insensitive) or returns {@code Boolean.FALSE} if its value
* is {@code "false"} (case-insensitive). Otherwise {@code defaultValue} is returned.
*/
static Boolean getBooleanStrict( String key, Boolean defaultValue ) {
String value = System.getProperty( key );
if( "true".equalsIgnoreCase( value ) )
return Boolean.TRUE;
if( "false".equalsIgnoreCase( value ) )
return Boolean.FALSE;
return defaultValue;
}
}

View File

@@ -147,6 +147,15 @@ public class IntelliJTheme
applyColorPalette( defaults ); applyColorPalette( defaults );
applyCheckBoxColors( defaults ); applyCheckBoxColors( defaults );
// copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() )
defaults.put( e.getKey(), defaults.get( e.getValue() ) );
// IDEA does not paint button background if disabled, but FlatLaf does
Object panelBackground = defaults.get( "Panel.background" );
defaults.put( "Button.disabledBackground", panelBackground );
defaults.put( "ToggleButton.disabledBackground", panelBackground );
// IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground // IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
Object helpButtonBackground = defaults.get( "Button.startBackground" ); Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" ); Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
@@ -156,7 +165,7 @@ public class IntelliJTheme
helpButtonBorderColor = defaults.get( "Button.borderColor" ); helpButtonBorderColor = defaults.get( "Button.borderColor" );
defaults.put( "HelpButton.background", helpButtonBackground ); defaults.put( "HelpButton.background", helpButtonBackground );
defaults.put( "HelpButton.borderColor", helpButtonBorderColor ); defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
defaults.put( "HelpButton.disabledBackground", defaults.get( "Panel.background" ) ); defaults.put( "HelpButton.disabledBackground", panelBackground );
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) ); defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) ); defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) ); defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
@@ -407,6 +416,10 @@ public class IntelliJTheme
String newKey = checkboxKeyMapping.get( key ); String newKey = checkboxKeyMapping.get( key );
if( newKey != null ) { if( newKey != null ) {
String checkBoxIconPrefix = "CheckBox.icon.";
if( !dark && newKey.startsWith( checkBoxIconPrefix ) )
newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) );
ColorUIResource color = toColor( (String) value ); ColorUIResource color = toColor( (String) value );
if( color != null ) { if( color != null ) {
defaults.put( newKey, color ); defaults.put( newKey, color );
@@ -439,17 +452,24 @@ public class IntelliJTheme
// remove hover and pressed colors // remove hover and pressed colors
if( checkboxModified ) { if( checkboxModified ) {
defaults.remove( "CheckBox.icon.focusWidth" );
defaults.remove( "CheckBox.icon.hoverBorderColor" ); defaults.remove( "CheckBox.icon.hoverBorderColor" );
defaults.remove( "CheckBox.icon.focusedBackground" ); defaults.remove( "CheckBox.icon.focusedBackground" );
defaults.remove( "CheckBox.icon.hoverBackground" ); defaults.remove( "CheckBox.icon.hoverBackground" );
defaults.remove( "CheckBox.icon.pressedBackground" ); defaults.remove( "CheckBox.icon.pressedBackground" );
defaults.remove( "CheckBox.icon.selectedFocusedBackground" );
defaults.remove( "CheckBox.icon.selectedHoverBackground" ); defaults.remove( "CheckBox.icon.selectedHoverBackground" );
defaults.remove( "CheckBox.icon.selectedPressedBackground" ); defaults.remove( "CheckBox.icon.selectedPressedBackground" );
}
// copy values defaults.remove( "CheckBox.icon[filled].focusWidth" );
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) defaults.remove( "CheckBox.icon[filled].hoverBorderColor" );
defaults.put( e.getKey(), defaults.get( e.getValue() ) ); defaults.remove( "CheckBox.icon[filled].focusedBackground" );
defaults.remove( "CheckBox.icon[filled].hoverBackground" );
defaults.remove( "CheckBox.icon[filled].pressedBackground" );
defaults.remove( "CheckBox.icon[filled].selectedFocusedBackground" );
defaults.remove( "CheckBox.icon[filled].selectedHoverBackground" );
defaults.remove( "CheckBox.icon[filled].selectedPressedBackground" );
}
} }
private static Map<String, String> uiKeyMapping = new HashMap<>(); private static Map<String, String> uiKeyMapping = new HashMap<>();
@@ -476,11 +496,26 @@ public class IntelliJTheme
// Link // Link
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" ); uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
// Menu
uiKeyMapping.put( "Menu.border", "Menu.margin" );
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
// IDEA uses List.selectionBackground also for menu selection
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "MenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
// ProgressBar // ProgressBar
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" ); uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" ); uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
// ScrollBar // ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" ); uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
@@ -492,6 +527,10 @@ public class IntelliJTheme
// Slider // Slider
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite) uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
// TitlePane
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() ) for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
uiKeyInverseMapping.put( e.getValue(), e.getKey() ); uiKeyInverseMapping.put( e.getValue(), e.getKey() );
@@ -506,7 +545,7 @@ public class IntelliJTheme
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" ); checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" ); checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" ); checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusedColor" ); checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusColor" );
checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" ); checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" );
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" ); checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" ); checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );

View File

@@ -39,7 +39,7 @@ import com.formdev.flatlaf.util.UIScale;
class LinuxFontPolicy class LinuxFontPolicy
{ {
static Font getFont() { static Font getFont() {
return SystemInfo.IS_KDE ? getKDEFont() : getGnomeFont(); return SystemInfo.isKDE ? getKDEFont() : getGnomeFont();
} }
/** /**
@@ -74,6 +74,13 @@ class LinuxFontPolicy
family = family.isEmpty() ? word : (family + ' ' + word); family = family.isEmpty() ? word : (family + ' ' + word);
} }
// Ubuntu font is rendered poorly (except if running in JetBrains VM)
// --> use Liberation Sans font
if( family.startsWith( "Ubuntu" ) &&
!SystemInfo.isJetBrainsJVM &&
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_UBUNTU_FONT, false ) )
family = "Liberation Sans";
// scale font size // scale font size
double dsize = size * getGnomeFontScale(); double dsize = size * getGnomeFontScale();
size = (int) (dsize + 0.5); size = (int) (dsize + 0.5);

View File

@@ -71,13 +71,13 @@ class MnemonicHandler
@Override @Override
public boolean postProcessKeyEvent( KeyEvent e ) { public boolean postProcessKeyEvent( KeyEvent e ) {
int keyCode = e.getKeyCode(); int keyCode = e.getKeyCode();
if( SystemInfo.IS_MAC ) { if( SystemInfo.isMacOS ) {
// Ctrl+Alt keys must be pressed on Mac // Ctrl+Alt keys must be pressed on Mac
if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT ) if( keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT )
showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() ); showMnemonics( shouldShowMnemonics( e ) && e.isControlDown() && e.isAltDown(), e.getComponent() );
} else { } else {
// Alt key must be pressed on Windows and Linux // Alt key must be pressed on Windows and Linux
if( SystemInfo.IS_WINDOWS ) if( SystemInfo.isWindows )
return processKeyEventOnWindows( e ); return processKeyEventOnWindows( e );
if( keyCode == KeyEvent.VK_ALT ) if( keyCode == KeyEvent.VK_ALT )

View File

@@ -144,9 +144,9 @@ class UIDefaultsLoader
// handle platform specific properties // handle platform specific properties
String platformPrefix = String platformPrefix =
SystemInfo.IS_WINDOWS ? "[win]" : SystemInfo.isWindows ? "[win]" :
SystemInfo.IS_MAC ? "[mac]" : SystemInfo.isMacOS ? "[mac]" :
SystemInfo.IS_LINUX ? "[linux]" : "[unknown]"; SystemInfo.isLinux ? "[linux]" : "[unknown]";
for( String key : platformSpecificKeys ) { for( String key : platformSpecificKeys ) {
Object value = properties.remove( key ); Object value = properties.remove( key );
if( key.startsWith( platformPrefix ) ) if( key.startsWith( platformPrefix ) )
@@ -154,8 +154,11 @@ class UIDefaultsLoader
} }
} }
Function<String, String> propertiesGetter = key -> {
return properties.getProperty( key );
};
Function<String, String> resolver = value -> { Function<String, String> resolver = value -> {
return resolveValue( properties, value ); return resolveValue( value, propertiesGetter );
}; };
// get globals, which override all other defaults that end with same suffix // get globals, which override all other defaults that end with same suffix
@@ -165,9 +168,10 @@ class UIDefaultsLoader
if( !key.startsWith( GLOBAL_PREFIX ) ) if( !key.startsWith( GLOBAL_PREFIX ) )
continue; continue;
String value = resolveValue( properties, (String) e.getValue() ); String value = resolveValue( (String) e.getValue(), propertiesGetter );
try { try {
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver, addonClassLoaders ) ); globals.put( key.substring( GLOBAL_PREFIX.length() ),
parseValue( key, value, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( Level.SEVERE, key, value, ex ); logParseError( Level.SEVERE, key, value, ex );
} }
@@ -190,9 +194,9 @@ class UIDefaultsLoader
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) ) if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
continue; continue;
String value = resolveValue( properties, (String) e.getValue() ); String value = resolveValue( (String) e.getValue(), propertiesGetter );
try { try {
defaults.put( key, parseValue( key, value, resolver, addonClassLoaders ) ); defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( Level.SEVERE, key, value, ex ); logParseError( Level.SEVERE, key, value, ex );
} }
@@ -206,7 +210,10 @@ class UIDefaultsLoader
FlatLaf.LOG.log( level, "FlatLaf: Failed to parse: '" + key + '=' + value + '\'', ex ); FlatLaf.LOG.log( level, "FlatLaf: Failed to parse: '" + key + '=' + value + '\'', ex );
} }
private static String resolveValue( Properties properties, String value ) { static String resolveValue( String value, Function<String, String> propertiesGetter ) {
value = value.trim();
String value0 = value;
if( value.startsWith( PROPERTY_PREFIX ) ) if( value.startsWith( PROPERTY_PREFIX ) )
value = value.substring( PROPERTY_PREFIX.length() ); value = value.substring( PROPERTY_PREFIX.length() );
else if( !value.startsWith( VARIABLE_PREFIX ) ) else if( !value.startsWith( VARIABLE_PREFIX ) )
@@ -218,7 +225,7 @@ class UIDefaultsLoader
optional = true; optional = true;
} }
String newValue = properties.getProperty( value ); String newValue = propertiesGetter.apply( value );
if( newValue == null ) { if( newValue == null ) {
if( optional ) if( optional )
return "null"; return "null";
@@ -226,29 +233,40 @@ class UIDefaultsLoader
throw new IllegalArgumentException( "variable or property '" + value + "' not found" ); throw new IllegalArgumentException( "variable or property '" + value + "' not found" );
} }
return resolveValue( properties, newValue ); if( newValue.equals( value0 ) )
throw new IllegalArgumentException( "endless recursion in variable or property '" + value + "'" );
return resolveValue( newValue, propertiesGetter );
} }
private enum ValueType { UNKNOWN, STRING, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER } SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
private static ValueType[] tempResultValueType = new ValueType[1];
static Object parseValue( String key, String value ) { static Object parseValue( String key, String value ) {
return parseValue( key, value, v -> v, Collections.emptyList() ); return parseValue( key, value, null, v -> v, Collections.emptyList() );
} }
private static Object parseValue( String key, String value, Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) { static Object parseValue( String key, String value, ValueType[] resultValueType,
Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
{
if( resultValueType == null )
resultValueType = tempResultValueType;
value = value.trim(); value = value.trim();
// null, false, true // null, false, true
switch( value ) { switch( value ) {
case "null": return null; case "null": resultValueType[0] = ValueType.NULL; return null;
case "false": return false; case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
case "true": return true; case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
} }
// check for function "lazy" // check for function "lazy"
// Syntax: lazy(uiKey) // Syntax: lazy(uiKey)
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) { if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
resultValueType[0] = ValueType.LAZY;
String uiKey = value.substring( 5, value.length() - 1 ).trim(); String uiKey = value.substring( 5, value.length() - 1 ).trim();
return (LazyValue) t -> { return (LazyValue) t -> {
return lazyUIManagerGet( uiKey ); return lazyUIManagerGet( uiKey );
@@ -301,6 +319,8 @@ class UIDefaultsLoader
valueType = ValueType.GRAYFILTER; valueType = ValueType.GRAYFILTER;
} }
resultValueType[0] = valueType;
// parse value // parse value
switch( valueType ) { switch( valueType ) {
case STRING: return value; case STRING: return value;
@@ -323,20 +343,27 @@ class UIDefaultsLoader
default: default:
// colors // colors
Object color = parseColorOrFunction( value, resolver, false ); Object color = parseColorOrFunction( value, resolver, false );
if( color != null ) if( color != null ) {
resultValueType[0] = ValueType.COLOR;
return color; return color;
}
// integer // integer
Integer integer = parseInteger( value, false ); Integer integer = parseInteger( value, false );
if( integer != null ) if( integer != null ) {
resultValueType[0] = ValueType.INTEGER;
return integer; return integer;
}
// float // float
Float f = parseFloat( value, false ); Float f = parseFloat( value, false );
if( f != null ) if( f != null ) {
resultValueType[0] = ValueType.FLOAT;
return f; return f;
}
// string // string
resultValueType[0] = ValueType.STRING;
return value; return value;
} }
} }
@@ -572,7 +599,7 @@ class UIDefaultsLoader
* saturate(color,amount[,options]) or desaturate(color,amount[,options]) * saturate(color,amount[,options]) or desaturate(color,amount[,options])
* - color: a color (e.g. #f00) or a color function * - color: a color (e.g. #f00) or a color function
* - amount: percentage 0-100% * - amount: percentage 0-100%
* - options: [relative] [autoInverse] [lazy] [derived] * - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
*/ */
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase, private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List<String> params, Function<String, String> resolver, boolean reportError ) List<String> params, Function<String, String> resolver, boolean reportError )
@@ -590,6 +617,10 @@ class UIDefaultsLoader
autoInverse = options.contains( "autoInverse" ); autoInverse = options.contains( "autoInverse" );
lazy = options.contains( "lazy" ); lazy = options.contains( "lazy" );
derived = options.contains( "derived" ); derived = options.contains( "derived" );
// use autoInverse by default for derived colors, except if noAutoInverse is set
if( derived && !options.contains( "noAutoInverse" ) )
autoInverse = true;
} }
// create function // create function
@@ -606,15 +637,19 @@ class UIDefaultsLoader
} }
// parse base color // parse base color
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolver.apply( colorStr ), resolver, reportError ); String resolvedColorStr = resolver.apply( colorStr );
ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError );
if( baseColor == null )
return null;
// apply this function to base color // apply this function to base color
Color newColor = ColorFunctions.applyFunctions( baseColor, function ); Color newColor = ColorFunctions.applyFunctions( baseColor, function );
if( derived ) { if( derived ) {
ColorFunction[] functions; ColorFunction[] functions;
if( baseColor instanceof DerivedColor ) { if( baseColor instanceof DerivedColor && resolvedColorStr == colorStr ) {
// if the base color is also derived, join the color functions // if the base color is also derived, join the color functions
// but only if base color function is specified directly in this function
ColorFunction[] baseFunctions = ((DerivedColor)baseColor).getFunctions(); ColorFunction[] baseFunctions = ((DerivedColor)baseColor).getFunctions();
functions = new ColorFunction[baseFunctions.length + 1]; functions = new ColorFunction[baseFunctions.length + 1];
System.arraycopy( baseFunctions, 0, functions, 0, baseFunctions.length ); System.arraycopy( baseFunctions, 0, functions, 0, baseFunctions.length );

View File

@@ -36,25 +36,28 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* is painted outside of the icon bounds. Make sure that the checkbox * is painted outside of the icon bounds. Make sure that the checkbox
* has margins, which are equal or greater than focusWidth. * has margins, which are equal or greater than focusWidth.
* *
* @uiDefault CheckBox.icon.style String optional; "outline"/null (default) or "filled"
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.focusColor Color * @uiDefault Component.focusColor Color
* @uiDefault CheckBox.icon.focusedColor Color optional; defaults to Component.focusColor * @uiDefault CheckBox.icon.focusWidth int optional; defaults to Component.focusWidth
* @uiDefault CheckBox.icon.focusColor Color optional; defaults to Component.focusColor
* @uiDefault CheckBox.icon.borderColor Color * @uiDefault CheckBox.icon.borderColor Color
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.selectedBorderColor Color
* @uiDefault CheckBox.icon.focusedBorderColor Color
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
* @uiDefault CheckBox.icon.background Color * @uiDefault CheckBox.icon.background Color
* @uiDefault CheckBox.icon.disabledBackground Color * @uiDefault CheckBox.icon.selectedBorderColor Color
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.selectedBackground Color * @uiDefault CheckBox.icon.selectedBackground Color
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
* @uiDefault CheckBox.icon.checkmarkColor Color * @uiDefault CheckBox.icon.checkmarkColor Color
* @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.disabledBackground Color
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color * @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.icon.focusedBorderColor Color
* @uiDefault CheckBox.icon.focusedBackground Color optional
* @uiDefault CheckBox.icon.selectedFocusedBorderColor Color optional
* @uiDefault CheckBox.icon.selectedFocusedBackground Color optional
* @uiDefault CheckBox.icon.hoverBorderColor Color optional
* @uiDefault CheckBox.icon.hoverBackground Color optional
* @uiDefault CheckBox.icon.selectedHoverBackground Color optional
* @uiDefault CheckBox.icon.pressedBackground Color optional
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional
* @uiDefault CheckBox.arc int * @uiDefault CheckBox.arc int
* *
* @author Karl Tauber * @author Karl Tauber
@@ -62,27 +65,62 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatCheckBoxIcon public class FlatCheckBoxIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public final int focusWidth = UIManager.getInt( "Component.focusWidth" ); protected final String style = UIManager.getString( "CheckBox.icon.style" );
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusedColor", public final int focusWidth = getUIInt( "CheckBox.icon.focusWidth",
UIManager.getInt( "Component.focusWidth" ), style );
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor",
UIManager.getColor( "Component.focusColor" ) ); UIManager.getColor( "Component.focusColor" ) );
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 ); protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" ); // enabled
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" ); protected final Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
protected final Color selectedBorderColor = UIManager.getColor( "CheckBox.icon.selectedBorderColor" ); protected final Color background = getUIColor( "CheckBox.icon.background", style );
protected final Color focusedBorderColor = UIManager.getColor( "CheckBox.icon.focusedBorderColor" ); protected final Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
protected final Color hoverBorderColor = UIManager.getColor( "CheckBox.icon.hoverBorderColor" ); protected final Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
protected final Color selectedFocusedBorderColor = UIManager.getColor( "CheckBox.icon.selectedFocusedBorderColor" ); protected final Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
protected final Color background = UIManager.getColor( "CheckBox.icon.background" );
protected final Color disabledBackground = UIManager.getColor( "CheckBox.icon.disabledBackground" ); // disabled
protected final Color focusedBackground = UIManager.getColor( "CheckBox.icon.focusedBackground" ); protected final Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
protected final Color hoverBackground = UIManager.getColor( "CheckBox.icon.hoverBackground" ); protected final Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
protected final Color pressedBackground = UIManager.getColor( "CheckBox.icon.pressedBackground" ); protected final Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
protected final Color selectedBackground = UIManager.getColor( "CheckBox.icon.selectedBackground" );
protected final Color selectedHoverBackground = UIManager.getColor( "CheckBox.icon.selectedHoverBackground" ); // focused
protected final Color selectedPressedBackground = UIManager.getColor( "CheckBox.icon.selectedPressedBackground" ); protected final Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
protected final Color checkmarkColor = UIManager.getColor( "CheckBox.icon.checkmarkColor" ); protected final Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
protected final Color disabledCheckmarkColor = UIManager.getColor( "CheckBox.icon.disabledCheckmarkColor" ); protected final Color selectedFocusedBorderColor = getUIColor( "CheckBox.icon.selectedFocusedBorderColor", style );
protected final Color selectedFocusedBackground = getUIColor( "CheckBox.icon.selectedFocusedBackground", style );
protected final Color selectedFocusedCheckmarkColor = getUIColor( "CheckBox.icon.selectedFocusedCheckmarkColor", style );
// hover
protected final Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
protected final Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
protected final Color selectedHoverBackground = getUIColor( "CheckBox.icon.selectedHoverBackground", style );
// pressed
protected final Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
protected final Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style );
protected static Color getUIColor( String key, String style ) {
if( style != null ) {
Color color = UIManager.getColor( styleKey( key, style ) );
if( color != null )
return color;
}
return UIManager.getColor( key );
}
protected static int getUIInt( String key, int defaultValue, String style ) {
if( style != null ) {
Object value = UIManager.get( styleKey( key, style ) );
if( value instanceof Integer )
return (Integer) value;
}
return FlatUIUtils.getUIInt( key, defaultValue );
}
private static String styleKey( String key, String style ) {
return key.replace( ".icon.", ".icon[" + style + "]." );
}
static final int ICON_SIZE = 15; static final int ICON_SIZE = 15;
@@ -94,9 +132,10 @@ public class FlatCheckBoxIcon
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE ); boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected()); boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
boolean isFocused = FlatUIUtils.isPermanentFocusOwner( c );
// paint focused border // paint focused border
if( FlatUIUtils.isPermanentFocusOwner( c ) && focusWidth > 0 ) { if( isFocused && focusWidth > 0 && FlatButtonUI.isFocusPainted( c ) ) {
g2.setColor( focusColor ); g2.setColor( focusColor );
paintFocusBorder( g2 ); paintFocusBorder( g2 );
} }
@@ -111,18 +150,22 @@ public class FlatCheckBoxIcon
paintBorder( g2 ); paintBorder( g2 );
// paint background // paint background
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c, g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
selected ? selectedBackground : background, selected ? selectedBackground : background,
disabledBackground, disabledBackground,
focusedBackground, (selected && selectedFocusedBackground != null) ? selectedFocusedBackground : focusedBackground,
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground, (selected && selectedHoverBackground != null) ? selectedHoverBackground : hoverBackground,
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ), (selected && selectedPressedBackground != null) ? selectedPressedBackground : pressedBackground ),
background ); background ) );
paintBackground( g2 ); paintBackground( g2 );
// paint checkmark // paint checkmark
if( selected || indeterminate ) { if( selected || indeterminate ) {
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor ); g2.setColor( c.isEnabled()
? ((selected && isFocused && selectedFocusedCheckmarkColor != null)
? selectedFocusedCheckmarkColor
: checkmarkColor)
: disabledCheckmarkColor );
if( indeterminate ) if( indeterminate )
paintIndeterminate( g2 ); paintIndeterminate( g2 );
else else

View File

@@ -67,14 +67,14 @@ public class FlatCheckBoxMenuItemIcon
g2.draw( path ); g2.draw( path );
} }
private Color getCheckmarkColor( Component c ) { protected Color getCheckmarkColor( Component c ) {
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() ) if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() )
return selectionForeground; return selectionForeground;
return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor; return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor;
} }
private boolean isUnderlineSelection() { protected boolean isUnderlineSelection() {
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime // not storing value of "MenuItem.selectionType" in class to allow changing at runtime
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
} }

View File

@@ -85,7 +85,7 @@ public class FlatHelpButtonIcon
boolean focused = FlatUIUtils.isPermanentFocusOwner( c ); boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
// paint focused border // paint focused border
if( focused ) { if( focused && FlatButtonUI.isFocusPainted( c ) ) {
g2.setColor( focusColor ); g2.setColor( focusColor );
g2.fill( new Ellipse2D.Float( 0.5f, 0.5f, iconSize - 1, iconSize - 1 ) ); g2.fill( new Ellipse2D.Float( 0.5f, 0.5f, iconSize - 1, iconSize - 1 ) );
} }
@@ -100,12 +100,12 @@ public class FlatHelpButtonIcon
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) ); g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
// paint background // paint background
FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c, g2.setColor( FlatUIUtils.deriveColor( FlatButtonUI.buttonStateColor( c,
background, background,
disabledBackground, disabledBackground,
focusedBackground, focusedBackground,
hoverBackground, hoverBackground,
pressedBackground ), background ); pressedBackground ), background ) );
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) ); g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
// paint question mark // paint question mark

View File

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

View File

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

View File

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

View File

@@ -65,14 +65,14 @@ public class FlatMenuArrowIcon
} }
} }
private Color getArrowColor( Component c ) { protected Color getArrowColor( Component c ) {
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() ) if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
return selectionForeground; return selectionForeground;
return c.isEnabled() ? arrowColor : disabledArrowColor; return c.isEnabled() ? arrowColor : disabledArrowColor;
} }
private boolean isUnderlineSelection() { protected boolean isUnderlineSelection() {
// not storing value of "MenuItem.selectionType" in class to allow changing at runtime // not storing value of "MenuItem.selectionType" in class to allow changing at runtime
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
} }

View File

@@ -18,7 +18,6 @@ package com.formdev.flatlaf.icons;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* Icon for {@link javax.swing.JRadioButton}. * Icon for {@link javax.swing.JRadioButton}.
@@ -34,7 +33,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatRadioButtonIcon public class FlatRadioButtonIcon
extends FlatCheckBoxIcon extends FlatCheckBoxIcon
{ {
protected final int centerDiameter = FlatUIUtils.getUIInt( "RadioButton.icon.centerDiameter", 8 ); protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
@Override @Override
protected void paintFocusBorder( Graphics2D g2 ) { protected void paintFocusBorder( Graphics2D g2 ) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.BasicStroke; import java.awt.BasicStroke;
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.Graphics2D; import java.awt.Graphics2D;
@@ -26,6 +27,7 @@ import java.awt.Shape;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.JComponent;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicArrowButton;
@@ -45,15 +47,23 @@ public class FlatArrowButton
private final Color disabledForeground; private final Color disabledForeground;
private final Color hoverForeground; private final Color hoverForeground;
private final Color hoverBackground; private final Color hoverBackground;
private final Color pressedBackground;
private int arrowWidth = DEFAULT_ARROW_WIDTH; private int arrowWidth = DEFAULT_ARROW_WIDTH;
private int xOffset = 0; private int xOffset = 0;
private int yOffset = 0; private int yOffset = 0;
private boolean hover; private boolean hover;
private boolean pressed;
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground, public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground ) Color hoverForeground, Color hoverBackground )
{
this( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, null );
}
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground, Color pressedBackground )
{ {
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE ); super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
@@ -62,11 +72,12 @@ public class FlatArrowButton
this.disabledForeground = disabledForeground; this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground; this.hoverForeground = hoverForeground;
this.hoverBackground = hoverBackground; this.hoverBackground = hoverBackground;
this.pressedBackground = pressedBackground;
setOpaque( false ); setOpaque( false );
setBorder( null ); setBorder( null );
if( hoverForeground != null || hoverBackground != null ) { if( hoverForeground != null || hoverBackground != null || pressedBackground != null ) {
addMouseListener( new MouseAdapter() { addMouseListener( new MouseAdapter() {
@Override @Override
public void mouseEntered( MouseEvent e ) { public void mouseEntered( MouseEvent e ) {
@@ -79,6 +90,18 @@ public class FlatArrowButton
hover = false; hover = false;
repaint(); repaint();
} }
@Override
public void mousePressed( MouseEvent e ) {
pressed = true;
repaint();
}
@Override
public void mouseReleased( MouseEvent e ) {
pressed = false;
repaint();
}
} ); } );
} }
} }
@@ -95,6 +118,10 @@ public class FlatArrowButton
return hover; return hover;
} }
protected boolean isPressed() {
return pressed;
}
public int getXOffset() { public int getXOffset() {
return xOffset; return xOffset;
} }
@@ -111,6 +138,10 @@ public class FlatArrowButton
this.yOffset = yOffset; this.yOffset = yOffset;
} }
protected Color deriveBackground( Color background ) {
return background;
}
@Override @Override
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
return scale( super.getPreferredSize() ); return scale( super.getPreferredSize() );
@@ -130,33 +161,54 @@ public class FlatArrowButton
int height = getHeight(); int height = getHeight();
boolean enabled = isEnabled(); boolean enabled = isEnabled();
// paint hover background // paint hover or pressed background
if( enabled && isHover() && hoverBackground != null ) { if( enabled ) {
g.setColor( hoverBackground ); Color background = (pressedBackground != null && isPressed())
g.fillRect( 0, 0, width, height ); ? deriveBackground( pressedBackground )
: ((hoverBackground != null && isHover())
? deriveBackground( hoverBackground )
: null);
if( background != null ) {
g.setColor( background );
g.fillRect( 0, 0, width, height );
}
} }
int direction = getDirection(); int direction = getDirection();
boolean vert = (direction == NORTH || direction == SOUTH); boolean vert = (direction == NORTH || direction == SOUTH);
// compute width/height
int w = scale( arrowWidth + (chevron ? 0 : 1) ); int w = scale( arrowWidth + (chevron ? 0 : 1) );
int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) ); int h = scale( (arrowWidth / 2) + (chevron ? 0 : 1) );
// rotate width/height
int rw = vert ? w : h; int rw = vert ? w : h;
int rh = vert ? h : w; int rh = vert ? h : w;
// chevron lines end 1px outside of width/height
if( chevron ) {
// add 1px to width/height for position calculation only
rw++;
rh++;
}
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) ); int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) ); int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
// optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane) // move arrow for round borders
if( x + rw >= width && x > 0 ) Container parent = getParent();
x--; if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
if( y + rh >= height && y > 0 ) x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
y--;
// paint arrow // paint arrow
g.setColor( enabled g.setColor( enabled
? (isHover() && hoverForeground != null ? hoverForeground : foreground) ? (isHover() && hoverForeground != null ? hoverForeground : foreground)
: disabledForeground ); : disabledForeground );
g.translate( x, y ); g.translate( x, y );
/*debug
debugPaint( g2, vert, rw, rh );
debug*/
Shape arrowShape = createArrowShape( direction, chevron, w, h ); Shape arrowShape = createArrowShape( direction, chevron, w, h );
if( chevron ) { if( chevron ) {
g2.setStroke( new BasicStroke( scale( 1f ) ) ); g2.setStroke( new BasicStroke( scale( 1f ) ) );
@@ -177,4 +229,22 @@ public class FlatArrowButton
default: return new Path2D.Float(); default: return new Path2D.Float();
} }
} }
/*debug
private void debugPaint( Graphics g, boolean vert, int w, int h ) {
Color oldColor = g.getColor();
g.setColor( Color.red );
g.drawRect( 0, 0, w - 1, h - 1 );
int xy1 = -2;
int xy2 = h + 1;
for( int i = 0; i < 20; i++ ) {
g.drawRect( vert ? 0 : xy1, vert ? xy1 : 0, 0, 0 );
g.drawRect( vert ? 0 : xy2, vert ? xy2 : 0, 0, 0 );
xy1 -= 2;
xy2 += 2;
}
g.setColor( oldColor );
}
debug*/
} }

View File

@@ -43,24 +43,24 @@ import com.formdev.flatlaf.util.DerivedColor;
* Border for various components (e.g. {@link javax.swing.JTextField}). * Border for various components (e.g. {@link javax.swing.JTextField}).
* *
* There is empty space around the component border, if Component.focusWidth is greater than zero, * There is empty space around the component border, if Component.focusWidth is greater than zero,
* which is used to paint focus border. * which is used to paint outer focus border.
* *
* Because there is empty space (if focus border is not painted), * Because there is empty space (if outer focus border is not painted),
* UI delegates that use this border (or subclasses) must invoke * UI delegates that use this border (or subclasses) must invoke
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly. * {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.innerFocusWidth int or float * @uiDefault Component.innerFocusWidth int or float
* @uiDefault Component.focusColor Color * @uiDefault Component.focusColor Color
* @uiDefault Component.borderColor Color * @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color * @uiDefault Component.disabledBorderColor Color
* @uiDefault Component.focusedBorderColor Color * @uiDefault Component.focusedBorderColor Color
* *
* @uiDefault Component.error.borderColor Color * @uiDefault Component.error.borderColor Color
* @uiDefault Component.error.focusedBorderColor Color * @uiDefault Component.error.focusedBorderColor Color
* @uiDefault Component.warning.borderColor Color * @uiDefault Component.warning.borderColor Color
* @uiDefault Component.warning.focusedBorderColor Color * @uiDefault Component.warning.focusedBorderColor Color
* @uiDefault Component.custom.borderColor Color * @uiDefault Component.custom.borderColor Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -87,22 +87,24 @@ public class FlatBorder
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
boolean isCellEditor = isTableCellEditor( c ); boolean isCellEditor = isCellEditor( c );
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) ); float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
float borderWidth = scale( (float) getBorderWidth( c ) ); float borderWidth = scale( (float) getBorderWidth( c ) );
float arc = isCellEditor ? 0 : scale( (float) getArc( c ) ); float arc = isCellEditor ? 0 : scale( (float) getArc( c ) );
Color outlineColor = getOutlineColor( c ); Color outlineColor = getOutlineColor( c );
// paint outer border
if( outlineColor != null || isFocused( c ) ) { if( outlineColor != null || isFocused( c ) ) {
float innerFocusWidth = !(c instanceof JScrollPane) float innerWidth = !isCellEditor && !(c instanceof JScrollPane)
? (outlineColor != null ? innerOutlineWidth : this.innerFocusWidth) ? (outlineColor != null ? innerOutlineWidth : innerFocusWidth)
: 0; : 0;
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) ); g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height, focusWidth, FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height,
scale( (float) getLineWidth( c ) ) + scale( innerFocusWidth ), arc ); focusWidth, borderWidth + scale( innerWidth ), arc );
} }
// paint border
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) ); g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc ); FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
} finally { } finally {
@@ -110,6 +112,10 @@ public class FlatBorder
} }
} }
/**
* Returns the outline color of the component border specified in client property
* {@link FlatClientProperties#OUTLINE}.
*/
protected Color getOutlineColor( Component c ) { protected Color getOutlineColor( Component c ) {
if( !(c instanceof JComponent) ) if( !(c instanceof JComponent) )
return null; return null;
@@ -178,6 +184,9 @@ public class FlatBorder
Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent(); Component editorComponent = ((JComboBox<?>)c).getEditor().getEditorComponent();
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false; return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
} else if( c instanceof JSpinner ) { } else if( c instanceof JSpinner ) {
if( FlatUIUtils.isPermanentFocusOwner( c ) )
return true;
JComponent editor = ((JSpinner)c).getEditor(); JComponent editor = ((JSpinner)c).getEditor();
if( editor instanceof JSpinner.DefaultEditor ) { if( editor instanceof JSpinner.DefaultEditor ) {
JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField(); JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField();
@@ -189,13 +198,13 @@ public class FlatBorder
return FlatUIUtils.isPermanentFocusOwner( c ); return FlatUIUtils.isPermanentFocusOwner( c );
} }
protected boolean isTableCellEditor( Component c ) { protected boolean isCellEditor( Component c ) {
return FlatUIUtils.isTableCellEditor( c ); return FlatUIUtils.isCellEditor( c );
} }
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
boolean isCellEditor = isTableCellEditor( c ); boolean isCellEditor = isCellEditor( c );
float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) ); float focusWidth = isCellEditor ? 0 : scale( (float) getFocusWidth( c ) );
float ow = focusWidth + scale( (float) getLineWidth( c ) ); float ow = focusWidth + scale( (float) getLineWidth( c ) );
@@ -204,6 +213,18 @@ public class FlatBorder
insets.left = Math.round( scale( (float) insets.left ) + ow ); insets.left = Math.round( scale( (float) insets.left ) + ow );
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow ); insets.bottom = Math.round( scale( (float) insets.bottom ) + ow );
insets.right = Math.round( scale( (float) insets.right ) + ow ); insets.right = Math.round( scale( (float) insets.right ) + ow );
if( isCellEditor ) {
// remove top and bottom insets if used as cell editor
insets.top = insets.bottom = 0;
// remove right/left insets to avoid that text is truncated (e.g. in file chooser)
if( c.getComponentOrientation().isLeftToRight() )
insets.right = 0;
else
insets.left = 0;
}
return insets; return insets;
} }

View File

@@ -42,6 +42,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.default.hoverBorderColor Color optional * @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.default.focusedBorderColor Color * @uiDefault Button.default.focusedBorderColor Color
* @uiDefault Button.default.focusColor Color * @uiDefault Button.default.focusColor Color
* @uiDefault Button.borderWidth int
* @uiDefault Button.default.borderWidth int * @uiDefault Button.default.borderWidth int
* @uiDefault Button.toolbar.margin Insets * @uiDefault Button.toolbar.margin Insets
* @uiDefault Button.toolbar.spacingInsets Insets * @uiDefault Button.toolbar.spacingInsets Insets
@@ -62,6 +63,7 @@ public class FlatButtonBorder
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" ); protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" ); protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" ); protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" ); protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" ); protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" ); protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
@@ -81,6 +83,11 @@ public class FlatButtonBorder
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ); return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c );
} }
@Override
protected boolean isFocused( Component c ) {
return FlatButtonUI.isFocusPainted( c ) && super.isFocused( c );
}
@Override @Override
protected Paint getBorderColor( Component c ) { protected Paint getBorderColor( Component c ) {
boolean def = FlatButtonUI.isDefaultButton( c ); boolean def = FlatButtonUI.isDefaultButton( c );
@@ -114,8 +121,8 @@ public class FlatButtonBorder
} else { } else {
insets = super.getBorderInsets( c, insets ); insets = super.getBorderInsets( c, insets );
// use smaller left and right insets for icon-only buttons (so that they are square) // use smaller left and right insets for icon-only or single-character buttons (so that they are square)
if( FlatButtonUI.isIconOnlyButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource ) if( FlatButtonUI.isIconOnlyOrSingleCharacterButton( c ) && ((AbstractButton)c).getMargin() instanceof UIResource )
insets.left = insets.right = Math.min( insets.top, insets.bottom ); insets.left = insets.right = Math.min( insets.top, insets.bottom );
} }
@@ -129,7 +136,7 @@ public class FlatButtonBorder
@Override @Override
protected int getBorderWidth( Component c ) { protected int getBorderWidth( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : super.getBorderWidth( c ); return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;
} }
@Override @Override

View File

@@ -67,6 +67,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.focusedBackground Color optional * @uiDefault Button.focusedBackground Color optional
* @uiDefault Button.hoverBackground Color optional * @uiDefault Button.hoverBackground Color optional
* @uiDefault Button.pressedBackground Color optional * @uiDefault Button.pressedBackground Color optional
* @uiDefault Button.disabledBackground Color optional
* @uiDefault Button.disabledText Color * @uiDefault Button.disabledText Color
* @uiDefault Button.default.background Color * @uiDefault Button.default.background Color
* @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored * @uiDefault Button.default.startBackground Color optional; if set, a gradient paint is used and Button.default.background is ignored
@@ -92,11 +93,15 @@ public class FlatButtonUI
protected int minimumWidth; protected int minimumWidth;
protected int iconTextGap; protected int iconTextGap;
protected Color background;
protected Color foreground;
protected Color startBackground; protected Color startBackground;
protected Color endBackground; protected Color endBackground;
protected Color focusedBackground; protected Color focusedBackground;
protected Color hoverBackground; protected Color hoverBackground;
protected Color pressedBackground; protected Color pressedBackground;
protected Color disabledBackground;
protected Color disabledText; protected Color disabledText;
protected Color defaultBackground; protected Color defaultBackground;
@@ -137,11 +142,15 @@ public class FlatButtonUI
minimumWidth = UIManager.getInt( prefix + "minimumWidth" ); minimumWidth = UIManager.getInt( prefix + "minimumWidth" );
iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 ); iconTextGap = FlatUIUtils.getUIInt( prefix + "iconTextGap", 4 );
background = UIManager.getColor( prefix + "background" );
foreground = UIManager.getColor( prefix + "foreground" );
startBackground = UIManager.getColor( prefix + "startBackground" ); startBackground = UIManager.getColor( prefix + "startBackground" );
endBackground = UIManager.getColor( prefix + "endBackground" ); endBackground = UIManager.getColor( prefix + "endBackground" );
focusedBackground = UIManager.getColor( prefix + "focusedBackground" ); focusedBackground = UIManager.getColor( prefix + "focusedBackground" );
hoverBackground = UIManager.getColor( prefix + "hoverBackground" ); hoverBackground = UIManager.getColor( prefix + "hoverBackground" );
pressedBackground = UIManager.getColor( prefix + "pressedBackground" ); pressedBackground = UIManager.getColor( prefix + "pressedBackground" );
disabledBackground = UIManager.getColor( prefix + "disabledBackground" );
disabledText = UIManager.getColor( prefix + "disabledText" ); disabledText = UIManager.getColor( prefix + "disabledText" );
if( UIManager.getBoolean( "Button.paintShadow" ) ) { if( UIManager.getBoolean( "Button.paintShadow" ) ) {
@@ -193,23 +202,19 @@ public class FlatButtonUI
@Override @Override
protected BasicButtonListener createButtonListener( AbstractButton b ) { protected BasicButtonListener createButtonListener( AbstractButton b ) {
return new BasicButtonListener( b ) { return new FlatButtonListener( b );
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}
};
} }
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) { protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case SQUARE_SIZE:
case MINIMUM_WIDTH: case MINIMUM_WIDTH:
case MINIMUM_HEIGHT: case MINIMUM_HEIGHT:
b.revalidate(); b.revalidate();
break; break;
case BUTTON_TYPE: case BUTTON_TYPE:
b.revalidate();
b.repaint(); b.repaint();
break; break;
} }
@@ -219,11 +224,19 @@ public class FlatButtonUI
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled(); return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
} }
public static boolean isFocusPainted( Component c ) {
return !(c instanceof AbstractButton) || ((AbstractButton)c).isFocusPainted();
}
static boolean isDefaultButton( Component c ) { static boolean isDefaultButton( Component c ) {
return c instanceof JButton && ((JButton)c).isDefaultButton(); return c instanceof JButton && ((JButton)c).isDefaultButton();
} }
static boolean isIconOnlyButton( Component c ) { /**
* Returns true if the button has an icon but no text,
* or it it does not have an icon and the text is either "..." or one character.
*/
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
if( !(c instanceof JButton) && !(c instanceof JToggleButton) ) if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
return false; return false;
@@ -272,55 +285,61 @@ public class FlatButtonUI
protected void paintBackground( Graphics g, JComponent c ) { protected void paintBackground( Graphics g, JComponent c ) {
Color background = getBackground( c ); Color background = getBackground( c );
if( background != null ) { if( background == null )
Graphics2D g2 = (Graphics2D) g.create(); return;
try {
FlatUIUtils.setRenderingHints( g2 );
boolean isToolBarButton = isToolBarButton( c ); Graphics2D g2 = (Graphics2D) g.create();
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c ); try {
float arc = FlatUIUtils.getBorderArc( c ); FlatUIUtils.setRenderingHints( g2 );
boolean def = isDefaultButton( c ); boolean isToolBarButton = isToolBarButton( c );
float focusWidth = isToolBarButton ? 0 : FlatUIUtils.getBorderFocusWidth( c );
float arc = FlatUIUtils.getBorderArc( c );
int x = 0; boolean def = isDefaultButton( c );
int y = 0;
int width = c.getWidth();
int height = c.getHeight();
if( isToolBarButton ) { int x = 0;
Insets spacing = UIScale.scale( toolbarSpacingInsets ); int y = 0;
x += spacing.left; int width = c.getWidth();
y += spacing.top; int height = c.getHeight();
width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom;
}
// paint shadow if( isToolBarButton ) {
Color shadowColor = def ? defaultShadowColor : this.shadowColor; Insets spacing = UIScale.scale( toolbarSpacingInsets );
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 && x += spacing.left;
!FlatUIUtils.isPermanentFocusOwner( c ) && c.isEnabled() ) y += spacing.top;
{ width -= spacing.left + spacing.right;
g2.setColor( shadowColor ); height -= spacing.top + spacing.bottom;
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
}
// paint background
Color startBg = def ? defaultBackground : startBackground;
Color endBg = def ? defaultEndBackground : endBackground;
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
else
FlatUIUtils.setColor( g2, background, def ? defaultBackground : c.getBackground() );
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
} finally {
g2.dispose();
} }
// paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( !isToolBarButton && shadowColor != null && shadowWidth > 0 && focusWidth > 0 &&
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) && c.isEnabled() )
{
g2.setColor( shadowColor );
g2.fill( new RoundRectangle2D.Float( focusWidth, focusWidth + UIScale.scale( (float) shadowWidth ),
width - focusWidth * 2, height - focusWidth * 2, arc, arc ) );
}
// paint background
Color startBg = def ? defaultBackground : startBackground;
Color endBg = def ? defaultEndBackground : endBackground;
if( background == startBg && endBg != null && !startBg.equals( endBg ) )
g2.setPaint( new GradientPaint( 0, 0, startBg, 0, height, endBg ) );
else
g2.setColor( FlatUIUtils.deriveColor( background, getBackgroundBase( c, def ) ) );
FlatUIUtils.paintComponentBackground( g2, x, y, width, height, focusWidth, arc );
} finally {
g2.dispose();
} }
} }
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
}
@Override @Override
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) { protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
if( isHelpButton( b ) ) if( isHelpButton( b ) )
@@ -337,7 +356,7 @@ public class FlatButtonUI
} }
} }
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText ); paintText( g, b, textRect, text, getForeground( b ) );
} }
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) { public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
@@ -351,7 +370,7 @@ public class FlatButtonUI
protected Color getBackground( JComponent c ) { protected Color getBackground( JComponent c ) {
if( !c.isEnabled() ) if( !c.isEnabled() )
return null; return disabledBackground;
// toolbar button // toolbar button
if( isToolBarButton( c ) ) { if( isToolBarButton( c ) ) {
@@ -367,13 +386,26 @@ public class FlatButtonUI
boolean def = isDefaultButton( c ); boolean def = isDefaultButton( c );
return buttonStateColor( c, return buttonStateColor( c,
def ? defaultBackground : c.getBackground(), getBackgroundBase( c, def ),
null, null,
def ? defaultFocusedBackground : focusedBackground, isCustomBackground( c.getBackground() ) ? null : (def ? defaultFocusedBackground : focusedBackground),
def ? defaultHoverBackground : hoverBackground, def ? defaultHoverBackground : hoverBackground,
def ? defaultPressedBackground : pressedBackground ); def ? defaultPressedBackground : pressedBackground );
} }
protected Color getBackgroundBase( JComponent c, boolean def ) {
// use component background if explicitly set
Color bg = c.getBackground();
if( isCustomBackground( bg ) )
return bg;
return def ? defaultBackground : bg;
}
protected boolean isCustomBackground( Color bg ) {
return bg != background && (startBackground == null || bg != startBackground);
}
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor, public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
Color focusedColor, Color hoverColor, Color pressedColor ) Color focusedColor, Color hoverColor, Color pressedColor )
{ {
@@ -388,15 +420,27 @@ public class FlatButtonUI
if( hoverColor != null && b != null && b.getModel().isRollover() ) if( hoverColor != null && b != null && b.getModel().isRollover() )
return hoverColor; return hoverColor;
if( focusedColor != null && FlatUIUtils.isPermanentFocusOwner( c ) ) if( focusedColor != null && isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c ) )
return focusedColor; return focusedColor;
return enabledColor; return enabledColor;
} }
protected Color getForeground( JComponent c ) { protected Color getForeground( JComponent c ) {
if( !c.isEnabled() )
return disabledText;
// use component foreground if explicitly set
Color fg = c.getForeground();
if( isCustomForeground( fg ) )
return fg;
boolean def = isDefaultButton( c ); boolean def = isDefaultButton( c );
return def ? defaultForeground : c.getForeground(); return def ? defaultForeground : fg;
}
protected boolean isCustomForeground( Color fg ) {
return fg != foreground;
} }
@Override @Override
@@ -408,11 +452,16 @@ public class FlatButtonUI
if( prefSize == null ) if( prefSize == null )
return null; return null;
// make button square if it is a icon-only button // make square or apply minimum width/height
// or apply minimum width, if not in toolbar and not a icon-only button boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
if( isIconOnlyButton( c ) ) if( clientPropertyBoolean( c, SQUARE_SIZE, false ) ) {
// make button square (increase width or height so that they are equal)
prefSize.width = prefSize.height = Math.max( prefSize.width, prefSize.height );
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
// make single-character-no-icon button square (increase width)
prefSize.width = Math.max( prefSize.width, prefSize.height ); prefSize.width = Math.max( prefSize.width, prefSize.height );
else if( !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) { } else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) {
// apply minimum width/height
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) ); prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) ); prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) );
@@ -420,4 +469,23 @@ public class FlatButtonUI
return prefSize; return prefSize;
} }
//---- class FlatButtonListener -------------------------------------------
protected class FlatButtonListener
extends BasicButtonListener
{
private final AbstractButton b;
protected FlatButtonListener( AbstractButton b ) {
super( b );
this.b = b;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatButtonUI.this.propertyChange( b, e );
}
}
} }

View File

@@ -31,7 +31,7 @@ import javax.swing.text.JTextComponent;
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
class FlatCaret public class FlatCaret
extends DefaultCaret extends DefaultCaret
implements UIResource implements UIResource
{ {
@@ -41,7 +41,7 @@ class FlatCaret
private boolean wasTemporaryLost; private boolean wasTemporaryLost;
private boolean isMousePressed; private boolean isMousePressed;
FlatCaret( String selectAllOnFocusPolicy ) { public FlatCaret( String selectAllOnFocusPolicy ) {
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy; this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
} }
@@ -87,7 +87,7 @@ class FlatCaret
super.mouseReleased( e ); super.mouseReleased( e );
} }
private void selectAllOnFocusGained() { protected void selectAllOnFocusGained() {
JTextComponent c = getComponent(); JTextComponent c = getComponent();
Document doc = c.getDocument(); Document doc = c.getDocument();
if( doc == null || !c.isEnabled() || !c.isEditable() ) if( doc == null || !c.isEnabled() || !c.isEditable() )

View File

@@ -39,6 +39,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.ComboBoxEditor;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap; import javax.swing.InputMap;
import javax.swing.JButton; import javax.swing.JButton;
@@ -46,6 +47,8 @@ import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JTextField;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer; import javax.swing.ListCellRenderer;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
@@ -76,6 +79,10 @@ import com.formdev.flatlaf.util.UIScale;
* *
* <!-- FlatComboBoxUI --> * <!-- FlatComboBoxUI -->
* *
* @uiDefault ComboBox.minimumWidth int
* @uiDefault ComboBox.editorColumns int
* @uiDefault ComboBox.maximumRowCount int
* @uiDefault ComboBox.buttonStyle String auto (default), button or none
* @uiDefault Component.arrowType String triangle (default) or chevron * @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Component.borderColor Color * @uiDefault Component.borderColor Color
@@ -94,6 +101,9 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatComboBoxUI public class FlatComboBoxUI
extends BasicComboBoxUI extends BasicComboBoxUI
{ {
protected int minimumWidth;
protected int editorColumns;
protected String buttonStyle;
protected String arrowType; protected String arrowType;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color borderColor; protected Color borderColor;
@@ -110,7 +120,7 @@ public class FlatComboBoxUI
protected Color buttonHoverArrowColor; protected Color buttonHoverArrowColor;
private MouseListener hoverListener; private MouseListener hoverListener;
private boolean hover; protected boolean hover;
private WeakReference<Component> lastRendererComponent; private WeakReference<Component> lastRendererComponent;
@@ -146,6 +156,9 @@ public class FlatComboBoxUI
LookAndFeel.installProperty( comboBox, "opaque", false ); LookAndFeel.installProperty( comboBox, "opaque", false );
minimumWidth = UIManager.getInt( "ComboBox.minimumWidth" );
editorColumns = UIManager.getInt( "ComboBox.editorColumns" );
buttonStyle = UIManager.getString( "ComboBox.buttonStyle" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
borderColor = UIManager.getColor( "Component.borderColor" ); borderColor = UIManager.getColor( "Component.borderColor" );
@@ -161,6 +174,11 @@ public class FlatComboBoxUI
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" ); buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" ); buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
// set maximumRowCount
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
comboBox.setMaximumRowCount( maximumRowCount );
// scale // scale
padding = UIScale.scale( padding ); padding = UIScale.scale( padding );
@@ -245,6 +263,8 @@ public class FlatComboBoxUI
editor.repaint(); editor.repaint();
else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) ) else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) )
comboBox.repaint(); comboBox.repaint();
else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) )
comboBox.revalidate();
} }
}; };
} }
@@ -254,18 +274,30 @@ public class FlatComboBoxUI
return new FlatComboPopup( comboBox ); return new FlatComboPopup( comboBox );
} }
@Override
protected ComboBoxEditor createEditor() {
ComboBoxEditor comboBoxEditor = super.createEditor();
Component editor = comboBoxEditor.getEditorComponent();
if( editor instanceof JTextField ) {
JTextField textField = (JTextField) editor;
textField.setColumns( editorColumns );
// assign a non-null and non-javax.swing.plaf.UIResource border to the text field,
// otherwise it is replaced with default text field border when switching LaF
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
// instead of "border instanceof javax.swing.plaf.UIResource"
textField.setBorder( BorderFactory.createEmptyBorder() );
}
return comboBoxEditor;
}
@Override @Override
protected void configureEditor() { protected void configureEditor() {
super.configureEditor(); super.configureEditor();
// assign a non-javax.swing.plaf.UIResource border to the text field,
// otherwise it is replaced with default text field border when switching LaF
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder()
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource"
// instead of "border instanceof javax.swing.plaf.UIResource"
if( editor instanceof JTextComponent )
((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() );
// explicitly make non-opaque // explicitly make non-opaque
if( editor instanceof JComponent ) if( editor instanceof JComponent )
((JComponent)editor).setOpaque( false ); ((JComponent)editor).setOpaque( false );
@@ -275,7 +307,7 @@ public class FlatComboBoxUI
updateEditorColors(); updateEditorColors();
// macOS // macOS
if( SystemInfo.IS_MAC && editor instanceof JTextComponent ) { if( SystemInfo.isMacOS && editor instanceof JTextComponent ) {
// delegate actions from editor text field to combobox, which is necessary // delegate actions from editor text field to combobox, which is necessary
// because text field on macOS already handle those keys // because text field on macOS already handle those keys
InputMap inputMap = ((JTextComponent)editor).getInputMap(); InputMap inputMap = ((JTextComponent)editor).getInputMap();
@@ -292,24 +324,16 @@ public class FlatComboBoxUI
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
// is used, then the editor is updated after the combobox and the // is used, then the editor is updated after the combobox and the
// colors are again replaced with default colors // colors are again replaced with default colors
boolean enabled = editor.isEnabled(); boolean isTextComponent = editor instanceof JTextComponent;
editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent) editor.setForeground( FlatUIUtils.nonUIResource( getForeground( isTextComponent || editor.isEnabled() ) ) );
? comboBox.getForeground()
: disabledForeground ) ); if( isTextComponent )
if( editor instanceof JTextComponent ) ((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
((JTextComponent)editor).setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
} }
@Override @Override
protected JButton createArrowButton() { protected JButton createArrowButton() {
return new FlatArrowButton( SwingConstants.SOUTH, arrowType, buttonArrowColor, return new FlatComboBoxButton();
buttonDisabledArrowColor, buttonHoverArrowColor, null )
{
@Override
protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false);
}
};
} }
@Override @Override
@@ -328,18 +352,17 @@ public class FlatComboBoxUI
int height = c.getHeight(); int height = c.getHeight();
int arrowX = arrowButton.getX(); int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth(); int arrowWidth = arrowButton.getWidth();
boolean paintButton = (comboBox.isEditable() || "button".equals( buttonStyle )) && !"none".equals( buttonStyle );
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled g2.setColor( getBackground( enabled ) );
? (editableBackground != null && comboBox.isEditable() ? editableBackground : c.getBackground())
: getDisabledBackground( comboBox ) );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background // paint arrow button background
if( enabled ) { if( enabled ) {
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground ); g2.setColor( paintButton ? buttonEditableBackground : buttonBackground );
Shape oldClip = g2.getClip(); Shape oldClip = g2.getClip();
if( isLeftToRight ) if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height ); g2.clipRect( arrowX, 0, width - arrowX, height );
@@ -350,7 +373,7 @@ public class FlatComboBoxUI
} }
// paint vertical line between value and arrow button // paint vertical line between value and arrow button
if( comboBox.isEditable() ) { if( paintButton ) {
g2.setColor( enabled ? borderColor : disabledBorderColor ); g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f ); float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
@@ -373,8 +396,8 @@ public class FlatComboBoxUI
uninstallCellPaddingBorder( c ); uninstallCellPaddingBorder( c );
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
c.setForeground( enabled ? comboBox.getForeground() : disabledForeground ); c.setBackground( getBackground( enabled ) );
c.setBackground( enabled ? comboBox.getBackground() : getDisabledBackground( comboBox ) ); c.setForeground( getForeground( enabled ) );
boolean shouldValidate = (c instanceof JPanel); boolean shouldValidate = (c instanceof JPanel);
if( padding != null ) if( padding != null )
@@ -394,8 +417,21 @@ public class FlatComboBoxUI
// not necessary because already painted in update() // not necessary because already painted in update()
} }
private Color getDisabledBackground( JComponent c ) { protected Color getBackground( boolean enabled ) {
return isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground; return enabled
? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground())
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground);
}
protected Color getForeground( boolean enabled ) {
return enabled ? comboBox.getForeground() : disabledForeground;
}
@Override
public Dimension getMinimumSize( JComponent c ) {
Dimension minimumSize = super.getMinimumSize( c );
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) );
return minimumSize;
} }
@Override @Override
@@ -418,6 +454,18 @@ public class FlatComboBoxUI
Dimension displaySize = super.getDisplaySize(); Dimension displaySize = super.getDisplaySize();
// recalculate width without hardcoded 100 under special conditions
if( displaySize.width == 100 + padding.left + padding.right &&
comboBox.isEditable() &&
comboBox.getItemCount() == 0 &&
comboBox.getPrototypeDisplayValue() == null )
{
int width = getDefaultSize().width;
width = Math.max( width, editor.getPreferredSize().width );
width += padding.left + padding.right;
displaySize = new Dimension( width, displaySize.height );
}
uninstallCellPaddingBorder( renderer ); uninstallCellPaddingBorder( renderer );
return displaySize; return displaySize;
} }
@@ -453,6 +501,27 @@ public class FlatComboBoxUI
} }
} }
//---- class FlatComboBoxButton -------------------------------------------
protected class FlatComboBoxButton
extends FlatArrowButton
{
protected FlatComboBoxButton() {
this( SwingConstants.SOUTH, arrowType, buttonArrowColor, buttonDisabledArrowColor, buttonHoverArrowColor, null, null );
}
protected FlatComboBoxButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground, Color pressedBackground )
{
super( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, pressedBackground );
}
@Override
protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false);
}
}
//---- class FlatComboPopup ----------------------------------------------- //---- class FlatComboPopup -----------------------------------------------
@SuppressWarnings( { "rawtypes", "unchecked" } ) @SuppressWarnings( { "rawtypes", "unchecked" } )
@@ -476,13 +545,26 @@ public class FlatComboBoxUI
@Override @Override
protected Rectangle computePopupBounds( int px, int py, int pw, int ph ) { protected Rectangle computePopupBounds( int px, int py, int pw, int ph ) {
// get maximum display size of all items // get maximum display width of all items
Dimension displaySize = getDisplaySize(); int displayWidth = getDisplaySize().width;
// add border insets
for( Border border : new Border[] { scroller.getViewportBorder(), scroller.getBorder() } ) {
if( border != null ) {
Insets borderInsets = border.getBorderInsets( null );
displayWidth += borderInsets.left + borderInsets.right;
}
}
// add width of vertical scroll bar
JScrollBar verticalScrollBar = scroller.getVerticalScrollBar();
if( verticalScrollBar != null )
displayWidth += verticalScrollBar.getPreferredSize().width;
// make popup wider if necessary // make popup wider if necessary
if( displaySize.width > pw ) { if( displayWidth > pw ) {
int diff = displaySize.width - pw; int diff = displayWidth - pw;
pw = displaySize.width; pw = displayWidth;
if( !comboBox.getComponentOrientation().isLeftToRight() ) if( !comboBox.getComponentOrientation().isLeftToRight() )
px -= diff; px -= diff;

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -26,6 +28,8 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
@@ -83,6 +87,20 @@ public class FlatEditorPaneUI
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
propertyChange( getComponent(), e );
}
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate();
break;
}
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth ); return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
@@ -103,6 +121,11 @@ public class FlatEditorPaneUI
return size; return size;
} }
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -27,6 +27,7 @@ import javax.swing.BoxLayout;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -175,6 +176,18 @@ public class FlatFileChooserUI
} }
} }
} }
// increase maximum row count of directory combo box popup list
try {
Component directoryComboBox = ((JPanel)topPanel).getComponent( 2 );
if( directoryComboBox instanceof JComboBox ) {
int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" );
if( maximumRowCount > 0 )
((JComboBox<?>)directoryComboBox).setMaximumRowCount( maximumRowCount );
}
} catch( ArrayIndexOutOfBoundsException ex ) {
// ignore
}
} }
@Override @Override

View File

@@ -26,13 +26,14 @@ import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JInternalFrame; import javax.swing.JInternalFrame;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane; import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -91,7 +92,21 @@ public class FlatInternalFrameTitlePane
updateFrameIcon(); updateFrameIcon();
updateColors(); updateColors();
buttonPanel = new JPanel(); buttonPanel = new JPanel() {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
int height = size.height;
// use height of invisible buttons to always have same title pane height
if( !iconButton.isVisible() )
height = Math.max( height, iconButton.getPreferredSize().height );
if( !maxButton.isVisible() )
height = Math.max( height, maxButton.getPreferredSize().height );
if( !closeButton.isVisible() )
height = Math.max( height, closeButton.getPreferredSize().height );
return new Dimension( size.width, height );
}
};
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) ); buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
buttonPanel.setOpaque( false ); buttonPanel.setOpaque( false );
@@ -103,14 +118,16 @@ public class FlatInternalFrameTitlePane
add( buttonPanel, BorderLayout.LINE_END ); add( buttonPanel, BorderLayout.LINE_END );
} }
private void updateFrameIcon() { protected void updateFrameIcon() {
Icon frameIcon = frame.getFrameIcon(); Icon frameIcon = frame.getFrameIcon();
if( frameIcon == UIManager.getIcon( "InternalFrame.icon" ) ) if( frameIcon != null && (frameIcon.getIconWidth() == 0 || frameIcon.getIconHeight() == 0) )
frameIcon = null; frameIcon = null;
else if( frameIcon instanceof ImageIcon )
frameIcon = new ScaledImageIcon( (ImageIcon) frameIcon );
titleLabel.setIcon( frameIcon ); titleLabel.setIcon( frameIcon );
} }
private void updateColors() { protected void updateColors() {
Color background = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTitleColor : notSelectedTitleColor ); Color background = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTitleColor : notSelectedTitleColor );
Color foreground = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTextColor : notSelectedTextColor ); Color foreground = FlatUIUtils.nonUIResource( frame.isSelected() ? selectedTextColor : notSelectedTextColor );
@@ -123,7 +140,7 @@ public class FlatInternalFrameTitlePane
closeButton.setForeground( foreground ); closeButton.setForeground( foreground );
} }
private void updateButtonsVisibility() { protected void updateButtonsVisibility() {
iconButton.setVisible( frame.isIconifiable() ); iconButton.setVisible( frame.isIconifiable() );
maxButton.setVisible( frame.isMaximizable() ); maxButton.setVisible( frame.isMaximizable() );
closeButton.setVisible( frame.isClosable() ); closeButton.setVisible( frame.isClosable() );
@@ -150,7 +167,7 @@ public class FlatInternalFrameTitlePane
//---- class FlatPropertyChangeHandler ------------------------------------ //---- class FlatPropertyChangeHandler ------------------------------------
private class FlatPropertyChangeHandler protected class FlatPropertyChangeHandler
extends PropertyChangeHandler extends PropertyChangeHandler
{ {
@Override @Override

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.Icon; import javax.swing.Icon;
@@ -30,6 +31,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.plaf.basic.BasicLabelUI;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -124,6 +126,17 @@ public class FlatLabelUI
BasicHTML.updateRenderer( c, text ); BasicHTML.updateRenderer( c, text );
} }
static Graphics createGraphicsHTMLTextYCorrection( Graphics g, JComponent c ) {
return (c.getClientProperty( BasicHTML.propertyKey ) != null)
? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g )
: g;
}
@Override
public void paint( Graphics g, JComponent c ) {
super.paint( createGraphicsHTMLTextYCorrection( g, c ), c );
}
@Override @Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) { protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1; int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -106,7 +107,11 @@ public class FlatListUI
@Override @Override
public void focusLost( FocusEvent e ) { public void focusLost( FocusEvent e ) {
super.focusLost( e ); super.focusLost( e );
toggleSelectionColors();
// use invokeLater for the case that the window is deactivated
EventQueue.invokeLater( () -> {
toggleSelectionColors();
} );
} }
}; };
} }

View File

@@ -82,7 +82,7 @@ public class FlatMenuBarUI
JMenuBar menuBar = (JMenuBar) e.getSource(); JMenuBar menuBar = (JMenuBar) e.getSource();
JMenu menu = menuBar.getMenu( 0 ); JMenu menu = menuBar.getMenu( 0 );
if( menu != null ) { if( menu != null ) {
MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.IS_WINDOWS MenuSelectionManager.defaultManager().setSelectedPath( SystemInfo.isWindows
? new MenuElement[] { menuBar, menu } ? new MenuElement[] { menuBar, menu }
: new MenuElement[] { menuBar, menu, menu.getPopupMenu() } ); : new MenuElement[] { menuBar, menu, menu.getPopupMenu() } );

View File

@@ -40,7 +40,7 @@ public class FlatMenuItemBorder
if( c.getParent() instanceof JMenuBar ) { if( c.getParent() instanceof JMenuBar ) {
insets.top = scale( menuBarItemMargins.top ); insets.top = scale( menuBarItemMargins.top );
insets.left = scale( menuBarItemMargins.left ); insets.left = scale( menuBarItemMargins.left );
insets.bottom = scale( menuBarItemMargins.bottom + 1 ); insets.bottom = scale( menuBarItemMargins.bottom );
insets.right = scale( menuBarItemMargins.right ); insets.right = scale( menuBarItemMargins.right );
return insets; return insets;
} else } else

View File

@@ -40,6 +40,8 @@ import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Renderer for menu items. * Renderer for menu items.
@@ -260,7 +262,9 @@ debug*/
// paint background // paint background
g.setColor( armedOrSelected g.setColor( armedOrSelected
? (isUnderlineSelection() ? underlineSelectionBackground : selectionBackground) ? (isUnderlineSelection()
? deriveBackground( underlineSelectionBackground )
: selectionBackground)
: menuItem.getBackground() ); : menuItem.getBackground() );
g.fillRect( 0, 0, width, height ); g.fillRect( 0, 0, width, height );
@@ -282,12 +286,20 @@ debug*/
} }
} }
protected Color deriveBackground( Color background ) {
Color baseColor = menuItem.isOpaque()
? menuItem.getBackground()
: FlatUIUtils.getParentBackground( menuItem );
return FlatUIUtils.deriveColor( background, baseColor );
}
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon ) { protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon ) {
// if checkbox/radiobutton menu item is selected and also has a custom icon, // if checkbox/radiobutton menu item is selected and also has a custom icon,
// then use filled icon background to indicate selection (instead of using checkIcon) // then use filled icon background to indicate selection (instead of using checkIcon)
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) { if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {
Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) ); Rectangle r = FlatUIUtils.addInsets( iconRect, scale( checkMargins ) );
g.setColor( isUnderlineSelection() ? underlineSelectionCheckBackground : checkBackground ); g.setColor( deriveBackground( isUnderlineSelection() ? underlineSelectionCheckBackground : checkBackground ) );
g.fillRect( r.x, r.y, r.width, r.height ); g.fillRect( r.x, r.y, r.width, r.height );
} }
@@ -302,7 +314,7 @@ debug*/
} }
int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1; int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
Color foreground = menuItem.getForeground(); Color foreground = (isTopLevelMenu( menuItem ) ? menuItem.getParent() : menuItem).getForeground();
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(), paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(),
foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground ); foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
@@ -360,7 +372,7 @@ debug*/
if( isArmedOrSelected( menuItem ) && selectionForeground != null ) if( isArmedOrSelected( menuItem ) && selectionForeground != null )
g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground ); g = new GraphicsProxyWithTextColor( (Graphics2D) g, selectionForeground );
htmlView.paint( g, textRect ); htmlView.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), textRect );
} }
protected static boolean isArmedOrSelected( JMenuItem menuItem ) { protected static boolean isArmedOrSelected( JMenuItem menuItem ) {
@@ -371,7 +383,7 @@ debug*/
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu(); return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
} }
private boolean isUnderlineSelection() { protected boolean isUnderlineSelection() {
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
} }
@@ -407,32 +419,78 @@ debug*/
private KeyStroke cachedAccelerator; private KeyStroke cachedAccelerator;
private String cachedAcceleratorText; private String cachedAcceleratorText;
private boolean cachedAcceleratorLeftToRight;
private String getAcceleratorText() { private String getAcceleratorText() {
KeyStroke accelerator = menuItem.getAccelerator(); KeyStroke accelerator = menuItem.getAccelerator();
if( accelerator == null ) if( accelerator == null )
return null; return null;
if( accelerator == cachedAccelerator ) boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
if( accelerator == cachedAccelerator && leftToRight == cachedAcceleratorLeftToRight )
return cachedAcceleratorText; return cachedAcceleratorText;
StringBuilder buf = new StringBuilder(); cachedAccelerator = accelerator;
int modifiers = accelerator.getModifiers(); cachedAcceleratorText = getTextForAccelerator( accelerator );
if( modifiers != 0 ) cachedAcceleratorLeftToRight = leftToRight;
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
return cachedAcceleratorText;
}
protected String getTextForAccelerator( KeyStroke accelerator ) {
StringBuilder buf = new StringBuilder();
boolean leftToRight = menuItem.getComponentOrientation().isLeftToRight();
// modifiers
int modifiers = accelerator.getModifiers();
if( modifiers != 0 ) {
if( SystemInfo.isMacOS ) {
if( leftToRight )
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
} else
buf.append( InputEvent.getModifiersExText( modifiers ) ).append( acceleratorDelimiter );
}
// key
int keyCode = accelerator.getKeyCode(); int keyCode = accelerator.getKeyCode();
if( keyCode != 0 ) if( keyCode != 0 )
buf.append( KeyEvent.getKeyText( keyCode ) ); buf.append( KeyEvent.getKeyText( keyCode ) );
else else
buf.append( accelerator.getKeyChar() ); buf.append( accelerator.getKeyChar() );
cachedAccelerator = accelerator; // modifiers if right-to-left on macOS
cachedAcceleratorText = buf.toString(); if( modifiers != 0 && !leftToRight && SystemInfo.isMacOS )
buf.append( getMacOSModifiersExText( modifiers, leftToRight ) );
return cachedAcceleratorText; return buf.toString();
} }
protected String getMacOSModifiersExText( int modifiers, boolean leftToRight ) {
StringBuilder buf = new StringBuilder();
if( (modifiers & InputEvent.CTRL_DOWN_MASK) != 0 )
buf.append( controlGlyph );
if( (modifiers & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0 )
buf.append( optionGlyph );
if( (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 )
buf.append( shiftGlyph );
if( (modifiers & InputEvent.META_DOWN_MASK) != 0 )
buf.append( commandGlyph );
// reverse order for right-to-left
if( !leftToRight )
buf.reverse();
return buf.toString();
}
private static final char
controlGlyph = 0x2303,
optionGlyph = 0x2325,
shiftGlyph = 0x21E7,
commandGlyph = 0x2318;
//---- class MinSizeIcon -------------------------------------------------- //---- class MinSizeIcon --------------------------------------------------
private class MinSizeIcon private class MinSizeIcon

View File

@@ -151,7 +151,7 @@ public class FlatMenuUI
if( model.isRollover() && !model.isArmed() && !model.isSelected() && if( model.isRollover() && !model.isArmed() && !model.isSelected() &&
model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() ) model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() )
{ {
FlatUIUtils.setColor( g, hoverBackground, menuItem.getBackground() ); g.setColor( deriveBackground( hoverBackground ) );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() ); g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
} else } else
super.paintBackground( g, selectionBackground ); super.paintBackground( g, selectionBackground );

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
@@ -33,6 +34,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.plaf.basic.BasicPasswordFieldUI;
import javax.swing.text.Caret; import javax.swing.text.Caret;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
@@ -153,7 +155,8 @@ public class FlatPasswordFieldUI
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme ); FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground ); FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
paintCapsLock( g ); paintCapsLock( g );
super.paintSafely( g );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
} }
protected void paintCapsLock( Graphics g ) { protected void paintCapsLock( Graphics g ) {

View File

@@ -32,6 +32,7 @@ import java.lang.reflect.Method;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLayeredPane; import javax.swing.JLayeredPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.Popup; import javax.swing.Popup;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
@@ -62,7 +63,7 @@ public class FlatPopupFactory
return new NonFlashingPopup( super.getPopup( owner, contents, x, y ), contents ); return new NonFlashingPopup( super.getPopup( owner, contents, x, y ), contents );
// macOS and Linux adds drop shadow to heavy weight popups // macOS and Linux adds drop shadow to heavy weight popups
if( SystemInfo.IS_MAC || SystemInfo.IS_LINUX ) { if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
Popup popup = getHeavyWeightPopup( owner, contents, x, y ); Popup popup = getHeavyWeightPopup( owner, contents, x, y );
if( popup == null ) if( popup == null )
popup = super.getPopup( owner, contents, x, y ); popup = super.getPopup( owner, contents, x, y );
@@ -105,7 +106,7 @@ public class FlatPopupFactory
throws IllegalArgumentException throws IllegalArgumentException
{ {
try { try {
if( SystemInfo.IS_JAVA_9_OR_LATER ) { if( SystemInfo.isJava_9_orLater ) {
if( java9getPopupMethod == null ) { if( java9getPopupMethod == null ) {
java9getPopupMethod = PopupFactory.class.getDeclaredMethod( java9getPopupMethod = PopupFactory.class.getDeclaredMethod(
"getPopup", Component.class, Component.class, int.class, int.class, boolean.class ); "getPopup", Component.class, Component.class, int.class, int.class, boolean.class );
@@ -132,6 +133,7 @@ public class FlatPopupFactory
extends Popup extends Popup
{ {
private Popup delegate; private Popup delegate;
private Component contents;
// heavy weight // heavy weight
protected Window popupWindow; protected Window popupWindow;
@@ -139,6 +141,7 @@ public class FlatPopupFactory
NonFlashingPopup( Popup delegate, Component contents ) { NonFlashingPopup( Popup delegate, Component contents ) {
this.delegate = delegate; this.delegate = delegate;
this.contents = contents;
popupWindow = SwingUtilities.windowForComponent( contents ); popupWindow = SwingUtilities.windowForComponent( contents );
if( popupWindow != null ) { if( popupWindow != null ) {
@@ -153,7 +156,25 @@ public class FlatPopupFactory
@Override @Override
public void show() { public void show() {
delegate.show(); if( delegate != null ) {
delegate.show();
// increase tooltip size if necessary because it may be too small on HiDPI screens
// https://bugs.openjdk.java.net/browse/JDK-8213535
if( contents instanceof JToolTip ) {
Container parent = contents.getParent();
if( parent instanceof JPanel ) {
Dimension prefSize = parent.getPreferredSize();
if( !prefSize.equals( parent.getSize() ) ) {
Container panel = SwingUtilities.getAncestorOfClass( Panel.class, parent );
if( panel != null )
panel.setSize( prefSize ); // for medium weight popup
else
parent.setSize( prefSize ); // for light weight popup
}
}
}
}
} }
@Override @Override
@@ -161,6 +182,7 @@ public class FlatPopupFactory
if( delegate != null ) { if( delegate != null ) {
delegate.hide(); delegate.hide();
delegate = null; delegate = null;
contents = null;
} }
if( popupWindow != null ) { if( popupWindow != null ) {
@@ -185,6 +207,7 @@ public class FlatPopupFactory
private boolean oldOpaque; private boolean oldOpaque;
// medium weight // medium weight
private boolean mediumWeightShown;
private Panel mediumWeightPanel; private Panel mediumWeightPanel;
private JPanel dropShadowPanel; private JPanel dropShadowPanel;
private ComponentListener mediumPanelListener; private ComponentListener mediumPanelListener;
@@ -311,6 +334,11 @@ public class FlatPopupFactory
} }
private void showMediumWeightDropShadow() { private void showMediumWeightDropShadow() {
if( mediumWeightShown )
return;
mediumWeightShown = true;
Window window = SwingUtilities.windowForComponent( owner ); Window window = SwingUtilities.windowForComponent( owner );
if( window == null ) if( window == null )
return; return;
@@ -326,24 +354,29 @@ public class FlatPopupFactory
mediumPanelListener = new ComponentListener() { mediumPanelListener = new ComponentListener() {
@Override @Override
public void componentShown( ComponentEvent e ) { public void componentShown( ComponentEvent e ) {
dropShadowPanel.setVisible( true ); if( dropShadowPanel != null )
dropShadowPanel.setVisible( true );
} }
@Override @Override
public void componentHidden( ComponentEvent e ) { public void componentHidden( ComponentEvent e ) {
dropShadowPanel.setVisible( false ); if( dropShadowPanel != null )
dropShadowPanel.setVisible( false );
} }
@Override @Override
public void componentMoved( ComponentEvent e ) { public void componentMoved( ComponentEvent e ) {
Point location = mediumWeightPanel.getLocation(); if( dropShadowPanel != null && mediumWeightPanel != null ) {
Insets insets = dropShadowPanel.getInsets(); Point location = mediumWeightPanel.getLocation();
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top ); Insets insets = dropShadowPanel.getInsets();
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
}
} }
@Override @Override
public void componentResized( ComponentEvent e ) { public void componentResized( ComponentEvent e ) {
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) ); if( dropShadowPanel != null )
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
} }
}; };
mediumWeightPanel.addComponentListener( mediumPanelListener ); mediumWeightPanel.addComponentListener( mediumPanelListener );

View File

@@ -31,6 +31,7 @@ import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI; import javax.swing.plaf.basic.BasicProgressBarUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -194,6 +195,11 @@ public class FlatProgressBarUI
} }
} }
@Override
protected void paintString( Graphics g, int x, int y, int width, int height, int amountFull, Insets b ) {
super.paintString( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), x, y, width, height, amountFull, b );
}
@Override @Override
protected void setAnimationIndex( int newValue ) { protected void setAnimationIndex( int newValue ) {
super.setAnimationIndex( newValue ); super.setAnimationIndex( newValue );

View File

@@ -153,7 +153,7 @@ public class FlatRadioButtonUI
} }
} }
super.paint( g, c ); super.paint( FlatLabelUI.createGraphicsHTMLTextYCorrection( g, c ), c );
} }
@Override @Override

View File

@@ -16,23 +16,357 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Window;
import java.beans.PropertyChangeEvent;
import java.util.function.Function;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRootPaneUI; import javax.swing.plaf.basic.BasicRootPaneUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}.
* *
* <!-- FlatRootPaneUI -->
*
* @uiDefault RootPane.border Border
* @uiDefault RootPane.activeBorderColor Color
* @uiDefault RootPane.inactiveBorderColor Color
*
* <!-- FlatWindowResizer -->
*
* @uiDefault RootPane.borderDragThickness int
* @uiDefault RootPane.cornerDragWidth int
* @uiDefault RootPane.honorFrameMinimumSizeOnResize boolean
* @uiDefault RootPane.honorDialogMinimumSizeOnResize boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatRootPaneUI public class FlatRootPaneUI
extends BasicRootPaneUI extends BasicRootPaneUI
{ {
private static ComponentUI instance; // check this field before using class JBRCustomDecorations to avoid unnecessary loading of that class
static final boolean canUseJBRCustomDecorations
= SystemInfo.isJetBrainsJVM_11_orLater && SystemInfo.isWindows_10_orLater;
protected JRootPane rootPane;
protected FlatTitlePane titlePane;
protected FlatWindowResizer windowResizer;
private LayoutManager oldLayout;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
if( instance == null ) return new FlatRootPaneUI();
instance = new FlatRootPaneUI(); }
return instance;
@Override
public void installUI( JComponent c ) {
super.installUI( c );
rootPane = (JRootPane) c;
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
installClientDecorations();
if( canUseJBRCustomDecorations )
JBRCustomDecorations.install( rootPane );
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
uninstallClientDecorations();
rootPane = null;
}
@Override
protected void installDefaults( JRootPane c ) {
super.installDefaults( c );
// Update background color of JFrame or JDialog parent to avoid bad border
// on HiDPI screens when switching from light to dark Laf.
// The background of JFrame is initialized in JFrame.frameInit() and
// the background of JDialog in JDialog.dialogInit(),
// but it was not updated when switching Laf.
Container parent = c.getParent();
if( parent instanceof JFrame || parent instanceof JDialog ) {
Color background = parent.getBackground();
if( background == null || background instanceof UIResource )
parent.setBackground( UIManager.getColor( "control" ) );
}
// enable dark window appearance on macOS when running in JetBrains Runtime
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater ) {
LookAndFeel laf = UIManager.getLookAndFeel();
boolean isDark = laf instanceof FlatLaf && ((FlatLaf)laf).isDark();
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", isDark );
}
}
protected void installClientDecorations() {
boolean isJBRSupported = canUseJBRCustomDecorations && JBRCustomDecorations.isSupported();
// install border
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE && !isJBRSupported )
LookAndFeel.installBorder( rootPane, "RootPane.border" );
else
LookAndFeel.uninstallBorder( rootPane );
// install title pane
setTitlePane( createTitlePane() );
// install layout
oldLayout = rootPane.getLayout();
rootPane.setLayout( createRootLayout() );
// install window resizer
if( !isJBRSupported )
windowResizer = createWindowResizer();
}
protected void uninstallClientDecorations() {
LookAndFeel.uninstallBorder( rootPane );
setTitlePane( null );
if( windowResizer != null ) {
windowResizer.uninstall();
windowResizer = null;
}
if( oldLayout != null ) {
rootPane.setLayout( oldLayout );
oldLayout = null;
}
if( rootPane.getWindowDecorationStyle() == JRootPane.NONE ) {
rootPane.revalidate();
rootPane.repaint();
}
}
protected FlatRootLayout createRootLayout() {
return new FlatRootLayout();
}
protected FlatWindowResizer createWindowResizer() {
return new FlatWindowResizer( rootPane );
}
protected FlatTitlePane createTitlePane() {
return new FlatTitlePane( rootPane );
}
// layer title pane under frame content layer to allow placing menu bar over title pane
protected final static Integer TITLE_PANE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 1;
protected void setTitlePane( FlatTitlePane newTitlePane ) {
JLayeredPane layeredPane = rootPane.getLayeredPane();
if( titlePane != null )
layeredPane.remove( titlePane );
if( newTitlePane != null )
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
titlePane = newTitlePane;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
switch( e.getPropertyName() ) {
case "windowDecorationStyle":
uninstallClientDecorations();
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
installClientDecorations();
break;
case FlatClientProperties.MENU_BAR_EMBEDDED:
if( titlePane != null ) {
titlePane.menuBarChanged();
rootPane.revalidate();
rootPane.repaint();
}
break;
}
}
//---- class FlatRootLayout -----------------------------------------------
protected class FlatRootLayout
implements LayoutManager2
{
@Override public void addLayoutComponent( String name, Component comp ) {}
@Override public void addLayoutComponent( Component comp, Object constraints ) {}
@Override public void removeLayoutComponent( Component comp ) {}
@Override
public Dimension preferredLayoutSize( Container parent ) {
return computeLayoutSize( parent, c -> c.getPreferredSize() );
}
@Override
public Dimension minimumLayoutSize( Container parent ) {
return computeLayoutSize( parent, c -> c.getMinimumSize() );
}
@Override
public Dimension maximumLayoutSize( Container parent ) {
return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
}
private Dimension computeLayoutSize( Container parent, Function<Component, Dimension> getSizeFunc ) {
JRootPane rootPane = (JRootPane) parent;
Dimension titlePaneSize = (titlePane != null)
? getSizeFunc.apply( titlePane )
: new Dimension();
Dimension contentSize = (rootPane.getContentPane() != null)
? getSizeFunc.apply( rootPane.getContentPane() )
: rootPane.getSize();
int width = Math.max( titlePaneSize.width, contentSize.width );
int height = titlePaneSize.height + contentSize.height;
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
Dimension menuBarSize = (rootPane.getJMenuBar() != null)
? getSizeFunc.apply( rootPane.getJMenuBar() )
: new Dimension();
width = Math.max( width, menuBarSize.width );
height += menuBarSize.height;
}
Insets insets = rootPane.getInsets();
return new Dimension(
width + insets.left + insets.right,
height + insets.top + insets.bottom );
}
@Override
public void layoutContainer( Container parent ) {
JRootPane rootPane = (JRootPane) parent;
Insets insets = rootPane.getInsets();
int x = insets.left;
int y = insets.top;
int width = rootPane.getWidth() - insets.left - insets.right;
int height = rootPane.getHeight() - insets.top - insets.bottom;
if( rootPane.getLayeredPane() != null )
rootPane.getLayeredPane().setBounds( x, y, width, height );
if( rootPane.getGlassPane() != null )
rootPane.getGlassPane().setBounds( x, y, width, height );
int nextY = 0;
if( titlePane != null ) {
Dimension prefSize = titlePane.getPreferredSize();
titlePane.setBounds( 0, 0, width, prefSize.height );
nextY += prefSize.height;
}
JMenuBar menuBar = rootPane.getJMenuBar();
if( menuBar != null ) {
if( titlePane != null && titlePane.isMenuBarEmbedded() ) {
titlePane.validate();
menuBar.setBounds( titlePane.getMenuBarBounds() );
} else {
Dimension prefSize = menuBar.getPreferredSize();
menuBar.setBounds( 0, nextY, width, prefSize.height );
nextY += prefSize.height;
}
}
Container contentPane = rootPane.getContentPane();
if( contentPane != null )
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );
}
@Override
public void invalidateLayout( Container parent ) {
if( titlePane != null )
titlePane.menuBarChanged();
}
@Override
public float getLayoutAlignmentX( Container target ) {
return 0;
}
@Override
public float getLayoutAlignmentY( Container target ) {
return 0;
}
}
//---- class FlatWindowBorder ---------------------------------------------
public static class FlatWindowBorder
extends BorderUIResource.EmptyBorderUIResource
{
protected final Color activeBorderColor = UIManager.getColor( "RootPane.activeBorderColor" );
protected final Color inactiveBorderColor = UIManager.getColor( "RootPane.inactiveBorderColor" );
protected final Color baseBorderColor = UIManager.getColor( "Panel.background" );
public FlatWindowBorder() {
super( 1, 1, 1, 1 );
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
if( isWindowMaximized( c ) ) {
// hide border if window is maximized
insets.top = insets.left = insets.bottom = insets.right = 0;
return insets;
} else
return super.getBorderInsets( c, insets );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( isWindowMaximized( c ) )
return;
Container parent = c.getParent();
boolean active = parent instanceof Window ? ((Window)parent).isActive() : false;
g.setColor( FlatUIUtils.deriveColor( active ? activeBorderColor : inactiveBorderColor, baseBorderColor ) );
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
}
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
g.drawRect( x, y, width - 1, height - 1 );
}
protected boolean isWindowMaximized( Component c ) {
Container parent = c.getParent();
return parent instanceof Frame
? (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
: false;
}
} }
} }

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
@@ -28,6 +30,7 @@ import java.util.Objects;
import javax.swing.InputMap; import javax.swing.InputMap;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -52,29 +55,49 @@ import com.formdev.flatlaf.util.UIScale;
* *
* <!-- FlatScrollBarUI --> * <!-- FlatScrollBarUI -->
* *
* @uiDefault ScrollBar.hoverTrackColor Color * @uiDefault ScrollBar.trackInsets Insets
* @uiDefault ScrollBar.hoverThumbColor Color * @uiDefault ScrollBar.thumbInsets Insets
* @uiDefault ScrollBar.trackArc int
* @uiDefault ScrollBar.thumbArc int
* @uiDefault ScrollBar.hoverTrackColor Color optional
* @uiDefault ScrollBar.hoverThumbColor Color optional
* @uiDefault ScrollBar.hoverThumbWithTrack boolean
* @uiDefault ScrollBar.pressedTrackColor Color optional
* @uiDefault ScrollBar.pressedThumbColor Color optional
* @uiDefault ScrollBar.pressedThumbWithTrack boolean
* @uiDefault Component.arrowType String triangle (default) or chevron * @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault ScrollBar.showButtons boolean * @uiDefault ScrollBar.showButtons boolean
* @uiDefault ScrollBar.buttonArrowColor Color * @uiDefault ScrollBar.buttonArrowColor Color
* @uiDefault ScrollBar.buttonDisabledArrowColor Color * @uiDefault ScrollBar.buttonDisabledArrowColor Color
* @uiDefault ScrollBar.hoverButtonBackground Color optional
* @uiDefault ScrollBar.pressedButtonBackground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatScrollBarUI public class FlatScrollBarUI
extends BasicScrollBarUI extends BasicScrollBarUI
{ {
protected Insets trackInsets;
protected Insets thumbInsets;
protected int trackArc;
protected int thumbArc;
protected Color hoverTrackColor; protected Color hoverTrackColor;
protected Color hoverThumbColor; protected Color hoverThumbColor;
protected boolean hoverThumbWithTrack;
protected Color pressedTrackColor;
protected Color pressedThumbColor;
protected boolean pressedThumbWithTrack;
protected boolean showButtons; protected boolean showButtons;
protected String arrowType; protected String arrowType;
protected Color buttonArrowColor; protected Color buttonArrowColor;
protected Color buttonDisabledArrowColor; protected Color buttonDisabledArrowColor;
protected Color hoverButtonBackground;
protected Color pressedButtonBackground;
private MouseAdapter hoverListener; private MouseAdapter hoverListener;
private boolean hoverTrack; protected boolean hoverTrack;
private boolean hoverThumb; protected boolean hoverThumb;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatScrollBarUI(); return new FlatScrollBarUI();
@@ -102,24 +125,40 @@ public class FlatScrollBarUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
thumbArc = UIManager.getInt( "ScrollBar.thumbArc" );
hoverTrackColor = UIManager.getColor( "ScrollBar.hoverTrackColor" ); hoverTrackColor = UIManager.getColor( "ScrollBar.hoverTrackColor" );
hoverThumbColor = UIManager.getColor( "ScrollBar.hoverThumbColor" ); hoverThumbColor = UIManager.getColor( "ScrollBar.hoverThumbColor" );
hoverThumbWithTrack = UIManager.getBoolean( "ScrollBar.hoverThumbWithTrack" );
pressedTrackColor = UIManager.getColor( "ScrollBar.pressedTrackColor" );
pressedThumbColor = UIManager.getColor( "ScrollBar.pressedThumbColor" );
pressedThumbWithTrack = UIManager.getBoolean( "ScrollBar.pressedThumbWithTrack" );
showButtons = UIManager.getBoolean( "ScrollBar.showButtons" ); showButtons = UIManager.getBoolean( "ScrollBar.showButtons" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
buttonArrowColor = UIManager.getColor( "ScrollBar.buttonArrowColor" ); buttonArrowColor = UIManager.getColor( "ScrollBar.buttonArrowColor" );
buttonDisabledArrowColor = UIManager.getColor( "ScrollBar.buttonDisabledArrowColor" ); buttonDisabledArrowColor = UIManager.getColor( "ScrollBar.buttonDisabledArrowColor" );
hoverButtonBackground = UIManager.getColor( "ScrollBar.hoverButtonBackground" );
pressedButtonBackground = UIManager.getColor( "ScrollBar.pressedButtonBackground" );
} }
@Override @Override
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
trackInsets = null;
thumbInsets = null;
hoverTrackColor = null; hoverTrackColor = null;
hoverThumbColor = null; hoverThumbColor = null;
pressedTrackColor = null;
pressedThumbColor = null;
buttonArrowColor = null; buttonArrowColor = null;
buttonDisabledArrowColor = null; buttonDisabledArrowColor = null;
hoverButtonBackground = null;
pressedButtonBackground = null;
} }
@Override @Override
@@ -159,50 +198,61 @@ public class FlatScrollBarUI
@Override @Override
protected JButton createDecreaseButton( int orientation ) { protected JButton createDecreaseButton( int orientation ) {
return createArrowButton( orientation ); return new FlatScrollBarButton( orientation );
} }
@Override @Override
protected JButton createIncreaseButton( int orientation ) { protected JButton createIncreaseButton( int orientation ) {
return createArrowButton( orientation ); return new FlatScrollBarButton( orientation );
} }
private JButton createArrowButton( int orientation ) { protected boolean isShowButtons() {
FlatArrowButton button = new FlatArrowButton( orientation,
arrowType, buttonArrowColor, buttonDisabledArrowColor, null, hoverTrackColor )
{
@Override
public Dimension getPreferredSize() {
if( isShowButtons() ) {
int w = UIScale.scale( scrollBarWidth );
return new Dimension( w, w );
} else
return new Dimension();
}
@Override
public Dimension getMinimumSize() {
return isShowButtons() ? super.getMinimumSize() : new Dimension();
}
@Override
public Dimension getMaximumSize() {
return isShowButtons() ? super.getMaximumSize() : new Dimension();
}
};
button.setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
button.setFocusable( false );
button.setRequestFocusEnabled( false );
return button;
}
private boolean isShowButtons() {
Object showButtons = scrollbar.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS ); Object showButtons = scrollbar.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane ) if( showButtons == null && scrollbar.getParent() instanceof JScrollPane )
showButtons = ((JScrollPane)scrollbar.getParent()).getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS ); showButtons = ((JScrollPane)scrollbar.getParent()).getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons; return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons;
} }
@Override
public void paint( Graphics g, JComponent c ) {
FlatUIUtils.setRenderingHints( (Graphics2D) g );
super.paint( g, c );
}
@Override
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) {
g.setColor( getTrackColor( c, hoverTrack, isPressed && hoverTrack && !hoverThumb ) );
paintTrackOrThumb( g, c, trackBounds, trackInsets, trackArc );
}
@Override
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) {
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() )
return;
g.setColor( getThumbColor( c, hoverThumb || (hoverThumbWithTrack && hoverTrack),
isPressed && (hoverThumb || (pressedThumbWithTrack && hoverTrack)) ) );
paintTrackOrThumb( g, c, thumbBounds, thumbInsets, thumbArc );
}
protected void paintTrackOrThumb( Graphics g, JComponent c, Rectangle bounds, Insets insets, int arc ) {
// rotate insets for horizontal orientation because they are given for vertical orientation
if( scrollbar.getOrientation() == JScrollBar.HORIZONTAL )
insets = new Insets( insets.right, insets.top, insets.left, insets.bottom );
// subtract insets from bounds
bounds = FlatUIUtils.subtractInsets( bounds, UIScale.scale( insets ) );
if( arc <= 0 ) {
// paint rectangle
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
} else {
// paint round rectangle
arc = Math.min( UIScale.scale( arc ), Math.min( bounds.width, bounds.height ) );
g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, arc, arc );
}
}
@Override @Override
protected void paintDecreaseHighlight( Graphics g ) { protected void paintDecreaseHighlight( Graphics g ) {
// do not paint // do not paint
@@ -213,29 +263,33 @@ public class FlatScrollBarUI
// do not paint // do not paint
} }
@Override protected Color getTrackColor( JComponent c, boolean hover, boolean pressed ) {
protected void paintTrack( Graphics g, JComponent c, Rectangle trackBounds ) { Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
g.setColor( hoverTrack ? hoverTrackColor : trackColor ); return (pressed && pressedTrackColor != null)
g.fillRect( trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height ); ? FlatUIUtils.deriveColor( pressedTrackColor, trackColor )
: ((hover && hoverTrackColor != null)
? FlatUIUtils.deriveColor( hoverTrackColor, trackColor )
: trackColor);
} }
@Override protected Color getThumbColor( JComponent c, boolean hover, boolean pressed ) {
protected void paintThumb( Graphics g, JComponent c, Rectangle thumbBounds ) { Color trackColor = FlatUIUtils.deriveColor( this.trackColor, c.getBackground() );
if( thumbBounds.isEmpty() || !scrollbar.isEnabled() ) Color thumbColor = FlatUIUtils.deriveColor( this.thumbColor, trackColor );
return; return (pressed && pressedThumbColor != null)
? FlatUIUtils.deriveColor( pressedThumbColor, thumbColor )
g.setColor( hoverThumb ? hoverThumbColor : thumbColor ); : ((hover && hoverThumbColor != null)
g.fillRect( thumbBounds.x, thumbBounds.y, thumbBounds.width, thumbBounds.height ); ? FlatUIUtils.deriveColor( hoverThumbColor, thumbColor )
: thumbColor);
} }
@Override @Override
protected Dimension getMinimumThumbSize() { protected Dimension getMinimumThumbSize() {
return UIScale.scale( super.getMinimumThumbSize() ); return UIScale.scale( FlatUIUtils.addInsets( super.getMinimumThumbSize(), thumbInsets ) );
} }
@Override @Override
protected Dimension getMaximumThumbSize() { protected Dimension getMaximumThumbSize() {
return UIScale.scale( super.getMaximumThumbSize() ); return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) );
} }
//---- class ScrollBarHoverListener --------------------------------------- //---- class ScrollBarHoverListener ---------------------------------------
@@ -263,11 +317,14 @@ public class FlatScrollBarUI
@Override @Override
public void mousePressed( MouseEvent e ) { public void mousePressed( MouseEvent e ) {
isPressed = true; isPressed = true;
repaint();
} }
@Override @Override
public void mouseReleased( MouseEvent e ) { public void mouseReleased( MouseEvent e ) {
isPressed = false; isPressed = false;
repaint();
update( e.getX(), e.getY() ); update( e.getX(), e.getY() );
} }
@@ -286,4 +343,49 @@ public class FlatScrollBarUI
scrollbar.repaint(); scrollbar.repaint();
} }
} }
//---- class FlatScrollBarButton ------------------------------------------
protected class FlatScrollBarButton
extends FlatArrowButton
{
protected FlatScrollBarButton( int direction ) {
this( direction, arrowType, buttonArrowColor, buttonDisabledArrowColor,
null, hoverButtonBackground, pressedButtonBackground );
}
protected FlatScrollBarButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground, Color pressedBackground )
{
super( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, pressedBackground );
setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
setFocusable( false );
setRequestFocusEnabled( false );
}
@Override
protected Color deriveBackground( Color background ) {
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
}
@Override
public Dimension getPreferredSize() {
if( isShowButtons() ) {
int w = UIScale.scale( scrollBarWidth );
return new Dimension( w, w );
} else
return new Dimension();
}
@Override
public Dimension getMinimumSize() {
return isShowButtons() ? super.getMinimumSize() : new Dimension();
}
@Override
public Dimension getMaximumSize() {
return isShowButtons() ? super.getMaximumSize() : new Dimension();
}
}
} }

View File

@@ -114,10 +114,7 @@ public class FlatScrollPaneUI
return new BasicScrollPaneUI.MouseWheelHandler() { return new BasicScrollPaneUI.MouseWheelHandler() {
@Override @Override
public void mouseWheelMoved( MouseWheelEvent e ) { public void mouseWheelMoved( MouseWheelEvent e ) {
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow if( isSmoothScrollingEnabled() &&
// applications to turn smooth scrolling on or off at any time
// (e.g. in application options dialog).
if( UIManager.getBoolean( "ScrollPane.smoothScrolling" ) &&
scrollpane.isWheelScrollingEnabled() && scrollpane.isWheelScrollingEnabled() &&
e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL && e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL &&
e.getPreciseWheelRotation() != 0 && e.getPreciseWheelRotation() != 0 &&
@@ -130,6 +127,17 @@ public class FlatScrollPaneUI
}; };
} }
protected boolean isSmoothScrollingEnabled() {
Object smoothScrolling = scrollpane.getClientProperty( FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING );
if( smoothScrolling instanceof Boolean )
return (Boolean) smoothScrolling;
// Note: Getting UI value "ScrollPane.smoothScrolling" here to allow
// applications to turn smooth scrolling on or off at any time
// (e.g. in application options dialog).
return UIManager.getBoolean( "ScrollPane.smoothScrolling" );
}
private static final double EPSILON = 1e-5d; private static final double EPSILON = 1e-5d;
private void mouseWheelMovedSmooth( MouseWheelEvent e ) { private void mouseWheelMovedSmooth( MouseWheelEvent e ) {

View File

@@ -201,7 +201,7 @@ public class FlatSliderUI
} }
if( coloredTrack != null ) { if( coloredTrack != null ) {
FlatUIUtils.setColor( g, FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor ); g.setColor( FlatUIUtils.deriveColor( FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), thumbColor ) );
((Graphics2D)g).fill( coloredTrack ); ((Graphics2D)g).fill( coloredTrack );
} }
@@ -211,10 +211,10 @@ public class FlatSliderUI
@Override @Override
public void paintThumb( Graphics g ) { public void paintThumb( Graphics g ) {
FlatUIUtils.setColor( g, slider.isEnabled() g.setColor( FlatUIUtils.deriveColor( slider.isEnabled()
? (FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor)) ? (FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor))
: disabledForeground, : disabledForeground,
thumbColor ); thumbColor ) );
if( isRoundThumb() ) if( isRoundThumb() )
g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height ); g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height );

View File

@@ -58,6 +58,7 @@ import com.formdev.flatlaf.FlatClientProperties;
* <!-- FlatSpinnerUI --> * <!-- FlatSpinnerUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Spinner.buttonStyle String button (default) or none
* @uiDefault Component.arrowType String triangle (default) or chevron * @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Component.borderColor Color * @uiDefault Component.borderColor Color
@@ -78,6 +79,7 @@ public class FlatSpinnerUI
private Handler handler; private Handler handler;
protected int minimumWidth; protected int minimumWidth;
protected String buttonStyle;
protected String arrowType; protected String arrowType;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color borderColor; protected Color borderColor;
@@ -101,6 +103,7 @@ public class FlatSpinnerUI
LookAndFeel.installProperty( spinner, "opaque", false ); LookAndFeel.installProperty( spinner, "opaque", false );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
buttonStyle = UIManager.getString( "Spinner.buttonStyle" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
borderColor = UIManager.getColor( "Component.borderColor" ); borderColor = UIManager.getColor( "Component.borderColor" );
@@ -141,6 +144,7 @@ public class FlatSpinnerUI
super.installListeners(); super.installListeners();
addEditorFocusListener( spinner.getEditor() ); addEditorFocusListener( spinner.getEditor() );
spinner.addFocusListener( getHandler() );
spinner.addPropertyChangeListener( getHandler() ); spinner.addPropertyChangeListener( getHandler() );
} }
@@ -149,6 +153,7 @@ public class FlatSpinnerUI
super.uninstallListeners(); super.uninstallListeners();
removeEditorFocusListener( spinner.getEditor() ); removeEditorFocusListener( spinner.getEditor() );
spinner.removeFocusListener( getHandler() );
spinner.removePropertyChangeListener( getHandler() ); spinner.removePropertyChangeListener( getHandler() );
handler = null; handler = null;
@@ -201,17 +206,27 @@ public class FlatSpinnerUI
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
// is used, then the text field is updated after the spinner and the // is used, then the text field is updated after the spinner and the
// colors are again replaced with default colors // colors are again replaced with default colors
textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) ); textField.setForeground( FlatUIUtils.nonUIResource( getForeground( true ) ) );
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) ); textField.setDisabledTextColor( FlatUIUtils.nonUIResource( getForeground( false ) ) );
} }
} }
private JTextField getEditorTextField( JComponent editor ) { private static JTextField getEditorTextField( JComponent editor ) {
return editor instanceof JSpinner.DefaultEditor return editor instanceof JSpinner.DefaultEditor
? ((JSpinner.DefaultEditor)editor).getTextField() ? ((JSpinner.DefaultEditor)editor).getTextField()
: null; : null;
} }
protected Color getBackground( boolean enabled ) {
return enabled
? spinner.getBackground()
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground);
}
protected Color getForeground( boolean enabled ) {
return enabled ? spinner.getForeground() : disabledForeground;
}
@Override @Override
protected LayoutManager createLayout() { protected LayoutManager createLayout() {
return getHandler(); return getHandler();
@@ -256,17 +271,16 @@ public class FlatSpinnerUI
Component nextButton = getHandler().nextButton; Component nextButton = getHandler().nextButton;
int arrowX = nextButton.getX(); int arrowX = nextButton.getX();
int arrowWidth = nextButton.getWidth(); int arrowWidth = nextButton.getWidth();
boolean paintButton = !"none".equals( buttonStyle );
boolean enabled = spinner.isEnabled(); boolean enabled = spinner.isEnabled();
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled g2.setColor( getBackground( enabled ) );
? c.getBackground()
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground) );
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow buttons background // paint arrow buttons background
if( enabled ) { if( paintButton && enabled ) {
g2.setColor( buttonBackground ); g2.setColor( buttonBackground );
Shape oldClip = g2.getClip(); Shape oldClip = g2.getClip();
if( isLeftToRight ) if( isLeftToRight )
@@ -278,10 +292,12 @@ public class FlatSpinnerUI
} }
// paint vertical line between value and arrow buttons // paint vertical line between value and arrow buttons
g2.setColor( enabled ? borderColor : disabledBorderColor ); if( paintButton ) {
float lw = scale( 1f ); g2.setColor( enabled ? borderColor : disabledBorderColor );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw; float lw = scale( 1f );
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) ); float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - 1 - (focusWidth * 2) ) );
}
paint( g, c ); paint( g, c );
} }
@@ -365,12 +381,14 @@ public class FlatSpinnerUI
if( editor != null ) if( editor != null )
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) ); editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) );
int nextHeight = Math.round( buttonsRect.height / 2f ); int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
if( nextButton != null ) if( nextButton != null )
nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight ); nextButton.setBounds( buttonsRect.x, buttonsRect.y, buttonsRect.width, nextHeight );
if( previousButton != null ) { if( previousButton != null ) {
previousButton.setBounds( buttonsRect.x, buttonsRect.y + nextHeight, // for precise layout of arrows, the "previous" button has the same height
buttonsRect.width, buttonsRect.height - nextHeight ); // as the "next" button and may overlap on uneven buttonsRect.height
int previousY = buttonsRect.y + buttonsRect.height - nextHeight;
previousButton.setBounds( buttonsRect.x, previousY, buttonsRect.width, nextHeight );
} }
} }
@@ -379,6 +397,13 @@ public class FlatSpinnerUI
@Override @Override
public void focusGained( FocusEvent e ) { public void focusGained( FocusEvent e ) {
spinner.repaint(); spinner.repaint();
// if spinner gained focus, transfer it to the editor text field
if( e.getComponent() == spinner ) {
JTextField textField = getEditorTextField( spinner.getEditor() );
if( textField != null )
textField.requestFocusInWindow();
}
} }
@Override @Override
@@ -399,6 +424,10 @@ public class FlatSpinnerUI
case FlatClientProperties.COMPONENT_ROUND_RECT: case FlatClientProperties.COMPONENT_ROUND_RECT:
spinner.repaint(); spinner.repaint();
break; break;
case FlatClientProperties.MINIMUM_WIDTH:
spinner.revalidate();
break;
} }
} }
} }

View File

@@ -87,10 +87,10 @@ public class FlatSplitPaneUI
//---- class FlatSplitPaneDivider ----------------------------------------- //---- class FlatSplitPaneDivider -----------------------------------------
private class FlatSplitPaneDivider protected class FlatSplitPaneDivider
extends BasicSplitPaneDivider extends BasicSplitPaneDivider
{ {
public FlatSplitPaneDivider( BasicSplitPaneUI ui ) { protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
super( ui ); super( ui );
} }

View File

@@ -333,28 +333,30 @@ public class FlatTabbedPaneUI
// paint tab separators // paint tab separators
if( clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_TAB_SEPARATORS, showTabSeparators ) && if( clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_TAB_SEPARATORS, showTabSeparators ) &&
!isLastInRun( tabIndex ) ) !isLastInRun( tabIndex ) )
{ paintTabSeparator( g, tabPlacement, x, y, w, h );
float sepWidth = UIScale.scale( 1f );
float offset = tabSeparatorsFullHeight ? 0 : UIScale.scale( 5f );
g.setColor( (tabSeparatorColor != null) ? tabSeparatorColor : contentAreaColor );
if( tabPlacement == LEFT || tabPlacement == RIGHT ) {
// paint tab separator at bottom side
((Graphics2D)g).fill( new Rectangle2D.Float( x + offset, y + h - sepWidth, w - (offset * 2), sepWidth ) );
} else if( tabPane.getComponentOrientation().isLeftToRight() ) {
// paint tab separator at right side
((Graphics2D)g).fill( new Rectangle2D.Float( x + w - sepWidth, y + offset, sepWidth, h - (offset * 2) ) );
} else {
// paint tab separator at left side
((Graphics2D)g).fill( new Rectangle2D.Float( x, y + offset, sepWidth, h - (offset * 2) ) );
}
}
if( isSelected ) if( isSelected )
paintTabSelection( g, tabPlacement, x, y, w, h ); paintTabSelection( g, tabPlacement, x, y, w, h );
} }
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) { protected void paintTabSeparator( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
float sepWidth = UIScale.scale( 1f );
float offset = tabSeparatorsFullHeight ? 0 : UIScale.scale( 5f );
g.setColor( (tabSeparatorColor != null) ? tabSeparatorColor : contentAreaColor );
if( tabPlacement == LEFT || tabPlacement == RIGHT ) {
// paint tab separator at bottom side
((Graphics2D)g).fill( new Rectangle2D.Float( x + offset, y + h - sepWidth, w - (offset * 2), sepWidth ) );
} else if( tabPane.getComponentOrientation().isLeftToRight() ) {
// paint tab separator at right side
((Graphics2D)g).fill( new Rectangle2D.Float( x + w - sepWidth, y + offset, sepWidth, h - (offset * 2) ) );
} else {
// paint tab separator at left side
((Graphics2D)g).fill( new Rectangle2D.Float( x, y + offset, sepWidth, h - (offset * 2) ) );
}
}
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
// increase clip bounds in scroll-tab-layout to paint over the separator line // increase clip bounds in scroll-tab-layout to paint over the separator line
Rectangle clipBounds = isScrollTabLayout() ? g.getClipBounds() : null; Rectangle clipBounds = isScrollTabLayout() ? g.getClipBounds() : null;
if( clipBounds != null ) { if( clipBounds != null ) {

View File

@@ -86,7 +86,7 @@ public class FlatTableCellBorder
/** /**
* Checks whether at least one selected cell is editable. * Checks whether at least one selected cell is editable.
*/ */
private boolean isSelectionEditable( JTable table ) { protected boolean isSelectionEditable( JTable table ) {
if( table.getRowSelectionAllowed() ) { if( table.getRowSelectionAllowed() ) {
int columnCount = table.getColumnCount(); int columnCount = table.getColumnCount();
int[] selectedRows = table.getSelectedRows(); int[] selectedRows = table.getSelectedRows();

View File

@@ -86,26 +86,12 @@ public class FlatTableHeaderUI
case "top": sortIconPosition = SwingConstants.TOP; break; case "top": sortIconPosition = SwingConstants.TOP; break;
case "bottom": sortIconPosition = SwingConstants.BOTTOM; break; case "bottom": sortIconPosition = SwingConstants.BOTTOM; break;
} }
// use own renderer if necessary
if( sortIconPosition != SwingConstants.RIGHT ) {
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
if( defaultRenderer instanceof UIResource )
header.setDefaultRenderer( new FlatTableCellHeaderRenderer( defaultRenderer ) );
}
} }
@Override @Override
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
// restore default renderer
TableCellRenderer defaultRenderer = header.getDefaultRenderer();
if( defaultRenderer instanceof FlatTableCellHeaderRenderer ) {
((FlatTableCellHeaderRenderer)defaultRenderer).reset();
header.setDefaultRenderer( ((FlatTableCellHeaderRenderer)defaultRenderer).delegate );
}
separatorColor = null; separatorColor = null;
bottomSeparatorColor = null; bottomSeparatorColor = null;
} }
@@ -125,8 +111,22 @@ public class FlatTableHeaderUI
if( paintBorders ) if( paintBorders )
paintColumnBorders( g, c ); paintColumnBorders( g, c );
// temporary use own default renderer if necessary
FlatTableCellHeaderRenderer sortIconRenderer = null;
if( sortIconPosition != SwingConstants.RIGHT ) {
sortIconRenderer = new FlatTableCellHeaderRenderer( header.getDefaultRenderer() );
header.setDefaultRenderer( sortIconRenderer );
}
// paint header
super.paint( g, c ); super.paint( g, c );
// restore default renderer
if( sortIconRenderer != null ) {
sortIconRenderer.reset();
header.setDefaultRenderer( sortIconRenderer.delegate );
}
if( paintBorders ) if( paintBorders )
paintDraggedColumnBorders( g, c ); paintDraggedColumnBorders( g, c );
} }
@@ -257,6 +257,7 @@ public class FlatTableHeaderUI
{ {
private final TableCellRenderer delegate; private final TableCellRenderer delegate;
private JLabel l;
private int oldHorizontalTextPosition = -1; private int oldHorizontalTextPosition = -1;
private Border origBorder; private Border origBorder;
private Icon sortIcon; private Icon sortIcon;
@@ -273,7 +274,7 @@ public class FlatTableHeaderUI
if( !(c instanceof JLabel) ) if( !(c instanceof JLabel) )
return c; return c;
JLabel l = (JLabel) c; l = (JLabel) c;
if( sortIconPosition == SwingConstants.LEFT ) { if( sortIconPosition == SwingConstants.LEFT ) {
if( oldHorizontalTextPosition < 0 ) if( oldHorizontalTextPosition < 0 )
@@ -291,11 +292,8 @@ public class FlatTableHeaderUI
} }
void reset() { void reset() {
if( sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 ) { if( l != null && sortIconPosition == SwingConstants.LEFT && oldHorizontalTextPosition >= 0 )
Component c = getTableCellRendererComponent( header.getTable(), "", false, false, -1, 0 ); l.setHorizontalTextPosition( oldHorizontalTextPosition );
if( c instanceof JLabel && ((JLabel)c).getHorizontalTextPosition() == SwingConstants.RIGHT )
((JLabel)c).setHorizontalTextPosition( oldHorizontalTextPosition );
}
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JCheckBox; import javax.swing.JCheckBox;
@@ -70,6 +71,10 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Table.cellFocusColor Color * @uiDefault Table.cellFocusColor Color
* @uiDefault Table.showCellFocusIndicator boolean * @uiDefault Table.showCellFocusIndicator boolean
* *
* <!-- FlatInputMaps -->
*
* @uiDefault Table.consistentHomeEndKeyBehavior boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatTableUI public class FlatTableUI
@@ -92,16 +97,6 @@ public class FlatTableUI
return new FlatTableUI(); return new FlatTableUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -174,7 +169,11 @@ public class FlatTableUI
@Override @Override
public void focusLost( FocusEvent e ) { public void focusLost( FocusEvent e ) {
super.focusLost( e ); super.focusLost( e );
toggleSelectionColors();
// use invokeLater for the case that the window is deactivated
EventQueue.invokeLater( () -> {
toggleSelectionColors();
} );
} }
}; };
} }

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -26,6 +28,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.plaf.basic.BasicTextAreaUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
@@ -82,6 +85,17 @@ public class FlatTextAreaUI
inactiveBackground = null; inactiveBackground = null;
} }
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatEditorPaneUI.propertyChange( getComponent(), e );
}
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -32,13 +32,13 @@ import javax.swing.JSpinner;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.Caret; import javax.swing.text.Caret;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
@@ -136,6 +136,10 @@ public class FlatTextFieldUI
case FlatClientProperties.COMPONENT_ROUND_RECT: case FlatClientProperties.COMPONENT_ROUND_RECT:
c.repaint(); c.repaint();
break; break;
case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate();
break;
} }
} }
@@ -143,7 +147,8 @@ public class FlatTextFieldUI
protected void paintSafely( Graphics g ) { protected void paintSafely( Graphics g ) {
paintBackground( g, getComponent(), isIntelliJTheme ); paintBackground( g, getComponent(), isIntelliJTheme );
paintPlaceholder( g, getComponent(), placeholderForeground ); paintPlaceholder( g, getComponent(), placeholderForeground );
super.paintSafely( g );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
} }
@Override @Override
@@ -152,14 +157,12 @@ public class FlatTextFieldUI
} }
static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) { static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) {
Border border = c.getBorder();
// do not paint background if: // do not paint background if:
// - not opaque and // - not opaque and
// - border is not a flat border and // - border is not a flat border and
// - opaque was explicitly set (to false) // - opaque was explicitly set (to false)
// (same behaviour as in AquaTextFieldUI) // (same behaviour as in AquaTextFieldUI)
if( !c.isOpaque() && !(border instanceof FlatBorder) && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) ) if( !c.isOpaque() && FlatUIUtils.getOutsideFlatBorder( c ) == null && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
return; return;
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = FlatUIUtils.getBorderFocusWidth( c );

View File

@@ -18,6 +18,8 @@ package com.formdev.flatlaf.ui;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -25,6 +27,7 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
@@ -82,6 +85,12 @@ public class FlatTextPaneUI
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatEditorPaneUI.propertyChange( getComponent(), e );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return FlatEditorPaneUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth ); return FlatEditorPaneUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
@@ -92,6 +101,11 @@ public class FlatTextPaneUI
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
} }
@Override
protected void paintSafely( Graphics g ) {
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); JTextComponent c = getComponent();

View File

@@ -0,0 +1,800 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.accessibility.AccessibleContext;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.JBRCustomDecorations.JBRWindowTopBorder;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF title bar.
*
* @uiDefault TitlePane.background Color
* @uiDefault TitlePane.inactiveBackground Color
* @uiDefault TitlePane.foreground Color
* @uiDefault TitlePane.inactiveForeground Color
* @uiDefault TitlePane.embeddedForeground Color
* @uiDefault TitlePane.iconSize Dimension
* @uiDefault TitlePane.iconMargins Insets
* @uiDefault TitlePane.titleMargins Insets
* @uiDefault TitlePane.menuBarMargins Insets
* @uiDefault TitlePane.menuBarEmbedded boolean
* @uiDefault TitlePane.buttonMaximizedHeight int
* @uiDefault TitlePane.closeIcon Icon
* @uiDefault TitlePane.iconifyIcon Icon
* @uiDefault TitlePane.maximizeIcon Icon
* @uiDefault TitlePane.restoreIcon Icon
*
* @author Karl Tauber
*/
public class FlatTitlePane
extends JComponent
{
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
protected final Insets menuBarMargins = UIManager.getInsets( "TitlePane.menuBarMargins" );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
protected final JRootPane rootPane;
protected JPanel leftPanel;
protected JLabel iconLabel;
protected JComponent menuBarPlaceholder;
protected JLabel titleLabel;
protected JPanel buttonPanel;
protected JButton iconifyButton;
protected JButton maximizeButton;
protected JButton restoreButton;
protected JButton closeButton;
protected Window window;
private final Handler handler;
public FlatTitlePane( JRootPane rootPane ) {
this.rootPane = rootPane;
handler = createHandler();
setBorder( createTitlePaneBorder() );
addSubComponents();
activeChanged( true );
addMouseListener( handler );
addMouseMotionListener( handler );
// necessary for closing window with double-click on icon
iconLabel.addMouseListener( handler );
}
protected FlatTitlePaneBorder createTitlePaneBorder() {
return new FlatTitlePaneBorder();
}
protected Handler createHandler() {
return new Handler();
}
protected void addSubComponents() {
leftPanel = new JPanel();
iconLabel = new JLabel();
titleLabel = new JLabel();
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
leftPanel.setOpaque( false );
leftPanel.add( iconLabel );
menuBarPlaceholder = new JComponent() {
@Override
public Dimension getPreferredSize() {
JMenuBar menuBar = rootPane.getJMenuBar();
return (menuBar != null && isMenuBarEmbedded())
? FlatUIUtils.addInsets( menuBar.getPreferredSize(), UIScale.scale( menuBarMargins ) )
: new Dimension();
}
};
leftPanel.add( menuBarPlaceholder );
createButtons();
setLayout( new BorderLayout() );
add( leftPanel, BorderLayout.LINE_START );
add( titleLabel, BorderLayout.CENTER );
add( buttonPanel, BorderLayout.LINE_END );
}
protected void createButtons() {
iconifyButton = createButton( "TitlePane.iconifyIcon", "Iconify", e -> iconify() );
maximizeButton = createButton( "TitlePane.maximizeIcon", "Maximize", e -> maximize() );
restoreButton = createButton( "TitlePane.restoreIcon", "Restore", e -> restore() );
closeButton = createButton( "TitlePane.closeIcon", "Close", e -> close() );
buttonPanel = new JPanel() {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if( buttonMaximizedHeight > 0 &&
window instanceof Frame &&
(((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
{
// make title pane height smaller when frame is maximized
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
}
return size;
}
};
buttonPanel.setOpaque( false );
buttonPanel.setLayout( new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS ) );
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
// JRootPane.FRAME works only for frames (and not for dialogs)
// but at this time the owner window type is unknown (not yet added)
// so we add the iconify/maximize/restore buttons and they are hidden
// later in frameStateChanged(), which is invoked from addNotify()
restoreButton.setVisible( false );
buttonPanel.add( iconifyButton );
buttonPanel.add( maximizeButton );
buttonPanel.add( restoreButton );
}
buttonPanel.add( closeButton );
}
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
JButton button = new JButton( UIManager.getIcon( iconKey ) );
button.setFocusable( false );
button.setContentAreaFilled( false );
button.setBorder( BorderFactory.createEmptyBorder() );
button.putClientProperty( AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName );
button.addActionListener( action );
return button;
}
protected void activeChanged( boolean active ) {
boolean hasEmbeddedMenuBar = rootPane.getJMenuBar() != null && isMenuBarEmbedded();
Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground );
Color foreground = FlatUIUtils.nonUIResource( active
? (hasEmbeddedMenuBar ? embeddedForeground : activeForeground)
: inactiveForeground );
setBackground( background );
titleLabel.setForeground( foreground );
titleLabel.setHorizontalAlignment( hasEmbeddedMenuBar ? SwingConstants.CENTER : SwingConstants.LEADING );
// this is necessary because hover/pressed colors are derived from background color
iconifyButton.setBackground( background );
maximizeButton.setBackground( background );
restoreButton.setBackground( background );
closeButton.setBackground( background );
}
protected void frameStateChanged() {
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
return;
if( window instanceof Frame ) {
Frame frame = (Frame) window;
boolean resizable = frame.isResizable();
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
iconifyButton.setVisible( true );
maximizeButton.setVisible( resizable && !maximized );
restoreButton.setVisible( resizable && maximized );
if( maximized &&
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
{
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", null );
// In case that frame was maximized from custom code (e.g. when restoring
// window state on application startup), then maximized bounds is not set
// and the window would overlap Windows task bar.
// To avoid this, update maximized bounds here and if it has changed
// re-maximize windows so that maximized bounds are used.
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
updateMaximizedBounds();
Rectangle newMaximizedBounds = frame.getMaximizedBounds();
if( newMaximizedBounds != null && !newMaximizedBounds.equals( oldMaximizedBounds ) ) {
int oldExtendedState = frame.getExtendedState();
frame.setExtendedState( oldExtendedState & ~Frame.MAXIMIZED_BOTH );
frame.setExtendedState( oldExtendedState );
}
}
} else {
// hide buttons because they are only supported in frames
iconifyButton.setVisible( false );
maximizeButton.setVisible( false );
restoreButton.setVisible( false );
revalidate();
repaint();
}
}
protected void updateIcon() {
// get window images
List<Image> images = window.getIconImages();
if( images.isEmpty() ) {
// search in owners
for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) {
images = owner.getIconImages();
if( !images.isEmpty() )
break;
}
}
boolean hasIcon = true;
// set icon
if( !images.isEmpty() )
iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) );
else {
// no icon set on window --> use default icon
Icon defaultIcon = UIManager.getIcon( "InternalFrame.icon" );
if( defaultIcon != null && (defaultIcon.getIconWidth() == 0 || defaultIcon.getIconHeight() == 0) )
defaultIcon = null;
if( defaultIcon != null ) {
if( defaultIcon instanceof ImageIcon )
defaultIcon = new ScaledImageIcon( (ImageIcon) defaultIcon, iconSize.width, iconSize.height );
iconLabel.setIcon( defaultIcon );
} else
hasIcon = false;
}
// show/hide icon
iconLabel.setVisible( hasIcon );
updateJBRHitTestSpotsAndTitleBarHeightLater();
}
@Override
public void addNotify() {
super.addNotify();
uninstallWindowListeners();
window = SwingUtilities.getWindowAncestor( this );
if( window != null ) {
frameStateChanged();
activeChanged( window.isActive() );
updateIcon();
titleLabel.setText( getWindowTitle() );
installWindowListeners();
}
updateJBRHitTestSpotsAndTitleBarHeightLater();
}
@Override
public void removeNotify() {
super.removeNotify();
uninstallWindowListeners();
window = null;
}
protected String getWindowTitle() {
if( window instanceof Frame )
return ((Frame)window).getTitle();
if( window instanceof Dialog )
return ((Dialog)window).getTitle();
return null;
}
protected void installWindowListeners() {
if( window == null )
return;
window.addPropertyChangeListener( handler );
window.addWindowListener( handler );
window.addWindowStateListener( handler );
window.addComponentListener( handler );
}
protected void uninstallWindowListeners() {
if( window == null )
return;
window.removePropertyChangeListener( handler );
window.removeWindowListener( handler );
window.removeWindowStateListener( handler );
window.removeComponentListener( handler );
}
protected boolean isMenuBarEmbedded() {
// not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime
return UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) &&
FlatClientProperties.clientPropertyBoolean( rootPane, FlatClientProperties.MENU_BAR_EMBEDDED, true ) &&
FlatSystemProperties.getBoolean( FlatSystemProperties.MENUBAR_EMBEDDED, true );
}
protected Rectangle getMenuBarBounds() {
Insets insets = rootPane.getInsets();
Rectangle bounds = new Rectangle(
SwingUtilities.convertPoint( menuBarPlaceholder, -insets.left, -insets.top, rootPane ),
menuBarPlaceholder.getSize() );
// add menu bar bottom border insets to bounds so that menu bar overlaps
// title pane border (menu bar border is painted over title pane border)
Insets borderInsets = getBorder().getBorderInsets( this );
bounds.height += borderInsets.bottom;
return FlatUIUtils.subtractInsets( bounds, UIScale.scale( getMenuBarMargins() ) );
}
protected void menuBarChanged() {
menuBarPlaceholder.invalidate();
// update title foreground color
EventQueue.invokeLater( () -> {
activeChanged( window == null || window.isActive() );
} );
}
protected Insets getMenuBarMargins() {
return getComponentOrientation().isLeftToRight()
? menuBarMargins
: new Insets( menuBarMargins.top, menuBarMargins.right, menuBarMargins.bottom, menuBarMargins.left );
}
@Override
protected void paintComponent( Graphics g ) {
g.setColor( getBackground() );
g.fillRect( 0, 0, getWidth(), getHeight() );
}
protected void repaintWindowBorder() {
int width = rootPane.getWidth();
int height = rootPane.getHeight();
Insets insets = rootPane.getInsets();
rootPane.repaint( 0, 0, width, insets.top ); // top
rootPane.repaint( 0, 0, insets.left, height ); // left
rootPane.repaint( 0, height - insets.bottom, width, insets.bottom ); // bottom
rootPane.repaint( width - insets.right, 0, insets.right, height ); // right
}
/**
* Iconifies the window.
*/
protected void iconify() {
if( window instanceof Frame ) {
Frame frame = (Frame) window;
frame.setExtendedState( frame.getExtendedState() | Frame.ICONIFIED );
}
}
/**
* Maximizes the window.
*/
protected void maximize() {
if( !(window instanceof Frame) )
return;
Frame frame = (Frame) window;
updateMaximizedBounds();
// let our WindowStateListener know that the maximized bounds are up-to-date
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", true );
// maximize window
frame.setExtendedState( frame.getExtendedState() | Frame.MAXIMIZED_BOTH );
}
protected void updateMaximizedBounds() {
Frame frame = (Frame) window;
// set maximized bounds to avoid that maximized window overlaps Windows task bar
// (if not running in JBR and if not modified from the application)
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
if( !hasJBRCustomDecoration() &&
(oldMaximizedBounds == null ||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
{
GraphicsConfiguration gc = window.getGraphicsConfiguration();
// Screen bounds, which may be smaller than physical size on Java 9+.
// E.g. if running a 3840x2160 screen at 200%, screenBounds.size is 1920x1080.
// In Java 9+, each screen can have its own scale factor.
//
// On Java 8, which does not scale, screenBounds.size of the primary screen
// is identical to its physical size. But when the primary screen is scaled,
// then screenBounds.size of secondary screens is scaled with the scale factor
// of the primary screen.
// E.g. primary 3840x2160 screen at 150%, secondary 1920x1080 screen at 100%,
// then screenBounds.size is 3840x2160 on primary and 2880x1560 on secondary.
Rectangle screenBounds = gc.getBounds();
int maximizedX = screenBounds.x;
int maximizedY = screenBounds.y;
int maximizedWidth = screenBounds.width;
int maximizedHeight = screenBounds.height;
if( !isMaximizedBoundsFixed() ) {
// on Java 8 to 14, maximized x,y are 0,0 based on all screens in a multi-screen environment
maximizedX = 0;
maximizedY = 0;
// scale maximized screen size to get physical screen size for Java 9 to 14
AffineTransform defaultTransform = gc.getDefaultTransform();
maximizedWidth = (int) (maximizedWidth * defaultTransform.getScaleX());
maximizedHeight = (int) (maximizedHeight * defaultTransform.getScaleY());
}
// screen insets are in physical size, except for Java 15+
// (see https://bugs.openjdk.java.net/browse/JDK-8243925)
// and except for Java 8 on secondary screens where primary screen is scaled
Insets screenInsets = window.getToolkit().getScreenInsets( gc );
// maximized bounds are required in physical size, except for Java 15+
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
// https://bugs.openjdk.java.net/browse/JDK-8176359)
// and except for Java 8 on secondary screens where primary screen is scaled
Rectangle newMaximizedBounds = new Rectangle(
maximizedX + screenInsets.left,
maximizedY + screenInsets.top,
maximizedWidth - screenInsets.left - screenInsets.right,
maximizedHeight - screenInsets.top - screenInsets.bottom );
if( !Objects.equals( oldMaximizedBounds, newMaximizedBounds ) ) {
// change maximized bounds
frame.setMaximizedBounds( newMaximizedBounds );
// remember maximized bounds in client property to be able to detect
// whether maximized bounds are modified from the application
rootPane.putClientProperty( "_flatlaf.maximizedBounds", newMaximizedBounds );
}
}
}
/**
* Frame.setMaximizedBounds() behaves different on some Java versions after issues
* https://bugs.openjdk.java.net/browse/JDK-8231564 and
* https://bugs.openjdk.java.net/browse/JDK-8176359
* (see also https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8176359)
* were fixed in Java 15 and backported to 11.0.8 and 13.0.4.
*/
private boolean isMaximizedBoundsFixed() {
return SystemInfo.isJava_15_orLater ||
(SystemInfo.javaVersion >= SystemInfo.toVersion( 11, 0, 8, 0 ) &&
SystemInfo.javaVersion < SystemInfo.toVersion( 12, 0, 0, 0 )) ||
(SystemInfo.javaVersion >= SystemInfo.toVersion( 13, 0, 4, 0 ) &&
SystemInfo.javaVersion < SystemInfo.toVersion( 14, 0, 0, 0 ));
}
/**
* Restores the window size.
*/
protected void restore() {
if( window instanceof Frame ) {
Frame frame = (Frame) window;
int state = frame.getExtendedState();
frame.setExtendedState( ((state & Frame.ICONIFIED) != 0)
? (state & ~Frame.ICONIFIED)
: (state & ~Frame.MAXIMIZED_BOTH) );
}
}
/**
* Closes the window.
*/
protected void close() {
if( window != null )
window.dispatchEvent( new WindowEvent( window, WindowEvent.WINDOW_CLOSING ) );
}
protected boolean hasJBRCustomDecoration() {
return FlatRootPaneUI.canUseJBRCustomDecorations &&
window != null &&
JBRCustomDecorations.hasCustomDecoration( window );
}
protected void updateJBRHitTestSpotsAndTitleBarHeightLater() {
EventQueue.invokeLater( () -> {
updateJBRHitTestSpotsAndTitleBarHeight();
} );
}
protected void updateJBRHitTestSpotsAndTitleBarHeight() {
if( !isDisplayable() )
return;
if( !hasJBRCustomDecoration() )
return;
List<Rectangle> hitTestSpots = new ArrayList<>();
if( iconLabel.isVisible() )
addJBRHitTestSpot( iconLabel, false, hitTestSpots );
addJBRHitTestSpot( buttonPanel, false, hitTestSpots );
addJBRHitTestSpot( menuBarPlaceholder, true, hitTestSpots );
int titleBarHeight = getHeight();
// slightly reduce height so that component receives mouseExit events
if( titleBarHeight > 0 )
titleBarHeight--;
JBRCustomDecorations.setHitTestSpotsAndTitleBarHeight( window, hitTestSpots, titleBarHeight );
}
protected void addJBRHitTestSpot( JComponent c, boolean subtractMenuBarMargins, List<Rectangle> hitTestSpots ) {
Dimension size = c.getSize();
if( size.width <= 0 || size.height <= 0 )
return;
Point location = SwingUtilities.convertPoint( c, 0, 0, window );
Rectangle r = new Rectangle( location, size );
if( subtractMenuBarMargins )
r = FlatUIUtils.subtractInsets( r, UIScale.scale( getMenuBarMargins() ) );
// slightly increase rectangle so that component receives mouseExit events
r.grow( 2, 2 );
hitTestSpots.add( r );
}
//---- class TitlePaneBorder ----------------------------------------------
protected class FlatTitlePaneBorder
extends AbstractBorder
{
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
super.getBorderInsets( c, insets );
// if menu bar is embedded, add bottom insets of menu bar border
Border menuBarBorder = getMenuBarBorder();
if( menuBarBorder != null ) {
Insets menuBarInsets = menuBarBorder.getBorderInsets( c );
insets.bottom += menuBarInsets.bottom;
}
if( hasJBRCustomDecoration() )
insets = FlatUIUtils.addInsets( insets, JBRWindowTopBorder.getInstance().getBorderInsets() );
return insets;
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
// if menu bar is embedded, paint menu bar border
Border menuBarBorder = getMenuBarBorder();
if( menuBarBorder != null )
menuBarBorder.paintBorder( c, g, x, y, width, height );
if( hasJBRCustomDecoration() )
JBRWindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
}
protected Border getMenuBarBorder() {
JMenuBar menuBar = rootPane.getJMenuBar();
return (menuBar != null && isMenuBarEmbedded()) ? menuBar.getBorder() : null;
}
}
//---- class Handler ------------------------------------------------------
protected class Handler
extends WindowAdapter
implements PropertyChangeListener, MouseListener, MouseMotionListener, ComponentListener
{
//---- interface PropertyChangeListener ----
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case "title":
titleLabel.setText( getWindowTitle() );
break;
case "resizable":
if( window instanceof Frame )
frameStateChanged();
break;
case "iconImage":
updateIcon();
break;
case "componentOrientation":
updateJBRHitTestSpotsAndTitleBarHeightLater();
break;
}
}
//---- interface WindowListener ----
@Override
public void windowActivated( WindowEvent e ) {
activeChanged( true );
updateJBRHitTestSpotsAndTitleBarHeight();
if( hasJBRCustomDecoration() )
JBRWindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
repaintWindowBorder();
}
@Override
public void windowDeactivated( WindowEvent e ) {
activeChanged( false );
updateJBRHitTestSpotsAndTitleBarHeight();
if( hasJBRCustomDecoration() )
JBRWindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
repaintWindowBorder();
}
@Override
public void windowStateChanged( WindowEvent e ) {
frameStateChanged();
updateJBRHitTestSpotsAndTitleBarHeight();
}
//---- interface MouseListener ----
private int lastXOnScreen;
private int lastYOnScreen;
@Override
public void mouseClicked( MouseEvent e ) {
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
if( e.getSource() == iconLabel ) {
// double-click on icon closes window
close();
} else if( !hasJBRCustomDecoration() &&
window instanceof Frame &&
((Frame)window).isResizable() )
{
// maximize/restore on double-click
Frame frame = (Frame) window;
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
restore();
else
maximize();
}
}
}
@Override
public void mousePressed( MouseEvent e ) {
lastXOnScreen = e.getXOnScreen();
lastYOnScreen = e.getYOnScreen();
}
@Override public void mouseReleased( MouseEvent e ) {}
@Override public void mouseEntered( MouseEvent e ) {}
@Override public void mouseExited( MouseEvent e ) {}
//---- interface MouseMotionListener ----
@Override
public void mouseDragged( MouseEvent e ) {
if( hasJBRCustomDecoration() )
return; // do nothing if running in JBR
int xOnScreen = e.getXOnScreen();
int yOnScreen = e.getYOnScreen();
if( lastXOnScreen == xOnScreen && lastYOnScreen == yOnScreen )
return;
// restore window if it is maximized
if( window instanceof Frame ) {
Frame frame = (Frame) window;
int state = frame.getExtendedState();
if( (state & Frame.MAXIMIZED_BOTH) != 0 ) {
int maximizedX = window.getX();
int maximizedY = window.getY();
// restore window size, which also moves window to pre-maximized location
frame.setExtendedState( state & ~Frame.MAXIMIZED_BOTH );
int restoredWidth = window.getWidth();
int newX = maximizedX;
JComponent rightComp = getComponentOrientation().isLeftToRight() ? buttonPanel : leftPanel;
if( xOnScreen >= maximizedX + restoredWidth - rightComp.getWidth() - 10 )
newX = xOnScreen + rightComp.getWidth() + 10 - restoredWidth;
// move window near mouse
window.setLocation( newX, maximizedY );
return;
}
}
// compute new window location
int newX = window.getX() + (xOnScreen - lastXOnScreen);
int newY = window.getY() + (yOnScreen - lastYOnScreen);
// move window
window.setLocation( newX, newY );
lastXOnScreen = xOnScreen;
lastYOnScreen = yOnScreen;
}
@Override public void mouseMoved( MouseEvent e ) {}
//---- interface ComponentListener ----
@Override
public void componentResized( ComponentEvent e ) {
updateJBRHitTestSpotsAndTitleBarHeightLater();
}
@Override
public void componentShown( ComponentEvent e ) {
// necessary for the case that the frame is maximized before it is shown
frameStateChanged();
}
@Override public void componentMoved( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Dimension;
import java.awt.Image;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.ScaledImageIcon;
/**
* @author Karl Tauber
*/
public class FlatTitlePaneIcon
extends ScaledImageIcon
{
public static Icon create( List<Image> images, Dimension size ) {
// collect all images including multi-resolution variants
List<Image> allImages = new ArrayList<>();
for( Image image : images ) {
if( MultiResolutionImageSupport.isMultiResolutionImage( image ) )
allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) );
else
allImages.add( image );
}
// sort images by size
allImages.sort( (image1, image2) -> {
return image1.getWidth( null ) - image2.getWidth( null );
} );
// create icon
return new FlatTitlePaneIcon( allImages, size );
}
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 ) &&
destImageHeight <= image.getHeight( null ) )
return image;
}
return images.get( images.size() - 1 );
}
}

View File

@@ -50,6 +50,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault ToggleButton.startBackground Color optional; if set, a gradient paint is used and ToggleButton.background is ignored * @uiDefault ToggleButton.startBackground Color optional; if set, a gradient paint is used and ToggleButton.background is ignored
* @uiDefault ToggleButton.endBackground Color optional; if set, a gradient paint is used * @uiDefault ToggleButton.endBackground Color optional; if set, a gradient paint is used
* @uiDefault ToggleButton.pressedBackground Color * @uiDefault ToggleButton.pressedBackground Color
* @uiDefault ToggleButton.disabledBackground Color optional
* @uiDefault ToggleButton.disabledText Color * @uiDefault ToggleButton.disabledText Color
* @uiDefault ToggleButton.toolbar.hoverBackground Color * @uiDefault ToggleButton.toolbar.hoverBackground Color
* @uiDefault ToggleButton.toolbar.pressedBackground Color * @uiDefault ToggleButton.toolbar.pressedBackground Color
@@ -205,9 +206,7 @@ public class FlatToggleButtonUI
@Override @Override
protected Color getForeground( JComponent c ) { protected Color getForeground( JComponent c ) {
ButtonModel model = ((AbstractButton)c).getModel(); if( c.isEnabled() && ((AbstractButton)c).isSelected() && !isToolBarButton( c ) )
if( model.isSelected() && !isToolBarButton( c ) )
return selectedForeground; return selectedForeground;
return super.getForeground( c ); return super.getForeground( c );

View File

@@ -29,6 +29,7 @@ import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicToolTipUI; import javax.swing.plaf.basic.BasicToolTipUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
/** /**
@@ -93,6 +94,11 @@ public class FlatToolTipUI
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
// do not show tool tip if text is empty
String text = ((JToolTip)c).getTipText();
if( text == null || text.isEmpty() )
return new Dimension();
if( isMultiLine( c ) ) { if( isMultiLine( c ) ) {
FontMetrics fm = c.getFontMetrics( c.getFont() ); FontMetrics fm = c.getFontMetrics( c.getFont() );
Insets insets = c.getInsets(); Insets insets = c.getInsets();
@@ -130,7 +136,7 @@ public class FlatToolTipUI
FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y ); FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
} }
} else } else
super.paint( g, c ); super.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), c );
} }
private boolean isMultiLine( JComponent c ) { private boolean isMultiLine( JComponent c ) {

View File

@@ -25,6 +25,7 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import javax.swing.CellRendererPane;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
@@ -75,6 +76,11 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Tree.dropCellBackground Color * @uiDefault Tree.dropCellBackground Color
* @uiDefault Tree.dropCellForeground Color * @uiDefault Tree.dropCellForeground Color
* *
* <!-- DefaultTreeCellEditor -->
*
* @uiDefault Tree.editorBorder Border
* @uiDefault Tree.editorBorderSelectionColor Color
*
* <!-- FlatTreeUI --> * <!-- FlatTreeUI -->
* *
* @uiDefault Tree.border Border * @uiDefault Tree.border Border
@@ -226,6 +232,11 @@ public class FlatTreeUI
boolean isSelected = tree.isRowSelected( row ); boolean isSelected = tree.isRowSelected( row );
boolean isDropRow = isDropRow( row ); boolean isDropRow = isDropRow( row );
// if tree is used as cell renderer in another component (e.g. in Rhino JavaScript debugger),
// check whether that component is focused to get correct selection colors
if( !hasFocus && isSelected && tree.getParent() instanceof CellRendererPane )
hasFocus = FlatUIUtils.isPermanentFocusOwner( tree.getParent().getParent() );
// wide selection background // wide selection background
if( wideSelection && (isSelected || isDropRow) ) { if( wideSelection && (isSelected || isDropRow) ) {
// fill background // fill background

View File

@@ -38,14 +38,15 @@ import java.awt.geom.RoundRectangle2D;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
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;
import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -135,12 +136,27 @@ public class FlatUIUtils
return FlatClientProperties.clientPropertyInt( c, FlatClientProperties.MINIMUM_HEIGHT, minimumHeight ); return FlatClientProperties.clientPropertyInt( c, FlatClientProperties.MINIMUM_HEIGHT, minimumHeight );
} }
public static boolean isTableCellEditor( Component c ) { public static boolean isCellEditor( Component c ) {
// check whether used as cell editor in file chooser
// Tree.cellEditor is set in sun.swing.FilePane.editFileName()
// Table.editor is set in JTable.GenericEditor constructor
String name = c.getName();
if( "Tree.cellEditor".equals( name ) || "Table.editor".equals( name ) )
return true;
// for using combo box as cell editor in table
// JComboBox.isTableCellEditor is set in javax.swing.DefaultCellEditor(JComboBox) constructor
return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) ); return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) );
} }
/**
* Returns whether the given component is the permanent focus owner and
* is in the active window. Used to paint focus indicators.
*/
public static boolean isPermanentFocusOwner( Component c ) { public static boolean isPermanentFocusOwner( Component c ) {
return (KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() == c); KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
return keyboardFocusManager.getPermanentFocusOwner() == c &&
keyboardFocusManager.getActiveWindow() == SwingUtilities.windowForComponent( c );
} }
public static boolean isRoundRect( Component c ) { public static boolean isRoundRect( Component c ) {
@@ -152,9 +168,9 @@ public class FlatUIUtils
* Returns the scaled thickness of the outer focus border for the given component. * Returns the scaled thickness of the outer focus border for the given component.
*/ */
public static float getBorderFocusWidth( JComponent c ) { public static float getBorderFocusWidth( JComponent c ) {
Border border = c.getBorder(); FlatBorder border = getOutsideFlatBorder( c );
return (border instanceof FlatBorder) return (border != null)
? UIScale.scale( (float) ((FlatBorder)border).getFocusWidth( c ) ) ? UIScale.scale( (float) border.getFocusWidth( c ) )
: 0; : 0;
} }
@@ -162,12 +178,28 @@ public class FlatUIUtils
* Returns the scaled arc diameter of the border for the given component. * Returns the scaled arc diameter of the border for the given component.
*/ */
public static float getBorderArc( JComponent c ) { public static float getBorderArc( JComponent c ) {
Border border = c.getBorder(); FlatBorder border = getOutsideFlatBorder( c );
return (border instanceof FlatBorder) return (border != null)
? UIScale.scale( (float) ((FlatBorder)border).getArc( c ) ) ? UIScale.scale( (float) border.getArc( c ) )
: 0; : 0;
} }
public static boolean hasRoundBorder( JComponent c ) {
return getBorderArc( c ) >= c.getHeight();
}
public static FlatBorder getOutsideFlatBorder( JComponent c ) {
Border border = c.getBorder();
for(;;) {
if( border instanceof FlatBorder )
return (FlatBorder) border;
else if( border instanceof CompoundBorder )
border = ((CompoundBorder)border).getOutsideBorder();
else
return null;
}
}
/** /**
* Sets rendering hints used for painting. * Sets rendering hints used for painting.
*/ */
@@ -177,17 +209,17 @@ public class FlatUIUtils
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE ); MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
} }
public static void setColor( Graphics g, Color color, Color baseColor ) { public static Color deriveColor( Color color, Color baseColor ) {
if( color instanceof DerivedColor ) return (color instanceof DerivedColor)
color = ((DerivedColor)color).derive( baseColor ); ? ((DerivedColor)color).derive( baseColor )
g.setColor( color ); : color;
} }
/** /**
* Paints an outer border, which is usually a focus border. * Paints an outer border, which is usually a focus border.
* <p> * <p>
* The outside bounds of the painted border are {@code x,y,width,height}. * The outside bounds of the painted border are {@code x,y,width,height}.
* The line width of the painted border is {@code focusWidth + lineWidth}. * The line thickness of the painted border is {@code focusWidth + lineWidth}.
* The given arc diameter refers to the inner rectangle ({@code x,y,width,height} minus {@code focusWidth}). * The given arc diameter refers to the inner rectangle ({@code x,y,width,height} minus {@code focusWidth}).
* *
* @see #paintComponentBorder * @see #paintComponentBorder
@@ -196,6 +228,9 @@ public class FlatUIUtils
public static void paintComponentOuterBorder( Graphics2D g, int x, int y, int width, int height, public static void paintComponentOuterBorder( Graphics2D g, int x, int y, int width, int height,
float focusWidth, float lineWidth, float arc ) float focusWidth, float lineWidth, float arc )
{ {
if( focusWidth + lineWidth == 0 )
return; // nothing to paint
double systemScaleFactor = UIScale.getSystemScaleFactor( g ); double systemScaleFactor = UIScale.getSystemScaleFactor( g );
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) { if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175% // paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
@@ -232,6 +267,7 @@ public class FlatUIUtils
* <p> * <p>
* The outside bounds of the painted border are * The outside bounds of the painted border are
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}. * {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
* The line thickness of the painted border is {@code lineWidth}.
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}). * The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
* *
* @see #paintComponentOuterBorder * @see #paintComponentOuterBorder
@@ -240,6 +276,9 @@ public class FlatUIUtils
public static void paintComponentBorder( Graphics2D g, int x, int y, int width, int height, public static void paintComponentBorder( Graphics2D g, int x, int y, int width, int height,
float focusWidth, float lineWidth, float arc ) float focusWidth, float lineWidth, float arc )
{ {
if( lineWidth == 0 )
return; // nothing to paint
double systemScaleFactor = UIScale.getSystemScaleFactor( g ); double systemScaleFactor = UIScale.getSystemScaleFactor( g );
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) { if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175% // paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
@@ -432,23 +471,24 @@ public class FlatUIUtils
} }
/** /**
* Draws the given string at the specified location using text properties * Draws the given string at the specified location.
* and anti-aliasing hints from the provided component. * The provided component is used to query text properties and anti-aliasing hints.
* * <p>
* Use this method instead of Graphics.drawString() for correct anti-aliasing. * Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
* * <p>
* Replacement for SwingUtilities2.drawString() * Replacement for {@code SwingUtilities2.drawString()}.
* Uses {@link HiDPIUtils#drawStringWithYCorrection(JComponent, Graphics2D, String, int, int)}.
*/ */
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) { public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y ); HiDPIUtils.drawStringWithYCorrection( c, (Graphics2D) g, text, x, y );
} }
/** /**
* Draws the given string at the specified location underlining the specified * Draws the given string at the specified location underlining the specified character.
* character. The provided component is used to query text properties and * The provided component is used to query text properties and anti-aliasing hints.
* anti-aliasing hints. * <p>
* * Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
* Replacement for SwingUtilities2.drawStringUnderlineCharAt() * Uses {@link HiDPIUtils#drawStringUnderlineCharAtWithYCorrection(JComponent, Graphics2D, String, int, int, int)}.
*/ */
public static void drawStringUnderlineCharAt( JComponent c, Graphics g, public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
String text, int underlinedIndex, int x, int y ) String text, int underlinedIndex, int x, int y )
@@ -470,7 +510,7 @@ public class FlatUIUtils
}; };
} }
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y ); HiDPIUtils.drawStringUnderlineCharAtWithYCorrection( c, (Graphics2D) g, text, underlinedIndex, x, y );
} }
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) { public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {

View File

@@ -0,0 +1,375 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import static java.awt.Cursor.*;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import com.formdev.flatlaf.util.UIScale;
/**
* Resizes frames and dialogs.
*
* @author Karl Tauber
*/
public class FlatWindowResizer
implements PropertyChangeListener, WindowStateListener, ComponentListener
{
protected final static Integer WINDOW_RESIZER_LAYER = JLayeredPane.DRAG_LAYER + 1;
protected final JRootPane rootPane;
protected final int borderDragThickness = FlatUIUtils.getUIInt( "RootPane.borderDragThickness", 5 );
protected final int cornerDragWidth = FlatUIUtils.getUIInt( "RootPane.cornerDragWidth", 16 );
protected final boolean honorFrameMinimumSizeOnResize = UIManager.getBoolean( "RootPane.honorFrameMinimumSizeOnResize" );
protected final boolean honorDialogMinimumSizeOnResize = UIManager.getBoolean( "RootPane.honorDialogMinimumSizeOnResize" );
protected final JComponent north;
protected final JComponent south;
protected final JComponent west;
protected final JComponent east;
protected Window window;
public FlatWindowResizer( JRootPane rootPane ) {
this.rootPane = rootPane;
north = createDragBorderComponent( NW_RESIZE_CURSOR, N_RESIZE_CURSOR, NE_RESIZE_CURSOR );
south = createDragBorderComponent( SW_RESIZE_CURSOR, S_RESIZE_CURSOR, SE_RESIZE_CURSOR );
west = createDragBorderComponent( NW_RESIZE_CURSOR, W_RESIZE_CURSOR, SW_RESIZE_CURSOR );
east = createDragBorderComponent( NE_RESIZE_CURSOR, E_RESIZE_CURSOR, SE_RESIZE_CURSOR );
JLayeredPane layeredPane = rootPane.getLayeredPane();
layeredPane.add( north, WINDOW_RESIZER_LAYER );
layeredPane.add( south, WINDOW_RESIZER_LAYER );
layeredPane.add( west, WINDOW_RESIZER_LAYER );
layeredPane.add( east, WINDOW_RESIZER_LAYER );
rootPane.addComponentListener( this );
rootPane.addPropertyChangeListener( "ancestor", this );
if( rootPane.isDisplayable() )
addNotify();
}
protected DragBorderComponent createDragBorderComponent( int leadingResizeDir, int centerResizeDir, int trailingResizeDir ) {
return new DragBorderComponent( leadingResizeDir, centerResizeDir, trailingResizeDir );
}
public void uninstall() {
removeNotify();
rootPane.removeComponentListener( this );
rootPane.removePropertyChangeListener( "ancestor", this );
JLayeredPane layeredPane = rootPane.getLayeredPane();
layeredPane.remove( north );
layeredPane.remove( south );
layeredPane.remove( west );
layeredPane.remove( east );
}
public void doLayout() {
if( !north.isVisible() )
return;
int x = 0;
int y = 0;
int width = rootPane.getWidth();
int height = rootPane.getHeight();
if( width == 0 || height == 0 )
return;
int thickness = UIScale.scale( borderDragThickness );
int y2 = y + thickness;
int height2 = height - (thickness * 2);
north.setBounds( x, y, width, thickness );
south.setBounds( x, y + height - thickness, width, thickness );
west.setBounds( x, y2, thickness, height2 );
east.setBounds( x + width - thickness, y2, thickness, height2 );
}
protected void addNotify() {
Container parent = rootPane.getParent();
window = (parent instanceof Window) ? (Window) parent : null;
if( window instanceof Frame ) {
window.addPropertyChangeListener( "resizable", this );
window.addWindowStateListener( this );
}
updateVisibility();
}
protected void removeNotify() {
if( window instanceof Frame ) {
window.removePropertyChangeListener( "resizable", this );
window.removeWindowStateListener( this );
}
window = null;
updateVisibility();
}
protected void updateVisibility() {
boolean visible = isWindowResizable();
if( visible == north.isVisible() )
return;
north.setVisible( visible );
south.setVisible( visible );
west.setVisible( visible );
// The east component is not hidden, instead its bounds are set to 0,0,1,1 and
// it is disabled. This is necessary so that DragBorderComponent.paintComponent() is invoked.
east.setEnabled( visible );
if( visible ) {
east.setVisible( true ); // necessary because it is initially invisible
doLayout();
} else
east.setBounds( 0, 0, 1, 1 );
}
protected boolean isWindowResizable() {
if( window instanceof Frame )
return ((Frame)window).isResizable() && (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) == 0;
if( window instanceof Dialog )
return ((Dialog)window).isResizable();
return false;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case "ancestor":
if( e.getNewValue() != null )
addNotify();
else
removeNotify();
break;
case "resizable":
updateVisibility();
break;
}
}
@Override
public void windowStateChanged( WindowEvent e ) {
updateVisibility();
}
@Override
public void componentResized( ComponentEvent e ) {
doLayout();
}
@Override public void componentMoved( ComponentEvent e ) {}
@Override public void componentShown( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
//---- class DragBorderComponent ------------------------------------------
protected class DragBorderComponent
extends JComponent
implements MouseListener, MouseMotionListener
{
private final int leadingResizeDir;
private final int centerResizeDir;
private final int trailingResizeDir;
private int resizeDir = -1;
private int dragStartMouseX;
private int dragStartMouseY;
private Rectangle dragStartWindowBounds;
protected DragBorderComponent( int leadingResizeDir, int centerResizeDir, int trailingResizeDir ) {
this.leadingResizeDir = leadingResizeDir;
this.centerResizeDir = centerResizeDir;
this.trailingResizeDir = trailingResizeDir;
setResizeDir( centerResizeDir );
setVisible( false );
addMouseListener( this );
addMouseMotionListener( this );
}
protected void setResizeDir( int resizeDir ) {
if( this.resizeDir == resizeDir )
return;
this.resizeDir = resizeDir;
setCursor( getPredefinedCursor( resizeDir ) );
}
@Override
public Dimension getPreferredSize() {
int thickness = UIScale.scale( borderDragThickness );
return new Dimension( thickness, thickness );
}
@Override
protected void paintComponent( Graphics g ) {
super.paintChildren( g );
// this is necessary because Dialog.setResizable() does not fire events
if( window instanceof Dialog )
updateVisibility();
/*debug
g.setColor( java.awt.Color.red );
g.drawRect( 0, 0, getWidth() - 1, getHeight() - 1 );
debug*/
}
@Override
public void mouseClicked( MouseEvent e ) {
}
@Override
public void mousePressed( MouseEvent e ) {
if( window == null )
return;
dragStartMouseX = e.getXOnScreen();
dragStartMouseY = e.getYOnScreen();
dragStartWindowBounds = window.getBounds();
}
@Override
public void mouseReleased( MouseEvent e ) {
dragStartWindowBounds = null;
}
@Override
public void mouseEntered( MouseEvent e ) {
}
@Override
public void mouseExited( MouseEvent e ) {
}
@Override
public void mouseMoved( MouseEvent e ) {
boolean topBottom = (centerResizeDir == N_RESIZE_CURSOR || centerResizeDir == S_RESIZE_CURSOR);
int xy = topBottom ? e.getX() : e.getY();
int wh = topBottom ? getWidth() : getHeight();
int cornerWH = UIScale.scale( cornerDragWidth - (topBottom ? 0 : borderDragThickness) );
setResizeDir( xy <= cornerWH
? leadingResizeDir
: (xy >= wh - cornerWH
? trailingResizeDir
: centerResizeDir) );
}
@Override
public void mouseDragged( MouseEvent e ) {
if( dragStartWindowBounds == null )
return;
if( !isWindowResizable() )
return;
int mouseDeltaX = e.getXOnScreen() - dragStartMouseX;
int mouseDeltaY = e.getYOnScreen() - dragStartMouseY;
int deltaX = 0;
int deltaY = 0;
int deltaWidth = 0;
int deltaHeight = 0;
// north
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
deltaY = mouseDeltaY;
deltaHeight = -mouseDeltaY;
}
// south
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
deltaHeight = mouseDeltaY;
// west
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
deltaX = mouseDeltaX;
deltaWidth = -mouseDeltaX;
}
// east
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
deltaWidth = mouseDeltaX;
// compute new window bounds
Rectangle newBounds = new Rectangle( dragStartWindowBounds );
newBounds.x += deltaX;
newBounds.y += deltaY;
newBounds.width += deltaWidth;
newBounds.height += deltaHeight;
// apply minimum window size
boolean honorMinimumSizeOnResize =
(honorFrameMinimumSizeOnResize && window instanceof Frame) ||
(honorDialogMinimumSizeOnResize && window instanceof Dialog);
Dimension minimumSize = honorMinimumSizeOnResize ? window.getMinimumSize() : null;
if( minimumSize == null )
minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
if( newBounds.width < minimumSize.width ) {
if( deltaX != 0 )
newBounds.x -= (minimumSize.width - newBounds.width);
newBounds.width = minimumSize.width;
}
if( newBounds.height < minimumSize.height ) {
if( deltaY != 0 )
newBounds.y -= (minimumSize.height - newBounds.height);
newBounds.height = minimumSize.height;
}
// set window bounds
if( !newBounds.equals( dragStartWindowBounds ) ) {
window.setBounds( newBounds );
// immediately layout drag border components
FlatWindowResizer.this.doLayout();
if( Toolkit.getDefaultToolkit().isDynamicLayoutActive() ) {
window.validate();
rootPane.repaint();
}
}
}
}
}

View File

@@ -0,0 +1,315 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.BorderUIResource;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Support for custom window decorations provided by JetBrains Runtime (based on OpenJDK).
* Requires that the application runs on Windows 10 in a JetBrains Runtime 11 or later.
* <ul>
* <li><a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime</a></li>
* <li><a href="https://github.com/JetBrains/JetBrainsRuntime">https://github.com/JetBrains/JetBrainsRuntime</a></li>
* </ul>
*
* @author Karl Tauber
*/
public class JBRCustomDecorations
{
private static boolean initialized;
private static Method Window_hasCustomDecoration;
private static Method Window_setHasCustomDecoration;
private static Method WWindowPeer_setCustomDecorationHitTestSpots;
private static Method WWindowPeer_setCustomDecorationTitleBarHeight;
private static Method AWTAccessor_getComponentAccessor;
private static Method AWTAccessor_ComponentAccessor_getPeer;
public static boolean isSupported() {
initialize();
return Window_setHasCustomDecoration != null;
}
static void install( JRootPane rootPane ) {
if( !isSupported() )
return;
// check whether root pane already has a parent, which is the case when switching LaF
if( rootPane.getParent() != null )
return;
// Use hierarchy listener to wait until the root pane is added to a window.
// Enabling JBR decorations must be done very early, probably before
// window becomes displayable (window.isDisplayable()). Tried also using
// "ancestor" property change event on root pane, but this is invoked too late.
HierarchyListener addListener = new HierarchyListener() {
@Override
public void hierarchyChanged( HierarchyEvent e ) {
if( e.getChanged() != rootPane || (e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == 0 )
return;
Container parent = e.getChangedParent();
if( parent instanceof Window )
install( (Window) parent );
// use invokeLater to remove listener to avoid that listener
// is removed while listener queue is processed
EventQueue.invokeLater( () -> {
rootPane.removeHierarchyListener( this );
} );
}
};
rootPane.addHierarchyListener( addListener );
}
static void install( Window window ) {
if( !isSupported() )
return;
// do not enable JBR decorations if LaF provides decorations
if( UIManager.getLookAndFeel().getSupportsWindowDecorations() )
return;
if( window instanceof JFrame ) {
JFrame frame = (JFrame) window;
// do not enable JBR decorations if JFrame should use system window decorations
// and if not forced to use JBR decorations
if( !JFrame.isDefaultLookAndFeelDecorated() &&
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false ))
return;
// do not enable JBR decorations if frame is undecorated
if( frame.isUndecorated() )
return;
// enable JBR custom window decoration for window
setHasCustomDecoration( frame );
// enable Swing window decoration
frame.getRootPane().setWindowDecorationStyle( JRootPane.FRAME );
} else if( window instanceof JDialog ) {
JDialog dialog = (JDialog) window;
// do not enable JBR decorations if JDialog should use system window decorations
// and if not forced to use JBR decorations
if( !JDialog.isDefaultLookAndFeelDecorated() &&
!FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, false ))
return;
// do not enable JBR decorations if dialog is undecorated
if( dialog.isUndecorated() )
return;
// enable JBR custom window decoration for window
setHasCustomDecoration( dialog );
// enable Swing window decoration
dialog.getRootPane().setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
}
}
static boolean hasCustomDecoration( Window window ) {
if( !isSupported() )
return false;
try {
return (Boolean) Window_hasCustomDecoration.invoke( window );
} catch( Exception ex ) {
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
return false;
}
}
static void setHasCustomDecoration( Window window ) {
if( !isSupported() )
return;
try {
Window_setHasCustomDecoration.invoke( window );
} catch( Exception ex ) {
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
}
}
static void setHitTestSpotsAndTitleBarHeight( Window window, List<Rectangle> hitTestSpots, int titleBarHeight ) {
if( !isSupported() )
return;
try {
Object compAccessor = AWTAccessor_getComponentAccessor.invoke( null );
Object peer = AWTAccessor_ComponentAccessor_getPeer.invoke( compAccessor, window );
WWindowPeer_setCustomDecorationHitTestSpots.invoke( peer, hitTestSpots );
WWindowPeer_setCustomDecorationTitleBarHeight.invoke( peer, titleBarHeight );
} catch( Exception ex ) {
Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex );
}
}
private static void initialize() {
if( initialized )
return;
initialized = true;
// requires JetBrains Runtime 11 and Windows 10
if( !SystemInfo.isJetBrainsJVM_11_orLater || !SystemInfo.isWindows_10_orLater )
return;
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_JETBRAINS_CUSTOM_DECORATIONS, true ) )
return;
try {
Class<?> awtAcessorClass = Class.forName( "sun.awt.AWTAccessor" );
Class<?> compAccessorClass = Class.forName( "sun.awt.AWTAccessor$ComponentAccessor" );
AWTAccessor_getComponentAccessor = awtAcessorClass.getDeclaredMethod( "getComponentAccessor" );
AWTAccessor_ComponentAccessor_getPeer = compAccessorClass.getDeclaredMethod( "getPeer", Component.class );
Class<?> peerClass = Class.forName( "sun.awt.windows.WWindowPeer" );
WWindowPeer_setCustomDecorationHitTestSpots = peerClass.getDeclaredMethod( "setCustomDecorationHitTestSpots", List.class );
WWindowPeer_setCustomDecorationTitleBarHeight = peerClass.getDeclaredMethod( "setCustomDecorationTitleBarHeight", int.class );
WWindowPeer_setCustomDecorationHitTestSpots.setAccessible( true );
WWindowPeer_setCustomDecorationTitleBarHeight.setAccessible( true );
Window_hasCustomDecoration = Window.class.getDeclaredMethod( "hasCustomDecoration" );
Window_setHasCustomDecoration = Window.class.getDeclaredMethod( "setHasCustomDecoration" );
Window_hasCustomDecoration.setAccessible( true );
Window_setHasCustomDecoration.setAccessible( true );
} catch( Exception ex ) {
// ignore
}
}
//---- class JBRWindowTopBorder -------------------------------------------
static class JBRWindowTopBorder
extends BorderUIResource.EmptyBorderUIResource
{
private static JBRWindowTopBorder instance;
private final Color defaultActiveBorder = new Color( 0x707070 );
private final Color inactiveLightColor = new Color( 0xaaaaaa );
private final Color inactiveDarkColor = new Color( 0x3f3f3f );
private boolean colorizationAffectsBorders;
private Color activeColor = defaultActiveBorder;
static JBRWindowTopBorder getInstance() {
if( instance == null )
instance = new JBRWindowTopBorder();
return instance;
}
private JBRWindowTopBorder() {
super( 1, 0, 0, 0 );
colorizationAffectsBorders = calculateAffectsBorders();
activeColor = calculateActiveBorderColor();
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor.affects.borders", e -> {
colorizationAffectsBorders = calculateAffectsBorders();
activeColor = calculateActiveBorderColor();
} );
PropertyChangeListener l = e -> {
activeColor = calculateActiveBorderColor();
};
toolkit.addPropertyChangeListener( "win.dwm.colorizationColor", l );
toolkit.addPropertyChangeListener( "win.dwm.colorizationColorBalance", l );
toolkit.addPropertyChangeListener( "win.frame.activeBorderColor", l );
}
private boolean calculateAffectsBorders() {
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "win.dwm.colorizationColor.affects.borders" );
return (value instanceof Boolean) ? (Boolean) value : true;
}
private Color calculateActiveBorderColor() {
if( !colorizationAffectsBorders )
return defaultActiveBorder;
Toolkit toolkit = Toolkit.getDefaultToolkit();
Color colorizationColor = (Color) toolkit.getDesktopProperty( "win.dwm.colorizationColor" );
if( colorizationColor != null ) {
Object colorizationColorBalanceObj = toolkit.getDesktopProperty( "win.dwm.colorizationColorBalance" );
if( colorizationColorBalanceObj instanceof Integer ) {
int colorizationColorBalance = (Integer) colorizationColorBalanceObj;
if( colorizationColorBalance < 0 )
colorizationColorBalance = 100;
if( colorizationColorBalance == 0 )
return new Color( 0xD9D9D9 );
if( colorizationColorBalance == 100 )
return colorizationColor;
float alpha = colorizationColorBalance / 100.0f;
float remainder = 1 - alpha;
int r = Math.round( (colorizationColor.getRed() * alpha + 0xD9 * remainder) );
int g = Math.round( (colorizationColor.getGreen() * alpha + 0xD9 * remainder) );
int b = Math.round( (colorizationColor.getBlue() * alpha + 0xD9 * remainder) );
return new Color( r, g, b );
}
return colorizationColor;
}
Color activeBorderColor = (Color) toolkit.getDesktopProperty( "win.frame.activeBorderColor" );
return (activeBorderColor != null) ? activeBorderColor : UIManager.getColor( "MenuBar.borderColor" );
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Window window = SwingUtilities.windowForComponent( c );
boolean active = (window != null) ? window.isActive() : false;
g.setColor( active ? activeColor : (FlatLaf.isLafDark() ? inactiveDarkColor : inactiveLightColor) );
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
}
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
g.drawRect( x, y, width - 1, 0 );
}
void repaintBorder( Component c ) {
c.repaint( 0, 0, c.getWidth(), 1 );
}
}
}

View File

@@ -21,7 +21,6 @@ import java.awt.Insets;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.border.Border;
/** /**
* Support for MigLayout visual paddings. * Support for MigLayout visual paddings.
@@ -75,9 +74,9 @@ public class MigLayoutVisualPadding
return; return;
install( c, c2 -> { install( c, c2 -> {
Border border = c2.getBorder(); FlatBorder border = FlatUIUtils.getOutsideFlatBorder( c2 );
if( border instanceof FlatBorder ) { if( border != null ) {
int focusWidth = ((FlatBorder)border).getFocusWidth( c2 ); int focusWidth = border.getFocusWidth( c2 );
return new Insets( focusWidth, focusWidth, focusWidth, focusWidth ); return new Insets( focusWidth, focusWidth, focusWidth, focusWidth );
} else } else
return null; return null;

View File

@@ -0,0 +1,317 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
import java.util.ArrayList;
import javax.swing.Timer;
/**
* Simple animator based on ideas and concepts from "Filthy Rich Clients" book
* and "Timing Framework" library.
*
* @author Karl Tauber
*/
public class Animator
{
private int duration;
private int resolution = 10;
private Interpolator interpolator;
private final ArrayList<TimingTarget> targets = new ArrayList<>();
private final Runnable endRunnable;
private boolean running;
private boolean hasBegun;
private boolean timeToStop;
private long startTime;
private Timer timer;
/**
* Creates an animation that runs duration milliseconds.
* Use {@link #addTarget(TimingTarget)} to receive timing events
* and {@link #start()} to start the animation.
*
* @param duration the duration of the animation in milliseconds
*/
public Animator( int duration ) {
this( duration, null, null );
}
/**
* Creates an animation that runs duration milliseconds.
* Use {@link #start()} to start the animation.
*
* @param duration the duration of the animation in milliseconds
* @param target the target that receives timing events
*/
public Animator( int duration, TimingTarget target ) {
this( duration, target, null );
}
/**
* Creates an animation that runs duration milliseconds.
* Use {@link #start()} to start the animation.
*
* @param duration the duration of the animation in milliseconds
* @param target the target that receives timing events
* @param endRunnable a runnable invoked when the animation ends; or {@code null}
*/
public Animator( int duration, TimingTarget target, Runnable endRunnable ) {
setDuration( duration );
addTarget( target );
this.endRunnable = endRunnable;
}
/**
* Returns the duration of the animation in milliseconds.
*/
public int getDuration() {
return duration;
}
/**
* Sets the duration of the animation in milliseconds.
*
* @throws IllegalStateException if animation is running
* @throws IllegalArgumentException if duration is <= zero
*/
public void setDuration( int duration ) {
throwExceptionIfRunning();
if( duration <= 0 )
throw new IllegalArgumentException();
this.duration = duration;
}
/**
* Returns the resolution of the animation in milliseconds (default is 10).
* Resolution is the amount of time between timing events.
*/
public int getResolution() {
return resolution;
}
/**
* Sets the resolution of the animation in milliseconds.
*
* @param resolution the resolution of the animation in milliseconds
* @throws IllegalStateException if animation is running
* @throws IllegalArgumentException if resolution is <= zero
*/
public void setResolution( int resolution ) {
throwExceptionIfRunning();
if( resolution <= 0 )
throw new IllegalArgumentException();
this.resolution = resolution;
}
/**
* Returns the interpolator for the animation.
* Default is {@code null}, which means linear.
*/
public Interpolator getInterpolator() {
return interpolator;
}
/**
* Sets the interpolator for the animation.
*
* @throws IllegalStateException if animation is running
*/
public void setInterpolator( Interpolator interpolator ) {
throwExceptionIfRunning();
this.interpolator = interpolator;
}
/**
* Adds a target to the animation that receives timing events.
*
* @param target the target that receives timing events
*/
public void addTarget( TimingTarget target ) {
if( target == null )
return;
synchronized( targets ) {
if( !targets.contains( target ) )
targets.add( target );
}
}
/**
* Removes a target from the animation.
*
* @param target the target that should be removed
*/
public void removeTarget( TimingTarget target ) {
synchronized( targets ) {
targets.remove( target );
}
}
/**
* Starts the animation.
*
* @throws IllegalStateException if animation is running
*/
public void start() {
throwExceptionIfRunning();
running = true;
hasBegun = false;
timeToStop = false;
startTime = System.nanoTime() / 1000000;
timer = new Timer( resolution, e -> {
if( !hasBegun ) {
begin();
hasBegun = true;
}
timingEvent( getTimingFraction() );
} );
timer.setInitialDelay( 0 );
timer.start();
}
/**
* Stops the animation before it normally ends.
* Invokes {@link TimingTarget#end()} on timing targets.
*/
public void stop() {
stop( false );
}
/**
* Cancels the animation before it normally ends.
* Does not invoke {@link TimingTarget#end()} on timing targets.
*/
public void cancel() {
stop( true );
}
private void stop( boolean cancel ) {
if( timer != null ) {
timer.stop();
timer = null;
}
if( !cancel )
end();
running = false;
timeToStop = false;
}
/**
* Returns whether this animation is running.
*/
public boolean isRunning() {
return running;
}
private float getTimingFraction() {
long currentTime = System.nanoTime() / 1000000;
long elapsedTime = currentTime - startTime;
timeToStop = (elapsedTime >= duration);
float fraction = clampFraction( (float) elapsedTime / duration );
if( interpolator != null )
fraction = clampFraction( interpolator.interpolate( fraction ) );
return fraction;
}
private float clampFraction( float fraction ) {
if( fraction < 0 )
return 0;
if( fraction > 1 )
return 1;
return fraction;
}
private void timingEvent( float fraction ) {
synchronized( targets ) {
for( TimingTarget target : targets )
target.timingEvent( fraction );
}
if( timeToStop )
stop();
}
private void begin() {
synchronized( targets ) {
for( TimingTarget target : targets )
target.begin();
}
}
private void end() {
synchronized( targets ) {
for( TimingTarget target : targets )
target.end();
}
if( endRunnable != null )
endRunnable.run();
}
private void throwExceptionIfRunning() {
if( isRunning() )
throw new IllegalStateException();
}
//---- interface TimingTarget ---------------------------------------------
/**
* Animation callbacks.
*/
@FunctionalInterface
public interface TimingTarget {
/**
* Invoked multiple times while animation is running.
*
* @param fraction the percent (0 to 1) elapsed of the current animation cycle
*/
void timingEvent( float fraction );
/**
* Invoked when the animation begins.
*/
default void begin() {}
/**
* Invoked when the animation ends.
*/
default void end() {}
}
//---- interface Interpolator ---------------------------------------------
/**
* Interpolator used by animation to change timing fraction. E.g. for easing.
*/
@FunctionalInterface
public interface Interpolator {
/**
* Interpolate the given fraction and returns a new fraction.
* Both fractions are in range [0, 1].
*
* @param fraction the percent (0 to 1) elapsed of the current animation cycle
* @return new fraction in range [0, 1]
*/
float interpolate( float fraction );
}
}

View File

@@ -35,7 +35,7 @@ public class ColorFunctions
return HSLColor.toRGB( hsl, alpha ); return HSLColor.toRGB( hsl, alpha );
} }
private static float clamp( float value ) { public static float clamp( float value ) {
return (value < 0) return (value < 0)
? 0 ? 0
: ((value > 100) : ((value > 100)

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2020 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
/**
* An interpolator for {@link Animator} that uses a cubic bezier curve.
*
* @author Karl Tauber
*/
public class CubicBezierEasing
implements Animator.Interpolator
{
// common cubic-bezier easing functions (same as in CSS)
// https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function
public static final CubicBezierEasing EASE = new CubicBezierEasing( 0.25f, 0.1f, 0.25f, 1f );
public static final CubicBezierEasing EASE_IN = new CubicBezierEasing( 0.42f, 0f, 1f, 1f );
public static final CubicBezierEasing EASE_IN_OUT = new CubicBezierEasing( 0.42f, 0f, 0.58f, 1f );
public static final CubicBezierEasing EASE_OUT = new CubicBezierEasing( 0f, 0f, 0.58f, 1f );
private final float x1;
private final float y1;
private final float x2;
private final float y2;
/**
* Creates a cubic bezier easing interpolator with the given control points.
* The start point of the cubic bezier curve is always 0,0 and the end point 1,1.
*
* @param x1 the x coordinate of the first control point in range [0, 1]
* @param y1 the y coordinate of the first control point in range [0, 1]
* @param x2 the x coordinate of the second control point in range [0, 1]
* @param y2 the y coordinate of the second control point in range [0, 1]
*/
public CubicBezierEasing( float x1, float y1, float x2, float y2 ) {
if( x1 < 0 || x1 > 1 || y1 < 0 || y1 > 1 ||
x2 < 0 || x2 > 1 || y2 < 0 || y2 > 1 )
throw new IllegalArgumentException( "control points must be in range [0, 1]");
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
@Override
public float interpolate( float fraction ) {
if( fraction <= 0 || fraction >= 1 )
return fraction;
// use binary search
float low = 0;
float high = 1;
while( true ) {
float mid = (low + high) / 2;
float estimate = cubicBezier( mid, x1, x2 );
if( Math.abs( fraction - estimate ) < 0.0005f )
return cubicBezier( mid, y1, y2 );
if( estimate < fraction )
low = mid;
else
high = mid;
}
}
/**
* Computes the x or y point on a cubic bezier curve for a given t value.
*
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B%C3%A9zier_curves
*
* The general cubic bezier formula is:
* x = b0*x0 + b1*x1 + b2*x2 + b3*x3
* y = b0*y0 + b1*y1 + b2*y2 + b3*y3
*
* where:
* b0 = (1-t)^3
* b1 = 3 * t * (1-t)^2
* b2 = 3 * t^2 * (1-t)
* b3 = t^3
*
* x0,y0 is always 0,0 and x3,y3 is 1,1, so we can simplify to:
* x = b1*x1 + b2*x2 + b3
* y = b1*x1 + b2*x2 + b3
*/
private static float cubicBezier( float t, float xy1, float xy2 ) {
float invT = (1 - t);
float b1 = 3 * t * (invT * invT);
float b2 = 3 * (t * t) * invT;
float b3 = t * t * t;
return (b1 * xy1) + (b2 * xy2) + b3;
}
}

View File

@@ -32,13 +32,28 @@ public class DerivedColor
{ {
private final ColorFunction[] functions; private final ColorFunction[] functions;
private boolean hasBaseOfDefaultColor;
private int baseOfDefaultColorRGB;
public DerivedColor( Color defaultColor, ColorFunction... functions ) { public DerivedColor( Color defaultColor, ColorFunction... functions ) {
super( (defaultColor != null) ? defaultColor : Color.red ); super( (defaultColor != null) ? defaultColor : Color.red );
this.functions = functions; this.functions = functions;
} }
public Color derive( Color baseColor ) { public Color derive( Color baseColor ) {
return ColorFunctions.applyFunctions( baseColor, functions ); if( (hasBaseOfDefaultColor && baseOfDefaultColorRGB == baseColor.getRGB()) || baseColor == this )
return this; // return default color
Color result = ColorFunctions.applyFunctions( baseColor, functions );
// if the result is equal to the default color, then the original base color
// was passed and we can cache this to avoid color calculations
if( !hasBaseOfDefaultColor && result.getRGB() == this.getRGB() ) {
hasBaseOfDefaultColor = true;
baseOfDefaultColorRGB = baseColor.getRGB();
}
return result;
} }
public ColorFunction[] getFunctions() { public ColorFunction[] getFunctions() {

View File

@@ -16,10 +16,14 @@
package com.formdev.flatlaf.util; package com.formdev.flatlaf.util;
import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator;
import javax.swing.JComponent; import javax.swing.JComponent;
import com.formdev.flatlaf.FlatSystemProperties;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -95,4 +99,134 @@ public class HiDPIUtils
private static double normalize( double value ) { private static double normalize( double value ) {
return Math.floor( value + 0.25 ) + 0.25; return Math.floor( value + 0.25 ) + 0.25;
} }
private static Boolean useTextYCorrection;
private static boolean useTextYCorrection() {
if( useTextYCorrection == null )
useTextYCorrection = FlatSystemProperties.getBoolean( FlatSystemProperties.USE_TEXT_Y_CORRECTION, true );
return useTextYCorrection;
}
/**
* When painting text on HiDPI screens and the JRE scales, then the text is
* painted too far down on some operating systems.
* The higher the system scale factor is, the more.
* <p>
* This methods computes a correction value for the Y position.
*/
public static float computeTextYCorrection( Graphics2D g ) {
if( !useTextYCorrection() || !SystemInfo.isWindows )
return 0;
if( !SystemInfo.isJava_9_orLater )
return UIScale.getUserScaleFactor() > 1 ? -UIScale.scale( 0.625f ) : 0;
AffineTransform t = g.getTransform();
double scaleY = t.getScaleY();
if( scaleY < 1.25 )
return 0;
// Text is painted at slightly different Y positions depending on scale factor
// and Y position of component.
// The exact reason is not yet known (to me), but there are several factors:
// - fractional scale factors result in fractional component Y device coordinates
// - fractional text Y device coordinates are rounded for horizontal lines of characters
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
// - Java adds 0.5 to X/Y positions in before drawing string in BufferedTextPipe.enqueueGlyphList()
// this is not the optimal solution, but works very good in most cases
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
if( scaleY <= 1.25 )
return -0.875f;
if( scaleY <= 1.5 )
return -0.625f;
if( scaleY <= 1.75 )
return -0.875f;
if( scaleY <= 2.0 )
return -0.75f;
if( scaleY <= 2.25 )
return -0.875f;
if( scaleY <= 3.5 )
return -0.75f;
return -0.875f;
}
/**
* Applies Y correction and draws the given string at the specified location.
* The provided component is used to query text properties and anti-aliasing hints.
* <p>
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
* <p>
* Replacement for {@code SwingUtilities2.drawString()}.
*/
public static void drawStringWithYCorrection( JComponent c, Graphics2D g, String text, int x, int y ) {
drawStringUnderlineCharAtWithYCorrection( c, g, text, -1, x, y );
}
/**
* Applies Y correction and draws the given string at the specified location underlining the specified character.
* The provided component is used to query text properties and anti-aliasing hints.
* <p>
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
*/
public static void drawStringUnderlineCharAtWithYCorrection( JComponent c,
Graphics2D g, String text, int underlinedIndex, int x, int y )
{
float yCorrection = computeTextYCorrection( g );
if( yCorrection != 0 ) {
g.translate( 0, yCorrection );
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
g.translate( 0, -yCorrection );
} else
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
}
/**
* Creates a graphics object and applies Y correction to string drawing methods.
* If no Y correction is necessary, the passed in graphics object is returned.
*/
public static Graphics2D createGraphicsTextYCorrection( Graphics2D g ) {
float yCorrection = computeTextYCorrection( g );
if( yCorrection == 0 )
return g;
return new Graphics2DProxy( g ) {
@Override
public void drawString( String str, int x, int y ) {
super.drawString( str, x, y + yCorrection );
}
@Override
public void drawString( String str, float x, float y ) {
super.drawString( str, x, y + yCorrection );
}
@Override
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
super.drawString( iterator, x, y + yCorrection );
}
@Override
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
super.drawString( iterator, x, y + yCorrection );
}
@Override
public void drawChars( char[] data, int offset, int length, int x, int y ) {
super.drawChars( data, offset, length, x, Math.round( y + yCorrection ) );
}
@Override
public void drawBytes( byte[] data, int offset, int length, int x, int y ) {
super.drawBytes( data, offset, length, x, Math.round( y + yCorrection ) );
}
@Override
public void drawGlyphVector( GlyphVector g, float x, float y ) {
super.drawGlyphVector( g, x, y + yCorrection );
}
};
}
} }

View File

@@ -48,10 +48,10 @@ public class JavaCompatibility
synchronized( JavaCompatibility.class ) { synchronized( JavaCompatibility.class ) {
if( drawStringUnderlineCharAtMethod == null ) { if( drawStringUnderlineCharAtMethod == null ) {
try { try {
Class<?> cls = Class.forName( SystemInfo.IS_JAVA_9_OR_LATER Class<?> cls = Class.forName( SystemInfo.isJava_9_orLater
? "javax.swing.plaf.basic.BasicGraphicsUtils" ? "javax.swing.plaf.basic.BasicGraphicsUtils"
: "sun.swing.SwingUtilities2" ); : "sun.swing.SwingUtilities2" );
drawStringUnderlineCharAtMethod = cls.getMethod( "drawStringUnderlineCharAt", SystemInfo.IS_JAVA_9_OR_LATER drawStringUnderlineCharAtMethod = cls.getMethod( "drawStringUnderlineCharAt", SystemInfo.isJava_9_orLater
? new Class[] { JComponent.class, Graphics2D.class, String.class, int.class, float.class, float.class } ? new Class[] { JComponent.class, Graphics2D.class, String.class, int.class, float.class, float.class }
: new Class[] { JComponent.class, Graphics.class, String.class, int.class, int.class, int.class } ); : new Class[] { JComponent.class, Graphics.class, String.class, int.class, int.class, int.class } );
} catch( Exception ex ) { } catch( Exception ex ) {
@@ -62,7 +62,7 @@ public class JavaCompatibility
} }
try { try {
if( SystemInfo.IS_JAVA_9_OR_LATER ) if( SystemInfo.isJava_9_orLater )
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, (float) x, (float) y ); drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, (float) x, (float) y );
else else
drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, x, y ); drawStringUnderlineCharAtMethod.invoke( null, c, g, text, underlinedIndex, x, y );

View File

@@ -37,30 +37,38 @@ public class ScaledImageIcon
implements Icon implements Icon
{ {
private final ImageIcon imageIcon; private final ImageIcon imageIcon;
private final int iconWidth;
private final int iconHeight;
private double lastSystemScaleFactor; private double lastSystemScaleFactor;
private float lastUserScaleFactor; private float lastUserScaleFactor;
private Image lastImage; private Image lastImage;
public ScaledImageIcon( ImageIcon imageIcon ) { public ScaledImageIcon( ImageIcon imageIcon ) {
this( imageIcon, imageIcon.getIconWidth(), imageIcon.getIconHeight() );
}
public ScaledImageIcon( ImageIcon imageIcon, int iconWidth, int iconHeight ) {
this.imageIcon = imageIcon; this.imageIcon = imageIcon;
this.iconWidth = iconWidth;
this.iconHeight = iconHeight;
} }
@Override @Override
public int getIconWidth() { public int getIconWidth() {
return UIScale.scale( imageIcon.getIconWidth() ); return UIScale.scale( iconWidth );
} }
@Override @Override
public int getIconHeight() { public int getIconHeight() {
return UIScale.scale( imageIcon.getIconHeight() ); return UIScale.scale( iconHeight );
} }
@Override @Override
public void paintIcon( Component c, Graphics g, int x, int y ) { public void paintIcon( Component c, Graphics g, int x, int y ) {
/*debug /*debug
g.setColor( Color.red ); g.setColor( Color.red );
g.drawRect( x, y, getIconWidth(), getIconHeight() ); g.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
debug*/ debug*/
// scale factor // scale factor
@@ -69,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 ) { if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) {
imageIcon.paintIcon( c, g, x, y ); imageIcon.paintIcon( c, g, x, y );
return; return;
} }
@@ -84,12 +92,11 @@ debug*/
} }
// destination image size // destination image size
int destImageWidth = (int) Math.round( imageIcon.getIconWidth() * scaleFactor ); int destImageWidth = (int) Math.round( iconWidth * scaleFactor );
int destImageHeight = (int) Math.round( imageIcon.getIconHeight() * scaleFactor ); int destImageHeight = (int) Math.round( iconHeight * scaleFactor );
// get resolution variant of image if it is a multi-resolution image // get resolution variant of image if it is a multi-resolution image
Image image = MultiResolutionImageSupport.getResolutionVariant( Image image = getResolutionVariant( destImageWidth, destImageHeight );
imageIcon.getImage(), destImageWidth, destImageHeight );
// size of image // size of image
int imageWidth = image.getWidth( null ); int imageWidth = image.getWidth( null );
@@ -124,6 +131,11 @@ debug*/
paintLastImage( g, x, y ); paintLastImage( g, x, y );
} }
protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) {
return MultiResolutionImageSupport.getResolutionVariant(
imageIcon.getImage(), destImageWidth, destImageHeight );
}
private void paintLastImage( Graphics g, int x, int y ) { private void paintLastImage( Graphics g, int x, int y ) {
if( lastSystemScaleFactor > 1 ) { if( lastSystemScaleFactor > 1 ) {
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used

View File

@@ -27,46 +27,60 @@ import java.util.StringTokenizer;
public class SystemInfo public class SystemInfo
{ {
// platforms // platforms
public static final boolean IS_WINDOWS; public static final boolean isWindows;
public static final boolean IS_MAC; public static final boolean isMacOS;
public static final boolean IS_LINUX; public static final boolean isLinux;
// OS versions // OS versions
public static final boolean IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER; public static final long osVersion;
public static final boolean isWindows_10_orLater;
public static final boolean isMacOS_10_11_ElCapitan_orLater;
public static final boolean isMacOS_10_14_Mojave_orLater;
public static final boolean isMacOS_10_15_Catalina_orLater;
// Java versions // Java versions
public static final boolean IS_JAVA_9_OR_LATER; public static final long javaVersion;
public static final boolean isJava_9_orLater;
public static final boolean isJava_11_orLater;
public static final boolean isJava_15_orLater;
// Java VMs // Java VMs
public static final boolean IS_JETBRAINS_JVM; public static final boolean isJetBrainsJVM;
public static final boolean isJetBrainsJVM_11_orLater;
// UI toolkits // UI toolkits
public static final boolean IS_KDE; public static final boolean isKDE;
static { static {
// platforms // platforms
String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH ); String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
IS_WINDOWS = osName.startsWith( "windows" ); isWindows = osName.startsWith( "windows" );
IS_MAC = osName.startsWith( "mac" ); isMacOS = osName.startsWith( "mac" );
IS_LINUX = osName.startsWith( "linux" ); isLinux = osName.startsWith( "linux" );
// OS versions // OS versions
long osVersion = scanVersion( System.getProperty( "os.version" ) ); osVersion = scanVersion( System.getProperty( "os.version" ) );
IS_MAC_OS_10_11_EL_CAPITAN_OR_LATER = (IS_MAC && osVersion >= toVersion( 10, 11, 0, 0 )); isWindows_10_orLater = (isWindows && osVersion >= toVersion( 10, 0, 0, 0 ));
isMacOS_10_11_ElCapitan_orLater = (isMacOS && osVersion >= toVersion( 10, 11, 0, 0 ));
isMacOS_10_14_Mojave_orLater = (isMacOS && osVersion >= toVersion( 10, 14, 0, 0 ));
isMacOS_10_15_Catalina_orLater = (isMacOS && osVersion >= toVersion( 10, 15, 0, 0 ));
// Java versions // Java versions
long javaVersion = scanVersion( System.getProperty( "java.version" ) ); javaVersion = scanVersion( System.getProperty( "java.version" ) );
IS_JAVA_9_OR_LATER = (javaVersion >= toVersion( 9, 0, 0, 0 )); isJava_9_orLater = (javaVersion >= toVersion( 9, 0, 0, 0 ));
isJava_11_orLater = (javaVersion >= toVersion( 11, 0, 0, 0 ));
isJava_15_orLater = (javaVersion >= toVersion( 15, 0, 0, 0 ));
// Java VMs // Java VMs
IS_JETBRAINS_JVM = System.getProperty( "java.vm.vendor", "Unknown" ) isJetBrainsJVM = System.getProperty( "java.vm.vendor", "Unknown" )
.toLowerCase( Locale.ENGLISH ).contains( "jetbrains" ); .toLowerCase( Locale.ENGLISH ).contains( "jetbrains" );
isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater;
// UI toolkits // UI toolkits
IS_KDE = (IS_LINUX && System.getenv( "KDE_FULL_SESSION" ) != null); isKDE = (isLinux && System.getenv( "KDE_FULL_SESSION" ) != null);
} }
private static long scanVersion( String version ) { public static long scanVersion( String version ) {
int major = 1; int major = 1;
int minor = 0; int minor = 0;
int micro = 0; int micro = 0;
@@ -84,7 +98,7 @@ public class SystemInfo
return toVersion( major, minor, micro, patch ); return toVersion( major, minor, micro, patch );
} }
private static long toVersion( int major, int minor, int micro, int patch ) { public static long toVersion( int major, int minor, int micro, int patch ) {
return ((long) major << 48) + ((long) minor << 32) + ((long) micro << 16) + patch; return ((long) major << 48) + ((long) minor << 32) + ((long) micro << 16) + patch;
} }
} }

View File

@@ -32,6 +32,7 @@ import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource; import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.FlatSystemProperties;
/** /**
* Two scaling modes are supported for HiDPI displays: * Two scaling modes are supported for HiDPI displays:
@@ -89,10 +90,10 @@ public class UIScale
jreHiDPI = false; jreHiDPI = false;
if( SystemInfo.IS_JAVA_9_OR_LATER ) { if( SystemInfo.isJava_9_orLater ) {
// Java 9 and later supports per-monitor scaling // Java 9 and later supports per-monitor scaling
jreHiDPI = true; jreHiDPI = true;
} else if( SystemInfo.IS_JETBRAINS_JVM ) { } else if( SystemInfo.isJetBrainsJVM ) {
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling // IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling
// see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled() // see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled()
try { try {
@@ -176,27 +177,25 @@ public class UIScale
// default font size // default font size
float fontSizeDivider = 12f; float fontSizeDivider = 12f;
if( SystemInfo.IS_WINDOWS ) { if( SystemInfo.isWindows ) {
// Windows LaF uses Tahoma font rather than the actual Windows system font (Segoe UI), // Windows LaF uses Tahoma font rather than the actual Windows system font (Segoe UI),
// and its size is always ca. 10% smaller than the actual system font size. // and its size is always ca. 10% smaller than the actual system font size.
// Tahoma 11 is used at 100% // Tahoma 11 is used at 100%
if( "Tahoma".equals( font.getFamily() ) ) if( "Tahoma".equals( font.getFamily() ) )
fontSizeDivider = 11f; fontSizeDivider = 11f;
} else if( SystemInfo.IS_MAC ) { } else if( SystemInfo.isMacOS ) {
// default font size on macOS is 13 // default font size on macOS is 13
fontSizeDivider = 13f; fontSizeDivider = 13f;
} else if( SystemInfo.IS_LINUX ) { } else if( SystemInfo.isLinux ) {
// default font size for Unity and Gnome is 15 and for KDE it is 13 // default font size for Unity and Gnome is 15 and for KDE it is 13
fontSizeDivider = SystemInfo.IS_KDE ? 13f : 15f; fontSizeDivider = SystemInfo.isKDE ? 13f : 15f;
} }
return font.getSize() / fontSizeDivider; return font.getSize() / fontSizeDivider;
} }
private static boolean isUserScalingEnabled() { private static boolean isUserScalingEnabled() {
// same as in IntelliJ IDEA return FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ENABLED, true );
String hidpi = System.getProperty( "hidpi" );
return (hidpi != null) ? Boolean.parseBoolean( hidpi ) : true;
} }
/** /**
@@ -204,7 +203,10 @@ public class UIScale
* to the given font. * to the given font.
*/ */
public static FontUIResource applyCustomScaleFactor( FontUIResource font ) { public static FontUIResource applyCustomScaleFactor( FontUIResource font ) {
String uiScale = System.getProperty( "flatlaf.uiScale" ); if( !isUserScalingEnabled() )
return font;
String uiScale = System.getProperty( FlatSystemProperties.UI_SCALE );
float scaleFactor = parseScaleFactor( uiScale ); float scaleFactor = parseScaleFactor( uiScale );
if( scaleFactor <= 0 ) if( scaleFactor <= 0 )
return font; return font;

View File

@@ -29,9 +29,9 @@
@disabledText=#777777 @disabledText=#777777
@textComponentBackground=#45494A @textComponentBackground=#45494A
@menuBackground=darken(@background,5%) @menuBackground=darken(@background,5%)
@menuHoverBackground=lighten(@menuBackground,10%) @menuHoverBackground=lighten(@menuBackground,10%,derived)
@menuCheckBackground=lighten(@menuBackground,10%) @menuCheckBackground=lighten(@menuBackground,10%,derived)
@menuCheckHoverBackground=lighten(@menuBackground,20%) @menuCheckHoverBackground=lighten(@menuBackground,20%,derived)
@cellFocusColor=#000000 @cellFocusColor=#000000
@icon=#adadad @icon=#adadad
@@ -72,8 +72,8 @@ controlDkShadow=lighten($controlShadow,10%)
#---- Button ---- #---- Button ----
Button.background=#4c5052 Button.background=#4c5052
Button.hoverBackground=lighten($Button.background,3%,derived autoInverse) Button.hoverBackground=lighten($Button.background,3%,derived)
Button.pressedBackground=lighten($Button.background,6%,derived autoInverse) Button.pressedBackground=lighten($Button.background,6%,derived)
Button.borderColor=#5e6060 Button.borderColor=#5e6060
Button.disabledBorderColor=#5e6060 Button.disabledBorderColor=#5e6060
@@ -82,34 +82,53 @@ Button.hoverBorderColor=$Button.focusedBorderColor
Button.default.background=#365880 Button.default.background=#365880
Button.default.foreground=#bbbbbb Button.default.foreground=#bbbbbb
Button.default.hoverBackground=lighten($Button.default.background,3%,derived autoInverse) Button.default.hoverBackground=lighten($Button.default.background,3%,derived)
Button.default.pressedBackground=lighten($Button.default.background,6%,derived autoInverse) Button.default.pressedBackground=lighten($Button.default.background,6%,derived)
Button.default.borderColor=#4c708c Button.default.borderColor=#4c708c
Button.default.hoverBorderColor=#537699 Button.default.hoverBorderColor=#537699
Button.default.focusedBorderColor=#537699 Button.default.focusedBorderColor=#537699
Button.default.focusColor=#43688c Button.default.focusColor=#43688c
Button.default.boldText=true Button.default.boldText=true
Button.toolbar.hoverBackground=lighten($Button.background,1%,derived autoInverse) Button.toolbar.hoverBackground=lighten($Button.background,1%,derived)
Button.toolbar.pressedBackground=lighten($Button.background,4%,derived autoInverse) Button.toolbar.pressedBackground=lighten($Button.background,4%,derived)
#---- CheckBox ---- #---- CheckBox ----
# enabled
CheckBox.icon.borderColor=#6B6B6B CheckBox.icon.borderColor=#6B6B6B
CheckBox.icon.disabledBorderColor=#545556
CheckBox.icon.selectedBorderColor=#6B6B6B
CheckBox.icon.focusedBorderColor=#466D94
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
CheckBox.icon.selectedFocusedBorderColor=#466D94
CheckBox.icon.background=#43494A CheckBox.icon.background=#43494A
CheckBox.icon.disabledBackground=@background CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
CheckBox.icon.hoverBackground=lighten($CheckBox.icon.background,3%,derived autoInverse) CheckBox.icon.selectedBackground=$CheckBox.icon.background
CheckBox.icon.pressedBackground=lighten($CheckBox.icon.background,6%,derived autoInverse)
CheckBox.icon.selectedBackground=#43494A
CheckBox.icon.checkmarkColor=#A7A7A7 CheckBox.icon.checkmarkColor=#A7A7A7
# disabled
CheckBox.icon.disabledBorderColor=#545556
CheckBox.icon.disabledBackground=@background
CheckBox.icon.disabledCheckmarkColor=#606060 CheckBox.icon.disabledCheckmarkColor=#606060
# focused
CheckBox.icon.focusedBorderColor=#466D94
CheckBox.icon.selectedFocusedBorderColor=#466D94
# hover
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
CheckBox.icon.hoverBackground=lighten($CheckBox.icon.background,3%,derived)
# pressed
CheckBox.icon.pressedBackground=lighten($CheckBox.icon.background,6%,derived)
# used if CheckBox.icon.style=filled
# enabled
CheckBox.icon[filled].selectedBorderColor=$CheckBox.icon.checkmarkColor
CheckBox.icon[filled].selectedBackground=$CheckBox.icon.checkmarkColor
CheckBox.icon[filled].checkmarkColor=$CheckBox.icon.background
# hover
CheckBox.icon[filled].selectedHoverBackground=darken($CheckBox.icon[filled].selectedBackground,3%)
# pressed
CheckBox.icon[filled].selectedPressedBackground=darken($CheckBox.icon[filled].selectedBackground,6%)
#---- ComboBox ---- #---- ComboBox ----
@@ -134,7 +153,7 @@ Component.error.borderColor=desaturate($Component.error.focusedBorderColor,25%)
Component.error.focusedBorderColor=#8b3c3c Component.error.focusedBorderColor=#8b3c3c
Component.warning.borderColor=darken(desaturate($Component.warning.focusedBorderColor,20%),10%) Component.warning.borderColor=darken(desaturate($Component.warning.focusedBorderColor,20%),10%)
Component.warning.focusedBorderColor=#ac7920 Component.warning.focusedBorderColor=#ac7920
Component.custom.borderColor=desaturate(#f00,50%,relative derived) Component.custom.borderColor=desaturate(#f00,50%,relative derived noAutoInverse)
#---- Desktop ---- #---- Desktop ----
@@ -157,8 +176,8 @@ InternalFrame.inactiveTitleForeground=@disabledText
InternalFrame.activeBorderColor=darken(@background,7%) InternalFrame.activeBorderColor=darken(@background,7%)
InternalFrame.inactiveBorderColor=darken(@background,3%) InternalFrame.inactiveBorderColor=darken(@background,3%)
InternalFrame.buttonHoverBackground=lighten($InternalFrame.activeTitleBackground,10%,derived autoInverse) InternalFrame.buttonHoverBackground=lighten($InternalFrame.activeTitleBackground,10%,derived)
InternalFrame.buttonPressedBackground=lighten($InternalFrame.activeTitleBackground,20%,derived autoInverse) InternalFrame.buttonPressedBackground=lighten($InternalFrame.activeTitleBackground,20%,derived)
InternalFrame.closeHoverBackground=lazy(Actions.Red) InternalFrame.closeHoverBackground=lazy(Actions.Red)
InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy) InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy)
InternalFrame.closeHoverForeground=#fff InternalFrame.closeHoverForeground=#fff
@@ -215,12 +234,26 @@ ProgressBar.selectionForeground=@foreground
ProgressBar.selectionBackground=@foreground ProgressBar.selectionBackground=@foreground
#---- RadioButton ----
RadioButton.icon[filled].centerDiameter=5
#---- RootPane ----
RootPane.activeBorderColor=darken(@background,7%,derived)
RootPane.inactiveBorderColor=darken(@background,5%,derived)
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.track=#3F4244 ScrollBar.track=lighten(@background,1%,derived noAutoInverse)
ScrollBar.thumb=lighten($ScrollBar.track,10%) ScrollBar.thumb=lighten($ScrollBar.track,10%,derived noAutoInverse)
ScrollBar.hoverTrackColor=lighten($ScrollBar.track,4%) ScrollBar.hoverTrackColor=lighten($ScrollBar.track,4%,derived noAutoInverse)
ScrollBar.hoverThumbColor=lighten($ScrollBar.thumb,10%) ScrollBar.hoverThumbColor=lighten($ScrollBar.thumb,10%,derived noAutoInverse)
ScrollBar.pressedThumbColor=lighten($ScrollBar.thumb,15%,derived noAutoInverse)
ScrollBar.hoverButtonBackground=lighten(@background,5%,derived noAutoInverse)
ScrollBar.pressedButtonBackground=lighten(@background,10%,derived noAutoInverse)
#---- Separator ---- #---- Separator ----
@@ -233,7 +266,7 @@ Separator.foreground=#515151
Slider.trackColor=#646464 Slider.trackColor=#646464
Slider.thumbColor=#A6A6A6 Slider.thumbColor=#A6A6A6
Slider.tickColor=#888888 Slider.tickColor=#888888
Slider.hoverColor=darken($Slider.thumbColor,15%,derived autoInverse) Slider.hoverColor=darken($Slider.thumbColor,15%,derived)
Slider.disabledForeground=#4c5052 Slider.disabledForeground=#4c5052
@@ -266,13 +299,20 @@ TableHeader.separatorColor=lighten($TableHeader.background,10%)
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
#---- TitlePane ----
TitlePane.embeddedForeground=darken($TitlePane.foreground,15%)
TitlePane.buttonHoverBackground=lighten($TitlePane.background,10%,derived)
TitlePane.buttonPressedBackground=lighten($TitlePane.background,20%,derived)
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.selectedBackground=lighten($ToggleButton.background,10%,derived autoInverse) ToggleButton.selectedBackground=lighten($ToggleButton.background,10%,derived)
ToggleButton.selectedForeground=@foreground ToggleButton.selectedForeground=@foreground
ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,3%,derived autoInverse) ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,3%,derived)
ToggleButton.toolbar.selectedBackground=lighten($ToggleButton.background,7%,derived autoInverse) ToggleButton.toolbar.selectedBackground=lighten($ToggleButton.background,7%,derived)
#---- ToolTip ---- #---- ToolTip ----

View File

@@ -35,13 +35,7 @@ Button.default.borderWidth=1
#---- CheckBox ---- #---- CheckBox ----
CheckBox.icon.selectedBorderColor=#4B97D9 CheckBox.icon.style=filled
CheckBox.icon.selectedFocusedBorderColor=#ACCFF7
CheckBox.icon.selectedBackground=#4F9EE3
CheckBox.icon.checkmarkColor=#FFFFFF
CheckBox.icon.selectedHoverBackground=#5E94CE
CheckBox.icon.selectedPressedBackground=#72A1D4
#---- Component ---- #---- Component ----
@@ -50,8 +44,3 @@ Component.focusWidth=2
Component.innerFocusWidth=0 Component.innerFocusWidth=0
Component.innerOutlineWidth=0 Component.innerOutlineWidth=0
Component.arrowType=triangle Component.arrowType=triangle
#---- RadioButton ----
RadioButton.icon.centerDiameter=5

View File

@@ -135,6 +135,7 @@ Button.rollover=true
Button.defaultButtonFollowsFocus=false Button.defaultButtonFollowsFocus=false
[win]Button.defaultButtonFollowsFocus=true [win]Button.defaultButtonFollowsFocus=true
Button.borderWidth=1
Button.default.borderWidth=1 Button.default.borderWidth=1
Button.toolbar.margin=3,3,3,3 Button.toolbar.margin=3,3,3,3
@@ -178,7 +179,11 @@ ColorChooser.swatchesDefaultRecentColor=$control
ComboBox.border=com.formdev.flatlaf.ui.FlatRoundBorder ComboBox.border=com.formdev.flatlaf.ui.FlatRoundBorder
ComboBox.padding=2,6,2,6 ComboBox.padding=2,6,2,6
ComboBox.minimumWidth=72
ComboBox.editorColumns=0
ComboBox.maximumRowCount=15
[mac]ComboBox.showPopupOnNavigation=true [mac]ComboBox.showPopupOnNavigation=true
ComboBox.buttonStyle=auto
#---- Component ---- #---- Component ----
@@ -259,7 +264,7 @@ InternalFrame.buttonSize=24,24
InternalFrame.closeIcon=com.formdev.flatlaf.icons.FlatInternalFrameCloseIcon InternalFrame.closeIcon=com.formdev.flatlaf.icons.FlatInternalFrameCloseIcon
InternalFrame.iconifyIcon=com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon InternalFrame.iconifyIcon=com.formdev.flatlaf.icons.FlatInternalFrameIconifyIcon
InternalFrame.maximizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon InternalFrame.maximizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMaximizeIcon
InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameMinimizeIcon InternalFrame.minimizeIcon=com.formdev.flatlaf.icons.FlatInternalFrameRestoreIcon
InternalFrame.windowBindings=null InternalFrame.windowBindings=null
# drop shadow # drop shadow
@@ -288,6 +293,7 @@ List.selectionInactiveForeground=@selectionInactiveForeground
List.dropCellBackground=@dropCellBackground List.dropCellBackground=@dropCellBackground
List.dropCellForeground=@dropCellForeground List.dropCellForeground=@dropCellForeground
List.dropLineColor=@dropLineColor List.dropLineColor=@dropLineColor
List.showCellFocusIndicator=false
#---- Menu ---- #---- Menu ----
@@ -421,15 +427,41 @@ RadioButtonMenuItem.borderPainted=true
RadioButtonMenuItem.background=@menuBackground RadioButtonMenuItem.background=@menuBackground
#---- RootPane ----
RootPane.border=com.formdev.flatlaf.ui.FlatRootPaneUI$FlatWindowBorder
RootPane.borderDragThickness=5
RootPane.cornerDragWidth=16
RootPane.honorFrameMinimumSizeOnResize=false
RootPane.honorDialogMinimumSizeOnResize=true
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.width=10 ScrollBar.width=10
ScrollBar.minimumThumbSize=10,10
ScrollBar.maximumThumbSize=100000,100000
ScrollBar.trackInsets=0,0,0,0
ScrollBar.thumbInsets=0,0,0,0
ScrollBar.trackArc=0
ScrollBar.thumbArc=0
ScrollBar.hoverThumbWithTrack=false
ScrollBar.pressedThumbWithTrack=false
ScrollBar.showButtons=false ScrollBar.showButtons=false
ScrollBar.squareButtons=false ScrollBar.squareButtons=false
ScrollBar.buttonArrowColor=$ComboBox.buttonArrowColor ScrollBar.buttonArrowColor=$ComboBox.buttonArrowColor
ScrollBar.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor ScrollBar.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
ScrollBar.allowsAbsolutePositioning=true ScrollBar.allowsAbsolutePositioning=true
[mac]ScrollBar.minimumThumbSize=18,18
[mac]ScrollBar.thumbInsets=2,2,2,2
[mac]ScrollBar.thumbArc=999
[mac]ScrollBar.hoverThumbWithTrack=true
[linux]ScrollBar.minimumThumbSize=18,18
[linux]ScrollBar.thumbInsets=2,2,2,2
[linux]ScrollBar.thumbArc=999
#---- ScrollPane ---- #---- ScrollPane ----
@@ -463,6 +495,7 @@ Spinner.buttonDisabledArrowColor=$ComboBox.buttonDisabledArrowColor
Spinner.buttonHoverArrowColor=$ComboBox.buttonHoverArrowColor Spinner.buttonHoverArrowColor=$ComboBox.buttonHoverArrowColor
Spinner.padding=@textComponentMargin Spinner.padding=@textComponentMargin
Spinner.editorBorderPainted=false Spinner.editorBorderPainted=false
Spinner.buttonStyle=button
#---- SplitPane ---- #---- SplitPane ----
@@ -498,6 +531,7 @@ TabbedPane.contentBorderInsets=null
Table.rowHeight=20 Table.rowHeight=20
Table.showHorizontalLines=false Table.showHorizontalLines=false
Table.showVerticalLines=false Table.showVerticalLines=false
Table.consistentHomeEndKeyBehavior=true
Table.intercellSpacing={dimension}0,0 Table.intercellSpacing={dimension}0,0
Table.scrollPaneBorder=com.formdev.flatlaf.ui.FlatBorder Table.scrollPaneBorder=com.formdev.flatlaf.ui.FlatBorder
Table.ascendingSortIcon=com.formdev.flatlaf.icons.FlatAscendingSortIcon Table.ascendingSortIcon=com.formdev.flatlaf.icons.FlatAscendingSortIcon
@@ -560,6 +594,31 @@ TitledBorder.titleColor=@foreground
TitledBorder.border=1,1,1,1,$Separator.foreground TitledBorder.border=1,1,1,1,$Separator.foreground
#---- TitlePane ----
TitlePane.menuBarEmbedded=true
TitlePane.iconSize=16,16
TitlePane.iconMargins=3,8,3,0
TitlePane.menuBarMargins=0,8,0,22
TitlePane.titleMargins=3,8,3,8
TitlePane.buttonSize=44,30
TitlePane.buttonMaximizedHeight=22
TitlePane.closeIcon=com.formdev.flatlaf.icons.FlatWindowCloseIcon
TitlePane.iconifyIcon=com.formdev.flatlaf.icons.FlatWindowIconifyIcon
TitlePane.maximizeIcon=com.formdev.flatlaf.icons.FlatWindowMaximizeIcon
TitlePane.restoreIcon=com.formdev.flatlaf.icons.FlatWindowRestoreIcon
TitlePane.background=$MenuBar.background
TitlePane.inactiveBackground=$TitlePane.background
TitlePane.foreground=@foreground
TitlePane.inactiveForeground=@disabledText
TitlePane.closeHoverBackground=#e81123
TitlePane.closePressedBackground=rgba($TitlePane.closeHoverBackground,60%)
TitlePane.closeHoverForeground=#fff
TitlePane.closePressedForeground=#fff
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.border=com.formdev.flatlaf.ui.FlatButtonBorder ToggleButton.border=com.formdev.flatlaf.ui.FlatButtonBorder
@@ -608,6 +667,7 @@ ToolTipManager.enableToolTipMode=activeApplication
#---- Tree ---- #---- Tree ----
Tree.border=1,1,1,1 Tree.border=1,1,1,1
Tree.editorBorder=1,1,1,1,@cellFocusColor
Tree.selectionInactiveBackground=@selectionInactiveBackground Tree.selectionInactiveBackground=@selectionInactiveBackground
Tree.selectionInactiveForeground=@selectionInactiveForeground Tree.selectionInactiveForeground=@selectionInactiveForeground
Tree.textBackground=$Tree.background Tree.textBackground=$Tree.background
@@ -620,6 +680,7 @@ Tree.rendererMargins=1,2,1,2
Tree.wideSelection=true Tree.wideSelection=true
Tree.repaintWholeRow=true Tree.repaintWholeRow=true
Tree.paintLines=false Tree.paintLines=false
Tree.showCellFocusIndicator=false
Tree.leftChildIndent=7 Tree.leftChildIndent=7
Tree.rightChildIndent=11 Tree.rightChildIndent=11
Tree.rowHeight=0 Tree.rowHeight=0

View File

@@ -29,9 +29,9 @@
@disabledText=#8C8C8C @disabledText=#8C8C8C
@textComponentBackground=#ffffff @textComponentBackground=#ffffff
@menuBackground=#fff @menuBackground=#fff
@menuHoverBackground=darken(@menuBackground,10%) @menuHoverBackground=darken(@menuBackground,10%,derived)
@menuCheckBackground=darken(@menuBackground,10%) @menuCheckBackground=darken(@menuBackground,10%,derived)
@menuCheckHoverBackground=darken(@menuBackground,20%) @menuCheckHoverBackground=darken(@menuBackground,20%,derived)
@cellFocusColor=#000000 @cellFocusColor=#000000
@icon=#afafaf @icon=#afafaf
@@ -73,8 +73,8 @@ controlDkShadow=darken($controlShadow,15%)
Button.background=#ffffff Button.background=#ffffff
Button.focusedBackground=#e3f1fa Button.focusedBackground=#e3f1fa
Button.hoverBackground=darken($Button.background,3%,derived autoInverse) Button.hoverBackground=darken($Button.background,3%,derived)
Button.pressedBackground=darken($Button.background,10%,derived autoInverse) Button.pressedBackground=darken($Button.background,10%,derived)
Button.borderColor=$Component.borderColor Button.borderColor=$Component.borderColor
Button.disabledBorderColor=$Component.disabledBorderColor Button.disabledBorderColor=$Component.disabledBorderColor
@@ -92,26 +92,50 @@ Button.default.focusedBorderColor=$Button.focusedBorderColor
Button.default.focusColor=$Component.focusColor Button.default.focusColor=$Component.focusColor
Button.default.borderWidth=2 Button.default.borderWidth=2
Button.toolbar.hoverBackground=darken($Button.background,12%,derived autoInverse) Button.toolbar.hoverBackground=darken($Button.background,12%,derived)
Button.toolbar.pressedBackground=darken($Button.background,15%,derived autoInverse) Button.toolbar.pressedBackground=darken($Button.background,15%,derived)
#---- CheckBox ---- #---- CheckBox ----
# enabled
CheckBox.icon.borderColor=#b0b0b0 CheckBox.icon.borderColor=#b0b0b0
CheckBox.icon.disabledBorderColor=#BDBDBD
CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
CheckBox.icon.focusedBorderColor=#7B9FC7
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
CheckBox.icon.background=#FFFFFF CheckBox.icon.background=#FFFFFF
CheckBox.icon.disabledBackground=@background CheckBox.icon.selectedBorderColor=$CheckBox.icon.borderColor
CheckBox.icon.focusedBackground=$Button.focusedBackground CheckBox.icon.selectedBackground=$CheckBox.icon.background
CheckBox.icon.hoverBackground=$Button.hoverBackground
CheckBox.icon.pressedBackground=$Button.pressedBackground
CheckBox.icon.selectedBackground=#FFFFFF
CheckBox.icon.checkmarkColor=#4F9EE3 CheckBox.icon.checkmarkColor=#4F9EE3
# disabled
CheckBox.icon.disabledBorderColor=#BDBDBD
CheckBox.icon.disabledBackground=@background
CheckBox.icon.disabledCheckmarkColor=#ABABAB CheckBox.icon.disabledCheckmarkColor=#ABABAB
# focused
CheckBox.icon.focusedBorderColor=#7B9FC7
CheckBox.icon.focusedBackground=$Button.focusedBackground
# hover
CheckBox.icon.hoverBorderColor=$CheckBox.icon.focusedBorderColor
CheckBox.icon.hoverBackground=$Button.hoverBackground
# pressed
CheckBox.icon.pressedBackground=$Button.pressedBackground
# used if CheckBox.icon.style=filled
# enabled
CheckBox.icon[filled].selectedBorderColor=#4B97D9
CheckBox.icon[filled].selectedBackground=#4F9EE3
CheckBox.icon[filled].checkmarkColor=#FFFFFF
# focused
CheckBox.icon[filled].selectedFocusedBorderColor=#ACCFF7
CheckBox.icon[filled].selectedFocusedBackground=$CheckBox.icon[filled].selectedBackground
CheckBox.icon[filled].selectedFocusedCheckmarkColor=$CheckBox.icon.focusedBackground
# hover
CheckBox.icon[filled].selectedHoverBackground=darken($CheckBox.icon[filled].selectedBackground,5%)
# pressed
CheckBox.icon[filled].selectedPressedBackground=darken($CheckBox.icon[filled].selectedBackground,10%)
#---- ComboBox ---- #---- ComboBox ----
@@ -136,7 +160,7 @@ Component.error.borderColor=lighten(desaturate($Component.error.focusedBorderCol
Component.error.focusedBorderColor=#e53e4d Component.error.focusedBorderColor=#e53e4d
Component.warning.borderColor=lighten(saturate($Component.warning.focusedBorderColor,25%),20%) Component.warning.borderColor=lighten(saturate($Component.warning.focusedBorderColor,25%),20%)
Component.warning.focusedBorderColor=#e2a53a Component.warning.focusedBorderColor=#e2a53a
Component.custom.borderColor=lighten(desaturate(#f00,20%,derived),25%,derived) Component.custom.borderColor=lighten(desaturate(#f00,20%,derived noAutoInverse),25%,derived noAutoInverse)
#---- Desktop ---- #---- Desktop ----
@@ -164,8 +188,8 @@ InternalFrame.inactiveTitleForeground=@disabledText
InternalFrame.activeBorderColor=darken($Component.borderColor,20%) InternalFrame.activeBorderColor=darken($Component.borderColor,20%)
InternalFrame.inactiveBorderColor=$Component.borderColor InternalFrame.inactiveBorderColor=$Component.borderColor
InternalFrame.buttonHoverBackground=darken($InternalFrame.activeTitleBackground,10%,derived autoInverse) InternalFrame.buttonHoverBackground=darken($InternalFrame.activeTitleBackground,10%,derived)
InternalFrame.buttonPressedBackground=darken($InternalFrame.activeTitleBackground,20%,derived autoInverse) InternalFrame.buttonPressedBackground=darken($InternalFrame.activeTitleBackground,20%,derived)
InternalFrame.closeHoverBackground=lazy(Actions.Red) InternalFrame.closeHoverBackground=lazy(Actions.Red)
InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy) InternalFrame.closePressedBackground=darken(Actions.Red,10%,lazy)
InternalFrame.closeHoverForeground=#fff InternalFrame.closeHoverForeground=#fff
@@ -222,12 +246,26 @@ ProgressBar.selectionForeground=@textComponentBackground
ProgressBar.selectionBackground=@foreground ProgressBar.selectionBackground=@foreground
#---- RadioButton ----
RadioButton.icon[filled].centerDiameter=5
#---- RootPane ----
RootPane.activeBorderColor=#707070
RootPane.inactiveBorderColor=lighten($RootPane.activeBorderColor,20%,derived)
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.track=#F5F5F5 ScrollBar.track=lighten(@background,1%,derived noAutoInverse)
ScrollBar.thumb=darken($ScrollBar.track,10%) ScrollBar.thumb=darken($ScrollBar.track,10%,derived noAutoInverse)
ScrollBar.hoverTrackColor=darken($ScrollBar.track,3%) ScrollBar.hoverTrackColor=darken($ScrollBar.track,3%,derived noAutoInverse)
ScrollBar.hoverThumbColor=darken($ScrollBar.thumb,10%) ScrollBar.hoverThumbColor=darken($ScrollBar.thumb,10%,derived noAutoInverse)
ScrollBar.pressedThumbColor=darken($ScrollBar.thumb,20%,derived noAutoInverse)
ScrollBar.hoverButtonBackground=darken(@background,5%,derived noAutoInverse)
ScrollBar.pressedButtonBackground=darken(@background,10%,derived noAutoInverse)
#---- Separator ---- #---- Separator ----
@@ -240,7 +278,7 @@ Separator.foreground=#d1d1d1
Slider.trackColor=#c4c4c4 Slider.trackColor=#c4c4c4
Slider.thumbColor=#6e6e6e Slider.thumbColor=#6e6e6e
Slider.tickColor=#888888 Slider.tickColor=#888888
Slider.hoverColor=lighten($Slider.thumbColor,15%,derived autoInverse) Slider.hoverColor=lighten($Slider.thumbColor,15%,derived)
Slider.disabledForeground=#c0c0c0 Slider.disabledForeground=#c0c0c0
@@ -273,11 +311,18 @@ TableHeader.separatorColor=darken($TableHeader.background,10%)
TableHeader.bottomSeparatorColor=$TableHeader.separatorColor TableHeader.bottomSeparatorColor=$TableHeader.separatorColor
#---- TitlePane ----
TitlePane.embeddedForeground=lighten($TitlePane.foreground,35%)
TitlePane.buttonHoverBackground=darken($TitlePane.background,10%,derived)
TitlePane.buttonPressedBackground=darken($TitlePane.background,20%,derived)
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.selectedBackground=darken($ToggleButton.background,20%,derived autoInverse) ToggleButton.selectedBackground=darken($ToggleButton.background,20%,derived)
ToggleButton.selectedForeground=@foreground ToggleButton.selectedForeground=@foreground
ToggleButton.disabledSelectedBackground=darken($ToggleButton.background,13%,derived autoInverse) ToggleButton.disabledSelectedBackground=darken($ToggleButton.background,13%,derived)
ToggleButton.toolbar.selectedBackground=$ToggleButton.selectedBackground ToggleButton.toolbar.selectedBackground=$ToggleButton.selectedBackground

View File

@@ -39,12 +39,30 @@ HelpButton.hoverBorderColor=null
ToggleButton.startBackground=$ToggleButton.background ToggleButton.startBackground=$ToggleButton.background
ToggleButton.endBackground=$ToggleButton.background ToggleButton.endBackground=$ToggleButton.background
[dark]ToggleButton.selectedBackground=lighten($ToggleButton.background,15%,derived autoInverse) [dark]ToggleButton.selectedBackground=lighten($ToggleButton.background,15%,derived)
[dark]ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,5%,derived autoInverse) [dark]ToggleButton.disabledSelectedBackground=lighten($ToggleButton.background,5%,derived)
#---- theme specific ---- #---- theme specific ----
[Arc_Theme]ProgressBar.selectionBackground=#000
[Arc_Theme]ProgressBar.selectionForeground=#fff
[Arc_Theme_-_Orange]ProgressBar.selectionBackground=#000
[Arc_Theme_-_Orange]ProgressBar.selectionForeground=#fff
[Arc_Theme_Dark]ProgressBar.selectionBackground=#ddd
[Arc_Theme_Dark]ProgressBar.selectionForeground=#ddd
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionBackground=#ddd
[Arc_Theme_Dark_-_Orange]ProgressBar.selectionForeground=#fff
[Cobalt_2]CheckBox.icon.background=#002946
[Cobalt_2]CheckBox.icon.checkmarkColor=#002946
[Dracula]ProgressBar.selectionBackground=#fff
[Dracula]ProgressBar.selectionForeground=#fff
[Gruvbox_Dark_Hard]ToggleButton.selectedBackground=$ToggleButton.selectedBackground [Gruvbox_Dark_Hard]ToggleButton.selectedBackground=$ToggleButton.selectedBackground
[Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground=$ToggleButton.toolbar.selectedBackground [Gruvbox_Dark_Hard]ToggleButton.toolbar.selectedBackground=$ToggleButton.toolbar.selectedBackground
@@ -62,3 +80,57 @@ ToggleButton.endBackground=$ToggleButton.background
[High_contrast]ToggleButton.selectedForeground=#000 [High_contrast]ToggleButton.selectedForeground=#000
[High_contrast]ToggleButton.disabledSelectedBackground=#444 [High_contrast]ToggleButton.disabledSelectedBackground=#444
[High_contrast]ToggleButton.toolbar.selectedBackground=#fff [High_contrast]ToggleButton.toolbar.selectedBackground=#fff
# Material Theme UI Lite
[Dracula_Contrast]ProgressBar.selectionBackground=#fff
[Dracula_Contrast]ProgressBar.selectionForeground=#fff
[GitHub]ProgressBar.selectionBackground=#222
[GitHub]ProgressBar.selectionForeground=#222
[GitHub_Contrast]ProgressBar.selectionBackground=#222
[GitHub_Contrast]ProgressBar.selectionForeground=#222
[Light_Owl]ProgressBar.selectionBackground=#111
[Light_Owl]ProgressBar.selectionForeground=#fff
[Light_Owl_Contrast]ProgressBar.selectionBackground=#111
[Light_Owl_Contrast]ProgressBar.selectionForeground=#fff
[Material_Lighter]ProgressBar.selectionBackground=#222
[Material_Lighter]ProgressBar.selectionForeground=#fff
[Material_Lighter_Contrast]ProgressBar.selectionBackground=#222
[Material_Lighter_Contrast]ProgressBar.selectionForeground=#fff
[Material_Oceanic]ProgressBar.selectionBackground=#ddd
[Material_Oceanic]ProgressBar.selectionForeground=#ddd
[Material_Oceanic_Contrast]ProgressBar.selectionBackground=#ddd
[Material_Oceanic_Contrast]ProgressBar.selectionForeground=#ddd
[Material_Palenight]ProgressBar.selectionBackground=#ddd
[Material_Palenight]ProgressBar.selectionForeground=#ddd
[Material_Palenight_Contrast]ProgressBar.selectionBackground=#ddd
[Material_Palenight_Contrast]ProgressBar.selectionForeground=#ddd
[Night_Owl]ProgressBar.selectionBackground=#ddd
[Night_Owl]ProgressBar.selectionForeground=#ddd
[Night_Owl_Contrast]ProgressBar.selectionBackground=#ddd
[Night_Owl_Contrast]ProgressBar.selectionForeground=#ddd
[Solarized_Dark]ProgressBar.selectionBackground=#ccc
[Solarized_Dark]ProgressBar.selectionForeground=#ccc
[Material_Solarized_Dark_Contrast]ProgressBar.selectionBackground=#ccc
[Material_Solarized_Dark_Contrast]ProgressBar.selectionForeground=#ccc
[Solarized_Light]ProgressBar.selectionBackground=#222
[Solarized_Light]ProgressBar.selectionForeground=#fff
[Material_Solarized_Light_Contrast]ProgressBar.selectionBackground=#222
[Material_Solarized_Light_Contrast]ProgressBar.selectionForeground=#fff

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<defs>
<linearGradient id="flatlaf-a" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#DD6900"/>
<stop offset="100%" stop-color="#D45500"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="url(#flatlaf-a)"/>
<polygon fill="#FFF" points="9 13 13 13 12.5 11.5 10.5 11.5 10.5 6.5 9 6"/>
<polygon fill="#FFF" points="4 12.5 4 3 9 3 8.5 4.5 5.5 4.5 5.5 7 7.5 7 7 8.5 5.5 8.5 5.5 12"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 583 B

View File

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

View File

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

View File

@@ -158,12 +158,12 @@ class BasicComponentsPanel
add(labelLabel, "cell 0 0"); add(labelLabel, "cell 0 0");
//---- label1 ---- //---- label1 ----
label1.setText("enabled"); label1.setText("Enabled");
label1.setDisplayedMnemonic('E'); label1.setDisplayedMnemonic('E');
add(label1, "cell 1 0"); add(label1, "cell 1 0");
//---- label2 ---- //---- label2 ----
label2.setText("disabled"); label2.setText("Disabled");
label2.setDisplayedMnemonic('D'); label2.setDisplayedMnemonic('D');
label2.setEnabled(false); label2.setEnabled(false);
add(label2, "cell 2 0"); add(label2, "cell 2 0");
@@ -173,23 +173,23 @@ class BasicComponentsPanel
add(buttonLabel, "cell 0 1"); add(buttonLabel, "cell 0 1");
//---- button1 ---- //---- button1 ----
button1.setText("enabled"); button1.setText("Enabled");
button1.setDisplayedMnemonicIndex(0); button1.setDisplayedMnemonicIndex(0);
add(button1, "cell 1 1"); add(button1, "cell 1 1");
//---- button2 ---- //---- button2 ----
button2.setText("disabled"); button2.setText("Disabled");
button2.setDisplayedMnemonicIndex(0); button2.setDisplayedMnemonicIndex(0);
button2.setEnabled(false); button2.setEnabled(false);
add(button2, "cell 2 1"); add(button2, "cell 2 1");
//---- button5 ---- //---- button5 ----
button5.setText("square"); button5.setText("Square");
button5.putClientProperty("JButton.buttonType", "square"); button5.putClientProperty("JButton.buttonType", "square");
add(button5, "cell 3 1"); add(button5, "cell 3 1");
//---- button6 ---- //---- button6 ----
button6.setText("round"); button6.setText("Round");
button6.putClientProperty("JButton.buttonType", "roundRect"); button6.putClientProperty("JButton.buttonType", "roundRect");
add(button6, "cell 4 1"); add(button6, "cell 4 1");
@@ -225,23 +225,23 @@ class BasicComponentsPanel
add(checkBoxLabel, "cell 0 2"); add(checkBoxLabel, "cell 0 2");
//---- checkBox1 ---- //---- checkBox1 ----
checkBox1.setText("enabled"); checkBox1.setText("Enabled");
checkBox1.setMnemonic('A'); checkBox1.setMnemonic('A');
add(checkBox1, "cell 1 2"); add(checkBox1, "cell 1 2");
//---- checkBox2 ---- //---- checkBox2 ----
checkBox2.setText("disabled"); checkBox2.setText("Disabled");
checkBox2.setEnabled(false); checkBox2.setEnabled(false);
checkBox2.setMnemonic('D'); checkBox2.setMnemonic('D');
add(checkBox2, "cell 2 2"); add(checkBox2, "cell 2 2");
//---- checkBox3 ---- //---- checkBox3 ----
checkBox3.setText("selected"); checkBox3.setText("Selected");
checkBox3.setSelected(true); checkBox3.setSelected(true);
add(checkBox3, "cell 3 2"); add(checkBox3, "cell 3 2");
//---- checkBox4 ---- //---- checkBox4 ----
checkBox4.setText("selected disabled"); checkBox4.setText("Selected disabled");
checkBox4.setSelected(true); checkBox4.setSelected(true);
checkBox4.setEnabled(false); checkBox4.setEnabled(false);
add(checkBox4, "cell 4 2"); add(checkBox4, "cell 4 2");
@@ -251,23 +251,23 @@ class BasicComponentsPanel
add(radioButtonLabel, "cell 0 3"); add(radioButtonLabel, "cell 0 3");
//---- radioButton1 ---- //---- radioButton1 ----
radioButton1.setText("enabled"); radioButton1.setText("Enabled");
radioButton1.setMnemonic('N'); radioButton1.setMnemonic('N');
add(radioButton1, "cell 1 3"); add(radioButton1, "cell 1 3");
//---- radioButton2 ---- //---- radioButton2 ----
radioButton2.setText("disabled"); radioButton2.setText("Disabled");
radioButton2.setEnabled(false); radioButton2.setEnabled(false);
radioButton2.setMnemonic('S'); radioButton2.setMnemonic('S');
add(radioButton2, "cell 2 3"); add(radioButton2, "cell 2 3");
//---- radioButton3 ---- //---- radioButton3 ----
radioButton3.setText("selected"); radioButton3.setText("Selected");
radioButton3.setSelected(true); radioButton3.setSelected(true);
add(radioButton3, "cell 3 3"); add(radioButton3, "cell 3 3");
//---- radioButton4 ---- //---- radioButton4 ----
radioButton4.setText("selected disabled"); radioButton4.setText("Selected disabled");
radioButton4.setSelected(true); radioButton4.setSelected(true);
radioButton4.setEnabled(false); radioButton4.setEnabled(false);
add(radioButton4, "cell 4 3"); add(radioButton4, "cell 4 3");
@@ -281,7 +281,7 @@ class BasicComponentsPanel
//---- comboBox1 ---- //---- comboBox1 ----
comboBox1.setEditable(true); comboBox1.setEditable(true);
comboBox1.setModel(new DefaultComboBoxModel<>(new String[] { comboBox1.setModel(new DefaultComboBoxModel<>(new String[] {
"editable", "Editable",
"a", "a",
"bb", "bb",
"ccc" "ccc"
@@ -292,7 +292,7 @@ class BasicComponentsPanel
comboBox2.setEditable(true); comboBox2.setEditable(true);
comboBox2.setEnabled(false); comboBox2.setEnabled(false);
comboBox2.setModel(new DefaultComboBoxModel<>(new String[] { comboBox2.setModel(new DefaultComboBoxModel<>(new String[] {
"disabled", "Disabled",
"a", "a",
"bb", "bb",
"ccc" "ccc"
@@ -301,7 +301,7 @@ class BasicComponentsPanel
//---- comboBox3 ---- //---- comboBox3 ----
comboBox3.setModel(new DefaultComboBoxModel<>(new String[] { comboBox3.setModel(new DefaultComboBoxModel<>(new String[] {
"not editable", "Not editable",
"a", "a",
"bb", "bb",
"ccc" "ccc"
@@ -310,7 +310,7 @@ class BasicComponentsPanel
//---- comboBox4 ---- //---- comboBox4 ----
comboBox4.setModel(new DefaultComboBoxModel<>(new String[] { comboBox4.setModel(new DefaultComboBoxModel<>(new String[] {
"not editable disabled", "Not editable disabled",
"a", "a",
"bb", "bb",
"ccc" "ccc"
@@ -320,7 +320,7 @@ class BasicComponentsPanel
//---- comboBox5 ---- //---- comboBox5 ----
comboBox5.setModel(new DefaultComboBoxModel<>(new String[] { comboBox5.setModel(new DefaultComboBoxModel<>(new String[] {
"wide popup if text is longer", "Wide popup if text is longer",
"aa", "aa",
"bbb", "bbb",
"cccc" "cccc"
@@ -340,7 +340,7 @@ class BasicComponentsPanel
//---- comboBox6 ---- //---- comboBox6 ----
comboBox6.setEditable(true); comboBox6.setEditable(true);
comboBox6.putClientProperty("JTextField.placeholderText", "placeholder"); comboBox6.putClientProperty("JTextField.placeholderText", "Placeholder");
add(comboBox6, "cell 5 5,growx"); add(comboBox6, "cell 5 5,growx");
//---- textFieldLabel ---- //---- textFieldLabel ----
@@ -350,28 +350,28 @@ class BasicComponentsPanel
add(textFieldLabel, "cell 0 6"); add(textFieldLabel, "cell 0 6");
//---- textField1 ---- //---- textField1 ----
textField1.setText("editable"); textField1.setText("Editable");
textField1.setComponentPopupMenu(popupMenu1); textField1.setComponentPopupMenu(popupMenu1);
add(textField1, "cell 1 6,growx"); add(textField1, "cell 1 6,growx");
//---- textField2 ---- //---- textField2 ----
textField2.setText("disabled"); textField2.setText("Disabled");
textField2.setEnabled(false); textField2.setEnabled(false);
add(textField2, "cell 2 6,growx"); add(textField2, "cell 2 6,growx");
//---- textField3 ---- //---- textField3 ----
textField3.setText("not editable"); textField3.setText("Not editable");
textField3.setEditable(false); textField3.setEditable(false);
add(textField3, "cell 3 6,growx"); add(textField3, "cell 3 6,growx");
//---- textField4 ---- //---- textField4 ----
textField4.setText("not editable disabled"); textField4.setText("Not editable disabled");
textField4.setEnabled(false); textField4.setEnabled(false);
textField4.setEditable(false); textField4.setEditable(false);
add(textField4, "cell 4 6,growx"); add(textField4, "cell 4 6,growx");
//---- textField6 ---- //---- textField6 ----
textField6.putClientProperty("JTextField.placeholderText", "placeholder"); textField6.putClientProperty("JTextField.placeholderText", "Placeholder");
add(textField6, "cell 5 6,growx"); add(textField6, "cell 5 6,growx");
//---- formattedTextFieldLabel ---- //---- formattedTextFieldLabel ----
@@ -381,28 +381,28 @@ class BasicComponentsPanel
add(formattedTextFieldLabel, "cell 0 7"); add(formattedTextFieldLabel, "cell 0 7");
//---- formattedTextField1 ---- //---- formattedTextField1 ----
formattedTextField1.setText("editable"); formattedTextField1.setText("Editable");
formattedTextField1.setComponentPopupMenu(popupMenu1); formattedTextField1.setComponentPopupMenu(popupMenu1);
add(formattedTextField1, "cell 1 7,growx"); add(formattedTextField1, "cell 1 7,growx");
//---- formattedTextField2 ---- //---- formattedTextField2 ----
formattedTextField2.setText("disabled"); formattedTextField2.setText("Disabled");
formattedTextField2.setEnabled(false); formattedTextField2.setEnabled(false);
add(formattedTextField2, "cell 2 7,growx"); add(formattedTextField2, "cell 2 7,growx");
//---- formattedTextField3 ---- //---- formattedTextField3 ----
formattedTextField3.setText("not editable"); formattedTextField3.setText("Not editable");
formattedTextField3.setEditable(false); formattedTextField3.setEditable(false);
add(formattedTextField3, "cell 3 7,growx"); add(formattedTextField3, "cell 3 7,growx");
//---- formattedTextField4 ---- //---- formattedTextField4 ----
formattedTextField4.setText("not editable disabled"); formattedTextField4.setText("Not editable disabled");
formattedTextField4.setEnabled(false); formattedTextField4.setEnabled(false);
formattedTextField4.setEditable(false); formattedTextField4.setEditable(false);
add(formattedTextField4, "cell 4 7,growx"); add(formattedTextField4, "cell 4 7,growx");
//---- formattedTextField5 ---- //---- formattedTextField5 ----
formattedTextField5.putClientProperty("JTextField.placeholderText", "placeholder"); formattedTextField5.putClientProperty("JTextField.placeholderText", "Placeholder");
add(formattedTextField5, "cell 5 7,growx"); add(formattedTextField5, "cell 5 7,growx");
//---- passwordFieldLabel ---- //---- passwordFieldLabel ----
@@ -410,27 +410,27 @@ class BasicComponentsPanel
add(passwordFieldLabel, "cell 0 8"); add(passwordFieldLabel, "cell 0 8");
//---- passwordField1 ---- //---- passwordField1 ----
passwordField1.setText("editable"); passwordField1.setText("Editable");
add(passwordField1, "cell 1 8,growx"); add(passwordField1, "cell 1 8,growx");
//---- passwordField2 ---- //---- passwordField2 ----
passwordField2.setText("disabled"); passwordField2.setText("Disabled");
passwordField2.setEnabled(false); passwordField2.setEnabled(false);
add(passwordField2, "cell 2 8,growx"); add(passwordField2, "cell 2 8,growx");
//---- passwordField3 ---- //---- passwordField3 ----
passwordField3.setText("not editable"); passwordField3.setText("Not editable");
passwordField3.setEditable(false); passwordField3.setEditable(false);
add(passwordField3, "cell 3 8,growx"); add(passwordField3, "cell 3 8,growx");
//---- passwordField4 ---- //---- passwordField4 ----
passwordField4.setText("not editable disabled"); passwordField4.setText("Not editable disabled");
passwordField4.setEnabled(false); passwordField4.setEnabled(false);
passwordField4.setEditable(false); passwordField4.setEditable(false);
add(passwordField4, "cell 4 8,growx"); add(passwordField4, "cell 4 8,growx");
//---- passwordField5 ---- //---- passwordField5 ----
passwordField5.putClientProperty("JTextField.placeholderText", "placeholder"); passwordField5.putClientProperty("JTextField.placeholderText", "Placeholder");
add(passwordField5, "cell 5 8,growx"); add(passwordField5, "cell 5 8,growx");
//---- textAreaLabel ---- //---- textAreaLabel ----
@@ -443,7 +443,7 @@ class BasicComponentsPanel
scrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textArea1 ---- //---- textArea1 ----
textArea1.setText("editable"); textArea1.setText("Editable");
textArea1.setRows(2); textArea1.setRows(2);
scrollPane1.setViewportView(textArea1); scrollPane1.setViewportView(textArea1);
} }
@@ -455,7 +455,7 @@ class BasicComponentsPanel
scrollPane2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane2.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textArea2 ---- //---- textArea2 ----
textArea2.setText("disabled"); textArea2.setText("Disabled");
textArea2.setRows(2); textArea2.setRows(2);
textArea2.setEnabled(false); textArea2.setEnabled(false);
scrollPane2.setViewportView(textArea2); scrollPane2.setViewportView(textArea2);
@@ -468,7 +468,7 @@ class BasicComponentsPanel
scrollPane3.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane3.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textArea3 ---- //---- textArea3 ----
textArea3.setText("not editable"); textArea3.setText("Not editable");
textArea3.setRows(2); textArea3.setRows(2);
textArea3.setEditable(false); textArea3.setEditable(false);
scrollPane3.setViewportView(textArea3); scrollPane3.setViewportView(textArea3);
@@ -481,7 +481,7 @@ class BasicComponentsPanel
scrollPane4.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane4.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textArea4 ---- //---- textArea4 ----
textArea4.setText("not editable disabled"); textArea4.setText("Not editable disabled");
textArea4.setRows(2); textArea4.setRows(2);
textArea4.setEditable(false); textArea4.setEditable(false);
textArea4.setEnabled(false); textArea4.setEnabled(false);
@@ -491,7 +491,7 @@ class BasicComponentsPanel
//---- textArea5 ---- //---- textArea5 ----
textArea5.setRows(2); textArea5.setRows(2);
textArea5.setText("no scroll pane"); textArea5.setText("No scroll pane");
add(textArea5, "cell 5 9,growx"); add(textArea5, "cell 5 9,growx");
//---- editorPaneLabel ---- //---- editorPaneLabel ----
@@ -504,7 +504,7 @@ class BasicComponentsPanel
scrollPane5.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane5.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- editorPane1 ---- //---- editorPane1 ----
editorPane1.setText("editable"); editorPane1.setText("Editable");
scrollPane5.setViewportView(editorPane1); scrollPane5.setViewportView(editorPane1);
} }
add(scrollPane5, "cell 1 10,growx"); add(scrollPane5, "cell 1 10,growx");
@@ -515,7 +515,7 @@ class BasicComponentsPanel
scrollPane6.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane6.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- editorPane2 ---- //---- editorPane2 ----
editorPane2.setText("disabled"); editorPane2.setText("Disabled");
editorPane2.setEnabled(false); editorPane2.setEnabled(false);
scrollPane6.setViewportView(editorPane2); scrollPane6.setViewportView(editorPane2);
} }
@@ -527,7 +527,7 @@ class BasicComponentsPanel
scrollPane7.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane7.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- editorPane3 ---- //---- editorPane3 ----
editorPane3.setText("not editable"); editorPane3.setText("Not editable");
editorPane3.setEditable(false); editorPane3.setEditable(false);
scrollPane7.setViewportView(editorPane3); scrollPane7.setViewportView(editorPane3);
} }
@@ -539,7 +539,7 @@ class BasicComponentsPanel
scrollPane8.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane8.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- editorPane4 ---- //---- editorPane4 ----
editorPane4.setText("not editable disabled"); editorPane4.setText("Not editable disabled");
editorPane4.setEditable(false); editorPane4.setEditable(false);
editorPane4.setEnabled(false); editorPane4.setEnabled(false);
scrollPane8.setViewportView(editorPane4); scrollPane8.setViewportView(editorPane4);
@@ -547,7 +547,7 @@ class BasicComponentsPanel
add(scrollPane8, "cell 4 10,growx"); add(scrollPane8, "cell 4 10,growx");
//---- editorPane5 ---- //---- editorPane5 ----
editorPane5.setText("no scroll pane"); editorPane5.setText("No scroll pane");
add(editorPane5, "cell 5 10,growx"); add(editorPane5, "cell 5 10,growx");
//---- textPaneLabel ---- //---- textPaneLabel ----
@@ -560,7 +560,7 @@ class BasicComponentsPanel
scrollPane9.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane9.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textPane1 ---- //---- textPane1 ----
textPane1.setText("editable"); textPane1.setText("Editable");
scrollPane9.setViewportView(textPane1); scrollPane9.setViewportView(textPane1);
} }
add(scrollPane9, "cell 1 11,growx"); add(scrollPane9, "cell 1 11,growx");
@@ -571,7 +571,7 @@ class BasicComponentsPanel
scrollPane10.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane10.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textPane2 ---- //---- textPane2 ----
textPane2.setText("disabled"); textPane2.setText("Disabled");
textPane2.setEnabled(false); textPane2.setEnabled(false);
scrollPane10.setViewportView(textPane2); scrollPane10.setViewportView(textPane2);
} }
@@ -583,7 +583,7 @@ class BasicComponentsPanel
scrollPane11.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane11.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textPane3 ---- //---- textPane3 ----
textPane3.setText("not editable"); textPane3.setText("Not editable");
textPane3.setEditable(false); textPane3.setEditable(false);
scrollPane11.setViewportView(textPane3); scrollPane11.setViewportView(textPane3);
} }
@@ -595,7 +595,7 @@ class BasicComponentsPanel
scrollPane12.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane12.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//---- textPane4 ---- //---- textPane4 ----
textPane4.setText("not editable disabled"); textPane4.setText("Not editable disabled");
textPane4.setEditable(false); textPane4.setEditable(false);
textPane4.setEnabled(false); textPane4.setEnabled(false);
scrollPane12.setViewportView(textPane4); scrollPane12.setViewportView(textPane4);
@@ -603,7 +603,7 @@ class BasicComponentsPanel
add(scrollPane12, "cell 4 11,growx"); add(scrollPane12, "cell 4 11,growx");
//---- textPane5 ---- //---- textPane5 ----
textPane5.setText("no scroll pane"); textPane5.setText("No scroll pane");
add(textPane5, "cell 5 11,growx"); add(textPane5, "cell 5 11,growx");
//---- label3 ---- //---- label3 ----
@@ -617,7 +617,7 @@ class BasicComponentsPanel
//---- comboBox7 ---- //---- comboBox7 ----
comboBox7.putClientProperty("JComponent.outline", "error"); comboBox7.putClientProperty("JComponent.outline", "error");
comboBox7.setModel(new DefaultComboBoxModel<>(new String[] { comboBox7.setModel(new DefaultComboBoxModel<>(new String[] {
"editable" "Editable"
})); }));
comboBox7.setEditable(true); comboBox7.setEditable(true);
add(comboBox7, "cell 2 12,growx"); add(comboBox7, "cell 2 12,growx");
@@ -637,7 +637,7 @@ class BasicComponentsPanel
//---- comboBox8 ---- //---- comboBox8 ----
comboBox8.putClientProperty("JComponent.outline", "warning"); comboBox8.putClientProperty("JComponent.outline", "warning");
comboBox8.setModel(new DefaultComboBoxModel<>(new String[] { comboBox8.setModel(new DefaultComboBoxModel<>(new String[] {
"not editable" "Not editable"
})); }));
add(comboBox8, "cell 2 13,growx"); add(comboBox8, "cell 2 13,growx");

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8" JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -20,14 +20,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1" name: "label1"
"text": "enabled" "text": "Enabled"
"displayedMnemonic": 69 "displayedMnemonic": 69
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0" "value": "cell 1 0"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "label2" name: "label2"
"text": "disabled" "text": "Disabled"
"displayedMnemonic": 68 "displayedMnemonic": 68
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -41,14 +41,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "button1" name: "button1"
"text": "enabled" "text": "Enabled"
"displayedMnemonicIndex": 0 "displayedMnemonicIndex": 0
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1" "value": "cell 1 1"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "button2" name: "button2"
"text": "disabled" "text": "Disabled"
"displayedMnemonicIndex": 0 "displayedMnemonicIndex": 0
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -56,14 +56,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "button5" name: "button5"
"text": "square" "text": "Square"
"$client.JButton.buttonType": "square" "$client.JButton.buttonType": "square"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 1" "value": "cell 3 1"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "button6" name: "button6"
"text": "round" "text": "Round"
"$client.JButton.buttonType": "roundRect" "$client.JButton.buttonType": "roundRect"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1" "value": "cell 4 1"
@@ -115,14 +115,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "checkBox1" name: "checkBox1"
"text": "enabled" "text": "Enabled"
"mnemonic": 65 "mnemonic": 65
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2" "value": "cell 1 2"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "checkBox2" name: "checkBox2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
"mnemonic": 68 "mnemonic": 68
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -130,14 +130,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "checkBox3" name: "checkBox3"
"text": "selected" "text": "Selected"
"selected": true "selected": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 2" "value": "cell 3 2"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "checkBox4" name: "checkBox4"
"text": "selected disabled" "text": "Selected disabled"
"selected": true "selected": true
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -151,14 +151,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JRadioButton" ) { add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "radioButton1" name: "radioButton1"
"text": "enabled" "text": "Enabled"
"mnemonic": 78 "mnemonic": 78
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3" "value": "cell 1 3"
} ) } )
add( new FormComponent( "javax.swing.JRadioButton" ) { add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "radioButton2" name: "radioButton2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
"mnemonic": 83 "mnemonic": 83
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -166,14 +166,14 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JRadioButton" ) { add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "radioButton3" name: "radioButton3"
"text": "selected" "text": "Selected"
"selected": true "selected": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 3" "value": "cell 3 3"
} ) } )
add( new FormComponent( "javax.swing.JRadioButton" ) { add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "radioButton4" name: "radioButton4"
"text": "selected disabled" "text": "Selected disabled"
"selected": true "selected": true
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -191,8 +191,8 @@ new FormModel {
name: "comboBox1" name: "comboBox1"
"editable": true "editable": true
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "editable" selectedItem: "Editable"
addElement( "editable" ) addElement( "Editable" )
addElement( "a" ) addElement( "a" )
addElement( "bb" ) addElement( "bb" )
addElement( "ccc" ) addElement( "ccc" )
@@ -205,8 +205,8 @@ new FormModel {
"editable": true "editable": true
"enabled": false "enabled": false
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "disabled" selectedItem: "Disabled"
addElement( "disabled" ) addElement( "Disabled" )
addElement( "a" ) addElement( "a" )
addElement( "bb" ) addElement( "bb" )
addElement( "ccc" ) addElement( "ccc" )
@@ -217,8 +217,8 @@ new FormModel {
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JComboBox" ) {
name: "comboBox3" name: "comboBox3"
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "not editable" selectedItem: "Not editable"
addElement( "not editable" ) addElement( "Not editable" )
addElement( "a" ) addElement( "a" )
addElement( "bb" ) addElement( "bb" )
addElement( "ccc" ) addElement( "ccc" )
@@ -229,8 +229,8 @@ new FormModel {
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JComboBox" ) {
name: "comboBox4" name: "comboBox4"
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "not editable disabled" selectedItem: "Not editable disabled"
addElement( "not editable disabled" ) addElement( "Not editable disabled" )
addElement( "a" ) addElement( "a" )
addElement( "bb" ) addElement( "bb" )
addElement( "ccc" ) addElement( "ccc" )
@@ -242,8 +242,8 @@ new FormModel {
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JComboBox" ) {
name: "comboBox5" name: "comboBox5"
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "wide popup if text is longer" selectedItem: "Wide popup if text is longer"
addElement( "wide popup if text is longer" ) addElement( "Wide popup if text is longer" )
addElement( "aa" ) addElement( "aa" )
addElement( "bbb" ) addElement( "bbb" )
addElement( "cccc" ) addElement( "cccc" )
@@ -273,7 +273,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "javax.swing.JComboBox" ) {
name: "comboBox6" name: "comboBox6"
"editable": true "editable": true
"$client.JTextField.placeholderText": "placeholder" "$client.JTextField.placeholderText": "Placeholder"
auxiliary() { auxiliary() {
"JavaCodeGenerator.typeParameters": "String" "JavaCodeGenerator.typeParameters": "String"
} }
@@ -290,28 +290,28 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField1" name: "textField1"
"text": "editable" "text": "Editable"
"componentPopupMenu": &FormReference0 new FormReference( "popupMenu1" ) "componentPopupMenu": &FormReference0 new FormReference( "popupMenu1" )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6,growx" "value": "cell 1 6,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField2" name: "textField2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 6,growx" "value": "cell 2 6,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField3" name: "textField3"
"text": "not editable" "text": "Not editable"
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 6,growx" "value": "cell 3 6,growx"
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField4" name: "textField4"
"text": "not editable disabled" "text": "Not editable disabled"
"enabled": false "enabled": false
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -319,7 +319,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JTextField" ) { add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField6" name: "textField6"
"$client.JTextField.placeholderText": "placeholder" "$client.JTextField.placeholderText": "Placeholder"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 6,growx" "value": "cell 5 6,growx"
} ) } )
@@ -333,28 +333,28 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JFormattedTextField" ) { add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField1" name: "formattedTextField1"
"text": "editable" "text": "Editable"
"componentPopupMenu": #FormReference0 "componentPopupMenu": #FormReference0
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7,growx" "value": "cell 1 7,growx"
} ) } )
add( new FormComponent( "javax.swing.JFormattedTextField" ) { add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField2" name: "formattedTextField2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 7,growx" "value": "cell 2 7,growx"
} ) } )
add( new FormComponent( "javax.swing.JFormattedTextField" ) { add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField3" name: "formattedTextField3"
"text": "not editable" "text": "Not editable"
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 7,growx" "value": "cell 3 7,growx"
} ) } )
add( new FormComponent( "javax.swing.JFormattedTextField" ) { add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField4" name: "formattedTextField4"
"text": "not editable disabled" "text": "Not editable disabled"
"enabled": false "enabled": false
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -362,7 +362,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JFormattedTextField" ) { add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField5" name: "formattedTextField5"
"$client.JTextField.placeholderText": "placeholder" "$client.JTextField.placeholderText": "Placeholder"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 7,growx" "value": "cell 5 7,growx"
} ) } )
@@ -374,27 +374,27 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JPasswordField" ) { add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField1" name: "passwordField1"
"text": "editable" "text": "Editable"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 8,growx" "value": "cell 1 8,growx"
} ) } )
add( new FormComponent( "javax.swing.JPasswordField" ) { add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField2" name: "passwordField2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 8,growx" "value": "cell 2 8,growx"
} ) } )
add( new FormComponent( "javax.swing.JPasswordField" ) { add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField3" name: "passwordField3"
"text": "not editable" "text": "Not editable"
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 8,growx" "value": "cell 3 8,growx"
} ) } )
add( new FormComponent( "javax.swing.JPasswordField" ) { add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField4" name: "passwordField4"
"text": "not editable disabled" "text": "Not editable disabled"
"enabled": false "enabled": false
"editable": false "editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -402,7 +402,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JPasswordField" ) { add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField5" name: "passwordField5"
"$client.JTextField.placeholderText": "placeholder" "$client.JTextField.placeholderText": "Placeholder"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 8,growx" "value": "cell 5 8,growx"
} ) } )
@@ -418,7 +418,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextArea" ) { add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea1" name: "textArea1"
"text": "editable" "text": "Editable"
"rows": 2 "rows": 2
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -430,7 +430,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextArea" ) { add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea2" name: "textArea2"
"text": "disabled" "text": "Disabled"
"rows": 2 "rows": 2
"enabled": false "enabled": false
} ) } )
@@ -443,7 +443,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextArea" ) { add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea3" name: "textArea3"
"text": "not editable" "text": "Not editable"
"rows": 2 "rows": 2
"editable": false "editable": false
} ) } )
@@ -456,7 +456,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextArea" ) { add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea4" name: "textArea4"
"text": "not editable disabled" "text": "Not editable disabled"
"rows": 2 "rows": 2
"editable": false "editable": false
"enabled": false "enabled": false
@@ -467,7 +467,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JTextArea" ) { add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea5" name: "textArea5"
"rows": 2 "rows": 2
"text": "no scroll pane" "text": "No scroll pane"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 9,growx" "value": "cell 5 9,growx"
} ) } )
@@ -483,7 +483,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JEditorPane" ) { add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane1" name: "editorPane1"
"text": "editable" "text": "Editable"
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 10,growx" "value": "cell 1 10,growx"
@@ -494,7 +494,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JEditorPane" ) { add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane2" name: "editorPane2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -506,7 +506,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JEditorPane" ) { add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane3" name: "editorPane3"
"text": "not editable" "text": "Not editable"
"editable": false "editable": false
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -518,7 +518,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JEditorPane" ) { add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane4" name: "editorPane4"
"text": "not editable disabled" "text": "Not editable disabled"
"editable": false "editable": false
"enabled": false "enabled": false
} ) } )
@@ -527,7 +527,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JEditorPane" ) { add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane5" name: "editorPane5"
"text": "no scroll pane" "text": "No scroll pane"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 10,growx" "value": "cell 5 10,growx"
} ) } )
@@ -543,7 +543,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextPane" ) { add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane1" name: "textPane1"
"text": "editable" "text": "Editable"
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 11,growx" "value": "cell 1 11,growx"
@@ -554,7 +554,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextPane" ) { add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane2" name: "textPane2"
"text": "disabled" "text": "Disabled"
"enabled": false "enabled": false
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -566,7 +566,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextPane" ) { add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane3" name: "textPane3"
"text": "not editable" "text": "Not editable"
"editable": false "editable": false
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -578,7 +578,7 @@ new FormModel {
"horizontalScrollBarPolicy": 31 "horizontalScrollBarPolicy": 31
add( new FormComponent( "javax.swing.JTextPane" ) { add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane4" name: "textPane4"
"text": "not editable disabled" "text": "Not editable disabled"
"editable": false "editable": false
"enabled": false "enabled": false
} ) } )
@@ -587,7 +587,7 @@ new FormModel {
} ) } )
add( new FormComponent( "javax.swing.JTextPane" ) { add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane5" name: "textPane5"
"text": "no scroll pane" "text": "No scroll pane"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 11,growx" "value": "cell 5 11,growx"
} ) } )
@@ -607,8 +607,8 @@ new FormModel {
name: "comboBox7" name: "comboBox7"
"$client.JComponent.outline": "error" "$client.JComponent.outline": "error"
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "editable" selectedItem: "Editable"
addElement( "editable" ) addElement( "Editable" )
} }
"editable": true "editable": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
@@ -636,8 +636,8 @@ new FormModel {
name: "comboBox8" name: "comboBox8"
"$client.JComponent.outline": "warning" "$client.JComponent.outline": "warning"
"model": new javax.swing.DefaultComboBoxModel { "model": new javax.swing.DefaultComboBoxModel {
selectedItem: "not editable" selectedItem: "Not editable"
addElement( "not editable" ) addElement( "Not editable" )
} }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 13,growx" "value": "cell 2 13,growx"

View File

@@ -27,6 +27,7 @@ import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel; import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.*; import com.formdev.flatlaf.*;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -37,7 +38,7 @@ import net.miginfocom.swing.*;
class ControlBar class ControlBar
extends JPanel extends JPanel
{ {
private JFrame frame; private DemoFrame frame;
private JTabbedPane tabbedPane; private JTabbedPane tabbedPane;
ControlBar() { ControlBar() {
@@ -58,9 +59,9 @@ class ControlBar
className.equals( "com.sun.java.swing.plaf.motif.MotifLookAndFeel" ) ) className.equals( "com.sun.java.swing.plaf.motif.MotifLookAndFeel" ) )
continue; continue;
if( (SystemInfo.IS_WINDOWS && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) || if( (SystemInfo.isWindows && className.equals( "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" )) ||
(SystemInfo.IS_MAC && className.equals( "com.apple.laf.AquaLookAndFeel") ) || (SystemInfo.isMacOS && className.equals( "com.apple.laf.AquaLookAndFeel") ) ||
(SystemInfo.IS_LINUX && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) ) (SystemInfo.isLinux && className.equals( "com.sun.java.swing.plaf.gtk.GTKLookAndFeel") ) )
name += " (F9)"; name += " (F9)";
else if( className.equals( MetalLookAndFeel.class.getName() ) ) else if( className.equals( MetalLookAndFeel.class.getName() ) )
name += " (F12)"; name += " (F12)";
@@ -78,6 +79,9 @@ class ControlBar
// update info label because user scale factor may change // update info label because user scale factor may change
updateInfoLabel(); updateInfoLabel();
// update "Font" menu
frame.updateFontMenuItems();
// this is necessary because embedded JOptionPane's "steal" the default button // this is necessary because embedded JOptionPane's "steal" the default button
frame.getRootPane().setDefaultButton( closeButton ); frame.getRootPane().setDefaultButton( closeButton );
} ); } );
@@ -90,7 +94,15 @@ class ControlBar
} ); } );
} }
void initialize( JFrame frame, JTabbedPane tabbedPane ) { @Override
public void updateUI() {
super.updateUI();
if( infoLabel != null )
updateInfoLabel();
}
void initialize( DemoFrame frame, JTabbedPane tabbedPane ) {
this.frame = frame; this.frame = frame;
this.tabbedPane = tabbedPane; this.tabbedPane = tabbedPane;
@@ -100,11 +112,11 @@ class ControlBar
registerSwitchToLookAndFeel( KeyEvent.VK_F3, FlatIntelliJLaf.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F3, FlatIntelliJLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F4, FlatDarculaLaf.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F4, FlatDarculaLaf.class.getName() );
if( SystemInfo.IS_WINDOWS ) if( SystemInfo.isWindows )
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" ); registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" );
else if( SystemInfo.IS_MAC ) else if( SystemInfo.isMacOS )
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" ); registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" );
else if( SystemInfo.IS_LINUX ) else if( SystemInfo.isLinux )
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" ); registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" );
registerSwitchToLookAndFeel( KeyEvent.VK_F12, MetalLookAndFeel.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F12, MetalLookAndFeel.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() ); registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() );
@@ -139,12 +151,20 @@ class ControlBar
} }
private void updateInfoLabel() { private void updateInfoLabel() {
String javaVendor = System.getProperty( "java.vendor" );
if( "Oracle Corporation".equals( javaVendor ) )
javaVendor = null;
double systemScaleFactor = UIScale.getSystemScaleFactor( getGraphicsConfiguration() ); double systemScaleFactor = UIScale.getSystemScaleFactor( getGraphicsConfiguration() );
float userScaleFactor = UIScale.getUserScaleFactor(); float userScaleFactor = UIScale.getUserScaleFactor();
Font font = UIManager.getFont( "Label.font" );
String newInfo = "(Java " + System.getProperty( "java.version" ) String newInfo = "(Java " + System.getProperty( "java.version" )
+ (javaVendor != null ? ("; " + javaVendor) : "")
+ (systemScaleFactor != 1 ? ("; system scale factor " + systemScaleFactor) : "") + (systemScaleFactor != 1 ? ("; system scale factor " + systemScaleFactor) : "")
+ (userScaleFactor != 1 ? ("; user scale factor " + userScaleFactor) : "") + (userScaleFactor != 1 ? ("; user scale factor " + userScaleFactor) : "")
+ (systemScaleFactor == 1 && userScaleFactor == 1 ? "; no scaling" : "") + (systemScaleFactor == 1 && userScaleFactor == 1 ? "; no scaling" : "")
+ "; " + font.getFamily() + " " + font.getSize()
+ (font.isBold() ? " BOLD" : "")
+ (font.isItalic() ? " ITALIC" : "")
+ ")"; + ")";
if( !newInfo.equals( infoLabel.getText() ) ) if( !newInfo.equals( infoLabel.getText() ) )
@@ -174,11 +194,18 @@ class ControlBar
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
try { try {
FlatAnimatedLafChange.showSnapshot();
// change look and feel // change look and feel
UIManager.setLookAndFeel( lafClassName ); UIManager.setLookAndFeel( lafClassName );
// clear custom default font when switching to non-FlatLaf LaF
if( !(UIManager.getLookAndFeel() instanceof FlatLaf) )
UIManager.put( "defaultFont", null );
// update all components // update all components
FlatLaf.updateUI(); FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
// increase size of frame if necessary // increase size of frame if necessary
int width = frame.getWidth(); int width = frame.getWidth();
@@ -208,6 +235,9 @@ class ControlBar
private void enabledChanged() { private void enabledChanged() {
enabledDisable( tabbedPane, enabledCheckBox.isSelected() ); enabledDisable( tabbedPane, enabledCheckBox.isSelected() );
// repainting whole tabbed pane is faster than repainting many individual components
tabbedPane.repaint();
} }
private void enabledDisable( Container container, boolean enabled ) { private void enabledDisable( Container container, boolean enabled ) {

View File

@@ -18,12 +18,19 @@ package com.formdev.flatlaf.demo;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.DefaultEditorKit; import javax.swing.text.DefaultEditorKit;
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.extras.*; import com.formdev.flatlaf.demo.extras.*;
import com.formdev.flatlaf.demo.intellijthemes.*; import com.formdev.flatlaf.demo.intellijthemes.*;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.extras.SVGUtils;
import com.formdev.flatlaf.ui.JBRCustomDecorations;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
/** /**
@@ -32,12 +39,22 @@ import net.miginfocom.swing.*;
class DemoFrame class DemoFrame
extends JFrame extends JFrame
{ {
private final String[] availableFontFamilyNames;
private int initialFontMenuItemCount = -1;
DemoFrame() { DemoFrame() {
int tabIndex = DemoPrefs.getState().getInt( FlatLafDemo.KEY_TAB, 0 ); int tabIndex = DemoPrefs.getState().getInt( FlatLafDemo.KEY_TAB, 0 );
availableFontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getAvailableFontFamilyNames().clone();
Arrays.sort( availableFontFamilyNames );
initComponents(); initComponents();
updateFontMenuItems();
controlBar.initialize( this, tabbedPane ); controlBar.initialize( this, tabbedPane );
setIconImages( SVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
if( tabIndex >= 0 && tabIndex < tabbedPane.getTabCount() && tabIndex != tabbedPane.getSelectedIndex() ) if( tabIndex >= 0 && tabIndex < tabbedPane.getTabCount() && tabIndex != tabbedPane.getSelectedIndex() )
tabbedPane.setSelectedIndex( tabIndex ); tabbedPane.setSelectedIndex( tabIndex );
} }
@@ -60,6 +77,26 @@ class DemoFrame
} ); } );
} }
private void windowDecorationsChanged() {
boolean windowDecorations = windowDecorationsCheckBoxMenuItem.isSelected();
dispose();
setUndecorated( windowDecorations );
getRootPane().setWindowDecorationStyle( windowDecorations ? JRootPane.FRAME : JRootPane.NONE );
menuBarEmbeddedCheckBoxMenuItem.setEnabled( windowDecorations );
setVisible( true );
}
private void menuBarEmbeddedChanged() {
getRootPane().putClientProperty( FlatClientProperties.MENU_BAR_EMBEDDED,
menuBarEmbeddedCheckBoxMenuItem.isSelected() ? null : false );
// alternative method for all frames and menu bars in an application
// UIManager.put( "TitlePane.menuBarEmbedded", menuBarEmbeddedCheckBoxMenuItem.isSelected() );
// revalidate();
// repaint();
}
private void underlineMenuSelection() { private void underlineMenuSelection() {
UIManager.put( "MenuItem.selectionType", underlineMenuSelectionMenuItem.isSelected() ? "underline" : null ); UIManager.put( "MenuItem.selectionType", underlineMenuSelectionMenuItem.isSelected() ? "underline" : null );
} }
@@ -69,14 +106,21 @@ class DemoFrame
repaint(); repaint();
} }
private void animatedLafChangeChanged() {
System.setProperty( "flatlaf.animatedLafChange", String.valueOf( animatedLafChangeMenuItem.isSelected() ) );
}
private void fontFamilyChanged( ActionEvent e ) { private void fontFamilyChanged( ActionEvent e ) {
String fontFamily = e.getActionCommand(); String fontFamily = e.getActionCommand();
FlatAnimatedLafChange.showSnapshot();
Font font = UIManager.getFont( "defaultFont" ); Font font = UIManager.getFont( "defaultFont" );
Font newFont = new Font( fontFamily, font.getStyle(), font.getSize() ); Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() );
UIManager.put( "defaultFont", newFont ); UIManager.put( "defaultFont", newFont );
FlatLaf.updateUI(); FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
} }
private void fontSizeChanged( ActionEvent e ) { private void fontSizeChanged( ActionEvent e ) {
@@ -91,6 +135,7 @@ class DemoFrame
private void restoreFont() { private void restoreFont() {
UIManager.put( "defaultFont", null ); UIManager.put( "defaultFont", null );
updateFontMenuItems();
FlatLaf.updateUI(); FlatLaf.updateUI();
} }
@@ -99,17 +144,80 @@ class DemoFrame
Font newFont = font.deriveFont( (float) (font.getSize() + 1) ); Font newFont = font.deriveFont( (float) (font.getSize() + 1) );
UIManager.put( "defaultFont", newFont ); UIManager.put( "defaultFont", newFont );
updateFontMenuItems();
FlatLaf.updateUI(); FlatLaf.updateUI();
} }
private void decrFont() { private void decrFont() {
Font font = UIManager.getFont( "defaultFont" ); Font font = UIManager.getFont( "defaultFont" );
Font newFont = font.deriveFont( (float) Math.max( font.getSize() - 1, 8 ) ); Font newFont = font.deriveFont( (float) Math.max( font.getSize() - 1, 10 ) );
UIManager.put( "defaultFont", newFont ); UIManager.put( "defaultFont", newFont );
updateFontMenuItems();
FlatLaf.updateUI(); FlatLaf.updateUI();
} }
void updateFontMenuItems() {
if( initialFontMenuItemCount < 0 )
initialFontMenuItemCount = fontMenu.getItemCount();
else {
// remove old font items
for( int i = fontMenu.getItemCount() - 1; i >= initialFontMenuItemCount; i-- )
fontMenu.remove( i );
}
// get current font
Font currentFont = UIManager.getFont( "Label.font" );
String currentFamily = currentFont.getFamily();
String currentSize = Integer.toString( currentFont.getSize() );
// add font families
fontMenu.addSeparator();
ArrayList<String> families = new ArrayList<>( Arrays.asList(
"Arial", "Cantarell", "Comic Sans MS", "Courier New", "DejaVu Sans",
"Dialog", "Liberation Sans", "Monospaced", "Noto Sans", "Roboto",
"SansSerif", "Segoe UI", "Serif", "Tahoma", "Ubuntu", "Verdana" ) );
if( !families.contains( currentFamily ) )
families.add( currentFamily );
families.sort( String.CASE_INSENSITIVE_ORDER );
ButtonGroup familiesGroup = new ButtonGroup();
for( String family : families ) {
if( Arrays.binarySearch( availableFontFamilyNames, family ) < 0 )
continue; // not available
JCheckBoxMenuItem item = new JCheckBoxMenuItem( family );
item.setSelected( family.equals( currentFamily ) );
item.addActionListener( this::fontFamilyChanged );
fontMenu.add( item );
familiesGroup.add( item );
}
// add font sizes
fontMenu.addSeparator();
ArrayList<String> sizes = new ArrayList<>( Arrays.asList(
"10", "12", "14", "16", "18", "20", "24", "28" ) );
if( !sizes.contains( currentSize ) )
sizes.add( currentSize );
sizes.sort( String.CASE_INSENSITIVE_ORDER );
ButtonGroup sizesGroup = new ButtonGroup();
for( String size : sizes ) {
JCheckBoxMenuItem item = new JCheckBoxMenuItem( size );
item.setSelected( size.equals( currentSize ) );
item.addActionListener( this::fontSizeChanged );
fontMenu.add( item );
sizesGroup.add( item );
}
// enabled/disable items
boolean enabled = UIManager.getLookAndFeel() instanceof FlatLaf;
for( Component item : fontMenu.getMenuComponents() )
item.setEnabled( enabled );
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JMenuBar menuBar1 = new JMenuBar(); JMenuBar menuBar1 = new JMenuBar();
@@ -144,8 +252,11 @@ class DemoFrame
JMenuItem incrFontMenuItem = new JMenuItem(); JMenuItem incrFontMenuItem = new JMenuItem();
JMenuItem decrFontMenuItem = new JMenuItem(); JMenuItem decrFontMenuItem = new JMenuItem();
JMenu optionsMenu = new JMenu(); JMenu optionsMenu = new JMenu();
windowDecorationsCheckBoxMenuItem = new JCheckBoxMenuItem();
menuBarEmbeddedCheckBoxMenuItem = new JCheckBoxMenuItem();
underlineMenuSelectionMenuItem = new JCheckBoxMenuItem(); underlineMenuSelectionMenuItem = new JCheckBoxMenuItem();
alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem(); alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem();
animatedLafChangeMenuItem = new JCheckBoxMenuItem();
JMenu helpMenu = new JMenu(); JMenu helpMenu = new JMenu();
JMenuItem aboutMenuItem = new JMenuItem(); JMenuItem aboutMenuItem = new JMenuItem();
JToolBar toolBar1 = new JToolBar(); JToolBar toolBar1 = new JToolBar();
@@ -356,19 +467,19 @@ class DemoFrame
//---- restoreFontMenuItem ---- //---- restoreFontMenuItem ----
restoreFontMenuItem.setText("Restore Font"); restoreFontMenuItem.setText("Restore Font");
restoreFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, KeyEvent.CTRL_MASK)); restoreFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
restoreFontMenuItem.addActionListener(e -> restoreFont()); restoreFontMenuItem.addActionListener(e -> restoreFont());
fontMenu.add(restoreFontMenuItem); fontMenu.add(restoreFontMenuItem);
//---- incrFontMenuItem ---- //---- incrFontMenuItem ----
incrFontMenuItem.setText("Increase Font Size"); incrFontMenuItem.setText("Increase Font Size");
incrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.CTRL_MASK)); incrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
incrFontMenuItem.addActionListener(e -> incrFont()); incrFontMenuItem.addActionListener(e -> incrFont());
fontMenu.add(incrFontMenuItem); fontMenu.add(incrFontMenuItem);
//---- decrFontMenuItem ---- //---- decrFontMenuItem ----
decrFontMenuItem.setText("Decrease Font Size"); decrFontMenuItem.setText("Decrease Font Size");
decrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyEvent.CTRL_MASK)); decrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
decrFontMenuItem.addActionListener(e -> decrFont()); decrFontMenuItem.addActionListener(e -> decrFont());
fontMenu.add(decrFontMenuItem); fontMenu.add(decrFontMenuItem);
} }
@@ -378,6 +489,18 @@ class DemoFrame
{ {
optionsMenu.setText("Options"); optionsMenu.setText("Options");
//---- windowDecorationsCheckBoxMenuItem ----
windowDecorationsCheckBoxMenuItem.setText("Window decorations");
windowDecorationsCheckBoxMenuItem.setSelected(true);
windowDecorationsCheckBoxMenuItem.addActionListener(e -> windowDecorationsChanged());
optionsMenu.add(windowDecorationsCheckBoxMenuItem);
//---- menuBarEmbeddedCheckBoxMenuItem ----
menuBarEmbeddedCheckBoxMenuItem.setText("Embedded menu bar");
menuBarEmbeddedCheckBoxMenuItem.setSelected(true);
menuBarEmbeddedCheckBoxMenuItem.addActionListener(e -> menuBarEmbeddedChanged());
optionsMenu.add(menuBarEmbeddedCheckBoxMenuItem);
//---- underlineMenuSelectionMenuItem ---- //---- underlineMenuSelectionMenuItem ----
underlineMenuSelectionMenuItem.setText("Use underline menu selection"); underlineMenuSelectionMenuItem.setText("Use underline menu selection");
underlineMenuSelectionMenuItem.addActionListener(e -> underlineMenuSelection()); underlineMenuSelectionMenuItem.addActionListener(e -> underlineMenuSelection());
@@ -387,6 +510,12 @@ class DemoFrame
alwaysShowMnemonicsMenuItem.setText("Always show mnemonics"); alwaysShowMnemonicsMenuItem.setText("Always show mnemonics");
alwaysShowMnemonicsMenuItem.addActionListener(e -> alwaysShowMnemonics()); alwaysShowMnemonicsMenuItem.addActionListener(e -> alwaysShowMnemonics());
optionsMenu.add(alwaysShowMnemonicsMenuItem); optionsMenu.add(alwaysShowMnemonicsMenuItem);
//---- animatedLafChangeMenuItem ----
animatedLafChangeMenuItem.setText("Animated Laf Change");
animatedLafChangeMenuItem.setSelected(true);
animatedLafChangeMenuItem.addActionListener(e -> animatedLafChangeChanged());
optionsMenu.add(animatedLafChangeMenuItem);
} }
menuBar1.add(optionsMenu); menuBar1.add(optionsMenu);
@@ -494,31 +623,19 @@ class DemoFrame
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() ); copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() ); pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
// add font families boolean supportsWindowDecorations = UIManager.getLookAndFeel()
fontMenu.addSeparator(); .getSupportsWindowDecorations() || JBRCustomDecorations.isSupported();
String[] fontFamilies = { "Arial", "Comic Sans MS", "Courier New", "Dialog", windowDecorationsCheckBoxMenuItem.setEnabled( supportsWindowDecorations && !JBRCustomDecorations.isSupported() );
"Monospaced", "SansSerif", "Serif", "Tahoma", "Verdana" }; menuBarEmbeddedCheckBoxMenuItem.setEnabled( supportsWindowDecorations );
for( String fontFamily : fontFamilies ) {
JMenuItem fontItem = new JMenuItem( fontFamily );
fontItem.addActionListener( this::fontFamilyChanged );
fontMenu.add( fontItem );
}
// add font sizes
fontMenu.addSeparator();
int[] fontSizes = { 8, 10, 12, 14, 16, 18, 20, 24, 28 };
for( int fontSize : fontSizes ) {
String fontSizeStr = Integer.toString( fontSize );
JMenuItem fontItem = new JMenuItem( fontSizeStr );
fontItem.addActionListener( this::fontSizeChanged );
fontMenu.add( fontItem );
}
} }
// 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 JCheckBoxMenuItem windowDecorationsCheckBoxMenuItem;
private JCheckBoxMenuItem menuBarEmbeddedCheckBoxMenuItem;
private JCheckBoxMenuItem underlineMenuSelectionMenuItem; private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem; private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem;
private JCheckBoxMenuItem animatedLafChangeMenuItem;
private JTabbedPane tabbedPane; private JTabbedPane tabbedPane;
private ControlBar controlBar; private ControlBar controlBar;
// 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.1.0.272" Java: "13.0.2" encoding: "UTF-8" JFDML JFormDesigner: "7.0.2.0.298" Java: "14.0.2" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -303,25 +303,43 @@ new FormModel {
add( new FormComponent( "javax.swing.JMenuItem" ) { add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "restoreFontMenuItem" name: "restoreFontMenuItem"
"text": "Restore Font" "text": "Restore Font"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 48, 130, false ) "accelerator": static javax.swing.KeyStroke getKeyStroke( 48, 4226, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "restoreFont", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "restoreFont", false ) )
} ) } )
add( new FormComponent( "javax.swing.JMenuItem" ) { add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "incrFontMenuItem" name: "incrFontMenuItem"
"text": "Increase Font Size" "text": "Increase Font Size"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 521, 130, false ) "accelerator": static javax.swing.KeyStroke getKeyStroke( 521, 4226, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "incrFont", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "incrFont", false ) )
} ) } )
add( new FormComponent( "javax.swing.JMenuItem" ) { add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "decrFontMenuItem" name: "decrFontMenuItem"
"text": "Decrease Font Size" "text": "Decrease Font Size"
"accelerator": static javax.swing.KeyStroke getKeyStroke( 45, 130, false ) "accelerator": static javax.swing.KeyStroke getKeyStroke( 45, 4226, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "decrFont", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "decrFont", false ) )
} ) } )
} ) } )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "optionsMenu" name: "optionsMenu"
"text": "Options" "text": "Options"
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "windowDecorationsCheckBoxMenuItem"
"text": "Window decorations"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "windowDecorationsChanged", false ) )
} )
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "menuBarEmbeddedCheckBoxMenuItem"
"text": "Embedded menu bar"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuBarEmbeddedChanged", false ) )
} )
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "underlineMenuSelectionMenuItem" name: "underlineMenuSelectionMenuItem"
"text": "Use underline menu selection" "text": "Use underline menu selection"
@@ -338,6 +356,15 @@ new FormModel {
} }
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "alwaysShowMnemonics", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "alwaysShowMnemonics", false ) )
} ) } )
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "animatedLafChangeMenuItem"
"text": "Animated Laf Change"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "animatedLafChangeChanged", false ) )
} )
} ) } )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "helpMenu" name: "helpMenu"

View File

@@ -82,7 +82,7 @@ public class DemoPrefs
} else } else
UIManager.setLookAndFeel( lafClassName ); UIManager.setLookAndFeel( lafClassName );
} }
} catch( Exception ex ) { } catch( Throwable ex ) {
ex.printStackTrace(); ex.printStackTrace();
// fallback // fallback

View File

@@ -16,7 +16,10 @@
package com.formdev.flatlaf.demo; package com.formdev.flatlaf.demo;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import com.formdev.flatlaf.extras.FlatInspector;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
@@ -28,15 +31,23 @@ public class FlatLafDemo
static final String KEY_TAB = "tab"; static final String KEY_TAB = "tab";
public static void main( String[] args ) { public static void main( String[] args ) {
if( SystemInfo.IS_MAC ) // on macOS enable screen menu bar
if( SystemInfo.isMacOS && System.getProperty( "apple.laf.useScreenMenuBar" ) == null )
System.setProperty( "apple.laf.useScreenMenuBar", "true" ); System.setProperty( "apple.laf.useScreenMenuBar", "true" );
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
DemoPrefs.init( PREFS_ROOT_PATH ); DemoPrefs.init( PREFS_ROOT_PATH );
// enable window decorations
JFrame.setDefaultLookAndFeelDecorated( true );
JDialog.setDefaultLookAndFeelDecorated( true );
// set look and feel // set look and feel
DemoPrefs.initLaf( args ); DemoPrefs.initLaf( args );
// install inspector
FlatInspector.install( "ctrl shift alt X" );
// create frame // create frame
DemoFrame frame = new DemoFrame(); DemoFrame frame = new DemoFrame();

View File

@@ -91,12 +91,13 @@ public class ExtrasPanel
add(label1, "cell 0 1"); add(label1, "cell 0 1");
//---- triStateCheckBox1 ---- //---- triStateCheckBox1 ----
triStateCheckBox1.setText("three states"); triStateCheckBox1.setText("Three States");
triStateCheckBox1.addActionListener(e -> triStateCheckBox1Changed()); triStateCheckBox1.addActionListener(e -> triStateCheckBox1Changed());
add(triStateCheckBox1, "cell 1 1"); add(triStateCheckBox1, "cell 1 1");
//---- triStateLabel1 ---- //---- triStateLabel1 ----
triStateLabel1.setText("text"); triStateLabel1.setText("text");
triStateLabel1.setEnabled(false);
add(triStateLabel1, "cell 2 1"); add(triStateLabel1, "cell 2 1");
//---- label2 ---- //---- label2 ----

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8" JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -23,7 +23,7 @@ new FormModel {
} ) } )
add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) { add( new FormComponent( "com.formdev.flatlaf.extras.TriStateCheckBox" ) {
name: "triStateCheckBox1" name: "triStateCheckBox1"
"text": "three states" "text": "Three States"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "triStateCheckBox1Changed", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "triStateCheckBox1Changed", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1" "value": "cell 1 1"
@@ -31,6 +31,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "triStateLabel1" name: "triStateLabel1"
"text": "text" "text": "text"
"enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1" "value": "cell 2 1"
} ) } )

View File

@@ -25,6 +25,7 @@ class IJThemeInfo
{ {
final String name; final String name;
final String resourceName; final String resourceName;
final boolean dark;
final String license; final String license;
final String licenseFile; final String licenseFile;
final String sourceCodeUrl; final String sourceCodeUrl;
@@ -32,13 +33,14 @@ class IJThemeInfo
final File themeFile; final File themeFile;
final String lafClassName; final String lafClassName;
IJThemeInfo( String name, String resourceName, IJThemeInfo( String name, String resourceName, boolean dark,
String license, String licenseFile, String license, String licenseFile,
String sourceCodeUrl, String sourceCodePath, String sourceCodeUrl, String sourceCodePath,
File themeFile, String lafClassName ) File themeFile, String lafClassName )
{ {
this.name = name; this.name = name;
this.resourceName = resourceName; this.resourceName = resourceName;
this.dark = dark;
this.license = license; this.license = license;
this.licenseFile = licenseFile; this.licenseFile = licenseFile;
this.sourceCodeUrl = sourceCodeUrl; this.sourceCodeUrl = sourceCodeUrl;

View File

@@ -55,12 +55,13 @@ class IJThemesManager
String resourceName = e.getKey(); String resourceName = e.getKey();
Map<String, String> value = (Map<String, String>) e.getValue(); Map<String, String> value = (Map<String, String>) e.getValue();
String name = value.get( "name" ); String name = value.get( "name" );
boolean dark = Boolean.parseBoolean( value.get( "dark" ) );
String license = value.get( "license" ); String license = value.get( "license" );
String licenseFile = value.get( "licenseFile" ); String licenseFile = value.get( "licenseFile" );
String sourceCodeUrl = value.get( "sourceCodeUrl" ); String sourceCodeUrl = value.get( "sourceCodeUrl" );
String sourceCodePath = value.get( "sourceCodePath" ); String sourceCodePath = value.get( "sourceCodePath" );
bundledThemes.add( new IJThemeInfo( name, resourceName, license, licenseFile, sourceCodeUrl, sourceCodePath, null, null ) ); bundledThemes.add( new IJThemeInfo( name, resourceName, dark, license, licenseFile, sourceCodeUrl, sourceCodePath, null, null ) );
} }
} }
@@ -83,7 +84,7 @@ class IJThemesManager
String name = fname.endsWith( ".properties" ) String name = fname.endsWith( ".properties" )
? StringUtils.removeTrailing( fname, ".properties" ) ? StringUtils.removeTrailing( fname, ".properties" )
: StringUtils.removeTrailing( fname, ".theme.json" ); : StringUtils.removeTrailing( fname, ".theme.json" );
moreThemes.add( new IJThemeInfo( name, null, null, null, null, null, f, null ) ); moreThemes.add( new IJThemeInfo( name, null, false, null, null, null, null, f, null ) );
lastModifiedMap.put( f, f.lastModified() ); lastModifiedMap.put( f, f.lastModified() );
} }
} }

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.demo.intellijthemes;
import java.awt.Component; import java.awt.Component;
import java.awt.Desktop; import java.awt.Desktop;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
@@ -49,6 +50,7 @@ import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatPropertiesLaf; import com.formdev.flatlaf.FlatPropertiesLaf;
import com.formdev.flatlaf.IntelliJTheme; import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.demo.DemoPrefs; import com.formdev.flatlaf.demo.DemoPrefs;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -119,6 +121,10 @@ public class IJThemesPanel
} }
private void updateThemesList() { private void updateThemesList() {
int filterLightDark = filterComboBox.getSelectedIndex();
boolean showLight = (filterLightDark != 2);
boolean showDark = (filterLightDark != 1);
// load theme infos // load theme infos
themesManager.loadBundledThemes(); themesManager.loadBundledThemes();
themesManager.loadThemesFromDirectory(); themesManager.loadThemesFromDirectory();
@@ -128,15 +134,22 @@ public class IJThemesPanel
themesManager.bundledThemes.sort( comparator ); themesManager.bundledThemes.sort( comparator );
themesManager.moreThemes.sort( comparator ); themesManager.moreThemes.sort( comparator );
// remember selection (must be invoked before clearing themes field)
IJThemeInfo oldSel = themesList.getSelectedValue();
themes.clear(); themes.clear();
categories.clear(); categories.clear();
// add core themes at beginning // add core themes at beginning
categories.put( themes.size(), "Core Themes" ); categories.put( themes.size(), "Core Themes" );
themes.add( new IJThemeInfo( "Flat Light", null, null, null, null, null, null, FlatLightLaf.class.getName() ) ); if( showLight )
themes.add( new IJThemeInfo( "Flat Dark", null, null, null, null, null, null, FlatDarkLaf.class.getName() ) ); themes.add( new IJThemeInfo( "Flat Light", null, false, null, null, null, null, null, FlatLightLaf.class.getName() ) );
themes.add( new IJThemeInfo( "Flat IntelliJ", null, null, null, null, null, null, FlatIntelliJLaf.class.getName() ) ); if( showDark )
themes.add( new IJThemeInfo( "Flat Darcula", null, null, null, null, null, null, FlatDarculaLaf.class.getName() ) ); themes.add( new IJThemeInfo( "Flat Dark", null, true, null, null, null, null, null, FlatDarkLaf.class.getName() ) );
if( showLight )
themes.add( new IJThemeInfo( "Flat IntelliJ", null, false, null, null, null, null, null, FlatIntelliJLaf.class.getName() ) );
if( showDark )
themes.add( new IJThemeInfo( "Flat Darcula", null, true, null, null, null, null, null, FlatDarculaLaf.class.getName() ) );
// add themes from directory // add themes from directory
categories.put( themes.size(), "Current Directory" ); categories.put( themes.size(), "Current Directory" );
@@ -145,15 +158,17 @@ public class IJThemesPanel
// add uncategorized bundled themes // add uncategorized bundled themes
categories.put( themes.size(), "IntelliJ Themes" ); categories.put( themes.size(), "IntelliJ Themes" );
for( IJThemeInfo ti : themesManager.bundledThemes ) { for( IJThemeInfo ti : themesManager.bundledThemes ) {
if( !ti.name.contains( "/" ) ) boolean show = (showLight && !ti.dark) || (showDark && ti.dark);
if( show && !ti.name.contains( "/" ) )
themes.add( ti ); themes.add( ti );
} }
// add categorized bundled themes // add categorized bundled themes
String lastCategory = null; String lastCategory = null;
for( IJThemeInfo ti : themesManager.bundledThemes ) { for( IJThemeInfo ti : themesManager.bundledThemes ) {
boolean show = (showLight && !ti.dark) || (showDark && ti.dark);
int sep = ti.name.indexOf( '/' ); int sep = ti.name.indexOf( '/' );
if( sep < 0 ) if( !show || sep < 0 )
continue; continue;
String category = ti.name.substring( 0, sep ).trim(); String category = ti.name.substring( 0, sep ).trim();
@@ -165,9 +180,6 @@ public class IJThemesPanel
themes.add( ti ); themes.add( ti );
} }
// remember selection
IJThemeInfo oldSel = themesList.getSelectedValue();
// fill themes list // fill themes list
themesList.setModel( new AbstractListModel<IJThemeInfo>() { themesList.setModel( new AbstractListModel<IJThemeInfo>() {
@Override @Override
@@ -194,6 +206,18 @@ public class IJThemesPanel
} }
} }
} }
// select first theme if none selected
if( themesList.getSelectedIndex() < 0 )
themesList.setSelectedIndex( 0 );
// scroll selection into visible area
int sel = themesList.getSelectedIndex();
if( sel >= 0 ) {
Rectangle bounds = themesList.getCellBounds( sel, sel );
if( bounds != null )
themesList.scrollRectToVisible( bounds );
}
} }
private void themesListValueChanged( ListSelectionEvent e ) { private void themesListValueChanged( ListSelectionEvent e ) {
@@ -219,6 +243,8 @@ public class IJThemesPanel
if( themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) ) if( themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) )
return; return;
FlatAnimatedLafChange.showSnapshot();
try { try {
UIManager.setLookAndFeel( themeInfo.lafClassName ); UIManager.setLookAndFeel( themeInfo.lafClassName );
} catch( Exception ex ) { } catch( Exception ex ) {
@@ -226,6 +252,8 @@ public class IJThemesPanel
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex ); showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
} }
} else if( themeInfo.themeFile != null ) { } else if( themeInfo.themeFile != null ) {
FlatAnimatedLafChange.showSnapshot();
try { try {
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) { if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) {
FlatLaf.install( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) ); FlatLaf.install( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) );
@@ -238,12 +266,15 @@ public class IJThemesPanel
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex ); showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
} }
} else { } else {
FlatAnimatedLafChange.showSnapshot();
IntelliJTheme.install( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) ); IntelliJTheme.install( 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 );
} }
// update all components // update all components
FlatLaf.updateUI(); FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
} }
private void saveTheme() { private void saveTheme() {
@@ -373,12 +404,17 @@ public class IJThemesPanel
isAdjustingThemesList = false; isAdjustingThemesList = false;
} }
private void filterChanged() {
updateThemesList();
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel themesLabel = new JLabel(); JLabel themesLabel = new JLabel();
toolBar = new JToolBar(); toolBar = new JToolBar();
saveButton = new JButton(); saveButton = new JButton();
sourceCodeButton = new JButton(); sourceCodeButton = new JButton();
filterComboBox = new JComboBox<>();
themesScrollPane = new JScrollPane(); themesScrollPane = new JScrollPane();
themesList = new JList<>(); themesList = new JList<>();
@@ -411,6 +447,17 @@ public class IJThemesPanel
} }
add(toolBar, "cell 0 0,alignx right,growx 0"); add(toolBar, "cell 0 0,alignx right,growx 0");
//---- filterComboBox ----
filterComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
"all",
"light",
"dark"
}));
filterComboBox.putClientProperty("JComponent.minimumWidth", 0);
filterComboBox.setFocusable(false);
filterComboBox.addActionListener(e -> filterChanged());
add(filterComboBox, "cell 0 0,alignx right,growx 0");
//======== themesScrollPane ======== //======== themesScrollPane ========
{ {
@@ -427,6 +474,7 @@ public class IJThemesPanel
private JToolBar toolBar; private JToolBar toolBar;
private JButton saveButton; private JButton saveButton;
private JButton sourceCodeButton; private JButton sourceCodeButton;
private JComboBox<String> filterComboBox;
private JScrollPane themesScrollPane; private JScrollPane themesScrollPane;
private JList<IJThemeInfo> themesList; private JList<IJThemeInfo> themesList;
// 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.0.0.194" Java: "11.0.2" encoding: "UTF-8" JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -34,6 +34,20 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0,alignx right,growx 0" "value": "cell 0 0,alignx right,growx 0"
} ) } )
add( new FormComponent( "javax.swing.JComboBox" ) {
name: "filterComboBox"
"model": new javax.swing.DefaultComboBoxModel {
selectedItem: "all"
addElement( "all" )
addElement( "light" )
addElement( "dark" )
}
"$client.JComponent.minimumWidth": 0
"focusable": false
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0,alignx right,growx 0"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "themesScrollPane" name: "themesScrollPane"
add( new FormComponent( "javax.swing.JList" ) { add( new FormComponent( "javax.swing.JList" ) {

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<defs>
<linearGradient id="flatlaf-a" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#DD6900"/>
<stop offset="100%" stop-color="#D45500"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="url(#flatlaf-a)"/>
<polygon fill="#FFF" points="9 13 13 13 12.5 11.5 10.5 11.5 10.5 6.5 9 6"/>
<polygon fill="#FFF" points="4 12.5 4 3 9 3 8.5 4.5 5.5 4.5 5.5 7 7.5 7 7 8.5 5.5 8.5 5.5 12"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 583 B

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