Compare commits

...

127 Commits
0.13 ... 0.20

Author SHA1 Message Date
Karl Tauber
6ee5234351 release 0.20
(skipping 0.19)
2019-11-29 16:36:21 +01:00
Karl Tauber
398a041ddf screenshots updated 2019-11-29 16:35:28 +01:00
Karl Tauber
02bb73c335 FileChooser: scale file chooser size (issue #5) 2019-11-29 10:29:28 +01:00
Karl Tauber
f37c4cdc4d IntelliJ Themes: added "Save" and "GitHub" buttons to themes list toolbar in demo (and testing apps) to allow users quickly save .theme.json files (including license) or visit theme source code repository 2019-11-29 10:24:04 +01:00
Karl Tauber
d5c9bcddc8 fixed "cannot find symbol" error in NetBeans editor, when source/binary format is set to JDK 9 (or later) in NetBeans project (issue #13)
flatlaf.jar is no longer a multi-release jar
2019-11-28 19:04:42 +01:00
Karl Tauber
f3f8c81518 SwingX: JXTitledPanel support (issue #22) 2019-11-28 18:29:47 +01:00
Karl Tauber
a99ffd4821 fixed color of links in HTML text 2019-11-28 17:06:45 +01:00
Karl Tauber
7b5a9d9949 Demo: added square buttons 2019-11-28 11:29:09 +01:00
Karl Tauber
feb8d0591e Button: make button square if button text is "..." or a single character 2019-11-28 10:55:10 +01:00
Karl Tauber
2197808631 ComboBox: fixed issues with NetBeans org.openide.awt.ColorComboBox component 2019-11-28 10:33:26 +01:00
Karl Tauber
36b3ccc34f IntelliJ Themes: fixes for ScrollBar 2019-11-27 23:51:27 +01:00
Karl Tauber
a5b69d712c IntelliJ Themes Demo: updated themes (used IJThemesUpdater) 2019-11-26 16:26:03 +01:00
Karl Tauber
8edcca9745 IntelliJ Themes Demo: IJThemesUpdater tool added to update themes from source code repositories 2019-11-26 13:31:44 +01:00
Karl Tauber
f3b1f4b608 IntelliJ Themes Demo: replaced themes.properties with themes.json 2019-11-26 11:39:29 +01:00
Karl Tauber
879a8aaa6d renamed FlatLaf.initColorPalette() to initIconColors() 2019-11-26 11:06:13 +01:00
Karl Tauber
900d005d89 IntelliJ Themes: fixes for ComboBox, Spinner, CheckBox and RadioButton 2019-11-26 10:41:11 +01:00
Karl Tauber
c8225171a3 IntelliJ Themes: avoid double setting LaFs 2019-11-26 00:41:47 +01:00
Karl Tauber
c513c052fc SwingX: fixed too wide border when using date picker as table cell editor (issue #24) 2019-11-26 00:05:38 +01:00
Karl Tauber
711c4dd2b5 hex color values in .properties files now must start with a # character 2019-11-25 19:10:51 +01:00
Karl Tauber
81f1ebd1db added readme files to sub-projects 2019-11-24 16:59:13 +01:00
Karl Tauber
c722934510 look and feel identifier returned by FlatLaf.getID() now always starts with "FlatLaf" 2019-11-24 14:08:38 +01:00
Karl Tauber
3ffe8e225d IntelliJ Themes: fixes for Slider:
- use Component.focusColor if Slider.focusedColor is not set (which is the case in all IntelliJ themes)
- compute hover color based on thumb color
- ignore Slider.trackWidth (used in Material Theme UI Lite)
2019-11-24 12:58:38 +01:00
Karl Tauber
6d86cf8f9c IntelliJ Themes: added more popular open-source IntelliJ themes to demo
(downloaded latest .theme.json from source repos;
see themes.properties for source repo URLs)
2019-11-21 13:17:06 +01:00
Karl Tauber
e6e19110b2 HSLColor: fixed javadoc errors 2019-11-20 17:21:49 +01:00
Karl Tauber
b5c13bd1b3 IntelliJ Themes: fixes for ProgressBar 2019-11-20 17:09:49 +01:00
Karl Tauber
b129fe437c JIDE: fixed JidePopup border 2019-11-20 17:01:23 +01:00
Karl Tauber
645be4bfa3 IntelliJ Themes: Tree: fixed renderer background 2019-11-18 19:16:48 +01:00
Karl Tauber
321c49ee32 OptionPane: fixed button order on Mac 2019-11-18 17:31:24 +01:00
Karl Tauber
84db2f9b65 OptionPane:
- fixed background, which was wrong when OptionPane.background is different to Panel.background (e.g. in Hiberbee or Solarized themes)
- use non-UIResource borders in sub-panels to avoid that they are replaced when switching LaF
2019-11-18 13:12:27 +01:00
Karl Tauber
6ba1a419bc FlatSVGIcon:
- use SVGDiagram directly instead of using SVGIcon
- check cliping bounds before painting
- paint red box on errors
2019-11-17 13:04:46 +01:00
Karl Tauber
3de329a332 moved ScaledSVGIcon.java from demo to flatlaf-extras and renamed to FlatSVGIcon.java 2019-11-16 23:23:02 +01:00
Karl Tauber
f175c36736 IntelliJ Themes: OptionPane: use colors for error/information/question/warning icons from default color palette, which enables modification of icon colors by theme 2019-11-16 21:55:28 +01:00
Karl Tauber
f1de65b471 UI inspector: support anonymous classes 2019-11-16 20:13:37 +01:00
Karl Tauber
5069013e6e FileChooser implemented (issue #5) 2019-11-16 17:21:28 +01:00
Karl Tauber
c0642ed620 IntelliJ Themes: apply action/object icons color palette from .theme.json to FlatLaf default color palette in UI defaults 2019-11-16 13:36:19 +01:00
Karl Tauber
a145673dd1 use chevron arrows for table header ascending/descending sort icons (#7) 2019-11-15 23:41:26 +01:00
Karl Tauber
223af48c09 added default color palette for action icons and object icons (based on IntelliJ Platform colors)
and use color palette for file chooser icons (issue #5)
2019-11-15 23:40:52 +01:00
Karl Tauber
d72cfc37d6 fixed jittery submenu rendering on Mac (issue #10) 2019-11-15 18:24:22 +01:00
Karl Tauber
3ba8133890 Table: fixed selection background of checkbox in table cell 2019-11-14 12:33:04 +01:00
Karl Tauber
a907cd7f46 IntelliJ Themes: fixes for text component disabled backgrounds, button backgrounds, combobox disabled backgrounds and spinner disabled backgrounds 2019-11-14 11:28:38 +01:00
Karl Tauber
3b740cb494 IntelliJ Themes: fixes for ComboBox, text components and Spinner 2019-11-13 19:17:34 +01:00
Karl Tauber
0f0f21a7b1 IntelliJ Themes Demo: refresh themes list (from current working directory) on window activation 2019-11-13 13:54:17 +01:00
Karl Tauber
537f6703c0 IntelliJ Themes Demo: search for .theme.json files in current working directory and show them in themes list 2019-11-13 13:53:01 +01:00
Karl Tauber
da0c562ac2 FlatTestFrame: fixed exception when changing scale factor (when running in Java 8) 2019-11-13 10:48:20 +01:00
Karl Tauber
0bef71907c IntelliJ Themes: added core themes to list of themes 2019-11-13 10:44:39 +01:00
Karl Tauber
0ebd43bc5f IntelliJ Themes:
- added themes list to demo (and testing) apps
- added some popular open-source IntelliJ themes to demo
  (downloaded latest .theme.json from source repos;
  see themes.properties for source repo URLs)
2019-11-12 19:23:20 +01:00
Karl Tauber
3092fced3c Demo: moved Laf combobox related code to new class LookAndFeelsComboBox 2019-11-12 16:30:41 +01:00
Karl Tauber
a02784fcba IntelliJ Themes: fixes for Button, CheckBox, RadioButton, ComboBox and Spinner 2019-11-12 12:40:20 +01:00
Karl Tauber
924abde89e StringUtils added 2019-11-12 10:19:56 +01:00
Karl Tauber
f011468819 IntelliJ Themes: use single Laf class for light and dark IntelliJ themes and added IntelliJTheme$ThemeLaf.properties to allow (re-)setting UI defaults before .theme.json is applied 2019-11-12 10:11:26 +01:00
Karl Tauber
11f459d5b0 IntelliJ Themes:
- support theming check boxes and radio buttons
- fixed button background and border
2019-11-11 22:55:40 +01:00
Karl Tauber
974f7d5d68 IntelliJ Themes: reworked applying values so that it works and behaves the same way as in IntelliJ Platform 2019-11-11 18:35:31 +01:00
Karl Tauber
e60db4ff90 IntelliJ Themes: basic support for loading and applying IntelliJ Platform themes in .theme.json format 2019-11-11 16:25:37 +01:00
Karl Tauber
ebe1cd3367 IntelliJ Themes: added internal json parser for parsing IntelliJ .theme.json files
this is a partly copy of https://github.com/ralfstx/minimal-json (license is MIT)
2019-11-11 13:46:36 +01:00
Karl Tauber
30db9d13a5 UIDefaultsLoader:
- detect colors and UIs
- fixed parsing of colors with transparency
- allow '#' prefix colors
2019-11-11 13:39:11 +01:00
Karl Tauber
368611359c documented used UI defaults in most UI delegates 2019-11-10 18:18:57 +01:00
Karl Tauber
746918c054 README.md: fixed link to "JIDE Common Layer" addon 2019-11-10 10:26:34 +01:00
Karl Tauber
6572198178 release 0.18 2019-11-10 10:06:59 +01:00
Karl Tauber
f69b3f56dd ToolTip: use anti-aliasing to render multi-line tooltips 2019-11-10 00:09:51 +01:00
Karl Tauber
c379f2f3b0 JIDE: added missing dependency to flatlaf-testing project 2019-11-09 18:51:52 +01:00
Karl Tauber
e7194e43b4 JIDE: README.md added and publishing added to build.gradle.kts 2019-11-09 18:44:31 +01:00
Karl Tauber
883b282cd8 JIDE: JideTabbedPane: hover tab event if mouse is over close button
unfortunately it is not possible to replace JIDEs arrow and close buttons with own implementations
2019-11-09 18:21:25 +01:00
Karl Tauber
7c2b2d7f26 JIDE: basic JideTabbedPane implementation 2019-11-09 17:23:55 +01:00
Karl Tauber
08f525de5f TabbedPane: content pane is no longer opaque and use antialiasing for painting separator and content border 2019-11-09 15:53:02 +01:00
Karl Tauber
433659a5df TabbedPane: no longer modify BasicTabbedPaneUI.contentBorderInsets in getContentBorderInsets() because this is useless and confusing 2019-11-09 13:57:39 +01:00
Karl Tauber
7f50a30b29 TabbedPane: reworked painting in scroll-tab-layout, so that the separator line now spans the whole width and is no longer interrupted by the scroll buttons 2019-11-09 10:58:31 +01:00
Karl Tauber
d5944779e8 TabbedPane: use FlatClientProperties for JTabbedPane.hasFullBorder client property 2019-11-08 23:01:33 +01:00
Karl Tauber
fdaea31475 JIDE: flatlaf-jide-oss subproject created 2019-11-08 15:51:28 +01:00
Karl Tauber
a66ebd29b4 update to Gradle 5.6.4
./gradlew wrapper --gradle-version=5.6.4
2019-11-07 18:24:33 +01:00
Karl Tauber
f3006467e9 TextField and TextArea: do not apply minimum width if columns property > 0 2019-10-30 15:14:23 +01:00
Karl Tauber
aa52af4c8f added FlatLaf.isDark() 2019-10-29 11:01:48 +01:00
Karl Tauber
2e0fde464d release 0.17 2019-10-27 12:29:12 +01:00
Karl Tauber
9bf0124950 FlatBorder: replaced Paint with Color 2019-10-27 12:27:31 +01:00
Karl Tauber
eaa6db1d19 Table: fixed missing upper right corner (e.g. in SwingX JXTable with column control visible) 2019-10-27 12:25:39 +01:00
Karl Tauber
2ec142f000 Button: hover and pressed background colors are now derived from actual button background color (issue #21) 2019-10-27 11:03:40 +01:00
Karl Tauber
ec572436a9 extracted properties file parsing to new class UIDefaultsLoader 2019-10-25 23:07:44 +02:00
Karl Tauber
6e5e548c9d Testing: fixed content panel insets and removed 5,5 gaps 2019-10-25 10:44:24 +02:00
Karl Tauber
61c3bbad60 ComboBox and Spinner:
- make child components explicitly non-opaque
- paint parent background only if necessary
2019-10-25 10:28:24 +02:00
Karl Tauber
bc10c4e871 Made JComboBox, JProgressBar, JSpinner and JXDatePicker non-opaque.
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
an outside focus border (e.g. IntelliJ and Darcula themes).
(issues #20 and #17)
2019-10-25 10:28:18 +02:00
Karl Tauber
8b8d84c2a3 TextField and PasswordField: reduced duplicate code 2019-10-24 20:47:31 +02:00
Karl Tauber
5743b5d59f CheckBox: removed accidentally checked in debug output 2019-10-24 18:07:22 +02:00
Karl Tauber
9450ba5e46 Extras: fixed link in README.md 2019-10-24 15:31:13 +02:00
Karl Tauber
cfcbf3e61c CheckBox:
- compute focus border arc based on Component.focusWidth
- allow specifying border arc in UI defaults (CheckBox.arc)
2019-10-24 14:28:50 +02:00
Karl Tauber
136481c110 Testing: added "opaque" checkbox to test apps 2019-10-24 12:44:16 +02:00
Karl Tauber
7f43b3003c TriStateCheckBox component added 2019-10-24 12:36:40 +02:00
Karl Tauber
1b0c2687c8 Testing: added "background" checkbox to test apps 2019-10-24 10:52:53 +02:00
Karl Tauber
aeb80f862b build.gradle.kts: depend task "assemble" on "sourcesJar" and "javadocJar" so that they are built on Travic CI to file problems early (previously those tasks were build only just before publishing) 2019-10-23 17:06:25 +02:00
Karl Tauber
1de367e19e moved testing applications from src/test to new project flatlaf-testing (part 2) 2019-10-23 16:44:39 +02:00
Karl Tauber
62895a602f moved testing applications from src/test to new project flatlaf-testing (part 1) 2019-10-23 16:44:19 +02:00
Karl Tauber
6438e890bb release 0.16 2019-10-23 10:46:46 +02:00
Karl Tauber
7d72b13ac9 made JButton, JCheckBox, JRadioButton, JToggleButton and JSlider non-opaque (#20) 2019-10-23 10:36:33 +02:00
Karl Tauber
a2e21cb07b fixed Java 9 module descriptor (broken since 0.14) 2019-10-23 09:55:55 +02:00
Karl Tauber
06766cb4db Demo: missing SwingUtilities.invokeLater() added 2019-10-23 09:03:08 +02:00
Karl Tauber
72e8ab70a3 Demo: tooltips added to toolbar buttons 2019-10-22 12:09:04 +02:00
Karl Tauber
0f38af5922 ComboBox: right-to-left fixes (#18) 2019-10-22 12:07:23 +02:00
Karl Tauber
4181759008 right-to-left fixes:
-Slider: colored track (if ticks and labels are hidden) was on the left side of the thumb
- ToolTip: multi-line text was not aligned to the right

(issue #18)
2019-10-21 22:12:51 +02:00
Karl Tauber
fff0e5e946 fixed FlatTestLaf (broken by commit 342b932f9e) 2019-10-21 20:11:35 +02:00
Karl Tauber
be88eeb343 release 0.15 2019-10-21 18:29:40 +02:00
Karl Tauber
342b932f9e ToolTip:
- Improved styling of dark tooltips (darker background, no border).
- increased top and bottom margins
- use brighter color in light theme
- Fixed colors in tooltips of disabled components. (issue #15)
2019-10-21 18:07:43 +02:00
Karl Tauber
964dc14a8a ComboBox: fixed NPE in combobox with custom renderer after switching to FlatLaf (#16; regression in 0.14) 2019-10-21 17:04:23 +02:00
Karl Tauber
b56f462626 SwingX: added screenshots 2019-10-21 13:42:22 +02:00
Karl Tauber
4477b4c44e release 0.14 2019-10-21 10:52:33 +02:00
Karl Tauber
714c6e2920 TextField and PasswordField: fixed minimum width if focusWidth > 2 and not having a FlatBorder 2019-10-20 22:17:15 +02:00
Karl Tauber
0853a1aa2e SwingX: fixed preferred width of JXDatePicker, which was too large (#8) 2019-10-20 22:16:13 +02:00
Karl Tauber
f9d2312b3a ComboBox: fixed StackOverflowError when switching LaF (#14) 2019-10-20 20:04:10 +02:00
Karl Tauber
f53f205f52 SwingX: fixed JXDatePicker.TodayPanel colors (#8) 2019-10-20 18:18:06 +02:00
Karl Tauber
41ecbccc76 EditorPane and TextPane: fixed font and text color when using HTML content (#9) 2019-10-20 18:17:47 +02:00
Karl Tauber
5a952c187c SwingX: JXMonthView support (#8) 2019-10-20 10:47:53 +02:00
Karl Tauber
0a86d00c1e FlatLaf: allow specifying value type in value for cases where auto-detecting value type from key or value does not work 2019-10-19 13:47:53 +02:00
Karl Tauber
b3e9d82537 SwingX: added SwingX LaF addon (#8) 2019-10-19 09:36:43 +02:00
Karl Tauber
0970dceee2 SwingX: JXDatePicker support (#8) 2019-10-19 09:35:01 +02:00
Karl Tauber
ffef71d6db OptionPane: fixed rendering of longer HTML text (#12) 2019-10-18 18:41:14 +02:00
Karl Tauber
0ede8cd5b9 SwingX: build.gradle.kts: added maven publishing and bintray upload 2019-10-18 14:36:04 +02:00
Karl Tauber
c1a9f48e6b SwingX: JXBusyLabel support (#8) 2019-10-18 13:26:30 +02:00
Karl Tauber
3f7215c602 update to Gradle 5.6.3
./gradlew wrapper --gradle-version=5.6.3
2019-10-18 10:34:39 +02:00
Karl Tauber
8b5e3e344a SwingX: JXHeader support (#8) 2019-10-18 10:33:05 +02:00
Karl Tauber
212ff012d6 SwingX: JXTaskPaneContainer and JXTaskPane support (#8) 2019-10-18 10:31:24 +02:00
Karl Tauber
7c77b857f6 SwingX: added test app 2019-10-17 12:09:22 +02:00
Karl Tauber
423c01074a SwingX: flatlaf-swingx subproject created; JXHyperlink support (#8) 2019-10-17 11:21:23 +02:00
Karl Tauber
2dbd584e28 use KeyEventPostProcessor instead of AWTEventListener for listening for Alt key pressed (similar to WindowLookAndFeel) (#4) 2019-10-16 19:42:55 +02:00
Karl Tauber
250f435ceb build.gradle.kts: moved jcenter to root script 2019-10-16 19:39:41 +02:00
Karl Tauber
fa4e409555 ToolBar: disable focusability of buttons in toolbar 2019-10-15 19:00:51 +02:00
Karl Tauber
dfc3b7c796 README.md: intro updated 2019-10-15 11:40:19 +02:00
Karl Tauber
41df9859ad ComboBox: use small border if used as table editor 2019-10-15 10:41:28 +02:00
Karl Tauber
a8b8cbdf8c FlatTestFrame: reduced duplicate code 2019-10-14 17:55:38 +02:00
Karl Tauber
fe2909c56a Demo: build.gradle.kts: added bintray upload 2019-10-14 10:59:45 +02:00
Karl Tauber
3a2fe06c34 README.md: added Maven Central coordinates 2019-10-13 22:54:41 +02:00
254 changed files with 43938 additions and 1542 deletions

View File

@@ -1,6 +1,84 @@
FlatLaf Change Log FlatLaf Change Log
================== ==================
## 0.20
- Support using IntelliJ platform themes (.theme.json files).
- Support `JFileChooser`. (issue #5)
- Look and feel identifier returned by `FlatLaf.getID()` now always starts with
"FlatLaf". Use `UIManager.getLookAndFeel().getID().startsWith( "FlatLaf" )` to
check whether the current look and feel is FlatLaf.
- Fixed selection background of checkbox in table cell.
- Fixed color of links in HTML text.
- Fixed jittery submenu rendering on Mac. (issue #10)
- Fixed "cannot find symbol" error in NetBeans editor, when source/binary format
is set to JDK 9 (or later) in NetBeans project. (issue #13)
- Button: Make button square if button text is "..." or a single character.
- ComboBox: Fixed issues with NetBeans `org.openide.awt.ColorComboBox`
component.
- Hex color values in `.properties` files now must start with a `#` character.
- SwingX: Support `JXTitledPanel`. (issue #22)
- SwingX: Fixed too wide border when using date picker as table cell editor.
(issue #24)
- JIDE Common Layer: Fixed `JidePopup` border.
## 0.18
- TextField and TextArea: Do not apply minimum width if `columns` property is
greater than zero.
- TabbedPane: In scroll-tab-layout, the separator line now spans the whole width
and is no longer interrupted by the scroll buttons.
- TabbedPane: Content pane is no longer opaque. Use antialiasing for painting
separator and content border.
- ToolTip: Use anti-aliasing to render multi-line tooltips.
- JIDE Common Layer: Support `JideTabbedPane`.
## 0.17
- CheckBox: Support painting a third state (set client property
"JButton.selectedState" to "indeterminate").
- `TriStateCheckBox` component added (see [FlatLaf Extras](flatlaf-extras)).
- Made `JComboBox`, `JProgressBar`, `JSpinner` and `JXDatePicker` non-opaque.
`JPasswordField`, `JScrollPane` and `JTextField` are non-opaque if they have
an outside focus border (e.g. IntelliJ and Darcula themes). (issues #20 and
#17)
- Button: Hover and pressed background colors are now derived from actual button
background color. (issue #21)
- Table: Fixed missing upper right corner (e.g. in SwingX JXTable with column
control visible).
## 0.16
- Made some fixes for right-to-left support in ComboBox, Slider and ToolTip.
(issue #18)
- Fixed Java 9 module descriptor (broken since 0.14).
- Made `JButton`, `JCheckBox`, `JRadioButton`, `JToggleButton` and `JSlider`
non-opaque. (issue #20)
## 0.15
- ToolTip: Improved styling of dark tooltips (darker background, no border).
- ToolTip: Fixed colors in tooltips of disabled components. (issue #15)
- ComboBox: Fixed NPE in combobox with custom renderer after switching to
FlatLaf. (issue #16; regression in 0.14)
## 0.14
- ComboBox: Use small border if used as table editor.
- ToolBar: Disable focusability of buttons in toolbar.
- OptionPane: Fixed rendering of longer HTML text. (issue #12)
- EditorPane and TextPane: Fixed font and text color when using HTML content.
(issue #9)
- ComboBox: Fixed `StackOverflowError` when switching LaF. (issue #14)
- SwingX: Support `JXBusyLabel`, `JXDatePicker`, `JXHeader`, `JXHyperlink`,
`JXMonthView`, `JXTaskPaneContainer` and `JXTaskPane`. (issue #8)
## 0.13 ## 0.13
- Added developer information to Maven POM for Maven Central publishing. - Added developer information to Maven POM for Maven Central publishing.

View File

@@ -1,21 +1,31 @@
FlatLaf - Flat Look and Feel FlatLaf - Flat Look and Feel
============================ ============================
**FlatLaf** is a modern open-source cross-platform Look and Feel for Java **FlatLaf** is a modern **open-source** cross-platform Look and Feel for Java
desktop applications. Swing desktop applications.
It looks mostly "flat" (no shadows or gradients), clean, simple and elegant. It looks almost flat (no shadows or gradients), clean, simple and elegant.
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes, FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
scales on **HiDPI** displays and runs on Java 8 or newer. scales on **HiDPI** displays and runs on Java 8 or newer.
The look is heavily inspired by **Darcula** and **IntelliJ** themes from The look is heavily inspired by **Darcula** and **IntelliJ** themes from
IntelliJ IDEA 2019.2+ and uses mostly the same colors and icons. IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
![Flat Light Demo](images/FlatLightDemo.png) ![Flat Light Demo](images/FlatLightDemo.png)
![Flat Dark Demo](images/FlatDarkDemo.png) ![Flat Dark Demo](images/FlatDarkDemo.png)
IntelliJ Platform Themes
------------------------
FlatLaf can use 3rd party themes created for IntelliJ Platform:
![Cyan Light Demo](images/CyanLightDemo.png)
![Dark Purple Demo](images/DarkPurpleDemo.png)
Demo Demo
---- ----
@@ -28,9 +38,25 @@ Requires Java 8 or newer.
Download Download
-------- --------
FlatLaf binaries are available on **JCenter** and **Maven Central**.
If you use Maven or Gradle, add a dependency with following coordinates to your
build script:
groupId: com.formdev
artifactId: flatlaf
version: 0.20
Otherwise download `flatlaf-<version>.jar` here:
[![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf/images/download.svg)](https://bintray.com/jformdesigner/flatlaf/flatlaf/_latestVersion) [![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf/images/download.svg)](https://bintray.com/jformdesigner/flatlaf/flatlaf/_latestVersion)
Download from JCenter and Maven Central is coming soon.
Addons
------
- [SwingX](flatlaf-swingx)
- [JIDE Common Layer](flatlaf-jide-oss)
Documentation Documentation

View File

@@ -14,7 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
version = "0.13" version = "0.20"
allprojects {
repositories {
jcenter()
}
}
// check required Java version // check required Java version
if( JavaVersion.current() < JavaVersion.VERSION_1_8 ) if( JavaVersion.current() < JavaVersion.VERSION_1_8 )

4
flatlaf-core/README.md Normal file
View File

@@ -0,0 +1,4 @@
FlatLaf Core
============
This sub-project contains the FlatLaf core source code.

View File

@@ -22,10 +22,6 @@ plugins {
id( "com.jfrog.bintray" ) version "1.8.4" id( "com.jfrog.bintray" ) version "1.8.4"
} }
repositories {
jcenter()
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) { if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
sourceSets { sourceSets {
create( "module-info" ) { create( "module-info" ) {
@@ -38,17 +34,19 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
} }
} }
dependencies {
testImplementation( "com.miglayout:miglayout-swing:5.2" )
testImplementation( "com.jgoodies:jgoodies-forms:1.9.0" )
}
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
tasks { tasks {
assemble {
dependsOn(
"sourcesJar",
"javadocJar"
)
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) { if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
named<JavaCompile>( "compileModuleInfoJava" ) { named<JavaCompile>( "compileModuleInfoJava" ) {
sourceCompatibility = "9" sourceCompatibility = "9"
@@ -60,12 +58,7 @@ tasks {
archiveBaseName.set( "flatlaf" ) archiveBaseName.set( "flatlaf" )
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) { if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
manifest.attributes( from( sourceSets["module-info"].output ) {
"Multi-Release" to "true"
)
into( "META-INF/versions/9" ) {
from( sourceSets["module-info"].output )
include( "module-info.class" ) include( "module-info.class" )
} }
} }

View File

@@ -27,6 +27,11 @@ public interface FlatClientProperties
String BUTTON_TYPE = "JButton.buttonType"; String BUTTON_TYPE = "JButton.buttonType";
String BUTTON_TYPE_HELP = "help"; String BUTTON_TYPE_HELP = "help";
String SELECTED_STATE = "JButton.selectedState";
String SELECTED_STATE_INDETERMINATE = "indeterminate";
String TABBED_PANE_HAS_FULL_BORDER = "JTabbedPane.hasFullBorder";
/** /**
* Checks whether a client property of a component has the given value. * Checks whether a client property of a component has the given value.
*/ */

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a dark color scheme and looks like Darcula LaF. * A Flat LaF that has a dark color scheme and looks like Darcula LaF.
* *
* The UI defaults are loaded from FlatDarculaLaf.properties, FlatDarkLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatDarculaLaf public class FlatDarculaLaf

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a dark color scheme. * A Flat LaF that has a dark color scheme.
* *
* The UI defaults are loaded from FlatDarkLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatDarkLaf public class FlatDarkLaf
@@ -37,4 +39,9 @@ public class FlatDarkLaf
public String getDescription() { public String getDescription() {
return "Flat Dark Look and Feel"; return "Flat Dark Look and Feel";
} }
@Override
public boolean isDark() {
return true;
}
} }

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.io.InputStream;
/**
* Addon for FlatLaf UI defaults.
*
* Allows loading of additional .properties files from addon JARs.
* {@link java.util.ServiceLoader} is used to load extensions of this class from addon JARs.
*
* If you extend this class in a addon JAR, you also have to add a text file named
* {@code META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon}
* to the addon JAR. The file must contain a single line with the class name.
*
* See 'flatlaf-swingx' addon for an example
*
* @author Karl Tauber
*/
public abstract class FlatDefaultsAddon
{
/**
* Finds an addon .properties file for the given LaF class and returns
* it as input stream. Or {@code null} if not found.
*/
public abstract InputStream getDefaults( Class<?> lafClass );
}

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a light color scheme and looks like IntelliJ LaF. * A Flat LaF that has a light color scheme and looks like IntelliJ LaF.
* *
* The UI defaults are loaded from FlatIntelliJLaf.properties, FlatLightLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatIntelliJLaf public class FlatIntelliJLaf

View File

@@ -16,47 +16,33 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.AWTEvent;
import java.awt.Color; 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.EventQueue; import java.awt.EventQueue;
import java.awt.Font; import java.awt.Font;
import java.awt.Insets; import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager; import java.awt.KeyboardFocusManager;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.Window; import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JTabbedPane; import javax.swing.JTabbedPane;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource; import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import com.formdev.flatlaf.ui.FlatEmptyBorder; import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.ScaledNumber;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -68,17 +54,12 @@ import com.formdev.flatlaf.util.UIScale;
public abstract class FlatLaf public abstract class FlatLaf
extends BasicLookAndFeel extends BasicLookAndFeel
{ {
private static final String VARIABLE_PREFIX = "@";
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
private static final String OPTIONAL_PREFIX = "?";
private static final String GLOBAL_PREFIX = "*.";
private BasicLookAndFeel base; private BasicLookAndFeel base;
private String desktopPropertyName; private String desktopPropertyName;
private PropertyChangeListener desktopPropertyListener; private PropertyChangeListener desktopPropertyListener;
private AWTEventListener mnemonicListener; private KeyEventPostProcessor mnemonicListener;
private static boolean altKeyPressed; private static boolean altKeyPressed;
public static boolean install( LookAndFeel newLookAndFeel ) { public static boolean install( LookAndFeel newLookAndFeel ) {
@@ -91,11 +72,21 @@ public abstract class FlatLaf
} }
} }
/**
* Returns the look and feel identifier.
* <p>
* Syntax: "FlatLaf - ${theme-name}"
* <p>
* Use {@code UIManager.getLookAndFeel().getID().startsWith( "FlatLaf" )}
* to check whether the current look and feel is FlatLaf.
*/
@Override @Override
public String getID() { public String getID() {
return getName(); return "FlatLaf - " + getName();
} }
public abstract boolean isDark();
@Override @Override
public boolean isNativeLookAndFeel() { public boolean isNativeLookAndFeel() {
return true; return true;
@@ -112,12 +103,18 @@ public abstract class FlatLaf
super.initialize(); super.initialize();
// make sure that a plain popup factory is used (otherwise sub-menu rendering
// is "jittery" on Mac, where AquaLookAndFeel installs its own popup factory)
if( PopupFactory.getSharedInstance().getClass() != PopupFactory.class )
PopupFactory.setSharedInstance( new PopupFactory() );
// add mnemonic listener // add mnemonic listener
mnemonicListener = e -> { mnemonicListener = e -> {
if( e instanceof KeyEvent && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ALT ) if( e.getKeyCode() == KeyEvent.VK_ALT )
altKeyChanged( e.getID() == KeyEvent.KEY_PRESSED ); altKeyChanged( e.getID() == KeyEvent.KEY_PRESSED );
return false;
}; };
Toolkit.getDefaultToolkit().addAWTEventListener( mnemonicListener, AWTEvent.KEY_EVENT_MASK ); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor( mnemonicListener );
// listen to desktop property changes to update UI if system font or scaling changes // listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.IS_WINDOWS ) { if( SystemInfo.IS_WINDOWS ) {
@@ -149,10 +146,13 @@ public abstract class FlatLaf
// remove mnemonic listener // remove mnemonic listener
if( mnemonicListener != null ) { if( mnemonicListener != null ) {
Toolkit.getDefaultToolkit().removeAWTEventListener( mnemonicListener ); KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor( mnemonicListener );
mnemonicListener = null; mnemonicListener = null;
} }
// restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a { color: blue; }" );
if( base != null ) if( base != null )
base.uninitialize(); base.uninitialize();
@@ -183,6 +183,9 @@ public abstract class FlatLaf
public UIDefaults getDefaults() { public UIDefaults getDefaults() {
UIDefaults defaults = getBase().getDefaults(); UIDefaults defaults = getBase().getDefaults();
// add Metal resource bundle, which is required for FlatFileChooserUI
defaults.addResourceBundle( "com.sun.swing.internal.plaf.metal.resources.metal" );
// initialize some defaults (for overriding) that are used in basic UI delegates, // initialize some defaults (for overriding) that are used in basic UI delegates,
// but are not set in MetalLookAndFeel or BasicLookAndFeel // but are not set in MetalLookAndFeel or BasicLookAndFeel
Color control = defaults.getColor( "control" ); Color control = defaults.getColor( "control" );
@@ -205,15 +208,33 @@ public abstract class FlatLaf
Object aquaMenuBarUI = useScreenMenuBar ? defaults.get( "MenuBarUI" ) : null; Object aquaMenuBarUI = useScreenMenuBar ? defaults.get( "MenuBarUI" ) : null;
initFonts( defaults ); initFonts( defaults );
loadDefaultsFromProperties( defaults ); initIconColors( defaults, isDark() );
// load defaults from properties
List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading();
if( lafClassesForDefaultsLoading != null )
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, defaults );
else
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), defaults );
// use Aqua MenuBarUI if Mac screen menubar is enabled // use Aqua MenuBarUI if Mac screen menubar is enabled
if( useScreenMenuBar ) if( useScreenMenuBar )
defaults.put( "MenuBarUI", aquaMenuBarUI ); defaults.put( "MenuBarUI", aquaMenuBarUI );
// update link color in HTML text
Color linkColor = defaults.getColor( "Component.linkColor" );
if( linkColor != null ) {
new HTMLEditorKit().getStyleSheet().addRule(
String.format( "a { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
}
return defaults; return defaults;
} }
List<Class<?>> getLafClassesForDefaultsLoading() {
return null;
}
private void initFonts( UIDefaults defaults ) { private void initFonts( UIDefaults defaults ) {
FontUIResource uiFont = null; FontUIResource uiFont = null;
@@ -251,263 +272,42 @@ public abstract class FlatLaf
} }
/** /**
* Load properties associated to Flat LaF classes and add to UI defaults. * Adds the default color palette for action icons and object icons to the given UIDefaults.
* * <p>
* Each class that extend this class may have its own .properties file * This method is public and static to allow using the color palette with
* in the same package as the class. Properties from superclasses are loaded * other LaFs (e.g. Windows LaF). To do so invoke:
* first to give subclasses a chance to override defaults. * {@code FlatLaf.initIconColors( UIManager.getLookAndFeelDefaults(), false );}
* E.g. if running FlatDarkLaf, then the FlatLaf.properties is loaded first * after
* and FlatDarkLaf.properties loaded second. * {@code UIManager.setLookAndFeel( ... );}.
* <p>
* The colors are based on IntelliJ Platform
* <a href="https://jetbrains.design/intellij/principles/icons/#action-icons">Action icons</a>
* and
* <a href="https://jetbrains.design/intellij/principles/icons/#noun-icons">Noun icons</a>
*/ */
private void loadDefaultsFromProperties( UIDefaults defaults ) { public static void initIconColors( UIDefaults defaults, boolean dark ) {
// determine classes in class hierarchy in reverse order // colors for action icons
ArrayList<Class<?>> lafClasses = new ArrayList<>(); // see https://jetbrains.design/intellij/principles/icons/#action-icons
for( Class<?> lafClass = getClass(); defaults.put( "Actions.Red", new ColorUIResource( !dark ? 0xDB5860 : 0xC75450 ) );
FlatLaf.class.isAssignableFrom( lafClass ); defaults.put( "Actions.Yellow", new ColorUIResource( !dark ? 0xEDA200 : 0xF0A732 ) );
lafClass = lafClass.getSuperclass() ) defaults.put( "Actions.Green", new ColorUIResource( !dark ? 0x59A869 : 0x499C54 ) );
{ defaults.put( "Actions.Blue", new ColorUIResource( !dark ? 0x389FD6 : 0x3592C4 ) );
lafClasses.add( 0, lafClass ); defaults.put( "Actions.Grey", new ColorUIResource( !dark ? 0x6E6E6E : 0xAFB1B3 ) );
} defaults.put( "Actions.GreyInline", new ColorUIResource( !dark ? 0x7F8B91 : 0x7F8B91 ) );
try { // colors for object icons
// load properties files // see https://jetbrains.design/intellij/principles/icons/#noun-icons
Properties properties = new Properties(); defaults.put( "Objects.Grey", new ColorUIResource( 0x9AA7B0 ) );
for( Class<?> lafClass : lafClasses ) { defaults.put( "Objects.Blue", new ColorUIResource( 0x40B6E0 ) );
String propertiesName = "/" + lafClass.getName().replace( '.', '/' ) + ".properties"; defaults.put( "Objects.Green", new ColorUIResource( 0x62B543 ) );
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) { defaults.put( "Objects.Yellow", new ColorUIResource( 0xF4AF3D ) );
if( in != null ) defaults.put( "Objects.YellowDark", new ColorUIResource( 0xD9A343 ) );
properties.load( in ); defaults.put( "Objects.Purple", new ColorUIResource( 0xB99BF8 ) );
} defaults.put( "Objects.Pink", new ColorUIResource( 0xF98B9E ) );
} defaults.put( "Objects.Red", new ColorUIResource( 0xF26522 ) );
defaults.put( "Objects.RedStatus", new ColorUIResource( 0xE05555 ) );
Function<String, String> resolver = value -> { defaults.put( "Objects.GreenAndroid", new ColorUIResource( 0xA4C639 ) );
return resolveValue( properties, value ); defaults.put( "Objects.BlackText", new ColorUIResource( 0x231F20 ) );
};
// get globals, which override all other defaults that end with same suffix
HashMap<String, Object> globals = new HashMap<>();
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( !key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
}
// override UI defaults with globals
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).contains( "." ) ) {
String skey = (String) key;
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
Object globalValue = globals.get( globalKey );
if( globalValue != null )
defaults.put( key, globalValue );
}
}
// add non-global properties to UI defaults
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
defaults.put( key, parseValue( key, value, resolver ) );
}
} catch( IOException ex ) {
ex.printStackTrace();
}
}
private String resolveValue( Properties properties, String value ) {
if( !value.startsWith( VARIABLE_PREFIX ) )
return value;
if( value.startsWith( REF_PREFIX ) )
value = value.substring( REF_PREFIX.length() );
boolean optional = false;
if( value.startsWith( OPTIONAL_PREFIX ) ) {
value = value.substring( OPTIONAL_PREFIX.length() );
optional = true;
}
String newValue = properties.getProperty( value );
if( newValue == null ) {
if( optional )
return "null";
System.err.println( "variable or reference '" + value + "' not found" );
throw new IllegalArgumentException( value );
}
return resolveValue( properties, newValue );
}
private Object parseValue( String key, String value, Function<String, String> resolver ) {
value = value.trim();
// null, false, true
switch( value ) {
case "null": return null;
case "false": return false;
case "true": return true;
}
// borders
if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
return parseBorder( value, resolver );
// icons
if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
return parseInstance( value );
// insets
if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
return parseInsets( value );
// scaled number
ScaledNumber scaledNumber = parseScaledNumber( key, value );
if( scaledNumber != null )
return scaledNumber;
// size
if( key.endsWith( "Size" ) && !key.equals( "SplitPane.dividerSize" ))
return parseSize( value );
// width, height
if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
return parseInteger( value, true );
// colors
ColorUIResource color = parseColor( value, false );
if( color != null )
return color;
// integer
Integer integer = parseInteger( value, false );
if( integer != null )
return integer;
// string
return value;
}
private Object parseBorder( String value, Function<String, String> resolver ) {
if( value.indexOf( ',' ) >= 0 ) {
// top,left,bottom,right[,lineColor]
List<String> parts = split( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() == 5)
? parseColor( resolver.apply( parts.get( 4 ) ), true )
: null;
return (LazyValue) t -> {
return (lineColor != null)
? new FlatLineBorder( insets, lineColor )
: new FlatEmptyBorder( insets );
};
} else
return parseInstance( value );
}
private Object parseInstance( String value ) {
return (LazyValue) t -> {
try {
return Class.forName( value ).newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
ex.printStackTrace();
return null;
}
};
}
private Insets parseInsets( String value ) {
List<String> numbers = split( value, ',' );
try {
return new InsetsUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ),
Integer.parseInt( numbers.get( 2 ) ),
Integer.parseInt( numbers.get( 3 ) ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid insets '" + value + "'" );
throw ex;
}
}
private Dimension parseSize( String value ) {
List<String> numbers = split( value, ',' );
try {
return new DimensionUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid size '" + value + "'" );
throw ex;
}
}
private ColorUIResource parseColor( String value, boolean reportError ) {
try {
int rgb = Integer.parseInt( value, 16 );
if( value.length() == 6 )
return new ColorUIResource( rgb );
if( value.length() == 8 )
return new ColorUIResource( new Color( rgb, true ) );
if( reportError )
throw new NumberFormatException( value );
} catch( NumberFormatException ex ) {
if( reportError ) {
System.err.println( "invalid color '" + value + "'" );
throw ex;
}
// not a color --> ignore
}
return null;
}
private Integer parseInteger( String value, boolean reportError ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
if( reportError ) {
System.err.println( "invalid integer '" + value + "'" );
throw ex;
}
}
return null;
}
private ScaledNumber parseScaledNumber( String key, String value ) {
if( !key.equals( "OptionPane.buttonMinimumWidth" ) &&
!key.equals( "SplitPane.oneTouchButtonSize" ) &&
!key.equals( "SplitPane.oneTouchButtonOffset" ) )
return null; // not supported
try {
return new ScaledNumber( Integer.parseInt( value ) );
} catch( NumberFormatException ex ) {
System.err.println( "invalid integer '" + value + "'" );
throw ex;
}
}
public static List<String> split( String str, char delim ) {
ArrayList<String> strs = new ArrayList<>();
int delimIndex = str.indexOf( delim );
int index = 0;
while( delimIndex >= 0 ) {
strs.add( str.substring( index, delimIndex ) );
index = delimIndex + 1;
delimIndex = str.indexOf( delim, index );
}
strs.add( str.substring( index ) );
return strs;
} }
private static void reSetLookAndFeel() { private static void reSetLookAndFeel() {

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf;
/** /**
* A Flat LaF that has a light color scheme. * A Flat LaF that has a light color scheme.
* *
* The UI defaults are loaded from FlatLightLaf.properties and FlatLaf.properties
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatLightLaf public class FlatLightLaf
@@ -37,4 +39,9 @@ public class FlatLightLaf
public String getDescription() { public String getDescription() {
return "Flat Light Look and Feel"; return "Flat Light Look and Feel";
} }
@Override
public boolean isDark() {
return false;
}
} }

View File

@@ -0,0 +1,488 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.StringUtils;
/**
* This class supports loading IntelliJ .theme.json files and using them as a Laf.
*
* .theme.json files are used by Theme plugins for IntelliJ IDEA and other
* JetBrains IDEs that are based on IntelliJ platform.
*
* Here you can find IntelliJ Theme plugins:
* https://plugins.jetbrains.com/search?tags=Theme
*
* The IntelliJ .theme.json file are documented here:
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html
*
* @author Karl Tauber
*/
public class IntelliJTheme
{
public final String name;
public final boolean dark;
public final String author;
private final Map<String, String> colors;
private final Map<String, Object> ui;
private final Map<String, Object> icons;
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
/**
* Loads a IntelliJ .theme.json file from the given input stream,
* creates a Laf instance for it and installs it.
*
* The input stream is automatically closed.
* Using a buffered input stream is not necessary.
*/
public static boolean install( InputStream in ) {
try {
return FlatLaf.install( createLaf( in ) );
} catch( Exception ex ) {
System.err.println( "Failed to load IntelliJ theme" );
ex.printStackTrace();
return false;
}
}
/**
* Loads a IntelliJ .theme.json file from the given input stream and
* creates a Laf instance for it.
*
* The input stream is automatically closed.
* Using a buffered input stream is not necessary.
*/
public static FlatLaf createLaf( InputStream in )
throws IOException, ParseException
{
return createLaf( new IntelliJTheme( in ) );
}
/**
* Creates a Laf instance for the given IntelliJ theme.
*/
public static FlatLaf createLaf( IntelliJTheme theme ) {
return new ThemeLaf( theme );
}
/**
* Loads a IntelliJ .theme.json file from the given input stream.
*
* The input stream is automatically closed.
* Using a buffered input stream is not necessary.
*/
@SuppressWarnings( "unchecked" )
public IntelliJTheme( InputStream in )
throws IOException, ParseException
{
Map<String, Object> json;
try( Reader reader = new InputStreamReader( in, StandardCharsets.UTF_8 ) ) {
json = (Map<String, Object>) Json.parse( reader );
}
name = (String) json.get( "name" );
dark = Boolean.parseBoolean( (String) json.get( "dark" ) );
author = (String) json.get( "author" );
colors = (Map<String, String>) json.get( "colors" );
ui = (Map<String, Object>) json.get( "ui" );
icons = (Map<String, Object>) json.get( "icons" );
}
private void applyProperties( UIDefaults defaults ) {
if( ui == null )
return;
defaults.put( "Component.isIntelliJTheme", true );
loadNamedColors( defaults );
// convert Json "ui" structure to UI defaults
ArrayList<Object> defaultsKeysCache = new ArrayList<>();
Set<String> uiKeys = new HashSet<>();
for( Map.Entry<String, Object> e : ui.entrySet() )
apply( e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
applyColorPalette( defaults );
applyCheckBoxColors( defaults );
// IDEA uses TextField.background for editable ComboBox and Spinner
defaults.put( "ComboBox.editableBackground", defaults.get( "TextField.background" ) );
defaults.put( "Spinner.background", defaults.get( "TextField.background" ) );
// Spinner arrow button always has same colors as ComboBox arrow button
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
defaults.put( "Spinner.buttonArrowColor", defaults.get( "ComboBox.buttonArrowColor" ) );
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
// some themes specify colors for TextField.background, but forget to specify it for other components
// (probably because those components are not used in IntelliJ)
if( uiKeys.contains( "TextField.background" ) ) {
Object textFieldBackground = defaults.get( "TextField.background" );
if( !uiKeys.contains( "FormattedTextField.background" ) )
defaults.put( "FormattedTextField.background", textFieldBackground );
if( !uiKeys.contains( "PasswordField.background" ) )
defaults.put( "PasswordField.background", textFieldBackground );
if( !uiKeys.contains( "EditorPane.background" ) )
defaults.put( "EditorPane.background", textFieldBackground );
if( !uiKeys.contains( "TextArea.background" ) )
defaults.put( "TextArea.background", textFieldBackground );
if( !uiKeys.contains( "TextPane.background" ) )
defaults.put( "TextPane.background", textFieldBackground );
if( !uiKeys.contains( "Spinner.background" ) )
defaults.put( "Spinner.background", textFieldBackground );
}
}
/**
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#defining-named-colors
*/
private void loadNamedColors( UIDefaults defaults ) {
if( colors == null )
return;
namedColors = new HashMap<>();
for( Map.Entry<String, String> e : colors.entrySet() ) {
String value = e.getValue();
ColorUIResource color = UIDefaultsLoader.parseColor( value );
if( color != null ) {
String key = e.getKey();
namedColors.put( key, color );
defaults.put( "ColorPalette." + e.getKey(), color );
}
}
}
/**
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#custom-ui-control-colors
*/
@SuppressWarnings( "unchecked" )
private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) {
if( value instanceof Map ) {
for( Map.Entry<String, Object> e : ((Map<String, Object>)value).entrySet() )
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
} else {
uiKeys.add( key );
// map keys
key = uiKeyMapping.getOrDefault( key, key );
if( key.isEmpty() )
return; // ignore key
String valueStr = value.toString();
// map named colors
Object uiValue = namedColors.get( valueStr );
// parse value
if( uiValue == null ) {
// fix errors (missing '#' for colors)
if( !valueStr.startsWith( "#" ) && (key.endsWith( "ground" ) || key.endsWith( "Color" )) )
valueStr = "#" + valueStr;
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) ) {
List<String> parts = StringUtils.split( valueStr, ',' );
if( parts.size() == 5 && !parts.get( 4 ).startsWith( "#" ) ) {
parts.set( 4, "#" + parts.get( 4 ) );
valueStr = String.join( ",", parts );
}
}
// parse value
try {
uiValue = UIDefaultsLoader.parseValue( key, valueStr );
} catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( key, valueStr, ex );
return; // ignore invalid value
}
}
if( key.startsWith( "*." ) ) {
// wildcard
String tail = key.substring( 1 );
// because we can not iterate over the UI defaults keys while
// modifying UI defaults in the same loop, we have to copy the keys
if( defaultsKeysCache.size() != defaults.size() ) {
defaultsKeysCache.clear();
Enumeration<Object> e = defaults.keys();
while( e.hasMoreElements() )
defaultsKeysCache.add( e.nextElement() );
}
// replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) {
if( k instanceof String ) {
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
// because it is mapped from ComboBox.ArrowButton.background)
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
if( km.endsWith( tail ) && !noWildcardReplace.contains( k ) && !((String)k).startsWith( "CheckBox.icon." ) )
defaults.put( k, uiValue );
}
}
} else
defaults.put( key, uiValue );
}
}
private void applyColorPalette( UIDefaults defaults ) {
if( icons == null )
return;
Object palette = icons.get( "ColorPalette" );
if( !(palette instanceof Map) )
return;
@SuppressWarnings( "unchecked" )
Map<String, Object> colorPalette = (Map<String, Object>) palette;
for( Map.Entry<String, Object> e : colorPalette.entrySet() ) {
String key = e.getKey();
Object value = e.getValue();
if( key.startsWith( "Checkbox." ) || !(value instanceof String) )
continue;
if( dark )
key = StringUtils.removeTrailing( key, ".Dark" );
ColorUIResource color = toColor( (String) value );
if( color != null )
defaults.put( key, color );
}
}
private ColorUIResource toColor( String value ) {
// map named colors
ColorUIResource color = namedColors.get( value );
// parse color
return (color != null) ? color : UIDefaultsLoader.parseColor( value );
}
/**
* Because IDEA uses SVGs for check boxes and radio buttons the colors for
* this two components are specified in "icons > ColorPalette".
* FlatLaf uses vector icons and expects colors for the two components in UI defaults.
*/
private void applyCheckBoxColors( UIDefaults defaults ) {
if( icons == null )
return;
Object palette = icons.get( "ColorPalette" );
if( !(palette instanceof Map) )
return;
boolean checkboxModified = false;
@SuppressWarnings( "unchecked" )
Map<String, Object> colorPalette = (Map<String, Object>) palette;
for( Map.Entry<String, Object> e : colorPalette.entrySet() ) {
String key = e.getKey();
Object value = e.getValue();
if( !key.startsWith( "Checkbox." ) || !(value instanceof String) )
continue;
if( key.equals( "Checkbox.Background.Default" ) ||
key.equals( "Checkbox.Foreground.Selected" ) )
{
// This two keys do not work correctly in IDEA because they
// map SVG color "#ffffff" to another color, but checkBox.svg and
// radio.svg (in package com.intellij.ide.ui.laf.icons.intellij)
// use "#fff". So use white to get same appearance as in IDEA.
value = "#ffffff";
}
if( dark )
key = StringUtils.removeTrailing( key, ".Dark" );
String newKey = checkboxKeyMapping.get( key );
if( newKey != null ) {
ColorUIResource color = toColor( (String) value );
if( color != null )
defaults.put( newKey, color );
checkboxModified = true;
}
}
// When IDEA replaces colors in SVGs it uses color values and not the keys
// from com.intellij.ide.ui.UITheme.colorPalette, but there are some keys that
// have same color value:
// - Checkbox.Background.Default.Dark has same color as Checkbox.Background.Selected.Dark
// - Checkbox.Border.Default.Dark has same color as Checkbox.Border.Selected.Dark
// - Checkbox.Focus.Thin.Default.Dark has same color as Checkbox.Focus.Thin.Selected.Dark
//
// So if only e.g. Checkbox.Background.Default.Dark is specified in .theme.json,
// then this color is also used for Checkbox.Background.Selected.Dark.
// Occurs e.g. in "Dark purple" theme.
fixCheckBoxColor( defaults, colorPalette, "Checkbox.Background.Default.Dark", "Checkbox.Background.Selected.Dark" );
fixCheckBoxColor( defaults, colorPalette, "Checkbox.Border.Default.Dark", "Checkbox.Border.Selected.Dark" );
fixCheckBoxColor( defaults, colorPalette, "Checkbox.Focus.Thin.Default.Dark", "Checkbox.Focus.Thin.Selected.Dark" );
// remove hover and pressed colors
if( checkboxModified ) {
defaults.remove( "CheckBox.icon.hoverBorderColor" );
defaults.remove( "CheckBox.icon.focusedBackground" );
defaults.remove( "CheckBox.icon.hoverBackground" );
defaults.remove( "CheckBox.icon.pressedBackground" );
defaults.remove( "CheckBox.icon.selectedHoverBackground" );
defaults.remove( "CheckBox.icon.selectedPressedBackground" );
}
}
private void fixCheckBoxColor( UIDefaults defaults, Map<String, Object> colorPalette, String key1, String key2 ) {
if( colorPalette.containsKey( key1 ) == colorPalette.containsKey( key2 ) )
return;
String newKey1 = checkboxKeyMapping.get( StringUtils.removeTrailing( key1, ".Dark" ) );
String newKey2 = checkboxKeyMapping.get( StringUtils.removeTrailing( key2, ".Dark" ) );
if( colorPalette.containsKey( key1 ) )
defaults.put( newKey2, defaults.get( newKey1 ) );
else
defaults.put( newKey1, defaults.get( newKey2 ) );
}
private static Map<String, String> uiKeyMapping = new HashMap<>();
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
private static Set<String> noWildcardReplace = new HashSet<>();
static {
// Button
// IDEA buttons support gradient for background and border, but FlatLaf does not
uiKeyMapping.put( "Button.startBackground", "Button.background" );
uiKeyMapping.put( "Button.startBorderColor", "Button.borderColor" );
uiKeyMapping.put( "Button.default.startBackground", "Button.default.background" );
uiKeyMapping.put( "Button.default.startBorderColor", "Button.default.borderColor" );
uiKeyMapping.put( "Button.endBackground", "" ); // ignore
uiKeyMapping.put( "Button.endBorderColor", "" ); // ignore
uiKeyMapping.put( "Button.default.endBackground", "" ); // ignore
uiKeyMapping.put( "Button.default.endBorderColor", "" ); // ignore
// ComboBox
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.nonEditableBackground", "ComboBox.background" );
uiKeyMapping.put( "ComboBox.ArrowButton.background", "ComboBox.buttonEditableBackground" );
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
// ProgressBar
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
// ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
uiKeyMapping.put( "ScrollBar.thumbColor", "ScrollBar.thumb" );
// Slider
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
uiKeyInverseMapping.put( e.getValue(), e.getKey() );
checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" );
checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
checkboxKeyMapping.put( "Checkbox.Border.Disabled", "CheckBox.icon.disabledBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Default", "CheckBox.icon.focusedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Wide", "CheckBox.icon.focusedColor" );
checkboxKeyMapping.put( "Checkbox.Foreground.Disabled", "CheckBox.icon.disabledCheckmarkColor" );
checkboxKeyMapping.put( "Checkbox.Background.Selected", "CheckBox.icon.selectedBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Selected", "CheckBox.icon.selectedBorderColor" );
checkboxKeyMapping.put( "Checkbox.Foreground.Selected", "CheckBox.icon.checkmarkColor" );
checkboxKeyMapping.put( "Checkbox.Focus.Thin.Selected", "CheckBox.icon.selectedFocusedBorderColor" );
// because FlatLaf uses Button.background and Button.borderColor,
// but IDEA uses Button.startBackground and Button.startBorderColor,
// our default button background and border colors may be replaced by
// wildcard *.background and *.borderColor colors
noWildcardReplace.add( "Button.background" );
noWildcardReplace.add( "Button.borderColor" );
noWildcardReplace.add( "Button.default.background" );
noWildcardReplace.add( "Button.default.borderColor" );
noWildcardReplace.add( "ToggleButton.background" );
}
//---- class ThemeLaf -----------------------------------------------------
public static class ThemeLaf
extends FlatLaf
{
private final IntelliJTheme theme;
public ThemeLaf( IntelliJTheme theme ) {
this.theme = theme;
}
@Override
public String getName() {
return theme.name;
}
@Override
public String getDescription() {
return theme.name;
}
@Override
public boolean isDark() {
return theme.dark;
}
public IntelliJTheme getTheme() {
return theme;
}
@Override
public UIDefaults getDefaults() {
UIDefaults defaults = super.getDefaults();
theme.applyProperties( defaults );
return defaults;
}
@Override
ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
ArrayList<Class<?>> lafClasses = new ArrayList<>();
lafClasses.add( FlatLaf.class );
lafClasses.add( theme.dark ? FlatDarkLaf.class : FlatLightLaf.class );
lafClasses.add( theme.dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( ThemeLaf.class );
return lafClasses;
}
}
}

View File

@@ -28,6 +28,7 @@ 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 javax.swing.text.StyleContext;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
@@ -151,7 +152,7 @@ class LinuxFontPolicy
int size = 10; int size = 10;
if( generalFont != null ) { if( generalFont != null ) {
List<String> strs = FlatLaf.split( generalFont, ',' ); List<String> strs = StringUtils.split( generalFont, ',' );
try { try {
family = strs.get( 0 ); family = strs.get( 0 );
size = Integer.parseInt( strs.get( 1 ) ); size = Integer.parseInt( strs.get( 1 ) );

View File

@@ -0,0 +1,478 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.function.Function;
import javax.swing.UIDefaults;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.InsetsUIResource;
import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.ScaledNumber;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Load UI defaults from properties files associated to Flat LaF classes and add to UI defaults.
*
* Each class that extend the LaF class may have its own .properties file
* in the same package as the class. Properties from superclasses are loaded
* first to give subclasses a chance to override defaults.
* E.g. if running FlatDarkLaf, then the FlatLaf.properties is loaded first
* and FlatDarkLaf.properties loaded second.
*
* @author Karl Tauber
*/
class UIDefaultsLoader
{
private static final String TYPE_PREFIX = "{";
private static final String TYPE_PREFIX_END = "}";
private static final String VARIABLE_PREFIX = "@";
private static final String REF_PREFIX = VARIABLE_PREFIX + "@";
private static final String OPTIONAL_PREFIX = "?";
private static final String GLOBAL_PREFIX = "*.";
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, UIDefaults defaults ) {
// determine classes in class hierarchy in reverse order
ArrayList<Class<?>> lafClasses = new ArrayList<>();
for( Class<?> lafClass = lookAndFeelClass;
FlatLaf.class.isAssignableFrom( lafClass );
lafClass = lafClass.getSuperclass() )
{
lafClasses.add( 0, lafClass );
}
loadDefaultsFromProperties( lafClasses, defaults );
}
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, UIDefaults defaults ) {
try {
// load properties files
Properties properties = new Properties();
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );
for( Class<?> lafClass : lafClasses ) {
// load core properties
String propertiesName = "/" + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
if( in != null )
properties.load( in );
}
// load properties from addons
for( FlatDefaultsAddon addon : addonLoader ) {
try( InputStream in = addon.getDefaults( lafClass ) ) {
if( in != null )
properties.load( in );
}
}
}
// collect all platform specific keys (but do not modify properties)
ArrayList<String> platformSpecificKeys = new ArrayList<>();
for( Object key : properties.keySet() ) {
if( ((String)key).startsWith( "[" ) )
platformSpecificKeys.add( (String) key );
}
// remove platform specific properties and re-add only properties
// for current platform, but with platform prefix removed
if( !platformSpecificKeys.isEmpty() ) {
String platformPrefix =
SystemInfo.IS_WINDOWS ? "[win]" :
SystemInfo.IS_MAC ? "[mac]" :
SystemInfo.IS_LINUX ? "[linux]" : "[unknown]";
for( String key : platformSpecificKeys ) {
Object value = properties.remove( key );
if( key.startsWith( platformPrefix ) )
properties.put( key.substring( platformPrefix.length() ), value );
}
}
Function<String, String> resolver = value -> {
return resolveValue( properties, value );
};
// get globals, which override all other defaults that end with same suffix
HashMap<String, Object> globals = new HashMap<>();
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( !key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
try {
globals.put( key.substring( GLOBAL_PREFIX.length() ), parseValue( key, value, resolver ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex );
}
}
// override UI defaults with globals
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).contains( "." ) ) {
String skey = (String) key;
String globalKey = skey.substring( skey.lastIndexOf( '.' ) + 1 );
Object globalValue = globals.get( globalKey );
if( globalValue != null )
defaults.put( key, globalValue );
}
}
// add non-global properties to UI defaults
for( Map.Entry<Object, Object> e : properties.entrySet() ) {
String key = (String) e.getKey();
if( key.startsWith( VARIABLE_PREFIX ) || key.startsWith( GLOBAL_PREFIX ) )
continue;
String value = resolveValue( properties, (String) e.getValue() );
try {
defaults.put( key, parseValue( key, value, resolver ) );
} catch( RuntimeException ex ) {
logParseError( key, value, ex );
}
}
} catch( IOException ex ) {
ex.printStackTrace();
}
}
static void logParseError( String key, String value, RuntimeException ex ) {
System.err.println( "Failed to parse: '" + key + '=' + value + '\'' );
System.err.println( " " + ex.getMessage() );
}
private static String resolveValue( Properties properties, String value ) {
if( !value.startsWith( VARIABLE_PREFIX ) )
return value;
if( value.startsWith( REF_PREFIX ) )
value = value.substring( REF_PREFIX.length() );
boolean optional = false;
if( value.startsWith( OPTIONAL_PREFIX ) ) {
value = value.substring( OPTIONAL_PREFIX.length() );
optional = true;
}
String newValue = properties.getProperty( value );
if( newValue == null ) {
if( optional )
return "null";
throw new IllegalArgumentException( "variable or reference '" + value + "' not found" );
}
return resolveValue( properties, newValue );
}
private enum ValueType { UNKNOWN, STRING, INTEGER, BORDER, ICON, INSETS, SIZE, COLOR, SCALEDNUMBER }
static Object parseValue( String key, String value ) {
return parseValue( key, value, v -> v );
}
private static Object parseValue( String key, String value, Function<String, String> resolver ) {
value = value.trim();
// null, false, true
switch( value ) {
case "null": return null;
case "false": return false;
case "true": return true;
}
ValueType valueType = ValueType.UNKNOWN;
// check whether value type is specified in the value
if( value.startsWith( "#" ) )
valueType = ValueType.COLOR;
else if( value.startsWith( TYPE_PREFIX ) ) {
int end = value.indexOf( TYPE_PREFIX_END );
if( end != -1 ) {
try {
String typeStr = value.substring( TYPE_PREFIX.length(), end );
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
// remove type from value
value = value.substring( end + TYPE_PREFIX_END.length() );
} catch( IllegalArgumentException ex ) {
// ignore
}
}
}
// determine value type from key
if( valueType == ValueType.UNKNOWN ) {
if( key.endsWith( "ground" ) || key.endsWith( "Color" ) )
valueType = ValueType.COLOR;
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) )
valueType = ValueType.BORDER;
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) )
valueType = ValueType.ICON;
else if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
valueType = ValueType.INSETS;
else if( key.endsWith( "Size" ) )
valueType = ValueType.SIZE;
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
valueType = ValueType.INTEGER;
else if( key.endsWith( "UI" ) )
valueType = ValueType.STRING;
}
// parse value
switch( valueType ) {
case STRING: return value;
case INTEGER: return parseInteger( value, true );
case BORDER: return parseBorder( value, resolver );
case ICON: return parseInstance( value );
case INSETS: return parseInsets( value );
case SIZE: return parseSize( value );
case COLOR: return parseColorOrFunction( value, true );
case SCALEDNUMBER: return parseScaledNumber( value );
case UNKNOWN:
default:
// colors
ColorUIResource color = parseColorOrFunction( value, false );
if( color != null )
return color;
// integer
Integer integer = parseInteger( value, false );
if( integer != null )
return integer;
// string
return value;
}
}
private static Object parseBorder( String value, Function<String, String> resolver ) {
if( value.indexOf( ',' ) >= 0 ) {
// top,left,bottom,right[,lineColor]
List<String> parts = StringUtils.split( value, ',' );
Insets insets = parseInsets( value );
ColorUIResource lineColor = (parts.size() == 5)
? parseColorOrFunction( resolver.apply( parts.get( 4 ) ), true )
: null;
return (LazyValue) t -> {
return (lineColor != null)
? new FlatLineBorder( insets, lineColor )
: new FlatEmptyBorder( insets );
};
} else
return parseInstance( value );
}
private static Object parseInstance( String value ) {
return (LazyValue) t -> {
try {
return Class.forName( value ).newInstance();
} catch( InstantiationException | IllegalAccessException | ClassNotFoundException ex ) {
ex.printStackTrace();
return null;
}
};
}
private static Insets parseInsets( String value ) {
List<String> numbers = StringUtils.split( value, ',' );
try {
return new InsetsUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ),
Integer.parseInt( numbers.get( 2 ) ),
Integer.parseInt( numbers.get( 3 ) ) );
} catch( NumberFormatException ex ) {
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
}
}
private static Dimension parseSize( String value ) {
List<String> numbers = StringUtils.split( value, ',' );
try {
return new DimensionUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ) );
} catch( NumberFormatException ex ) {
throw new IllegalArgumentException( "invalid size '" + value + "'" );
}
}
private static ColorUIResource parseColorOrFunction( String value, boolean reportError ) {
if( value.endsWith( ")" ) )
return parseColorFunctions( value, reportError );
return parseColor( value, reportError );
}
static ColorUIResource parseColor( String value ) {
return parseColor( value, false );
}
private static ColorUIResource parseColor( String value, boolean reportError ) {
try {
int rgba = parseColorRGBA( value );
return ((rgba & 0xff000000) == 0xff000000)
? new ColorUIResource( rgba )
: new ColorUIResource( new Color( rgba, true ) );
} catch( IllegalArgumentException ex ) {
if( reportError )
throw new IllegalArgumentException( "invalid color '" + value + "'" );
// not a color --> ignore
}
return null;
}
/**
* Parses a hex color in {@code #RGB}, {@code #RGBA}, {@code #RRGGBB} or {@code #RRGGBBAA}
* format and returns it as {@code rgba} integer suitable for {@link java.awt.Color},
* which includes alpha component in bits 24-31.
*
* @throws IllegalArgumentException
*/
static int parseColorRGBA( String value ) {
int len = value.length();
if( (len != 4 && len != 5 && len != 7 && len != 9) || value.charAt( 0 ) != '#' )
throw new IllegalArgumentException();
// parse hex
int n = 0;
for( int i = 1; i < len; i++ ) {
char ch = value.charAt( i );
int digit;
if( ch >= '0' && ch <= '9' )
digit = ch - '0';
else if( ch >= 'a' && ch <= 'f' )
digit = ch - 'a' + 10;
else if( ch >= 'A' && ch <= 'F' )
digit = ch - 'A' + 10;
else
throw new IllegalArgumentException();
n = (n << 4) | digit;
}
if( len <= 5 ) {
// double nibbles
int n1 = n & 0xf000;
int n2 = n & 0xf00;
int n3 = n & 0xf0;
int n4 = n & 0xf;
n = (n1 << 16) | (n1 << 12) | (n2 << 12) | (n2 << 8) | (n3 << 8) | (n3 << 4) | (n4 << 4) | n4;
}
return (len == 4 || len == 7)
? (0xff000000 | n) // set alpha to 255
: (((n >> 8) & 0xffffff) | ((n & 0xff) << 24)); // move alpha from lowest to highest byte
}
private static ColorUIResource parseColorFunctions( String value, boolean reportError ) {
int paramsStart = value.indexOf( '(' );
if( paramsStart < 0 ) {
if( reportError )
throw new IllegalArgumentException( "missing opening parenthesis in function '" + value + "'" );
return null;
}
String function = value.substring( 0, paramsStart ).trim();
List<String> params = StringUtils.split( value.substring( paramsStart + 1, value.length() - 1 ), ',' );
if( params.isEmpty() )
throw new IllegalArgumentException( "missing parameters in function '" + value + "'" );
switch( function ) {
case "lighten": return parseColorLightenOrDarken( true, params, reportError );
case "darken": return parseColorLightenOrDarken( false, params, reportError );
}
throw new IllegalArgumentException( "unknown color function '" + value + "'" );
}
/**
* Syntax: lighten(amount[,options]) or darken(amount[,options])
* - amount: percentage 0-100%
* - options: [relative] [autoInverse]
*/
private static ColorUIResource parseColorLightenOrDarken( boolean lighten, List<String> params, boolean reportError ) {
int amount = parsePercentage( params.get( 0 ) );
boolean relative = false;
boolean autoInverse = false;
if( params.size() >= 2 ) {
String options = params.get( 1 );
relative = options.contains( "relative" );
autoInverse = options.contains( "autoInverse" );
}
return new DerivedColor( lighten
? new ColorFunctions.Lighten( amount, relative, autoInverse )
: new ColorFunctions.Darken( amount, relative, autoInverse ) );
}
private static int parsePercentage( String value ) {
if( !value.endsWith( "%" ) )
throw new NumberFormatException( "invalid percentage '" + value + "'" );
int val;
try {
val = Integer.parseInt( value.substring( 0, value.length() - 1 ) );
} catch( NumberFormatException ex ) {
throw new NumberFormatException( "invalid percentage '" + value + "'" );
}
if( val < 0 || val > 100 )
throw new IllegalArgumentException( "percentage out of range (0-100%) '" + value + "'" );
return val;
}
private static Integer parseInteger( String value, boolean reportError ) {
try {
return Integer.parseInt( value );
} catch( NumberFormatException ex ) {
if( reportError )
throw new NumberFormatException( "invalid integer '" + value + "'" );
}
return null;
}
private static ScaledNumber parseScaledNumber( String value ) {
try {
return new ScaledNumber( Integer.parseInt( value ) );
} catch( NumberFormatException ex ) {
throw new NumberFormatException( "invalid integer '" + value + "'" );
}
}
}

View File

@@ -16,15 +16,18 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "ascendingSort" icon for {@link javax.swing.table.JTableHeader}. * "ascendingSort" icon for {@link javax.swing.table.JTableHeader}.
* *
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Table.sortIconColor Color * @uiDefault Table.sortIconColor Color
* *
* @author Karl Tauber * @author Karl Tauber
@@ -32,6 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatAscendingSortIcon public class FlatAscendingSortIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatAscendingSortIcon() { public FlatAscendingSortIcon() {
@@ -41,6 +45,14 @@ public class FlatAscendingSortIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
g.setColor( sortIconColor ); g.setColor( sortIconColor );
g.fill( FlatUIUtils.createPath( 0.5,5, 9.5,5, 5,0 ) ); if( chevron ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,5, 5,1, 9,5 );
g.setStroke( new BasicStroke( 1f ) );
g.draw( path );
} else {
// triangle arrow
g.fill( FlatUIUtils.createPath( 0.5,5, 5,0, 9.5,5 ) );
}
} }
} }

View File

@@ -16,14 +16,18 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* Icon for {@link javax.swing.JCheckBox}. * Icon for {@link javax.swing.JCheckBox}.
@@ -34,6 +38,7 @@ import com.formdev.flatlaf.ui.FlatButtonUI;
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.focusColor Color * @uiDefault Component.focusColor Color
* @uiDefault CheckBox.icon.focusedColor Color optional; defaults to Component.focusColor
* @uiDefault CheckBox.icon.borderColor Color * @uiDefault CheckBox.icon.borderColor Color
* @uiDefault CheckBox.icon.disabledBorderColor Color * @uiDefault CheckBox.icon.disabledBorderColor Color
* @uiDefault CheckBox.icon.selectedBorderColor Color * @uiDefault CheckBox.icon.selectedBorderColor Color
@@ -50,6 +55,7 @@ import com.formdev.flatlaf.ui.FlatButtonUI;
* @uiDefault CheckBox.icon.selectedPressedBackground Color optional * @uiDefault CheckBox.icon.selectedPressedBackground Color optional
* @uiDefault CheckBox.icon.checkmarkColor Color * @uiDefault CheckBox.icon.checkmarkColor Color
* @uiDefault CheckBox.icon.disabledCheckmarkColor Color * @uiDefault CheckBox.icon.disabledCheckmarkColor Color
* @uiDefault CheckBox.arc int
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -57,7 +63,9 @@ public class FlatCheckBoxIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" ); protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" ); protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusedColor",
UIManager.getColor( "Component.focusColor" ) );
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" ); protected final Color borderColor = UIManager.getColor( "CheckBox.icon.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" ); protected final Color disabledBorderColor = UIManager.getColor( "CheckBox.icon.disabledBorderColor" );
@@ -84,7 +92,8 @@ public class FlatCheckBoxIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
boolean selected = (c instanceof AbstractButton) ? ((AbstractButton)c).isSelected() : false; boolean indeterminate = c instanceof JComponent && clientPropertyEquals( (JComponent) c, SELECTED_STATE, SELECTED_STATE_INDETERMINATE );
boolean selected = indeterminate || (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
// paint focused border // paint focused border
if( c.hasFocus() && focusWidth > 0 ) { if( c.hasFocus() && focusWidth > 0 ) {
@@ -102,33 +111,40 @@ public class FlatCheckBoxIcon
paintBorder( g2 ); paintBorder( g2 );
// paint background // paint background
g2.setColor( FlatButtonUI.buttonStateColor( c, FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
selected ? selectedBackground : background, selected ? selectedBackground : background,
disabledBackground, disabledBackground,
focusedBackground, focusedBackground,
selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground, selected && selectedHoverBackground != null ? selectedHoverBackground : hoverBackground,
selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ) ); selected && selectedPressedBackground != null ? selectedPressedBackground : pressedBackground ),
background );
paintBackground( g2 ); paintBackground( g2 );
// paint checkmark // paint checkmark
if( selected ) { if( selected || indeterminate ) {
g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor ); g2.setColor( c.isEnabled() ? checkmarkColor : disabledCheckmarkColor );
paintCheckmark( g2 ); if( indeterminate )
paintIndeterminate( g2 );
else
paintCheckmark( g2 );
} }
} }
protected void paintFocusBorder( Graphics2D g2 ) { protected void paintFocusBorder( Graphics2D g2 ) {
// the outline focus border is painted outside of the icon // the outline focus border is painted outside of the icon
int wh = ICON_SIZE - 1 + (focusWidth * 2); int wh = ICON_SIZE - 1 + (focusWidth * 2);
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, 8, 8 ); int arcwh = (arc + focusWidth) * 2;
g2.fillRoundRect( -focusWidth + 1, -focusWidth, wh, wh, arcwh, arcwh );
} }
protected void paintBorder( Graphics2D g2 ) { protected void paintBorder( Graphics2D g2 ) {
g2.fillRoundRect( 1, 0, 14, 14, 4, 4 ); int arcwh = arc * 2;
g2.fillRoundRect( 1, 0, 14, 14, arcwh, arcwh );
} }
protected void paintBackground( Graphics2D g2 ) { protected void paintBackground( Graphics2D g2 ) {
g2.fillRoundRect( 2, 1, 12, 12, 3, 3 ); int arcwh = (arc * 2) - 1;
g2.fillRoundRect( 2, 1, 12, 12, arcwh, arcwh );
} }
protected void paintCheckmark( Graphics2D g2 ) { protected void paintCheckmark( Graphics2D g2 ) {
@@ -140,4 +156,8 @@ public class FlatCheckBoxIcon
g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) ); g2.setStroke( new BasicStroke( 1.9f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND ) );
g2.draw( path ); g2.draw( path );
} }
protected void paintIndeterminate( Graphics2D g2 ) {
g2.fill( new RoundRectangle2D.Float( 3.75f, 5.75f, 8.5f, 2.5f, 2f, 2f ) );
}
} }

View File

@@ -16,15 +16,18 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "descendingSort" icon for {@link javax.swing.table.JTableHeader}. * "descendingSort" icon for {@link javax.swing.table.JTableHeader}.
* *
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Table.sortIconColor Color * @uiDefault Table.sortIconColor Color
* *
* @author Karl Tauber * @author Karl Tauber
@@ -32,6 +35,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatDescendingSortIcon public class FlatDescendingSortIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatDescendingSortIcon() { public FlatDescendingSortIcon() {
@@ -41,6 +45,14 @@ public class FlatDescendingSortIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
g.setColor( sortIconColor ); g.setColor( sortIconColor );
g.fill( FlatUIUtils.createPath( 0.5,0, 9.5,0, 5,5 ) ); if( chevron ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 9,1 );
g.setStroke( new BasicStroke( 1f ) );
g.draw( path );
} else {
// triangle arrow
g.fill( FlatUIUtils.createPath( 0.5,0, 5,5, 9.5,0 ) );
}
} }
} }

View File

@@ -23,7 +23,7 @@ import javax.swing.UIManager;
/** /**
* "details view" icon for {@link javax.swing.JFileChooser}. * "details view" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileChooser.icon.detailsViewColor Color * @uiDefault Actions.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -31,7 +31,7 @@ public class FlatFileChooserDetailsViewIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileChooserDetailsViewIcon() { public FlatFileChooserDetailsViewIcon() {
super( 16, 16, UIManager.getColor( "FileChooser.icon.detailsViewColor" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@Override @Override

View File

@@ -24,7 +24,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "home folder" icon for {@link javax.swing.JFileChooser}. * "home folder" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileChooser.icon.homeFolderColor Color * @uiDefault Actions.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +32,7 @@ public class FlatFileChooserHomeFolderIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileChooserHomeFolderIcon() { public FlatFileChooserHomeFolderIcon() {
super( 16, 16, UIManager.getColor( "FileChooser.icon.homeFolderColor" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@Override @Override

View File

@@ -23,7 +23,7 @@ import javax.swing.UIManager;
/** /**
* "list view" icon for {@link javax.swing.JFileChooser}. * "list view" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileChooser.icon.listViewColor Color * @uiDefault Actions.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -31,7 +31,7 @@ public class FlatFileChooserListViewIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileChooserListViewIcon() { public FlatFileChooserListViewIcon() {
super( 16, 16, UIManager.getColor( "FileChooser.icon.listViewColor" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@Override @Override

View File

@@ -24,7 +24,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "new folder" icon for {@link javax.swing.JFileChooser}. * "new folder" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileChooser.icon.newFolderColor Color * @uiDefault Actions.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +32,7 @@ public class FlatFileChooserNewFolderIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileChooserNewFolderIcon() { public FlatFileChooserNewFolderIcon() {
super( 16, 16, UIManager.getColor( "FileChooser.icon.newFolderColor" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@Override @Override

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -24,15 +25,18 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "up folder" icon for {@link javax.swing.JFileChooser}. * "up folder" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileChooser.icon.upFolderColor Color * @uiDefault Actions.Grey Color
* @uiDefault Actions.Blue Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatFileChooserUpFolderIcon public class FlatFileChooserUpFolderIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
private final Color blueColor = UIManager.getColor( "Actions.Blue" );
public FlatFileChooserUpFolderIcon() { public FlatFileChooserUpFolderIcon() {
super( 16, 16, UIManager.getColor( "FileChooser.icon.upFolderColor" ) ); super( 16, 16, UIManager.getColor( "Actions.Grey" ) );
} }
@Override @Override
@@ -47,6 +51,8 @@ public class FlatFileChooserUpFolderIcon
*/ */
g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 9,5, 9,9, 13,9, 13,5, 14,5, 14,13, 2,13 ) ); g.fill( FlatUIUtils.createPath( 2,3, 5.5,3, 7,5, 9,5, 9,9, 13,9, 13,5, 14,5, 14,13, 2,13 ) );
g.setColor( blueColor );
g.fill( FlatUIUtils.createPath( 12,4, 12,8, 10,8, 10,4, 8,4, 11,1, 14,4, 12,4 ) ); g.fill( FlatUIUtils.createPath( 12,4, 12,8, 10,8, 10,4, 8,4, 11,1, 14,4, 12,4 ) );
} }
} }

View File

@@ -25,7 +25,7 @@ import javax.swing.UIManager;
/** /**
* "computer" icon for {@link javax.swing.JFileChooser}. * "computer" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileView.icon.computerColor Color * @uiDefault Objects.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -33,7 +33,7 @@ public class FlatFileViewComputerIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileViewComputerIcon() { public FlatFileViewComputerIcon() {
super( 16, 16, UIManager.getColor( "FileView.icon.computerColor" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@Override @Override

View File

@@ -24,7 +24,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "directory" icon for {@link javax.swing.JFileChooser}. * "directory" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileView.icon.directoryColor Color * @uiDefault Objects.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +32,7 @@ public class FlatFileViewDirectoryIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileViewDirectoryIcon() { public FlatFileViewDirectoryIcon() {
super( 16, 16, UIManager.getColor( "FileView.icon.directoryColor" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@Override @Override

View File

@@ -24,7 +24,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "file" icon for {@link javax.swing.JFileChooser}. * "file" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileView.icon.fileColor Color * @uiDefault Objects.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +32,7 @@ public class FlatFileViewFileIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileViewFileIcon() { public FlatFileViewFileIcon() {
super( 16, 16, UIManager.getColor( "FileView.icon.fileColor" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@Override @Override

View File

@@ -25,7 +25,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "floppy drive" icon for {@link javax.swing.JFileChooser}. * "floppy drive" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileView.icon.floppyDriveColor Color * @uiDefault Objects.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -33,7 +33,7 @@ public class FlatFileViewFloppyDriveIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileViewFloppyDriveIcon() { public FlatFileViewFloppyDriveIcon() {
super( 16, 16, UIManager.getColor( "FileView.icon.floppyDriveColor" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@Override @Override

View File

@@ -25,7 +25,7 @@ import javax.swing.UIManager;
/** /**
* "hard drive" icon for {@link javax.swing.JFileChooser}. * "hard drive" icon for {@link javax.swing.JFileChooser}.
* *
* @uiDefault FileView.icon.hardDriveColor Color * @uiDefault Objects.Grey Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -33,7 +33,7 @@ public class FlatFileViewHardDriveIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
public FlatFileViewHardDriveIcon() { public FlatFileViewHardDriveIcon() {
super( 16, 16, UIManager.getColor( "FileView.icon.hardDriveColor" ) ); super( 16, 16, UIManager.getColor( "Objects.Grey" ) );
} }
@Override @Override

View File

@@ -24,6 +24,7 @@ import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* Help button icon for {@link javax.swing.JButton}. * Help button icon for {@link javax.swing.JButton}.
@@ -99,12 +100,12 @@ public class FlatHelpButtonIcon
g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) ); g2.fill( new Ellipse2D.Float( focusWidth + 0.5f, focusWidth + 0.5f, 21, 21 ) );
// paint background // paint background
g2.setColor( FlatButtonUI.buttonStateColor( c, FlatUIUtils.setColor( g2, FlatButtonUI.buttonStateColor( c,
background, background,
disabledBackground, disabledBackground,
focusedBackground, focusedBackground,
hoverBackground, hoverBackground,
pressedBackground ) ); pressedBackground ), background );
g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) ); g2.fill( new Ellipse2D.Float( focusWidth + 1.5f, focusWidth + 1.5f, 19, 19 ) );
// paint question mark // paint question mark

View File

@@ -60,7 +60,7 @@ public class FlatMenuArrowIcon
g.draw( path ); g.draw( path );
} else { } else {
// triangle arrow // triangle arrow
g.fill( FlatUIUtils.createPath( 0,0.5, 0,9.5, 5,5 ) ); g.fill( FlatUIUtils.createPath( 0,0.5, 5,5, 0,9.5 ) );
} }
} }

View File

@@ -22,11 +22,12 @@ import java.awt.Graphics2D;
import java.awt.Shape; import java.awt.Shape;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* Base class for icons for {@link javax.swing.JOptionPane}. * Base class for icons for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.icon.foreground Color * @uiDefault OptionPane.icon.foreground Color default is transparent
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -35,8 +36,8 @@ public abstract class FlatOptionPaneAbstractIcon
{ {
protected final Color foreground = UIManager.getColor( "OptionPane.icon.foreground" ); protected final Color foreground = UIManager.getColor( "OptionPane.icon.foreground" );
protected FlatOptionPaneAbstractIcon( String colorKey ) { protected FlatOptionPaneAbstractIcon( String colorKey, String defaultColorKey ) {
super( 32, 32, UIManager.getColor( colorKey ) ); super( 32, 32, FlatUIUtils.getUIColor( colorKey, defaultColorKey ) );
} }
@Override @Override

View File

@@ -24,7 +24,8 @@ import java.awt.geom.Rectangle2D;
/** /**
* "Error" icon for {@link javax.swing.JOptionPane}. * "Error" icon for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.icon.errorColor Color * @uiDefault OptionPane.icon.errorColor Color optional; defaults to Actions.Red
* @uiDefault Actions.Red Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +33,7 @@ public class FlatOptionPaneErrorIcon
extends FlatOptionPaneAbstractIcon extends FlatOptionPaneAbstractIcon
{ {
public FlatOptionPaneErrorIcon() { public FlatOptionPaneErrorIcon() {
super( "OptionPane.icon.errorColor" ); super( "OptionPane.icon.errorColor", "Actions.Red" );
} }
/* /*

View File

@@ -24,7 +24,8 @@ import java.awt.geom.Rectangle2D;
/** /**
* "Information" icon for {@link javax.swing.JOptionPane}. * "Information" icon for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.icon.informationColor Color * @uiDefault OptionPane.icon.informationColor Color optional; defaults to Actions.Blue
* @uiDefault Actions.Blue Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +33,7 @@ public class FlatOptionPaneInformationIcon
extends FlatOptionPaneAbstractIcon extends FlatOptionPaneAbstractIcon
{ {
public FlatOptionPaneInformationIcon() { public FlatOptionPaneInformationIcon() {
super( "OptionPane.icon.informationColor" ); super( "OptionPane.icon.informationColor", "Actions.Blue" );
} }
/* /*

View File

@@ -24,7 +24,8 @@ import java.awt.geom.Rectangle2D;
/** /**
* "Question" icon for {@link javax.swing.JOptionPane}. * "Question" icon for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.icon.questionColor Color * @uiDefault OptionPane.icon.questionColor Color optional; defaults to Actions.Blue
* @uiDefault Actions.Blue Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +33,7 @@ public class FlatOptionPaneQuestionIcon
extends FlatOptionPaneAbstractIcon extends FlatOptionPaneAbstractIcon
{ {
public FlatOptionPaneQuestionIcon() { public FlatOptionPaneQuestionIcon() {
super( "OptionPane.icon.questionColor" ); super( "OptionPane.icon.questionColor", "Actions.Blue" );
} }
/* /*

View File

@@ -24,7 +24,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
* "Warning" icon for {@link javax.swing.JOptionPane}. * "Warning" icon for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.icon.warningColor Color * @uiDefault OptionPane.icon.warningColor Color optional; defaults to Actions.Yellow
* @uiDefault Actions.Yellow Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -32,7 +33,7 @@ public class FlatOptionPaneWarningIcon
extends FlatOptionPaneAbstractIcon extends FlatOptionPaneAbstractIcon
{ {
public FlatOptionPaneWarningIcon() { public FlatOptionPaneWarningIcon() {
super( "OptionPane.icon.warningColor" ); super( "OptionPane.icon.warningColor", "Actions.Yellow" );
} }
/* /*

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2019 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
*
* http://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.json;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author Karl Tauber
*/
public class Json
{
public static Object parse( Reader reader )
throws IOException, ParseException
{
DefaultHandler handler = new DefaultHandler();
new JsonParser( handler ).parse( reader );
return handler.getValue();
}
//---- class DefaultHandler -----------------------------------------------
static class DefaultHandler
extends JsonHandler<List<Object>, Map<String, Object>>
{
private Object value;
@Override
public List<Object> startArray() {
return new ArrayList<>();
}
@Override
public Map<String, Object> startObject() {
return new LinkedHashMap<>();
}
@Override
public void endNull() {
value = "null";
}
@Override
public void endBoolean( boolean bool ) {
value = bool ? "true" : "false";
}
@Override
public void endString( String string ) {
value = string;
}
@Override
public void endNumber( String string ) {
value = string;
}
@Override
public void endArray( List<Object> array ) {
value = array;
}
@Override
public void endObject( Map<String, Object> object ) {
value = object;
}
@Override
public void endArrayValue( List<Object> array ) {
array.add( value );
}
@Override
public void endObjectValue( Map<String, Object> object, String name ) {
object.put( name, value );
}
Object getValue() {
return value;
}
}
}

View File

@@ -0,0 +1,266 @@
/*******************************************************************************
* Copyright (c) 2016 EclipseSource.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
// from https://github.com/ralfstx/minimal-json
package com.formdev.flatlaf.json;
/**
* A handler for parser events. Instances of this class can be given to a {@link JsonParser}. The
* parser will then call the methods of the given handler while reading the input.
* <p>
* The default implementations of these methods do nothing. Subclasses may override only those
* methods they are interested in. They can use <code>getLocation()</code> to access the current
* character position of the parser at any point. The <code>start*</code> methods will be called
* while the location points to the first character of the parsed element. The <code>end*</code>
* methods will be called while the location points to the character position that directly follows
* the last character of the parsed element. Example:
* </p>
*
* <pre>
* ["lorem ipsum"]
* ^ ^
* startString endString
* </pre>
* <p>
* Subclasses that build an object representation of the parsed JSON can return arbitrary handler
* objects for JSON arrays and JSON objects in {@link #startArray()} and {@link #startObject()}.
* These handler objects will then be provided in all subsequent parser events for this particular
* array or object. They can be used to keep track the elements of a JSON array or object.
* </p>
*
* @param <A>
* The type of handlers used for JSON arrays
* @param <O>
* The type of handlers used for JSON objects
* @see JsonParser
*/
abstract class JsonHandler<A, O> {
JsonParser parser;
/**
* Returns the current parser location.
*
* @return the current parser location
*/
protected Location getLocation() {
return parser.getLocation();
}
/**
* Indicates the beginning of a <code>null</code> literal in the JSON input. This method will be
* called when reading the first character of the literal.
*/
public void startNull() {
}
/**
* Indicates the end of a <code>null</code> literal in the JSON input. This method will be called
* after reading the last character of the literal.
*/
public void endNull() {
}
/**
* Indicates the beginning of a boolean literal (<code>true</code> or <code>false</code>) in the
* JSON input. This method will be called when reading the first character of the literal.
*/
public void startBoolean() {
}
/**
* Indicates the end of a boolean literal (<code>true</code> or <code>false</code>) in the JSON
* input. This method will be called after reading the last character of the literal.
*
* @param value
* the parsed boolean value
*/
public void endBoolean(boolean value) {
}
/**
* Indicates the beginning of a string in the JSON input. This method will be called when reading
* the opening double quote character (<code>'&quot;'</code>).
*/
public void startString() {
}
/**
* Indicates the end of a string in the JSON input. This method will be called after reading the
* closing double quote character (<code>'&quot;'</code>).
*
* @param string
* the parsed string
*/
public void endString(String string) {
}
/**
* Indicates the beginning of a number in the JSON input. This method will be called when reading
* the first character of the number.
*/
public void startNumber() {
}
/**
* Indicates the end of a number in the JSON input. This method will be called after reading the
* last character of the number.
*
* @param string
* the parsed number string
*/
public void endNumber(String string) {
}
/**
* Indicates the beginning of an array in the JSON input. This method will be called when reading
* the opening square bracket character (<code>'['</code>).
* <p>
* This method may return an object to handle subsequent parser events for this array. This array
* handler will then be provided in all calls to {@link #startArrayValue(Object)
* startArrayValue()}, {@link #endArrayValue(Object) endArrayValue()}, and
* {@link #endArray(Object) endArray()} for this array.
* </p>
*
* @return a handler for this array, or <code>null</code> if not needed
*/
public A startArray() {
return null;
}
/**
* Indicates the end of an array in the JSON input. This method will be called after reading the
* closing square bracket character (<code>']'</code>).
*
* @param array
* the array handler returned from {@link #startArray()}, or <code>null</code> if not
* provided
*/
public void endArray(A array) {
}
/**
* Indicates the beginning of an array element in the JSON input. This method will be called when
* reading the first character of the element, just before the call to the <code>start</code>
* method for the specific element type ({@link #startString()}, {@link #startNumber()}, etc.).
*
* @param array
* the array handler returned from {@link #startArray()}, or <code>null</code> if not
* provided
*/
public void startArrayValue(A array) {
}
/**
* Indicates the end of an array element in the JSON input. This method will be called after
* reading the last character of the element value, just after the <code>end</code> method for the
* specific element type (like {@link #endString(String) endString()}, {@link #endNumber(String)
* endNumber()}, etc.).
*
* @param array
* the array handler returned from {@link #startArray()}, or <code>null</code> if not
* provided
*/
public void endArrayValue(A array) {
}
/**
* Indicates the beginning of an object in the JSON input. This method will be called when reading
* the opening curly bracket character (<code>'{'</code>).
* <p>
* This method may return an object to handle subsequent parser events for this object. This
* object handler will be provided in all calls to {@link #startObjectName(Object)
* startObjectName()}, {@link #endObjectName(Object, String) endObjectName()},
* {@link #startObjectValue(Object, String) startObjectValue()},
* {@link #endObjectValue(Object, String) endObjectValue()}, and {@link #endObject(Object)
* endObject()} for this object.
* </p>
*
* @return a handler for this object, or <code>null</code> if not needed
*/
public O startObject() {
return null;
}
/**
* Indicates the end of an object in the JSON input. This method will be called after reading the
* closing curly bracket character (<code>'}'</code>).
*
* @param object
* the object handler returned from {@link #startObject()}, or null if not provided
*/
public void endObject(O object) {
}
/**
* Indicates the beginning of the name of an object member in the JSON input. This method will be
* called when reading the opening quote character ('&quot;') of the member name.
*
* @param object
* the object handler returned from {@link #startObject()}, or <code>null</code> if not
* provided
*/
public void startObjectName(O object) {
}
/**
* Indicates the end of an object member name in the JSON input. This method will be called after
* reading the closing quote character (<code>'"'</code>) of the member name.
*
* @param object
* the object handler returned from {@link #startObject()}, or null if not provided
* @param name
* the parsed member name
*/
public void endObjectName(O object, String name) {
}
/**
* Indicates the beginning of the name of an object member in the JSON input. This method will be
* called when reading the opening quote character ('&quot;') of the member name.
*
* @param object
* the object handler returned from {@link #startObject()}, or <code>null</code> if not
* provided
* @param name
* the member name
*/
public void startObjectValue(O object, String name) {
}
/**
* Indicates the end of an object member value in the JSON input. This method will be called after
* reading the last character of the member value, just after the <code>end</code> method for the
* specific member type (like {@link #endString(String) endString()}, {@link #endNumber(String)
* endNumber()}, etc.).
*
* @param object
* the object handler returned from {@link #startObject()}, or null if not provided
* @param name
* the parsed member name
*/
public void endObjectValue(O object, String name) {
}
}

View File

@@ -0,0 +1,514 @@
/*******************************************************************************
* Copyright (c) 2013, 2016 EclipseSource.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
// from https://github.com/ralfstx/minimal-json
package com.formdev.flatlaf.json;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
/**
* A streaming parser for JSON text. The parser reports all events to a given handler.
*/
class JsonParser {
private static final int MAX_NESTING_LEVEL = 1000;
private static final int MIN_BUFFER_SIZE = 10;
private static final int DEFAULT_BUFFER_SIZE = 1024;
private final JsonHandler<Object, Object> handler;
private Reader reader;
private char[] buffer;
private int bufferOffset;
private int index;
private int fill;
private int line;
private int lineOffset;
private int current;
private StringBuilder captureBuffer;
private int captureStart;
private int nestingLevel;
/*
* | bufferOffset
* v
* [a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t] < input
* [l|m|n|o|p|q|r|s|t|?|?] < buffer
* ^ ^
* | index fill
*/
/**
* Creates a new JsonParser with the given handler. The parser will report all parser events to
* this handler.
*
* @param handler
* the handler to process parser events
*/
@SuppressWarnings("unchecked")
public JsonParser(JsonHandler<?, ?> handler) {
if (handler == null) {
throw new NullPointerException("handler is null");
}
this.handler = (JsonHandler<Object, Object>)handler;
handler.parser = this;
}
/**
* Parses the given input string. The input must contain a valid JSON value, optionally padded
* with whitespace.
*
* @param string
* the input string, must be valid JSON
* @throws ParseException
* if the input is not valid JSON
*/
public void parse(String string) {
if (string == null) {
throw new NullPointerException("string is null");
}
int bufferSize = Math.max(MIN_BUFFER_SIZE, Math.min(DEFAULT_BUFFER_SIZE, string.length()));
try {
parse(new StringReader(string), bufferSize);
} catch (IOException exception) {
// StringReader does not throw IOException
throw new RuntimeException(exception);
}
}
/**
* Reads the entire input from the given reader and parses it as JSON. The input must contain a
* valid JSON value, optionally padded with whitespace.
* <p>
* Characters are read in chunks into a default-sized input buffer. Hence, wrapping a reader in an
* additional <code>BufferedReader</code> likely won't improve reading performance.
* </p>
*
* @param reader
* the reader to read the input from
* @throws IOException
* if an I/O error occurs in the reader
* @throws ParseException
* if the input is not valid JSON
*/
public void parse(Reader reader) throws IOException {
parse(reader, DEFAULT_BUFFER_SIZE);
}
/**
* Reads the entire input from the given reader and parses it as JSON. The input must contain a
* valid JSON value, optionally padded with whitespace.
* <p>
* Characters are read in chunks into an input buffer of the given size. Hence, wrapping a reader
* in an additional <code>BufferedReader</code> likely won't improve reading performance.
* </p>
*
* @param reader
* the reader to read the input from
* @param buffersize
* the size of the input buffer in chars
* @throws IOException
* if an I/O error occurs in the reader
* @throws ParseException
* if the input is not valid JSON
*/
public void parse(Reader reader, int buffersize) throws IOException {
if (reader == null) {
throw new NullPointerException("reader is null");
}
if (buffersize <= 0) {
throw new IllegalArgumentException("buffersize is zero or negative");
}
this.reader = reader;
buffer = new char[buffersize];
bufferOffset = 0;
index = 0;
fill = 0;
line = 1;
lineOffset = 0;
current = 0;
captureStart = -1;
read();
skipWhiteSpace();
readValue();
skipWhiteSpace();
if (!isEndOfText()) {
throw error("Unexpected character");
}
}
private void readValue() throws IOException {
switch (current) {
case 'n':
readNull();
break;
case 't':
readTrue();
break;
case 'f':
readFalse();
break;
case '"':
readString();
break;
case '[':
readArray();
break;
case '{':
readObject();
break;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
readNumber();
break;
default:
throw expected("value");
}
}
private void readArray() throws IOException {
Object array = handler.startArray();
read();
if (++nestingLevel > MAX_NESTING_LEVEL) {
throw error("Nesting too deep");
}
skipWhiteSpace();
if (readChar(']')) {
nestingLevel--;
handler.endArray(array);
return;
}
do {
skipWhiteSpace();
handler.startArrayValue(array);
readValue();
handler.endArrayValue(array);
skipWhiteSpace();
} while (readChar(','));
if (!readChar(']')) {
throw expected("',' or ']'");
}
nestingLevel--;
handler.endArray(array);
}
private void readObject() throws IOException {
Object object = handler.startObject();
read();
if (++nestingLevel > MAX_NESTING_LEVEL) {
throw error("Nesting too deep");
}
skipWhiteSpace();
if (readChar('}')) {
nestingLevel--;
handler.endObject(object);
return;
}
do {
skipWhiteSpace();
handler.startObjectName(object);
String name = readName();
handler.endObjectName(object, name);
skipWhiteSpace();
if (!readChar(':')) {
throw expected("':'");
}
skipWhiteSpace();
handler.startObjectValue(object, name);
readValue();
handler.endObjectValue(object, name);
skipWhiteSpace();
} while (readChar(','));
if (!readChar('}')) {
throw expected("',' or '}'");
}
nestingLevel--;
handler.endObject(object);
}
private String readName() throws IOException {
if (current != '"') {
throw expected("name");
}
return readStringInternal();
}
private void readNull() throws IOException {
handler.startNull();
read();
readRequiredChar('u');
readRequiredChar('l');
readRequiredChar('l');
handler.endNull();
}
private void readTrue() throws IOException {
handler.startBoolean();
read();
readRequiredChar('r');
readRequiredChar('u');
readRequiredChar('e');
handler.endBoolean(true);
}
private void readFalse() throws IOException {
handler.startBoolean();
read();
readRequiredChar('a');
readRequiredChar('l');
readRequiredChar('s');
readRequiredChar('e');
handler.endBoolean(false);
}
private void readRequiredChar(char ch) throws IOException {
if (!readChar(ch)) {
throw expected("'" + ch + "'");
}
}
private void readString() throws IOException {
handler.startString();
handler.endString(readStringInternal());
}
private String readStringInternal() throws IOException {
read();
startCapture();
while (current != '"') {
if (current == '\\') {
pauseCapture();
readEscape();
startCapture();
} else if (current < 0x20) {
throw expected("valid string character");
} else {
read();
}
}
String string = endCapture();
read();
return string;
}
private void readEscape() throws IOException {
read();
switch (current) {
case '"':
case '/':
case '\\':
captureBuffer.append((char)current);
break;
case 'b':
captureBuffer.append('\b');
break;
case 'f':
captureBuffer.append('\f');
break;
case 'n':
captureBuffer.append('\n');
break;
case 'r':
captureBuffer.append('\r');
break;
case 't':
captureBuffer.append('\t');
break;
case 'u':
char[] hexChars = new char[4];
for (int i = 0; i < 4; i++) {
read();
if (!isHexDigit()) {
throw expected("hexadecimal digit");
}
hexChars[i] = (char)current;
}
captureBuffer.append((char)Integer.parseInt(new String(hexChars), 16));
break;
default:
throw expected("valid escape sequence");
}
read();
}
private void readNumber() throws IOException {
handler.startNumber();
startCapture();
readChar('-');
int firstDigit = current;
if (!readDigit()) {
throw expected("digit");
}
if (firstDigit != '0') {
while (readDigit()) {
}
}
readFraction();
readExponent();
handler.endNumber(endCapture());
}
private boolean readFraction() throws IOException {
if (!readChar('.')) {
return false;
}
if (!readDigit()) {
throw expected("digit");
}
while (readDigit()) {
}
return true;
}
private boolean readExponent() throws IOException {
if (!readChar('e') && !readChar('E')) {
return false;
}
if (!readChar('+')) {
readChar('-');
}
if (!readDigit()) {
throw expected("digit");
}
while (readDigit()) {
}
return true;
}
private boolean readChar(char ch) throws IOException {
if (current != ch) {
return false;
}
read();
return true;
}
private boolean readDigit() throws IOException {
if (!isDigit()) {
return false;
}
read();
return true;
}
private void skipWhiteSpace() throws IOException {
while (isWhiteSpace()) {
read();
}
}
private void read() throws IOException {
if (index == fill) {
if (captureStart != -1) {
captureBuffer.append(buffer, captureStart, fill - captureStart);
captureStart = 0;
}
bufferOffset += fill;
fill = reader.read(buffer, 0, buffer.length);
index = 0;
if (fill == -1) {
current = -1;
index++;
return;
}
}
if (current == '\n') {
line++;
lineOffset = bufferOffset + index;
}
current = buffer[index++];
}
private void startCapture() {
if (captureBuffer == null) {
captureBuffer = new StringBuilder();
}
captureStart = index - 1;
}
private void pauseCapture() {
int end = current == -1 ? index : index - 1;
captureBuffer.append(buffer, captureStart, end - captureStart);
captureStart = -1;
}
private String endCapture() {
int start = captureStart;
int end = index - 1;
captureStart = -1;
if (captureBuffer.length() > 0) {
captureBuffer.append(buffer, start, end - start);
String captured = captureBuffer.toString();
captureBuffer.setLength(0);
return captured;
}
return new String(buffer, start, end - start);
}
Location getLocation() {
int offset = bufferOffset + index - 1;
int column = offset - lineOffset + 1;
return new Location(offset, line, column);
}
private ParseException expected(String expected) {
if (isEndOfText()) {
return error("Unexpected end of input");
}
return error("Expected " + expected);
}
private ParseException error(String message) {
return new ParseException(message, getLocation());
}
private boolean isWhiteSpace() {
return current == ' ' || current == '\t' || current == '\n' || current == '\r';
}
private boolean isDigit() {
return current >= '0' && current <= '9';
}
private boolean isHexDigit() {
return current >= '0' && current <= '9'
|| current >= 'a' && current <= 'f'
|| current >= 'A' && current <= 'F';
}
private boolean isEndOfText() {
return current == -1;
}
}

View File

@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2016 EclipseSource.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
// from https://github.com/ralfstx/minimal-json
package com.formdev.flatlaf.json;
/**
* An immutable object that represents a location in the parsed text.
*/
public class Location {
/**
* The absolute character index, starting at 0.
*/
public final int offset;
/**
* The line number, starting at 1.
*/
public final int line;
/**
* The column number, starting at 1.
*/
public final int column;
Location(int offset, int line, int column) {
this.offset = offset;
this.column = column;
this.line = line;
}
@Override
public String toString() {
return line + ":" + column;
}
@Override
public int hashCode() {
return offset;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Location other = (Location)obj;
return offset == other.offset && column == other.column && line == other.line;
}
}

View File

@@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright (c) 2013, 2016 EclipseSource.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
// from https://github.com/ralfstx/minimal-json
package com.formdev.flatlaf.json;
/**
* An unchecked exception to indicate that an input does not qualify as valid JSON.
*/
public class ParseException extends RuntimeException {
private final Location location;
ParseException(String message, Location location) {
super(message + " at " + location);
this.location = location;
}
/**
* Returns the location at which the error occurred.
*
* @return the error location
*/
public Location getLocation() {
return location;
}
/**
* Returns the absolute character index at which the error occurred. The offset of the first
* character of a document is 0.
*
* @return the character offset at which the error occurred, will be &gt;= 0
* @deprecated Use {@link #getLocation()} instead
*/
@Deprecated
public int getOffset() {
return location.offset;
}
/**
* Returns the line number in which the error occurred. The number of the first line is 1.
*
* @return the line in which the error occurred, will be &gt;= 1
* @deprecated Use {@link #getLocation()} instead
*/
@Deprecated
public int getLine() {
return location.line;
}
/**
* Returns the column number at which the error occurred, i.e. the number of the character in its
* line. The number of the first character of a line is 1.
*
* @return the column in which the error occurred, will be &gt;= 1
* @deprecated Use {@link #getLocation()} instead
*/
@Deprecated
public int getColumn() {
return location.column;
}
}

View File

@@ -157,7 +157,7 @@ public class FlatArrowButton
g.translate( -x, -y ); g.translate( -x, -y );
} }
public static Shape createArrowShape( int direction, boolean chevron, int w, int h ) { public static Shape createArrowShape( int direction, boolean chevron, float w, float h ) {
switch( direction ) { switch( direction ) {
case NORTH: return FlatUIUtils.createPath( !chevron, 0,h, (w / 2f),0, w,h ); case NORTH: return FlatUIUtils.createPath( !chevron, 0,h, (w / 2f),0, w,h );
case SOUTH: return FlatUIUtils.createPath( !chevron, 0,0, (w / 2f),h, w,0 ); case SOUTH: return FlatUIUtils.createPath( !chevron, 0,0, (w / 2f),h, w,0 );

View File

@@ -23,7 +23,6 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.KeyboardFocusManager; import java.awt.KeyboardFocusManager;
import java.awt.Paint;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@@ -72,9 +71,10 @@ public class FlatBorder
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
float focusWidth = getFocusWidth(); boolean isCellEditor = isTableCellEditor( c );
float focusWidth = isCellEditor ? 0 : getFocusWidth();
float borderWidth = getBorderWidth( c ); float borderWidth = getBorderWidth( c );
float arc = getArc(); float arc = isCellEditor ? 0 : getArc();
if( isFocused( c ) ) { if( isFocused( c ) ) {
g2.setColor( getFocusColor( c ) ); g2.setColor( getFocusColor( c ) );
@@ -82,7 +82,7 @@ public class FlatBorder
getLineWidth() + scale( (float) innerFocusWidth ), arc ); getLineWidth() + scale( (float) innerFocusWidth ), arc );
} }
g2.setPaint( getBorderColor( c ) ); g2.setColor( getBorderColor( c ) );
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, borderWidth, arc ); FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, borderWidth, arc );
} finally { } finally {
g2.dispose(); g2.dispose();
@@ -93,7 +93,7 @@ public class FlatBorder
return focusColor; return focusColor;
} }
protected Paint getBorderColor( Component c ) { protected Color getBorderColor( Component c ) {
boolean enabled = c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable()); boolean enabled = c.isEnabled() && (!(c instanceof JTextComponent) || ((JTextComponent)c).isEditable());
return enabled return enabled
? (isFocused( c ) ? focusedBorderColor : borderColor) ? (isFocused( c ) ? focusedBorderColor : borderColor)
@@ -132,9 +132,14 @@ public class FlatBorder
return c.hasFocus(); return c.hasFocus();
} }
protected boolean isTableCellEditor( Component c ) {
return FlatUIUtils.isTableCellEditor( c );
}
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
float ow = getFocusWidth() + getLineWidth(); boolean isCellEditor = isTableCellEditor( c );
float ow = (isCellEditor ? 0 : getFocusWidth()) + getLineWidth();
insets = super.getBorderInsets( c, insets ); insets = super.getBorderInsets( c, insets );
insets.top = Math.round( scale( (float) insets.top ) + ow ); insets.top = Math.round( scale( (float) insets.top ) + ow );

View File

@@ -21,7 +21,6 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Paint;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
@@ -68,7 +67,7 @@ public class FlatButtonBorder
} }
@Override @Override
protected Paint getBorderColor( Component c ) { protected Color getBorderColor( Component c ) {
boolean def = FlatButtonUI.isDefaultButton( c ); boolean def = FlatButtonUI.isDefaultButton( c );
return FlatButtonUI.buttonStateColor( c, return FlatButtonUI.buttonStateColor( c,
def ? defaultBorderColor : borderColor, def ? defaultBorderColor : borderColor,

View File

@@ -43,7 +43,16 @@ import com.formdev.flatlaf.FlatLaf;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JButton}. * Provides the Flat LaF UI delegate for {@link javax.swing.JButton}.
* *
* TODO document used UI defaults of superclass * <!-- BasicButtonUI -->
*
* @uiDefault Button.font Font
* @uiDefault Button.background Color
* @uiDefault Button.foreground Color
* @uiDefault Button.border Border
* @uiDefault Button.margin Insets
* @uiDefault Button.rollover boolean
*
* <!-- FlatButtonUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Button.arc int * @uiDefault Button.arc int
@@ -131,6 +140,7 @@ public class FlatButtonUI
defaults_initialized = true; defaults_initialized = true;
} }
LookAndFeel.installProperty( b, "opaque", false );
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) ); LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
MigLayoutVisualPadding.install( b, focusWidth ); MigLayoutVisualPadding.install( b, focusWidth );
@@ -153,10 +163,13 @@ public class FlatButtonUI
} }
static boolean isIconOnlyButton( Component c ) { static boolean isIconOnlyButton( Component c ) {
String text; if( !(c instanceof JButton) )
return c instanceof JButton && return false;
((JButton)c).getIcon() != null &&
((text = ((JButton)c).getText()) == null || text.isEmpty()); Icon icon = ((JButton)c).getIcon();
String text = ((JButton)c).getText();
return (icon != null && (text == null || text.isEmpty())) ||
(icon == null && text != null && ("...".equals( text ) || text.length() == 1));
} }
static boolean isHelpButton( Component c ) { static boolean isHelpButton( Component c ) {
@@ -169,15 +182,16 @@ public class FlatButtonUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( isHelpButton( c ) ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
if( isHelpButton( c ) ) {
helpButtonIcon.paintIcon( c, g, 0, 0 ); helpButtonIcon.paintIcon( c, g, 0, 0 );
return; return;
} }
if( c.isOpaque() && isContentAreaFilled( c ) ) { if( isContentAreaFilled( c ) ) {
FlatUIUtils.paintParentBackground( g, c );
Color background = getBackground( c ); Color background = getBackground( c );
if( background != null ) { if( background != null ) {
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
@@ -188,7 +202,7 @@ public class FlatButtonUI
float focusWidth = (border instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (border instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (border instanceof FlatButtonBorder || isToolBarButton( c )) ? scale( (float) this.arc ) : 0; float arc = (border instanceof FlatButtonBorder || isToolBarButton( c )) ? scale( (float) this.arc ) : 0;
g2.setColor( background ); FlatUIUtils.setColor( g2, background, isDefaultButton(c) ? defaultBackground : c.getBackground() );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
} finally { } finally {
g2.dispose(); g2.dispose();
@@ -218,7 +232,7 @@ public class FlatButtonUI
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText ); paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText );
} }
static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) { public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
FontMetrics fm = b.getFontMetrics( b.getFont() ); FontMetrics fm = b.getFontMetrics( b.getFont() );
int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1; int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1;
@@ -284,8 +298,11 @@ public class FlatButtonUI
Dimension prefSize = super.getPreferredSize( c ); Dimension prefSize = super.getPreferredSize( c );
// apply minimum width, if not in toolbar and not a icon-only button // make button square if it is a icon-only button
if( !isToolBarButton( c ) && !isIconOnlyButton( c ) ) // or apply minimum width, if not in toolbar and not a icon-only button
if( isIconOnlyButton( c ) )
prefSize.width = Math.max( prefSize.width, prefSize.height );
else if( !isToolBarButton( c ) )
prefSize.width = Math.max( prefSize.width, scale( minimumWidth + (focusWidth * 2) ) ); prefSize.width = Math.max( prefSize.width, scale( minimumWidth + (focusWidth * 2) ) );
return prefSize; return prefSize;

View File

@@ -25,6 +25,26 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}.
* *
* <!-- BasicCheckBoxMenuItemUI -->
*
* @uiDefault CheckBoxMenuItem.font Font
* @uiDefault CheckBoxMenuItem.background Color
* @uiDefault CheckBoxMenuItem.foreground Color
* @uiDefault CheckBoxMenuItem.disabledForeground Color
* @uiDefault CheckBoxMenuItem.selectionBackground Color
* @uiDefault CheckBoxMenuItem.selectionForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorForeground Color
* @uiDefault CheckBoxMenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault CheckBoxMenuItem.border Border
* @uiDefault CheckBoxMenuItem.borderPainted boolean
* @uiDefault CheckBoxMenuItem.margin Insets
* @uiDefault CheckBoxMenuItem.arrowIcon Icon
* @uiDefault CheckBoxMenuItem.checkIcon Icon
* @uiDefault CheckBoxMenuItem.opaque boolean
* @uiDefault CheckBoxMenuItem.evenHeight boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatCheckBoxMenuItemUI public class FlatCheckBoxMenuItemUI

View File

@@ -22,6 +22,21 @@ import javax.swing.plaf.ComponentUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBox}. * Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBox}.
* *
* <!-- BasicRadioButtonUI -->
*
* @uiDefault CheckBox.font Font
* @uiDefault CheckBox.background Color
* @uiDefault CheckBox.foreground Color
* @uiDefault CheckBox.border Border
* @uiDefault CheckBox.margin Insets
* @uiDefault CheckBox.rollover boolean
* @uiDefault CheckBox.icon Icon
*
* <!-- FlatRadioButtonUI -->
*
* @uiDefault CheckBox.iconTextGap int
* @uiDefault CheckBox.disabledText Color
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatCheckBoxUI public class FlatCheckBoxUI

View File

@@ -26,6 +26,11 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JColorChooser}. * Provides the Flat LaF UI delegate for {@link javax.swing.JColorChooser}.
* *
* <!-- BasicColorChooserUI -->
*
* @uiDefault ColorChooser.font Font
* @uiDefault ColorChooser.background Color
* @uiDefault ColorChooser.foreground Color
* @uiDefault ColorChooser.showPreviewPanelText boolean * @uiDefault ColorChooser.showPreviewPanelText boolean
* @uiDefault ColorChooser.swatchesSwatchSize Dimension * @uiDefault ColorChooser.swatchesSwatchSize Dimension
* @uiDefault ColorChooser.swatchesRecentSwatchSize Dimension * @uiDefault ColorChooser.swatchesRecentSwatchSize Dimension

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
@@ -33,6 +34,7 @@ import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComboBox; import javax.swing.JComboBox;
@@ -40,6 +42,7 @@ import javax.swing.JComponent;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.ListCellRenderer; import javax.swing.ListCellRenderer;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.AbstractBorder; import javax.swing.border.AbstractBorder;
@@ -54,13 +57,24 @@ 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}.
* *
* TODO document used UI defaults of superclass * <!-- BasicComboBoxUI -->
*
* @uiDefault ComboBox.font Font
* @uiDefault ComboBox.background Color
* @uiDefault ComboBox.foreground Color
* @uiDefault ComboBox.border Border
* @uiDefault ComboBox.padding Insets
* @uiDefault ComboBox.squareButton boolean default is true
*
* <!-- FlatComboBoxUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.arc int * @uiDefault Component.arc int
* @uiDefault Component.arrowType String triangle (default) or chevron * @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Component.borderColor Color * @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color * @uiDefault Component.disabledBorderColor Color
* @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background
* @uiDefault ComboBox.disabledBackground Color * @uiDefault ComboBox.disabledBackground Color
* @uiDefault ComboBox.disabledForeground Color * @uiDefault ComboBox.disabledForeground Color
* @uiDefault ComboBox.buttonBackground Color * @uiDefault ComboBox.buttonBackground Color
@@ -77,9 +91,11 @@ public class FlatComboBoxUI
protected int focusWidth; protected int focusWidth;
protected int arc; protected int arc;
protected String arrowType; protected String arrowType;
protected boolean isIntelliJTheme;
protected Color borderColor; protected Color borderColor;
protected Color disabledBorderColor; protected Color disabledBorderColor;
protected Color editableBackground;
protected Color disabledBackground; protected Color disabledBackground;
protected Color disabledForeground; protected Color disabledForeground;
@@ -92,6 +108,8 @@ public class FlatComboBoxUI
private MouseListener hoverListener; private MouseListener hoverListener;
private boolean hover; private boolean hover;
private WeakReference<Component> lastRendererComponent;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatComboBoxUI(); return new FlatComboBoxUI();
} }
@@ -122,12 +140,16 @@ public class FlatComboBoxUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( comboBox, "opaque", false );
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" ); arc = UIManager.getInt( "Component.arc" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
borderColor = UIManager.getColor( "Component.borderColor" ); borderColor = UIManager.getColor( "Component.borderColor" );
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" ); disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
editableBackground = UIManager.getColor( "ComboBox.editableBackground" );
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" ); disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" ); disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" );
@@ -150,6 +172,7 @@ public class FlatComboBoxUI
borderColor = null; borderColor = null;
disabledBorderColor = null; disabledBorderColor = null;
editableBackground = null;
disabledBackground = null; disabledBackground = null;
disabledForeground = null; disabledForeground = null;
@@ -208,11 +231,14 @@ public class FlatComboBoxUI
String propertyName = e.getPropertyName(); String propertyName = e.getPropertyName();
if( editor != null && if( editor != null &&
((source == comboBox && (propertyName == "background" || propertyName == "foreground")) || ((source == comboBox && propertyName == "foreground") ||
(source == editor && propertyName == "enabled")) ) (source == editor && propertyName == "enabled")) )
{ {
// fix editor component colors // fix editor component colors
updateEditorColors(); updateEditorColors();
} else if( editor != null && source == comboBox && propertyName == "componentOrientation" ) {
ComponentOrientation o = (ComponentOrientation) e.getNewValue();
editor.applyComponentOrientation( o );
} }
} }
}; };
@@ -235,6 +261,12 @@ public class FlatComboBoxUI
if( editor instanceof JTextComponent ) if( editor instanceof JTextComponent )
((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() ); ((JTextComponent)editor).setBorder( BorderFactory.createEmptyBorder() );
// explicitly make non-opaque
if( editor instanceof JComponent )
((JComponent)editor).setOpaque( false );
editor.applyComponentOrientation( comboBox.getComponentOrientation() );
updateEditorColors(); updateEditorColors();
} }
@@ -243,7 +275,6 @@ public class FlatComboBoxUI
// is used, then the editor is updated after the combobox and the // is used, then the editor is updated after the combobox and the
// colors are again replaced with default colors // colors are again replaced with default colors
boolean enabled = editor.isEnabled(); boolean enabled = editor.isEnabled();
editor.setBackground( FlatUIUtils.nonUIResource( enabled ? comboBox.getBackground() : disabledBackground ) );
editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent) editor.setForeground( FlatUIUtils.nonUIResource( (enabled || editor instanceof JTextComponent)
? comboBox.getForeground() ? comboBox.getForeground()
: disabledForeground ) ); : disabledForeground ) );
@@ -265,44 +296,46 @@ public class FlatComboBoxUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth(); int width = c.getWidth();
int height = c.getHeight(); int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0; float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
int arrowX = arrowButton.getX(); int arrowX = arrowButton.getX();
int arrowWidth = arrowButton.getWidth(); int arrowWidth = arrowButton.getWidth();
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = comboBox.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground ); g2.setColor( enabled
? (editableBackground != null && comboBox.isEditable() ? editableBackground : c.getBackground())
: getDisabledBackground( comboBox ) );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background
if( enabled ) {
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint arrow button background // paint vertical line between value and arrow button
if( enabled ) { if( comboBox.isEditable() ) {
g2.setColor( comboBox.isEditable() ? buttonEditableBackground : buttonBackground ); g2.setColor( enabled ? borderColor : disabledBorderColor );
Shape oldClip = g2.getClip(); float lw = scale( 1f );
if( isLeftToRight ) float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.clipRect( arrowX, 0, width - arrowX, height ); g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
if( comboBox.isEditable() ) {
// paint vertical line between value and arrow button
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
}
} }
paint( g, c ); paint( g, c );
@@ -312,14 +345,15 @@ public class FlatComboBoxUI
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) { public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
ListCellRenderer<Object> renderer = comboBox.getRenderer(); ListCellRenderer<Object> renderer = comboBox.getRenderer();
CellPaddingBorder.uninstall( renderer ); uninstallCellPaddingBorder( renderer );
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() );
CellPaddingBorder.uninstall( c ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
uninstallCellPaddingBorder( c );
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
c.setForeground( enabled ? comboBox.getForeground() : disabledForeground ); c.setForeground( enabled ? comboBox.getForeground() : disabledForeground );
c.setBackground( enabled ? comboBox.getBackground() : disabledBackground ); c.setBackground( enabled ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
boolean shouldValidate = (c instanceof JPanel); boolean shouldValidate = (c instanceof JPanel);
if( padding != null ) if( padding != null )
@@ -336,10 +370,38 @@ public class FlatComboBoxUI
@Override @Override
public void paintCurrentValueBackground( Graphics g, Rectangle bounds, boolean hasFocus ) { public void paintCurrentValueBackground( Graphics g, Rectangle bounds, boolean hasFocus ) {
g.setColor( comboBox.isEnabled() ? comboBox.getBackground() : disabledBackground ); g.setColor( comboBox.isEnabled() ? comboBox.getBackground() : getDisabledBackground( comboBox ) );
g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height ); g.fillRect( bounds.x, bounds.y, bounds.width, bounds.height );
} }
private Color getDisabledBackground( JComponent c ) {
return isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground;
}
@Override
protected Dimension getDefaultSize() {
@SuppressWarnings( "unchecked" )
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
Dimension size = super.getDefaultSize();
uninstallCellPaddingBorder( renderer );
return size;
}
@Override
protected Dimension getDisplaySize() {
@SuppressWarnings( "unchecked" )
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
Dimension displaySize = super.getDisplaySize();
uninstallCellPaddingBorder( renderer );
return displaySize;
}
@Override @Override
protected Dimension getSizeForComponent( Component comp ) { protected Dimension getSizeForComponent( Component comp ) {
Dimension size = super.getSizeForComponent( comp ); Dimension size = super.getSizeForComponent( comp );
@@ -363,17 +425,33 @@ public class FlatComboBoxUI
return null; return null;
} }
private void uninstallCellPaddingBorder( Object o ) {
CellPaddingBorder.uninstall( o );
if( lastRendererComponent != null ) {
CellPaddingBorder.uninstall( lastRendererComponent );
lastRendererComponent = null;
}
}
//---- class FlatComboPopup ----------------------------------------------- //---- class FlatComboPopup -----------------------------------------------
@SuppressWarnings( { "rawtypes", "unchecked" } ) @SuppressWarnings( { "rawtypes", "unchecked" } )
private class FlatComboPopup private class FlatComboPopup
extends BasicComboPopup extends BasicComboPopup
implements ListCellRenderer
{ {
private CellPaddingBorder paddingBorder; private CellPaddingBorder paddingBorder;
FlatComboPopup( JComboBox combo ) { FlatComboPopup( JComboBox combo ) {
super( combo ); super( combo );
// BasicComboPopup listens to JComboBox.componentOrientation and updates
// the component orientation of the list, scroller and popup, but when
// switching the LaF and a new combo popup is created, the component
// orientation is not applied.
ComponentOrientation o = comboBox.getComponentOrientation();
list.setComponentOrientation( o );
scroller.setComponentOrientation( o );
setComponentOrientation( o );
} }
@Override @Override
@@ -387,7 +465,13 @@ public class FlatComboBoxUI
comboBox.setPrototypeDisplayValue( prototype ); comboBox.setPrototypeDisplayValue( prototype );
// make popup wider if necessary // make popup wider if necessary
pw = Math.max( pw, displaySize.width ); if( displaySize.width > pw ) {
int diff = displaySize.width - pw;
pw = displaySize.width;
if( !comboBox.getComponentOrientation().isLeftToRight() )
px -= diff;
}
return super.computePopupBounds( px, py, pw, ph ); return super.computePopupBounds( px, py, pw, ph );
} }
@@ -405,7 +489,7 @@ public class FlatComboBoxUI
protected void configureList() { protected void configureList() {
super.configureList(); super.configureList();
list.setCellRenderer( this ); list.setCellRenderer( new PopupListCellRenderer() );
} }
@Override @Override
@@ -416,27 +500,37 @@ public class FlatComboBoxUI
super.propertyChange( e ); super.propertyChange( e );
if( e.getPropertyName() == "renderer" ) if( e.getPropertyName() == "renderer" )
list.setCellRenderer( FlatComboPopup.this ); list.setCellRenderer( new PopupListCellRenderer() );
} }
}; };
} }
@Override //---- class PopupListCellRenderer -----
public Component getListCellRendererComponent( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus ) private class PopupListCellRenderer
implements ListCellRenderer
{ {
ListCellRenderer renderer = comboBox.getRenderer(); @Override
CellPaddingBorder.uninstall( renderer ); public Component getListCellRendererComponent( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus )
{
ListCellRenderer renderer = comboBox.getRenderer();
CellPaddingBorder.uninstall( renderer );
CellPaddingBorder.uninstall( lastRendererComponent );
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
c.applyComponentOrientation( comboBox.getComponentOrientation() );
if( c instanceof JComponent ) { if( c instanceof JComponent ) {
if( paddingBorder == null ) if( paddingBorder == null )
paddingBorder = new CellPaddingBorder( padding ); paddingBorder = new CellPaddingBorder( padding );
paddingBorder.install( (JComponent) c ); paddingBorder.install( (JComponent) c );
}
lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null;
return c;
} }
return c;
} }
} }
@@ -469,6 +563,9 @@ public class FlatComboBoxUI
} }
static void uninstall( Object o ) { static void uninstall( Object o ) {
if( o instanceof WeakReference )
o = ((WeakReference<?>)o).get();
if( !(o instanceof JComponent) ) if( !(o instanceof JComponent) )
return; return;

View File

@@ -18,17 +18,37 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.JTextComponent;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
* *
* TODO document used UI defaults of superclass * <!-- BasicEditorPaneUI -->
*
* @uiDefault EditorPane.font Font
* @uiDefault EditorPane.background Color also used if not editable
* @uiDefault EditorPane.foreground Color
* @uiDefault EditorPane.caretForeground Color
* @uiDefault EditorPane.selectionBackground Color
* @uiDefault EditorPane.selectionForeground Color
* @uiDefault EditorPane.disabledBackground Color used if not enabled
* @uiDefault EditorPane.inactiveBackground Color used if not editable
* @uiDefault EditorPane.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault EditorPane.border Border
* @uiDefault EditorPane.margin Insets
* @uiDefault EditorPane.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatEditorPaneUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -36,6 +56,9 @@ public class FlatEditorPaneUI
extends BasicEditorPaneUI extends BasicEditorPaneUI
{ {
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme;
private Object oldHonorDisplayProperties;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatEditorPaneUI(); return new FlatEditorPaneUI();
@@ -46,6 +69,18 @@ public class FlatEditorPaneUI
super.installDefaults(); super.installDefaults();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
// use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override @Override
@@ -66,4 +101,17 @@ public class FlatEditorPaneUI
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) ); size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
return size; return size;
} }
@Override
protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent();
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
FlatUIUtils.paintParentBackground( g, c );
return;
}
super.paintBackground( g );
}
} }

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.awt.Dimension;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalFileChooserUI;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JFileChooser}.
*
* TODO document used UI defaults of superclass
*
* @author Karl Tauber
*/
public class FlatFileChooserUI
extends MetalFileChooserUI
{
public static ComponentUI createUI( JComponent c ) {
return new FlatFileChooserUI( (JFileChooser) c );
}
public FlatFileChooserUI( JFileChooser filechooser ) {
super( filechooser );
}
@Override
public Dimension getPreferredSize( JComponent c ) {
return UIScale.scale( super.getPreferredSize( c ) );
}
@Override
public Dimension getMinimumSize( JComponent c ) {
return UIScale.scale( super.getMinimumSize( c ) );
}
}

