Compare commits

..

155 Commits
1.3 ... 1.6.5

Author SHA1 Message Date
Karl Tauber
d8df8c9631 release 1.6.5 2021-12-07 15:05:13 +01:00
Karl Tauber
f61a7288eb fixed updating (embedded) menu bar layout when window is narrow and changing TitlePane.menuBarEmbedded 2021-12-07 11:52:33 +01:00
Karl Tauber
47a1122f04 Window decorations: do not exit application with UnsatisfiedLinkError in case that FlatLaf DLL cannot be executed because of restrictions on temporary directory (issue #436) 2021-12-07 00:39:28 +01:00
Karl Tauber
e1bfabbce5 macOS: fixed NullPointerException when using AWT component java.awt.Choice (issue #439) 2021-12-06 22:45:24 +01:00
Karl Tauber
9708fec0e0 GitHub Actions: produce snapshots only on develop-* branches; change version to 1.6.5-SNAPSHOT 2021-12-06 17:27:49 +01:00
Karl Tauber
7f4efaf0a3 ComboBox: fixed occasional StackOverflowError when modifying combo box not on AWT thread (issue #432) 2021-12-06 17:15:37 +01:00
Karl Tauber
269eb0ba29 MenuItem: changed accelerator delimiter from - to + (Windows and Linux) 2021-12-04 12:15:53 +01:00
Karl Tauber
7dac3825d7 Linux: Fixed font problems when running on Oracle Java 8 (OpenJDK 8 is not affected):
- oversized text if system font is "Inter" (issue #427)
- missing text if system font is "Cantarell" (on Fedora)
2021-11-24 10:47:58 +01:00
Karl Tauber
6c0b122fbc release 1.6.4 2021-11-16 15:37:19 +01:00
Karl Tauber
4da2bd90cb ComboBox: fixed regression in FlatLaf 1.6.3 that makes selected item invisible in popup list if DefaultListCellRenderer is used as renderer (issue #426) 2021-11-16 15:36:14 +01:00
Karl Tauber
cb70fb4e82 GitHub Actions: run Gradle wrapper validation only once
(to reduce risk of connection timeout)
2021-11-14 23:06:23 +01:00
Karl Tauber
2593a43d72 release 1.6.3 2021-11-14 22:42:10 +01:00
Karl Tauber
e44ff5b72a Tree: Fixed editing cell issue with custom cell renderer and cell editor that use same component for rendering and editing (fixes #385)
(cherry picked from commit 161ee090a8)
2021-11-14 22:34:28 +01:00
Karl Tauber
22cb1b50a6 ComboBox (not editable): fixed regression that may display text in non-editable combo boxes in bold (issue #423)
fixes commits 02f3239669
and 0b6df8be1c
2021-11-14 22:11:19 +01:00
Karl Tauber
95a15c3cf8 release 1.6.2 2021-11-11 12:45:50 +01:00
Karl Tauber
ab320684f5 Native window decorations: fixed layout loop (issue #420)
(cherry picked from commit d3355eda65)
2021-11-11 12:35:51 +01:00
Karl Tauber
a284b69a1e FileChooser: workaround for crash on Windows with Java 17 32bit (issue #403)
(cherry picked from commits 44d8545c09 and 33b25c1129)
2021-11-11 12:35:16 +01:00
Karl Tauber
b590f41254 Linux: fixed NPE when using java.awt.TrayIcon (issue #405)
(cherry picked from commit 16a769ea61)
2021-11-11 12:31:14 +01:00
Karl Tauber
a97076ead5 ComboBox: fix NPE in CellPaddingBorder.install() (issue #408)
(cherry picked from commit d48b98f582)
2021-11-11 12:30:10 +01:00
Karl Tauber
0b6df8be1c ComboBox (not editable): fixed background painted outside of border if round edges are enabled (similar to issue #382; regression since fixing #330 in FlatLaf 1.4)
(cherry picked from commit 02f3239669)
2021-11-11 12:26:09 +01:00
Karl Tauber
150bab0b57 Table: do not select text in cell editor when it gets focus (when JTable.surrendersFocusOnKeystroke is true) and TextComponent.selectAllOnFocusPolicy is once (the default) or always (issue #395)
(cherry picked from commit f8b9f4c1fa)
2021-11-11 12:19:58 +01:00
Karl Tauber
a253b6c0cf release 1.6.1 2021-10-14 22:35:33 +02:00
Karl Tauber
efcbc1fbdb Native window decorations: catch UnsatisfiedLinkError when trying to load jawt.dll to avoid an application crash (Java 8 on Windows 10 only) 2021-10-14 18:59:26 +02:00
Karl Tauber
ae28c595f9 release 1.6 2021-09-14 15:00:29 +02:00
Karl Tauber
1d08ddda60 InternalFrame: added missing since 1.6 2021-09-14 14:56:21 +02:00
Karl Tauber
578379fd00 Table and TableHeader: renamed UI keys Table[Header].showLastVerticalLine to Table[Header].showTrailingVerticalLine (issue #332) 2021-09-14 14:31:17 +02:00
Karl Tauber
7c9f550d4c ComboBox: fixed popup location if shown above of combo box (Java 8 only) 2021-09-14 14:16:53 +02:00
Karl Tauber
84d4510d70 ComboBox: fixed popup border painting on HiDPI screens (e.g. at 150% scaling) 2021-09-14 12:46:51 +02:00
Karl Tauber
fa194ec258 TableHeader: fixed missing trailing vertical separator line if used in upper left corner of scroll pane (issue #332) 2021-09-14 00:52:59 +02:00
Karl Tauber
fd56de403d Slider: fixed calculation of baseline (see also PR #214) 2021-09-13 22:05:48 +02:00
Karl Tauber
85fde46504 Testing: FlatSingleComponentTest: revalidate and repaint when changing component orientation using Alt+R 2021-09-13 10:11:09 +02:00
Karl Tauber
b283178979 Spinner: fixed painting of border corners on left side (issue #382; regression since FlatLaf 1.4)
ComboBox (editable): fixed wrong border of internal text field under special circumstances
2021-09-10 16:37:07 +02:00
Karl Tauber
bddef38a7c Theme Editor: preview: added "editable" check box for text components 2021-09-08 00:22:02 +02:00
Karl Tauber
b5f2f77944 Theme Editor: layout of "All" preview tab improvements:
- right align "enabled" and "focused" check boxes
- two columns for controls
- removed help button
- JTextArea, JEditorPane and JTextPane in single line
- reduced some vertical gaps
2021-09-08 00:10:53 +02:00
Karl Tauber
fca0718ed0 Native window decorations: fixed unwanted uninstall of native window border when using JInternalFrame (which has its own JRootPane) and invoking updateUI() on internal frame (e.g. in preview of FlatLaf Theme Editor) 2021-09-07 17:55:45 +02:00
Karl Tauber
0d44ade6ea Theme Editor: preview improvements:
- remember state of "enabled", "focused" and "buttonType" and sync it with all editors
- added "_" button near "JMenuBar" label to test menu underline selection
2021-09-07 14:31:09 +02:00
Karl Tauber
6018f83a22 Theme Editor: center some labels and help buttons in preview 2021-09-05 22:15:49 +02:00
Karl Tauber
0b6247851b Theme Editor: fixed preview of focused list and table selection 2021-09-05 22:05:21 +02:00
Karl Tauber
8640dee053 Theme Editor: preview improvements:
- added "focused" checkbox to "All" tab to preview focused components
- added "button type" selector to "Buttons" tab
- added "unfocused"/"focused" header labels to "Buttons" and "Switches" tabs
- use local variables instead of fields where possible
2021-09-05 21:08:36 +02:00
Karl Tauber
824db2e3bd Table and TableHeader: added UI defaults to show last vertical line (issue #332) 2021-09-05 11:51:28 +02:00
Karl Tauber
c2c79c4676 Theme Editor:
- remember last used preview tab
- sync selected preview tab with all editors
2021-09-05 11:13:29 +02:00
Karl Tauber
4795fe5687 Theme Editor:
- added preview of buttons, checkboxes, radiobuttons, etc in various states (hover, pressed, focused, selected, disabled)
  (copied from `FlatComponentStateTest`)
- moved components preview panel from FlatThemePreview.jfd` to FlatThemePreviewAll.jfd`
- added tabs at top of preview area
2021-09-05 10:55:51 +02:00
Karl Tauber
d508f339c1 TableHeader: do not show resize cursor for last column if resizing last column is not possible because auto resize mode of table is not off (issue #332) 2021-09-04 18:20:21 +02:00
Karl Tauber
c7054537e7 Testing: FlatSingleComponentTest: support changing component orientation using Alt+R 2021-09-04 13:28:02 +02:00
Karl Tauber
b98b904023 added missing UI defaults to javadoc 2021-09-04 13:24:19 +02:00
Karl Tauber
253df9325d Extras: FlatAnimatedLafChange: made animated Laf change transition smoother 2021-09-04 13:19:12 +02:00
Karl Tauber
78a9cc1d0c Theme Editor: fixed: editor was not focused after startup or when switching directory 2021-09-03 17:32:59 +02:00
Karl Tauber
b25fcc3381 OptionPane: fixed rendering of longer HTML text if it is passed as StringBuilder, StringBuffer, or any other object that returns HTML text in method toString() (similar to issue #12) 2021-09-03 11:26:30 +02:00
Karl Tauber
51d7bc2c37 TextField, FormattedTextField, PasswordField and ComboBox: fixed alignment of placeholder text in right-to-left component orientation 2021-09-02 16:18:53 +02:00
Karl Tauber
09a18b2305 Theme Editor:
- highlight opened directory in history combobox list
- support removing directories from history ('x' button in combobox list)
2021-08-29 18:39:40 +02:00
Karl Tauber
31f2feee2e Theme Editor:
- special renderer for directory history combobox list that dimes path parts
- disable menu items and buttons if no directory or editor is open
- set editor font size when opening new editor if increased/decreased
2021-08-29 16:06:50 +02:00
Karl Tauber
218bb62bfd Theme Editor:
- fixed increasing layout and wrong top border color of find/replace bar when switching Laf
- fixed duplicate keys in reference auto-completion
2021-08-29 14:28:11 +02:00
Karl Tauber
694c2ad767 Theme Editor: preview improvements:
- added JSplitPane (contains JList and JTree)
- sort first column in JTable to have preview of sort direction arrow
- fixed background color of JEditorPane and JTextPane when enabling/disabling
- keep first JMenu enabled, but disable the menu items
2021-08-29 11:44:38 +02:00
Karl Tauber
97943fcd38 Theme Editor: changed main class to com.formdev.flatlaf.themeeditor.FlatThemeEditor 2021-08-28 17:38:51 +02:00
Karl Tauber
77f33467d2 Theme Editor: fixed endless look in "replace all" when replacing e.g. "a" with "aa" 2021-08-28 17:37:02 +02:00
Karl Tauber
651454170d Theme Editor:
- fixed duplicate lines action if selection includes line separator at the end
- preview: do not disable internal components of JInternalFrame
2021-08-28 14:30:11 +02:00
Karl Tauber
7ca48bd136 Theme Editor:
- support lazy values and icon colors in overlay color preview
- support icon colors in preview
- support icon colors in reference auto-completion
- support changing preview theme when editing FlatLaf.properties via adding `@baseTheme = dark|darcula|intellij`
2021-08-28 14:18:11 +02:00
Karl Tauber
968e508bb5 Theme Editor:
- change border color of find field to red if noting found/matches
- update search match highlighting after reloading file on external change
2021-08-27 22:53:04 +02:00
Karl Tauber
a6d318a197 Theme Editor: fixed missing keys (e.g. Button.foreground) in reference auto-completion, which are defined as wildcards or have some prefix 2021-08-27 22:32:59 +02:00
Karl Tauber
cd20f4086b Theme Editor: fixed preview of focused button in FlatDarkLaf (and probably other null value related issues) 2021-08-27 18:32:42 +02:00
Karl Tauber
ebd5905947 Theme Editor: preview improvements:
- added JToolBar, JProgressBar with string painted, JDesktopPane and JInternalFrame
- placed text components side-by-side to save vertical space
- changed button texts and removed tooltips
- fixed painting of table cell focus border
- added missing add.svg
2021-08-27 16:10:10 +02:00
Karl Tauber
817a3c62bb Theme Editor: preview improvements:
- fixed table header borders (runWithUIDefaultsGetter() in paint())
- cache lazy values
- use runWithUIDefaultsGetter() in layout(), validateTree() and paint()
2021-08-24 22:32:48 +02:00
Karl Tauber
f8f58400fe Theme Editor: added list, tree and table to preview 2021-08-24 21:49:09 +02:00
Karl Tauber
ef06840649 Theme Editor: basic README.md with shapshot download link 2021-08-24 18:38:21 +02:00
Karl Tauber
b17c14d62e Theme Editor: use UTF-8 encoding to load properties files 2021-08-24 17:50:03 +02:00
Karl Tauber
19dba94064 IntelliJ Themes: removed deprecated install() methods
but keep them in the flatlaf-core for API compatibility in NetBeans plugin
2021-08-24 17:38:19 +02:00
Karl Tauber
601e24f9e7 Theme Editor: fixed "..." in menus 2021-08-24 16:52:45 +02:00
Karl Tauber
c7f323ee13 Theme Editor: added window icon 2021-08-24 16:49:55 +02:00
Karl Tauber
e4522f3af4 Theme Editor: added "About" dialog
Demo: updated "About" dialog
2021-08-24 16:40:17 +02:00
Karl Tauber
79af461a5b Theme Editor: instead of creating empty FlatLightLaf.properties and FlatDarkLaf.properties, add some how-to-use description to those files 2021-08-24 15:38:15 +02:00
Karl Tauber
2e8e07faf6 Theme Editor: auto-completion for keys improved:
- now also contains variables and keys defined in current and base themes
- appended " = "
- removes some unsupported keys (fonts and input maps)
2021-08-24 15:13:30 +02:00
Karl Tauber
ecdb000818 Theme Editor: avoid changing editor text (and adding item to undo history) when simply pressing OK button in "Insert Color" dialog without changing anything 2021-08-23 23:56:27 +02:00
Karl Tauber
999fd0d4da Theme Editor: generate .java file when creating new theme 2021-08-23 23:52:22 +02:00
Karl Tauber
705dd9558f Theme Editor:
- added "New Properties File" action to "File" menu
- added "+" button to tabbed pane
- ask to create .properties files when opening a directory that does not contain .properties files
- fixed Darcula baseTheme/preview
2021-08-23 23:02:41 +02:00
Karl Tauber
97ca866ffa OptionPane: fixed OptionPane.sameSizeButtons, which did not work as expected when setting to false 2021-08-23 16:53:23 +02:00
Karl Tauber
543b977db7 updated SVG icons from IntelliJ IDEA Community Edition to latest versions that include license header; added license header to SVGs where it were missing 2021-08-23 15:57:26 +02:00
Karl Tauber
ebb8a6d025 Theme Editor: ignore custom UI delegates in preview 2021-08-23 15:00:28 +02:00
Karl Tauber
506543281e Theme Editor: "Insert Color" dialog now immediately updates editor with new color, which updates "live" preview; also save/restore location of dialog 2021-08-23 14:41:53 +02:00
Karl Tauber
60322be22a Theme Editor: added "Insert Color" action to "Edit" menu that opens a color chooser dialog and inserts/edits a color at caret position 2021-08-23 14:06:18 +02:00
Karl Tauber
e1f30f24a8 Theme Editor: to toggle comment, add Ctrl+7 for German keyboards where Ctrl+/ does not work 2021-08-22 17:34:18 +02:00
Karl Tauber
1759f6b25c Theme Editor: increment/decrement color parts (red, green, blue or alpha) at caret using Ctrl+UP/Ctrl+DOWN 2021-08-22 17:26:29 +02:00
Karl Tauber
6578f25cc9 GitHub Actions: upload theme editor 2021-08-22 16:10:29 +02:00
Karl Tauber
8c26e0323f Theme Editor: increment/decrement numbers at caret using Ctrl+UP/Ctrl+DOWN 2021-08-22 15:33:29 +02:00
Karl Tauber
a5575894ab Theme Editor:
- update preview after 300ms (was 500ms)
- added separator between editor and preview
2021-08-22 14:26:18 +02:00
Karl Tauber
357823a027 Theme Editor: added "Show HSL/RGB colors" menu items to "View" menu to control display of color models in overlay color preview 2021-08-22 12:34:48 +02:00
Karl Tauber
a6d3f6b3eb Theme Editor: added menu components to preview 2021-08-22 11:19:47 +02:00
Karl Tauber
ae4c69e75c Theme Editor: fixed preview when switching Laf 2021-08-22 11:13:05 +02:00
Karl Tauber
31cadc532b Theme Editor:
- F12 now activates editor if focus is in preview or in find/replace
- changed accelerators for light/dark themes from F11/F12 to Alt+F1/F2
2021-08-22 00:33:34 +02:00
Karl Tauber
6e8443473b Theme Editor: special order for tabs: first core themes, then other themes 2021-08-21 23:27:43 +02:00
Karl Tauber
cca4ab3cd8 Theme Editor: fixed tabbed pane "more tabs" popup in preview 2021-08-21 18:24:57 +02:00
Karl Tauber
dab0ee3306 Theme Editor: added "live" preview 2021-08-21 18:09:59 +02:00
Karl Tauber
c6d1ed91a7 Menus: fixed missing modifiers flags in ActionEvent (issue #371; regression since FlatLaf 1.3) 2021-08-13 20:32:07 +02:00
Karl Tauber
a613a244f4 InternalFrame: double-click on icon in internal frame title bar now closes the internal frame (issue #374) 2021-08-13 19:11:03 +02:00
Karl Tauber
268fe15004 Tree: improved support for JTree.getPathForLocation(int x, int y) in wide selection (issue #373)
this is experimental and disabled by default; enable with:
`UIManager.put( "FlatLaf.experimental.tree.widePathForLocation", true );`
2021-08-13 00:19:34 +02:00
Karl Tauber
7bc9be686f FlatLaf: use larger initial capacity for UI defaults table to avoid resizing hash table and to save some memory 2021-08-13 00:13:54 +02:00
Karl Tauber
751919ec5a Theme Editor: find/replace improvements:
- while typing in find field, select match near caret and scroll to it
- PageUp/PageDown keys scroll editor if find/replace fields have focus
2021-08-12 22:05:08 +02:00
Karl Tauber
da913b426e Theme Editor: paint current line highlight always in the line where the caret is, which makes it easier to locate current match when using find/replace
RSyntaxTextArea paints line highlight only if selection is empty (caret dot == mark)
2021-08-11 23:59:33 +02:00
Karl Tauber
d8ef99cd8f Theme Editor: support resolving properties that use wildcards 2021-08-11 23:24:55 +02:00
Karl Tauber
d08a6d7dd3 Theme Editor: support loading/resolving base properties from core themes 2021-08-11 22:38:35 +02:00
Karl Tauber
896e9bca8e Theme Editor: re-implemented support loading/resolving base properties from other editors in opened directory 2021-08-11 21:53:10 +02:00
Karl Tauber
1df9597bb1 Theme Editor: support Ctrl+PageDown/PageUp to switch to next/previous editor 2021-08-09 10:19:24 +02:00
Karl Tauber
eaf55f2099 Theme Editor: store unscaled window bounds in preferences so that using Java 8 or 9+ results in same size on screen 2021-08-08 19:15:10 +02:00
Karl Tauber
5018a1f9eb Theme Editor: increase/decrease editor font size 2021-08-08 19:14:46 +02:00
Karl Tauber
71ba8f55a7 Theme Editor:
- support dark theme (menu "View > Dark Laf")
- moved RSyntaxTextArea theme config from XML to properties files
- bracket matching enabled
- highlight selected tab background
2021-08-08 17:43:59 +02:00
Karl Tauber
b65db707ed Theme Editor: auto-completion improved: support auto-activate after spaces, tabs or ',' 2021-08-07 14:59:20 +02:00
Karl Tauber
ed62266a43 Theme Editor: always select all text in find/replace text fields 2021-08-07 12:55:25 +02:00
Karl Tauber
49913b7dad Theme Editor: duplicate lines with Ctrl+Alt+Up or Ctrl+Alt+Down 2021-08-07 12:51:00 +02:00
Karl Tauber
3eeeb9e00b Theme Editor: update RSyntaxTextArea from 3.1.2 to 3.1.3 2021-08-07 11:18:00 +02:00
Karl Tauber
bfb1642284 UIDefaultsDump: dump HSL color values 2021-08-06 10:45:57 +02:00
Karl Tauber
0544a605c3 UIDefaultsLoader: added tint() and shade() color functions (inspired by Less CSS) 2021-08-05 23:37:42 +02:00
Karl Tauber
3f5acda132 UI defaults inspector: round HSL values (as also done in theme editor) 2021-08-05 18:49:03 +02:00
Karl Tauber
02b1ba2926 UIDefaultsLoader: added mix() color function (inspired by Less CSS) 2021-08-05 18:19:42 +02:00
Karl Tauber
7f7f9e3c7c UIDefaultsLoader: added changeHue(), changeSaturation(), changeLightness() and changeAlpha() color functions (inspired by Sass CSS color.change() function) 2021-08-05 17:08:20 +02:00
Karl Tauber
6fcee03752 release 1.5 2021-08-04 15:13:58 +02:00
Karl Tauber
5782ceeb5d README.md: added descriptions to addons 2021-08-04 14:27:57 +02:00
Karl Tauber
f752db5892 FileChooser: fixed missing (localized) texts when FlatLaf is loaded in special classloader
(e.g. plugin system in Apache NetBeans)

https://issues.apache.org/jira/browse/NETBEANS-5865
2021-08-04 11:15:18 +02:00
Karl Tauber
bce58bc97b SwingX: added search and clear icons to JXSearchField (issue #359) 2021-08-03 17:52:49 +02:00
Karl Tauber
d373687bc4 Testing: added FlatSingleComponentTest to easier test/debug single components 2021-08-03 15:16:04 +02:00
Karl Tauber
e5e510c825 Demo: fixed inconsistent behavior when first changing font size and then font family, which did loose user scale factor on Windows in Java 9+ (issue #352) 2021-08-02 19:16:38 +02:00
Karl Tauber
29064ec72f Button and TextComponent: do not apply minimum width/height if margins are set (issue #364) 2021-08-02 18:36:10 +02:00
Karl Tauber
953eee1dc8 TableHeader: made getRolloverColumn() public to allow usage in custom renderers (issue #336) 2021-08-02 18:01:08 +02:00
Karl Tauber
75f76f4875 ComboBox and Spinner: limit arrow button width if component has large preferred height (issue #361) 2021-08-02 15:27:25 +02:00
Karl Tauber
ecfbe68c33 Native window decorations: updated DLLs (issues #357 and #339)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/1085691279
2021-07-31 21:22:09 +02:00
Karl Tauber
7f02eb9cf0 Native window decorations: when window is initially shown, fill background with window background color (instead of white), which avoids flickering in dark themes (issue #339) 2021-07-31 21:05:01 +02:00
Karl Tauber
4ab90065dc Native window decorations: when resizing a window to the right or to the bottom, then first fill the new space with the window background color (instead of black) before the layout is updated (issue #339) 2021-07-31 18:02:10 +02:00
Karl Tauber
d3e39a1359 Native window decorations: fixed occasional application crash on Windows 10 in flatlaf-windows.dll (issue #357) 2021-07-30 23:06:09 +02:00
Karl Tauber
60e5861de4 InternalFrame: limit internal frame bounds to parent bounds on resize; honor maximum size of internal frame (issue #362) 2021-07-29 16:44:50 +02:00
Karl Tauber
ca7f5045ae Popup: fixed incorrectly placed drop shadow for medium-weight popups in maximized windows (issue #358) 2021-07-29 15:39:16 +02:00
Karl Tauber
b0997fb5d2 release 1.4 2021-07-13 11:02:10 +02:00
Karl Tauber
37dab9fb22 TabbedPane: fixed rendering of tab separators in scroll layout if scaled on HiDPI screens 2021-07-12 11:48:34 +02:00
Karl Tauber
fb44c8fbe4 TextField: fixed location of placeholder text if paddings are used (e.g. in ComboBox) (for commit a9dcf09d13) 2021-07-10 21:05:26 +02:00
Karl Tauber
94375b7d36 Extras: added support for client property JTextField.padding (for commit a9dcf09d13) 2021-07-10 20:59:34 +02:00
Karl Tauber
8b585deb78 ToolBar: support focusable buttons in toolbar (issue #346)
fixed focusable state when switching to/from other Laf
2021-07-10 13:32:30 +02:00
Karl Tauber
4d8b544aed UIDefaultsKeysDump: also use FlatTestLaf, which adds missing keys to FlatLafUIKeys.txt 2021-07-10 13:28:02 +02:00
Karl Tauber
548d651d29 PasswordField: move the lower bar of the caps lock icon up a half pixel 2021-07-10 11:03:13 +02:00
Karl Tauber
0b342acec9 PasswordField: paint caps lock icon on left side in right-to-left component orientation 2021-07-09 15:14:29 +02:00
Karl Tauber
cc6d3c1b1a PasswordField: Caps lock icon no longer painted over long text (issue #172) 2021-07-09 15:03:16 +02:00
Karl Tauber
74a748d92e use LoggingFacade instead of printStackTrace() in flatlaf-extras and flatlaf-demo 2021-07-09 13:22:37 +02:00
Karl Tauber
1de81d0af5 ComboBox: fixed StackOverflowError when using single renderer instance in multiple comboboxes (regression since commit 4507ce359d) 2021-07-09 11:39:35 +02:00
Karl Tauber
ff9ef21f67 OptionPane: align wrapped lines to the right if component orientation is right-to-left (issue #350) 2021-07-08 17:53:44 +02:00
Karl Tauber
266a546478 Window decorations: window title bar width is no longer considered when calculating preferred/minimum width of window (issue #351) 2021-07-08 16:54:34 +02:00
Karl Tauber
87407ca832 Table and PopupFactory: use StackWalker in Java 9+ for better performance (issue #334) 2021-07-08 14:02:50 +02:00
Karl Tauber
90282d4436 UI defaults dumps updated for issue #335 2021-07-08 00:02:33 +02:00
Karl Tauber
abbe6d6c1f ToolBar: paint focus indicator for focused button in toolbar (issue #346) 2021-07-07 18:17:45 +02:00
Karl Tauber
a28f701e6f OptionPane: do not make child components, which are derived from JPanel, non-opaque (issue #349) 2021-07-07 10:57:54 +02:00
Karl Tauber
4cdc995a7f ComboBox: simplified code in configureEditor() 2021-07-05 23:14:05 +02:00
Karl Tauber
c708205593 TestFlatComponentSizes: shortened combobox text because unit tests on GitHub Actions use font size 15 2021-07-05 20:06:07 +02:00
Karl Tauber
a22c6c8013 ComboBox (not editable):
- increased size of internal renderer pane to the component border so that it can paint within the whole component
- increase combo box size if a custom renderer uses a border with insets that are larger than the default combo box padding (`2,6,2,6`)
2021-07-05 18:41:17 +02:00
Karl Tauber
b576f473e5 fixed component heights at 1.25x, 1.75x and 2.25x scaling factors (Java 8 only) so that Button, ComboBox, Spinner and TextField components (including subclasses) have same heights 2021-07-05 15:15:37 +02:00
Karl Tauber
0b127caa83 ComboBox: fixed minimum width if focusWidth > 0 (to be equal with button minimum width)
added some unit tests to compare component sizes
2021-07-05 11:07:32 +02:00
Karl Tauber
4507ce359d ComboBox: reworked uninstall of CellPaddingBorder, which is temporary used for cell renderers, to make it easier to understand and reliable
(tested using FlatCustomBordersTest, FlatNetBeansTest, etc)
2021-07-03 10:43:55 +02:00
Karl Tauber
3e14f28dc2 ComboBox (editable) and Spinner: increased size of internal text field to the component border so that it behaves like plain text field (issue #330) 2021-07-02 18:43:37 +02:00
Karl Tauber
a9dcf09d13 TextField: support adding extra padding
(for #172, #173 and #330)
2021-07-02 15:38:45 +02:00
Karl Tauber
c8998c2bcf PasswordField: UI delegate FlatPasswordFieldUI now extends FlatTextFieldUI (instead of BasicPasswordFieldUI) to avoid duplicate code and for easier extensibility (e.g. for #173 and #341) 2021-07-02 14:03:54 +02:00
Karl Tauber
10bf1295bc CHANGELOG.md: fixed UI key ComboBox.popupFocusedBackground to ComboBox.popupBackground 2021-07-02 10:52:30 +02:00
249 changed files with 13044 additions and 2841 deletions

View File

@@ -34,6 +34,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1 - uses: gradle/wrapper-validation-action@v1
if: matrix.java == '1.8'
- name: Setup Java ${{ matrix.java }} - name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v1 uses: actions/setup-java@v1
@@ -72,7 +73,7 @@ jobs:
needs: build needs: build
if: | if: |
github.event_name == 'push' && github.event_name == 'push' &&
github.ref == 'refs/heads/main' && (github.ref == 'refs/heads/main' || startsWith( github.ref, 'refs/heads/develop-' )) &&
github.repository == 'JFormDesigner/FlatLaf' github.repository == 'JFormDesigner/FlatLaf'
steps: steps:
@@ -97,11 +98,22 @@ jobs:
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Publish snapshot to oss.sonatype.org - name: Publish snapshot to oss.sonatype.org
run: ./gradlew publish -Dorg.gradle.internal.publish.checksums.insecure=true run: ./gradlew publish :flatlaf-theme-editor:build -Dorg.gradle.internal.publish.checksums.insecure=true
env: env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "snapshots"
options: "--only-newer --no-recursion --verbose=1"
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -133,7 +145,7 @@ jobs:
restore-keys: ${{ runner.os }}-gradle restore-keys: ${{ runner.os }}-gradle
- name: Release a new stable version to Maven Central - name: Release a new stable version to Maven Central
run: ./gradlew publish :flatlaf-demo:build -Drelease=true run: ./gradlew publish :flatlaf-demo:build :flatlaf-theme-editor:build -Drelease=true
env: env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
@@ -150,3 +162,14 @@ jobs:
localDir: "flatlaf-demo/build/libs" localDir: "flatlaf-demo/build/libs"
remoteDir: "." remoteDir: "."
options: "--only-newer --no-recursion --verbose=1" options: "--only-newer --no-recursion --verbose=1"
- name: Upload theme editor
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ${{ secrets.FTP_SERVER }}
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
forceSsl: true
localDir: "flatlaf-theme-editor/build/libs"
remoteDir: "."
options: "--only-newer --no-recursion --verbose=1"

View File

@@ -1,6 +1,180 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 1.6.5
#### Fixed bugs
- Linux: Fixed font problems when running on Oracle Java (OpenJDK is not
affected):
- oversized text if system font is "Inter" (issue #427)
- missing text if system font is "Cantarell" (on Fedora)
- MenuItem: Changed accelerator delimiter from `-` to `+`. (Windows and Linux).
- ComboBox: Fixed occasional `StackOverflowError` when modifying combo box not
on AWT thread. (issue #432)
- macOS: Fixed `NullPointerException` when using AWT component
`java.awt.Choice`. (issue #439)
- Native window decorations: Do not exit application with `UnsatisfiedLinkError`
in case that FlatLaf DLL cannot be executed because of restrictions on
temporary directory. Instead, continue with default window decorations. (issue
#436)
## 1.6.4
#### Fixed bugs
- ComboBox: Fixed regression in FlatLaf 1.6.3 that makes selected item invisible
in popup list if `DefaultListCellRenderer` is used as renderer. If using
default renderer, it works. (issue #426)
## 1.6.3
#### Fixed bugs
- ComboBox (not editable): Fixed regression in FlatLaf 1.6.2 that may display
text in non-editable combo boxes in bold. (issue #423)
- Tree: Fixed editing cell issue with custom cell renderer and cell editor that
use same component for rendering and editing. (issue #385)
## 1.6.2
#### Fixed bugs
- ComboBox (not editable): Fixed background painted outside of border if round
edges are enabled (client property `JComponent.roundRect` is `true`). (similar
to issue #382; regression since fixing #330 in FlatLaf 1.4)
- ComboBox: Fixed `NullPointerException`, which may occur under special
circumstances. (issue #408)
- Table: Do not select text in cell editor when it gets focus (when
`JTable.surrendersFocusOnKeystroke` is `true`) and
`TextComponent.selectAllOnFocusPolicy` is `once` (the default) or `always`.
(issue #395)
- Linux: Fixed NPE when using `java.awt.TrayIcon`. (issue #405)
- FileChooser: Workaround for crash on Windows with Java 17 32-bit (disabled
Windows icons). Java 17 64-bit is not affected. (issue #403)
- Native window decorations: Fixed layout loop, which may occur under special
circumstances and slows down the application. (issue #420)
## 1.6.1
#### Fixed bugs
- Native window decorations: Catch `UnsatisfiedLinkError` when trying to load
`jawt.dll` to avoid an application crash (Java 8 on Windows 10 only).
## 1.6
#### New features and improvements
- InternalFrame: Double-click on icon in internal frame title bar now closes the
internal frame. (issue #374)
- IntelliJ Themes: Removed deprecated `install()` methods.
#### Fixed bugs
- Menus: Fixed missing modifiers flags in `ActionEvent` (e.g. `Ctrl` key
pressed) when running in Java 9+ on Linux, macOS. Occurs also on Windows in
large popup menus that do not fit into the window. (issue #371; regression
since FlatLaf 1.3)
- OptionPane: Fixed `OptionPane.sameSizeButtons`, which did not work as expected
when setting to `false`.
- OptionPane: Fixed rendering of longer HTML text if it is passed as
`StringBuilder`, `StringBuffer`, or any other object that returns HTML text in
method `toString()`. (similar to issue #12)
- ComboBox: Fixed popup border painting on HiDPI screens (e.g. at 150% scaling).
- ComboBox: Fixed popup location if shown above of combo box (Java 8 only).
- ComboBox (editable): Fixed wrong border of internal text field under special
circumstances.
- Spinner: Fixed painting of border corners on left side. (issue #382;
regression since fixing #330 in FlatLaf 1.4)
- TableHeader: Do not show resize cursor for last column if resizing last column
is not possible because auto resize mode of table is not off. (issue #332)
- TableHeader: Fixed missing trailing vertical separator line if used in upper
left corner of scroll pane. (issue #332)
- TextField, FormattedTextField, PasswordField and ComboBox: Fixed alignment of
placeholder text in right-to-left component orientation.
- Slider: Fixed calculation of baseline, which was wrong under some
circumstances.
## 1.5
#### New features and improvements
- SwingX: Added search and clear icons to `JXSearchField`. (issue #359)
#### Fixed bugs
- Button and TextComponent: Do not apply minimum width/height if margins are
set. (issue #364)
- ComboBox and Spinner: Limit arrow button width if component has large
preferred height. (issue #361)
- FileChooser: Fixed missing (localized) texts when FlatLaf is loaded in special
classloader (e.g. plugin system in Apache NetBeans).
- InternalFrame: Limit internal frame bounds to parent bounds on resize. Also
honor maximum size of internal frame. (issue #362)
- Popup: Fixed incorrectly placed drop shadow for medium-weight popups in
maximized windows. (issue #358)
- Native window decorations (Windows 10 only):
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
- When window is initially shown, fill background with window background color
(instead of white), which avoids flickering in dark themes. (issue 339)
- When resizing a window at the right/bottom edge, then first fill the new
space with the window background color (instead of black) before the layout
is updated.
- When resizing a window at the left/top edge, then first fill the new space
with the window background color (instead of garbage) before the layout is
updated.
## 1.4
#### New features and improvements
- TextField, FormattedTextField and PasswordField: Support adding extra padding.
(set client property `JTextField.padding` to `Insets`).
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
extensibility.
- Table and PopupFactory: Use `StackWalker` in Java 9+ for better performance.
(issue #334)
- ToolBar: Paint focus indicator for focused button in toolbar. (issue #346)
- ToolBar: Support focusable buttons in toolbar (set UI value
`ToolBar.focusableButtons` to `true`). (issue #346)
#### Fixed bugs
- ComboBox (editable) and Spinner: Increased size of internal text field to the
component border so that it behaves like plain text field (mouse click to left
of text now positions caret to first character instead of opening ComboBox
popup; mouse cursor is now of type "text" within the whole component, except
for arrow buttons). (issue #330)
- ComboBox (not editable): Increased size of internal renderer pane to the
component border so that it can paint within the whole component. Also
increase combo box size if a custom renderer uses a border with insets that
are larger than the default combo box padding (`2,6,2,6`).
- Fixed component heights at `1.25x`, `1.75x` and `2.25x` scaling factors (Java
8 only) so that Button, ComboBox, Spinner and TextField components (including
subclasses) have same heights. This increases heights of Button and TextField
components by:
- `2px` at `1.75x` in **Light** and **Dark** themes
- `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes
- OptionPane: Do not make child components, which are derived from `JPanel`,
non-opaque. (issue #349)
- OptionPane: Align wrapped lines to the right if component orientation is
right-to-left. (issue #350)
- PasswordField: Caps lock icon no longer painted over long text. (issue #172)
- PasswordField: Paint caps lock icon on left side in right-to-left component
orientation.
- Window decorations: Window title bar width is no longer considered when
calculating preferred/minimum width of window. (issue #351)
## 1.3 ## 1.3
#### New features and improvements #### New features and improvements
@@ -10,7 +184,7 @@ FlatLaf Change Log
`PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`, `PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`,
`TextArea.focusedBackground`, `TextPane.focusedBackground`, `TextArea.focusedBackground`, `TextPane.focusedBackground`,
`EditorPane.focusedBackground`, `ComboBox.focusedBackground`, `EditorPane.focusedBackground`, `ComboBox.focusedBackground`,
`ComboBox.buttonFocusedBackground`, `ComboBox.popupFocusedBackground` and `ComboBox.buttonFocusedBackground`, `ComboBox.popupBackground` and
`Spinner.focusedBackground`). (issue #335) `Spinner.focusedBackground`). (issue #335)
#### Fixed bugs #### Fixed bugs

View File

@@ -67,10 +67,13 @@ docs).
Addons Addons
------ ------
- [IntelliJ Themes Pack](flatlaf-intellij-themes) - [IntelliJ Themes Pack](flatlaf-intellij-themes) - bundles many popular
- [Extras](flatlaf-extras) open-source 3rd party themes
- [SwingX](flatlaf-swingx) - [Extras](flatlaf-extras) - SVG icon, tri-state check box, UI inspectors, and
- [JIDE Common Layer](flatlaf-jide-oss) more
- [SwingX](flatlaf-swingx) - support for SwingX components
- [JIDE Common Layer](flatlaf-jide-oss) - support for JIDE Common Layer
components
Getting started Getting started

View File

@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
val releaseVersion = "1.3" val releaseVersion = "1.6.5"
val developmentVersion = "1.4-SNAPSHOT" val developmentVersion = "1.6.6-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion

View File

@@ -21,6 +21,12 @@ plugins {
`flatlaf-publish` `flatlaf-publish`
} }
dependencies {
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testImplementation( "org.junit.jupiter:junit-jupiter-params" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
}
java { java {
withSourcesJar() withSourcesJar()
withJavadocJar() withJavadocJar()
@@ -52,6 +58,11 @@ tasks {
named<Jar>( "javadocJar" ) { named<Jar>( "javadocJar" ) {
archiveBaseName.set( "flatlaf" ) archiveBaseName.set( "flatlaf" )
} }
test {
useJUnitPlatform()
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
} }
flatlafPublish { flatlafPublish {

View File

@@ -733,6 +733,18 @@ public interface FlatClientProperties
*/ */
String PLACEHOLDER_TEXT = "JTextField.placeholderText"; String PLACEHOLDER_TEXT = "JTextField.placeholderText";
/**
* Specifies the padding of the text.
* This changes the location and size of the text view within the component bounds,
* but does not affect the size of the component.
* <p>
* <strong>Component</strong> {@link javax.swing.JTextField} (and subclasses)<br>
* <strong>Value type</strong> {@link java.awt.Insets}
*
* @since 1.4
*/
String TEXT_FIELD_PADDING = "JTextField.padding";
//---- JToggleButton ------------------------------------------------------ //---- JToggleButton ------------------------------------------------------
/** /**

View File

@@ -32,10 +32,14 @@ import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties; import java.util.Properties;
import java.util.ResourceBundle;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@@ -45,6 +49,7 @@ import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
@@ -63,9 +68,11 @@ import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.FlatNativeWindowBorder;
import com.formdev.flatlaf.ui.FlatPopupFactory; import com.formdev.flatlaf.ui.FlatPopupFactory;
import com.formdev.flatlaf.ui.FlatRootPaneUI; import com.formdev.flatlaf.ui.FlatRootPaneUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.GrayFilter; import com.formdev.flatlaf.util.GrayFilter;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -92,6 +99,7 @@ public abstract class FlatLaf
private MnemonicHandler mnemonicHandler; private MnemonicHandler mnemonicHandler;
private Consumer<UIDefaults> postInitialization; private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;
/** /**
* Sets the application look and feel to the given LaF * Sets the application look and feel to the given LaF
@@ -257,6 +265,12 @@ public abstract class FlatLaf
} }
}; };
Toolkit toolkit = Toolkit.getDefaultToolkit(); Toolkit toolkit = Toolkit.getDefaultToolkit();
// make sure that AWT desktop properties are initialized (on Linux)
// before invoking toolkit.addPropertyChangeListener()
// https://github.com/JFormDesigner/FlatLaf/issues/405#issuecomment-960242342
toolkit.getDesktopProperty( "dummy" );
toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener ); toolkit.addPropertyChangeListener( desktopPropertyName, desktopPropertyListener );
if( desktopPropertyName2 != null ) if( desktopPropertyName2 != null )
toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener ); toolkit.addPropertyChangeListener( desktopPropertyName2, desktopPropertyListener );
@@ -350,14 +364,21 @@ public abstract class FlatLaf
@Override @Override
public UIDefaults getDefaults() { public UIDefaults getDefaults() {
UIDefaults defaults = super.getDefaults(); // use larger initial capacity to avoid resizing UI defaults hash table
// (from 610 to 1221 to 2443 entries) and to save some memory
UIDefaults defaults = new FlatUIDefaults( 1500, 0.75f );
// initialize basic defaults (see super.getDefaults())
initClassDefaults( defaults );
initSystemColorDefaults( defaults );
initComponentDefaults( defaults );
// add flag that indicates whether the LaF is light or dark // add flag that indicates whether the LaF is light or dark
// (can be queried without using FlatLaf API) // (can be queried without using FlatLaf API)
defaults.put( "laf.dark", isDark() ); defaults.put( "laf.dark", isDark() );
// add resource bundle for localized texts // init resource bundle for localized texts
defaults.addResourceBundle( "com.formdev.flatlaf.resources.Bundle" ); initResourceBundle( defaults, "com.formdev.flatlaf.resources.Bundle" );
// 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
@@ -453,6 +474,45 @@ public abstract class FlatLaf
return null; return null;
} }
private void initResourceBundle( UIDefaults defaults, String bundleName ) {
// add resource bundle for localized texts
defaults.addResourceBundle( bundleName );
// Check whether Swing can not load the FlatLaf resource bundle,
// which can happen in applications that use some plugin system
// and load FlatLaf in a plugin that uses its own classloader.
// (e.g. Apache NetBeans)
if( defaults.get( "FileChooser.fileNameHeaderText" ) != null )
return;
// load FlatLaf resource bundle and add content to defaults
try {
ResourceBundle bundle = ResourceBundle.getBundle( bundleName, defaults.getDefaultLocale() );
Enumeration<String> keys = bundle.getKeys();
while( keys.hasMoreElements() ) {
String key = keys.nextElement();
String value = bundle.getString( key );
String baseKey = StringUtils.removeTrailing( key, ".textAndMnemonic" );
if( baseKey != key ) {
String text = value.replace( "&", "" );
String mnemonic = null;
int index = value.indexOf( '&' );
if( index >= 0 )
mnemonic = Integer.toString( Character.toUpperCase( value.charAt( index + 1 ) ) );
defaults.put( baseKey + "Text", text );
if( mnemonic != null )
defaults.put( baseKey + "Mnemonic", mnemonic );
} else
defaults.put( key, value );
}
} catch( MissingResourceException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
private void initFonts( UIDefaults defaults ) { private void initFonts( UIDefaults defaults ) {
FontUIResource uiFont = null; FontUIResource uiFont = null;
@@ -819,12 +879,23 @@ public abstract class FlatLaf
/** /**
* Revalidate and repaint all displayable frames and dialogs. * Revalidate and repaint all displayable frames and dialogs.
* <p>
* Useful to update UI after changing {@code TitlePane.menuBarEmbedded}.
* *
* @since 1.1.2 * @since 1.1.2
*/ */
public static void revalidateAndRepaintAllFramesAndDialogs() { public static void revalidateAndRepaintAllFramesAndDialogs() {
for( Window w : Window.getWindows() ) { for( Window w : Window.getWindows() ) {
if( isDisplayableFrameOrDialog( w ) ) { if( isDisplayableFrameOrDialog( w ) ) {
// revalidate menu bar
JMenuBar menuBar = (w instanceof JFrame)
? ((JFrame)w).getJMenuBar()
: (w instanceof JDialog
? ((JDialog)w).getJMenuBar()
: null);
if( menuBar != null )
menuBar.revalidate();
w.revalidate(); w.revalidate();
w.repaint(); w.repaint();
} }
@@ -833,6 +904,9 @@ public abstract class FlatLaf
/** /**
* Repaint all displayable frames and dialogs. * Repaint all displayable frames and dialogs.
* <p>
* Useful to update UI after changing {@code TitlePane.unifiedBackground},
* {@code MenuItem.selectionType} or {@code Component.hideMnemonics}.
* *
* @since 1.1.2 * @since 1.1.2
*/ */
@@ -871,6 +945,139 @@ public abstract class FlatLaf
return super.hashCode(); return super.hashCode();
} }
/**
* Registers a UI defaults getter function that is invoked before the standard getter.
* This allows using different UI defaults for special purposes
* (e.g. using multiple themes at the same time).
* <p>
* The key is passed as parameter to the function.
* If the function returns {@code null}, then the next registered function is invoked.
* If all registered functions return {@code null}, then the current look and feel is asked.
* If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}.
*
* @see #unregisterUIDefaultsGetter(Function)
* @see #runWithUIDefaultsGetter(Function, Runnable)
* @since 1.6
*/
public void registerUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter ) {
if( uiDefaultsGetters == null )
uiDefaultsGetters = new ArrayList<>();
uiDefaultsGetters.remove( uiDefaultsGetter );
uiDefaultsGetters.add( uiDefaultsGetter );
// disable shared UIs
FlatUIUtils.setUseSharedUIs( false );
}
/**
* Unregisters a UI defaults getter function that was invoked before the standard getter.
*
* @see #registerUIDefaultsGetter(Function)
* @see #runWithUIDefaultsGetter(Function, Runnable)
* @since 1.6
*/
public void unregisterUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter ) {
if( uiDefaultsGetters == null )
return;
uiDefaultsGetters.remove( uiDefaultsGetter );
// enable shared UIs
if( uiDefaultsGetters.isEmpty() )
FlatUIUtils.setUseSharedUIs( true );
}
/**
* Registers a UI defaults getter function that is invoked before the standard getter,
* runs the given runnable and unregisters the UI defaults getter function again.
* This allows using different UI defaults for special purposes
* (e.g. using multiple themes at the same time).
* If the current look and feel is not FlatLaf, then the getter is ignored and
* the given runnable invoked.
* <p>
* The key is passed as parameter to the function.
* If the function returns {@code null}, then the next registered function is invoked.
* If all registered functions return {@code null}, then the current look and feel is asked.
* If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}.
* <p>
* Example:
* <pre>{@code
* // create secondary theme
* UIDefaults darkDefaults = new FlatDarkLaf().getDefaults();
*
* // create panel using secondary theme
* FlatLaf.runWithUIDefaultsGetter( key -> {
* Object value = darkDefaults.get( key );
* return (value != null) ? value : FlatLaf.NULL_VALUE;
* }, () -> {
* // TODO create components that should use secondary theme here
* } );
* }</pre>
*
* @see #registerUIDefaultsGetter(Function)
* @see #unregisterUIDefaultsGetter(Function)
* @since 1.6
*/
public static void runWithUIDefaultsGetter( Function<Object, Object> uiDefaultsGetter, Runnable runnable ) {
LookAndFeel laf = UIManager.getLookAndFeel();
if( laf instanceof FlatLaf ) {
((FlatLaf)laf).registerUIDefaultsGetter( uiDefaultsGetter );
try {
runnable.run();
} finally {
((FlatLaf)laf).unregisterUIDefaultsGetter( uiDefaultsGetter );
}
} else
runnable.run();
}
/**
* Special value returned by functions used in {@link #runWithUIDefaultsGetter(Function, Runnable)}
* or {@link #registerUIDefaultsGetter(Function)} to indicate that the UI value should
* become {@code null}.
*
* @see #runWithUIDefaultsGetter(Function, Runnable)
* @see #registerUIDefaultsGetter(Function)
* @since 1.6
*/
public static final Object NULL_VALUE = new Object();
//---- class FlatUIDefaults -----------------------------------------------
private class FlatUIDefaults
extends UIDefaults
{
FlatUIDefaults( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor );
}
@Override
public Object get( Object key ) {
Object value = getValue( key );
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key );
}
@Override
public Object get( Object key, Locale l ) {
Object value = getValue( key );
return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l );
}
private Object getValue( Object key ) {
if( uiDefaultsGetters == null )
return null;
for( int i = uiDefaultsGetters.size() - 1; i >= 0; i-- ) {
Object value = uiDefaultsGetters.get( i ).apply( key );
if( value != null )
return value;
}
return null;
}
}
//---- class ActiveFont --------------------------------------------------- //---- class ActiveFont ---------------------------------------------------
private static class ActiveFont private static class ActiveFont

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.awt.Toolkit; import java.awt.Toolkit;
@@ -28,7 +29,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import javax.swing.text.StyleContext;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -121,14 +122,25 @@ class LinuxFontPolicy
for(;;) { for(;;) {
Font font = createFont( family, style, size, dsize ); Font font = createFont( family, style, size, dsize );
// if the font family does not match any font on the system, "Dialog" family is returned if( Font.DIALOG.equals( family ) )
if( !"Dialog".equals( font.getFamily() ) || "Dialog".equals( family ) )
return font; return font;
// if the font family does not match any font on the system, "Dialog" family is returned
if( !Font.DIALOG.equals( font.getFamily() ) ) {
// check for font problems
// - font height much larger than expected (e.g. font Inter; Oracle Java 8)
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
return createFont( Font.DIALOG, style, size, dsize );
return font;
}
// find last word in family // find last word in family
int index = family.lastIndexOf( ' ' ); int index = family.lastIndexOf( ' ' );
if( index < 0 ) if( index < 0 )
return createFont( "Dialog", style, size, dsize ); return createFont( Font.DIALOG, style, size, dsize );
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy) // check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
String lastWord = family.substring( index + 1 ).toLowerCase(); String lastWord = family.substring( index + 1 ).toLowerCase();
@@ -309,6 +321,9 @@ class LinuxFontPolicy
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings * - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
*/ */
private static boolean isSystemScaling() { private static boolean isSystemScaling() {
if( GraphicsEnvironment.isHeadless() )
return true;
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration(); .getDefaultScreenDevice().getDefaultConfiguration();
return UIScale.getSystemScaleFactor( gc ) > 1; return UIScale.getSystemScaleFactor( gc ) > 1;

View File

@@ -604,6 +604,13 @@ class UIDefaultsLoader
case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError ); case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError );
case "fade": return parseColorFade( params, resolver, reportError ); case "fade": return parseColorFade( params, resolver, reportError );
case "spin": return parseColorSpin( params, resolver, reportError ); case "spin": return parseColorSpin( params, resolver, reportError );
case "changeHue": return parseColorChange( 0, params, resolver, reportError );
case "changeSaturation":return parseColorChange( 1, params, resolver, reportError );
case "changeLightness": return parseColorChange( 2, params, resolver, reportError );
case "changeAlpha": return parseColorChange( 3, params, resolver, reportError );
case "mix": return parseColorMix( null, params, resolver, reportError );
case "tint": return parseColorMix( "#fff", params, resolver, reportError );
case "shade": return parseColorMix( "#000", params, resolver, reportError );
} }
} finally { } finally {
parseColorDepth--; parseColorDepth--;
@@ -753,6 +760,68 @@ class UIDefaultsLoader
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError ); return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
} }
/**
* Syntax: changeHue(color,value[,options]) or
* changeSaturation(color,value[,options]) or
* changeLightness(color,value[,options]) or
* changeAlpha(color,value[,options])
* - color: a color (e.g. #f00) or a color function
* - value: for hue: number of degrees; otherwise: percentage 0-100%
* - options: [derived]
*/
private static Object parseColorChange( int hslIndex,
List<String> params, Function<String, String> resolver, boolean reportError )
{
String colorStr = params.get( 0 );
int value = (hslIndex == 0)
? parseInteger( params.get( 1 ), true )
: parsePercentage( params.get( 1 ) );
boolean derived = false;
if( params.size() > 2 ) {
String options = params.get( 2 );
derived = options.contains( "derived" );
}
// create function
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError );
}
/**
* Syntax: mix(color1,color2[,weight]) or
* tint(color[,weight]) or
* shade(color[,weight])
* - color1: a color (e.g. #f00) or a color function
* - color2: a color (e.g. #f00) or a color function
* - weight: the weight (in range 0-100%) to mix the two colors
* larger weight uses more of first color, smaller weight more of second color
*/
private static Object parseColorMix( String color1Str, List<String> params, Function<String, String> resolver, boolean reportError ) {
int i = 0;
if( color1Str == null )
color1Str = params.get( i++ );
String color2Str = params.get( i++ );
int weight = 50;
if( params.size() > i )
weight = parsePercentage( params.get( i++ ) );
// parse second color
String resolvedColor2Str = resolver.apply( color2Str );
ColorUIResource color2 = (ColorUIResource) parseColorOrFunction( resolvedColor2Str, resolver, reportError );
if( color2 == null )
return null;
// create function
ColorFunction function = new ColorFunctions.Mix( color2, weight );
// parse first color, apply function and create mixed color
return parseFunctionBaseColor( color1Str, function, false, resolver, reportError );
}
private static Object parseFunctionBaseColor( String colorStr, ColorFunction function, private static Object parseFunctionBaseColor( String colorStr, ColorFunction function,
boolean derived, Function<String, String> resolver, boolean reportError ) boolean derived, Function<String, String> resolver, boolean reportError )
{ {

View File

@@ -44,7 +44,7 @@ public class FlatCapsLockIcon
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/> <rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="6" height="2" x="5" y="12" fill="#FFF"/> <rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/> <path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
</g> </g>
</svg> </svg>
@@ -52,7 +52,7 @@ public class FlatCapsLockIcon
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false ); path.append( new RoundRectangle2D.Float( 0, 0, 16, 16, 6, 6 ), false );
path.append( new Rectangle2D.Float( 5, 12, 6, 2 ), false ); path.append( new Rectangle2D.Float( 5, 11.5f, 6, 2 ), false );
path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false ); path.append( FlatUIUtils.createPath( 2,8, 8,2, 14,8, 11,8, 11,10, 5,10, 5,8 ), false );
g.fill( path ); g.fill( path );
} }

View File

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

View File

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

View File

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

View File

@@ -45,6 +45,7 @@ import com.formdev.flatlaf.util.DerivedColor;
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.innerFocusWidth int or float * @uiDefault Component.innerFocusWidth int or float
* @uiDefault Component.innerOutlineWidth 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
@@ -176,13 +177,14 @@ public class FlatBorder
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
float focusWidth = scale( (float) getFocusWidth( c ) ); float focusWidth = scale( (float) getFocusWidth( c ) );
float ow = focusWidth + scale( (float) getLineWidth( c ) ); int ow = Math.round( focusWidth + scale( (float) getLineWidth( c ) ) );
insets = super.getBorderInsets( c, insets ); insets = super.getBorderInsets( c, insets );
insets.top = Math.round( scale( (float) insets.top ) + ow );
insets.left = Math.round( scale( (float) insets.left ) + ow ); insets.top = scale( insets.top ) + ow;
insets.bottom = Math.round( scale( (float) insets.bottom ) + ow ); insets.left = scale( insets.left ) + ow;
insets.right = Math.round( scale( (float) insets.right ) + ow ); insets.bottom = scale( insets.bottom ) + ow;
insets.right = scale( insets.right ) + ow;
if( isCellEditor( c ) ) { if( isCellEditor( c ) ) {
// remove top and bottom insets if used as cell editor // remove top and bottom insets if used as cell editor

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.GradientPaint; import java.awt.GradientPaint;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Paint; import java.awt.Paint;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
@@ -42,11 +43,13 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.default.hoverBorderColor Color optional * @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.default.focusedBorderColor Color * @uiDefault Button.default.focusedBorderColor Color
* @uiDefault Button.default.focusColor Color * @uiDefault Button.default.focusColor Color
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
* @uiDefault Button.borderWidth int * @uiDefault Button.borderWidth int
* @uiDefault Button.default.borderWidth int * @uiDefault Button.default.borderWidth int
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth * @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
* @uiDefault Button.toolbar.margin Insets * @uiDefault Button.toolbar.margin Insets
* @uiDefault Button.toolbar.spacingInsets Insets * @uiDefault Button.toolbar.spacingInsets Insets
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1
* @uiDefault Button.arc int * @uiDefault Button.arc int
* *
* @author Karl Tauber * @author Karl Tauber
@@ -64,11 +67,15 @@ public class FlatButtonBorder
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" ); protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" ); protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" ); protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
/** @since 1.4 */
protected final Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" ); protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" ); protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth ); protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" ); protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" ); protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
/** @since 1.4 */
protected final float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
protected final int arc = UIManager.getInt( "Button.arc" ); protected final int arc = UIManager.getInt( "Button.arc" );
@Override @Override
@@ -79,11 +86,41 @@ public class FlatButtonBorder
!FlatButtonUI.isHelpButton( c ) && !FlatButtonUI.isHelpButton( c ) &&
!FlatToggleButtonUI.isTabButton( c ) ) !FlatToggleButtonUI.isTabButton( c ) )
super.paintBorder( c, g, x, y, width, height ); super.paintBorder( c, g, x, y, width, height );
else if( FlatButtonUI.isToolBarButton( c ) && isFocused( c ) )
paintToolBarFocus( c, g, x, y, width, height );
}
/**
* @since 1.4
*/
protected void paintToolBarFocus( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
float focusWidth = UIScale.scale( toolbarFocusWidth );
float arc = UIScale.scale( (float) getArc( c ) );
Color outlineColor = getOutlineColor( c );
Insets spacing = UIScale.scale( toolbarSpacingInsets );
x += spacing.left;
y += spacing.top;
width -= spacing.left + spacing.right;
height -= spacing.top + spacing.bottom;
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
// not using paintComponentOuterBorder() here because its round edges look too "thick"
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0, focusWidth, arc );
} finally {
g2.dispose();
}
} }
@Override @Override
protected Color getFocusColor( Component c ) { protected Color getFocusColor( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ); return (toolbarFocusColor != null && FlatButtonUI.isToolBarButton( c ))
? toolbarFocusColor
: (FlatButtonUI.isDefaultButton( c ) ? defaultFocusColor : super.getFocusColor( c ));
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Objects;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
import javax.swing.Icon; import javax.swing.Icon;
@@ -129,6 +130,7 @@ public class FlatButtonUI
protected Color toolbarSelectedBackground; protected Color toolbarSelectedBackground;
private Icon helpButtonIcon; private Icon helpButtonIcon;
private Insets defaultMargin;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
@@ -184,6 +186,7 @@ public class FlatButtonUI
toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" ); toolbarSelectedBackground = UIManager.getColor( prefix + "toolbar.selectedBackground" );
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" ); helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
defaultMargin = UIManager.getInsets( prefix + "margin" );
defaults_initialized = true; defaults_initialized = true;
} }
@@ -499,16 +502,23 @@ public class FlatButtonUI
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) { } else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
// make single-character-no-icon button square (increase width) // 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( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) { } else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) &&
c.getBorder() instanceof FlatButtonBorder && hasDefaultMargins( c ) )
{
// apply minimum width/height // apply minimum width/height
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) ); prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) ); prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw );
} }
return prefSize; return prefSize;
} }
private boolean hasDefaultMargins( JComponent c ) {
Insets margin = ((AbstractButton)c).getMargin();
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
}
//---- class FlatButtonListener ------------------------------------------- //---- class FlatButtonListener -------------------------------------------
protected class FlatButtonListener protected class FlatButtonListener

View File

@@ -18,10 +18,13 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*; import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import javax.swing.JFormattedTextField; import javax.swing.JFormattedTextField;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret; import javax.swing.text.DefaultCaret;
import javax.swing.text.Document; import javax.swing.text.Document;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
@@ -61,6 +64,19 @@ public class FlatCaret
} }
} }
@Override
protected void adjustVisibility( Rectangle nloc ) {
JTextComponent c = getComponent();
if( c != null && c.getUI() instanceof FlatTextFieldUI ) {
Insets padding = ((FlatTextFieldUI)c.getUI()).getPadding();
if( padding != null ) {
nloc.x -= padding.left;
nloc.y -= padding.top;
}
}
super.adjustVisibility( nloc );
}
@Override @Override
public void focusGained( FocusEvent e ) { public void focusGained( FocusEvent e ) {
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) ) if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
@@ -92,7 +108,7 @@ public class FlatCaret
protected 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() || FlatUIUtils.isCellEditor( c ) )
return; return;
Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY ); Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
@@ -127,4 +143,23 @@ public class FlatCaret
moveDot( doc.getLength() ); moveDot( doc.getLength() );
} }
} }
/**
* @since 1.4
*/
public void scrollCaretToVisible() {
JTextComponent c = getComponent();
if( c == null || c.getUI() == null )
return;
try {
Rectangle loc = c.getUI().modelToView( c, getDot(), getDotBias() );
if( loc != null ) {
adjustVisibility( loc );
damage( loc );
}
} catch( BadLocationException ex ) {
// ignore
}
}
} }

View File

@@ -17,11 +17,13 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import static com.formdev.flatlaf.util.UIScale.unscale;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.ComponentOrientation; import java.awt.ComponentOrientation;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
@@ -39,11 +41,9 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
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;
@@ -68,7 +68,6 @@ import javax.swing.plaf.basic.ComboPopup;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}. * Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}.
@@ -137,7 +136,7 @@ public class FlatComboBoxUI
protected boolean hover; protected boolean hover;
protected boolean pressed; protected boolean pressed;
private WeakReference<Component> lastRendererComponent; private CellPaddingBorder paddingBorder;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatComboBoxUI(); return new FlatComboBoxUI();
@@ -222,8 +221,7 @@ public class FlatComboBoxUI
if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 ) if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 )
comboBox.setMaximumRowCount( maximumRowCount ); comboBox.setMaximumRowCount( maximumRowCount );
// scale paddingBorder = new CellPaddingBorder( padding );
padding = UIScale.scale( padding );
MigLayoutVisualPadding.install( comboBox ); MigLayoutVisualPadding.install( comboBox );
} }
@@ -250,6 +248,8 @@ public class FlatComboBoxUI
popupBackground = null; popupBackground = null;
paddingBorder.uninstall();
MigLayoutVisualPadding.uninstall( comboBox ); MigLayoutVisualPadding.uninstall( comboBox );
} }
@@ -260,9 +260,16 @@ public class FlatComboBoxUI
public void layoutContainer( Container parent ) { public void layoutContainer( Container parent ) {
super.layoutContainer( parent ); super.layoutContainer( parent );
if( arrowButton != null ) { // on macOS, a Swing combo box is used for AWT component java.awt.Choice
// and the font may be (temporary) null
if( arrowButton != null && comboBox.getFont() != null ) {
// limit button width to height of a raw combobox (without insets)
FontMetrics fm = comboBox.getFontMetrics( comboBox.getFont() );
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
Insets insets = getInsets(); Insets insets = getInsets();
int buttonWidth = parent.getPreferredSize().height - insets.top - insets.bottom; int buttonWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
if( buttonWidth != arrowButton.getWidth() ) { if( buttonWidth != arrowButton.getWidth() ) {
// set width of arrow button to preferred height of combobox // set width of arrow button to preferred height of combobox
int xOffset = comboBox.getComponentOrientation().isLeftToRight() int xOffset = comboBox.getComponentOrientation().isLeftToRight()
@@ -276,11 +283,6 @@ public class FlatComboBoxUI
editor.setBounds( rectangleForCurrentValue() ); editor.setBounds( rectangleForCurrentValue() );
} }
} }
if( editor != null && padding != null ) {
// fix editor bounds by subtracting padding
editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) );
}
} }
}; };
} }
@@ -338,39 +340,32 @@ public class FlatComboBoxUI
} }
@Override @Override
protected ComboBoxEditor createEditor() { protected void configureEditor() {
ComboBoxEditor comboBoxEditor = super.createEditor(); super.configureEditor();
Component editor = comboBoxEditor.getEditorComponent();
if( editor instanceof JTextField ) { if( editor instanceof JTextField ) {
JTextField textField = (JTextField) editor; JTextField textField = (JTextField) editor;
textField.setColumns( editorColumns ); textField.setColumns( editorColumns );
// assign a non-null and non-javax.swing.plaf.UIResource border to the text field, // remove default text field border from editor
// otherwise it is replaced with default text field border when switching LaF Border border = textField.getBorder();
// because javax.swing.plaf.basic.BasicComboBoxEditor.BorderlessTextField.setBorder() if( border == null || border instanceof UIResource ) {
// uses "border instanceof javax.swing.plaf.basic.BasicComboBoxEditor.UIResource" // assign a non-null and non-javax.swing.plaf.UIResource border to the text field,
// instead of "border instanceof javax.swing.plaf.UIResource" // otherwise it is replaced with default text field border when switching LaF
textField.setBorder( BorderFactory.createEmptyBorder() ); // 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
protected void configureEditor() {
super.configureEditor();
// remove default text field border from editor
if( editor instanceof JTextField && ((JTextField)editor).getBorder() instanceof FlatTextBorder )
((JTextField)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 );
editor.applyComponentOrientation( comboBox.getComponentOrientation() ); editor.applyComponentOrientation( comboBox.getComponentOrientation() );
updateEditorPadding();
updateEditorColors(); updateEditorColors();
// macOS // macOS
@@ -387,6 +382,25 @@ public class FlatComboBoxUI
} }
} }
private void updateEditorPadding() {
if( !(editor instanceof JTextField) )
return;
JTextField textField = (JTextField) editor;
Insets insets = textField.getInsets();
Insets pad = padding;
if( insets.top != 0 || insets.left != 0 || insets.bottom != 0 || insets.right != 0 ) {
// if text field has custom border, subtract text field insets from padding
pad = new Insets(
unscale( Math.max( scale( padding.top ) - insets.top, 0 ) ),
unscale( Math.max( scale( padding.left ) - insets.left, 0 ) ),
unscale( Math.max( scale( padding.bottom ) - insets.bottom, 0 ) ),
unscale( Math.max( scale( padding.right ) - insets.right, 0 ) )
);
}
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad );
}
private void updateEditorColors() { private void updateEditorColors() {
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
// is used, then the editor is updated after the combobox and the // is used, then the editor is updated after the combobox and the
@@ -471,30 +485,33 @@ public class FlatComboBoxUI
@Override @Override
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) { public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
paddingBorder.uninstall();
ListCellRenderer<Object> renderer = comboBox.getRenderer(); ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
if( renderer == null ) if( renderer == null )
renderer = new DefaultListCellRenderer(); renderer = new DefaultListCellRenderer();
Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false ); Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false );
c.setFont( comboBox.getFont() ); c.setFont( comboBox.getFont() );
c.applyComponentOrientation( comboBox.getComponentOrientation() ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
uninstallCellPaddingBorder( c );
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
c.setBackground( getBackground( enabled ) ); c.setBackground( getBackground( enabled ) );
c.setForeground( getForeground( enabled ) ); c.setForeground( getForeground( enabled ) );
// make renderer component temporary non-opaque to avoid that renderer paints
// background outside of border if combobox uses larger arc for edges
// (e.g. FlatClientProperties.COMPONENT_ROUND_RECT is true)
if( c instanceof JComponent )
((JComponent)c).setOpaque( false );
boolean shouldValidate = (c instanceof JPanel); boolean shouldValidate = (c instanceof JPanel);
if( padding != null )
bounds = FlatUIUtils.subtractInsets( bounds, padding );
// increase the size of the rendering area to make sure that the text
// is vertically aligned with other component types (e.g. JTextField)
Insets rendererInsets = getRendererComponentInsets( c );
if( rendererInsets != null )
bounds = FlatUIUtils.addInsets( bounds, rendererInsets );
paddingBorder.install( c );
currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate ); currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate );
paddingBorder.uninstall();
if( c instanceof JComponent )
((JComponent)c).setOpaque( true );
} }
@Override @Override
@@ -526,77 +543,49 @@ public class FlatComboBoxUI
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
Dimension minimumSize = super.getMinimumSize( c ); Dimension minimumSize = super.getMinimumSize( c );
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) ); int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
return minimumSize; return minimumSize;
} }
@Override @Override
protected Dimension getDefaultSize() { protected Dimension getDefaultSize() {
@SuppressWarnings( "unchecked" ) paddingBorder.uninstall();
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
Dimension size = super.getDefaultSize(); Dimension size = super.getDefaultSize();
paddingBorder.uninstall();
uninstallCellPaddingBorder( renderer );
return size; return size;
} }
@Override @Override
protected Dimension getDisplaySize() { protected Dimension getDisplaySize() {
@SuppressWarnings( "unchecked" ) paddingBorder.uninstall();
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
Dimension displaySize = super.getDisplaySize(); Dimension displaySize = super.getDisplaySize();
paddingBorder.uninstall();
// remove padding added in super.getDisplaySize()
int displayWidth = displaySize.width - padding.left - padding.right;
int displayHeight = displaySize.height - padding.top - padding.bottom;
// recalculate width without hardcoded 100 under special conditions // recalculate width without hardcoded 100 under special conditions
if( displaySize.width == 100 + padding.left + padding.right && if( displayWidth == 100 &&
comboBox.isEditable() && comboBox.isEditable() &&
comboBox.getItemCount() == 0 && comboBox.getItemCount() == 0 &&
comboBox.getPrototypeDisplayValue() == null ) comboBox.getPrototypeDisplayValue() == null )
{ {
int width = getDefaultSize().width; displayWidth = Math.max( getDefaultSize().width, editor.getPreferredSize().width );
width = Math.max( width, editor.getPreferredSize().width );
width += padding.left + padding.right;
displaySize = new Dimension( width, displaySize.height );
} }
uninstallCellPaddingBorder( renderer ); return new Dimension( displayWidth, displayHeight );
return displaySize;
} }
@Override @Override
protected Dimension getSizeForComponent( Component comp ) { protected Dimension getSizeForComponent( Component comp ) {
paddingBorder.install( comp );
Dimension size = super.getSizeForComponent( comp ); Dimension size = super.getSizeForComponent( comp );
paddingBorder.uninstall();
// remove the renderer border top/bottom insets from the size to make sure that
// the combobox gets the same height as other component types (e.g. JTextField)
Insets rendererInsets = getRendererComponentInsets( comp );
if( rendererInsets != null )
size = new Dimension( size.width, size.height - rendererInsets.top - rendererInsets.bottom );
return size; return size;
} }
private Insets getRendererComponentInsets( Component rendererComponent ) {
if( rendererComponent instanceof JComponent ) {
Border rendererBorder = ((JComponent)rendererComponent).getBorder();
if( rendererBorder != null )
return rendererBorder.getBorderInsets( rendererComponent );
}
return null;
}
private void uninstallCellPaddingBorder( Object o ) {
CellPaddingBorder.uninstall( o );
if( lastRendererComponent != null ) {
CellPaddingBorder.uninstall( lastRendererComponent );
lastRendererComponent = null;
}
}
private boolean isCellRenderer() { private boolean isCellRenderer() {
return comboBox.getParent() instanceof CellRendererPane; return comboBox.getParent() instanceof CellRendererPane;
} }
@@ -660,13 +649,11 @@ public class FlatComboBoxUI
protected class FlatComboPopup protected class FlatComboPopup
extends BasicComboPopup extends BasicComboPopup
{ {
private CellPaddingBorder paddingBorder;
protected FlatComboPopup( JComboBox combo ) { protected FlatComboPopup( JComboBox combo ) {
super( combo ); super( combo );
// BasicComboPopup listens to JComboBox.componentOrientation and updates // BasicComboPopup listens to JComboBox.componentOrientation and updates
// the component orientation of the list, scroller and popup, but when // the component orientation of the list, scroll pane and popup, but when
// switching the LaF and a new combo popup is created, the component // switching the LaF and a new combo popup is created, the component
// orientation is not applied. // orientation is not applied.
ComponentOrientation o = comboBox.getComponentOrientation(); ComponentOrientation o = comboBox.getComponentOrientation();
@@ -720,6 +707,9 @@ public class FlatComboBoxUI
protected void configurePopup() { protected void configurePopup() {
super.configurePopup(); super.configurePopup();
// make opaque to avoid that background shines thru border (e.g. at 150% scaling)
setOpaque( true );
Border border = UIManager.getBorder( "PopupMenu.border" ); Border border = UIManager.getBorder( "PopupMenu.border" );
if( border != null ) if( border != null )
setBorder( border ); setBorder( border );
@@ -745,6 +735,34 @@ public class FlatComboBoxUI
}; };
} }
@Override
protected int getPopupHeightForRowCount( int maxRowCount ) {
int height = super.getPopupHeightForRowCount( maxRowCount );
paddingBorder.uninstall();
return height;
}
@Override
public void show( Component invoker, int x, int y ) {
// Java 8: fix y coordinate if popup is shown above the combobox
// (already fixed in Java 9+ https://bugs.openjdk.java.net/browse/JDK-7072653)
if( y < 0 && !SystemInfo.isJava_9_orLater ) {
Border popupBorder = getBorder();
if( popupBorder != null ) {
Insets insets = popupBorder.getBorderInsets( this );
y -= insets.top + insets.bottom;
}
}
super.show( invoker, x, y );
}
@Override
protected void paintChildren( Graphics g ) {
super.paintChildren( g );
paddingBorder.uninstall();
}
//---- class PopupListCellRenderer ----- //---- class PopupListCellRenderer -----
private class PopupListCellRenderer private class PopupListCellRenderer
@@ -754,22 +772,15 @@ public class FlatComboBoxUI
public Component getListCellRendererComponent( JList list, Object value, public Component getListCellRendererComponent( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus ) int index, boolean isSelected, boolean cellHasFocus )
{ {
ListCellRenderer renderer = comboBox.getRenderer(); paddingBorder.uninstall();
CellPaddingBorder.uninstall( renderer );
CellPaddingBorder.uninstall( lastRendererComponent );
ListCellRenderer renderer = comboBox.getRenderer();
if( renderer == null ) if( renderer == null )
renderer = new DefaultListCellRenderer(); renderer = new DefaultListCellRenderer();
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
c.applyComponentOrientation( comboBox.getComponentOrientation() ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
if( c instanceof JComponent ) { paddingBorder.install( c );
if( paddingBorder == null )
paddingBorder = new CellPaddingBorder( padding );
paddingBorder.install( (JComponent) c );
}
lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null;
return c; return c;
} }
@@ -779,50 +790,72 @@ public class FlatComboBoxUI
//---- class CellPaddingBorder -------------------------------------------- //---- class CellPaddingBorder --------------------------------------------
/** /**
* Cell padding border used only in popup list. * Cell padding border used in popup list and for current value if not editable.
* * <p>
* The insets are the union of the cell padding and the renderer border insets, * The insets are the union of the cell padding and the renderer border insets,
* which vertically aligns text in popup list with text in combobox. * which vertically aligns text in popup list with text in combobox.
* * <p>
* The renderer border is painted on the outside of this border. * The renderer border is painted on the outer side of this border.
*/ */
private static class CellPaddingBorder private static class CellPaddingBorder
extends AbstractBorder extends AbstractBorder
{ {
private final Insets padding; private final Insets padding;
private JComponent rendererComponent;
private Border rendererBorder; private Border rendererBorder;
CellPaddingBorder( Insets padding ) { CellPaddingBorder( Insets padding ) {
this.padding = padding; this.padding = padding;
} }
void install( JComponent rendererComponent ) { // using synchronized to avoid problems with code that modifies combo box
Border oldBorder = rendererComponent.getBorder(); // (model, selection, etc) not on AWT thread (which should be not done)
if( !(oldBorder instanceof CellPaddingBorder) ) { synchronized void install( Component c ) {
rendererBorder = oldBorder; if( !(c instanceof JComponent) )
rendererComponent.setBorder( this );
}
}
static void uninstall( Object o ) {
if( o instanceof WeakReference )
o = ((WeakReference<?>)o).get();
if( !(o instanceof JComponent) )
return; return;
JComponent rendererComponent = (JComponent) o; JComponent jc = (JComponent) c;
Border border = rendererComponent.getBorder(); Border oldBorder = jc.getBorder();
if( border instanceof CellPaddingBorder ) { if( oldBorder == this )
CellPaddingBorder paddingBorder = (CellPaddingBorder) border; return; // already installed
rendererComponent.setBorder( paddingBorder.rendererBorder );
paddingBorder.rendererBorder = null; // component already has a padding border --> uninstall it
} // (may happen if single renderer instance is used in multiple comboboxes)
if( oldBorder instanceof CellPaddingBorder )
((CellPaddingBorder)oldBorder).uninstall();
// this border can be installed only at one component
// (may happen if a renderer returns varying components)
uninstall();
// remember component where this border was installed for uninstall
rendererComponent = jc;
// remember old border and replace it
rendererBorder = jc.getBorder();
jc.setBorder( this );
}
/**
* Uninstall border from previously installed component.
* Because this border is installed in PopupListCellRenderer.getListCellRendererComponent(),
* there is no single place to uninstall it.
* This is the reason why this method is called from various places.
*/
synchronized void uninstall() {
if( rendererComponent == null )
return;
if( rendererComponent.getBorder() == this )
rendererComponent.setBorder( rendererBorder );
rendererComponent = null;
rendererBorder = null;
} }
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { synchronized public Insets getBorderInsets( Component c, Insets insets ) {
if( rendererBorder != null ) { Insets padding = scale( this.padding );
if( rendererBorder != null && !(rendererBorder instanceof CellPaddingBorder) ) {
Insets insideInsets = rendererBorder.getBorderInsets( c ); Insets insideInsets = rendererBorder.getBorderInsets( c );
insets.top = Math.max( padding.top, insideInsets.top ); insets.top = Math.max( padding.top, insideInsets.top );
insets.left = Math.max( padding.left, insideInsets.left ); insets.left = Math.max( padding.left, insideInsets.left );

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -65,6 +66,8 @@ public class FlatEditorPaneUI
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground; protected Color focusedBackground;
private Insets defaultMargin;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener; private FocusListener focusListener;
@@ -81,6 +84,8 @@ public class FlatEditorPaneUI
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" );
// use component font and foreground for HTML text // use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true );
@@ -128,15 +133,19 @@ public class FlatEditorPaneUI
@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, defaultMargin );
} }
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth, defaultMargin );
} }
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) { static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth, Insets defaultMargin ) {
// do not apply minimum width if JTextComponent.margin is set
if( !FlatTextFieldUI.hasDefaultMargins( c, defaultMargin ) )
return size;
// Assume that text area is in a scroll pane (that displays the border) // Assume that text area is in a scroll pane (that displays the border)
// and subtract 1px border line width. // and subtract 1px border line width.
// Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding // Using "(scale( 1 ) * 2)" instead of "scale( 2 )" to deal with rounding

View File

@@ -262,12 +262,20 @@ public class FlatFileChooserUI
@Override @Override
public FileView getFileView( JFileChooser fc ) { public FileView getFileView( JFileChooser fc ) {
return fileView; return doNotUseSystemIcons() ? super.getFileView( fc ) : fileView;
} }
@Override @Override
public void clearIconCache() { public void clearIconCache() {
fileView.clearIconCache(); if( doNotUseSystemIcons() )
super.clearIconCache();
else
fileView.clearIconCache();
}
private boolean doNotUseSystemIcons() {
// Java 17 32bit craches on Windows when using system icons
return SystemInfo.isWindows && SystemInfo.isJava_17_orLater && !SystemInfo.isX86_64;
} }
//---- class FlatFileView ------------------------------------------------- //---- class FlatFileView -------------------------------------------------

View File

@@ -39,8 +39,6 @@ import javax.swing.plaf.ComponentUI;
* *
* <!-- FlatTextFieldUI --> * <!-- FlatTextFieldUI -->
* *
* @uiDefault TextComponent.arc int
* @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault FormattedTextField.placeholderForeground Color * @uiDefault FormattedTextField.placeholderForeground Color

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.LayoutManager; import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
@@ -146,6 +147,19 @@ public class FlatInternalFrameTitlePane
closeButton.setVisible( frame.isClosable() ); closeButton.setVisible( frame.isClosable() );
} }
Rectangle getFrameIconBounds() {
Icon icon = titleLabel.getIcon();
if( icon == null )
return null;
int iconWidth = icon.getIconWidth();
int iconHeight = icon.getIconHeight();
boolean leftToRight = titleLabel.getComponentOrientation().isLeftToRight();
int x = titleLabel.getX() + (leftToRight ? 0 : (titleLabel.getWidth() - iconWidth));
int y = titleLabel.getY() + ((titleLabel.getHeight() - iconHeight) / 2);
return new Rectangle( x, y, iconWidth, iconHeight );
}
/** /**
* Does nothing because FlatLaf internal frames do not have system menus. * Does nothing because FlatLaf internal frames do not have system menus.
*/ */

View File

@@ -22,10 +22,13 @@ import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JInternalFrame; import javax.swing.JInternalFrame;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicInternalFrameUI; import javax.swing.plaf.basic.BasicInternalFrameUI;
@@ -122,6 +125,11 @@ public class FlatInternalFrameUI
return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager ); return new FlatWindowResizer.InternalFrameResizer( frame, this::getDesktopManager );
} }
@Override
protected MouseInputAdapter createBorderListener( JInternalFrame w ) {
return new FlatBorderListener();
}
//---- class FlatInternalFrameBorder -------------------------------------- //---- class FlatInternalFrameBorder --------------------------------------
public static class FlatInternalFrameBorder public static class FlatInternalFrameBorder
@@ -195,4 +203,29 @@ public class FlatInternalFrameUI
} }
} }
} }
//---- class FlatBorderListener -------------------------------------------
/**
* @since 1.6
*/
protected class FlatBorderListener
extends BorderListener
{
@Override
public void mouseClicked( MouseEvent e ) {
if( e.getClickCount() == 2 && !frame.isIcon() &&
e.getSource() instanceof FlatInternalFrameTitlePane )
{
Rectangle iconBounds = ((FlatInternalFrameTitlePane)e.getSource()).getFrameIconBounds();
if( iconBounds != null && iconBounds.contains( e.getX(), e.getY() ) ) {
if( frame.isClosable() )
frame.doDefaultCloseAction();
return;
}
}
super.mouseClicked( e );
}
}
} }

View File

@@ -20,10 +20,12 @@ import java.awt.Color;
import java.awt.EventQueue; 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 java.beans.PropertyChangeListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicListUI; import javax.swing.plaf.basic.BasicListUI;
import com.formdev.flatlaf.FlatClientProperties;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}. * Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
@@ -95,6 +97,17 @@ public class FlatListUI
selectionInactiveForeground = null; selectionInactiveForeground = null;
} }
@Override
protected PropertyChangeListener createPropertyChangeListener() {
PropertyChangeListener superListener = super.createPropertyChangeListener();
return e -> {
superListener.propertyChange( e );
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
toggleSelectionColors();
};
}
@Override @Override
protected FocusListener createFocusListener() { protected FocusListener createFocusListener() {
return new BasicListUI.FocusHandler() { return new BasicListUI.FocusHandler() {

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.Container;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
@@ -24,7 +25,6 @@ import java.util.List;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JRootPane; import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
@@ -76,6 +76,11 @@ public class FlatNativeWindowBorder
if( !isSupported() ) if( !isSupported() )
return null; return null;
// do nothing if root pane has a parent that is not a window (e.g. a JInternalFrame)
Container parent = rootPane.getParent();
if( parent != null && !(parent instanceof Window) )
return null;
// Check whether root pane already has a window, which is the case when // Check whether root pane already has a window, which is the case when
// switching from another LaF to FlatLaf. // switching from another LaF to FlatLaf.
// Also check whether the window is displayable, which is required to install // Also check whether the window is displayable, which is required to install
@@ -83,9 +88,8 @@ public class FlatNativeWindowBorder
// If the window is not displayable, then it was probably closed/disposed but not yet removed // If the window is not displayable, then it was probably closed/disposed but not yet removed
// from the list of windows that AWT maintains and returns with Window.getWindows(). // from the list of windows that AWT maintains and returns with Window.getWindows().
// It could be also be a window that is currently hidden, but may be shown later. // It could be also be a window that is currently hidden, but may be shown later.
Window window = SwingUtilities.windowForComponent( rootPane ); if( parent instanceof Window && parent.isDisplayable() )
if( window != null && window.isDisplayable() ) install( (Window) parent );
install( window );
// Install FlatLaf native window border, which must be done late, // Install FlatLaf native window border, which must be done late,
// when the native window is already created, because it needs access to the window. // when the native window is already created, because it needs access to the window.
@@ -174,9 +178,9 @@ public class FlatNativeWindowBorder
return; return;
// uninstall native window border // uninstall native window border
Window window = SwingUtilities.windowForComponent( rootPane ); Container parent = rootPane.getParent();
if( window != null ) if( parent instanceof Window )
uninstall( window ); uninstall( (Window) parent );
} }
private static void uninstall( Window window ) { private static void uninstall( Window window ) {

View File

@@ -22,7 +22,11 @@ import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.Insets; import java.awt.Insets;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
@@ -88,6 +92,7 @@ public class FlatOptionPaneUI
protected int messagePadding; protected int messagePadding;
protected int maxCharactersPerLine; protected int maxCharactersPerLine;
private int focusWidth; private int focusWidth;
private boolean sameSizeButtons;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatOptionPaneUI(); return new FlatOptionPaneUI();
@@ -101,6 +106,7 @@ public class FlatOptionPaneUI
messagePadding = UIManager.getInt( "OptionPane.messagePadding" ); messagePadding = UIManager.getInt( "OptionPane.messagePadding" );
maxCharactersPerLine = UIManager.getInt( "OptionPane.maxCharactersPerLine" ); maxCharactersPerLine = UIManager.getInt( "OptionPane.maxCharactersPerLine" );
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
sameSizeButtons = FlatUIUtils.getUIBoolean( "OptionPane.sameSizeButtons", true );
} }
@Override @Override
@@ -157,15 +163,40 @@ public class FlatOptionPaneUI
cons.insets.bottom = UIScale.scale( messagePadding ); cons.insets.bottom = UIScale.scale( messagePadding );
// disable line wrapping for HTML // disable line wrapping for HTML
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) ) if( msg != null &&
maxll = Integer.MAX_VALUE; !(msg instanceof Component) &&
!(msg instanceof Object[]) &&
!(msg instanceof Icon) )
{
msg = msg.toString();
if( BasicHTML.isHTMLString( (String) msg ) )
maxll = Integer.MAX_VALUE;
}
// fix right-to-left alignment if super.addMessageComponents() breaks longer lines
// into multiple labels and puts them into a box that aligns them to the left
if( msg instanceof Box ) {
Box box = (Box) msg;
if( "OptionPane.verticalBox".equals( box.getName() ) &&
box.getLayout() instanceof BoxLayout &&
((BoxLayout)box.getLayout()).getAxis() == BoxLayout.Y_AXIS )
{
box.addPropertyChangeListener( "componentOrientation", e -> {
float alignX = box.getComponentOrientation().isLeftToRight() ? 0 : 1;
for( Component c : box.getComponents() ) {
if( c instanceof JLabel && "OptionPane.label".equals( c.getName() ) )
((JLabel)c).setAlignmentX( alignX );
}
} );
}
}
super.addMessageComponents( container, cons, msg, maxll, internallyCreated ); super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
} }
private void updateChildPanels( Container c ) { private void updateChildPanels( Container c ) {
for( Component child : c.getComponents() ) { for( Component child : c.getComponents() ) {
if( child instanceof JPanel ) { if( child.getClass() == JPanel.class ) {
JPanel panel = (JPanel)child; JPanel panel = (JPanel)child;
// make sub-panel non-opaque for OptionPane.background // make sub-panel non-opaque for OptionPane.background
@@ -177,9 +208,8 @@ public class FlatOptionPaneUI
panel.setBorder( new NonUIResourceBorder( border ) ); panel.setBorder( new NonUIResourceBorder( border ) );
} }
if( child instanceof Container ) { if( child instanceof Container )
updateChildPanels( (Container) child ); updateChildPanels( (Container) child );
}
} }
} }
@@ -197,6 +227,11 @@ public class FlatOptionPaneUI
return null; return null;
} }
@Override
protected boolean getSizeButtonsToSameWidth() {
return sameSizeButtons;
}
//---- class NonUIResourceBorder ------------------------------------------ //---- class NonUIResourceBorder ------------------------------------------
private static class NonUIResourceBorder private static class NonUIResourceBorder

View File

@@ -16,30 +16,31 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Insets;
import java.awt.Shape;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent; import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Caret; import javax.swing.text.Element;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils; import javax.swing.text.PasswordView;
import javax.swing.text.View;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
* *
* <!-- BasicPasswordFieldUI --> * <!-- BasicTextFieldUI -->
* *
* @uiDefault PasswordField.font Font * @uiDefault PasswordField.font Font
* @uiDefault PasswordField.background Color * @uiDefault PasswordField.background Color
@@ -52,74 +53,66 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground) * @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault PasswordField.border Border * @uiDefault PasswordField.border Border
* @uiDefault PasswordField.margin Insets * @uiDefault PasswordField.margin Insets
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds * @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
* *
* <!-- FlatPasswordFieldUI --> * <!-- FlatTextFieldUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault PasswordField.placeholderForeground Color * @uiDefault PasswordField.placeholderForeground Color
* @uiDefault PasswordField.focusedBackground Color optional * @uiDefault PasswordField.focusedBackground Color optional
* @uiDefault PasswordField.showCapsLock boolean
* @uiDefault PasswordField.capsLockIcon Icon
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean * @uiDefault TextComponent.selectAllOnMouseClick boolean
* *
* <!-- FlatPasswordFieldUI -->
*
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.showCapsLock boolean
* @uiDefault PasswordField.capsLockIcon Icon
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatPasswordFieldUI public class FlatPasswordFieldUI
extends BasicPasswordFieldUI extends FlatTextFieldUI
{ {
protected int minimumWidth;
protected boolean isIntelliJTheme;
protected Color placeholderForeground;
protected Color focusedBackground;
protected boolean showCapsLock; protected boolean showCapsLock;
protected Icon capsLockIcon; protected Icon capsLockIcon;
private FocusListener focusListener;
private KeyListener capsLockListener; private KeyListener capsLockListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI(); return new FlatPasswordFieldUI();
} }
@Override
protected String getPropertyPrefix() {
return "PasswordField";
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
String prefix = getPropertyPrefix(); String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); Character echoChar = (Character) UIManager.get( prefix + ".echoChar" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); if( echoChar != null )
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); LookAndFeel.installProperty( getComponent(), "echoChar", echoChar );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" ); showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" ); capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
LookAndFeel.installProperty( getComponent(), "opaque", false );
MigLayoutVisualPadding.install( getComponent() );
} }
@Override @Override
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
placeholderForeground = null;
focusedBackground = null;
capsLockIcon = null; capsLockIcon = null;
MigLayoutVisualPadding.uninstall( getComponent() );
} }
@Override @Override
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
// necessary to update focus border and background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
// update caps lock indicator // update caps lock indicator
capsLockListener = new KeyAdapter() { capsLockListener = new KeyAdapter() {
@Override @Override
@@ -131,12 +124,13 @@ public class FlatPasswordFieldUI
repaint( e ); repaint( e );
} }
private void repaint( KeyEvent e ) { private void repaint( KeyEvent e ) {
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) {
e.getComponent().repaint(); e.getComponent().repaint();
scrollCaretToVisible();
}
} }
}; };
getComponent().addFocusListener( focusListener );
getComponent().addKeyListener( capsLockListener ); getComponent().addKeyListener( capsLockListener );
} }
@@ -144,59 +138,74 @@ public class FlatPasswordFieldUI
protected void uninstallListeners() { protected void uninstallListeners() {
super.uninstallListeners(); super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
getComponent().removeKeyListener( capsLockListener ); getComponent().removeKeyListener( capsLockListener );
focusListener = null;
capsLockListener = null; capsLockListener = null;
} }
@Override @Override
protected Caret createCaret() { protected void installKeyboardActions() {
return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ), super.installKeyboardActions();
UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) );
// map "select-word" action (double-click) to "select-line" action
ActionMap map = SwingUtilities.getUIActionMap( getComponent() );
if( map != null && map.get( DefaultEditorKit.selectWordAction ) != null ) {
Action selectLineAction = map.get( DefaultEditorKit.selectLineAction );
if( selectLineAction != null )
map.put( DefaultEditorKit.selectWordAction, selectLineAction );
}
} }
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { public View create( Element elem ) {
super.propertyChange( e ); return new PasswordView( elem );
FlatTextFieldUI.propertyChange( getComponent(), e );
} }
@Override @Override
protected void paintSafely( Graphics g ) { protected void paintSafely( Graphics g ) {
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); // safe and restore clipping area because super.paintSafely() modifies it
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground ); // and the caps lock icon would be truncated
paintCapsLock( g ); Shape oldClip = g.getClip();
super.paintSafely( g );
g.setClip( oldClip );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) ); paintCapsLock( g );
} }
protected void paintCapsLock( Graphics g ) { protected void paintCapsLock( Graphics g ) {
if( !showCapsLock ) if( !isCapsLockVisible() )
return; return;
JTextComponent c = getComponent(); JTextComponent c = getComponent();
if( !FlatUIUtils.isPermanentFocusOwner( c ) ||
!Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK ) )
return;
int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2; int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
int x = c.getWidth() - capsLockIcon.getIconWidth() - y; int x = c.getComponentOrientation().isLeftToRight()
? c.getWidth() - capsLockIcon.getIconWidth() - y
: y;
capsLockIcon.paintIcon( c, g, x, y ); capsLockIcon.paintIcon( c, g, x, y );
} }
@Override /**
protected void paintBackground( Graphics g ) { * @since 1.4
// background is painted elsewhere */
protected boolean isCapsLockVisible() {
if( !showCapsLock )
return false;
JTextComponent c = getComponent();
return FlatUIUtils.isPermanentFocusOwner( c ) &&
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
} }
/**
* @since 1.4
*/
@Override @Override
public Dimension getPreferredSize( JComponent c ) { protected Insets getPadding() {
return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth ); Insets padding = super.getPadding();
} if( !isCapsLockVisible() )
return padding;
@Override boolean ltr = getComponent().getComponentOrientation().isLeftToRight();
public Dimension getMinimumSize( JComponent c ) { int iconWidth = capsLockIcon.getIconWidth();
return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return FlatUIUtils.addInsets( padding, new Insets( 0, ltr ? 0 : iconWidth, 0, ltr ? iconWidth : 0 ) );
} }
} }

View File

@@ -44,6 +44,7 @@ import javax.swing.Popup;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer; import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
@@ -120,6 +121,10 @@ public class FlatPopupFactory
popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() ) popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() )
return popup; return popup;
// avoid endless loop (should newer happen; PopupFactory cache size is 5)
if( ++count > 10 )
return popup;
// remove contents component from popup window // remove contents component from popup window
if( popupWindow instanceof JWindow ) if( popupWindow instanceof JWindow )
((JWindow)popupWindow).getContentPane().removeAll(); ((JWindow)popupWindow).getContentPane().removeAll();
@@ -127,10 +132,6 @@ public class FlatPopupFactory
// dispose unused popup // dispose unused popup
// (do not invoke popup.hide() because this would cache the popup window) // (do not invoke popup.hide() because this would cache the popup window)
popupWindow.dispose(); popupWindow.dispose();
// avoid endless loop (should newer happen; PopupFactory cache size is 5)
if( ++count > 10 )
return popup;
} }
} }
@@ -260,13 +261,7 @@ public class FlatPopupFactory
} }
private boolean wasInvokedFromToolTipManager() { private boolean wasInvokedFromToolTipManager() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
for( StackTraceElement stackTraceElement : stackTrace ) {
if( "javax.swing.ToolTipManager".equals( stackTraceElement.getClassName() ) &&
"showTipWindow".equals( stackTraceElement.getMethodName() ) )
return true;
}
return false;
} }
//---- class NonFlashingPopup --------------------------------------------- //---- class NonFlashingPopup ---------------------------------------------
@@ -494,6 +489,9 @@ public class FlatPopupFactory
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane(); JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 ); layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
moveMediumWeightDropShadow();
resizeMediumWeightDropShadow();
mediumPanelListener = new ComponentListener() { mediumPanelListener = new ComponentListener() {
@Override @Override
public void componentShown( ComponentEvent e ) { public void componentShown( ComponentEvent e ) {
@@ -509,17 +507,12 @@ public class FlatPopupFactory
@Override @Override
public void componentMoved( ComponentEvent e ) { public void componentMoved( ComponentEvent e ) {
if( dropShadowPanel != null && mediumWeightPanel != null ) { moveMediumWeightDropShadow();
Point location = mediumWeightPanel.getLocation();
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 ) {
if( dropShadowPanel != null ) resizeMediumWeightDropShadow();
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
} }
}; };
mediumWeightPanel.addComponentListener( mediumPanelListener ); mediumWeightPanel.addComponentListener( mediumPanelListener );
@@ -535,5 +528,18 @@ public class FlatPopupFactory
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height ); parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
} }
} }
private void moveMediumWeightDropShadow() {
if( dropShadowPanel != null && mediumWeightPanel != null ) {
Point location = mediumWeightPanel.getLocation();
Insets insets = dropShadowPanel.getInsets();
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
}
}
private void resizeMediumWeightDropShadow() {
if( dropShadowPanel != null && mediumWeightPanel != null )
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
}
} }
} }

View File

@@ -24,8 +24,8 @@ import javax.swing.plaf.ComponentUI;
* *
* <!-- BasicSeparatorUI --> * <!-- BasicSeparatorUI -->
* *
* @uiDefault PopupMenuSeparator.background Color unused * @uiDefault Separator.background Color unused
* @uiDefault PopupMenuSeparator.foreground Color * @uiDefault Separator.foreground Color
* *
* <!-- FlatSeparatorUI --> * <!-- FlatSeparatorUI -->
* *

View File

@@ -27,9 +27,11 @@ import java.awt.Insets;
import java.awt.LayoutManager; import java.awt.LayoutManager;
import java.awt.LayoutManager2; import java.awt.LayoutManager2;
import java.awt.Window; import java.awt.Window;
import java.awt.event.HierarchyEvent; import java.awt.event.ComponentAdapter;
import java.awt.event.HierarchyListener; import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
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.JDialog; import javax.swing.JDialog;
@@ -38,6 +40,7 @@ import javax.swing.JLayeredPane;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JRootPane; import javax.swing.JRootPane;
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.plaf.BorderUIResource; import javax.swing.plaf.BorderUIResource;
@@ -81,7 +84,8 @@ public class FlatRootPaneUI
private Object nativeWindowBorderData; private Object nativeWindowBorderData;
private LayoutManager oldLayout; private LayoutManager oldLayout;
private HierarchyListener hierarchyListener; private PropertyChangeListener ancestorListener;
private ComponentListener componentListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatRootPaneUI(); return new FlatRootPaneUI();
@@ -149,16 +153,32 @@ public class FlatRootPaneUI
// This is very disturbing in dark themes, but hard to notice in light themes. // This is very disturbing in dark themes, but hard to notice in light themes.
// Seems to be a rounding issue when Swing adds dirty region of window // Seems to be a rounding issue when Swing adds dirty region of window
// using RepaintManager.nativeAddDirtyRegion(). // using RepaintManager.nativeAddDirtyRegion().
hierarchyListener = e -> { //
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && // Note: Not using a HierarchyListener here, which would be much easier,
rootPane.getParent() instanceof Window ) // because this causes problems with mouse clicks in heavy-weight popups.
{ // Instead, add a listener to the root pane that waits until it is added
// add whole root pane to dirty regions when window is initially shown // to a window, then add a component listener to the window.
rootPane.getParent().repaint( rootPane.getX(), rootPane.getY(), // See: https://github.com/JFormDesigner/FlatLaf/issues/371
rootPane.getWidth(), rootPane.getHeight() ); ancestorListener = e -> {
Object oldValue = e.getOldValue();
Object newValue = e.getNewValue();
if( newValue instanceof Window ) {
if( componentListener == null ) {
componentListener = new ComponentAdapter() {
@Override
public void componentShown( ComponentEvent e ) {
// add whole root pane to dirty regions when window is initially shown
root.getParent().repaint( root.getX(), root.getY(), root.getWidth(), root.getHeight() );
}
};
}
((Window)newValue).addComponentListener( componentListener );
} else if( newValue == null && oldValue instanceof Window ) {
if( componentListener != null )
((Window)oldValue).removeComponentListener( componentListener );
} }
}; };
root.addHierarchyListener( hierarchyListener ); root.addPropertyChangeListener( "ancestor", ancestorListener );
} }
} }
@@ -167,8 +187,14 @@ public class FlatRootPaneUI
super.uninstallListeners( root ); super.uninstallListeners( root );
if( SystemInfo.isJava_9_orLater ) { if( SystemInfo.isJava_9_orLater ) {
root.removeHierarchyListener( hierarchyListener ); if( componentListener != null ) {
hierarchyListener = null; Window window = SwingUtilities.windowForComponent( root );
if( window != null )
window.removeComponentListener( componentListener );
componentListener = null;
}
root.removePropertyChangeListener( "ancestor", ancestorListener );
ancestorListener = null;
} }
} }
@@ -342,7 +368,7 @@ public class FlatRootPaneUI
? getSizeFunc.apply( rootPane.getContentPane() ) ? getSizeFunc.apply( rootPane.getContentPane() )
: rootPane.getSize(); : rootPane.getSize();
int width = Math.max( titlePaneSize.width, contentSize.width ); int width = contentSize.width; // title pane width is not considered here
int height = titlePaneSize.height + contentSize.height; int height = titlePaneSize.height + contentSize.height;
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) { if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
JMenuBar menuBar = rootPane.getJMenuBar(); JMenuBar menuBar = rootPane.getJMenuBar();

View File

@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics; import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Shape; import java.awt.Shape;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
@@ -176,9 +178,27 @@ public class FlatSliderUI
if( slider.getOrientation() == JSlider.VERTICAL ) if( slider.getOrientation() == JSlider.VERTICAL )
return -1; return -1;
// use default font (instead of slider font) because the slider font size
// may be different to label font size, but we want align the track/thumb with labels
Font font = UIManager.getFont( "defaultFont" );
if( font == null )
font = slider.getFont();
FontMetrics fm = slider.getFontMetrics( font );
// calculate track y coordinate and height
// (not using field trackRect here because slider size may be [0,0]
// and field trackRect may have invalid values in this case)
Insets insets = slider.getInsets();
int thumbHeight = getThumbSize().height;
int contentHeight = height - insets.top - insets.bottom - focusInsets.top - focusInsets.bottom;
int centerSpacing = thumbHeight
+ (slider.getPaintTicks() ? getTickLength() : 0)
+ (slider.getPaintLabels() ? getHeightOfTallestLabel() : 0);
int trackY = insets.top + focusInsets.top + (contentHeight - centerSpacing - 1) / 2;
int trackHeight = thumbHeight;
// compute a baseline so that the track is vertically centered // compute a baseline so that the track is vertically centered
FontMetrics fm = slider.getFontMetrics( slider.getFont() ); return trackY + Math.round( (trackHeight - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
return trackRect.y + Math.round( (trackRect.height - fm.getHeight()) / 2f ) + fm.getAscent() - 1;
} }
@Override @Override

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
@@ -123,9 +124,6 @@ public class FlatSpinnerUI
buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" ); buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" );
padding = UIManager.getInsets( "Spinner.padding" ); padding = UIManager.getInsets( "Spinner.padding" );
// scale
padding = scale( padding );
MigLayoutVisualPadding.install( spinner ); MigLayoutVisualPadding.install( spinner );
} }
@@ -177,14 +175,7 @@ public class FlatSpinnerUI
@Override @Override
protected JComponent createEditor() { protected JComponent createEditor() {
JComponent editor = super.createEditor(); JComponent editor = super.createEditor();
configureEditor( editor );
// explicitly make non-opaque
editor.setOpaque( false );
JTextField textField = getEditorTextField( editor );
if( textField != null )
textField.setOpaque( false );
updateEditorColors();
return editor; return editor;
} }
@@ -192,8 +183,21 @@ public class FlatSpinnerUI
protected void replaceEditor( JComponent oldEditor, JComponent newEditor ) { protected void replaceEditor( JComponent oldEditor, JComponent newEditor ) {
super.replaceEditor( oldEditor, newEditor ); super.replaceEditor( oldEditor, newEditor );
configureEditor( newEditor );
removeEditorFocusListener( oldEditor ); removeEditorFocusListener( oldEditor );
addEditorFocusListener( newEditor ); addEditorFocusListener( newEditor );
}
/** @since 1.6 */
protected void configureEditor( JComponent editor ) {
// explicitly make non-opaque
editor.setOpaque( false );
JTextField textField = getEditorTextField( editor );
if( textField != null )
textField.setOpaque( false );
updateEditorPadding();
updateEditorColors(); updateEditorColors();
} }
@@ -209,6 +213,12 @@ public class FlatSpinnerUI
textField.removeFocusListener( getHandler() ); textField.removeFocusListener( getHandler() );
} }
private void updateEditorPadding() {
JTextField textField = getEditorTextField( spinner.getEditor() );
if( textField != null )
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, padding );
}
private void updateEditorColors() { private void updateEditorColors() {
JTextField textField = getEditorTextField( spinner.getEditor() ); JTextField textField = getEditorTextField( spinner.getEditor() );
if( textField != null ) { if( textField != null ) {
@@ -373,6 +383,7 @@ public class FlatSpinnerUI
@Override @Override
public Dimension preferredLayoutSize( Container parent ) { public Dimension preferredLayoutSize( Container parent ) {
Insets insets = parent.getInsets(); Insets insets = parent.getInsets();
Insets padding = scale( FlatSpinnerUI.this.padding );
Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 ); Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 );
// the arrows width is the same as the inner height so that the arrows area is square // the arrows width is the same as the inner height so that the arrows area is square
@@ -397,15 +408,19 @@ public class FlatSpinnerUI
if( nextButton == null && previousButton == null ) { if( nextButton == null && previousButton == null ) {
if( editor != null ) if( editor != null )
editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) ); editor.setBounds( r );
return; return;
} }
Rectangle editorRect = new Rectangle( r ); Rectangle editorRect = new Rectangle( r );
Rectangle buttonsRect = new Rectangle( r ); Rectangle buttonsRect = new Rectangle( r );
// limit buttons width to height of a raw spinner (without insets)
FontMetrics fm = spinner.getFontMetrics( spinner.getFont() );
int maxButtonWidth = fm.getHeight() + scale( padding.top ) + scale( padding.bottom );
// make button area square (if spinner has preferred height) // make button area square (if spinner has preferred height)
int buttonsWidth = parent.getPreferredSize().height - insets.top - insets.bottom; int buttonsWidth = Math.min( parent.getPreferredSize().height - insets.top - insets.bottom, maxButtonWidth );
buttonsRect.width = buttonsWidth; buttonsRect.width = buttonsWidth;
if( parent.getComponentOrientation().isLeftToRight() ) { if( parent.getComponentOrientation().isLeftToRight() ) {
@@ -417,7 +432,7 @@ public class FlatSpinnerUI
} }
if( editor != null ) if( editor != null )
editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) ); editor.setBounds( editorRect );
int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up
if( nextButton != null ) if( nextButton != null )

View File

@@ -842,6 +842,17 @@ public class FlatTabbedPaneUI
paintTabArea( g, tabPlacement, selectedIndex ); paintTabArea( g, tabPlacement, selectedIndex );
} }
@Override
protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex ) {
// need to set rendering hints here too because this method is also invoked
// from BasicTabbedPaneUI.ScrollableTabPanel.paintComponent()
Object[] oldHints = FlatUIUtils.setRenderingHints( g );
super.paintTabArea( g, tabPlacement, selectedIndex );
FlatUIUtils.resetRenderingHints( g, oldHints );
}
@Override @Override
protected void paintTab( Graphics g, int tabPlacement, Rectangle[] rects, protected void paintTab( Graphics g, int tabPlacement, Rectangle[] rects,
int tabIndex, Rectangle iconRect, Rectangle textRect ) int tabIndex, Rectangle iconRect, Rectangle textRect )

View File

@@ -24,6 +24,7 @@ import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import javax.swing.JScrollBar; import javax.swing.JScrollBar;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
@@ -44,6 +45,7 @@ public class FlatTableHeaderBorder
{ {
protected Color separatorColor = UIManager.getColor( "TableHeader.separatorColor" ); protected Color separatorColor = UIManager.getColor( "TableHeader.separatorColor" );
protected Color bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" ); protected Color bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
/** @since 1.6 */ protected boolean showTrailingVerticalLine = UIManager.getBoolean( "TableHeader.showTrailingVerticalLine" );
public FlatTableHeaderBorder() { public FlatTableHeaderBorder() {
super( UIManager.getInsets( "TableHeader.cellMargins" ) ); super( UIManager.getInsets( "TableHeader.cellMargins" ) );
@@ -108,12 +110,23 @@ public class FlatTableHeaderBorder
} }
protected boolean hideTrailingVerticalLine( JTableHeader header ) { protected boolean hideTrailingVerticalLine( JTableHeader header ) {
if( showTrailingVerticalLine )
return false;
// do not hide if table header is not a child of a scroll pane
Container viewport = header.getParent(); Container viewport = header.getParent();
Container viewportParent = (viewport != null) ? viewport.getParent() : null; Container viewportParent = (viewport != null) ? viewport.getParent() : null;
if( !(viewportParent instanceof JScrollPane) ) if( !(viewportParent instanceof JScrollPane) )
return true; return false;
JScrollBar vsb = ((JScrollPane)viewportParent).getVerticalScrollBar(); // do not hide if table header is not the column header of the scroll pane
JScrollPane scrollPane = (JScrollPane) viewportParent;
JViewport columnHeader = scrollPane.getColumnHeader();
if( viewport != columnHeader )
return false;
// hide if vertical scroll bar is not shown
JScrollBar vsb = scrollPane.getVerticalScrollBar();
if( vsb == null || !vsb.isVisible() ) if( vsb == null || !vsb.isVisible() )
return true; return true;

View File

@@ -18,10 +18,13 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Objects; import java.util.Objects;
import javax.swing.Icon; import javax.swing.Icon;
@@ -31,6 +34,7 @@ import javax.swing.JTable;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.event.MouseInputListener;
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.BasicTableHeaderUI; import javax.swing.plaf.basic.BasicTableHeaderUI;
@@ -58,6 +62,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TableHeader.cellMargins Insets * @uiDefault TableHeader.cellMargins Insets
* @uiDefault TableHeader.separatorColor Color * @uiDefault TableHeader.separatorColor Color
* @uiDefault TableHeader.bottomSeparatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color
* @uiDefault TableHeader.showTrailingVerticalLine boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -94,6 +99,17 @@ public class FlatTableHeaderUI
bottomSeparatorColor = null; bottomSeparatorColor = null;
} }
@Override
protected MouseInputListener createMouseInputListener() {
return new FlatMouseInputHandler();
}
// overridden and made public to allow usage in custom renderers
@Override
public int getRolloverColumn() {
return super.getRolloverColumn();
}
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
TableColumnModel columnModel = header.getColumnModel(); TableColumnModel columnModel = header.getColumnModel();
@@ -246,4 +262,54 @@ public class FlatTableHeaderUI
return (origBorder != null) ? origBorder.isBorderOpaque() : false; return (origBorder != null) ? origBorder.isBorderOpaque() : false;
} }
} }
//---- class FlatMouseInputHandler ----------------------------------------
/**
* @since 1.6
*/
protected class FlatMouseInputHandler
extends MouseInputHandler
{
Cursor oldCursor;
@Override
public void mouseMoved( MouseEvent e ) {
// restore old cursor, which is necessary because super.mouseMoved() swaps cursors
if( oldCursor != null ) {
header.setCursor( oldCursor );
oldCursor = null;
}
super.mouseMoved( e );
// if resizing last column is not possible, then Swing still shows a resize cursor,
// which can be confusing for the user --> change cursor to standard cursor
JTable table;
int column;
if( header.isEnabled() &&
(table = header.getTable()) != null &&
table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF &&
header.getCursor() == Cursor.getPredefinedCursor( Cursor.E_RESIZE_CURSOR ) &&
(column = header.columnAtPoint( e.getPoint() )) >= 0 &&
column == header.getColumnModel().getColumnCount() - 1 )
{
// mouse is in last column
Rectangle r = header.getHeaderRect( column );
r.grow( -3, 0 );
if( !r.contains( e.getX(), e.getY() ) ) {
// mouse is in left or right resize area of last column
boolean isResizeLastColumn = (e.getX() >= r.x + (r.width / 2));
if( !header.getComponentOrientation().isLeftToRight() )
isResizeLastColumn = !isResizeLastColumn;
if( isResizeLastColumn ) {
// resize is not possible --> change cursor to standard cursor
oldCursor = header.getCursor();
header.setCursor( Cursor.getDefaultCursor() );
}
}
}
}
}
} }

View File

@@ -25,6 +25,7 @@ import java.awt.Graphics2D;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JViewport; import javax.swing.JViewport;
@@ -34,6 +35,7 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTableUI; import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -69,6 +71,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Table.rowHeight int * @uiDefault Table.rowHeight int
* @uiDefault Table.showHorizontalLines boolean * @uiDefault Table.showHorizontalLines boolean
* @uiDefault Table.showVerticalLines boolean * @uiDefault Table.showVerticalLines boolean
* @uiDefault Table.showTrailingVerticalLine boolean
* @uiDefault Table.intercellSpacing Dimension * @uiDefault Table.intercellSpacing Dimension
* @uiDefault Table.selectionInactiveBackground Color * @uiDefault Table.selectionInactiveBackground Color
* @uiDefault Table.selectionInactiveForeground Color * @uiDefault Table.selectionInactiveForeground Color
@@ -90,6 +93,7 @@ public class FlatTableUI
{ {
protected boolean showHorizontalLines; protected boolean showHorizontalLines;
protected boolean showVerticalLines; protected boolean showVerticalLines;
/** @since 1.6 */ protected boolean showTrailingVerticalLine;
protected Dimension intercellSpacing; protected Dimension intercellSpacing;
protected Color selectionBackground; protected Color selectionBackground;
@@ -101,6 +105,8 @@ public class FlatTableUI
private boolean oldShowVerticalLines; private boolean oldShowVerticalLines;
private Dimension oldIntercellSpacing; private Dimension oldIntercellSpacing;
private PropertyChangeListener propertyChangeListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTableUI(); return new FlatTableUI();
} }
@@ -111,6 +117,7 @@ public class FlatTableUI
showHorizontalLines = UIManager.getBoolean( "Table.showHorizontalLines" ); showHorizontalLines = UIManager.getBoolean( "Table.showHorizontalLines" );
showVerticalLines = UIManager.getBoolean( "Table.showVerticalLines" ); showVerticalLines = UIManager.getBoolean( "Table.showVerticalLines" );
showTrailingVerticalLine = UIManager.getBoolean( "Table.showTrailingVerticalLine" );
intercellSpacing = UIManager.getDimension( "Table.intercellSpacing" ); intercellSpacing = UIManager.getDimension( "Table.intercellSpacing" );
selectionBackground = UIManager.getColor( "Table.selectionBackground" ); selectionBackground = UIManager.getColor( "Table.selectionBackground" );
@@ -159,6 +166,25 @@ public class FlatTableUI
table.setIntercellSpacing( oldIntercellSpacing ); table.setIntercellSpacing( oldIntercellSpacing );
} }
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = e -> {
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
toggleSelectionColors();
};
table.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
table.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
@Override @Override
protected FocusListener createFocusListener() { protected FocusListener createFocusListener() {
return new BasicTableUI.FocusHandler() { return new BasicTableUI.FocusHandler() {
@@ -240,7 +266,7 @@ public class FlatTableUI
if( isDragging && if( isDragging &&
SystemInfo.isJava_9_orLater && SystemInfo.isJava_9_orLater &&
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) && ((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
wasInvokedFromPaintDraggedArea() ) wasInvokedFromMethod( "paintDraggedArea" ) )
{ {
if( y1 == y2 ) { if( y1 == y2 ) {
// horizontal grid line // horizontal grid line
@@ -282,22 +308,8 @@ public class FlatTableUI
return wasInvokedFromMethod( "paintGrid" ); return wasInvokedFromMethod( "paintGrid" );
} }
private boolean wasInvokedFromPaintDraggedArea() {
return wasInvokedFromMethod( "paintDraggedArea" );
}
private boolean wasInvokedFromMethod( String methodName ) { private boolean wasInvokedFromMethod( String methodName ) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); return StackUtils.wasInvokedFrom( BasicTableUI.class.getName(), methodName, 8 );
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) {
String methodName2 = stackTrace[i].getMethodName();
if( "paintCell".equals( methodName2 ) )
return false;
if( methodName.equals( methodName2 ) )
return true;
}
}
return false;
} }
}; };
} }
@@ -306,6 +318,10 @@ public class FlatTableUI
} }
protected boolean hideLastVerticalLine() { protected boolean hideLastVerticalLine() {
if( showTrailingVerticalLine )
return false;
// do not hide if table is not a child of a scroll pane
Container viewport = SwingUtilities.getUnwrappedParent( table ); Container viewport = SwingUtilities.getUnwrappedParent( table );
Container viewportParent = (viewport != null) ? viewport.getParent() : null; Container viewportParent = (viewport != null) ? viewport.getParent() : null;
if( !(viewportParent instanceof JScrollPane) ) if( !(viewportParent instanceof JScrollPane) )

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -67,6 +68,8 @@ public class FlatTextAreaUI
protected Color inactiveBackground; protected Color inactiveBackground;
protected Color focusedBackground; protected Color focusedBackground;
private Insets defaultMargin;
private FocusListener focusListener; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
@@ -90,6 +93,8 @@ public class FlatTextAreaUI
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" ); disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" ); inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
focusedBackground = UIManager.getColor( "TextArea.focusedBackground" ); focusedBackground = UIManager.getColor( "TextArea.focusedBackground" );
defaultMargin = UIManager.getInsets( "TextArea.margin" );
} }
@Override @Override
@@ -170,7 +175,7 @@ public class FlatTextAreaUI
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 ) if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
return size; return size;
return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth ); return FlatEditorPaneUI.applyMinimumWidth( c, size, minimumWidth, defaultMargin );
} }
@Override @Override

View File

@@ -24,8 +24,10 @@ import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Objects;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
@@ -40,6 +42,7 @@ import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.JavaCompatibility; import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
@@ -78,6 +81,8 @@ public class FlatTextFieldUI
protected Color placeholderForeground; protected Color placeholderForeground;
protected Color focusedBackground; protected Color focusedBackground;
private Insets defaultMargin;
private FocusListener focusListener; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
@@ -94,6 +99,8 @@ public class FlatTextFieldUI
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" );
LookAndFeel.installProperty( getComponent(), "opaque", false ); LookAndFeel.installProperty( getComponent(), "opaque", false );
MigLayoutVisualPadding.install( getComponent() ); MigLayoutVisualPadding.install( getComponent() );
@@ -142,6 +149,7 @@ public class FlatTextFieldUI
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case FlatClientProperties.PLACEHOLDER_TEXT: case FlatClientProperties.PLACEHOLDER_TEXT:
case FlatClientProperties.COMPONENT_ROUND_RECT: case FlatClientProperties.COMPONENT_ROUND_RECT:
case FlatClientProperties.TEXT_FIELD_PADDING:
c.repaint(); c.repaint();
break; break;
@@ -154,7 +162,7 @@ public class FlatTextFieldUI
@Override @Override
protected void paintSafely( Graphics g ) { protected void paintSafely( Graphics g ) {
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
paintPlaceholder( g, getComponent(), placeholderForeground ); paintPlaceholder( g );
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) ); super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
} }
@@ -210,7 +218,9 @@ public class FlatTextFieldUI
return background; return background;
} }
static void paintPlaceholder( Graphics g, JTextComponent c, Color placeholderForeground ) { protected void paintPlaceholder( Graphics g ) {
JTextComponent c = getComponent();
// check whether text component is empty // check whether text component is empty
if( c.getDocument().getLength() > 0 ) if( c.getDocument().getLength() > 0 )
return; return;
@@ -225,15 +235,14 @@ public class FlatTextFieldUI
return; return;
// compute placeholder location // compute placeholder location
Insets insets = c.getInsets(); Rectangle r = getVisibleEditorRect();
FontMetrics fm = c.getFontMetrics( c.getFont() ); FontMetrics fm = c.getFontMetrics( c.getFont() );
int x = insets.left; String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, (String) placeholder, r.width );
int y = insets.top + fm.getAscent() + ((c.getHeight() - insets.top - insets.bottom - fm.getHeight()) / 2); int x = r.x + (c.getComponentOrientation().isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
// paint placeholder // paint placeholder
g.setColor( placeholderForeground ); g.setColor( placeholderForeground );
String clippedPlaceholder = JavaCompatibility.getClippedString( jc, fm,
(String) placeholder, c.getWidth() - insets.left - insets.right );
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y ); FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
} }
@@ -247,11 +256,15 @@ public class FlatTextFieldUI
return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
} }
static Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) { private Dimension applyMinimumWidth( JComponent c, Dimension size, int minimumWidth ) {
// do not apply minimum width if JTextField.columns is set // do not apply minimum width if JTextField.columns is set
if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 ) if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 )
return size; return size;
// do not apply minimum width if JTextComponent.margin is set
if( !hasDefaultMargins( c, defaultMargin ) )
return size;
// do not apply minimum width if used in combobox or spinner // do not apply minimum width if used in combobox or spinner
Container parent = c.getParent(); Container parent = c.getParent();
if( parent instanceof JComboBox || if( parent instanceof JComboBox ||
@@ -264,4 +277,41 @@ public class FlatTextFieldUI
size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) ); size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) );
return size; return size;
} }
static boolean hasDefaultMargins( JComponent c, Insets defaultMargin ) {
Insets margin = ((JTextComponent)c).getMargin();
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
}
@Override
protected Rectangle getVisibleEditorRect() {
Rectangle r = super.getVisibleEditorRect();
if( r != null ) {
// remove padding
Insets padding = getPadding();
if( padding != null ) {
r = FlatUIUtils.subtractInsets( r, padding );
r.width = Math.max( r.width, 0 );
r.height = Math.max( r.height, 0 );
}
}
return r;
}
/**
* @since 1.4
*/
protected Insets getPadding() {
Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING );
return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null;
}
/**
* @since 1.4
*/
protected void scrollCaretToVisible() {
Caret caret = getComponent().getCaret();
if( caret instanceof FlatCaret )
((FlatCaret)caret).scrollCaretToVisible();
}
} }

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -62,6 +63,8 @@ public class FlatTextPaneUI
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground; protected Color focusedBackground;
private Insets defaultMargin;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener; private FocusListener focusListener;
@@ -78,6 +81,8 @@ public class FlatTextPaneUI
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" );
// use component font and foreground for HTML text // use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true );
@@ -117,12 +122,12 @@ public class FlatTextPaneUI
@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, defaultMargin );
} }
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth, defaultMargin );
} }
@Override @Override

View File

@@ -508,7 +508,7 @@ public class FlatTitlePane
protected void menuBarLayouted() { protected void menuBarLayouted() {
updateNativeTitleBarHeightAndHitTestSpotsLater(); updateNativeTitleBarHeightAndHitTestSpotsLater();
revalidate(); doLayout();
} }
/*debug /*debug

View File

@@ -22,6 +22,7 @@ import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener; import java.awt.event.ContainerListener;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolBarUI; import javax.swing.plaf.basic.BasicToolBarUI;
@@ -41,15 +42,47 @@ import javax.swing.plaf.basic.BasicToolBarUI;
* @uiDefault ToolBar.floatingForeground Color * @uiDefault ToolBar.floatingForeground Color
* @uiDefault ToolBar.isRollover boolean * @uiDefault ToolBar.isRollover boolean
* *
* <!-- FlatToolBarUI -->
*
* @uiDefault ToolBar.focusableButtons boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatToolBarUI public class FlatToolBarUI
extends BasicToolBarUI extends BasicToolBarUI
{ {
/** @since 1.4 */
protected boolean focusableButtons;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatToolBarUI(); return new FlatToolBarUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
// disable focusable state of buttons (when switching from another Laf)
if( !focusableButtons )
setButtonsFocusable( false );
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
// re-enable focusable state of buttons (when switching to another Laf)
if( !focusableButtons )
setButtonsFocusable( true );
}
@Override
protected void installDefaults() {
super.installDefaults();
focusableButtons = UIManager.getBoolean( "ToolBar.focusableButtons" );
}
@Override @Override
protected ContainerListener createToolBarContListener() { protected ContainerListener createToolBarContListener() {
return new ToolBarContListener() { return new ToolBarContListener() {
@@ -57,22 +90,36 @@ public class FlatToolBarUI
public void componentAdded( ContainerEvent e ) { public void componentAdded( ContainerEvent e ) {
super.componentAdded( e ); super.componentAdded( e );
Component c = e.getChild(); if( !focusableButtons ) {
if( c instanceof AbstractButton ) Component c = e.getChild();
c.setFocusable( false ); if( c instanceof AbstractButton )
c.setFocusable( false );
}
} }
@Override @Override
public void componentRemoved( ContainerEvent e ) { public void componentRemoved( ContainerEvent e ) {
super.componentRemoved( e ); super.componentRemoved( e );
Component c = e.getChild(); if( !focusableButtons ) {
if( c instanceof AbstractButton ) Component c = e.getChild();
c.setFocusable( true ); if( c instanceof AbstractButton )
c.setFocusable( true );
}
} }
}; };
} }
/**
* @since 1.4
*/
protected void setButtonsFocusable( boolean focusable ) {
for( Component c : toolBar.getComponents() ) {
if( c instanceof AbstractButton )
c.setFocusable( focusable );
}
}
// disable rollover border // disable rollover border
@Override protected void setBorderToRollover( Component c ) {} @Override protected void setBorderToRollover( Component c ) {}
@Override protected void setBorderToNonRollover( Component c ) {} @Override protected void setBorderToNonRollover( Component c ) {}

View File

@@ -230,6 +230,26 @@ public class FlatTreeUI
tree.repaint( 0, r.y, tree.getWidth(), r.height ); tree.repaint( 0, r.y, tree.getWidth(), r.height );
} }
@Override
public Rectangle getPathBounds( JTree tree, TreePath path ) {
Rectangle bounds = super.getPathBounds( tree, path );
// If this method was invoked from JTree.getPathForLocation(int x, int y) to check whether
// the location is within tree node bounds, then return the bounds of a wide node.
// This changes the behavior of JTree.getPathForLocation(int x, int y) and
// JTree.getRowForLocation(int x, int y), which now return the path/row even
// if [x,y] is in the wide row area outside of the actual tree node.
if( bounds != null &&
isWideSelection() &&
UIManager.getBoolean( "FlatLaf.experimental.tree.widePathForLocation" ) &&
StackUtils.wasInvokedFrom( JTree.class.getName(), "getPathForLocation", 5 ) )
{
bounds.x = 0;
bounds.width = tree.getWidth();
}
return bounds;
}
/** /**
* Same as super.paintRow(), but supports wide selection and uses * Same as super.paintRow(), but supports wide selection and uses
* inactive selection background/foreground if tree is not focused. * inactive selection background/foreground if tree is not focused.
@@ -243,9 +263,19 @@ public class FlatTreeUI
boolean isDropRow = isDropRow( row ); boolean isDropRow = isDropRow( row );
boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection(); boolean needsSelectionPainting = (isSelected || isDropRow) && isPaintSelection();
// do not paint row if editing, except if selection needs painted // do not paint row if editing
if( isEditing && !needsSelectionPainting ) if( isEditing ) {
// paint wide selection
// (do not access cell renderer here to avoid side effect
// if renderer component is also used as editor component)
if( isSelected && isWideSelection() ) {
Color oldColor = g.getColor();
g.setColor( selectionInactiveBackground );
paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
g.setColor( oldColor );
}
return; return;
}
boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree ); boolean hasFocus = FlatUIUtils.isPermanentFocusOwner( tree );
boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow()); boolean cellHasFocus = hasFocus && (row == getLeadSelectionRow());
@@ -302,14 +332,7 @@ public class FlatTreeUI
if( isWideSelection() ) { if( isWideSelection() ) {
// wide selection // wide selection
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height ); paintWideSelection( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
// paint expand/collapse icon
// (was already painted before, but painted over with wide selection)
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
paintExpandControl( g, clipBounds, insets, bounds,
path, row, isExpanded, hasBeenExpanded, isLeaf );
}
} else { } else {
// non-wide selection // non-wide selection
paintCellBackground( g, rendererComponent, bounds ); paintCellBackground( g, rendererComponent, bounds );
@@ -333,8 +356,7 @@ public class FlatTreeUI
} }
// paint renderer // paint renderer
if( !isEditing ) rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
rendererPane.paintComponent( g, rendererComponent, tree, bounds.x, bounds.y, bounds.width, bounds.height, true );
// restore background selection color and border selection color // restore background selection color and border selection color
if( oldBackgroundSelectionColor != null ) if( oldBackgroundSelectionColor != null )
@@ -343,6 +365,19 @@ public class FlatTreeUI
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor ); ((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
} }
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
{
g.fillRect( 0, bounds.y, tree.getWidth(), bounds.height );
// paint expand/collapse icon
// (was already painted before, but painted over with wide selection)
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
paintExpandControl( g, clipBounds, insets, bounds,
path, row, isExpanded, hasBeenExpanded, isLeaf );
}
}
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) { private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
int xOffset = 0; int xOffset = 0;
int imageOffset = 0; int imageOffset = 0;

View File

@@ -69,6 +69,7 @@ public class FlatUIUtils
{ {
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" ); public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
private static boolean useSharedUIs = true;
private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>(); private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
public static Rectangle addInsets( Rectangle r, Insets insets ) { public static Rectangle addInsets( Rectangle r, Insets insets ) {
@@ -94,6 +95,11 @@ public class FlatUIUtils
} }
public static Insets addInsets( Insets insets1, Insets insets2 ) { public static Insets addInsets( Insets insets1, Insets insets2 ) {
if( insets1 == null )
return insets2;
if( insets2 == null )
return insets1;
return new Insets( return new Insets(
insets1.top + insets2.top, insets1.top + insets2.top,
insets1.left + insets2.left, insets1.left + insets2.left,
@@ -820,6 +826,27 @@ debug*/
return explicitlySet; return explicitlySet;
} }
/**
* Returns whether shared UI delegates are used.
*
* @since 1.6
*/
public static boolean isUseSharedUIs() {
return useSharedUIs;
}
/**
* Specifies whether shared UI delegates are used.
* This does not change already existing UI delegates.
*
* @since 1.6
*/
public static boolean setUseSharedUIs( boolean useSharedUIs ) {
boolean old = FlatUIUtils.useSharedUIs;
FlatUIUtils.useSharedUIs = useSharedUIs;
return old;
}
/** /**
* Creates a shared component UI for the given key and the current Laf. * Creates a shared component UI for the given key and the current Laf.
* Each Laf instance has its own shared component UI instance. * Each Laf instance has its own shared component UI instance.
@@ -828,6 +855,9 @@ debug*/
* may use multiple Laf instances at the same time. * may use multiple Laf instances at the same time.
*/ */
public static ComponentUI createSharedUI( Object key, Supplier<ComponentUI> newInstanceSupplier ) { public static ComponentUI createSharedUI( Object key, Supplier<ComponentUI> newInstanceSupplier ) {
if( !useSharedUIs )
return newInstanceSupplier.get();
return sharedUIinstances return sharedUIinstances
.computeIfAbsent( UIManager.getLookAndFeel(), k -> new IdentityHashMap<>() ) .computeIfAbsent( UIManager.getLookAndFeel(), k -> new IdentityHashMap<>() )
.computeIfAbsent( key, k -> newInstanceSupplier.get() ); .computeIfAbsent( key, k -> newInstanceSupplier.get() );

View File

@@ -181,8 +181,12 @@ public abstract class FlatWindowResizer
protected abstract boolean isWindowResizable(); protected abstract boolean isWindowResizable();
protected abstract Rectangle getWindowBounds(); protected abstract Rectangle getWindowBounds();
protected abstract void setWindowBounds( Rectangle r ); protected abstract void setWindowBounds( Rectangle r );
protected abstract boolean limitToParentBounds();
protected abstract Rectangle getParentBounds();
protected abstract boolean honorMinimumSizeOnResize(); protected abstract boolean honorMinimumSizeOnResize();
protected abstract boolean honorMaximumSizeOnResize();
protected abstract Dimension getWindowMinimumSize(); protected abstract Dimension getWindowMinimumSize();
protected abstract Dimension getWindowMaximumSize();
protected void beginResizing( int direction ) {} protected void beginResizing( int direction ) {}
protected void endResizing() {} protected void endResizing() {}
@@ -283,6 +287,16 @@ public abstract class FlatWindowResizer
} }
} }
@Override
protected boolean limitToParentBounds() {
return false;
}
@Override
protected Rectangle getParentBounds() {
return null;
}
@Override @Override
protected boolean honorMinimumSizeOnResize() { protected boolean honorMinimumSizeOnResize() {
return return
@@ -290,11 +304,21 @@ public abstract class FlatWindowResizer
(honorDialogMinimumSizeOnResize && window instanceof Dialog); (honorDialogMinimumSizeOnResize && window instanceof Dialog);
} }
@Override
protected boolean honorMaximumSizeOnResize() {
return false;
}
@Override @Override
protected Dimension getWindowMinimumSize() { protected Dimension getWindowMinimumSize() {
return window.getMinimumSize(); return window.getMinimumSize();
} }
@Override
protected Dimension getWindowMaximumSize() {
return window.getMaximumSize();
}
@Override @Override
boolean isDialog() { boolean isDialog() {
return window instanceof Dialog; return window instanceof Dialog;
@@ -354,16 +378,36 @@ public abstract class FlatWindowResizer
desktopManager.get().resizeFrame( getFrame(), r.x, r.y, r.width, r.height ); desktopManager.get().resizeFrame( getFrame(), r.x, r.y, r.width, r.height );
} }
@Override
protected boolean limitToParentBounds() {
return true;
}
@Override
protected Rectangle getParentBounds() {
return getFrame().getParent().getBounds();
}
@Override @Override
protected boolean honorMinimumSizeOnResize() { protected boolean honorMinimumSizeOnResize() {
return true; return true;
} }
@Override
protected boolean honorMaximumSizeOnResize() {
return true;
}
@Override @Override
protected Dimension getWindowMinimumSize() { protected Dimension getWindowMinimumSize() {
return getFrame().getMinimumSize(); return getFrame().getMinimumSize();
} }
@Override
protected Dimension getWindowMaximumSize() {
return getFrame().getMaximumSize();
}
@Override @Override
protected void beginResizing( int direction ) { protected void beginResizing( int direction ) {
desktopManager.get().beginResizingFrame( getFrame(), direction ); desktopManager.get().beginResizingFrame( getFrame(), direction );
@@ -521,7 +565,7 @@ debug*/
int xOnScreen = e.getXOnScreen(); int xOnScreen = e.getXOnScreen();
int yOnScreen = e.getYOnScreen(); int yOnScreen = e.getYOnScreen();
// Get current window bounds and compute new bounds based them. // Get current window bounds and compute new bounds based on them.
// This is necessary because window manager may alter window bounds while resizing. // This is necessary because window manager may alter window bounds while resizing.
// E.g. when having two monitors with different scale factors and resizing // E.g. when having two monitors with different scale factors and resizing
// a window on first screen to the second screen, then the window manager may // a window on first screen to the second screen, then the window manager may
@@ -535,41 +579,72 @@ debug*/
// top // top
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) { if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
newBounds.y = yOnScreen - dragTopOffset; newBounds.y = yOnScreen - dragTopOffset;
if( limitToParentBounds() && newBounds.y < 0 )
newBounds.y = 0;
newBounds.height += (oldBounds.y - newBounds.y); newBounds.height += (oldBounds.y - newBounds.y);
} }
// bottom // bottom
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y; newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
if( limitToParentBounds() ) {
int parentHeight = getParentBounds().height;
if( newBounds.y + newBounds.height > parentHeight )
newBounds.height = parentHeight - newBounds.y;
}
}
// left // left
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) { if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
newBounds.x = xOnScreen - dragLeftOffset; newBounds.x = xOnScreen - dragLeftOffset;
if( limitToParentBounds() && newBounds.x < 0 )
newBounds.x = 0;
newBounds.width += (oldBounds.x - newBounds.x); newBounds.width += (oldBounds.x - newBounds.x);
} }
// right // right
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x; newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
if( limitToParentBounds() ) {
int parentWidth = getParentBounds().width;
if( newBounds.x + newBounds.width > parentWidth )
newBounds.width = parentWidth - newBounds.x;
}
}
// apply minimum window size // apply minimum window size
Dimension minimumSize = honorMinimumSizeOnResize() ? getWindowMinimumSize() : null; Dimension minimumSize = honorMinimumSizeOnResize() ? getWindowMinimumSize() : null;
if( minimumSize == null ) if( minimumSize == null )
minimumSize = UIScale.scale( new Dimension( 150, 50 ) ); minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
if( newBounds.width < minimumSize.width ) { if( newBounds.width < minimumSize.width )
if( newBounds.x != oldBounds.x ) changeWidth( oldBounds, newBounds, minimumSize.width );
newBounds.x -= (minimumSize.width - newBounds.width); if( newBounds.height < minimumSize.height )
newBounds.width = minimumSize.width; changeHeight( oldBounds, newBounds, minimumSize.height );
}
if( newBounds.height < minimumSize.height ) { // apply maximum window size
if( newBounds.y != oldBounds.y ) if( honorMaximumSizeOnResize() ) {
newBounds.y -= (minimumSize.height - newBounds.height); Dimension maximumSize = getWindowMaximumSize();
newBounds.height = minimumSize.height; if( newBounds.width > maximumSize.width )
changeWidth( oldBounds, newBounds, maximumSize.width );
if( newBounds.height > maximumSize.height )
changeHeight( oldBounds, newBounds, maximumSize.height );
} }
// set window bounds // set window bounds
if( !newBounds.equals( oldBounds ) ) if( !newBounds.equals( oldBounds ) )
setWindowBounds( newBounds ); setWindowBounds( newBounds );
} }
private void changeWidth( Rectangle oldBounds, Rectangle newBounds, int width ) {
if( newBounds.x != oldBounds.x )
newBounds.x -= (width - newBounds.width);
newBounds.width = width;
}
private void changeHeight( Rectangle oldBounds, Rectangle newBounds, int height ) {
if( newBounds.y != oldBounds.y )
newBounds.y -= (height - newBounds.height);
newBounds.height = height;
}
} }
} }

View File

@@ -25,6 +25,8 @@ import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections; import java.util.Collections;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
@@ -94,6 +96,11 @@ class FlatWindowsNativeWindowBorder
// Java 9 and later does not have this problem. // Java 9 and later does not have this problem.
try { try {
System.loadLibrary( "jawt" ); System.loadLibrary( "jawt" );
} catch( UnsatisfiedLinkError ex ) {
// log error only if native library jawt.dll not already loaded
String message = ex.getMessage();
if( message == null || !message.contains( "already loaded in another classloader" ) )
LoggingFacade.INSTANCE.logSevere( null, ex );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex ); LoggingFacade.INSTANCE.logSevere( null, ex );
} }
@@ -156,11 +163,18 @@ class FlatWindowsNativeWindowBorder
return; return;
// install // install
WndProc wndProc = new WndProc( window ); try {
if( wndProc.hwnd == 0 ) WndProc wndProc = new WndProc( window );
return; if( wndProc.hwnd == 0 )
return;
windowsMap.put( window, wndProc ); windowsMap.put( window, wndProc );
} catch( UnsatisfiedLinkError ex ) {
// catch for the case that the operating system prevents execution of DLL
// (e.g. if DLLs in temp folder are restricted)
// --> continue application without custom decorations
LoggingFacade.INSTANCE.logSevere( null, ex );
}
} }
private void uninstall( Window window ) { private void uninstall( Window window ) {
@@ -289,6 +303,7 @@ class FlatWindowsNativeWindowBorder
//---- class WndProc ------------------------------------------------------ //---- class WndProc ------------------------------------------------------
private class WndProc private class WndProc
implements PropertyChangeListener
{ {
// WM_NCHITTEST mouse position codes // WM_NCHITTEST mouse position codes
private static final int private static final int
@@ -313,18 +328,36 @@ class FlatWindowsNativeWindowBorder
// remove the OS window title bar // remove the OS window title bar
updateFrame( hwnd, (window instanceof JFrame) ? ((JFrame)window).getExtendedState() : 0 ); updateFrame( hwnd, (window instanceof JFrame) ? ((JFrame)window).getExtendedState() : 0 );
// set window background (used when resizing window)
updateWindowBackground();
window.addPropertyChangeListener( "background", this );
} }
void uninstall() { void uninstall() {
window.removePropertyChangeListener( "background", this );
uninstallImpl( hwnd ); uninstallImpl( hwnd );
// cleanup // cleanup
window = null; window = null;
} }
@Override
public void propertyChange( PropertyChangeEvent e ) {
updateWindowBackground();
}
private void updateWindowBackground() {
Color bg = window.getBackground();
if( bg != null )
setWindowBackground( hwnd, bg.getRed(), bg.getGreen(), bg.getBlue() );
}
private native long installImpl( Window window ); private native long installImpl( Window window );
private native void uninstallImpl( long hwnd ); private native void uninstallImpl( long hwnd );
private native void updateFrame( long hwnd, int state ); private native void updateFrame( long hwnd, int state );
private native void setWindowBackground( long hwnd, int r, int g, int b );
private native void showWindow( long hwnd, int cmd ); private native void showWindow( long hwnd, int cmd );
// invoked from native code // invoked from native code

View File

@@ -70,9 +70,10 @@ public class JBRCustomDecorations
return null; return null;
// check whether root pane already has a parent, which is the case when switching LaF // check whether root pane already has a parent, which is the case when switching LaF
Window window = SwingUtilities.windowForComponent( rootPane ); Container parent = rootPane.getParent();
if( window != null ) { if( parent != null ) {
FlatNativeWindowBorder.install( window ); if( parent instanceof Window )
FlatNativeWindowBorder.install( (Window) parent );
return null; return null;
} }
@@ -110,9 +111,9 @@ public class JBRCustomDecorations
// since it is actually not possible to uninstall JBR decorations, // since it is actually not possible to uninstall JBR decorations,
// simply reduce titleBarHeight so that it is still possible to resize window // simply reduce titleBarHeight so that it is still possible to resize window
// and remove hitTestSpots // and remove hitTestSpots
Window window = SwingUtilities.windowForComponent( rootPane ); Container parent = rootPane.getParent();
if( window != null ) if( parent instanceof Window )
setHasCustomDecoration( window, false ); setHasCustomDecoration( (Window) parent, false );
} }
static boolean hasCustomDecoration( Window window ) { static boolean hasCustomDecoration( Window window ) {

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.util.function.BiPredicate;
/**
* @author Karl Tauber
*/
class StackUtils
{
private static final StackUtils INSTANCE = new StackUtilsImpl();
// hide from javadoc
StackUtils() {
}
/**
* Checks whether current method was invoked from the given class and method.
*/
public static boolean wasInvokedFrom( String className, String methodName, int limit ) {
return wasInvokedFrom( (c,m) -> c.equals( className ) && m.equals( methodName ), limit );
}
/**
* Checks whether current method was invoked from a class and method using the given predicate,
* which gets the class name of the stack frame as first parameter and the method name as second parameter.
*/
public static boolean wasInvokedFrom( BiPredicate<String, String> predicate, int limit ) {
return INSTANCE.wasInvokedFromImpl( predicate, limit );
}
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.util.function.BiPredicate;
/**
* @author Karl Tauber
*/
class StackUtilsImpl
extends StackUtils
{
@Override
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
int count = -2;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for( StackTraceElement stackTraceElement : stackTrace ) {
if( predicate.test( stackTraceElement.getClassName(), stackTraceElement.getMethodName() ) )
return true;
count++;
if( limit > 0 && count > limit )
return false;
}
return false;
}
}

View File

@@ -26,13 +26,16 @@ import java.awt.Color;
public class ColorFunctions public class ColorFunctions
{ {
public static Color applyFunctions( Color color, ColorFunction... functions ) { public static Color applyFunctions( Color color, ColorFunction... functions ) {
// convert RGB to HSL
float[] hsl = HSLColor.fromRGB( color ); float[] hsl = HSLColor.fromRGB( color );
float alpha = color.getAlpha() / 255f; float alpha = color.getAlpha() / 255f;
float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 }; float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 };
// apply color functions
for( ColorFunction function : functions ) for( ColorFunction function : functions )
function.apply( hsla ); function.apply( hsla );
// convert HSL to RGB
return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 ); return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
} }
@@ -145,7 +148,46 @@ public class ColorFunctions
} }
} }
//---- class HSLIncreaseDecrease ------------------------------------------ //---- class HSLChange ----------------------------------------------------
/**
* Set the hue, saturation, luminance or alpha of a color.
*
* @since 1.6
*/
public static class HSLChange
implements ColorFunction
{
public final int hslIndex;
public final float value;
public HSLChange( int hslIndex, float value ) {
this.hslIndex = hslIndex;
this.value = value;
}
@Override
public void apply( float[] hsla ) {
hsla[hslIndex] = (hslIndex == 0)
? value % 360
: clamp( value );
}
@Override
public String toString() {
String name;
switch( hslIndex ) {
case 0: name = "changeHue"; break;
case 1: name = "changeSaturation"; break;
case 2: name = "changeLightness"; break;
case 3: name = "changeAlpha"; break;
default: throw new IllegalArgumentException();
}
return String.format( "%s(%.0f%s)", name, value, (hslIndex == 0 ? "" : "%") );
}
}
//---- class Fade ---------------------------------------------------------
/** /**
* Set the alpha of a color. * Set the alpha of a color.
@@ -169,4 +211,42 @@ public class ColorFunctions
return String.format( "fade(%.0f%%)", amount ); return String.format( "fade(%.0f%%)", amount );
} }
} }
//---- class Mix ----------------------------------------------------------
/**
* Mix two colors.
*
* @since 1.6
*/
public static class Mix
implements ColorFunction
{
public final Color color2;
public final float weight;
public Mix( Color color2, float weight ) {
this.color2 = color2;
this.weight = weight;
}
@Override
public void apply( float[] hsla ) {
// convert from HSL to RGB because color mixing is done on RGB values
Color color1 = HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 );
// mix
Color color = mix( color1, color2, weight / 100 );
// convert RGB to HSL
float[] hsl = HSLColor.fromRGB( color );
System.arraycopy( hsl, 0, hsla, 0, hsl.length );
hsla[3] = (color.getAlpha() / 255f) * 100;
}
@Override
public String toString() {
return String.format( "mix(#%08x,%.0f%%)", color2.getRGB(), weight );
}
}
} }

View File

@@ -46,6 +46,7 @@ public class SystemInfo
public static final boolean isJava_9_orLater; public static final boolean isJava_9_orLater;
public static final boolean isJava_11_orLater; public static final boolean isJava_11_orLater;
public static final boolean isJava_15_orLater; public static final boolean isJava_15_orLater;
/** @since 2 */ public static final boolean isJava_17_orLater;
// Java VMs // Java VMs
public static final boolean isJetBrainsJVM; public static final boolean isJetBrainsJVM;
@@ -82,6 +83,7 @@ public class SystemInfo
isJava_9_orLater = (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_11_orLater = (javaVersion >= toVersion( 11, 0, 0, 0 ));
isJava_15_orLater = (javaVersion >= toVersion( 15, 0, 0, 0 )); isJava_15_orLater = (javaVersion >= toVersion( 15, 0, 0, 0 ));
isJava_17_orLater = (javaVersion >= toVersion( 17, 0, 0, 0 ));
// Java VMs // Java VMs
isJetBrainsJVM = System.getProperty( "java.vm.vendor", "Unknown" ) isJetBrainsJVM = System.getProperty( "java.vm.vendor", "Unknown" )

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.util.function.BiPredicate;
/**
* @author Karl Tauber
*/
class StackUtilsImpl
extends StackUtils
{
@Override
boolean wasInvokedFromImpl( BiPredicate<String, String> predicate, int limit ) {
return StackWalker.getInstance().walk( stream -> {
if( limit > 0 )
stream = stream.limit( limit + 2 );
return stream.anyMatch( f -> {
return predicate.test( f.getClassName(), f.getMethodName() );
} );
} );
}
}

View File

@@ -374,7 +374,7 @@ MenuItem.iconTextGap = 6
MenuItem.textAcceleratorGap = 24 MenuItem.textAcceleratorGap = 24
MenuItem.textNoAcceleratorGap = 6 MenuItem.textNoAcceleratorGap = 6
MenuItem.acceleratorArrowGap = 2 MenuItem.acceleratorArrowGap = 2
MenuItem.acceleratorDelimiter = - MenuItem.acceleratorDelimiter = +
[mac]MenuItem.acceleratorDelimiter = [mac]MenuItem.acceleratorDelimiter =
# for MenuItem.selectionType = underline # for MenuItem.selectionType = underline
@@ -514,6 +514,17 @@ ScrollPane.fillUpperCorner = true
ScrollPane.smoothScrolling = true ScrollPane.smoothScrolling = true
#---- SearchField ----
SearchField.searchIconColor = fadeout(Actions.GreyInline,10%,lazy)
SearchField.searchIconHoverColor = fadeout(Actions.GreyInline,30%,lazy)
SearchField.searchIconPressedColor = fadeout(Actions.GreyInline,50%,lazy)
SearchField.clearIconColor = fadeout(Actions.GreyInline,50%,lazy)
SearchField.clearIconHoverColor = $SearchField.clearIconColor
SearchField.clearIconPressedColor = fadeout(Actions.GreyInline,20%,lazy)
#---- Separator ---- #---- Separator ----
Separator.height = 3 Separator.height = 3
@@ -617,6 +628,7 @@ TabbedPane.closeCrossLineWidth = {float}1
Table.rowHeight = 20 Table.rowHeight = 20
Table.showHorizontalLines = false Table.showHorizontalLines = false
Table.showVerticalLines = false Table.showVerticalLines = false
Table.showTrailingVerticalLine = false
Table.consistentHomeEndKeyBehavior = true 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
@@ -646,7 +658,7 @@ TableHeader.cellBorder = com.formdev.flatlaf.ui.FlatTableHeaderBorder
TableHeader.cellMargins = 2,3,2,3 TableHeader.cellMargins = 2,3,2,3
TableHeader.focusCellBackground = $TableHeader.background TableHeader.focusCellBackground = $TableHeader.background
TableHeader.background = @textComponentBackground TableHeader.background = @textComponentBackground
TableHeader.showTrailingVerticalLine = false
#---- TextArea ---- #---- TextArea ----
@@ -752,6 +764,7 @@ ToolBar.separatorWidth = 7
ToolBar.separatorColor = $Separator.foreground ToolBar.separatorColor = $Separator.foreground
ToolBar.spacingBorder = $Button.toolbar.spacingInsets ToolBar.spacingBorder = $Button.toolbar.spacingInsets
ToolBar.focusableButtons = false
#---- ToolTipManager ---- #---- ToolTipManager ----

View File

@@ -0,0 +1,203 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import com.formdev.flatlaf.util.UIScale;
/**
* @author Karl Tauber
*/
public class TestFlatComponentSizes
{
@BeforeAll
static void setup() {
TestUtils.setup( false );
}
@AfterAll
static void cleanup() {
TestUtils.cleanup();
}
static float[] factors() {
return TestUtils.FACTORS;
}
@ParameterizedTest
@MethodSource( "factors" )
void sizes( float factor ) {
TestUtils.scaleFont( factor );
// should have same default size (minimumWidth is 64)
JTextField textField = new JTextField();
JFormattedTextField formattedTextField = new JFormattedTextField();
JPasswordField passwordField = new JPasswordField();
JSpinner spinner = new JSpinner();
Dimension textFieldSize = textField.getPreferredSize();
assertEquals( textFieldSize, formattedTextField.getPreferredSize() );
assertEquals( textFieldSize, passwordField.getPreferredSize() );
assertEquals( textFieldSize, spinner.getPreferredSize() );
// should have same default size (minimumWidth is 72)
JButton button = new JButton( "text" );
JComboBox<String> comboBox = new JComboBox<>();
JComboBox<String> comboBoxEditable = new JComboBox<>();
comboBoxEditable.setEditable( true );
Dimension buttonSize = button.getPreferredSize();
assertEquals( buttonSize, comboBox.getPreferredSize() );
assertEquals( buttonSize, comboBoxEditable.getPreferredSize() );
// should have same height
JToggleButton toggleButton = new JToggleButton( "text" );
assertEquals( textFieldSize.height, button.getPreferredSize().height );
assertEquals( textFieldSize.height, toggleButton.getPreferredSize().height );
// should have same size
JCheckBox checkBox = new JCheckBox( "text" );
JRadioButton radioButton = new JRadioButton( "text" );
assertEquals( checkBox.getPreferredSize(), radioButton.getPreferredSize() );
// should have same size
JMenu menu = new JMenu( "text" );
JMenuItem menuItem = new JMenuItem( "text" );
JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem( "text" );
JRadioButtonMenuItem radioButtonMenuItem = new JRadioButtonMenuItem( "text" );
Dimension menuSize = menu.getPreferredSize();
assertEquals( menuSize, menuItem.getPreferredSize() );
assertEquals( menuSize, checkBoxMenuItem.getPreferredSize() );
assertEquals( menuSize, radioButtonMenuItem.getPreferredSize() );
TestUtils.resetFont();
}
@ParameterizedTest
@MethodSource( "factors" )
void comboBox( float factor ) {
TestUtils.scaleFont( factor );
String[] items = { "t" };
JComboBox<String> comboBox = new JComboBox<>( items );
JComboBox<String> comboBox2 = new JComboBox<>( items );
JComboBox<String> comboBox3 = new JComboBox<>( items );
JComboBox<String> comboBox4 = new JComboBox<>( items );
applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() );
applyCustomComboBoxRendererBorder( comboBox4, null );
Dimension size = comboBox.getPreferredSize();
assertEquals( size.width, comboBox2.getPreferredSize().width );
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
assertEquals( size, comboBox3.getPreferredSize() );
assertEquals( size, comboBox4.getPreferredSize() );
TestUtils.resetFont();
}
@SuppressWarnings( "unchecked" )
private void applyCustomComboBoxRendererBorder( JComboBox<String> comboBox, Border border ) {
BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer();
customRenderer.setBorder( border );
comboBox.setRenderer( customRenderer );
}
@ParameterizedTest
@MethodSource( "factors" )
void comboBoxEditable( float factor ) {
TestUtils.scaleFont( factor );
String[] items = { "t" };
JComboBox<String> comboBox = new JComboBox<>( items );
JComboBox<String> comboBox2 = new JComboBox<>( items );
JComboBox<String> comboBox3 = new JComboBox<>( items );
JComboBox<String> comboBox4 = new JComboBox<>( items );
comboBox.setEditable( true );
comboBox2.setEditable( true );
comboBox3.setEditable( true );
comboBox4.setEditable( true );
applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) );
applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() );
applyCustomComboBoxEditorBorder( comboBox4, null );
Dimension size = comboBox.getPreferredSize();
assertEquals( size.width, comboBox2.getPreferredSize().width );
assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height );
assertEquals( size, comboBox3.getPreferredSize() );
assertEquals( size, comboBox4.getPreferredSize() );
TestUtils.resetFont();
}
private void applyCustomComboBoxEditorBorder( JComboBox<String> comboBox, Border border ) {
JTextField customTextField = new JTextField();
if( border != null )
customTextField.setBorder( border );
comboBox.setEditor( new BasicComboBoxEditor() {
@Override
protected JTextField createEditorComponent() {
return customTextField;
}
} );
}
//---- class BorderWithIcon -----------------------------------------------
private static class BorderWithIcon
implements Border
{
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
}
@Override
public boolean isBorderOpaque() {
return false;
}
@Override
public Insets getBorderInsets( Component c ) {
return new Insets( 0, 0, 0, UIScale.scale( 16 ) + 4 );
}
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import org.junit.jupiter.api.BeforeAll;
/**
* @author Karl Tauber
*/
public class TestFlatComponentSizesWithFocus
extends TestFlatComponentSizes
{
@BeforeAll
static void setup() {
TestUtils.setup( true );
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Font;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatSystemProperties;
/**
* @author Karl Tauber
*/
public class TestUtils
{
public static final float[] FACTORS = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 2.75f, 3f, 3.25f, 3.5f, 3.75f, 4f, 5f, 6f };
public static void setup( boolean withFocus ) {
System.setProperty( FlatSystemProperties.UI_SCALE, "1x" );
if( withFocus )
FlatIntelliJLaf.setup();
else
FlatLightLaf.setup();
System.clearProperty( FlatSystemProperties.UI_SCALE );
}
public static void cleanup() {
UIManager.put( "defaultFont", null );
}
public static void scaleFont( float factor ) {
Font defaultFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" );
UIManager.put( "defaultFont", defaultFont.deriveFont( (float) Math.round( defaultFont.getSize() * factor ) ) );
}
public static void resetFont() {
UIManager.put( "defaultFont", null );
}
}

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="16" height="16" fill="#6E6E6E" rx="3"/> <rect width="16" height="16" fill="#6E6E6E" rx="3"/>
<rect width="6" height="2" x="5" y="12" fill="#FFF"/> <rect width="6" height="2" x="5" y="11.5" fill="#FFF"/>
<path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/> <path fill="#FFF" d="M2,8 L8,2 L14,8 L11,8 L11,10 L5,10 L5,8 L2,8 Z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#7F8B91" fill-opacity=".5" fill-rule="evenodd" d="M8,1.75 C11.4517797,1.75 14.25,4.54822031 14.25,8 C14.25,11.4517797 11.4517797,14.25 8,14.25 C4.54822031,14.25 1.75,11.4517797 1.75,8 C1.75,4.54822031 4.54822031,1.75 8,1.75 Z M10.5,4.5 L8,7 L5.5,4.5 L4.5,5.5 L7,8 L4.5,10.5 L5.5,11.5 L8,9 L10.5,11.5 L11.5,10.5 L9,8 L11.5,5.5 L10.5,4.5 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="none" stroke="#7F8B91" stroke-linecap="square" stroke-opacity=".5" d="M5,5 L11,11 M5,11 L11,5"/>
</svg>

After

Width:  |  Height:  |  Size: 202 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
<polygon fill="#7F8B91" points="10.813 9.75 14 12.938 12.938 14 9.75 10.813"/>
<path fill="#7F8B91" d="M7,2 C9.76142375,2 12,4.23857625 12,7 C12,9.76142375 9.76142375,12 7,12 C4.23857625,12 2,9.76142375 2,7 C2,4.23857625 4.23857625,2 7,2 Z M7,3 C4.790861,3 3,4.790861 3,7 C3,9.209139 4.790861,11 7,11 C9.209139,11 11,9.209139 11,7 C11,4.790861 9.209139,3 7,3 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 526 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-opacity=".9" fill-rule="evenodd">
<polygon fill="#7F8B91" points="8.813 9.75 12 12.938 10.938 14 7.75 10.813"/>
<path fill="#7F8B91" d="M5,2 C7.76142375,2 10,4.23857625 10,7 C10,9.76142375 7.76142375,12 5,12 C2.23857625,12 0,9.76142375 0,7 C0,4.23857625 2.23857625,2 5,2 Z M5,3 C2.790861,3 1,4.790861 1,7 C1,9.209139 2.790861,11 5,11 C7.209139,11 9,9.209139 9,7 C9,4.790861 7.209139,3 5,3 Z"/>
<polygon fill="#7F8B91" points="11 7 16 7 13.5 10"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 579 B

View File

@@ -28,6 +28,7 @@ import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel; import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.*; import com.formdev.flatlaf.*;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.layout.ConstraintParser; import net.miginfocom.layout.ConstraintParser;
@@ -240,7 +241,7 @@ class ControlBar
frame.setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) ); frame.setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
} catch( Exception ex ) { } catch( Exception ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
} }
} ); } );
} }

View File

@@ -18,6 +18,10 @@ package com.formdev.flatlaf.demo;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Year;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.prefs.Preferences; import java.util.prefs.Preferences;
@@ -34,8 +38,10 @@ import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
import com.formdev.flatlaf.extras.components.FlatButton; import com.formdev.flatlaf.extras.components.FlatButton;
import com.formdev.flatlaf.extras.components.FlatButton.ButtonType; import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
import com.formdev.flatlaf.extras.FlatSVGUtils; import com.formdev.flatlaf.extras.FlatSVGUtils;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.JBRCustomDecorations; import com.formdev.flatlaf.ui.JBRCustomDecorations;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.layout.ConstraintParser; import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.layout.LC; import net.miginfocom.layout.LC;
import net.miginfocom.layout.UnitValue; import net.miginfocom.layout.UnitValue;
@@ -127,7 +133,36 @@ class DemoFrame
} }
private void aboutActionPerformed() { private void aboutActionPerformed() {
JOptionPane.showMessageDialog( this, "FlatLaf Demo", "About", JOptionPane.PLAIN_MESSAGE ); JLabel titleLabel = new JLabel( "FlatLaf Demo" );
Font titleFont = titleLabel.getFont();
titleLabel.setFont( titleFont.deriveFont( (float) titleFont.getSize() + UIScale.scale( 6 ) ) );
String link = "https://www.formdev.com/flatlaf/";
JLabel linkLabel = new JLabel( "<html><a href=\"#\">" + link + "</a></html>" );
linkLabel.setCursor( Cursor.getPredefinedCursor( Cursor.HAND_CURSOR ) );
linkLabel.addMouseListener( new MouseAdapter() {
@Override
public void mouseClicked( MouseEvent e ) {
try {
Desktop.getDesktop().browse( new URI( link ) );
} catch( IOException | URISyntaxException ex ) {
JOptionPane.showMessageDialog( linkLabel,
"Failed to open '" + link + "' in browser.",
"About", JOptionPane.PLAIN_MESSAGE );
}
}
} );
JOptionPane.showMessageDialog( this,
new Object[] {
titleLabel,
"Demonstrates FlatLaf Swing look and feel",
" ",
"Copyright 2019-" + Year.now() + " FormDev Software GmbH",
linkLabel,
},
"About", JOptionPane.PLAIN_MESSAGE );
} }
private void selectedTabChanged() { private void selectedTabChanged() {
@@ -185,6 +220,8 @@ class DemoFrame
Font font = UIManager.getFont( "defaultFont" ); Font font = UIManager.getFont( "defaultFont" );
Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() ); Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() );
// StyleContext.getFont() may return a UIResource, which would cause loosing user scale factor on Windows
newFont = FlatUIUtils.nonUIResource( newFont );
UIManager.put( "defaultFont", newFont ); UIManager.put( "defaultFont", newFont );
FlatLaf.updateUI(); FlatLaf.updateUI();

View File

@@ -25,6 +25,7 @@ import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatPropertiesLaf; import com.formdev.flatlaf.FlatPropertiesLaf;
import com.formdev.flatlaf.IntelliJTheme; import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel; import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
/** /**
@@ -83,7 +84,7 @@ public class DemoPrefs
UIManager.setLookAndFeel( lafClassName ); UIManager.setLookAndFeel( lafClassName );
} }
} catch( Throwable ex ) { } catch( Throwable ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
// fallback // fallback
FlatLightLaf.setup(); FlatLightLaf.setup();

View File

@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import com.formdev.flatlaf.util.LoggingFacade;
/** /**
* This tool creates look and feel classes for all themes listed in themes.json. * This tool creates look and feel classes for all themes listed in themes.json.
@@ -120,7 +121,7 @@ public class IJThemesClassGenerator
Files.write( out, content.getBytes( StandardCharsets.ISO_8859_1 ), Files.write( out, content.getBytes( StandardCharsets.ISO_8859_1 ),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
} catch( IOException ex ) { } catch( IOException ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
} }
} }
@@ -168,14 +169,6 @@ public class IJThemesClassGenerator
" }\n" + " }\n" +
" }\n" + " }\n" +
"\n" + "\n" +
" /**\n" +
" * @deprecated use {@link #setup()} instead; this method will be removed in a future version\n" +
" */\n" +
" @Deprecated\n" +
" public static boolean install() {\n" +
" return setup();\n" +
" }\n" +
"\n" +
" public static void installLafInfo() {\n" + " public static void installLafInfo() {\n" +
" installLafInfo( NAME, ${themeClass}.class );\n" + " installLafInfo( NAME, ${themeClass}.class );\n" +
" }\n" + " }\n" +

View File

@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
/** /**
@@ -46,7 +47,7 @@ class IJThemesManager
try( Reader reader = new InputStreamReader( getClass().getResourceAsStream( "themes.json" ), StandardCharsets.UTF_8 ) ) { try( Reader reader = new InputStreamReader( getClass().getResourceAsStream( "themes.json" ), StandardCharsets.UTF_8 ) ) {
json = (Map<String, Object>) Json.parse( reader ); json = (Map<String, Object>) Json.parse( reader );
} catch( IOException ex ) { } catch( IOException ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
return; return;
} }

View File

@@ -52,6 +52,7 @@ import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.demo.DemoPrefs; import com.formdev.flatlaf.demo.DemoPrefs;
import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatAnimatedLafChange;
import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -259,7 +260,7 @@ public class IJThemesPanel
try { try {
UIManager.setLookAndFeel( themeInfo.lafClassName ); UIManager.setLookAndFeel( themeInfo.lafClassName );
} catch( Exception ex ) { } catch( Exception ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex ); showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
} }
} else if( themeInfo.themeFile != null ) { } else if( themeInfo.themeFile != null ) {
@@ -273,7 +274,7 @@ public class IJThemesPanel
DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile ); DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.FILE_PREFIX + themeInfo.themeFile );
} catch( Exception ex ) { } catch( Exception ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex ); showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex );
} }
} else { } else {

View File

@@ -23,6 +23,7 @@ import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import com.formdev.flatlaf.util.LoggingFacade;
/** /**
* This tool updates all IntelliJ themes listed in themes.json by downloading * This tool updates all IntelliJ themes listed in themes.json by downloading
@@ -61,7 +62,7 @@ public class IJThemesUpdater
URLConnection con = url.openConnection(); URLConnection con = url.openConnection();
Files.copy( con.getInputStream(), out, StandardCopyOption.REPLACE_EXISTING ); Files.copy( con.getInputStream(), out, StandardCopyOption.REPLACE_EXISTING );
} catch( IOException ex ) { } catch( IOException ex ) {
ex.printStackTrace(); LoggingFacade.INSTANCE.logSevere( null, ex );
} }
} }
} }

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd" transform="translate(2 2)"> <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
<rect width="5.5" height="5.5" fill="#59A869"/> <rect width="5.5" height="5.5" fill="#59A869"/>

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/> <path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/>

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#59A869" fill-rule="evenodd" points="4 2 14 8 4 14"/> <polygon fill="#59A869" fill-rule="evenodd" points="4 2 14 8 4 14"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 162 B

After

Width:  |  Height:  |  Size: 309 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/> <rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/>

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 640 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/> <rect width="6" height="1" x="5" y="12" fill="#6E6E6E"/>

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 640 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<rect width="10" height="10" x="3" y="3" fill="#DB5860" fill-rule="evenodd"/> <rect width="10" height="10" x="3" y="3" fill="#DB5860" fill-rule="evenodd"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 171 B

After

Width:  |  Height:  |  Size: 318 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path fill="#DB5860" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z"/> <path fill="#DB5860" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 350 B

After

Width:  |  Height:  |  Size: 497 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path fill="#389FD6" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z" transform="rotate(180 16 16)"/> <path fill="#389FD6" fill-rule="evenodd" d="M16,30 C8.2680135,30 2,23.7319865 2,16 C2,8.2680135 8.2680135,2 16,2 C23.7319865,2 30,8.2680135 30,16 C30,23.7319865 23.7319865,30 16,30 Z M14,7 L14,18 L18,18 L18,7 L14,7 Z M14,21 L14,25 L18,25 L18,21 L14,21 Z" transform="rotate(180 16 16)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
<defs> <defs>
<rect id="abstractclass-a" width="8" height="14"/> <rect id="abstractclass-a" width="8" height="14"/>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
<defs> <defs>
<rect id="abstractmethod-a" width="8" height="14"/> <rect id="abstractmethod-a" width="8" height="14"/>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<path fill="#62B543" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/> <path fill="#62B543" fill-opacity=".6" d="M15,8 C15,11.866 11.866,15 8,15 C4.134,15 1,11.866 1,8 C1,4.134 4.134,1 8,1 C11.866,1 15,4.134 15,8"/>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,10 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<g fill="none" fill-rule="evenodd"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<polygon fill="#9AA7B0" fill-opacity=".8" points="7 1 3 5 7 5"/> <g id="css">
<polygon fill="#9AA7B0" fill-opacity=".8" points="8 1 8 6 3 6 3 8 13 8 13 1"/> <path id="Fill 1" fill-rule="evenodd" clip-rule="evenodd" d="M7 1L3 5H7V1Z" fill="#9AA7B0" fill-opacity="0.8"/>
<polygon fill="#40B6E0" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/> <path id="Fill 3" fill-rule="evenodd" clip-rule="evenodd" d="M8 1V6H3V8H13V1H8Z" fill="#9AA7B0" fill-opacity="0.8"/>
<path fill="#231F20" fill-opacity=".7" d="M0,2.501 C0,1 0.931,2.02832126e-16 2.256,0 C3.20239258,0 3.55,0.311 3.969,0.753 L3.42669678,1.42712402 C3.07669678,1.06812402 2.75,1 2.25,1 C1.418,1 1,1.73791504 1,2.487 C1,3.23608496 1.412,4 2.25,4 C2.787,4 3.05169678,3.89340869 3.42669678,3.50640869 L4,4.144 C3.544,4.669 3.19732666,5 2.225,5 C0.949,5 7.35277938e-17,4.002 0,2.501 Z" transform="translate(2 10)"/> <path id="Fill 5" fill-rule="evenodd" clip-rule="evenodd" d="M1 16H16V9H1V16Z" fill="#F98B9E" fill-opacity="0.6"/>
<path fill="#231F20" fill-opacity=".7" d="M0.972767969,1.50152588 C0.972767969,1.13305664 1.284,1 1.845,1 C1.85033333,1 2.23533333,1 3,1 L3,0 C2.26266667,0 1.88266667,0 1.86,0 C0.778,0 0,0.45916748 0,1.45 C0,2.31452637 0.419555664,2.69049072 1.47125244,2.91607666 C2.24158869,3.08131157 2.496155,3.22862939 2.496155,3.548 C2.496155,3.86737061 2.13842773,4 1.47125244,4 C1.46058577,4 1.07016829,4 0.3,4 L0.3,5 C1.07550163,5 1.46591911,5 1.47125244,5 C3.5,5 3.5,4 3.5,3.548 C3.5,2.91607666 3.02026367,2.42071533 2.15869141,2.14685059 C1.29711914,1.87298584 0.972767969,1.86999512 0.972767969,1.50152588 Z" transform="translate(7 10)"/> <g id="&#226;&#140;&#152;/alphabet/C">
<path fill="#231F20" fill-opacity=".7" d="M0.972767969,1.50152588 C0.972767969,1.13305664 1.284,1 1.845,1 C1.85033333,1 2.23533333,1 3,1 L3,0 C2.26266667,0 1.88266667,0 1.86,0 C0.778,0 0,0.45916748 0,1.45 C0,2.31452637 0.419555664,2.69049072 1.47125244,2.91607666 C2.24158869,3.08131157 2.496155,3.22862939 2.496155,3.548 C2.496155,3.86737061 2.13842773,4 1.47125244,4 C1.46058577,4 1.07016829,4 0.3,4 L0.3,5 C1.07550163,5 1.46591911,5 1.47125244,5 C3.5,5 3.5,4 3.5,3.548 C3.5,2.91607666 3.02026367,2.42071533 2.15869141,2.14685059 C1.29711914,1.87298584 0.972767969,1.86999512 0.972767969,1.50152588 Z" transform="translate(11 10)"/> <path id="&#226;&#140;&#152;/alphabet/C_2" fill-rule="evenodd" clip-rule="evenodd" d="M2 12.501C2 11 2.931 10 4.256 10C5.20239 10 5.55 10.311 5.969 10.753L5.4267 11.4271C5.0767 11.0681 4.75 11 4.25 11C3.418 11 3 11.7379 3 12.487C3 13.2361 3.412 14 4.25 14C4.787 14 5.0517 13.8934 5.4267 13.5064L6 14.144C5.544 14.669 5.19733 15 4.225 15C2.949 15 2 14.002 2 12.501Z" fill="#231F20" fill-opacity="0.7"/>
</g> </g>
<g id="&#226;&#140;&#152;/alphabet/S">
<path id="&#226;&#140;&#152;/alphabet/S_2" fill-rule="evenodd" clip-rule="evenodd" d="M7.97277 11.5015C7.97277 11.1331 8.284 11 8.845 11C8.853 11 10 11 10 11V10C10 10 8.894 10 8.86 10C7.778 10 7 10.4592 7 11.45C7 12.3145 7.41956 12.6905 8.47125 12.9161C9.24159 13.0813 9.49616 13.2286 9.49616 13.548C9.49616 13.8674 9.13843 14 8.47125 14C8.45525 14 7.3 14 7.3 14V15C7.3 15 8.46325 15 8.47125 15C10.5 15 10.5 14 10.5 13.548C10.5 12.9161 10.0203 12.4207 9.15869 12.1469C8.29712 11.873 7.97277 11.87 7.97277 11.5015Z" fill="#231F20" fill-opacity="0.7"/>
</g>
<g id="&#226;&#140;&#152;/alphabet/S_3">
<path id="&#226;&#140;&#152;/alphabet/S_4" fill-rule="evenodd" clip-rule="evenodd" d="M11.9728 11.5015C11.9728 11.1331 12.284 11 12.845 11C12.853 11 14 11 14 11V10C14 10 12.894 10 12.86 10C11.778 10 11 10.4592 11 11.45C11 12.3145 11.4196 12.6905 12.4713 12.9161C13.2416 13.0813 13.4962 13.2286 13.4962 13.548C13.4962 13.8674 13.1384 14 12.4713 14C12.4553 14 11.3 14 11.3 14V15C11.3 15 12.4633 15 12.4713 15C14.5 15 14.5 14 14.5 13.548C14.5 12.9161 14.0203 12.4207 13.1587 12.1469C12.2971 11.873 11.9728 11.87 11.9728 11.5015Z" fill="#231F20" fill-opacity="0.7"/>
</g>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<polygon fill="#F4AF3D" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/> <polygon fill="#F4AF3D" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<polygon fill="#F26522" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/> <polygon fill="#F26522" fill-opacity=".7" points="1 16 16 16 16 9 1 9"/>

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 645 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<path fill="#EDA200" fill-rule="evenodd" d="M16,2 L31,28 L1,28 L16,2 Z M18,25 L18,21 L14,21 L14,25 L18,25 Z M18,18 L18,10 L14,10 L14,18 L18,18 Z"/> <path fill="#EDA200" fill-rule="evenodd" d="M16,2 L31,28 L1,28 L16,2 Z M18,25 L18,21 L14,21 L14,25 L18,25 Z M18,18 L18,10 L14,10 L14,18 L18,18 Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 388 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 0C8.02219 0 6.08879 0.58649 4.4443 1.6853C2.79981 2.78412 1.51809 4.3459 0.761209 6.17317C0.00433284 8.00043 -0.193701 10.0111 0.192152 11.9509C0.578004 13.8907 1.53041 15.6725 2.92894 17.0711C4.32746 18.4696 6.10929 19.422 8.0491 19.8079C9.98891 20.1937 11.9996 19.9957 13.8268 19.2388C15.6541 18.4819 17.2159 17.2002 18.3147 15.5557C19.4135 13.9112 20 11.9778 20 10C20 7.34784 18.9464 4.8043 17.0711 2.92893C15.1957 1.05357 12.6522 0 10 0ZM10 18.2C8.3782 18.2 6.79281 17.7191 5.44433 16.8181C4.09585 15.917 3.04483 14.6364 2.42419 13.138C1.80355 11.6397 1.64117 9.9909 1.95757 8.40026C2.27396 6.80961 3.05494 5.34852 4.20173 4.20172C5.34852 3.05493 6.80962 2.27396 8.40026 1.95756C9.99091 1.64116 11.6397 1.80355 13.138 2.42419C14.6364 3.04483 15.917 4.09584 16.8181 5.44432C17.7191 6.79281 18.2 8.37819 18.2 10C18.1974 12.174 17.3326 14.2581 15.7954 15.7954C14.2581 17.3326 12.174 18.1974 10 18.2ZM10.9 9.43L14.46 11.09L13.7 12.72L9.10001 10.57V4H10.9V9.43Z" fill="#9AA7B0" fill-opacity="0.8"/> <path d="M10 0C8.02219 0 6.08879 0.58649 4.4443 1.6853C2.79981 2.78412 1.51809 4.3459 0.761209 6.17317C0.00433284 8.00043 -0.193701 10.0111 0.192152 11.9509C0.578004 13.8907 1.53041 15.6725 2.92894 17.0711C4.32746 18.4696 6.10929 19.422 8.0491 19.8079C9.98891 20.1937 11.9996 19.9957 13.8268 19.2388C15.6541 18.4819 17.2159 17.2002 18.3147 15.5557C19.4135 13.9112 20 11.9778 20 10C20 7.34784 18.9464 4.8043 17.0711 2.92893C15.1957 1.05357 12.6522 0 10 0ZM10 18.2C8.3782 18.2 6.79281 17.7191 5.44433 16.8181C4.09585 15.917 3.04483 14.6364 2.42419 13.138C1.80355 11.6397 1.64117 9.9909 1.95757 8.40026C2.27396 6.80961 3.05494 5.34852 4.20173 4.20172C5.34852 3.05493 6.80962 2.27396 8.40026 1.95756C9.99091 1.64116 11.6397 1.80355 13.138 2.42419C14.6364 3.04483 15.917 4.09584 16.8181 5.44432C17.7191 6.79281 18.2 8.37819 18.2 10C18.1974 12.174 17.3326 14.2581 15.7954 15.7954C14.2581 17.3326 12.174 18.1974 10 18.2ZM10.9 9.43L14.46 11.09L13.7 12.72L9.10001 10.57V4H10.9V9.43Z" fill="#9AA7B0" fill-opacity="0.8"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="#6E6E6E" fill-rule="evenodd" transform="translate(1 3)"> <g fill="#6E6E6E" fill-rule="evenodd" transform="translate(1 3)">
<rect width="12" height="2" x="1" y="4"/> <rect width="12" height="2" x="1" y="4"/>

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 589 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#389FD6" fill-rule="evenodd" d="M14.0431479,8.44999981 L14.3048222,13.4430431 L12.574725,11.885269 C11.4741571,13.1817306 9.83248424,14.0044386 7.99865879,14.0044386 C5.03921121,14.0044386 2.58020312,11.8617896 2.08827651,9.04314243 L3.94798986,9.10858763 C4.43427312,10.8903005 6.0642585,12.2000519 8.00015362,12.2000519 C9.30169687,12.2000519 10.4649641,11.6080237 11.2353504,10.6785714 L9.05000019,8.71167959 L14.0431479,8.44999981 Z M7.99865879,2.00443857 C10.9184669,2.00443857 13.3511517,4.09007371 13.888219,6.85284133 L12.0226275,6.7880427 C11.5024638,5.05933714 9.89836709,3.8000774 8.00015362,3.8000774 C6.69883692,3.8000774 5.53574811,4.39189956 4.76535914,5.32107268 L6.95482203,7.29304326 L1.96167436,7.55472304 L1.70000005,2.56167973 L3.42768119,4.11762166 C4.52821742,2.82461451 6.1676575,2.00443857 7.99865879,2.00443857 Z" transform="rotate(3 8.002 8.004)"/> <path fill="#389FD6" fill-rule="evenodd" d="M14.0431479,8.44999981 L14.3048222,13.4430431 L12.574725,11.885269 C11.4741571,13.1817306 9.83248424,14.0044386 7.99865879,14.0044386 C5.03921121,14.0044386 2.58020312,11.8617896 2.08827651,9.04314243 L3.94798986,9.10858763 C4.43427312,10.8903005 6.0642585,12.2000519 8.00015362,12.2000519 C9.30169687,12.2000519 10.4649641,11.6080237 11.2353504,10.6785714 L9.05000019,8.71167959 L14.0431479,8.44999981 Z M7.99865879,2.00443857 C10.9184669,2.00443857 13.3511517,4.09007371 13.888219,6.85284133 L12.0226275,6.7880427 C11.5024638,5.05933714 9.89836709,3.8000774 8.00015362,3.8000774 C6.69883692,3.8000774 5.53574811,4.39189956 4.76535914,5.32107268 L6.95482203,7.29304326 L1.96167436,7.55472304 L1.70000005,2.56167973 L3.42768119,4.11762166 C4.52821742,2.82461451 6.1676575,2.00443857 7.99865879,2.00443857 Z" transform="rotate(3 8.002 8.004)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#59A869" points="13.789 2.09 15.535 3.837 6.292 13.08 1.95 8.738 3.698 6.99 6.293 9.585"/> <polygon fill="#59A869" points="13.789 2.09 15.535 3.837 6.292 13.08 1.95 8.738 3.698 6.99 6.293 9.585"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 199 B

After

Width:  |  Height:  |  Size: 346 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/> <path fill="#6E6E6E" d="M11,3 L4,3 L4,11 L2,11 L2,1 L11,1 L11,3 Z"/>

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="#389FD6" fill-rule="evenodd" transform="translate(1)"> <g fill="#389FD6" fill-rule="evenodd" transform="translate(1)">
<path d="M10.9000003,4.89999992 L14.0999999,4.89999992 L9.9000001,9.09999973 L5.70000029,4.89999992 L8.90000027,4.89999992 L8.90000027,0.899999917 L10.9000003,0.899999917 L10.9000003,4.89999992 Z" transform="rotate(90 9.9 5)"/> <path d="M10.9000003,4.89999992 L14.0999999,4.89999992 L9.9000001,9.09999973 L5.70000029,4.89999992 L8.90000027,4.89999992 L8.90000027,0.899999917 L10.9000003,0.899999917 L10.9000003,4.89999992 Z" transform="rotate(90 9.9 5)"/>

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 777 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<polygon fill="#6E6E6E" points="9 7 12 7 8 11 4 7 7 7 7 2 9 2" transform="matrix(-1 0 0 1 16 0)"/> <polygon fill="#6E6E6E" points="9 7 12 7 8 11 4 7 7 7 7 2 9 2" transform="matrix(-1 0 0 1 16 0)"/>

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 448 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#F4AF3D" fill-rule="evenodd" points="7.998 11.522 3.673 14.311 4.989 9.336 1 6.084 6.138 5.798 7.998 1 9.858 5.798 14.996 6.084 11.007 9.336 12.323 14.311"/> <polygon fill="#F4AF3D" fill-rule="evenodd" points="7.998 11.522 3.673 14.311 4.989 9.336 1 6.084 6.138 5.798 7.998 1 9.858 5.798 14.996 6.084 11.007 9.336 12.323 14.311"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 413 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="11" height="2" x="2" y="7" fill="#6E6E6E" transform="matrix(-1 0 0 1 15 0)"/> <rect width="11" height="2" x="2" y="7" fill="#6E6E6E" transform="matrix(-1 0 0 1 15 0)"/>

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 631 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#161514" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1345551 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.38099 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/> <path fill="#161514" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1345551 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.38099 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFFFFE" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1341255 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.3805604 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/> <path fill="#FFFFFE" fill-rule="evenodd" d="M7.99707713,1 C4.13339149,1 1,4.1329619 1,7.9979363 C1,11.0896581 3.00487223,13.7122732 5.78557461,14.6375989 C6.13568621,14.7020366 6.2632729,14.4859554 6.2632729,14.3003748 C6.2632729,14.1341255 6.25725871,13.6942307 6.25382203,13.1104249 C4.30737333,13.5331364 3.89669027,12.1722117 3.89669027,12.1722117 C3.57836793,11.3637332 3.11957137,11.1485112 3.11957137,11.1485112 C2.48421546,10.7146305 3.16768487,10.7232222 3.16768487,10.7232222 C3.87005601,10.7726245 4.23949893,11.4444951 4.23949893,11.4444951 C4.86368564,12.5137317 5.87750575,12.2048602 6.27616044,12.0257233 C6.33973899,11.5738001 6.52059419,11.2653582 6.72035112,11.0905172 C5.16654292,10.9139579 3.53283195,10.3133983 3.53283195,7.63193005 C3.53283195,6.86812829 3.80561829,6.24308241 4.25324565,5.75421492 C4.1810754,5.57722598 3.9409375,4.86540398 4.32197921,3.90227487 C4.32197921,3.90227487 4.90922163,3.71411673 6.24608951,4.61968148 C6.80412015,4.46417178 7.40296136,4.38684652 7.9979363,4.38383942 C8.59248165,4.38684652 9.19089327,4.46417178 9.74978309,4.61968148 C11.0857918,3.71411673 11.672175,3.90227487 11.672175,3.90227487 C12.0540759,4.86540398 11.813938,5.57722598 11.7421974,5.75421492 C12.1906839,6.24308241 12.4613223,6.86812829 12.4613223,7.63193005 C12.4613223,10.3202717 10.8250338,10.91181 9.26650019,11.0849326 C9.51737771,11.3010138 9.74119139,11.7280211 9.74119139,12.3805604 C9.74119139,13.316196 9.7325997,14.0709765 9.7325997,14.3003748 C9.7325997,14.4876738 9.85889763,14.7054733 10.2137347,14.6371693 C12.9922891,13.7096957 14.995443,11.0887989 14.995443,7.9979363 C14.995443,4.1329619 11.8620515,1 7.99707713,1"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<rect width="12" height="2" x="2" y="3" fill="#6E6E6E"/> <rect width="12" height="2" x="2" y="3" fill="#6E6E6E"/>

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 467 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#6E6E6E" d="M6.53206047,5.10906 C6.68535547,4.77581 6.77200047,4.40923501 6.77200047,4.01600001 C6.77200047,2.54303502 5.57896548,1.35000002 4.10600049,1.35000002 C2.63303549,1.35000002 1.4400005,2.54303502 1.4400005,4.01600001 C1.4400005,5.488965 2.63303549,6.68199999 4.10600049,6.68199999 C4.49923548,6.68199999 4.86581048,6.59535499 5.19906048,6.44205999 L6.77200047,8.01499999 L5.19906048,9.58793998 C4.86581048,9.43464498 4.49923548,9.34799998 4.10600049,9.34799998 C2.63303549,9.34799998 1.4400005,10.541035 1.4400005,12.014 C1.4400005,13.486965 2.63303549,14.6799999 4.10600049,14.6799999 C5.57896548,14.6799999 6.77200047,13.486965 6.77200047,12.014 C6.77200047,11.620765 6.68535547,11.25419 6.53206047,10.92094 L8.10500046,9.34799998 L12.7705004,14 L14.7700004,14 L14.7700004,13.347 L6.53206047,5.10906 Z M4.1053342,5.33702364 C3.37236745,5.33702364 2.77266738,4.74383861 2.77266738,4.00402356 C2.77266738,3.26420851 3.37236745,2.67102348 4.1053342,2.67102348 C4.83830096,2.67102348 5.43800103,3.26420851 5.43800103,4.00402356 C5.43800103,4.74383861 4.83830096,5.33702364 4.1053342,5.33702364 Z M4.1053342,13.3350241 C3.37236745,13.3350241 2.77266738,12.7418391 2.77266738,12.0020241 C2.77266738,11.262209 3.37236745,10.669024 4.1053342,10.669024 C4.83830096,10.669024 5.43800103,11.262209 5.43800103,12.0020241 C5.43800103,12.7418391 4.83830096,13.3350241 4.1053342,13.3350241 Z M8.10333468,8.33627383 C7.91676132,8.33627383 7.77016797,8.18964382 7.77016797,8.00302381 C7.77016797,7.8164038 7.91676132,7.66977379 8.10333468,7.66977379 C8.28990803,7.66977379 8.43650138,7.8164038 8.43650138,8.00302381 C8.43650138,8.18964382 8.28990803,8.33627383 8.10333468,8.33627383 Z M12.7710002,2.00452344 L8.77299971,6.00352368 L10.1056665,7.33652377 L14.7700004,2.67102348 L14.7700004,2.00452344 L12.7710002,2.00452344 Z"/> <path fill="#6E6E6E" d="M6.53206047,5.10906 C6.68535547,4.77581 6.77200047,4.40923501 6.77200047,4.01600001 C6.77200047,2.54303502 5.57896548,1.35000002 4.10600049,1.35000002 C2.63303549,1.35000002 1.4400005,2.54303502 1.4400005,4.01600001 C1.4400005,5.488965 2.63303549,6.68199999 4.10600049,6.68199999 C4.49923548,6.68199999 4.86581048,6.59535499 5.19906048,6.44205999 L6.77200047,8.01499999 L5.19906048,9.58793998 C4.86581048,9.43464498 4.49923548,9.34799998 4.10600049,9.34799998 C2.63303549,9.34799998 1.4400005,10.541035 1.4400005,12.014 C1.4400005,13.486965 2.63303549,14.6799999 4.10600049,14.6799999 C5.57896548,14.6799999 6.77200047,13.486965 6.77200047,12.014 C6.77200047,11.620765 6.68535547,11.25419 6.53206047,10.92094 L8.10500046,9.34799998 L12.7705004,14 L14.7700004,14 L14.7700004,13.347 L6.53206047,5.10906 Z M4.1053342,5.33702364 C3.37236745,5.33702364 2.77266738,4.74383861 2.77266738,4.00402356 C2.77266738,3.26420851 3.37236745,2.67102348 4.1053342,2.67102348 C4.83830096,2.67102348 5.43800103,3.26420851 5.43800103,4.00402356 C5.43800103,4.74383861 4.83830096,5.33702364 4.1053342,5.33702364 Z M4.1053342,13.3350241 C3.37236745,13.3350241 2.77266738,12.7418391 2.77266738,12.0020241 C2.77266738,11.262209 3.37236745,10.669024 4.1053342,10.669024 C4.83830096,10.669024 5.43800103,11.262209 5.43800103,12.0020241 C5.43800103,12.7418391 4.83830096,13.3350241 4.1053342,13.3350241 Z M8.10333468,8.33627383 C7.91676132,8.33627383 7.77016797,8.18964382 7.77016797,8.00302381 C7.77016797,7.8164038 7.91676132,7.66977379 8.10333468,7.66977379 C8.28990803,7.66977379 8.43650138,7.8164038 8.43650138,8.00302381 C8.43650138,8.18964382 8.28990803,8.33627383 8.10333468,8.33627383 Z M12.7710002,2.00452344 L8.77299971,6.00352368 L10.1056665,7.33652377 L14.7700004,2.67102348 L14.7700004,2.00452344 L12.7710002,2.00452344 Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,3 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<path fill="#6E6E6E" fill-rule="evenodd" d="M3,1 L3,0 L7,0 L7,1 L10,1 L10,13 L0,13 L0,1 L3,1 Z M4,1 L4,2 L6,2 L6,1 L4,1 Z M2,4 L2,11 L8,11 L8,4 L2,4 Z" transform="translate(3 1)"/> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="menu-paste">
<g id="paste">
<path id="Shape" fill-rule="evenodd" clip-rule="evenodd" d="M6 2V1H10V2H13V14H3V2H6ZM7 2V3H9V2H7ZM5 5V12H11V5H5Z" fill="#6E6E6E"/>
</g>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 274 B

After

Width:  |  Height:  |  Size: 426 B

View File

@@ -1,3 +1,4 @@
<!-- Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">
<path fill="#9AA7B0" fill-opacity=".8" d="M1,1 L15,1 L15,14 L1,14 L1,1 Z M2,4 L2,13 L14,13 L14,4 L2,4 Z"/> <path fill="#9AA7B0" fill-opacity=".8" d="M1,1 L15,1 L15,14 L1,14 L1,1 Z M2,4 L2,13 L14,13 L14,4 L2,4 Z"/>

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 473 B

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