View File

@@ -22,6 +22,26 @@ import javax.swing.plaf.ComponentUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JFormattedTextField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JFormattedTextField}.
* *
* <!-- BasicTextFieldUI -->
*
* @uiDefault FormattedTextField.font Font
* @uiDefault FormattedTextField.background Color
* @uiDefault FormattedTextField.foreground Color also used if not editable
* @uiDefault FormattedTextField.caretForeground Color
* @uiDefault FormattedTextField.selectionBackground Color
* @uiDefault FormattedTextField.selectionForeground Color
* @uiDefault FormattedTextField.disabledBackground Color used if not enabled
* @uiDefault FormattedTextField.inactiveBackground Color used if not editable
* @uiDefault FormattedTextField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault FormattedTextField.border Border
* @uiDefault FormattedTextField.margin Insets
* @uiDefault FormattedTextField.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatTextFieldUI -->
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatFormattedTextFieldUI public class FlatFormattedTextFieldUI

View File

@@ -33,10 +33,15 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JLabel}. * Provides the Flat LaF UI delegate for {@link javax.swing.JLabel}.
* *
* <!-- BasicLabelUI -->
*
* @uiDefault Label.font Font
* @uiDefault Label.background Color only used if opaque * @uiDefault Label.background Color only used if opaque
* @uiDefault Label.foreground Color * @uiDefault Label.foreground Color
*
* <!-- FlatLabelUI -->
*
* @uiDefault Label.disabledForeground Color * @uiDefault Label.disabledForeground Color
* @uiDefault Label.font Font
* *
* @author Karl Tauber * @author Karl Tauber
*/ */

View File

@@ -27,7 +27,27 @@ import javax.swing.plaf.basic.BasicListUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}. * Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
* *
* TODO document used UI defaults of superclass * <!-- BasicListUI -->
*
* @uiDefault List.font Font
* @uiDefault List.background Color
* @uiDefault List.foreground Color
* @uiDefault List.selectionBackground Color
* @uiDefault List.selectionForeground Color
* @uiDefault List.dropLineColor Color
* @uiDefault List.border Border
* @uiDefault List.cellRenderer ListCellRenderer
* @uiDefault FileChooser.listFont Font used if client property List.isFileList is true
*
* <!-- DefaultListCellRenderer -->
*
* @uiDefault List.cellNoFocusBorder Border
* @uiDefault List.focusCellHighlightBorder Border
* @uiDefault List.focusSelectedCellHighlightBorder Border
* @uiDefault List.dropCellBackground Color
* @uiDefault List.dropCellForeground Color
*
* <!-- FlatListUI -->
* *
* @uiDefault List.selectionInactiveBackground Color * @uiDefault List.selectionInactiveBackground Color
* @uiDefault List.selectionInactiveForeground Color * @uiDefault List.selectionInactiveForeground Color

View File

@@ -23,6 +23,13 @@ import javax.swing.plaf.basic.BasicMenuBarUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenuBar}.
* *
* <!-- BasicMenuBarUI -->
*
* @uiDefault MenuBar.font Font
* @uiDefault MenuBar.background Color
* @uiDefault MenuBar.foreground Color
* @uiDefault MenuBar.border Border
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuBarUI public class FlatMenuBarUI

View File

@@ -25,6 +25,26 @@ import javax.swing.plaf.basic.BasicMenuItemUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}.
* *
* <!-- BasicMenuItemUI -->
*
* @uiDefault MenuItem.font Font
* @uiDefault MenuItem.background Color
* @uiDefault MenuItem.foreground Color
* @uiDefault MenuItem.disabledForeground Color
* @uiDefault MenuItem.selectionBackground Color
* @uiDefault MenuItem.selectionForeground Color
* @uiDefault MenuItem.acceleratorForeground Color
* @uiDefault MenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault MenuItem.border Border
* @uiDefault MenuItem.borderPainted boolean
* @uiDefault MenuItem.margin Insets
* @uiDefault MenuItem.arrowIcon Icon
* @uiDefault MenuItem.checkIcon Icon
* @uiDefault MenuItem.opaque boolean
* @uiDefault MenuItem.evenHeight boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuItemUI public class FlatMenuItemUI

View File

@@ -25,6 +25,29 @@ import javax.swing.plaf.basic.BasicMenuUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}.
* *
* <!-- BasicMenuUI -->
*
* @uiDefault Menu.font Font
* @uiDefault Menu.background Color
* @uiDefault Menu.foreground Color
* @uiDefault Menu.disabledForeground Color
* @uiDefault Menu.selectionBackground Color
* @uiDefault Menu.selectionForeground Color
* @uiDefault Menu.acceleratorForeground Color
* @uiDefault Menu.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault Menu.border Border
* @uiDefault Menu.borderPainted boolean
* @uiDefault Menu.margin Insets
* @uiDefault Menu.arrowIcon Icon
* @uiDefault Menu.checkIcon Icon
* @uiDefault Menu.opaque boolean
* @uiDefault Menu.evenHeight boolean
* @uiDefault Menu.crossMenuMnemonic boolean default is false
* @uiDefault Menu.useMenuBarBackgroundForTopLevel boolean default is false
* @uiDefault MenuBar.background Color used if Menu.useMenuBarBackgroundForTopLevel is true
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuUI public class FlatMenuUI

View File

@@ -19,16 +19,25 @@ package com.formdev.flatlaf.ui;
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.Graphics;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicOptionPaneUI; import javax.swing.plaf.basic.BasicOptionPaneUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JOptionPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JOptionPane}.
* *
* @uiDefault OptionPane.font Font unused
* @uiDefault OptionPane.background Color
* @uiDefault OptionPane.foreground Color unused
* @uiDefault OptionPane.border Border * @uiDefault OptionPane.border Border
* @uiDefault OptionPane.messageAreaBorder Border * @uiDefault OptionPane.messageAreaBorder Border
* @uiDefault OptionPane.buttonAreaBorder Border * @uiDefault OptionPane.buttonAreaBorder Border
@@ -76,6 +85,13 @@ public class FlatOptionPaneUI
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
} }
@Override
protected void installComponents() {
super.installComponents();
updateChildPanels( optionPane );
}
@Override @Override
public Dimension getMinimumOptionPaneSize() { public Dimension getMinimumOptionPaneSize() {
return UIScale.scale( super.getMinimumOptionPaneSize() ); return UIScale.scale( super.getMinimumOptionPaneSize() );
@@ -122,9 +138,33 @@ public class FlatOptionPaneUI
if( messagePadding > 0 ) if( messagePadding > 0 )
cons.insets.bottom = UIScale.scale( messagePadding ); cons.insets.bottom = UIScale.scale( messagePadding );
// disable line wrapping for HTML
if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) )
maxll = Integer.MAX_VALUE;
super.addMessageComponents( container, cons, msg, maxll, internallyCreated ); super.addMessageComponents( container, cons, msg, maxll, internallyCreated );
} }
private void updateChildPanels( Container c ) {
for( Component child : c.getComponents() ) {
if( child instanceof JPanel ) {
JPanel panel = (JPanel)child;
// make sub-panel non-opaque for OptionPane.background
panel.setOpaque( false );
// use non-UIResource borders to avoid that they are replaced when switching LaF
Border border = panel.getBorder();
if( border instanceof UIResource )
panel.setBorder( new NonUIResourceBorder( border ) );
}
if( child instanceof Container ) {
updateChildPanels( (Container) child );
}
}
}
private Component findByName( Container c, String name ) { private Component findByName( Container c, String name ) {
for( Component child : c.getComponents() ) { for( Component child : c.getComponents() ) {
if( name.equals( child.getName() ) ) if( name.equals( child.getName() ) )
@@ -138,4 +178,31 @@ public class FlatOptionPaneUI
} }
return null; return null;
} }
//---- class NonUIResourceBorder ------------------------------------------
private static class NonUIResourceBorder
implements Border
{
private final Border delegate;
NonUIResourceBorder( Border delegate ) {
this.delegate = delegate;
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
delegate.paintBorder( c, g, x, y, width, height );
}
@Override
public Insets getBorderInsets( Component c ) {
return delegate.getBorderInsets( c );
}
@Override
public boolean isBorderOpaque() {
return delegate.isBorderOpaque();
}
}
} }

View File

@@ -19,24 +19,38 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.plaf.basic.BasicPasswordFieldUI;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
* *
* TODO document used UI defaults of superclass * <!-- BasicPasswordFieldUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault PasswordField.font Font
* @uiDefault Component.minimumWidth int * @uiDefault PasswordField.background Color
* @uiDefault PasswordField.foreground Color also used if not editable
* @uiDefault PasswordField.caretForeground Color
* @uiDefault PasswordField.selectionBackground Color
* @uiDefault PasswordField.selectionForeground Color
* @uiDefault PasswordField.disabledBackground Color used if not enabled
* @uiDefault PasswordField.inactiveBackground Color used if not editable
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault PasswordField.border Border
* @uiDefault PasswordField.margin Insets
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatPasswordFieldUI -->
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -45,8 +59,9 @@ public class FlatPasswordFieldUI
{ {
protected int focusWidth; protected int focusWidth;
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme;
private Handler handler; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI(); return new FlatPasswordFieldUI();
@@ -62,6 +77,9 @@ public class FlatPasswordFieldUI
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( getComponent(), focusWidth ); MigLayoutVisualPadding.install( getComponent(), focusWidth );
} }
@@ -77,71 +95,42 @@ public class FlatPasswordFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
getComponent().addFocusListener( getHandler() ); focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
getComponent().addFocusListener( focusListener );
} }
@Override @Override
protected void uninstallListeners() { protected void uninstallListeners() {
super.uninstallListeners(); super.uninstallListeners();
getComponent().removeFocusListener( getHandler() ); getComponent().removeFocusListener( focusListener );
focusListener = null;
handler = null;
} }
public Handler getHandler() { @Override
if( handler == null ) protected void paintSafely( Graphics g ) {
handler = new Handler(); FlatTextFieldUI.paintBackground( g, getComponent(), focusWidth, isIntelliJTheme );
return handler; super.paintSafely( g );
} }
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); // background is painted elsewhere
FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
g2.setColor( c.getBackground() );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0 );
} finally {
g2.dispose();
}
} }
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( super.getPreferredSize( c ) ); return applyMinimumWidth( super.getPreferredSize( c ), c );
} }
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( super.getMinimumSize( c ) ); return applyMinimumWidth( super.getMinimumSize( c ), c );
} }
private Dimension applyMinimumWidth( Dimension size ) { private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) ); size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
return size; return size;
} }
//---- class Handler ------------------------------------------------------
private class Handler
implements FocusListener
{
@Override
public void focusGained( FocusEvent e ) {
getComponent().repaint();
}
@Override
public void focusLost( FocusEvent e ) {
getComponent().repaint();
}
}
} }

View File

@@ -22,6 +22,17 @@ import javax.swing.plaf.ComponentUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu.Separator}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu.Separator}.
* *
* <!-- BasicSeparatorUI -->
*
* @uiDefault PopupMenuSeparator.background Color unused
* @uiDefault PopupMenuSeparator.foreground Color
*
* <!-- FlatSeparatorUI -->
*
* @uiDefault PopupMenuSeparator.height int height (or width) of the component; may be larger than stripe
* @uiDefault PopupMenuSeparator.stripeWidth int width of the stripe
* @uiDefault PopupMenuSeparator.stripeIndent int indent of stripe from top (or left); allows positioning of stripe within component
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatPopupMenuSeparatorUI public class FlatPopupMenuSeparatorUI

View File

@@ -23,6 +23,13 @@ import javax.swing.plaf.basic.BasicPopupMenuUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}.
* *
* <!-- BasicPopupMenuUI -->
*
* @uiDefault PopupMenu.font Font
* @uiDefault PopupMenu.background Color
* @uiDefault PopupMenu.foreground Color
* @uiDefault PopupMenu.border Border
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatPopupMenuUI public class FlatPopupMenuUI

View File

@@ -23,6 +23,7 @@ import java.awt.Insets;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI; import javax.swing.plaf.basic.BasicProgressBarUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -30,6 +31,19 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JProgressBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JProgressBar}.
* *
* <!-- BasicProgressBarUI -->
*
* @uiDefault ProgressBar.font Font
* @uiDefault ProgressBar.background Color
* @uiDefault ProgressBar.foreground Color
* @uiDefault ProgressBar.selectionBackground Color
* @uiDefault ProgressBar.selectionForeground Color
* @uiDefault ProgressBar.border Border
* @uiDefault ProgressBar.horizontalSize Dimension default is 146,12
* @uiDefault ProgressBar.verticalSize Dimension default is 12,146
* @uiDefault ProgressBar.repaintInterval int default is 50 milliseconds
* @uiDefault ProgressBar.cycleTime int default is 3000 milliseconds
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatProgressBarUI public class FlatProgressBarUI
@@ -39,6 +53,13 @@ public class FlatProgressBarUI
return new FlatProgressBarUI(); return new FlatProgressBarUI();
} }
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installProperty( progressBar, "opaque", false );
}
@Override @Override
protected Dimension getPreferredInnerHorizontal() { protected Dimension getPreferredInnerHorizontal() {
return UIScale.scale( super.getPreferredInnerHorizontal() ); return UIScale.scale( super.getPreferredInnerHorizontal() );

View File

@@ -25,6 +25,26 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}.
* *
* <!-- BasicRadioButtonMenuItemUI -->
*
* @uiDefault RadioButtonMenuItem.font Font
* @uiDefault RadioButtonMenuItem.background Color
* @uiDefault RadioButtonMenuItem.foreground Color
* @uiDefault RadioButtonMenuItem.disabledForeground Color
* @uiDefault RadioButtonMenuItem.selectionBackground Color
* @uiDefault RadioButtonMenuItem.selectionForeground Color
* @uiDefault RadioButtonMenuItem.acceleratorForeground Color
* @uiDefault RadioButtonMenuItem.acceleratorSelectionForeground Color
* @uiDefault MenuItem.acceleratorFont Font defaults to MenuItem.font
* @uiDefault MenuItem.acceleratorDelimiter String
* @uiDefault RadioButtonMenuItem.border Border
* @uiDefault RadioButtonMenuItem.borderPainted boolean
* @uiDefault RadioButtonMenuItem.margin Insets
* @uiDefault RadioButtonMenuItem.arrowIcon Icon
* @uiDefault RadioButtonMenuItem.checkIcon Icon
* @uiDefault RadioButtonMenuItem.opaque boolean
* @uiDefault RadioButtonMenuItem.evenHeight boolean
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatRadioButtonMenuItemUI public class FlatRadioButtonMenuItemUI

View File

@@ -21,19 +21,31 @@ import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Rectangle; import java.awt.Rectangle;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.CellRendererPane;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRadioButtonUI; import javax.swing.plaf.basic.BasicRadioButtonUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButton}. * Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButton}.
* *
* TODO document used UI defaults of superclass * <!-- BasicRadioButtonUI -->
* *
* @uiDefault Button.iconTextGap int * @uiDefault RadioButton.font Font
* @uiDefault Button.disabledText Color * @uiDefault RadioButton.background Color
* @uiDefault RadioButton.foreground Color
* @uiDefault RadioButton.border Border
* @uiDefault RadioButton.margin Insets
* @uiDefault RadioButton.rollover boolean
* @uiDefault RadioButton.icon Icon
*
* <!-- FlatRadioButtonUI -->
*
* @uiDefault RadioButton.iconTextGap int
* @uiDefault RadioButton.disabledText Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -66,6 +78,7 @@ public class FlatRadioButtonUI
defaults_initialized = true; defaults_initialized = true;
} }
LookAndFeel.installProperty( b, "opaque", false );
LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) ); LookAndFeel.installProperty( b, "iconTextGap", scale( iconTextGap ) );
MigLayoutVisualPadding.install( b, null ); MigLayoutVisualPadding.install( b, null );
@@ -79,6 +92,21 @@ public class FlatRadioButtonUI
defaults_initialized = false; defaults_initialized = false;
} }
@Override
public void paint( Graphics g, JComponent c ) {
// fill background even if opaque if
// - used as cell renderer (because of selection background)
// - if background was explicitly set to a non-UIResource color
if( !c.isOpaque() &&
(c.getParent() instanceof CellRendererPane || !(c.getBackground() instanceof UIResource)) )
{
g.setColor( c.getBackground() );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
}
super.paint( g, c );
}
@Override @Override
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) { protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText ); FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );

View File

@@ -32,6 +32,8 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JScrollBar}.
* *
* <!-- BasicScrollBarUI -->
*
* @uiDefault ScrollBar.background Color * @uiDefault ScrollBar.background Color
* @uiDefault ScrollBar.foreground Color * @uiDefault ScrollBar.foreground Color
* @uiDefault ScrollBar.track Color * @uiDefault ScrollBar.track Color
@@ -39,8 +41,8 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault ScrollBar.hoverTrackColor Color * @uiDefault ScrollBar.hoverTrackColor Color
* @uiDefault ScrollBar.hoverThumbColor Color * @uiDefault ScrollBar.hoverThumbColor Color
* @uiDefault ScrollBar.width int * @uiDefault ScrollBar.width int
* @uiDefault ScrollBar.minimumThumbSize Insets * @uiDefault ScrollBar.minimumThumbSize Dimension
* @uiDefault ScrollBar.maximumThumbSize Insets * @uiDefault ScrollBar.maximumThumbSize Dimension
* @uiDefault ScrollBar.allowsAbsolutePositioning boolean * @uiDefault ScrollBar.allowsAbsolutePositioning boolean
* *
* @author Karl Tauber * @author Karl Tauber

View File

@@ -17,10 +17,8 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ContainerEvent; import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener; import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
@@ -29,15 +27,22 @@ import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JViewport; import javax.swing.JViewport;
import javax.swing.ScrollPaneLayout; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicScrollPaneUI; import javax.swing.plaf.basic.BasicScrollPaneUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
* *
* <!-- BasicScrollPaneUI -->
*
* @uiDefault ScrollPane.font Font unused
* @uiDefault ScrollPane.background Color
* @uiDefault ScrollPane.foreground Color unused
* @uiDefault ScrollPane.border Border
* @uiDefault ScrollPane.viewportBorder Border
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatScrollPaneUI public class FlatScrollPaneUI
@@ -53,17 +58,14 @@ public class FlatScrollPaneUI
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
super.installUI( c ); super.installUI( c );
if( scrollpane.getLayout() instanceof UIResource ) int focusWidth = UIManager.getInt( "Component.focusWidth" );
scrollpane.setLayout( new FlatScrollPaneLayout() ); LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( scrollpane, UIManager.getInt( "Component.focusWidth" ) ); MigLayoutVisualPadding.install( scrollpane, focusWidth );
} }
@Override @Override
public void uninstallUI( JComponent c ) { public void uninstallUI( JComponent c ) {
if( scrollpane.getLayout() instanceof FlatScrollPaneLayout )
scrollpane.setLayout( new ScrollPaneLayout.UIResource() );
MigLayoutVisualPadding.uninstall( scrollpane ); MigLayoutVisualPadding.uninstall( scrollpane );
super.uninstallUI( c ); super.uninstallUI( c );
@@ -169,27 +171,4 @@ public class FlatScrollPaneUI
scrollpane.repaint(); scrollpane.repaint();
} }
} }
//---- class FlatScrollPaneLayout -----------------------------------------
private static class FlatScrollPaneLayout
extends ScrollPaneLayout
{
@Override
public void layoutContainer( Container parent ) {
super.layoutContainer( parent );
// increase height of vertical scroll bar so that it also fills the upper right corner
if( colHead != null && vsb != null && colHead.isVisible() && vsb.isVisible() ) {
Rectangle colHeadBounds = colHead.getBounds();
Rectangle vsbBounds = vsb.getBounds();
if( vsbBounds.y > colHeadBounds.y ) {
vsbBounds.height += (vsbBounds.y - colHeadBounds.y);
vsbBounds.y = colHeadBounds.y;
vsb.setBounds( vsbBounds );
}
}
}
}
} }

View File

@@ -30,8 +30,13 @@ import javax.swing.plaf.basic.BasicSeparatorUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSeparator}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSeparator}.
* *
* <!-- BasicSeparatorUI -->
*
* @uiDefault Separator.background Color unused * @uiDefault Separator.background Color unused
* @uiDefault Separator.foreground Color * @uiDefault Separator.foreground Color
*
* <!-- FlatSeparatorUI -->
*
* @uiDefault Separator.height int height (or width) of the component; may be larger than stripe * @uiDefault Separator.height int height (or width) of the component; may be larger than stripe
* @uiDefault Separator.stripeWidth int width of the stripe * @uiDefault Separator.stripeWidth int width of the stripe
* @uiDefault Separator.stripeIndent int indent of stripe from top (or left); allows positioning of stripe within component * @uiDefault Separator.stripeIndent int indent of stripe from top (or left); allows positioning of stripe within component

View File

@@ -25,6 +25,7 @@ import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSlider; import javax.swing.JSlider;
import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSliderUI; import javax.swing.plaf.basic.BasicSliderUI;
@@ -33,21 +34,27 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSlider}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSlider}.
* *
* <!-- BasicSliderUI -->
*
* @uiDefault Slider.font Font * @uiDefault Slider.font Font
* @uiDefault Slider.background Color * @uiDefault Slider.background Color
* @uiDefault Slider.foreground Color unused * @uiDefault Slider.foreground Color unused
* @uiDefault Slider.disabledForeground Color used for track and thumb if disabled
* @uiDefault Slider.trackColor Color
* @uiDefault Slider.thumbColor Color
* @uiDefault Slider.tickColor Color * @uiDefault Slider.tickColor Color
* @uiDefault Slider.focusedColor Color
* @uiDefault Slider.hoverColor Color optional; defaults to Slider.focusedColor
* @uiDefault Slider.trackWidth int
* @uiDefault Slider.thumbWidth int
* @uiDefault Slider.horizontalSize Dimension preferred horizontal size; height is ignored; computed slider height is used * @uiDefault Slider.horizontalSize Dimension preferred horizontal size; height is ignored; computed slider height is used
* @uiDefault Slider.verticalSize Dimension preferred vertical size; width is ignored; computed slider width is used * @uiDefault Slider.verticalSize Dimension preferred vertical size; width is ignored; computed slider width is used
* @uiDefault Slider.minimumHorizontalSize Dimension height is ignored; computed slider height is used * @uiDefault Slider.minimumHorizontalSize Dimension height is ignored; computed slider height is used
* @uiDefault Slider.minimumVerticalSize Dimension width is ignored; computed slider width is used * @uiDefault Slider.minimumVerticalSize Dimension width is ignored; computed slider width is used
* @uiDefault Slider.border Border
*
* <!-- FlatSliderUI -->
*
* @uiDefault Slider.trackWidth int
* @uiDefault Slider.thumbWidth int
* @uiDefault Slider.trackColor Color
* @uiDefault Slider.thumbColor Color
* @uiDefault Slider.focusedColor Color optional; defaults to Component.focusColor
* @uiDefault Slider.hoverColor Color optional; defaults to Slider.focusedColor
* @uiDefault Slider.disabledForeground Color used for track and thumb is disabled
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -96,12 +103,14 @@ public class FlatSliderUI
protected void installDefaults( JSlider slider ) { protected void installDefaults( JSlider slider ) {
super.installDefaults( slider ); super.installDefaults( slider );
LookAndFeel.installProperty( slider, "opaque", false );
trackWidth = UIManager.getInt( "Slider.trackWidth" ); trackWidth = UIManager.getInt( "Slider.trackWidth" );
thumbWidth = UIManager.getInt( "Slider.thumbWidth" ); thumbWidth = UIManager.getInt( "Slider.thumbWidth" );
trackColor = UIManager.getColor( "Slider.trackColor" ); trackColor = UIManager.getColor( "Slider.trackColor" );
thumbColor = UIManager.getColor( "Slider.thumbColor" ); thumbColor = UIManager.getColor( "Slider.thumbColor" );
focusColor = UIManager.getColor( "Slider.focusedColor" ); focusColor = FlatUIUtils.getUIColor( "Slider.focusedColor", "Component.focusColor" );
hoverColor = FlatUIUtils.getUIColor( "Slider.hoverColor", focusColor ); hoverColor = FlatUIUtils.getUIColor( "Slider.hoverColor", focusColor );
disabledForeground = UIManager.getColor( "Slider.disabledForeground" ); disabledForeground = UIManager.getColor( "Slider.disabledForeground" );
} }
@@ -170,9 +179,15 @@ public class FlatSliderUI
if( slider.getOrientation() == JSlider.HORIZONTAL ) { if( slider.getOrientation() == JSlider.HORIZONTAL ) {
float y = trackRect.y + (trackRect.height - tw) / 2f; float y = trackRect.y + (trackRect.height - tw) / 2f;
if( enabled && isRoundThumb() ) { if( enabled && isRoundThumb() ) {
int cw = thumbRect.x + (thumbRect.width / 2) - trackRect.x; if( slider.getComponentOrientation().isLeftToRight() ) {
coloredTrack = new RoundRectangle2D.Float( trackRect.x, y, cw, tw, arc, arc ); int cw = thumbRect.x + (thumbRect.width / 2) - trackRect.x;
track = new RoundRectangle2D.Float( trackRect.x + cw, y, trackRect.width - cw, tw, arc, arc ); coloredTrack = new RoundRectangle2D.Float( trackRect.x, y, cw, tw, arc, arc );
track = new RoundRectangle2D.Float( trackRect.x + cw, y, trackRect.width - cw, tw, arc, arc );
} else {
int cw = trackRect.x + trackRect.width - thumbRect.x - (thumbRect.width / 2);
coloredTrack = new RoundRectangle2D.Float( trackRect.x + trackRect.width - cw, y, cw, tw, arc, arc );
track = new RoundRectangle2D.Float( trackRect.x, y, trackRect.width - cw, tw, arc, arc );
}
} else } else
track = new RoundRectangle2D.Float( trackRect.x, y, trackRect.width, tw, arc, arc ); track = new RoundRectangle2D.Float( trackRect.x, y, trackRect.width, tw, arc, arc );
} else { } else {
@@ -186,7 +201,7 @@ public class FlatSliderUI
} }
if( coloredTrack != null ) { if( coloredTrack != null ) {
g.setColor( slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor) ); FlatUIUtils.setColor( g, slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor), thumbColor );
((Graphics2D)g).fill( coloredTrack ); ((Graphics2D)g).fill( coloredTrack );
} }
@@ -196,9 +211,10 @@ public class FlatSliderUI
@Override @Override
public void paintThumb( Graphics g ) { public void paintThumb( Graphics g ) {
g.setColor( slider.isEnabled() FlatUIUtils.setColor( g, slider.isEnabled()
? (slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor)) ? (slider.hasFocus() ? focusColor : (hover ? hoverColor : thumbColor))
: disabledForeground ); : disabledForeground,
thumbColor );
if( isRoundThumb() ) if( isRoundThumb() )
g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height ); g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height );

View File

@@ -35,6 +35,7 @@ import java.beans.PropertyChangeListener;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
@@ -43,12 +44,23 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}.
* *
* TODO document used UI defaults of superclass * <!-- BasicSpinnerUI -->
*
* @uiDefault Spinner.font Font
* @uiDefault Spinner.background Color
* @uiDefault Spinner.foreground Color
* @uiDefault Spinner.border Border
* @uiDefault Spinner.disableOnBoundaryValues boolean default is false
* @uiDefault Spinner.editorAlignment int 0=center, 2=left, 4=right, 10=leading, 11=trailing
* @uiDefault Spinner.editorBorderPainted boolean paint inner editor border; defaults to false
*
* <!-- FlatSpinnerUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.arc int * @uiDefault Component.arc int
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.arrowType String triangle (default) or chevron * @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault Component.borderColor Color * @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color * @uiDefault Component.disabledBorderColor Color
* @uiDefault Spinner.disabledBackground Color * @uiDefault Spinner.disabledBackground Color
@@ -70,6 +82,7 @@ public class FlatSpinnerUI
protected int arc; protected int arc;
protected int minimumWidth; protected int minimumWidth;
protected String arrowType; protected String arrowType;
protected boolean isIntelliJTheme;
protected Color borderColor; protected Color borderColor;
protected Color disabledBorderColor; protected Color disabledBorderColor;
protected Color disabledBackground; protected Color disabledBackground;
@@ -88,10 +101,13 @@ public class FlatSpinnerUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
LookAndFeel.installProperty( spinner, "opaque", false );
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" ); arc = UIManager.getInt( "Component.arc" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
borderColor = UIManager.getColor( "Component.borderColor" ); borderColor = UIManager.getColor( "Component.borderColor" );
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" ); disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" ); disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
@@ -152,6 +168,13 @@ public class FlatSpinnerUI
@Override @Override
protected JComponent createEditor() { protected JComponent createEditor() {
JComponent editor = super.createEditor(); JComponent editor = super.createEditor();
// explicitly make non-opaque
editor.setOpaque( false );
JTextField textField = getEditorTextField( editor );
if( textField != null )
textField.setOpaque( false );
updateEditorColors(); updateEditorColors();
return editor; return editor;
} }
@@ -183,8 +206,6 @@ public class FlatSpinnerUI
// use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI()
// is used, then the text field is updated after the spinner and the // is used, then the text field is updated after the spinner and the
// colors are again replaced with default colors // colors are again replaced with default colors
textField.setBackground( FlatUIUtils.nonUIResource( spinner.isEnabled()
? spinner.getBackground() : disabledBackground ) );
textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) ); textField.setForeground( FlatUIUtils.nonUIResource( spinner.getForeground() ) );
textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) ); textField.setDisabledTextColor( FlatUIUtils.nonUIResource( disabledForeground ) );
} }
@@ -225,45 +246,47 @@ public class FlatSpinnerUI
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) { // fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && (focusWidth > 0 || arc != 0) )
FlatUIUtils.paintParentBackground( g, c ); FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth(); int width = c.getWidth();
int height = c.getHeight(); int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0; float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
Component nextButton = getHandler().nextButton; Component nextButton = getHandler().nextButton;
int arrowX = nextButton.getX(); int arrowX = nextButton.getX();
int arrowWidth = nextButton.getWidth(); int arrowWidth = nextButton.getWidth();
boolean enabled = spinner.isEnabled(); boolean enabled = spinner.isEnabled();
boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight(); boolean isLeftToRight = spinner.getComponentOrientation().isLeftToRight();
// paint background // paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground ); g2.setColor( enabled
? c.getBackground()
: (isIntelliJTheme ? FlatUIUtils.getParentBackground( c ) : disabledBackground) );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow buttons background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc ); FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
// paint arrow buttons background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow buttons
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
} }
// paint vertical line between value and arrow buttons
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
paint( g, c ); paint( g, c );
} }
@@ -370,7 +393,6 @@ public class FlatSpinnerUI
@Override @Override
public void propertyChange( PropertyChangeEvent e ) { public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case "background":
case "foreground": case "foreground":
case "enabled": case "enabled":
updateEditorColors(); updateEditorColors();

View File

@@ -31,14 +31,19 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSplitPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSplitPane}.
* *
* @uiDefault Component.arrowType String triangle (default) or chevron * <!-- BasicSplitPaneUI -->
*
* @uiDefault SplitPane.background Color * @uiDefault SplitPane.background Color
* @uiDefault SplitPane.foreground Color unused * @uiDefault SplitPane.foreground Color unused
* @uiDefault SplitPane.dividerSize int * @uiDefault SplitPane.dividerSize int
* @uiDefault SplitPane.continuousLayout boolean
* @uiDefault SplitPane.border Border * @uiDefault SplitPane.border Border
* @uiDefault SplitPaneDivider.border Border * @uiDefault SplitPaneDivider.border Border
* @uiDefault SplitPaneDivider.draggingColor Color only used if continuousLayout is false * @uiDefault SplitPaneDivider.draggingColor Color only used if continuousLayout is false
*
* <!-- FlatSplitPaneUI -->
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault SplitPane.continuousLayout boolean
* @uiDefault SplitPaneDivider.oneTouchArrowColor Color * @uiDefault SplitPaneDivider.oneTouchArrowColor Color
* @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color * @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color
* *

View File

@@ -17,12 +17,19 @@
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.FlatClientProperties.*;
import java.awt.Color; import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font; 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.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import javax.swing.JButton; import javax.swing.JButton;
@@ -108,7 +115,6 @@ public class FlatTabbedPaneUI
tabAreaInsets = scale( tabAreaInsets ); tabAreaInsets = scale( tabAreaInsets );
tabHeight = scale( tabHeight ); tabHeight = scale( tabHeight );
tabSelectionHeight = scale( tabSelectionHeight ); tabSelectionHeight = scale( tabSelectionHeight );
contentSeparatorHeight = scale( contentSeparatorHeight );
MigLayoutVisualPadding.install( tabPane, null ); MigLayoutVisualPadding.install( tabPane, null );
} }
@@ -135,7 +141,7 @@ public class FlatTabbedPaneUI
public void propertyChange( PropertyChangeEvent e ) { public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); super.propertyChange( e );
if( "JTabbedPane.hasFullBorder".equals( e.getPropertyName() ) ) { if( TABBED_PANE_HAS_FULL_BORDER.equals( e.getPropertyName() ) ) {
tabPane.revalidate(); tabPane.revalidate();
tabPane.repaint(); tabPane.repaint();
} }
@@ -176,70 +182,45 @@ public class FlatTabbedPaneUI
@Override @Override
protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) { protected int calculateTabWidth( int tabPlacement, int tabIndex, FontMetrics metrics ) {
return super.calculateTabWidth( tabPlacement, tabIndex, metrics ) - 3 // was added by superclass return super.calculateTabWidth( tabPlacement, tabIndex, metrics ) - 3 /* was added by superclass */;
+ (!isTopOrBottom( tabPlacement ) && isScrollTabLayout() ? contentSeparatorHeight : 0);
} }
@Override @Override
protected int calculateTabHeight( int tabPlacement, int tabIndex, int fontHeight ) { protected int calculateTabHeight( int tabPlacement, int tabIndex, int fontHeight ) {
return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, fontHeight ) - 2 /* was added by superclass */ ) return Math.max( tabHeight, super.calculateTabHeight( tabPlacement, tabIndex, fontHeight ) - 2 /* was added by superclass */ );
+ (isTopOrBottom( tabPlacement ) && isScrollTabLayout() ? contentSeparatorHeight : 0);
} }
/** /**
* The content border insets are used to create a separator between tabs and content. * The content border insets are used to create a separator between tabs and content.
* Except in scroll tab policy, where the separator is painted in paintTabArea().
* If client property JTabbedPane.hasFullBorder is true, then the content border insets * If client property JTabbedPane.hasFullBorder is true, then the content border insets
* are also used for the border. * are also used for the border.
*/ */
@Override @Override
protected Insets getContentBorderInsets( int tabPlacement ) { protected Insets getContentBorderInsets( int tabPlacement ) {
boolean hasFullBorder = this.hasFullBorder || (tabPane.getClientProperty( "JTabbedPane.hasFullBorder" ) == Boolean.TRUE); boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = contentSeparatorHeight; int sh = scale( contentSeparatorHeight );
Insets insets = hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 ); Insets insets = hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 );
if( isScrollTabLayout() ) Insets contentBorderInsets = new Insets( 0, 0, 0, 0 );
insets.top = 0;
rotateInsets( insets, contentBorderInsets, tabPlacement ); rotateInsets( insets, contentBorderInsets, tabPlacement );
return contentBorderInsets; return contentBorderInsets;
} }
@Override @Override
protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) { protected int getTabLabelShiftX( int tabPlacement, int tabIndex, boolean isSelected ) {
if( isScrollTabLayout() && !isTopOrBottom( tabPlacement ) ) { return 0;
float shift = contentSeparatorHeight / 2f;
return Math.round( tabPlacement == LEFT ? -shift : shift );
} else
return 0;
} }
@Override @Override
protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) { protected int getTabLabelShiftY( int tabPlacement, int tabIndex, boolean isSelected ) {
if( isScrollTabLayout() && isTopOrBottom( tabPlacement ) ) { return 0;
float shift = contentSeparatorHeight / 2f;
return Math.round( tabPlacement == TOP ? -shift : shift );
} else
return 0;
} }
@Override @Override
protected void paintTabArea( Graphics g, int tabPlacement, int selectedIndex ) { public void update( Graphics g, JComponent c ) {
if( isScrollTabLayout() ) { FlatUIUtils.setRenderingHints( (Graphics2D) g );
// paint separator between tabs and content
Rectangle bounds = g.getClipBounds();
g.setColor( contentAreaColor );
if( tabPlacement == TOP || tabPlacement == BOTTOM ) { super.update( g, c );
int y = (tabPlacement == TOP) ? bounds.y + bounds.height - contentSeparatorHeight : bounds.y;
g.fillRect( bounds.x, y, bounds.x + bounds.width, contentSeparatorHeight );
} else {
int x = (tabPlacement == LEFT) ? bounds.x + bounds.width - contentSeparatorHeight : bounds.x;
g.fillRect( x, bounds.y, contentSeparatorHeight, bounds.y + bounds.height );
}
}
super.paintTabArea( g, tabPlacement, selectedIndex );
} }
@Override @Override
@@ -275,19 +256,6 @@ public class FlatTabbedPaneUI
protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) int x, int y, int w, int h, boolean isSelected )
{ {
if( isScrollTabLayout() ) {
// make tab bounds smaller for separator between tabs and content
if( tabPlacement == TOP || tabPlacement == BOTTOM ) {
if( tabPlacement == BOTTOM )
y += contentSeparatorHeight;
h -= contentSeparatorHeight;
} else {
if( tabPlacement == RIGHT )
x += contentSeparatorHeight;
w -= contentSeparatorHeight;
}
}
// paint tab background // paint tab background
boolean enabled = tabPane.isEnabled(); boolean enabled = tabPane.isEnabled();
g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex g.setColor( enabled && tabPane.isEnabledAt( tabIndex ) && getRolloverTab() == tabIndex
@@ -302,8 +270,38 @@ public class FlatTabbedPaneUI
protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex, protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected ) int x, int y, int w, int h, boolean isSelected )
{ {
if( !isSelected ) if( isSelected )
return; paintTabSelection( g, tabPlacement, x, y, w, h );
}
protected void paintTabSelection( Graphics g, int tabPlacement, int x, int y, int w, int h ) {
// increase clip bounds in scroll-tab-layout to paint over the separator line
Rectangle clipBounds = isScrollTabLayout() ? g.getClipBounds() : null;
if( clipBounds != null ) {
Rectangle newClipBounds = new Rectangle( clipBounds );
int contentSeparatorHeight = scale( this.contentSeparatorHeight );
switch( tabPlacement ) {
case TOP:
default:
newClipBounds.height += contentSeparatorHeight;
break;
case BOTTOM:
newClipBounds.y -= contentSeparatorHeight;
newClipBounds.height += contentSeparatorHeight;
break;
case LEFT:
newClipBounds.width += contentSeparatorHeight;
break;
case RIGHT:
newClipBounds.x -= contentSeparatorHeight;
newClipBounds.width += contentSeparatorHeight;
break;
}
g.setClip( newClipBounds );
}
g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor ); g.setColor( tabPane.isEnabled() ? underlineColor : disabledUnderlineColor );
@@ -330,13 +328,16 @@ public class FlatTabbedPaneUI
g.fillRect( x - contentInsets.right, y, tabSelectionHeight, h ); g.fillRect( x - contentInsets.right, y, tabSelectionHeight, h );
break; break;
} }
if( clipBounds != null )
g.setClip( clipBounds );
} }
/** /**
* Actually does the nearly the same as super.paintContentBorder() but * Actually does the nearly the same as super.paintContentBorder() but
* - content pane is always opaque
* - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly * - not using UIManager.getColor("TabbedPane.contentAreaColor") to be GUI builder friendly
* - not invoking paintContentBorder*Edge() methods * - not invoking paintContentBorder*Edge() methods
* - repaint selection
*/ */
@Override @Override
protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) { protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) {
@@ -377,9 +378,34 @@ public class FlatTabbedPaneUI
h -= (y - insets.top); h -= (y - insets.top);
} }
// compute insets for separator or full border
boolean hasFullBorder = this.hasFullBorder || clientPropertyEquals( tabPane, TABBED_PANE_HAS_FULL_BORDER, true );
int sh = scale( contentSeparatorHeight * 100 ); // multiply by 100 because rotateInsets() does not use floats
Insets ci = new Insets( 0, 0, 0, 0 );
rotateInsets( hasFullBorder ? new Insets( sh, sh, sh, sh ) : new Insets( sh, 0, 0, 0 ), ci, tabPlacement );
// paint content area // paint content area
g.setColor( contentAreaColor ); g.setColor( contentAreaColor );
g.fillRect( x, y, w, h ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( new Rectangle2D.Float( x, y, w, h ), false );
path.append( new Rectangle2D.Float( x + (ci.left / 100f), y + (ci.top / 100f),
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
((Graphics2D)g).fill( path );
// repaint selection in scroll-tab-layout because it may be painted before
// the content border was painted (from BasicTabbedPaneUI$ScrollableTabPanel)
if( isScrollTabLayout() && selectedIndex >= 0 ) {
Component scrollableTabViewport = findComponentByClassName( tabPane,
BasicTabbedPaneUI.class.getName() + "$ScrollableTabViewport" );
if( scrollableTabViewport != null ) {
Rectangle tabRect = getTabBounds( tabPane, selectedIndex );
Shape oldClip = g.getClip();
g.setClip( scrollableTabViewport.getBounds() );
paintTabSelection( g, tabPlacement, tabRect.x, tabRect.y, tabRect.width, tabRect.height );
g.setClip( oldClip );
}
}
} }
@Override @Override
@@ -392,7 +418,17 @@ public class FlatTabbedPaneUI
return tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT; return tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
} }
private boolean isTopOrBottom( int tabPlacement ) { private Component findComponentByClassName( Container c, String className ) {
return tabPlacement == TOP || tabPlacement == BOTTOM; for( Component child : c.getComponents() ) {
if( className.equals( child.getClass().getName() ) )
return child;
if( child instanceof Container ) {
Component c2 = findComponentByClassName( (Container) child, className );
if( c2 != null )
return c2;
}
}
return null;
} }
} }

View File

@@ -36,7 +36,13 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.table.JTableHeader}. * Provides the Flat LaF UI delegate for {@link javax.swing.table.JTableHeader}.
* *
* TODO document used UI defaults of superclass * <!-- BasicTableHeaderUI -->
*
* @uiDefault TableHeader.font Font
* @uiDefault TableHeader.background Color
* @uiDefault TableHeader.foreground Color
*
* <!-- FlatTableHeaderUI -->
* *
* @uiDefault TableHeader.separatorColor Color * @uiDefault TableHeader.separatorColor Color
* @uiDefault TableHeader.bottomSeparatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color
@@ -75,8 +81,10 @@ public class FlatTableHeaderUI
@Override @Override
public void paint( Graphics g, JComponent c ) { public void paint( Graphics g, JComponent c ) {
// do not paint borders if JTableHeader.setDefaultRenderer() was used // do not paint borders if JTableHeader.setDefaultRenderer() was used
boolean paintBorders = header.getDefaultRenderer().getClass().getName().equals( String rendererClassName = header.getDefaultRenderer().getClass().getName();
"sun.swing.table.DefaultTableCellHeaderRenderer" ); boolean paintBorders =
rendererClassName.equals( "sun.swing.table.DefaultTableCellHeaderRenderer" ) ||
rendererClassName.equals( "sun.swing.FilePane$AlignableTableHeaderRenderer" );
if( paintBorders ) if( paintBorders )
paintColumnBorders( g, c ); paintColumnBorders( g, c );

View File

@@ -29,7 +29,30 @@ import com.formdev.flatlaf.util.UIScale;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTable}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTable}.
* *
* TODO document used UI defaults of superclass * <!-- BasicTableUI -->
*
* @uiDefault Table.font Font
* @uiDefault Table.background Color
* @uiDefault Table.foreground Color
* @uiDefault Table.selectionBackground Color
* @uiDefault Table.selectionForeground Color
* @uiDefault Table.gridColor Color
* @uiDefault Table.scrollPaneBorder Border
* @uiDefault Table.dropLineColor Color
* @uiDefault Table.dropLineShortColor Color
*
* <!-- DefaultTableCellRenderer -->
*
* @uiDefault Table.cellNoFocusBorder Border
* @uiDefault Table.focusCellHighlightBorder Border
* @uiDefault Table.focusSelectedCellHighlightBorder Border
* @uiDefault Table.dropCellBackground Color
* @uiDefault Table.dropCellForeground Color
* @uiDefault Table.alternateRowColor Color
* @uiDefault Table.focusCellBackground Color
* @uiDefault Table.focusCellForeground Color
*
* <!-- FlatTableUI -->
* *
* @uiDefault Table.rowHeight int * @uiDefault Table.rowHeight int
* @uiDefault Table.selectionInactiveBackground Color * @uiDefault Table.selectionInactiveBackground 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 javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
@@ -30,11 +31,25 @@ import javax.swing.text.JTextComponent;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
* *
* TODO document used UI defaults of superclass * <!-- BasicTextAreaUI -->
*
* @uiDefault TextArea.font Font
* @uiDefault TextArea.background Color
* @uiDefault TextArea.foreground Color also used if not editable
* @uiDefault TextArea.caretForeground Color
* @uiDefault TextArea.selectionBackground Color
* @uiDefault TextArea.selectionForeground Color
* @uiDefault TextArea.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault TextArea.border Border
* @uiDefault TextArea.margin Insets
* @uiDefault TextArea.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatTextAreaUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault TextArea.disabledBackground Color * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextArea.inactiveBackground Color * @uiDefault TextArea.disabledBackground Color used if not enabled
* @uiDefault TextArea.inactiveBackground Color used if not editable
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -42,6 +57,7 @@ public class FlatTextAreaUI
extends BasicTextAreaUI extends BasicTextAreaUI
{ {
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme;
protected Color disabledBackground; protected Color disabledBackground;
protected Color inactiveBackground; protected Color inactiveBackground;
@@ -54,6 +70,7 @@ public class FlatTextAreaUI
super.installDefaults(); super.installDefaults();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
disabledBackground = UIManager.getColor( "TextArea.disabledBackground" ); disabledBackground = UIManager.getColor( "TextArea.disabledBackground" );
inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" ); inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" );
} }
@@ -73,23 +90,29 @@ public class FlatTextAreaUI
Color background = c.getBackground(); Color background = c.getBackground();
g.setColor( !(background instanceof UIResource) g.setColor( !(background instanceof UIResource)
? background ? background
: (!c.isEnabled() : (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
? disabledBackground ? FlatUIUtils.getParentBackground( c )
: (!c.isEditable() ? inactiveBackground : background)) ); : (!c.isEnabled()
? disabledBackground
: (!c.isEditable() ? inactiveBackground : background))) );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
} }
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( super.getPreferredSize( c ) ); return applyMinimumWidth( super.getPreferredSize( c ), c );
} }
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
return applyMinimumWidth( super.getMinimumSize( c ) ); return applyMinimumWidth( super.getMinimumSize( c ), c );
} }
private Dimension applyMinimumWidth( Dimension size ) { private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
// do not apply minimum width if JTextArea.columns is set
if( c instanceof JTextArea && ((JTextArea)c).getColumns() > 0 )
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

@@ -17,27 +17,46 @@
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 java.awt.Color;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
* *
* TODO document used UI defaults of superclass * <!-- BasicTextFieldUI -->
*
* @uiDefault TextField.font Font
* @uiDefault TextField.background Color
* @uiDefault TextField.foreground Color also used if not editable
* @uiDefault TextField.caretForeground Color
* @uiDefault TextField.selectionBackground Color
* @uiDefault TextField.selectionForeground Color
* @uiDefault TextField.disabledBackground Color used if not enabled
* @uiDefault TextField.inactiveBackground Color used if not editable
* @uiDefault TextField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault TextField.border Border
* @uiDefault TextField.margin Insets
* @uiDefault TextField.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatTextFieldUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -46,8 +65,9 @@ public class FlatTextFieldUI
{ {
protected int focusWidth; protected int focusWidth;
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme;
private Handler handler; private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextFieldUI(); return new FlatTextFieldUI();
@@ -59,6 +79,9 @@ public class FlatTextFieldUI
focusWidth = UIManager.getInt( "Component.focusWidth" ); focusWidth = UIManager.getInt( "Component.focusWidth" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
LookAndFeel.installProperty( getComponent(), "opaque", focusWidth == 0 );
MigLayoutVisualPadding.install( getComponent(), focusWidth ); MigLayoutVisualPadding.install( getComponent(), focusWidth );
} }
@@ -74,38 +97,56 @@ public class FlatTextFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
getComponent().addFocusListener( getHandler() ); focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() );
getComponent().addFocusListener( focusListener );
} }
@Override @Override
protected void uninstallListeners() { protected void uninstallListeners() {
super.uninstallListeners(); super.uninstallListeners();
getComponent().removeFocusListener( getHandler() ); getComponent().removeFocusListener( focusListener );
focusListener = null;
handler = null;
} }
public Handler getHandler() { @Override
if( handler == null ) protected void paintSafely( Graphics g ) {
handler = new Handler(); paintBackground( g, getComponent(), focusWidth, isIntelliJTheme );
return handler; super.paintSafely( g );
} }
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); // background is painted elsewhere
}
FlatUIUtils.paintParentBackground( g, c ); static void paintBackground( Graphics g, JTextComponent c, int focusWidth, boolean isIntelliJTheme ) {
// do not paint background if:
// - not opaque and
// - border is not a flat border and
// - opaque was explicitly set (to false)
// (same behaviour as in AquaTextFieldUI)
if( !c.isOpaque() && !(c.getBorder() instanceof FlatBorder) && FlatUIUtils.hasOpaqueBeenExplicitlySet( c ) )
return;
// fill background if opaque to avoid garbage if user sets opaque to true
if( c.isOpaque() && focusWidth > 0 )
FlatUIUtils.paintParentBackground( g, c );
// paint background
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0; float fFocusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) focusWidth ) : 0;
g2.setColor( c.getBackground() ); Color background = c.getBackground();
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, 0 ); g2.setColor( !(background instanceof UIResource)
? background
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
? FlatUIUtils.getParentBackground( c )
: background) );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), fFocusWidth, 0 );
} finally { } finally {
g2.dispose(); g2.dispose();
} }
@@ -122,29 +163,18 @@ public class FlatTextFieldUI
} }
private Dimension applyMinimumWidth( Dimension size, JComponent c ) { private Dimension applyMinimumWidth( Dimension size, JComponent c ) {
// do not apply minimum width if JTextField.columns is set
if( c instanceof JTextField && ((JTextField)c).getColumns() > 0 )
return size;
Container parent = c.getParent(); Container parent = c.getParent();
if( parent instanceof JComboBox || if( parent instanceof JComboBox ||
parent instanceof JSpinner || parent instanceof JSpinner ||
(parent != null && parent.getParent() instanceof JSpinner) ) (parent != null && parent.getParent() instanceof JSpinner) )
return size; return size;
int focusWidth = (c.getBorder() instanceof FlatBorder) ? this.focusWidth : 0;
size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) ); size.width = Math.max( size.width, scale( minimumWidth + (focusWidth * 2) ) );
return size; return size;
} }
//---- class Handler ------------------------------------------------------
private class Handler
implements FocusListener
{
@Override
public void focusGained( FocusEvent e ) {
getComponent().repaint();
}
@Override
public void focusLost( FocusEvent e ) {
getComponent().repaint();
}
}
} }

View File

@@ -18,17 +18,37 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.JTextComponent;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
* *
* TODO document used UI defaults of superclass * <!-- BasicTextPaneUI -->
*
* @uiDefault TextPane.font Font
* @uiDefault TextPane.background Color
* @uiDefault TextPane.foreground Color also used if not editable
* @uiDefault TextPane.caretForeground Color
* @uiDefault TextPane.selectionBackground Color
* @uiDefault TextPane.selectionForeground Color
* @uiDefault TextPane.disabledBackground Color used if not enabled
* @uiDefault TextPane.inactiveBackground Color used if not editable
* @uiDefault TextPane.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault TextPane.border Border
* @uiDefault TextPane.margin Insets
* @uiDefault TextPane.caretBlinkRate int default is 500 milliseconds
*
* <!-- FlatTextPaneUI -->
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -36,6 +56,9 @@ public class FlatTextPaneUI
extends BasicTextPaneUI extends BasicTextPaneUI
{ {
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme;
private Object oldHonorDisplayProperties;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextPaneUI(); return new FlatTextPaneUI();
@@ -46,6 +69,18 @@ public class FlatTextPaneUI
super.installDefaults(); super.installDefaults();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
// use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, true );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override @Override
@@ -66,4 +101,17 @@ public class FlatTextPaneUI
size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) ); size.width = Math.max( size.width, scale( minimumWidth ) - (scale( 1 ) * 2) );
return size; return size;
} }
@Override
protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent();
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
FlatUIUtils.paintParentBackground( g, c );
return;
}
super.paintBackground( g );
}
} }

View File

@@ -26,17 +26,31 @@ import javax.swing.plaf.ComponentUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToggleButton}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToggleButton}.
* *
* TODO document used UI defaults of superclass * <!-- BasicButtonUI -->
*
* @uiDefault ToggleButton.font Font
* @uiDefault ToggleButton.background Color
* @uiDefault ToggleButton.foreground Color
* @uiDefault ToggleButton.border Border
* @uiDefault ToggleButton.margin Insets
* @uiDefault ToggleButton.rollover boolean
*
* <!-- FlatButtonUI -->
* *
* @uiDefault Component.focusWidth int * @uiDefault Component.focusWidth int
* @uiDefault ToggleButton.arc int * @uiDefault ToggleButton.arc int
* @uiDefault ToggleButton.minimumWidth int
* @uiDefault ToggleButton.iconTextGap int
* @uiDefault ToggleButton.pressedBackground Color * @uiDefault ToggleButton.pressedBackground Color
* @uiDefault ToggleButton.disabledText Color * @uiDefault ToggleButton.disabledText Color
* @uiDefault ToggleButton.toolbar.hoverBackground Color
* @uiDefault ToggleButton.toolbar.pressedBackground Color
*
* <!-- FlatToggleButtonUI -->
*
* @uiDefault ToggleButton.selectedBackground Color * @uiDefault ToggleButton.selectedBackground Color
* @uiDefault ToggleButton.selectedForeground Color * @uiDefault ToggleButton.selectedForeground Color
* @uiDefault ToggleButton.disabledSelectedBackground Color * @uiDefault ToggleButton.disabledSelectedBackground Color
* @uiDefault ToggleButton.toolbar.hoverBackground Color
* @uiDefault ToggleButton.toolbar.pressedBackground Color
* @uiDefault ToggleButton.toolbar.selectedBackground Color * @uiDefault ToggleButton.toolbar.selectedBackground Color
* *
* *

View File

@@ -33,6 +33,8 @@ import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar.Separator}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar.Separator}.
* *
* <!-- FlatToolBarSeparatorUI -->
*
* @uiDefault ToolBar.separatorWidth int * @uiDefault ToolBar.separatorWidth int
* @uiDefault ToolBar.separatorColor Color * @uiDefault ToolBar.separatorColor Color
* *

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Component; import java.awt.Component;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.ContainerEvent;
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.UIManager;
@@ -31,7 +33,19 @@ import javax.swing.plaf.basic.BasicToolBarUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}.
* *
* TODO document used UI defaults of superclass * <!-- BasicToolBarUI -->
*
* @uiDefault ToolBar.font Font
* @uiDefault ToolBar.background Color
* @uiDefault ToolBar.foreground Color
* @uiDefault ToolBar.border Border
* @uiDefault ToolBar.dockingBackground Color
* @uiDefault ToolBar.dockingForeground Color
* @uiDefault ToolBar.floatingBackground Color
* @uiDefault ToolBar.floatingForeground Color
* @uiDefault ToolBar.isRollover boolean
*
* <!-- FlatToolBarUI -->
* *
* @uiDefault ToolBar.buttonMargins Insets * @uiDefault ToolBar.buttonMargins Insets
* *
@@ -53,6 +67,29 @@ public class FlatToolBarUI
rolloverBorder = null; rolloverBorder = null;
} }
@Override
protected ContainerListener createToolBarContListener() {
return new ToolBarContListener() {
@Override
public void componentAdded( ContainerEvent e ) {
super.componentAdded( e );
Component c = e.getChild();
if( c instanceof AbstractButton )
c.setFocusable( false );
}
@Override
public void componentRemoved( ContainerEvent e ) {
super.componentRemoved( e );
Component c = e.getChild();
if( c instanceof AbstractButton )
c.setFocusable( true );
}
};
}
@Override @Override
protected Border createRolloverBorder() { protected Border createRolloverBorder() {
return getRolloverBorder(); return getRolloverBorder();

View File

@@ -27,11 +27,21 @@ import javax.swing.JToolTip;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolTipUI; import javax.swing.plaf.basic.BasicToolTipUI;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.StringUtils;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolTip}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToolTip}.
* *
* <!-- BasicToolTipUI -->
*
* @uiDefault ToolTip.font Font
* @uiDefault ToolTip.background Color
* @uiDefault ToolTip.foreground Color
* @uiDefault ToolTip.backgroundInactive Color
* @uiDefault ToolTip.foregroundInactive Color
* @uiDefault ToolTip.border Border
* @uiDefault ToolTip.borderInactive Border
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatToolTipUI public class FlatToolTipUI
@@ -51,7 +61,7 @@ public class FlatToolTipUI
FontMetrics fm = c.getFontMetrics( c.getFont() ); FontMetrics fm = c.getFontMetrics( c.getFont() );
Insets insets = c.getInsets(); Insets insets = c.getInsets();
List<String> lines = FlatLaf.split( ((JToolTip)c).getTipText(), '\n' ); List<String> lines = StringUtils.split( ((JToolTip)c).getTipText(), '\n' );
int width = 0; int width = 0;
int height = fm.getHeight() * Math.max( lines.size(), 1 ); int height = fm.getHeight() * Math.max( lines.size(), 1 );
for( String line : lines ) for( String line : lines )
@@ -71,14 +81,17 @@ public class FlatToolTipUI
FlatUIUtils.setRenderingHints( (Graphics2D) g ); FlatUIUtils.setRenderingHints( (Graphics2D) g );
g.setColor( c.getForeground() ); g.setColor( c.getForeground() );
List<String> lines = FlatLaf.split( ((JToolTip)c).getTipText(), '\n' ); List<String> lines = StringUtils.split( ((JToolTip)c).getTipText(), '\n' );
int x = insets.left; int x = insets.left;
int x2 = c.getWidth() - insets.right;
int y = insets.top - fm.getDescent(); int y = insets.top - fm.getDescent();
int lineHeight = fm.getHeight(); int lineHeight = fm.getHeight();
JComponent comp = ((JToolTip)c).getComponent();
boolean leftToRight = (comp != null ? comp : c).getComponentOrientation().isLeftToRight();
for( String line : lines ) { for( String line : lines ) {
y += lineHeight; y += lineHeight;
g.drawString( line, x, y ); FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
} }
} else } else
super.paint( g, c ); super.paint( g, c );

View File

@@ -17,13 +17,17 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Component;
import java.awt.Container; import java.awt.Container;
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.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Shape; import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
@@ -31,8 +35,10 @@ import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.JavaCompatibility; import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -61,6 +67,20 @@ public class FlatUIUtils
r.height - insets.top - insets.bottom ); r.height - insets.top - insets.bottom );
} }
public static Dimension addInsets( Dimension dim, Insets insets ) {
return new Dimension(
dim.width + insets.left + insets.right,
dim.height + insets.top + insets.bottom );
}
public static Insets addInsets( Insets insets1, Insets insets2 ) {
return new Insets(
insets1.top + insets2.top,
insets1.left + insets2.left,
insets1.bottom + insets2.bottom,
insets1.right + insets2.right );
}
public static Color getUIColor( String key, int defaultColorRGB ) { public static Color getUIColor( String key, int defaultColorRGB ) {
Color color = UIManager.getColor( key ); Color color = UIManager.getColor( key );
return (color != null) ? color : new Color( defaultColorRGB ); return (color != null) ? color : new Color( defaultColorRGB );
@@ -71,6 +91,11 @@ public class FlatUIUtils
return (color != null) ? color : defaultColor; return (color != null) ? color : defaultColor;
} }
public static Color getUIColor( String key, String defaultKey ) {
Color color = UIManager.getColor( key );
return (color != null) ? color : UIManager.getColor( defaultKey );
}
public static int getUIInt( String key, int defaultValue ) { public static int getUIInt( String key, int defaultValue ) {
Object value = UIManager.get( key ); Object value = UIManager.get( key );
return (value instanceof Integer) ? (Integer) value : defaultValue; return (value instanceof Integer) ? (Integer) value : defaultValue;
@@ -80,6 +105,10 @@ public class FlatUIUtils
return (c instanceof ColorUIResource) ? new Color( c.getRGB(), true ) : c; return (c instanceof ColorUIResource) ? new Color( c.getRGB(), true ) : c;
} }
public static boolean isTableCellEditor( Component c ) {
return c instanceof JComponent && Boolean.TRUE.equals( ((JComponent)c).getClientProperty( "JComboBox.isTableCellEditor" ) );
}
/** /**
* Sets rendering hints used for painting. * Sets rendering hints used for painting.
*/ */
@@ -89,6 +118,12 @@ public class FlatUIUtils
MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE ); MAC_USE_QUARTZ ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE );
} }
public static void setColor( Graphics g, Color color, Color baseColor ) {
if( color instanceof DerivedColor )
color = ((DerivedColor)color).derive( baseColor );
g.setColor( color );
}
/** /**
* Draws a round rectangle. * Draws a round rectangle.
*/ */
@@ -133,6 +168,16 @@ public class FlatUIUtils
} }
} }
/**
* Gets the background color of the first opaque parent.
*/
public static Color getParentBackground( JComponent c ) {
Container parent = findOpaqueParent( c );
return (parent != null)
? parent.getBackground()
: UIManager.getColor( "Panel.background" ); // fallback, probably never used
}
/** /**
* Find the first parent that is opaque. * Find the first parent that is opaque.
*/ */
@@ -160,21 +205,52 @@ public class FlatUIUtils
} }
private static Shape createOutlinePath( float x, float y, float width, float height, float arc ) { private static Shape createOutlinePath( float x, float y, float width, float height, float arc ) {
if( arc <= 0 ) return createRoundRectanglePath( x, y, width, height, arc, arc, arc, arc );
}
/**
* Creates a not-filled rounded rectangle shape and allows specifying the line width and the radius or each corner.
*/
public static Path2D createRoundRectangle( float x, float y, float width, float height,
float lineWidth, float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight )
{
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
path.append( createRoundRectanglePath( x, y, width, height, arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight ), false );
path.append( createRoundRectanglePath( x + lineWidth, y + lineWidth, width - (lineWidth * 2), height - (lineWidth * 2),
arcTopLeft - lineWidth, arcTopRight - lineWidth, arcBottomLeft - lineWidth, arcBottomRight - lineWidth ), false );
return path;
}
/**
* Creates a filled rounded rectangle shape and allows specifying the radius or each corner.
*/
public static Shape createRoundRectanglePath( float x, float y, float width, float height,
float arcTopLeft, float arcTopRight, float arcBottomLeft, float arcBottomRight )
{
if( arcTopLeft <= 0 && arcTopRight <= 0 && arcBottomLeft <= 0 && arcBottomRight <= 0 )
return new Rectangle2D.Float( x, y, width, height ); return new Rectangle2D.Float( x, y, width, height );
if( arcTopLeft < 0 )
arcTopLeft = 0;
if( arcTopRight < 0 )
arcTopRight = 0;
if( arcBottomLeft < 0 )
arcBottomLeft = 0;
if( arcBottomRight < 0 )
arcBottomRight = 0;
float x2 = x + width; float x2 = x + width;
float y2 = y + height; float y2 = y + height;
Path2D rect = new Path2D.Float(); Path2D rect = new Path2D.Float();
rect.moveTo( x2 - arc, y ); rect.moveTo( x2 - arcTopRight, y );
rect.quadTo( x2, y, x2, y + arc ); rect.quadTo( x2, y, x2, y + arcTopRight );
rect.lineTo( x2, y2 - arc ); rect.lineTo( x2, y2 - arcBottomRight );
rect.quadTo( x2, y2, x2 - arc, y2 ); rect.quadTo( x2, y2, x2 - arcBottomRight, y2 );
rect.lineTo( x + arc, y2 ); rect.lineTo( x + arcBottomLeft, y2 );
rect.quadTo( x, y2, x, y2 - arc ); rect.quadTo( x, y2, x, y2 - arcBottomLeft );
rect.lineTo( x, y + arc ); rect.lineTo( x, y + arcTopLeft );
rect.quadTo( x, y, x + arc, y ); rect.quadTo( x, y, x + arcTopLeft, y );
rect.closePath(); rect.closePath();
return rect; return rect;
@@ -195,6 +271,22 @@ public class FlatUIUtils
} }
/** /**
* Draws the given string at the specified location using text properties
* and anti-aliasing hints from the provided component.
*
* Use this method instead of Graphics.drawString() for correct anti-aliasing.
*
* Replacement for SwingUtilities2.drawString()
*/
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y );
}
/**
* Draws the given string at the specified location underlining the specified
* character. The provided component is used to query text properties and
* anti-aliasing hints.
*
* Replacement for SwingUtilities2.drawStringUnderlineCharAt() * Replacement for SwingUtilities2.drawStringUnderlineCharAt()
*/ */
public static void drawStringUnderlineCharAt( JComponent c, Graphics g, public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
@@ -203,15 +295,23 @@ public class FlatUIUtils
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y ); JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
} }
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {
boolean oldOpaque = c.isOpaque();
LookAndFeel.installProperty( c, "opaque", !oldOpaque );
boolean explicitlySet = c.isOpaque() == oldOpaque;
LookAndFeel.installProperty( c, "opaque", oldOpaque );
return explicitlySet;
}
//---- class HoverListener ------------------------------------------------ //---- class HoverListener ------------------------------------------------
public static class HoverListener public static class HoverListener
extends MouseAdapter extends MouseAdapter
{ {
private final JComponent repaintComponent; private final Component repaintComponent;
private final Consumer<Boolean> hoverChanged; private final Consumer<Boolean> hoverChanged;
public HoverListener( JComponent repaintComponent, Consumer<Boolean> hoverChanged ) { public HoverListener( Component repaintComponent, Consumer<Boolean> hoverChanged ) {
this.repaintComponent = repaintComponent; this.repaintComponent = repaintComponent;
this.hoverChanged = hoverChanged; this.hoverChanged = hoverChanged;
} }
@@ -233,4 +333,26 @@ public class FlatUIUtils
repaintComponent.repaint(); repaintComponent.repaint();
} }
} }
//---- class RepaintFocusListener -----------------------------------------
public static class RepaintFocusListener
implements FocusListener
{
private final Component repaintComponent;
public RepaintFocusListener( Component repaintComponent ) {
this.repaintComponent = repaintComponent;
}
@Override
public void focusGained( FocusEvent e ) {
repaintComponent.repaint();
}
@Override
public void focusLost( FocusEvent e ) {
repaintComponent.repaint();
}
}
} }

View File

@@ -27,6 +27,12 @@ import javax.swing.plaf.basic.BasicViewportUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JViewport}. * Provides the Flat LaF UI delegate for {@link javax.swing.JViewport}.
* *
* <!-- BasicViewportUI -->
*
* @uiDefault Viewport.font Font unused
* @uiDefault Viewport.background Color
* @uiDefault Viewport.foreground Color unused
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatViewportUI public class FlatViewportUI

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
import java.awt.Color;
/**
* Functions that modify colors.
*
* @author Karl Tauber
*/
public class ColorFunctions
{
public static Color applyFunctions( Color color, ColorFunction[] functions ) {
float[] hsl = HSLColor.fromRGB( color );
float alpha = color.getAlpha() / 255f;
for( ColorFunction function : functions )
function.apply( hsl );
return HSLColor.toRGB( hsl, alpha );
}
private static float clamp( float value ) {
return (value < 0)
? 0
: ((value > 100)
? 100
: value);
}
//---- interface ColorFunction --------------------------------------------
public interface ColorFunction {
void apply( float[] hsl );
}
//---- class Lighten ------------------------------------------------------
/**
* Increase the lightness of a color in the HSL color space by an absolute
* or relative amount.
*/
public static class Lighten
implements ColorFunction
{
private final float amount;
private final boolean relative;
private final boolean autoInverse;
public Lighten( float amount, boolean relative, boolean autoInverse ) {
this.amount = amount;
this.relative = relative;
this.autoInverse = autoInverse;
}
@Override
public void apply( float[] hsl ) {
float amount2 = autoInverse && shouldInverse( hsl ) ? -amount : amount;
hsl[2] = clamp( relative
? (hsl[2] * ((100 + amount2) / 100))
: (hsl[2] + amount2) );
}
protected boolean shouldInverse( float[] hsl ) {
return hsl[2] >= 50;
}
}
//---- class Darken -------------------------------------------------------
/**
* Decrease the lightness of a color in the HSL color space by an absolute
* or relative amount.
*/
public static class Darken
extends Lighten
{
public Darken( float amount, boolean relative, boolean autoInverse ) {
super( -amount, relative, autoInverse );
}
@Override
protected boolean shouldInverse( float[] hsl ) {
return hsl[2] < 50;
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
import java.awt.Color;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
/**
* A (red) color that acts as a placeholder in UI defaults.
* The actual color is derived from another color,
* which is modified by the given color functions.
*
* @author Karl Tauber
*/
public class DerivedColor
extends ColorUIResource
{
private final ColorFunction[] functions;
public DerivedColor( ColorFunction... functions ) {
super( Color.red );
this.functions = functions;
}
public Color derive( Color baseColor ) {
return ColorFunctions.applyFunctions( baseColor, functions );
}
}

View File

@@ -0,0 +1,432 @@
/*
* From http://tips4java.wordpress.com/2009/07/05/hsl-color/
*
* License note on http://tips4java.wordpress.com/about/
* "You are free to use and/or modify any or all code posted on the
* Java Tips Weblog without restriction. A credit in the code comments
* would be nice, but not in any way mandatory."
*/
package com.formdev.flatlaf.util;
import java.awt.Color;
/**
* The HSLColor class provides methods to manipulate HSL (Hue, Saturation
* Luminance) values to create a corresponding Color object using the RGB
* ColorSpace.
*
* The HUE is the color, the Saturation is the purity of the color (with
* respect to grey) and Luminance is the brightness of the color (with respect
* to black and white)
*
* The Hue is specified as an angel between 0 - 360 degrees where red is 0,
* green is 120 and blue is 240. In between you have the colors of the rainbow.
* Saturation is specified as a percentage between 0 - 100 where 100 is fully
* saturated and 0 approaches gray. Luminance is specified as a percentage
* between 0 - 100 where 0 is black and 100 is white.
*
* In particular the HSL color space makes it easier change the Tone or Shade
* of a color by adjusting the luminance value.
*/
public class HSLColor
{
private final Color rgb;
private final float[] hsl;
private final float alpha;
/**
* Create a HSLColor object using an RGB Color object.
*
* @param rgb the RGB Color object
*/
public HSLColor(Color rgb)
{
this.rgb = rgb;
hsl = fromRGB( rgb );
alpha = rgb.getAlpha() / 255.0f;
}
/**
* Create a HSLColor object using individual HSL values and a default
* alpha value of 1.0.
*
* @param h is the Hue value in degrees between 0 - 360
* @param s is the Saturation percentage between 0 - 100
* @param l is the Lumanance percentage between 0 - 100
*/
public HSLColor(float h, float s, float l)
{
this(h, s, l, 1.0f);
}
/**
* Create a HSLColor object using individual HSL values.
*
* @param h the Hue value in degrees between 0 - 360
* @param s the Saturation percentage between 0 - 100
* @param l the Lumanance percentage between 0 - 100
* @param alpha the alpha value between 0 - 1
*/
public HSLColor(float h, float s, float l, float alpha)
{
hsl = new float[] {h, s, l};
this.alpha = alpha;
rgb = toRGB(hsl, alpha);
}
/**
* Create a HSLColor object using an an array containing the
* individual HSL values and with a default alpha value of 1.
*
* @param hsl array containing HSL values
*/
public HSLColor(float[] hsl)
{
this(hsl, 1.0f);
}
/**
* Create a HSLColor object using an an array containing the
* individual HSL values.
*
* @param hsl array containing HSL values
* @param alpha the alpha value between 0 - 1
*/
public HSLColor(float[] hsl, float alpha)
{
this.hsl = hsl;
this.alpha = alpha;
rgb = toRGB(hsl, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different
* Hue value. The degrees specified is an absolute value.
*
* @param degrees - the Hue value between 0 - 360
* @return the RGB Color object
*/
public Color adjustHue(float degrees)
{
return toRGB(degrees, hsl[1], hsl[2], alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different
* Luminance value. The percent specified is an absolute value.
*
* @param percent - the Luminance value between 0 - 100
* @return the RGB Color object
*/
public Color adjustLuminance(float percent)
{
return toRGB(hsl[0], hsl[1], percent, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different
* Saturation value. The percent specified is an absolute value.
*
* @param percent - the Saturation value between 0 - 100
* @return the RGB Color object
*/
public Color adjustSaturation(float percent)
{
return toRGB(hsl[0], percent, hsl[2], alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different
* Shade. Changing the shade will return a darker color. The percent
* specified is a relative value.
*
* @param percent - the value between 0 - 100
* @return the RGB Color object
*/
public Color adjustShade(float percent)
{
float multiplier = (100.0f - percent) / 100.0f;
float l = Math.max(0.0f, hsl[2] * multiplier);
return toRGB(hsl[0], hsl[1], l, alpha);
}
/**
* Create a RGB Color object based on this HSLColor with a different
* Tone. Changing the tone will return a lighter color. The percent
* specified is a relative value.
*
* @param percent - the value between 0 - 100
* @return the RGB Color object
*/
public Color adjustTone(float percent)
{
float multiplier = (100.0f + percent) / 100.0f;
float l = Math.min(100.0f, hsl[2] * multiplier);
return toRGB(hsl[0], hsl[1], l, alpha);
}
/**
* Get the Alpha value.
*
* @return the Alpha value.
*/
public float getAlpha()
{
return alpha;
}
/**
* Create a RGB Color object that is the complementary color of this
* HSLColor. This is a convenience method. The complementary color is
* determined by adding 180 degrees to the Hue value.
* @return the RGB Color object
*/
public Color getComplementary()
{
float hue = (hsl[0] + 180.0f) % 360.0f;
return toRGB(hue, hsl[1], hsl[2]);
}
/**
* Get the Hue value.
*
* @return the Hue value.
*/
public float getHue()
{
return hsl[0];
}
/**
* Get the HSL values.
*
* @return the HSL values.
*/
public float[] getHSL()
{
return hsl;
}
/**
* Get the Luminance value.
*
* @return the Luminance value.
*/
public float getLuminance()
{
return hsl[2];
}
/**
* Get the RGB Color object represented by this HDLColor.
*
* @return the RGB Color object.
*/
public Color getRGB()
{
return rgb;
}
/**
* Get the Saturation value.
*
* @return the Saturation value.
*/
public float getSaturation()
{
return hsl[1];
}
@Override
public String toString()
{
String toString =
"HSLColor[h=" + hsl[0] +
",s=" + hsl[1] +
",l=" + hsl[2] +
",alpha=" + alpha + "]";
return toString;
}
/**
* Convert a RGB Color to it corresponding HSL values.
*
* @return an array containing the 3 HSL values.
*/
public static float[] fromRGB(Color color)
{
// Get RGB values in the range 0 - 1
float[] rgb = color.getRGBColorComponents( null );
float r = rgb[0];
float g = rgb[1];
float b = rgb[2];
// Minimum and Maximum RGB values are used in the HSL calculations
float min = Math.min(r, Math.min(g, b));
float max = Math.max(r, Math.max(g, b));
// Calculate the Hue
float h = 0;
if (max == min)
h = 0;
else if (max == r)
h = ((60 * (g - b) / (max - min)) + 360) % 360;
else if (max == g)
h = (60 * (b - r) / (max - min)) + 120;
else if (max == b)
h = (60 * (r - g) / (max - min)) + 240;
// Calculate the Luminance
float l = (max + min) / 2;
// System.out.println(max + " : " + min + " : " + l);
// Calculate the Saturation
float s = 0;
if (max == min)
s = 0;
else if (l <= .5f)
s = (max - min) / (max + min);
else
s = (max - min) / (2 - max - min);
// System.out.println(new HSLColor( new float[] {h, s * 100, l * 100} ));
return new float[] {h, s * 100, l * 100};
}
/**
* Convert HSL values to a RGB Color with a default alpha value of 1.
* H (Hue) is specified as degrees in the range 0 - 360.
* S (Saturation) is specified as a percentage in the range 1 - 100.
* L (Lumanance) is specified as a percentage in the range 1 - 100.
*
* @param hsl an array containing the 3 HSL values
*
* @return the RGB Color object
*/
public static Color toRGB(float[] hsl)
{
return toRGB(hsl, 1.0f);
}
/**
* Convert HSL values to a RGB Color.
* H (Hue) is specified as degrees in the range 0 - 360.
* S (Saturation) is specified as a percentage in the range 1 - 100.
* L (Lumanance) is specified as a percentage in the range 1 - 100.
*
* @param hsl an array containing the 3 HSL values
* @param alpha the alpha value between 0 - 1
*
* @return the RGB Color object
*/
public static Color toRGB(float[] hsl, float alpha)
{
return toRGB(hsl[0], hsl[1], hsl[2], alpha);
}
/**
* Convert HSL values to a RGB Color with a default alpha value of 1.
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
*
* @return the RGB Color object
*/
public static Color toRGB(float h, float s, float l)
{
return toRGB(h, s, l, 1.0f);
}
/**
* Convert HSL values to a RGB Color.
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
* @param alpha the alpha value between 0 - 1
*
* @return the RGB Color object
*/
public static Color toRGB(float h, float s, float l, float alpha)
{
if (s <0.0f || s > 100.0f)
{
String message = "Color parameter outside of expected range - Saturation";
throw new IllegalArgumentException( message );
}
if (l <0.0f || l > 100.0f)
{
String message = "Color parameter outside of expected range - Luminance";
throw new IllegalArgumentException( message );
}
if (alpha <0.0f || alpha > 1.0f)
{
String message = "Color parameter outside of expected range - Alpha";
throw new IllegalArgumentException( message );
}
// Formula needs all values between 0 - 1.
h = h % 360.0f;
h /= 360f;
s /= 100f;
l /= 100f;
float q = 0;
if (l < 0.5)
q = l * (1 + s);
else
q = (l + s) - (s * l);
float p = 2 * l - q;
float r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)));
float g = Math.max(0, HueToRGB(p, q, h));
float b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)));
r = Math.min(r, 1.0f);
g = Math.min(g, 1.0f);
b = Math.min(b, 1.0f);
return new Color(r, g, b, alpha);
}
private static float HueToRGB(float p, float q, float h)
{
if (h < 0) h += 1;
if (h > 1 ) h -= 1;
if (6 * h < 1)
{
return p + ((q - p) * 6 * h);
}
if (2 * h < 1 )
{
return q;
}
if (3 * h < 2)
{
return p + ( (q - p) * 6 * ((2.0f / 3.0f) - h) );
}
return p;
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.util;
import java.util.ArrayList;
import java.util.List;
/**
* Utility methods for strings.
*
* @author Karl Tauber
*/
public class StringUtils
{
public static String removeLeading( String string, String leading ) {
return string.startsWith( leading )
? string.substring( leading.length() )
: string;
}
public static String removeTrailing( String string, String trailing ) {
return string.endsWith( trailing )
? string.substring( 0, string.length() - trailing.length() )
: string;
}
public static List<String> split( String str, char delim ) {
ArrayList<String> strs = new ArrayList<>();
int delimIndex = str.indexOf( delim );
int index = 0;
while( delimIndex >= 0 ) {
strs.add( str.substring( index, delimIndex ) );
index = delimIndex + 1;
delimIndex = str.indexOf( delim, index );
}
strs.add( str.substring( index ) );
return strs;
}
}

View File

@@ -24,4 +24,6 @@ module com.formdev.flatlaf {
exports com.formdev.flatlaf.icons; exports com.formdev.flatlaf.icons;
exports com.formdev.flatlaf.ui; exports com.formdev.flatlaf.ui;
exports com.formdev.flatlaf.util; exports com.formdev.flatlaf.util;
uses com.formdev.flatlaf.FlatDefaultsAddon;
} }

View File

@@ -20,16 +20,20 @@
#---- variables ---- #---- variables ----
@background=3c3f41 @background=#3c3f41
@foreground=bbbbbb @foreground=#bbbbbb
@selectionBackground=4B6EAF @selectionBackground=#4B6EAF
@selectionForeground=@foreground @selectionForeground=@foreground
@selectionInactiveBackground=0D293E @selectionInactiveBackground=#0D293E
@selectionInactiveForeground=@foreground @selectionInactiveForeground=@foreground
@disabledText=777777 @disabledText=#777777
@textComponentBackground=45494A @textComponentBackground=#45494A
@cellFocusColor=000000 @cellFocusColor=#000000
@icon=adadad @icon=#adadad
# Button
@buttonHoverBackground=lighten(3%,autoInverse)
@buttonPressedBackground=lighten(6%,autoInverse)
#---- globals ---- #---- globals ----
@@ -46,7 +50,7 @@
*.disabledBackground=@background *.disabledBackground=@background
*.disabledForeground=@disabledText *.disabledForeground=@disabledText
*.disabledText=@disabledText *.disabledText=@disabledText
*.acceleratorForeground=bbbbbb *.acceleratorForeground=#bbbbbb
*.acceleratorSelectionForeground=@selectionForeground *.acceleratorSelectionForeground=@selectionForeground
@@ -62,62 +66,63 @@ window=@background
#---- Button ---- #---- Button ----
Button.background=4c5052 Button.background=#4c5052
Button.hoverBackground=525658 Button.hoverBackground=@buttonHoverBackground
Button.pressedBackground=5c6164 Button.pressedBackground=@buttonPressedBackground
Button.borderColor=5e6060 Button.borderColor=#5e6060
Button.disabledBorderColor=5e6060 Button.disabledBorderColor=#5e6060
Button.focusedBorderColor=466d94 Button.focusedBorderColor=#466d94
Button.hoverBorderColor=@@Button.focusedBorderColor Button.hoverBorderColor=@@Button.focusedBorderColor
Button.default.background=365880 Button.default.background=#365880
Button.default.foreground=bbbbbb Button.default.foreground=#bbbbbb
Button.default.hoverBackground=3d6185 Button.default.hoverBackground=@buttonHoverBackground
Button.default.pressedBackground=43688c Button.default.pressedBackground=@buttonPressedBackground
Button.default.borderColor=4c708c Button.default.borderColor=#4c708c
Button.default.hoverBorderColor=537699 Button.default.hoverBorderColor=#537699
Button.default.focusedBorderColor=537699 Button.default.focusedBorderColor=#537699
Button.default.focusColor=43688c Button.default.focusColor=#43688c
Button.default.boldText=true Button.default.boldText=true
Button.toolbar.hoverBackground=4c5052 Button.toolbar.hoverBackground=#4c5052
Button.toolbar.pressedBackground=555a5d Button.toolbar.pressedBackground=#555a5d
#---- CheckBox ---- #---- CheckBox ----
CheckBox.icon.borderColor=6B6B6B CheckBox.icon.borderColor=#6B6B6B
CheckBox.icon.disabledBorderColor=545556 CheckBox.icon.disabledBorderColor=#545556
CheckBox.icon.selectedBorderColor=6B6B6B CheckBox.icon.selectedBorderColor=#6B6B6B
CheckBox.icon.focusedBorderColor=466D94 CheckBox.icon.focusedBorderColor=#466D94
CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor
CheckBox.icon.selectedFocusedBorderColor=466D94 CheckBox.icon.selectedFocusedBorderColor=#466D94
CheckBox.icon.background=43494A CheckBox.icon.background=#43494A
CheckBox.icon.disabledBackground=@background CheckBox.icon.disabledBackground=@background
CheckBox.icon.hoverBackground=4c5052 CheckBox.icon.hoverBackground=@buttonHoverBackground
CheckBox.icon.pressedBackground=@@Button.pressedBackground CheckBox.icon.pressedBackground=@buttonPressedBackground
CheckBox.icon.selectedBackground=43494A CheckBox.icon.selectedBackground=#43494A
CheckBox.icon.checkmarkColor=A7A7A7 CheckBox.icon.checkmarkColor=#A7A7A7
CheckBox.icon.disabledCheckmarkColor=606060 CheckBox.icon.disabledCheckmarkColor=#606060
#---- ComboBox ---- #---- ComboBox ----
ComboBox.background=@textComponentBackground ComboBox.background=@textComponentBackground
ComboBox.buttonBackground=@textComponentBackground ComboBox.buttonBackground=@textComponentBackground
ComboBox.buttonEditableBackground=404445 ComboBox.buttonEditableBackground=#404445
ComboBox.buttonArrowColor=9A9DA1 ComboBox.buttonArrowColor=#9A9DA1
ComboBox.buttonDisabledArrowColor=585858 ComboBox.buttonDisabledArrowColor=#585858
ComboBox.buttonHoverArrowColor=bbbbbb ComboBox.buttonHoverArrowColor=#bbbbbb
#---- Component ---- #---- Component ----
Component.borderColor=646464 Component.borderColor=#646464
Component.disabledBorderColor=646464 Component.disabledBorderColor=#646464
Component.focusedBorderColor=466d94 Component.focusedBorderColor=#466d94
Component.focusColor=3d6185 Component.focusColor=#3d6185
Component.linkColor=#589df6
#---- List ---- #---- List ----
@@ -127,110 +132,101 @@ List.background=@textComponentBackground
#---- Menu ---- #---- Menu ----
Menu.icon.arrowColor=A7A7A7 Menu.icon.arrowColor=#A7A7A7
Menu.icon.disabledArrowColor=606060 Menu.icon.disabledArrowColor=#606060
#---- MenuBar ---- #---- MenuBar ----
MenuBar.borderColor=515151 MenuBar.borderColor=#515151
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----
MenuItemCheckBox.icon.checkmarkColor=A7A7A7 MenuItemCheckBox.icon.checkmarkColor=#A7A7A7
MenuItemCheckBox.icon.disabledCheckmarkColor=606060 MenuItemCheckBox.icon.disabledCheckmarkColor=#606060
#---- OptionPane ----
OptionPane.icon.errorColor=C75450
OptionPane.icon.informationColor=3592C4
OptionPane.icon.questionColor=3592C4
OptionPane.icon.warningColor=F0A732
OptionPane.icon.foreground=null
#---- PopupMenu ---- #---- PopupMenu ----
PopupMenu.borderColor=515151 PopupMenu.borderColor=#515151
#---- ProgressBar ---- #---- ProgressBar ----
ProgressBar.background=555555 ProgressBar.background=#555555
ProgressBar.foreground=a0a0a0 ProgressBar.foreground=#a0a0a0
ProgressBar.selectionForeground=@background ProgressBar.selectionForeground=@background
ProgressBar.selectionBackground=@foreground ProgressBar.selectionBackground=@foreground
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.track=3F4244 ScrollBar.track=#3F4244
ScrollBar.thumb=5B5E5F ScrollBar.thumb=#5B5E5F
ScrollBar.hoverTrackColor=434647 ScrollBar.hoverTrackColor=#434647
ScrollBar.hoverThumbColor=666868 ScrollBar.hoverThumbColor=#666868
#---- Separator ---- #---- Separator ----
Separator.foreground=515151 Separator.foreground=#515151
#---- Slider ---- #---- Slider ----
Slider.trackColor=646464 Slider.trackColor=#646464
Slider.thumbColor=A6A6A6 Slider.thumbColor=#A6A6A6
Slider.tickColor=888888 Slider.tickColor=#888888
Slider.focusedColor=@@Component.focusColor Slider.hoverColor=darken(15%,autoInverse)
Slider.hoverColor=888888 Slider.disabledForeground=#4c5052
Slider.disabledForeground=4c5052
#---- SplitPane ---- #---- SplitPane ----
SplitPaneDivider.draggingColor=646464 SplitPaneDivider.draggingColor=#646464
SplitPaneDivider.oneTouchHoverArrowColor=7A7D81 SplitPaneDivider.oneTouchHoverArrowColor=#7A7D81
#---- TabbedPane ---- #---- TabbedPane ----
TabbedPane.disabledForeground=777777 TabbedPane.disabledForeground=#777777
TabbedPane.underlineColor=4A88C7 TabbedPane.underlineColor=#4A88C7
TabbedPane.disabledUnderlineColor=7a7a7a TabbedPane.disabledUnderlineColor=#7a7a7a
TabbedPane.hoverColor=2e3133 TabbedPane.hoverColor=#2e3133
TabbedPane.focusColor=3d4b5c TabbedPane.focusColor=#3d4b5c
TabbedPane.contentAreaColor=323232 TabbedPane.contentAreaColor=#323232
#---- Table ---- #---- Table ----
Table.background=@textComponentBackground Table.background=@textComponentBackground
Table.gridColor=4F5152 Table.gridColor=#4F5152
#---- TableHeader ---- #---- TableHeader ----
TableHeader.background=45494A TableHeader.background=#45494A
TableHeader.separatorColor=585858 TableHeader.separatorColor=#585858
TableHeader.bottomSeparatorColor=585858 TableHeader.bottomSeparatorColor=#585858
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.selectedBackground=64696C ToggleButton.selectedBackground=#64696C
ToggleButton.selectedForeground=@foreground ToggleButton.selectedForeground=@foreground
ToggleButton.disabledSelectedBackground=525658 ToggleButton.disabledSelectedBackground=#525658
ToggleButton.toolbar.selectedBackground=5c6164 ToggleButton.toolbar.selectedBackground=#5c6164
#---- ToolTip ---- #---- ToolTip ----
ToolTip.background=4b4d4d ToolTip.border=4,6,4,6
ToolTip.background=#1e2123
#---- Tree ---- #---- Tree ----
Tree.background=@textComponentBackground Tree.background=@textComponentBackground
Tree.hash=505355 Tree.hash=#505355

View File

@@ -22,27 +22,27 @@
Button.focusedBackground=null Button.focusedBackground=null
Button.default.background=4A86C7 Button.default.background=#4A86C7
Button.default.foreground=f0f0f0 Button.default.foreground=#f0f0f0
Button.default.focusedBackground=null Button.default.focusedBackground=null
Button.default.hoverBackground=5B91CC Button.default.hoverBackground=#5B91CC
Button.default.pressedBackground=6E9ED2 Button.default.pressedBackground=#6E9ED2
Button.default.borderColor=3167ad Button.default.borderColor=#3167ad
Button.default.hoverBorderColor=a8cef6 Button.default.hoverBorderColor=#a8cef6
Button.default.focusedBorderColor=a8cef6 Button.default.focusedBorderColor=#a8cef6
Button.default.focusColor=97c3f3 Button.default.focusColor=#97c3f3
Button.default.boldText=true Button.default.boldText=true
#---- CheckBox ---- #---- CheckBox ----
CheckBox.icon.selectedBorderColor=4982CC CheckBox.icon.selectedBorderColor=#4982CC
CheckBox.icon.selectedFocusedBorderColor=ACCFF7 CheckBox.icon.selectedFocusedBorderColor=#ACCFF7
CheckBox.icon.selectedBackground=4D89C9 CheckBox.icon.selectedBackground=#4D89C9
CheckBox.icon.checkmarkColor=FFFFFF CheckBox.icon.checkmarkColor=#FFFFFF
CheckBox.icon.selectedHoverBackground=5E94CE CheckBox.icon.selectedHoverBackground=#5E94CE
CheckBox.icon.selectedPressedBackground=72A1D4 CheckBox.icon.selectedPressedBackground=#72A1D4
#---- Component ---- #---- Component ----

View File

@@ -22,6 +22,7 @@ CheckBoxMenuItemUI=com.formdev.flatlaf.ui.FlatCheckBoxMenuItemUI
ColorChooserUI=com.formdev.flatlaf.ui.FlatColorChooserUI ColorChooserUI=com.formdev.flatlaf.ui.FlatColorChooserUI
ComboBoxUI=com.formdev.flatlaf.ui.FlatComboBoxUI ComboBoxUI=com.formdev.flatlaf.ui.FlatComboBoxUI
EditorPaneUI=com.formdev.flatlaf.ui.FlatEditorPaneUI EditorPaneUI=com.formdev.flatlaf.ui.FlatEditorPaneUI
FileChooserUI=com.formdev.flatlaf.ui.FlatFileChooserUI
FormattedTextFieldUI=com.formdev.flatlaf.ui.FlatFormattedTextFieldUI FormattedTextFieldUI=com.formdev.flatlaf.ui.FlatFormattedTextFieldUI
LabelUI=com.formdev.flatlaf.ui.FlatLabelUI LabelUI=com.formdev.flatlaf.ui.FlatLabelUI
ListUI=com.formdev.flatlaf.ui.FlatListUI ListUI=com.formdev.flatlaf.ui.FlatListUI
@@ -77,6 +78,7 @@ Button.default.borderWidth=1
CheckBox.border=com.formdev.flatlaf.ui.FlatMarginBorder CheckBox.border=com.formdev.flatlaf.ui.FlatMarginBorder
CheckBox.icon=com.formdev.flatlaf.icons.FlatCheckBoxIcon CheckBox.icon=com.formdev.flatlaf.icons.FlatCheckBoxIcon
CheckBox.arc=2
CheckBox.margin=2,2,2,2 CheckBox.margin=2,2,2,2
CheckBox.iconTextGap=4 CheckBox.iconTextGap=4
CheckBox.rollover=true CheckBox.rollover=true
@@ -127,12 +129,6 @@ FileChooser.homeFolderIcon=com.formdev.flatlaf.icons.FlatFileChooserHomeFolderIc
FileChooser.detailsViewIcon=com.formdev.flatlaf.icons.FlatFileChooserDetailsViewIcon FileChooser.detailsViewIcon=com.formdev.flatlaf.icons.FlatFileChooserDetailsViewIcon
FileChooser.listViewIcon=com.formdev.flatlaf.icons.FlatFileChooserListViewIcon FileChooser.listViewIcon=com.formdev.flatlaf.icons.FlatFileChooserListViewIcon
FileChooser.icon.newFolderColor=@icon
FileChooser.icon.upFolderColor=@icon
FileChooser.icon.homeFolderColor=@icon
FileChooser.icon.detailsViewColor=@icon
FileChooser.icon.listViewColor=@icon
#---- FileView ---- #---- FileView ----
@@ -142,12 +138,6 @@ FileView.computerIcon=com.formdev.flatlaf.icons.FlatFileViewComputerIcon
FileView.hardDriveIcon=com.formdev.flatlaf.icons.FlatFileViewHardDriveIcon FileView.hardDriveIcon=com.formdev.flatlaf.icons.FlatFileViewHardDriveIcon
FileView.floppyDriveIcon=com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon FileView.floppyDriveIcon=com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon
FileView.icon.directoryColor=@icon
FileView.icon.fileColor=@icon
FileView.icon.computerColor=@icon
FileView.icon.hardDriveColor=@icon
FileView.icon.floppyDriveColor=@icon
#---- FormattedTextField ---- #---- FormattedTextField ----
@@ -212,10 +202,11 @@ OptionPane.maxCharactersPerLine=80
OptionPane.iconMessageGap=16 OptionPane.iconMessageGap=16
OptionPane.messagePadding=3 OptionPane.messagePadding=3
OptionPane.buttonPadding=8 OptionPane.buttonPadding=8
OptionPane.buttonMinimumWidth=72 OptionPane.buttonMinimumWidth={scaledNumber}72
OptionPane.sameSizeButtons=true OptionPane.sameSizeButtons=true
OptionPane.setButtonMargin=false OptionPane.setButtonMargin=false
OptionPane.buttonOrientation=4 OptionPane.buttonOrientation=4
[mac]OptionPane.isYesLast=true
OptionPane.errorIcon=com.formdev.flatlaf.icons.FlatOptionPaneErrorIcon OptionPane.errorIcon=com.formdev.flatlaf.icons.FlatOptionPaneErrorIcon
OptionPane.informationIcon=com.formdev.flatlaf.icons.FlatOptionPaneInformationIcon OptionPane.informationIcon=com.formdev.flatlaf.icons.FlatOptionPaneInformationIcon
@@ -277,6 +268,7 @@ ScrollBar.width=10
ScrollPane.border=com.formdev.flatlaf.ui.FlatBorder ScrollPane.border=com.formdev.flatlaf.ui.FlatBorder
ScrollPane.background=@@ScrollBar.track ScrollPane.background=@@ScrollBar.track
ScrollPane.fillUpperCorner=true
#---- Separator ---- #---- Separator ----
@@ -307,12 +299,12 @@ Spinner.editorBorderPainted=false
#---- SplitPane ---- #---- SplitPane ----
SplitPane.dividerSize=5 SplitPane.dividerSize={integer}5
SplitPane.continuousLayout=true SplitPane.continuousLayout=true
SplitPane.border=null SplitPane.border=null
SplitPane.centerOneTouchButtons=true SplitPane.centerOneTouchButtons=true
SplitPane.oneTouchButtonSize=6 SplitPane.oneTouchButtonSize={scaledNumber}6
SplitPane.oneTouchButtonOffset=2 SplitPane.oneTouchButtonOffset={scaledNumber}2
SplitPaneDivider.border=null SplitPaneDivider.border=null
SplitPaneDivider.oneTouchArrowColor=@@ComboBox.buttonArrowColor SplitPaneDivider.oneTouchArrowColor=@@ComboBox.buttonArrowColor
@@ -348,7 +340,7 @@ Table.selectionInactiveForeground=@selectionInactiveForeground
#---- TableHeader ---- #---- TableHeader ----
TableHeader.height=25 TableHeader.height=25
TableHeader.cellBorder=2,2,2,2 TableHeader.cellBorder=2,3,2,3
#---- TextArea ---- #---- TextArea ----
@@ -409,7 +401,10 @@ ToolBar.separatorColor=@@Separator.foreground
#---- ToolTip ---- #---- ToolTip ----
ToolTip.border=2,6,2,6,@@Component.borderColor ToolTip.border=4,6,4,6,@@Component.borderColor
ToolTip.borderInactive=null
ToolTip.backgroundInactive=@@ToolTip.background
ToolTip.foregroundInactive=@disabledText
#---- Tree ---- #---- Tree ----
@@ -417,7 +412,7 @@ ToolTip.border=2,6,2,6,@@Component.borderColor
Tree.border=1,1,1,1 Tree.border=1,1,1,1
Tree.selectionInactiveBackground=@selectionInactiveBackground Tree.selectionInactiveBackground=@selectionInactiveBackground
Tree.selectionInactiveForeground=@selectionInactiveForeground Tree.selectionInactiveForeground=@selectionInactiveForeground
Tree.textBackground=@@Tree.background Tree.textBackground=null
Tree.selectionBorderColor=@cellFocusColor Tree.selectionBorderColor=@cellFocusColor
Tree.rendererMargins=1,2,1,2 Tree.rendererMargins=1,2,1,2
Tree.paintLines=false Tree.paintLines=false

View File

@@ -20,39 +20,43 @@
#---- variables ---- #---- variables ----
@background=f2f2f2 @background=#f2f2f2
@foreground=000000 @foreground=#000000
@selectionBackground=4A6EB7 @selectionBackground=#4A6EB7
@selectionForeground=ffffff @selectionForeground=#ffffff
@selectionInactiveBackground=d4d4d4 @selectionInactiveBackground=#d4d4d4
@selectionInactiveForeground=@foreground @selectionInactiveForeground=@foreground
@disabledText=999999 @disabledText=#999999
@textComponentBackground=ffffff @textComponentBackground=#ffffff
@cellFocusColor=000000 @cellFocusColor=#000000
@icon=afafaf @icon=#afafaf
# Button
@buttonHoverBackground=darken(3%,autoInverse)
@buttonPressedBackground=darken(10%,autoInverse)
#---- globals ---- #---- globals ----
*.background=@background *.background=@background
*.foreground=@foreground *.foreground=@foreground
*.textBackground=cccccc *.textBackground=#cccccc
*.textForeground=@foreground *.textForeground=@foreground
*.caretForeground=@foreground *.caretForeground=@foreground
*.inactiveBackground=@background *.inactiveBackground=@background
*.inactiveForeground=777777 *.inactiveForeground=#777777
*.selectionBackground=@selectionBackground *.selectionBackground=@selectionBackground
*.selectionForeground=@selectionForeground *.selectionForeground=@selectionForeground
*.disabledBackground=@background *.disabledBackground=@background
*.disabledForeground=@disabledText *.disabledForeground=@disabledText
*.disabledText=@disabledText *.disabledText=@disabledText
*.acceleratorForeground=505050 *.acceleratorForeground=#505050
*.acceleratorSelectionForeground=@selectionForeground *.acceleratorSelectionForeground=@selectionForeground
#---- system ---- #---- system ----
control=e0e0e0 control=#e0e0e0
controlText=@foreground controlText=@foreground
infoText=@foreground infoText=@foreground
text=@foreground text=@foreground
@@ -62,69 +66,70 @@ window=@background
#---- Button ---- #---- Button ----
Button.background=ffffff Button.background=#ffffff
Button.focusedBackground=e3f1fa Button.focusedBackground=#e3f1fa
Button.hoverBackground=f8f8f8 Button.hoverBackground=@buttonHoverBackground
Button.pressedBackground=dfdfdf Button.pressedBackground=@buttonPressedBackground
Button.borderColor=bfbfbf Button.borderColor=#bfbfbf
Button.disabledBorderColor=cfcfcf Button.disabledBorderColor=#cfcfcf
Button.focusedBorderColor=87afda Button.focusedBorderColor=#87afda
Button.hoverBorderColor=@@Button.focusedBorderColor Button.hoverBorderColor=@@Button.focusedBorderColor
Button.default.background=@@Button.background Button.default.background=@@Button.background
Button.default.foreground=@foreground Button.default.foreground=@foreground
Button.default.focusedBackground=@@Button.focusedBackground Button.default.focusedBackground=@@Button.focusedBackground
Button.default.hoverBackground=@@Button.hoverBackground Button.default.hoverBackground=@buttonHoverBackground
Button.default.pressedBackground=@@Button.pressedBackground Button.default.pressedBackground=@buttonPressedBackground
Button.default.borderColor=4D89C9 Button.default.borderColor=#4D89C9
Button.default.hoverBorderColor=@@Button.hoverBorderColor Button.default.hoverBorderColor=@@Button.hoverBorderColor
Button.default.focusedBorderColor=@@Button.focusedBorderColor Button.default.focusedBorderColor=@@Button.focusedBorderColor
Button.default.focusColor=@@Component.focusColor Button.default.focusColor=@@Component.focusColor
Button.default.borderWidth=2 Button.default.borderWidth=2
Button.toolbar.hoverBackground=dfdfdf Button.toolbar.hoverBackground=#dfdfdf
Button.toolbar.pressedBackground=d8d8d8 Button.toolbar.pressedBackground=#d8d8d8
#---- CheckBox ---- #---- CheckBox ----
CheckBox.icon.borderColor=878787 CheckBox.icon.borderColor=#878787
CheckBox.icon.disabledBorderColor=BDBDBD CheckBox.icon.disabledBorderColor=#BDBDBD
CheckBox.icon.selectedBorderColor=878787 CheckBox.icon.selectedBorderColor=#878787
CheckBox.icon.focusedBorderColor=7B9FC7 CheckBox.icon.focusedBorderColor=#7B9FC7
CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor CheckBox.icon.hoverBorderColor=@@CheckBox.icon.focusedBorderColor
CheckBox.icon.background=FFFFFF CheckBox.icon.background=#FFFFFF
CheckBox.icon.disabledBackground=@background CheckBox.icon.disabledBackground=@background
CheckBox.icon.focusedBackground=@@Button.focusedBackground CheckBox.icon.focusedBackground=@@Button.focusedBackground
CheckBox.icon.hoverBackground=@@Button.hoverBackground CheckBox.icon.hoverBackground=@buttonHoverBackground
CheckBox.icon.pressedBackground=@@Button.pressedBackground CheckBox.icon.pressedBackground=@buttonPressedBackground
CheckBox.icon.selectedBackground=FFFFFF CheckBox.icon.selectedBackground=#FFFFFF
CheckBox.icon.checkmarkColor=4D89C9 CheckBox.icon.checkmarkColor=#4D89C9
CheckBox.icon.disabledCheckmarkColor=ABABAB CheckBox.icon.disabledCheckmarkColor=#ABABAB
#---- ComboBox ---- #---- ComboBox ----
ComboBox.background=@textComponentBackground ComboBox.background=@textComponentBackground
ComboBox.buttonBackground=@textComponentBackground ComboBox.buttonBackground=@textComponentBackground
ComboBox.buttonEditableBackground=fafafa ComboBox.buttonEditableBackground=#fafafa
ComboBox.buttonArrowColor=666666 ComboBox.buttonArrowColor=#666666
ComboBox.buttonDisabledArrowColor=ABABAB ComboBox.buttonDisabledArrowColor=#ABABAB
ComboBox.buttonHoverArrowColor=999999 ComboBox.buttonHoverArrowColor=#999999
#---- Component ---- #---- Component ----
Component.borderColor=c4c4c4 Component.borderColor=#c4c4c4
Component.disabledBorderColor=cfcfcf Component.disabledBorderColor=#cfcfcf
Component.focusedBorderColor=87afda Component.focusedBorderColor=#87afda
Component.focusColor=97c3f3 Component.focusColor=#97c3f3
Component.linkColor=#4a78c2
#---- HelpButton ---- #---- HelpButton ----
HelpButton.questionMarkColor=4D89C9 HelpButton.questionMarkColor=#4D89C9
#---- List ---- #---- List ----
@@ -134,110 +139,100 @@ List.background=@textComponentBackground
#---- Menu ---- #---- Menu ----
Menu.icon.arrowColor=666666 Menu.icon.arrowColor=#666666
Menu.icon.disabledArrowColor=ABABAB Menu.icon.disabledArrowColor=#ABABAB
#---- MenuBar ---- #---- MenuBar ----
MenuBar.borderColor=cdcdcd MenuBar.borderColor=#cdcdcd
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----
MenuItemCheckBox.icon.checkmarkColor=4D89C9 MenuItemCheckBox.icon.checkmarkColor=#4D89C9
MenuItemCheckBox.icon.disabledCheckmarkColor=ABABAB MenuItemCheckBox.icon.disabledCheckmarkColor=#ABABAB
#---- OptionPane ----
OptionPane.icon.errorColor=DB5860
OptionPane.icon.informationColor=389FD6
OptionPane.icon.questionColor=389FD6
OptionPane.icon.warningColor=EDA200
OptionPane.icon.foreground=null
#---- PopupMenu ---- #---- PopupMenu ----
PopupMenu.borderColor=cdcdcd PopupMenu.borderColor=#cdcdcd
#---- ProgressBar ---- #---- ProgressBar ----
ProgressBar.background=c4c4c4 ProgressBar.background=#c4c4c4
ProgressBar.foreground=808080 ProgressBar.foreground=#808080
ProgressBar.selectionForeground=@textComponentBackground ProgressBar.selectionForeground=@textComponentBackground
ProgressBar.selectionBackground=@foreground ProgressBar.selectionBackground=@foreground
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.track=F5F5F5 ScrollBar.track=#F5F5F5
ScrollBar.thumb=DBDBDB ScrollBar.thumb=#DBDBDB
ScrollBar.hoverTrackColor=e6e6e6 ScrollBar.hoverTrackColor=#e6e6e6
ScrollBar.hoverThumbColor=c6c6c6 ScrollBar.hoverThumbColor=#c6c6c6
#---- Separator ---- #---- Separator ----
Separator.foreground=cdcdcd Separator.foreground=#cdcdcd
#---- Slider ---- #---- Slider ----
Slider.trackColor=c4c4c4 Slider.trackColor=#c4c4c4
Slider.thumbColor=6e6e6e Slider.thumbColor=#6e6e6e
Slider.tickColor=888888 Slider.tickColor=#888888
Slider.focusedColor=@@Component.focusColor Slider.hoverColor=lighten(15%,autoInverse)
Slider.hoverColor=999999 Slider.disabledForeground=#c0c0c0
Slider.disabledForeground=c0c0c0
#---- SplitPane ---- #---- SplitPane ----
SplitPaneDivider.draggingColor=c4c4c4 SplitPaneDivider.draggingColor=#c4c4c4
SplitPaneDivider.oneTouchHoverArrowColor=333333 SplitPaneDivider.oneTouchHoverArrowColor=#333333
#---- TabbedPane ---- #---- TabbedPane ----
TabbedPane.disabledForeground=999999 TabbedPane.disabledForeground=#999999
TabbedPane.underlineColor=4083C9 TabbedPane.underlineColor=#4083C9
TabbedPane.disabledUnderlineColor=ababab TabbedPane.disabledUnderlineColor=#ababab
TabbedPane.hoverColor=d9d9d9 TabbedPane.hoverColor=#d9d9d9
TabbedPane.focusColor=dae4ed TabbedPane.focusColor=#dae4ed
TabbedPane.contentAreaColor=bfbfbf TabbedPane.contentAreaColor=#bfbfbf
#---- Table ---- #---- Table ----
Table.background=@textComponentBackground Table.background=@textComponentBackground
Table.gridColor=F7F7F7 Table.gridColor=#F7F7F7
#---- TableHeader ---- #---- TableHeader ----
TableHeader.background=ffffff TableHeader.background=#ffffff
TableHeader.separatorColor=e5e5e5 TableHeader.separatorColor=#e5e5e5
TableHeader.bottomSeparatorColor=e5e5e5 TableHeader.bottomSeparatorColor=#e5e5e5
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.selectedBackground=cfcfcf ToggleButton.selectedBackground=#cfcfcf
ToggleButton.selectedForeground=@foreground ToggleButton.selectedForeground=@foreground
ToggleButton.disabledSelectedBackground=dfdfdf ToggleButton.disabledSelectedBackground=#dfdfdf
ToggleButton.toolbar.selectedBackground=cfcfcf ToggleButton.toolbar.selectedBackground=#cfcfcf
#---- ToolTip ---- #---- ToolTip ----
ToolTip.background=f7f7f7 ToolTip.background=#fafafa
#---- Tree ---- #---- Tree ----
Tree.background=@textComponentBackground Tree.background=@textComponentBackground
Tree.hash=E6E6E6 Tree.hash=#E6E6E6

View File

@@ -0,0 +1,23 @@
#
# Copyright 2019 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
#
# http://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.
#
#---- Button ----
Button.hoverBorderColor=null
Button.default.hoverBorderColor=null
Button.default.hoverBackground=@buttonHoverBackground
Button.default.pressedBackground=@buttonPressedBackground

View File

@@ -1,264 +0,0 @@
#
# Copyright 2019 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
#
# http://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.
#
#---- variables ----
@background=ccffcc
@selectionBackground=00aa00
@selectionInactiveBackground=888888
@selectionInactiveForeground=ffffff
@textComponentBackground=ffffff
@cellFocusColor=ff0000
@icon=afafaf
#---- globals ----
*.background=@background
*.foreground=ff0000
*.textBackground=ccffcc
*.textForeground=ff0000
*.caretForeground=0000ff
*.inactiveBackground=f0f0f0
*.inactiveForeground=000088
*.selectionBackground=@selectionBackground
*.selectionForeground=ffff00
*.disabledBackground=e0e0e0
*.disabledForeground=000088
*.disabledText=000088
*.acceleratorForeground=ff8888
*.acceleratorSelectionForeground=ffffff
#---- Button ----
Button.background=ffffff
Button.focusedBackground=00ffff
Button.hoverBackground=ffff00
Button.pressedBackground=FFC800
Button.borderColor=0000ff
Button.disabledBorderColor=000088
Button.focusedBorderColor=466d94
Button.hoverBorderColor=ff0000
Button.default.background=dddddd
Button.default.foreground=880000
Button.default.focusedBackground=00ffff
Button.default.hoverBackground=ffff00
Button.default.pressedBackground=FFC800
Button.default.borderColor=ff0000
Button.default.hoverBorderColor=ff0000
Button.default.focusedBorderColor=537699
Button.default.focusColor=ff0000
Button.toolbar.hoverBackground=ffffff
Button.toolbar.pressedBackground=eeeeee
#---- CheckBox ----
CheckBox.icon.borderColor=878787
CheckBox.icon.disabledBorderColor=BDBDBD
CheckBox.icon.selectedBorderColor=4982CC
CheckBox.icon.focusedBorderColor=7B9FC7
CheckBox.icon.hoverBorderColor=ff0000
CheckBox.icon.selectedFocusedBorderColor=ACCFF7
CheckBox.icon.background=FFFFFF
CheckBox.icon.disabledBackground=F2F2F2
CheckBox.icon.focusedBackground=00ffff
CheckBox.icon.hoverBackground=ffff00
CheckBox.icon.pressedBackground=FFC800
CheckBox.icon.selectedBackground=4D89C9
CheckBox.icon.checkmarkColor=FFFFFF
CheckBox.icon.disabledCheckmarkColor=ABABAB
#---- ComboBox ----
ComboBox.background=ffffff
ComboBox.buttonBackground=f0f0f0
ComboBox.buttonEditableBackground=cccccc
ComboBox.buttonArrowColor=666666
ComboBox.buttonDisabledArrowColor=ABABAB
ComboBox.buttonHoverArrowColor=ff0000
#---- Component ----
Component.borderColor=ff0000
Component.disabledBorderColor=000088
Component.focusedBorderColor=466d94
Component.focusColor=97c3f3
#Component.focusWidth=5
#Component.arc=8
#---- HelpButton ----
HelpButton.questionMarkColor=0000ff
#---- Label ----
Label.foreground=008800
Label.disabledForeground=000088
#---- List ----
List.background=f0ffff
List.cellNoFocusBorder=1,6,1,6
List.focusSelectedCellHighlightBorder=1,6,1,6,880000
List.focusCellHighlightBorder=1,6,1,6,880000
#---- Menu ----
Menu.icon.arrowColor=4D89C9
Menu.icon.disabledArrowColor=ABABAB
#---- MenuBar ----
MenuBar.borderColor=4444ff
#---- MenuItemCheckBox ----
MenuItemCheckBox.icon.checkmarkColor=4D89C9
MenuItemCheckBox.icon.disabledCheckmarkColor=ABABAB
#---- OptionPane ----
OptionPane.icon.errorColor=ff0000
OptionPane.icon.informationColor=00ff00
OptionPane.icon.questionColor=0000ff
OptionPane.icon.warningColor=ffcc00
OptionPane.icon.foreground=ffffff
#---- PopupMenu ----
PopupMenu.borderColor=0000ff
#---- PopupMenuSeparator ----
PopupMenuSeparator.height=30
PopupMenuSeparator.stripeWidth=3
PopupMenuSeparator.stripeIndent=1
#---- ProgressBar ----
ProgressBar.background=88ff88
ProgressBar.foreground=33737373
ProgressBar.selectionForeground=ff0000
ProgressBar.selectionBackground=000088
ProgressBar.cycleTime=10000
#---- ScrollBar ----
ScrollBar.track=88ff88
ScrollBar.thumb=33737373
ScrollBar.hoverTrackColor=00ff00
ScrollBar.hoverThumbColor=ff0000
#---- Separator ----
Separator.foreground=00bb00
Separator.height=20
Separator.stripeWidth=10
Separator.stripeIndent=5
#---- Slider ----
Slider.trackColor=00bb00
Slider.thumbColor=880000
Slider.tickColor=ff0000
Slider.focusedColor=@@Component.focusColor
Slider.hoverColor=0000ff
Slider.disabledForeground=000088
#---- SplitPane ----
SplitPaneDivider.draggingColor=880000
SplitPaneDivider.oneTouchArrowColor=00ff00
SplitPaneDivider.oneTouchHoverArrowColor=ff0000
#---- TabbedPane ----
TabbedPane.disabledForeground=777777
TabbedPane.underlineColor=4A88C7
TabbedPane.disabledUnderlineColor=7a7a7a
TabbedPane.hoverColor=eeeeee
TabbedPane.focusColor=dddddd
TabbedPane.contentAreaColor=bbbbbb
#---- Table ----
Table.rowHeight=25
Table.background=fffff0
Table.sortIconColor=ffff00
Table.gridColor=00ffff
#---- TableHeader ----
TableHeader.background=4444ff
TableHeader.foreground=ffffff
TableHeader.separatorColor=00ff00
TableHeader.bottomSeparatorColor=00ff00
#---- TitledBorder ----
TitledBorder.titleColor=ff00ff
TitledBorder.border=1,1,1,1,ff00ff
#---- ToggleButton ----
ToggleButton.background=ddddff
ToggleButton.selectedBackground=44ff44
ToggleButton.selectedForeground=000000
ToggleButton.disabledSelectedBackground=44dd44
ToggleButton.focusedBackground=00ffff
ToggleButton.hoverBackground=ffff00
ToggleButton.pressedBackground=FFC800
ToggleButton.toolbar.selectedBackground=dddddd
#---- ToolTip ----
ToolTip.background=eeeeff
#---- Tree ----
Tree.background=fff0ff
Tree.paintLines=true
Tree.hash=ff0000

4
flatlaf-demo/README.md Normal file
View File

@@ -0,0 +1,4 @@
FlatLaf Demo
============
This sub-project contains the FlatLaf Demo source code.

View File

@@ -18,26 +18,26 @@ version = rootProject.version
plugins { plugins {
`java-library` `java-library`
} id( "com.jfrog.bintray" ) version "1.8.4"
repositories {
jcenter()
} }
dependencies { dependencies {
implementation( project( ":flatlaf-core" ) ) implementation( project( ":flatlaf-core" ) )
implementation( project( ":flatlaf-extras" ) )
implementation( "com.miglayout:miglayout-swing:5.2" ) implementation( "com.miglayout:miglayout-swing:5.2" )
implementation( "com.jgoodies:jgoodies-forms:1.9.0" ) implementation( "com.jgoodies:jgoodies-forms:1.9.0" )
implementation( "com.formdev:svgSalamander:1.1.2.1" )
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
tasks { tasks {
jar { jar {
dependsOn( ":flatlaf-core:jar" )
dependsOn( ":flatlaf-extras:jar" )
manifest { manifest {
attributes( "Main-Class" to "com.formdev.flatlaf.demo.FlatLafDemo" ) attributes( "Main-Class" to "com.formdev.flatlaf.demo.FlatLafDemo" )
} }
@@ -50,3 +50,23 @@ tasks {
} ) } )
} }
} }
bintray {
user = System.getenv( "BINTRAY_USER" ) ?: System.getProperty( "bintray.user" )
key = System.getenv( "BINTRAY_KEY" ) ?: System.getProperty( "bintray.key" )
setConfigurations( "archives" )
with( pkg ) {
repo = "flatlaf"
name = "flatlaf-demo"
setLicenses( "Apache-2.0" )
vcsUrl = "https://github.com/JFormDesigner/FlatLaf"
with( version ) {
name = project.version.toString()
}
publish = true
}
}

View File

@@ -40,6 +40,9 @@ class BasicComponentsPanel
JButton button3 = new JButton(); JButton button3 = new JButton();
JButton button4 = new JButton(); JButton button4 = new JButton();
JButton button13 = new JButton(); JButton button13 = new JButton();
JButton button14 = new JButton();
JButton button15 = new JButton();
JButton button16 = new JButton();
JLabel checkBoxLabel = new JLabel(); JLabel checkBoxLabel = new JLabel();
JCheckBox checkBox1 = new JCheckBox(); JCheckBox checkBox1 = new JCheckBox();
JCheckBox checkBox2 = new JCheckBox(); JCheckBox checkBox2 = new JCheckBox();
@@ -174,6 +177,18 @@ class BasicComponentsPanel
button13.setIcon(UIManager.getIcon("Tree.closedIcon")); button13.setIcon(UIManager.getIcon("Tree.closedIcon"));
add(button13, "cell 5 1"); add(button13, "cell 5 1");
//---- button14 ----
button14.setText("...");
add(button14, "cell 5 1");
//---- button15 ----
button15.setText("\u2026");
add(button15, "cell 5 1");
//---- button16 ----
button16.setText("#");
add(button16, "cell 5 1");
//---- checkBoxLabel ---- //---- checkBoxLabel ----
checkBoxLabel.setText("JCheckBox"); checkBoxLabel.setText("JCheckBox");
add(checkBoxLabel, "cell 0 2"); add(checkBoxLabel, "cell 0 2");

View File

@@ -75,6 +75,24 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1" "value": "cell 5 1"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button14"
"text": "..."
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button15"
"text": "…"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button16"
"text": "#"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "checkBoxLabel" name: "checkBoxLabel"
"text": "JCheckBox" "text": "JCheckBox"

View File

@@ -23,6 +23,7 @@ import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import javax.swing.*; import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel; import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.*; import com.formdev.flatlaf.*;
@@ -43,11 +44,11 @@ class ControlBar
initComponents(); initComponents();
// initialize look and feels combo box // initialize look and feels combo box
DefaultComboBoxModel<LafInfo> lafModel = new DefaultComboBoxModel<>(); DefaultComboBoxModel<LookAndFeelInfo> lafModel = new DefaultComboBoxModel<>();
lafModel.addElement( new LafInfo( "Flat Light (F1)", FlatLightLaf.class.getName() ) ); lafModel.addElement( new LookAndFeelInfo( "Flat Light (F1)", FlatLightLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Dark (F2)", FlatDarkLaf.class.getName() ) ); lafModel.addElement( new LookAndFeelInfo( "Flat Dark (F2)", FlatDarkLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat IntelliJ (F3)", FlatIntelliJLaf.class.getName() ) ); lafModel.addElement( new LookAndFeelInfo( "Flat IntelliJ (F3)", FlatIntelliJLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Darcula (F4)", FlatDarculaLaf.class.getName() ) ); lafModel.addElement( new LookAndFeelInfo( "Flat Darcula (F4)", FlatDarculaLaf.class.getName() ) );
UIManager.LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels(); UIManager.LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels();
for( UIManager.LookAndFeelInfo lookAndFeel : lookAndFeels ) { for( UIManager.LookAndFeelInfo lookAndFeel : lookAndFeels ) {
@@ -66,18 +67,9 @@ class ControlBar
else if( className.equals( NimbusLookAndFeel.class.getName() ) ) else if( className.equals( NimbusLookAndFeel.class.getName() ) )
name += " (F11)"; name += " (F11)";
lafModel.addElement( new LafInfo( name, className ) ); lafModel.addElement( new LookAndFeelInfo( name, className ) );
} }
LookAndFeel activeLaf = UIManager.getLookAndFeel();
String activeLafClassName = activeLaf.getClass().getName();
int sel = lafModel.getIndexOf( new LafInfo( null, activeLafClassName ) );
if( sel < 0 ) {
lafModel.addElement( new LafInfo( activeLaf.getName(), activeLafClassName ) );
sel = lafModel.getSize() - 1;
}
lafModel.setSelectedItem( lafModel.getElementAt( sel ) );
lookAndFeelComboBox.setModel( lafModel ); lookAndFeelComboBox.setModel( lafModel );
UIManager.addPropertyChangeListener( e -> { UIManager.addPropertyChangeListener( e -> {
@@ -161,26 +153,23 @@ class ControlBar
} }
private void selectLookAndFeel( String lafClassName ) { private void selectLookAndFeel( String lafClassName ) {
DefaultComboBoxModel<LafInfo> lafModel = (DefaultComboBoxModel<LafInfo>) lookAndFeelComboBox.getModel(); lookAndFeelComboBox.setSelectedLookAndFeel( lafClassName );
int sel = lafModel.getIndexOf( new LafInfo( null, lafClassName ) );
if( sel >= 0 )
lookAndFeelComboBox.setSelectedIndex( sel );
} }
private void lookAndFeelChanged() { private void lookAndFeelChanged() {
LafInfo newLaf = (LafInfo) lookAndFeelComboBox.getSelectedItem(); String lafClassName = lookAndFeelComboBox.getSelectedLookAndFeel();
if( newLaf == null ) if( lafClassName == null )
return; return;
if( newLaf.className.equals( UIManager.getLookAndFeel().getClass().getName() ) ) if( lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) )
return; return;
FlatLafDemo.prefs.put( FlatLafDemo.KEY_LAF, newLaf.className ); FlatLafDemo.prefs.put( FlatLafDemo.KEY_LAF, lafClassName );
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
try { try {
// change look and feel // change look and feel
UIManager.setLookAndFeel( newLaf.className ); UIManager.setLookAndFeel( lafClassName );
// update all components // update all components
FlatLaf.updateUI(); FlatLaf.updateUI();
@@ -250,7 +239,7 @@ class ControlBar
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
separator1 = new JSeparator(); separator1 = new JSeparator();
lookAndFeelComboBox = new JComboBox<>(); lookAndFeelComboBox = new LookAndFeelsComboBox();
rightToLeftCheckBox = new JCheckBox(); rightToLeftCheckBox = new JCheckBox();
enabledCheckBox = new JCheckBox(); enabledCheckBox = new JCheckBox();
infoLabel = new JLabel(); infoLabel = new JLabel();
@@ -300,33 +289,10 @@ class ControlBar
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JSeparator separator1; private JSeparator separator1;
private JComboBox<LafInfo> lookAndFeelComboBox; private LookAndFeelsComboBox lookAndFeelComboBox;
private JCheckBox rightToLeftCheckBox; private JCheckBox rightToLeftCheckBox;
private JCheckBox enabledCheckBox; private JCheckBox enabledCheckBox;
private JLabel infoLabel; private JLabel infoLabel;
private JButton closeButton; private JButton closeButton;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
//---- class LafInfo ------------------------------------------------------
static class LafInfo
{
final String name;
final String className;
LafInfo( String name, String className ) {
this.name = name;
this.className = className;
}
@Override
public boolean equals( Object obj ) {
return obj instanceof LafInfo && className.equals( ((LafInfo)obj).className );
}
@Override
public String toString() {
return name;
}
}
} }

View File

@@ -15,11 +15,8 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0 5 1" "value": "cell 0 0 5 1"
} ) } )
add( new FormComponent( "javax.swing.JComboBox" ) { add( new FormComponent( "com.formdev.flatlaf.demo.LookAndFeelsComboBox" ) {
name: "lookAndFeelComboBox" name: "lookAndFeelComboBox"
auxiliary() {
"JavaCodeGenerator.typeParameters": "LafInfo"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "lookAndFeelChanged", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "lookAndFeelChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1" "value": "cell 0 1"

View File

@@ -19,6 +19,8 @@ package com.formdev.flatlaf.demo;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import javax.swing.*; import javax.swing.*;
import com.formdev.flatlaf.demo.intellijthemes.*;
import com.formdev.flatlaf.extras.FlatSVGIcon;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
/** /**
@@ -87,6 +89,7 @@ class DemoFrame
TabsPanel tabsPanel = new TabsPanel(); TabsPanel tabsPanel = new TabsPanel();
OptionPanePanel optionPanePanel = new OptionPanePanel(); OptionPanePanel optionPanePanel = new OptionPanePanel();
controlBar = new ControlBar(); controlBar = new ControlBar();
IJThemesPanel themesPanel = new IJThemesPanel();
//======== this ======== //======== this ========
setTitle("FlatLaf Demo"); setTitle("FlatLaf Demo");
@@ -205,18 +208,37 @@ class DemoFrame
//======== toolBar1 ======== //======== toolBar1 ========
{ {
toolBar1.setMargin(new Insets(3, 3, 3, 3)); toolBar1.setMargin(new Insets(3, 3, 3, 3));
//---- backButton ----
backButton.setToolTipText("Back");
toolBar1.add(backButton); toolBar1.add(backButton);
//---- forwardButton ----
forwardButton.setToolTipText("Forward");
toolBar1.add(forwardButton); toolBar1.add(forwardButton);
toolBar1.addSeparator(); toolBar1.addSeparator();
//---- cutButton ----
cutButton.setToolTipText("Cut");
toolBar1.add(cutButton); toolBar1.add(cutButton);
//---- copyButton ----
copyButton.setToolTipText("Copy");
toolBar1.add(copyButton); toolBar1.add(copyButton);
//---- pasteButton ----
pasteButton.setToolTipText("Paste");
toolBar1.add(pasteButton); toolBar1.add(pasteButton);
toolBar1.addSeparator(); toolBar1.addSeparator();
//---- refreshButton ----
refreshButton.setToolTipText("Refresh");
toolBar1.add(refreshButton); toolBar1.add(refreshButton);
toolBar1.addSeparator(); toolBar1.addSeparator();
//---- showToggleButton ---- //---- showToggleButton ----
showToggleButton.setSelected(true); showToggleButton.setSelected(true);
showToggleButton.setToolTipText("Show Details");
toolBar1.add(showToggleButton); toolBar1.add(showToggleButton);
} }
contentPane.add(toolBar1, BorderLayout.NORTH); contentPane.add(toolBar1, BorderLayout.NORTH);
@@ -243,6 +265,7 @@ class DemoFrame
} }
contentPane.add(contentPanel, BorderLayout.CENTER); contentPane.add(contentPanel, BorderLayout.CENTER);
contentPane.add(controlBar, BorderLayout.SOUTH); contentPane.add(controlBar, BorderLayout.SOUTH);
contentPane.add(themesPanel, BorderLayout.EAST);
//---- buttonGroup1 ---- //---- buttonGroup1 ----
ButtonGroup buttonGroup1 = new ButtonGroup(); ButtonGroup buttonGroup1 = new ButtonGroup();
@@ -251,20 +274,20 @@ class DemoFrame
buttonGroup1.add(radioButtonMenuItem3); buttonGroup1.add(radioButtonMenuItem3);
// JFormDesigner - End of component initialization //GEN-END:initComponents // JFormDesigner - End of component initialization //GEN-END:initComponents
undoMenuItem.setIcon( new ScaledSVGIcon( "icons/undo.svg" ) ); undoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/undo.svg" ) );
redoMenuItem.setIcon( new ScaledSVGIcon( "icons/redo.svg" ) ); redoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/redo.svg" ) );
cutMenuItem.setIcon( new ScaledSVGIcon( "icons/menu-cut.svg" ) ); cutMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-cut.svg" ) );
copyMenuItem.setIcon( new ScaledSVGIcon( "icons/copy.svg" ) ); copyMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/copy.svg" ) );
pasteMenuItem.setIcon( new ScaledSVGIcon( "icons/menu-paste.svg" ) ); pasteMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-paste.svg" ) );
backButton.setIcon( new ScaledSVGIcon( "icons/back.svg" ) ); backButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/back.svg" ) );
forwardButton.setIcon( new ScaledSVGIcon( "icons/forward.svg" ) ); forwardButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/forward.svg" ) );
cutButton.setIcon( new ScaledSVGIcon( "icons/menu-cut.svg" ) ); cutButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-cut.svg" ) );
copyButton.setIcon( new ScaledSVGIcon( "icons/copy.svg" ) ); copyButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/copy.svg" ) );
pasteButton.setIcon( new ScaledSVGIcon( "icons/menu-paste.svg" ) ); pasteButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-paste.svg" ) );
refreshButton.setIcon( new ScaledSVGIcon( "icons/refresh.svg" ) ); refreshButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/refresh.svg" ) );
showToggleButton.setIcon( new ScaledSVGIcon( "icons/show.svg" ) ); showToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/show.svg" ) );
} }
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables

View File

@@ -17,27 +17,33 @@ new FormModel {
"margin": new java.awt.Insets( 3, 3, 3, 3 ) "margin": new java.awt.Insets( 3, 3, 3, 3 )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "backButton" name: "backButton"
"toolTipText": "Back"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "forwardButton" name: "forwardButton"
"toolTipText": "Forward"
} ) } )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) { add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator5" name: "separator5"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "cutButton" name: "cutButton"
"toolTipText": "Cut"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "copyButton" name: "copyButton"
"toolTipText": "Copy"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "pasteButton" name: "pasteButton"
"toolTipText": "Paste"
} ) } )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) { add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator6" name: "separator6"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "refreshButton" name: "refreshButton"
"toolTipText": "Refresh"
} ) } )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) { add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator7" name: "separator7"
@@ -45,6 +51,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JToggleButton" ) { add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "showToggleButton" name: "showToggleButton"
"selected": true "selected": true
"toolTipText": "Show Details"
} ) } )
}, new FormLayoutConstraints( class java.lang.String ) { }, new FormLayoutConstraints( class java.lang.String ) {
"value": "North" "value": "North"
@@ -100,6 +107,11 @@ new FormModel {
}, new FormLayoutConstraints( class java.lang.String ) { }, new FormLayoutConstraints( class java.lang.String ) {
"value": "South" "value": "South"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel" ) {
name: "themesPanel"
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "East"
} )
menuBar: new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) { menuBar: new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
name: "menuBar1" name: "menuBar1"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
@@ -213,7 +225,7 @@ new FormModel {
} }
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 800, 710 ) "size": new java.awt.Dimension( 935, 710 )
} ) } )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) { add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "buttonGroup1" name: "buttonGroup1"

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