Compare commits

..

38 Commits
2.0 ... 2.1

Author SHA1 Message Date
Karl Tauber
c00d99b85f release 2.1 2022-03-17 12:52:49 +01:00
Karl Tauber
0bf87b753d TabbedPane: disable all items in "Show Hidden Tabs" popup menu if tabbed pane is disabled 2022-03-17 12:42:49 +01:00
Karl Tauber
53f2730064 TextArea, TextPane and EditorPane: no longer select all text when component is focused for the first time (issue #498; regression in FlatLaf 2.0) 2022-03-17 12:21:06 +01:00
Karl Tauber
d487c3b005 JIDE: use FlatLaf menu scrolling for JidePopupMenu (issue #225) 2022-03-14 12:23:52 +01:00
Karl Tauber
fef6ae7ff7 Menus: scroll large menus using mouse wheel or up/down arrows (issue #225) 2022-03-14 11:41:05 +01:00
Karl Tauber
f6b42754de Testing: FlatScreenshotsBackground: also make title bar white/black 2022-03-14 11:20:09 +01:00
Karl Tauber
2ae9bb381d Menus: fixed IllegalComponentStateException: component must be showing on the screen to determine its location when submenu is empty (PR #490; issue #247) 2022-03-14 00:23:53 +01:00
Karl Tauber
53bde84710 fixed compiler warning 2022-03-13 19:17:41 +01:00
Karl Tauber
d006ac27ff Merge PR #490: Menus: improved usability of submenus 2022-03-13 19:07:59 +01:00
Karl Tauber
c478d28b71 PasswordField: fixed reveal button appearance in IntelliJ themes (issue #494) 2022-03-13 18:39:12 +01:00
Karl Tauber
99f7b9ad84 ScrollBar:
- added `ScrollBar.minimumButtonSize` to specify minimum scroll arrow button size
- center and scale arrows in scroll up/down buttons

(issue #493)
2022-03-13 10:58:27 +01:00
Karl Tauber
ab58101ce3 SwingX: test JXStatusBar (issue #492) 2022-03-06 11:41:54 +01:00
Karl Tauber
d8f3682dc0 Menus: improved usability of submenus (issue #247) 2022-02-28 14:45:57 +01:00
Karl Tauber
1fec7ba553 Linux: support using custom window decorations (issue #482) 2022-02-26 23:07:16 +01:00
Karl Tauber
418f55f34e Window decorations: fixed window resizing on Linux (issue #482) 2022-02-26 14:00:16 +01:00
Karl Tauber
05d795b2ae Window decorations: use special fix for maximized bounds only on Windows (issue #469) 2022-02-26 13:33:55 +01:00
Karl Tauber
a365b750d9 core: minor code cleanup:
- add final where possible
- removed "public" from interface methods
- simplified conditional expressions
- removed unnecessary unboxing
- removed unused assignements
- removed redundant casts

(used IntelliJ IDEA 2021.3 inspections)
2022-02-25 21:49:15 +01:00
Karl Tauber
0aecfb565f IntelliJ Themes: removed duplicate key and trailing spaces 2022-02-25 21:12:48 +01:00
Karl Tauber
0cf4edd9e5 core: fixed typos/grammar in comments 2022-02-25 20:40:37 +01:00
Karl Tauber
dd7b7c6aef release 2.0.2 2022-02-25 16:58:22 +01:00
Karl Tauber
0bd677c46b FlatSVGIcon: changed logging when icon resource is not found from "severe" to "config" (issue #476) 2022-02-25 16:55:04 +01:00
Karl Tauber
1a131d5206 Merge PR #484: Fix NPE when painting icon on OS X top menu bar 2022-02-25 15:58:41 +01:00
Karl Tauber
016e515ae2 moved TestFlatIconNullComponent to other package and fixed file name (issue #483) 2022-02-25 15:52:40 +01:00
Karl Tauber
456ceb3c58 Merge PR #486: Request to add Ultorg to list of apps using FlatLAF 2022-02-25 15:27:58 +01:00
Eirik Bakke
2169be1b45 In README, add Ultorg to list of apps using FlatLAF. 2022-02-24 19:00:37 -05:00
Karl Tauber
49eb0b0201 Native window decorations: updated DLLs (issue #477)
built by GitHub Actions:
https://github.com/JFormDesigner/FlatLaf/actions/runs/1866639721
2022-02-18 22:44:00 +01:00
Karl Tauber
2e222bcdea Native window decorations (Windows 10/11 only): fixed rendering artifacts on HiDPI screens when dragging window partly offscreen and back into screen bounds (issue #477) 2022-02-18 22:24:36 +01:00
Nicolas Roduit
c7fa475128 NPE when painting icon on OS X top menu bar #483 2022-02-18 18:30:24 +01:00
Karl Tauber
4174b065f3 repaint component when setting client property JComponent.outline (issue #480) 2022-02-16 23:53:21 +01:00
Karl Tauber
df6256d989 release 2.0.1 2022-01-25 18:46:29 +01:00
Karl Tauber
c27db56321 moved module-info.class from META-INF\versions\9\ to root folder of JARs (issue #466) 2022-01-25 16:59:31 +01:00
Karl Tauber
97bed8554a FlatSVGIcon: added copy constructor (issue #465) 2022-01-25 00:47:35 +01:00
Karl Tauber
751c0e16e9 ToolTip: fixed wrong tooltip location if component overrides JComponent.getToolTipLocation() and wants place tooltip under mouse location (issue #468) 2022-01-24 23:24:39 +01:00
Karl Tauber
936de60700 fixed memory leak in Panel, Separator and ToolBarSeparator (issue #471) 2022-01-24 18:28:38 +01:00
Karl Tauber
f6b64d48ec Merge PR #463: Updating MegaMek Suite Information 2022-01-19 17:27:12 +01:00
Justin Bowen
b043da7d4c Updating MegaMek Suite Information 2022-01-13 20:22:30 -05:00
Karl Tauber
7e47cc2443 updated sigtest for FlatLaf 2.0
(generated in clean workspace with gradle task `sigtestGenerate`)
2022-01-13 12:14:51 +01:00
Karl Tauber
b8b45f9442 Theme Editor: added to main readme 2022-01-11 16:17:17 +01:00
99 changed files with 2523 additions and 280 deletions

View File

@@ -1,6 +1,58 @@
FlatLaf Change Log
==================
## 2.1
#### New features and improvements
- Menus: Improved usability of submenus. (PR #490; issue #247)
- Menus: Scroll large menus using mouse wheel or up/down arrows. (issue #225)
- Linux: Support using custom window decorations. Enable with
`JFrame.setDefaultLookAndFeelDecorated(true)` and
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
(issue #482)
- ScrollBar: Added UI value `ScrollBar.minimumButtonSize` to specify minimum
scroll arrow button size (if shown). (issue #493)
#### Fixed bugs
- PasswordField: Fixed reveal button appearance in IntelliJ themes. (issue #494)
- ScrollBar: Center and scale arrows in scroll up/down buttons (if shown).
(issue #493)
- TextArea, TextPane and EditorPane: No longer select all text when component is
focused for the first time. (issue #498; regression in FlatLaf 2.0)
- TabbedPane: Disable all items in "Show Hidden Tabs" popup menu if tabbed pane
is disabled.
#### Incompatibilities
- Method `FlatUIUtils.paintArrow()` (and class `FlatArrowButton`) now paints
arrows one pixel smaller than before. To fix this, increase parameter
`arrowSize` by one.
## 2.0.2
- Native window decorations (Windows 10/11 only): Fixed rendering artifacts on
HiDPI screens when dragging window partly offscreen and back into screen
bounds. (issue #477)
- Repaint component when setting client property `JComponent.outline` (issue
#480).
- macOS: Fixed NPE when using some icons in main menu items. (issue #483)
## 2.0.1
- Fixed memory leak in Panel, Separator and ToolBarSeparator. (issue #471;
regression in FlatLaf 2.0)
- ToolTip: Fixed wrong tooltip location if component overrides
`JComponent.getToolTipLocation()` and wants place tooltip under mouse
location. (issue #468)
- Extras: Added copy constructor to `FlatSVGIcon`. (issue #465)
- Moved `module-info.class` from `META-INF\versions\9\` to root folder of JARs.
(issue #466)
## 2.0
- Added system property `flatlaf.nativeLibraryPath` to load native libraries

View File

@@ -11,9 +11,9 @@ scales on **HiDPI** displays and runs on Java 8 or newer.
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
IntelliJ IDEA 2019.2+ and uses almost the same colors and icons.
![Flat Light](images/flat_light.png)
![FlatLaf Light](images/flat_light.png)
![Flat Dark](images/flat_dark.png)
![FlatLaf Dark](images/flat_dark.png)
IntelliJ Platform Themes
@@ -105,6 +105,16 @@ For more information and documentation visit
- [System Properties](https://www.formdev.com/flatlaf/system-properties/)
Theme Editor
------------
The Theme Editor that supports editing FlatLaf theme properties files. See
[Theme Editor documentation](https://www.formdev.com/flatlaf/theme-editor/) for
details and downloads.
![Theme Editor](images/theme-editor@1.5x.png)
Buzz
----
@@ -116,6 +126,8 @@ Buzz
Applications using FlatLaf
--------------------------
- ![New](images/new.svg) [Ultorg](https://www.ultorg.com/) (**commercial**) - a
visual query system for relational databases
- ![New](images/new.svg) [MooInfo](https://github.com/rememberber/MooInfo) -
visual implementation of OSHI, to view information about the system and
hardware
@@ -154,9 +166,10 @@ Applications using FlatLaf
- [Total Validator](https://www.totalvalidator.com/) 15 (**commercial**) -
checks your website
- [j-lawyer](https://github.com/jlawyerorg/j-lawyer-org) - Kanzleisoftware
- [MegaMek](https://github.com/MegaMek/megamek) v0.47.4 and
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5 - a turn-based sci-fi board
game
- [MegaMek](https://github.com/MegaMek/megamek),
[MegaMekLab](https://github.com/MegaMek/megameklab) and
[MekHQ](https://github.com/MegaMek/mekhq) v0.47.5+ - a sci-fi tabletop
BattleTech simulator suite handling battles, unit building, and campaigns
- [GUIslice Builder](https://github.com/ImpulseAdventure/GUIslice-Builder)
0.13.b024 - GUI builder for
[GUIslice](https://github.com/ImpulseAdventure/GUIslice), a lightweight GUI

View File

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

View File

@@ -63,10 +63,8 @@ if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
jar {
manifest.attributes( "Multi-Release" to "true" )
into( "META-INF/versions/9" ) {
from( sourceSets["module-info"].output ) {
include( "module-info.class" )
}
from( sourceSets["module-info"].output ) {
include( "module-info.class" )
}
}
}

View File

@@ -1,5 +1,5 @@
#Signature file v4.1
#Version 1.6
#Version 2.0
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
@@ -31,6 +31,8 @@ fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "al
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"
fld public final static java.lang.String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"
fld public final static java.lang.String SQUARE_SIZE = "JButton.squareSize"
fld public final static java.lang.String STYLE = "FlatLaf.style"
fld public final static java.lang.String STYLE_CLASS = "FlatLaf.styleClass"
fld public final static java.lang.String TABBED_PANE_ALIGN_CENTER = "center"
fld public final static java.lang.String TABBED_PANE_ALIGN_FILL = "fill"
fld public final static java.lang.String TABBED_PANE_ALIGN_LEADING = "leading"
@@ -59,6 +61,9 @@ fld public final static java.lang.String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JT
fld public final static java.lang.String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"
fld public final static java.lang.String TABBED_PANE_TAB_ICON_PLACEMENT = "JTabbedPane.tabIconPlacement"
fld public final static java.lang.String TABBED_PANE_TAB_INSETS = "JTabbedPane.tabInsets"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE = "JTabbedPane.tabType"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_CARD = "card"
fld public final static java.lang.String TABBED_PANE_TAB_TYPE_UNDERLINED = "underlined"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE = "JTabbedPane.tabWidthMode"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_COMPACT = "compact"
fld public final static java.lang.String TABBED_PANE_TAB_WIDTH_MODE_EQUAL = "equal"
@@ -67,12 +72,20 @@ fld public final static java.lang.String TABBED_PANE_TRAILING_COMPONENT = "JTabb
fld public final static java.lang.String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_COLOR = "JToggleButton.tab.underlineColor"
fld public final static java.lang.String TAB_BUTTON_UNDERLINE_HEIGHT = "JToggleButton.tab.underlineHeight"
fld public final static java.lang.String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback"
fld public final static java.lang.String TEXT_FIELD_LEADING_COMPONENT = "JTextField.leadingComponent"
fld public final static java.lang.String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon"
fld public final static java.lang.String TEXT_FIELD_PADDING = "JTextField.padding"
fld public final static java.lang.String TEXT_FIELD_SHOW_CLEAR_BUTTON = "JTextField.showClearButton"
fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextField.trailingComponent"
fld public final static java.lang.String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon"
fld public final static java.lang.String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground"
fld public final static java.lang.String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
fld public final static java.lang.String TREE_PAINT_SELECTION = "JTree.paintSelection"
fld public final static java.lang.String TREE_WIDE_SELECTION = "JTree.wideSelection"
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "JRootPane.useWindowDecorations"
meth public static <%0 extends java.lang.Object> {%%0} clientProperty(javax.swing.JComponent,java.lang.String,{%%0},java.lang.Class<{%%0}>)
meth public static boolean clientPropertyBoolean(javax.swing.JComponent,java.lang.String,boolean)
meth public static boolean clientPropertyEquals(javax.swing.JComponent,java.lang.String,java.lang.Object)
meth public static int clientPropertyInt(javax.swing.JComponent,java.lang.String,int)
@@ -165,6 +178,7 @@ meth public boolean isSupportedLookAndFeel()
meth public final boolean equals(java.lang.Object)
meth public final int hashCode()
meth public java.lang.String getID()
meth public java.util.Map<java.lang.String,java.lang.String> getExtraDefaults()
meth public javax.swing.Icon getDisabledIcon(javax.swing.JComponent,javax.swing.Icon)
meth public javax.swing.UIDefaults getDefaults()
meth public static boolean install(javax.swing.LookAndFeel)
@@ -174,6 +188,8 @@ meth public static boolean isShowMnemonics()
meth public static boolean isUseNativeWindowDecorations()
meth public static boolean setup(javax.swing.LookAndFeel)
meth public static boolean supportsNativeWindowDecorations()
meth public static java.lang.Object parseDefaultsValue(java.lang.String,java.lang.String,java.lang.Class<?>)
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
meth public static void hideMnemonics()
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
@@ -181,22 +197,26 @@ meth public static void installLafInfo(java.lang.String,java.lang.Class<? extend
meth public static void registerCustomDefaultsSource(java.io.File)
meth public static void registerCustomDefaultsSource(java.lang.String)
meth public static void registerCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
meth public static void registerCustomDefaultsSource(java.net.URL)
meth public static void repaintAllFramesAndDialogs()
meth public static void revalidateAndRepaintAllFramesAndDialogs()
meth public static void runWithUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>,java.lang.Runnable)
meth public static void setGlobalExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
meth public static void setUseNativeWindowDecorations(boolean)
meth public static void showMnemonics(java.awt.Component)
meth public static void unregisterCustomDefaultsSource(java.io.File)
meth public static void unregisterCustomDefaultsSource(java.lang.String)
meth public static void unregisterCustomDefaultsSource(java.lang.String,java.lang.ClassLoader)
meth public static void unregisterCustomDefaultsSource(java.net.URL)
meth public static void updateUI()
meth public static void updateUILater()
meth public void initialize()
meth public void registerUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
meth public void setExtraDefaults(java.util.Map<java.lang.String,java.lang.String>)
meth public void uninitialize()
meth public void unregisterUIDefaultsGetter(java.util.function.Function<java.lang.Object,java.lang.Object>)
supr javax.swing.plaf.basic.BasicLookAndFeel
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,mnemonicHandler,oldPopupFactory,postInitialization,uiDefaultsGetters,updateUIPending
hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,uiDefaultsGetters,updateUIPending
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
@@ -231,6 +251,7 @@ hfds baseTheme,dark,name,properties
CLSS public abstract interface com.formdev.flatlaf.FlatSystemProperties
fld public final static java.lang.String ANIMATION = "flatlaf.animation"
fld public final static java.lang.String MENUBAR_EMBEDDED = "flatlaf.menuBarEmbedded"
fld public final static java.lang.String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath"
fld public final static java.lang.String UI_SCALE = "flatlaf.uiScale"
fld public final static java.lang.String UI_SCALE_ALLOW_SCALE_DOWN = "flatlaf.uiScale.allowScaleDown"
fld public final static java.lang.String UI_SCALE_ENABLED = "flatlaf.uiScale.enabled"
@@ -330,7 +351,15 @@ innr public static HSLIncreaseDecrease
innr public static Mix
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
meth public static float clamp(float)
meth public static float luma(java.awt.Color)
meth public static java.awt.Color darken(java.awt.Color,float)
meth public static java.awt.Color desaturate(java.awt.Color,float)
meth public static java.awt.Color lighten(java.awt.Color,float)
meth public static java.awt.Color mix(java.awt.Color,java.awt.Color,float)
meth public static java.awt.Color saturate(java.awt.Color,float)
meth public static java.awt.Color shade(java.awt.Color,float)
meth public static java.awt.Color spin(java.awt.Color,float)
meth public static java.awt.Color tint(java.awt.Color,float)
supr java.lang.Object
CLSS public abstract interface static com.formdev.flatlaf.util.ColorFunctions$ColorFunction
@@ -566,6 +595,7 @@ meth public static java.util.List<java.awt.Image> getResolutionVariants(java.awt
supr java.lang.Object
CLSS public com.formdev.flatlaf.util.NativeLibrary
cons public init(java.io.File,boolean)
cons public init(java.lang.String,java.lang.ClassLoader,boolean)
meth public boolean isLoaded()
supr java.lang.Object
@@ -589,18 +619,52 @@ meth public void paintIcon(java.awt.Component,java.awt.Graphics,int,int)
supr java.lang.Object
hfds iconHeight,iconWidth,imageIcon,lastImage,lastSystemScaleFactor,lastUserScaleFactor
CLSS public com.formdev.flatlaf.util.SoftCache<%0 extends java.lang.Object, %1 extends java.lang.Object>
cons public init()
cons public init(int)
intf java.util.Map<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>
meth public boolean containsKey(java.lang.Object)
meth public boolean containsValue(java.lang.Object)
meth public boolean isEmpty()
meth public int size()
meth public java.util.Collection<{com.formdev.flatlaf.util.SoftCache%1}> values()
meth public java.util.Set<java.util.Map$Entry<{com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1}>> entrySet()
meth public java.util.Set<{com.formdev.flatlaf.util.SoftCache%0}> keySet()
meth public void clear()
meth public void forEach(java.util.function.BiConsumer<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1}>)
meth public void putAll(java.util.Map<? extends {com.formdev.flatlaf.util.SoftCache%0},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
meth public void replaceAll(java.util.function.BiFunction<? super {com.formdev.flatlaf.util.SoftCache%0},? super {com.formdev.flatlaf.util.SoftCache%1},? extends {com.formdev.flatlaf.util.SoftCache%1}>)
meth public {com.formdev.flatlaf.util.SoftCache%1} get(java.lang.Object)
meth public {com.formdev.flatlaf.util.SoftCache%1} put({com.formdev.flatlaf.util.SoftCache%0},{com.formdev.flatlaf.util.SoftCache%1})
meth public {com.formdev.flatlaf.util.SoftCache%1} remove(java.lang.Object)
supr java.lang.Object
hfds map,queue
hcls CacheReference
CLSS public com.formdev.flatlaf.util.StringUtils
cons public init()
meth public static boolean isEmpty(java.lang.String)
meth public static boolean isTrimmedEmpty(java.lang.String)
meth public static java.lang.String removeLeading(java.lang.String,java.lang.String)
meth public static java.lang.String removeTrailing(java.lang.String,java.lang.String)
meth public static java.lang.String substringTrimmed(java.lang.String,int)
meth public static java.lang.String substringTrimmed(java.lang.String,int,int)
meth public static java.util.List<java.lang.String> split(java.lang.String,char)
meth public static java.util.List<java.lang.String> split(java.lang.String,char,boolean,boolean)
supr java.lang.Object
CLSS public com.formdev.flatlaf.util.SwingUtils
cons public init()
meth public static <%0 extends java.awt.Component> {%%0} getComponentByName(java.awt.Container,java.lang.String)
supr java.lang.Object
CLSS public com.formdev.flatlaf.util.SystemInfo
cons public init()
fld public final static boolean isAARCH64
fld public final static boolean isJava_11_orLater
fld public final static boolean isJava_15_orLater
fld public final static boolean isJava_17_orLater
fld public final static boolean isJava_18_orLater
fld public final static boolean isJava_9_orLater
fld public final static boolean isJetBrainsJVM
fld public final static boolean isJetBrainsJVM_11_orLater
@@ -615,6 +679,8 @@ fld public final static boolean isWebswing
fld public final static boolean isWinPE
fld public final static boolean isWindows
fld public final static boolean isWindows_10_orLater
fld public final static boolean isWindows_11_orLater
fld public final static boolean isX86
fld public final static boolean isX86_64
fld public final static long javaVersion
fld public final static long osVersion
@@ -627,6 +693,7 @@ cons public init()
meth public static boolean isSystemScalingEnabled()
meth public static double getSystemScaleFactor(java.awt.Graphics2D)
meth public static double getSystemScaleFactor(java.awt.GraphicsConfiguration)
meth public static float computeFontScaleFactor(java.awt.Font)
meth public static float getUserScaleFactor()
meth public static float scale(float)
meth public static float unscale(float)
@@ -933,6 +1000,34 @@ CLSS public abstract interface !annotation java.lang.annotation.Target
intf java.lang.annotation.Annotation
meth public abstract java.lang.annotation.ElementType[] value()
CLSS public abstract interface java.util.Map<%0 extends java.lang.Object, %1 extends java.lang.Object>
innr public abstract interface static Entry
meth public abstract boolean containsKey(java.lang.Object)
meth public abstract boolean containsValue(java.lang.Object)
meth public abstract boolean equals(java.lang.Object)
meth public abstract boolean isEmpty()
meth public abstract int hashCode()
meth public abstract int size()
meth public abstract java.util.Collection<{java.util.Map%1}> values()
meth public abstract java.util.Set<java.util.Map$Entry<{java.util.Map%0},{java.util.Map%1}>> entrySet()
meth public abstract java.util.Set<{java.util.Map%0}> keySet()
meth public abstract void clear()
meth public abstract void putAll(java.util.Map<? extends {java.util.Map%0},? extends {java.util.Map%1}>)
meth public abstract {java.util.Map%1} get(java.lang.Object)
meth public abstract {java.util.Map%1} put({java.util.Map%0},{java.util.Map%1})
meth public abstract {java.util.Map%1} remove(java.lang.Object)
meth public boolean remove(java.lang.Object,java.lang.Object)
meth public boolean replace({java.util.Map%0},{java.util.Map%1},{java.util.Map%1})
meth public void forEach(java.util.function.BiConsumer<? super {java.util.Map%0},? super {java.util.Map%1}>)
meth public void replaceAll(java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} compute({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} computeIfAbsent({java.util.Map%0},java.util.function.Function<? super {java.util.Map%0},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} computeIfPresent({java.util.Map%0},java.util.function.BiFunction<? super {java.util.Map%0},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} getOrDefault(java.lang.Object,{java.util.Map%1})
meth public {java.util.Map%1} merge({java.util.Map%0},{java.util.Map%1},java.util.function.BiFunction<? super {java.util.Map%1},? super {java.util.Map%1},? extends {java.util.Map%1}>)
meth public {java.util.Map%1} putIfAbsent({java.util.Map%0},{java.util.Map%1})
meth public {java.util.Map%1} replace({java.util.Map%0},{java.util.Map%1})
CLSS public abstract interface javax.swing.Icon
meth public abstract int getIconHeight()
meth public abstract int getIconWidth()

View File

@@ -26,7 +26,7 @@ import javax.swing.UIDefaults;
* Allows loading of additional .properties files from addon JARs.
* {@link java.util.ServiceLoader} is used to load extensions of this class from addon JARs.
* <p>
* If you extend this class in a addon JAR, you also have to add a text file named
* If you extend this class in an 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.
* <p>
@@ -61,7 +61,7 @@ public abstract class FlatDefaultsAddon
/**
* Returns the priority used to sort addon loading.
* The order is only important if you want overwrite UI defaults of other addons.
* The order is only important if you want to overwrite UI defaults of other addons.
* Lower numbers mean higher priority.
* Returns 10000 by default.
*/

View File

@@ -19,7 +19,7 @@ package com.formdev.flatlaf;
/**
* Default color palette for action icons and object icons.
* <p>
* The idea is to use only this well defined set of colors in SVG icons and
* The idea is to use only this well-defined set of colors in SVG icons, and
* then they are replaced at runtime to dark variants or to other theme colors.
* Then a single SVG icon (light variant) can be used for dark themes too.
* IntelliJ Platform uses this mechanism to allow themes to change IntelliJ Platform icons.
@@ -35,7 +35,7 @@ package com.formdev.flatlaf;
* <p>
* You may use these colors also in your application (outside of SVG icons), but do
* not use the RGB values defined in this enum.<br>
* Instead use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
* Instead, use {@code UIManager.getColor( FlatIconColors.ACTIONS_GREY.key )}.
*
* @author Karl Tauber
*/

View File

@@ -596,7 +596,7 @@ class FlatInputMaps
//---- class LazyInputMapEx -----------------------------------------------
/**
* Lazily creates a input map.
* Lazily creates an input map.
* Similar to {@link UIDefaults.LazyInputMap}, but can use multiple bindings arrays.
*/
private static class LazyInputMapEx

View File

@@ -103,6 +103,7 @@ public abstract class FlatLaf
private PopupFactory oldPopupFactory;
private MnemonicHandler mnemonicHandler;
private SubMenuUsabilityHelper subMenuUsabilityHelper;
private Consumer<UIDefaults> postInitialization;
private List<Function<Object, Object>> uiDefaultsGetters;
@@ -166,18 +167,19 @@ public abstract class FlatLaf
* Returns whether FlatLaf supports custom window decorations.
* This depends on the operating system and on the used Java runtime.
* <p>
* This method returns {@code true} on Windows 10 (see exception below), {@code false} otherwise.
* This method returns {@code true} on Windows 10/11 (see exception below)
* and on Linux, {@code false} otherwise.
* <p>
* Returns also {@code false} on Windows 10 if:
* Returns also {@code false} on Windows 10/11 if:
* <ul>
* <li>FlatLaf native window border support is available (requires Windows 10)</li>
* <li>FlatLaf native window border support is available (requires Windows 10/11)</li>
* <li>running in
* <a href="https://confluence.jetbrains.com/display/JBR/JetBrains+Runtime">JetBrains Runtime 11 (or later)</a>
* (<a href="https://github.com/JetBrains/JetBrainsRuntime">source code on github</a>)
* and JBR supports custom window decorations
* </li>
* </ul>
* In this cases, custom decorations are enabled by the root pane.
* In these cases, custom decorations are enabled by the root pane.
* Usage of {@link JFrame#setDefaultLookAndFeelDecorated(boolean)} or
* {@link JDialog#setDefaultLookAndFeelDecorated(boolean)} is not necessary.
*/
@@ -190,7 +192,7 @@ public abstract class FlatLaf
FlatNativeWindowBorder.isSupported() )
return false;
return SystemInfo.isWindows_10_orLater;
return SystemInfo.isWindows_10_orLater || SystemInfo.isLinux;
}
@Override
@@ -243,6 +245,10 @@ public abstract class FlatLaf
mnemonicHandler = new MnemonicHandler();
mnemonicHandler.install();
// install submenu usability helper
subMenuUsabilityHelper = new SubMenuUsabilityHelper();
subMenuUsabilityHelper.install();
// listen to desktop property changes to update UI if system font or scaling changes
if( SystemInfo.isWindows ) {
// Windows 10 allows increasing font size independent of scaling:
@@ -322,6 +328,12 @@ public abstract class FlatLaf
mnemonicHandler = null;
}
// uninstall submenu usability helper
if( subMenuUsabilityHelper != null ) {
subMenuUsabilityHelper.uninstall();
subMenuUsabilityHelper = null;
}
// restore default link color
new HTMLEditorKit().getStyleSheet().addRule( "a, address { color: blue; }" );
postInitialization = null;
@@ -605,7 +617,7 @@ public abstract class FlatLaf
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
} );
};
}
// increase font size if system property "flatlaf.uiScale" is set
uiFont = UIScale.applyCustomScaleFactor( uiFont );
@@ -760,7 +772,7 @@ public abstract class FlatLaf
* Invoke this method before setting the look and feel.
* <p>
* If using Java modules, the package must be opened in {@code module-info.java}.
* Otherwise use {@link #registerCustomDefaultsSource(URL)}.
* Otherwise, use {@link #registerCustomDefaultsSource(URL)}.
*
* @param packageName a package name (e.g. "com.myapp.resources")
*/
@@ -862,7 +874,7 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p>
* The global extra defaults are useful for smaller additional defaults that may change.
* E.g. accent color. Otherwise FlatLaf properties files should be used.
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}.
* <p>
* The keys and values are strings in same format as in FlatLaf properties files.
@@ -894,7 +906,7 @@ public abstract class FlatLaf
* E.g. using {@link UIManager#setLookAndFeel(LookAndFeel)} or {@link #setup(LookAndFeel)}.
* <p>
* The extra defaults are useful for smaller additional defaults that may change.
* E.g. accent color. Otherwise FlatLaf properties files should be used.
* E.g. accent color. Otherwise, FlatLaf properties files should be used.
* See {@link #registerCustomDefaultsSource(String)}.
* <p>
* The keys and values are strings in same format as in FlatLaf properties files.
@@ -951,7 +963,7 @@ public abstract class FlatLaf
// re-set current LaF
UIManager.setLookAndFeel( lookAndFeel );
// must fire property change events ourself because old and new LaF are the same
// must fire property change events ourselves because old and new LaF are the same
PropertyChangeEvent e = new PropertyChangeEvent( UIManager.class, "lookAndFeel", lookAndFeel, lookAndFeel );
for( PropertyChangeListener l : UIManager.getPropertyChangeListeners() )
l.propertyChange( e );
@@ -995,7 +1007,7 @@ public abstract class FlatLaf
/**
* Returns whether native window decorations are supported on current platform.
* <p>
* This requires Windows 10, but may be disabled if running in special environments
* This requires Windows 10/11, but may be disabled if running in special environments
* (JetBrains Projector, Webswing or WinPE) or if loading native library fails.
* If system property {@link FlatSystemProperties#USE_WINDOW_DECORATIONS} is set to
* {@code false}, then this method also returns {@code false}.

View File

@@ -34,7 +34,7 @@ public interface FlatSystemProperties
* To replace the Java 9+ system scale factor, use system property "sun.java2d.uiScale",
* which has the same syntax as this one.
* <p>
* Since FlatLaf 1.1.2: Scale factors less then 100% are allowed.
* Since FlatLaf 1.1.2: Scale factors less than 100% are allowed.
* <p>
* <strong>Allowed Values</strong> e.g. {@code 1.5}, {@code 1.5x}, {@code 150%} or {@code 144dpi} (96dpi is 100%)<br>
*/

View File

@@ -175,7 +175,7 @@ public class IntelliJTheme
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) );
// IDEA uses a SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
// IDEA uses an SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
if( helpButtonBackground == null )
@@ -242,7 +242,19 @@ public class IntelliJTheme
defaults.put( "Tree.rowHeight", 22 );
// apply theme specific UI defaults at the end to allow overwriting
defaults.putAll( themeSpecificDefaults );
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) {
Object key = e.getKey();
Object value = e.getValue();
// append styles to existing styles
if( key instanceof String && ((String)key).startsWith( "[style]" ) ) {
Object oldValue = defaults.get( key );
if( oldValue != null )
value = oldValue + "; " + value;
}
defaults.put( key, value );
}
}
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) {
@@ -534,12 +546,12 @@ public class IntelliJTheme
}
/** Rename UI default keys (key --> value). */
private static Map<String, String> uiKeyMapping = new HashMap<>();
private static final Map<String, String> uiKeyMapping = new HashMap<>();
/** Copy UI default keys (value --> key). */
private static Map<String, String> uiKeyCopying = new HashMap<>();
private static Map<String, String> uiKeyInverseMapping = new HashMap<>();
private static Map<String, String> checkboxKeyMapping = new HashMap<>();
private static Map<String, String> checkboxDuplicateColors = new HashMap<>();
private static final Map<String, String> uiKeyCopying = new HashMap<>();
private static final Map<String, String> uiKeyInverseMapping = new HashMap<>();
private static final Map<String, String> checkboxKeyMapping = new HashMap<>();
private static final Map<String, String> checkboxDuplicateColors = new HashMap<>();
static {
// ComboBox

View File

@@ -170,7 +170,7 @@ class LinuxFontPolicy
Object value = Toolkit.getDefaultToolkit().getDesktopProperty( "gnome.Xft/DPI" );
if( value instanceof Integer ) {
int dpi = ((Integer)value).intValue() / 1024;
int dpi = (Integer) value / 1024;
if( dpi == -1 )
dpi = 96;
if( dpi < 50 )
@@ -197,7 +197,7 @@ class LinuxFontPolicy
}
/**
* Gets the default font for KDE for KDE configuration files.
* Gets the default font for KDE from KDE configuration files.
*
* The Swing fonts are not updated when the user changes system font size
* (System Settings > Fonts > Force Font DPI). A application restart is necessary.
@@ -278,7 +278,7 @@ class LinuxFontPolicy
// read config file
ArrayList<String> lines = new ArrayList<>( 200 );
try( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
String line = null;
String line;
while( (line = reader.readLine()) != null )
lines.add( line );
} catch( IOException ex ) {

View File

@@ -0,0 +1,322 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* Improves usability of submenus by using a
* <a href="https://height.app/blog/guide-to-build-context-menus#safe-triangle">safe triangle</a>
* to avoid that the submenu closes while the user moves the mouse to it.
*
* @author Karl Tauber
*/
class SubMenuUsabilityHelper
implements ChangeListener
{
private static final String KEY_USE_SAFE_TRIANGLE = "Menu.useSafeTriangle";
private static final String KEY_SHOW_SAFE_TRIANGLE = "FlatLaf.debug.menu.showSafeTriangle";
private SubMenuEventQueue subMenuEventQueue;
private SafeTrianglePainter safeTrianglePainter;
private boolean changePending;
// mouse location in screen coordinates
private int mouseX;
private int mouseY;
// target popup bounds in screen coordinates
private int targetX;
private int targetTopY;
private int targetBottomY;
private Rectangle invokerBounds;
void install() {
MenuSelectionManager.defaultManager().addChangeListener( this );
}
void uninstall() {
MenuSelectionManager.defaultManager().removeChangeListener( this );
uninstallEventQueue();
}
@Override
public void stateChanged( ChangeEvent e ) {
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
return;
// handle menu selection change later, but only once in case of temporary changes
// e.g. moving mouse from one menu item to another one, fires two events:
// 1. old menu item is removed from menu selection
// 2. new menu item is added to menu selection
synchronized( this ) {
if( changePending )
return;
changePending = true;
}
EventQueue.invokeLater( () -> {
synchronized( this ) {
changePending = false;
}
menuSelectionChanged();
} );
}
private void menuSelectionChanged() {
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
/*debug
System.out.println( "--- " + path.length );
for( int i = 0; i < path.length; i++ )
System.out.println( " " + i + ": " + path[i].getClass().getName() );
debug*/
// find submenu in menu selection
int subMenuIndex = findSubMenu( path );
// uninstall if there is no submenu in selection
if( subMenuIndex < 0 || subMenuIndex != path.length - 1 ) {
uninstallEventQueue();
return;
}
// get current mouse location
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
Point mouseLocation = (pointerInfo != null) ? pointerInfo.getLocation() : new Point();
mouseX = mouseLocation.x;
mouseY = mouseLocation.y;
// check whether popup is showing, which is e.g. not the case if it is empty
JPopupMenu popup = (JPopupMenu) path[subMenuIndex];
if( !popup.isShowing() ) {
uninstallEventQueue();
return;
}
// get invoker screen bounds
Component invoker = popup.getInvoker();
invokerBounds = (invoker != null)
? new Rectangle( invoker.getLocationOnScreen(), invoker.getSize() )
: null;
// check whether mouse location is within invoker
if( invokerBounds != null && !invokerBounds.contains( mouseX, mouseY ) ) {
uninstallEventQueue();
return;
}
// compute top/bottom target locations
Point popupLocation = popup.getLocationOnScreen();
Dimension popupSize = popup.getSize();
targetX = (mouseX < popupLocation.x + (popupSize.width / 2))
? popupLocation.x
: popupLocation.x + popupSize.width;
targetTopY = popupLocation.y;
targetBottomY = popupLocation.y + popupSize.height;
// install own event queue to supress mouse events when mouse is moved within safe triangle
if( subMenuEventQueue == null )
subMenuEventQueue = new SubMenuEventQueue();
// create safe triangle painter
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
safeTrianglePainter = new SafeTrianglePainter( popup );
}
private void uninstallEventQueue() {
if( subMenuEventQueue != null ) {
subMenuEventQueue.uninstall();
subMenuEventQueue = null;
}
if( safeTrianglePainter != null ) {
safeTrianglePainter.uninstall();
safeTrianglePainter = null;
}
}
private int findSubMenu( MenuElement[] path ) {
for( int i = path.length - 1; i >= 1; i-- ) {
if( path[i] instanceof JPopupMenu &&
path[i - 1] instanceof JMenu &&
!((JMenu)path[i - 1]).isTopLevelMenu() )
return i;
}
return -1;
}
private Polygon createSafeTriangle() {
return new Polygon(
new int[] { mouseX, targetX, targetX },
new int[] { mouseY, targetTopY, targetBottomY },
3 );
}
//---- class SubMenuEventQueue --------------------------------------------
private class SubMenuEventQueue
extends EventQueue
{
private Timer mouseUpdateTimer;
private Timer timeoutTimer;
private int newMouseX;
private int newMouseY;
private AWTEvent lastMouseEvent;
SubMenuEventQueue() {
// timer used to slightly delay update of mouse location used for safe triangle
mouseUpdateTimer = new Timer( 50, e -> {
mouseX = newMouseX;
mouseY = newMouseY;
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
} );
mouseUpdateTimer.setRepeats( false );
// timer used to timeout safe triangle when mouse stops moving
timeoutTimer = new Timer( 200, e -> {
if( invokerBounds != null && !invokerBounds.contains( newMouseX, newMouseY ) ) {
// post last mouse event, which selects menu item at mouse location
if( lastMouseEvent != null ) {
postEvent( lastMouseEvent );
lastMouseEvent = null;
}
uninstallEventQueue();
return;
}
} );
timeoutTimer.setRepeats( false );
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
}
void uninstall() {
mouseUpdateTimer.stop();
mouseUpdateTimer = null;
timeoutTimer.stop();
timeoutTimer = null;
lastMouseEvent = null;
super.pop();
}
@Override
protected void dispatchEvent( AWTEvent e ) {
int id = e.getID();
if( e instanceof MouseEvent &&
(id == MouseEvent.MOUSE_MOVED || id == MouseEvent.MOUSE_DRAGGED) )
{
newMouseX = ((MouseEvent)e).getXOnScreen();
newMouseY = ((MouseEvent)e).getYOnScreen();
if( safeTrianglePainter != null )
safeTrianglePainter.repaint();
mouseUpdateTimer.stop();
timeoutTimer.stop();
// check whether mouse moved within safe triangle
if( createSafeTriangle().contains( newMouseX, newMouseY ) ) {
// update mouse location delayed (this changes the safe triangle)
mouseUpdateTimer.start();
timeoutTimer.start();
// remember last mouse event, which will be posted if the mouse stops moving
lastMouseEvent = e;
// ignore mouse event
return;
}
// update mouse location immediately (this changes the safe triangle)
mouseX = newMouseX;
mouseY = newMouseY;
}
super.dispatchEvent( e );
}
}
//---- class SafeTrianglePainter ------------------------------------------
private class SafeTrianglePainter
extends JComponent
{
SafeTrianglePainter( JPopupMenu popup ) {
Window window = SwingUtilities.windowForComponent( popup.getInvoker() );
if( window instanceof RootPaneContainer ) {
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
setSize( layeredPane.getSize() );
layeredPane.add( this, new Integer( JLayeredPane.POPUP_LAYER + 1 ) );
}
}
void uninstall() {
Container parent = getParent();
if( parent != null ) {
parent.remove( this );
parent.repaint();
}
}
@Override
protected void paintComponent( Graphics g ) {
Point locationOnScreen = getLocationOnScreen();
g.translate( -locationOnScreen.x, -locationOnScreen.y );
g.setColor( Color.red );
((Graphics2D)g).draw( createSafeTriangle() );
}
}
}

View File

@@ -350,7 +350,7 @@ class UIDefaultsLoader
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, INTEGERORFLOAT, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, FONT,
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
private static ValueType[] tempResultValueType = new ValueType[1];
private static final ValueType[] tempResultValueType = new ValueType[1];
private static Map<Class<?>, ValueType> javaValueTypes;
private static Map<String, ValueType> knownValueTypes;
@@ -792,7 +792,7 @@ class UIDefaultsLoader
* Syntax: if(condition,trueValue,falseValue)
* <p>
* This "if" function is only used if the "if" is passed as parameter to another
* color function. Otherwise the general "if" function is used.
* color function. Otherwise, the general "if" function is used.
*/
private static Object parseColorIf( String value, List<String> params, Function<String, String> resolver, boolean reportError ) {
if( params.size() != 3 )
@@ -1209,7 +1209,7 @@ class UIDefaultsLoader
}
Integer integer = parseInteger( value, true );
if( integer.intValue() < min || integer.intValue() > max )
if( integer < min || integer > max )
throw new NumberFormatException( "integer '" + value + "' out of range (" + min + '-' + max + ')' );
return integer;
}
@@ -1250,28 +1250,28 @@ class UIDefaultsLoader
private static ActiveValue parseScaledInteger( String value ) {
int val = parseInteger( value, true );
return (ActiveValue) t -> {
return t -> {
return UIScale.scale( val );
};
}
private static ActiveValue parseScaledFloat( String value ) {
float val = parseFloat( value, true );
return (ActiveValue) t -> {
return t -> {
return UIScale.scale( val );
};
}
private static ActiveValue parseScaledInsets( String value ) {
Insets insets = parseInsets( value );
return (ActiveValue) t -> {
return t -> {
return UIScale.scale( insets );
};
}
private static ActiveValue parseScaledDimension( String value ) {
Dimension dimension = parseDimension( value );
return (ActiveValue) t -> {
return t -> {
return UIScale.scale( dimension );
};
}

View File

@@ -23,13 +23,13 @@ import java.awt.Graphics2D;
import com.formdev.flatlaf.util.AnimatedIcon;
/**
* Base class for animated icons that scales width and height, creates and initializes
* Base class for animated icons that scale width and height, creates and initializes
* a scaled graphics context for icon painting.
* <p>
* Subclasses do not need to scale icon painting.
* <p>
* This class does not store any state information (needed for animation) in its instance.
* Instead a client property is set on the painted component.
* Instead, a client property is set on the painted component.
* This makes it possible to use a share icon instance for multiple components.
*
* @author Karl Tauber

View File

@@ -51,7 +51,7 @@ public class FlatAscendingSortIcon
boolean chevron = this.chevron;
Color sortIconColor = this.sortIconColor;
// Because this icons are always shared for all table headers,
// Because this icon is always shared for all table headers,
// get icon specific style from FlatTableHeaderUI.
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
if( tableHeader != null ) {

View File

@@ -96,8 +96,8 @@ public class FlatHelpButtonIcon
</svg>
*/
boolean enabled = c.isEnabled();
boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
boolean enabled = c == null || c.isEnabled();
boolean focused = c != null && FlatUIUtils.isPermanentFocusOwner( c );
float xy = 0.5f;
float wh = iconSize() - 1;

View File

@@ -63,7 +63,7 @@ public class FlatMenuArrowIcon
@Override
protected void paintIcon( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() )
if( c != null && !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.setColor( getArrowColor( c ) );
@@ -82,7 +82,7 @@ public class FlatMenuArrowIcon
if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
return selectionForeground;
return c.isEnabled() ? arrowColor : disabledArrowColor;
return c == null || c.isEnabled() ? arrowColor : disabledArrowColor;
}
protected boolean isUnderlineSelection() {

View File

@@ -76,7 +76,7 @@ public class FlatTreeCollapsedIcon
}
/**
* Because this icons are always shared for all trees,
* Because this icon is always shared for all trees,
* get icon specific style from FlatTreeUI.
*/
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {

View File

@@ -18,8 +18,8 @@ package com.formdev.flatlaf.resources;
/**
* The only purpose of this file is to add a .class file to this package to make it non-empty.
* Otherwise the compiler outputs a warning because this package is opend in module-info.java.
* Also when using --patch-module (e.g. from an IDE), an error would occur for empty packages.
* Otherwise, the compiler outputs a warning because this package is opened in module-info.java.
* Also, when using --patch-module (e.g. from an IDE), an error would occur for empty packages.
*
* @author Karl Tauber
*/

View File

@@ -37,7 +37,7 @@ public class FlatArrowButton
extends BasicArrowButton
implements UIResource
{
public static final int DEFAULT_ARROW_WIDTH = 8;
public static final int DEFAULT_ARROW_WIDTH = 9;
protected boolean chevron;
protected Color foreground;
@@ -211,6 +211,6 @@ public class FlatArrowButton
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 );
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, arrowWidth, xOffset, yOffset );
FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() );
}
}

View File

@@ -159,7 +159,7 @@ public class FlatButtonBorder
public Insets getBorderInsets( Component c, Insets insets ) {
if( FlatButtonUI.isToolBarButton( c ) ) {
// In toolbars, use button margin only if explicitly set.
// Otherwise use toolbar margin specified in UI defaults.
// Otherwise, use toolbar margin specified in UI defaults.
Insets margin = (c instanceof AbstractButton)
? ((AbstractButton)c).getMargin()
: null;

View File

@@ -262,6 +262,10 @@ public class FlatButtonUI
b.repaint();
break;
case OUTLINE:
b.repaint();
break;
case STYLE:
case STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
@@ -339,7 +343,7 @@ public class FlatButtonUI
/**
* Returns true if the button has an icon but no text,
* or it it does not have an icon and the text is either "..." or one character.
* or it does not have an icon and the text is either "..." or one character.
*/
static boolean isIconOnlyOrSingleCharacterButton( Component c ) {
if( !(c instanceof JButton) && !(c instanceof JToggleButton) )
@@ -569,6 +573,9 @@ public class FlatButtonUI
public static Color buttonStateColor( Component c, Color enabledColor, Color disabledColor,
Color focusedColor, Color hoverColor, Color pressedColor )
{
if( c == null )
return enabledColor;
if( !c.isEnabled() )
return disabledColor;

View File

@@ -96,7 +96,7 @@ public class FlatCaret
// if text component is focused, then caret and selection are visible,
// but when switching theme, the component does not yet have
// an highlighter and the selection is not painted
// a highlighter and the selection is not painted
// --> make selection temporary invisible later, then the caret
// adds selection highlights to the text component highlighter
if( isSelectionVisible() ) {
@@ -236,7 +236,7 @@ public class FlatCaret
if( selectAllOnFocusPolicy == null )
selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
if( SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
if( selectAllOnFocusPolicy == null || SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
return;
if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {

View File

@@ -354,6 +354,7 @@ public class FlatComboBoxUI
break;
case COMPONENT_ROUND_RECT:
case OUTLINE:
comboBox.repaint();
break;
@@ -699,7 +700,7 @@ public class FlatComboBoxUI
return true;
Component editorComponent = comboBox.getEditor().getEditorComponent();
return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false;
return editorComponent != null && FlatUIUtils.isPermanentFocusOwner( editorComponent );
} else
return FlatUIUtils.isPermanentFocusOwner( comboBox );
}

View File

@@ -72,7 +72,7 @@ public class FlatListCellBorder
}
/**
* Because this borders are always shared for all lists,
* Because this border is always shared for all lists,
* get border specific style from FlatListUI.
*/
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {

View File

@@ -212,7 +212,7 @@ public class FlatListUI
/**
* Toggle selection colors from focused to inactive and vice versa.
*
* This is not a optimal solution but much easier than rewriting the whole paint methods.
* This is not an optimal solution but much easier than rewriting the whole paint methods.
*
* Using a LaF specific renderer was avoided because often a custom renderer is
* already used in applications. Then either the inactive colors are not used,

View File

@@ -210,7 +210,7 @@ public class FlatMenuBarUI
// check whether:
// - TitlePane.unifiedBackground is true and
// - menu bar is the "main" menu bar and
// - window has custom decorations enabled
// - window root pane has custom decoration style
JRootPane rootPane;
// (not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime)
@@ -218,7 +218,7 @@ public class FlatMenuBarUI
(rootPane = SwingUtilities.getRootPane( c )) != null &&
rootPane.getParent() instanceof Window &&
rootPane.getJMenuBar() == c &&
FlatNativeWindowBorder.hasCustomDecoration( (Window) rootPane.getParent() );
rootPane.getWindowDecorationStyle() != JRootPane.NONE;
}
//---- class TakeFocus ----------------------------------------------------

View File

@@ -35,7 +35,7 @@ import javax.swing.plaf.MenuBarUI;
public class FlatMenuItemBorder
extends FlatMarginBorder
{
// only used if parent menubar is not a instance of FlatMenuBarUI
// only used if parent menubar is not an instance of FlatMenuBarUI
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
@Override

View File

@@ -18,12 +18,14 @@ package com.formdev.flatlaf.ui;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPanelUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -43,13 +45,12 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatPanelUI
extends BasicPanelUI
implements StyleableUI
implements StyleableUI, PropertyChangeListener
{
// only used via styling (not in UI defaults)
/** @since 2 */ @Styleable protected int arc = -1;
private final boolean shared;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
@@ -67,9 +68,7 @@ public class FlatPanelUI
public void installUI( JComponent c ) {
super.installUI( c );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
c, () -> stylePropertyChange( (JPanel) c ), null );
c.addPropertyChangeListener( propertyChangeListener );
c.addPropertyChangeListener( this );
installStyle( (JPanel) c );
}
@@ -78,21 +77,28 @@ public class FlatPanelUI
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
c.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
c.removePropertyChangeListener( this );
oldStyleValues = null;
}
private void stylePropertyChange( JPanel c ) {
if( shared && FlatStylingSupport.hasStyleProperty( c ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
c.updateUI();
} else
installStyle( c );
c.revalidate();
c.repaint();
/** @since 2.0.1 */
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
JPanel c = (JPanel) e.getSource();
if( shared && FlatStylingSupport.hasStyleProperty( c ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
c.updateUI();
} else
installStyle( c );
c.revalidate();
c.repaint();
break;
}
}
/** @since 2 */

View File

@@ -16,10 +16,12 @@
package com.formdev.flatlaf.ui;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
@@ -33,6 +35,7 @@ import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JComponent;
@@ -140,7 +143,7 @@ public class FlatPopupFactory
* <p>
* On a dual screen setup, where screens use different scale factors, it may happen
* that the window location changes when showing a heavy weight popup window.
* E.g. when opening an dialog on the secondary screen and making combobox popup visible.
* E.g. when opening a dialog on the secondary screen and making combobox popup visible.
* <p>
* This is a workaround for https://bugs.openjdk.java.net/browse/JDK-8224608
*/
@@ -219,7 +222,7 @@ public class FlatPopupFactory
* and corrects the y-location so that the tooltip is placed above the mouse location.
*/
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() || hasTipLocation( owner ) )
return null;
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
@@ -264,6 +267,35 @@ public class FlatPopupFactory
return StackUtils.wasInvokedFrom( ToolTipManager.class.getName(), "showTipWindow", 8 );
}
/**
* Checks whether the owner component returns a tooltip location in
* JComponent.getToolTipLocation(MouseEvent).
*/
private boolean hasTipLocation( Component owner ) {
if( !(owner instanceof JComponent) )
return false;
AWTEvent e = EventQueue.getCurrentEvent();
MouseEvent me;
if( e instanceof MouseEvent )
me = (MouseEvent) e;
else {
// no mouse event available because a timer is used to show the tooltip
// --> create mouse event from current mouse location
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
if( pointerInfo == null )
return false;
Point location = new Point( pointerInfo.getLocation());
SwingUtilities.convertPointFromScreen( location, owner );
me = new MouseEvent( owner, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(),
0, location.x, location.y, 0, false );
}
return me.getSource() == owner &&
((JComponent)owner).getToolTipLocation( me ) != null;
}
//---- class NonFlashingPopup ---------------------------------------------
private class NonFlashingPopup

View File

@@ -16,18 +16,58 @@
package com.formdev.flatlaf.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.BasicMenuItemUI;
import javax.swing.plaf.basic.BasicPopupMenuUI;
import javax.swing.plaf.basic.DefaultMenuLayout;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -41,12 +81,22 @@ import com.formdev.flatlaf.util.LoggingFacade;
* @uiDefault PopupMenu.foreground Color
* @uiDefault PopupMenu.border Border
*
* <!-- FlatPopupMenuUI -->
*
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault PopupMenu.scrollArrowColor Color
* @uiDefault PopupMenu.hoverScrollArrowBackground Color optional
*
* @author Karl Tauber
*/
public class FlatPopupMenuUI
extends BasicPopupMenuUI
implements StyleableUI
{
/** @since 2.1 */ @Styleable protected String arrowType;
/** @since 2.1 */ @Styleable protected Color scrollArrowColor;
/** @since 2.1 */ @Styleable protected Color hoverScrollArrowBackground;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
@@ -74,11 +124,23 @@ public class FlatPopupMenuUI
public void installDefaults() {
super.installDefaults();
arrowType = UIManager.getString( "Component.arrowType" );
scrollArrowColor = UIManager.getColor( "PopupMenu.scrollArrowColor" );
hoverScrollArrowBackground = UIManager.getColor( "PopupMenu.hoverScrollArrowBackground" );
LayoutManager layout = popupMenu.getLayout();
if( layout == null || layout instanceof UIResource )
popupMenu.setLayout( new FlatMenuLayout( popupMenu, BoxLayout.Y_AXIS ) );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
scrollArrowColor = null;
hoverScrollArrowBackground = null;
}
@Override
protected void installListeners() {
super.installListeners();
@@ -122,6 +184,52 @@ public class FlatPopupMenuUI
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
}
@Override
public Popup getPopup( JPopupMenu popup, int x, int y ) {
// do not add scroller to combobox popups or to popups that already have a scroll pane
if( popup instanceof BasicComboPopup ||
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
return super.getPopup( popup, x, y );
// do not add scroller if popup fits into screen
Dimension prefSize = popup.getPreferredSize();
int screenHeight = getScreenHeightAt( x, y );
if( prefSize.height <= screenHeight )
return super.getPopup( popup, x, y );
// create scroller
FlatPopupScroller scroller = new FlatPopupScroller( popup );
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
// create popup
PopupFactory popupFactory = PopupFactory.getSharedInstance();
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
}
private int getScreenHeightAt( int x, int y ) {
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
GraphicsConfiguration gc = null;
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
if( device.getType() == GraphicsDevice.TYPE_RASTER_SCREEN ) {
GraphicsConfiguration dgc = device.getDefaultConfiguration();
if( dgc.getBounds().contains( x, y ) ) {
gc = dgc;
break;
}
}
}
if( gc == null && popupMenu.getInvoker() != null )
gc = popupMenu.getInvoker().getGraphicsConfiguration();
// compute screen height
// (always subtract screen insets because there is no API to detect whether
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
Toolkit toolkit = Toolkit.getDefaultToolkit();
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
return screenBounds.height - screenInsets.top - screenInsets.bottom;
}
//---- class FlatMenuLayout -----------------------------------------------
protected static class FlatMenuLayout
@@ -138,4 +246,206 @@ public class FlatPopupMenuUI
return super.preferredLayoutSize( target );
}
}
//---- class FlatPopupScroller --------------------------------------------
private class FlatPopupScroller
extends JPanel
implements MouseWheelListener, PopupMenuListener, MenuKeyListener
{
private final JPopupMenu popup;
private final JScrollPane scrollPane;
private final JButton scrollUpButton;
private final JButton scrollDownButton;
private int unitIncrement;
FlatPopupScroller( JPopupMenu popup ) {
super( new BorderLayout() );
this.popup = popup;
// this panel is required to avoid that JPopupMenu.setLocation() will be invoked
// while scrolling, because this would call JPopupMenu.showPopup()
JPanel view = new JPanel( new BorderLayout() );
view.add( popup, BorderLayout.CENTER );
scrollPane = new JScrollPane( view, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
scrollPane.setBorder( null );
scrollUpButton = new ArrowButton( SwingConstants.NORTH );
scrollDownButton = new ArrowButton( SwingConstants.SOUTH );
add( scrollPane, BorderLayout.CENTER );
add( scrollUpButton, BorderLayout.NORTH );
add( scrollDownButton, BorderLayout.SOUTH );
setBackground( popup.getBackground() );
setBorder( popup.getBorder() );
popup.setBorder( null );
popup.addPopupMenuListener( this );
popup.addMouseWheelListener( this );
popup.addMenuKeyListener( this );
updateArrowButtons();
}
void scroll( int unitsToScroll ) {
if( unitIncrement == 0 )
unitIncrement = new JMenuItem( "X" ).getPreferredSize().height;
JViewport viewport = scrollPane.getViewport();
Point viewPosition = viewport.getViewPosition();
int newY = viewPosition.y + (unitIncrement * unitsToScroll);
if( newY < 0 )
newY = 0;
else
newY = Math.min( newY, viewport.getViewSize().height - viewport.getExtentSize().height );
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
updateArrowButtons();
}
void updateArrowButtons() {
JViewport viewport = scrollPane.getViewport();
Point viewPosition = viewport.getViewPosition();
scrollUpButton.setVisible( viewPosition.y > 0 );
scrollDownButton.setVisible( viewPosition.y < viewport.getViewSize().height - viewport.getExtentSize().height );
}
//---- interface PopupMenuListener ----
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
// restore popup border
popup.setBorder( getBorder() );
popup.removePopupMenuListener( this );
popup.removeMouseWheelListener( this );
popup.removeMenuKeyListener( this );
}
@Override public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {}
@Override public void popupMenuCanceled( PopupMenuEvent e ) {}
//---- interface MouseWheelListener ----
/**
* Scroll when user rotates mouse wheel.
*/
@Override
public void mouseWheelMoved( MouseWheelEvent e ) {
// convert mouse location before scrolling
Point mouseLocation = SwingUtilities.convertPoint( (Component) e.getSource(), e.getPoint(), this );
// scroll
scroll( e.getUnitsToScroll() );
// select menu item at mouse location
Component c = SwingUtilities.getDeepestComponentAt( this, mouseLocation.x, mouseLocation.y );
if( c instanceof JMenuItem ) {
ButtonUI ui = ((JMenuItem)c).getUI();
if( ui instanceof BasicMenuItemUI )
MenuSelectionManager.defaultManager().setSelectedPath( ((BasicMenuItemUI)ui).getPath() );
}
// this avoids that the popup is closed when running on Java 8
// https://bugs.openjdk.java.net/browse/JDK-8075063
e.consume();
}
//---- interface MenuKeyListener ----
/**
* Scroll when user presses Up or Down keys.
*/
@Override
public void menuKeyPressed( MenuKeyEvent e ) {
// use invokeLater() because menu selection is not yet updated because
// this listener is invoked before another listener that updates the menu selection
EventQueue.invokeLater( () -> {
if( !isDisplayable() )
return;
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
if( path.length == 0 )
return;
// scroll selected menu item to visible area
Component c = path[path.length - 1].getComponent();
JViewport viewport = scrollPane.getViewport();
Point pt = SwingUtilities.convertPoint( c, 0, 0, viewport );
viewport.scrollRectToVisible( new Rectangle( pt, c.getSize() ) );
// update arrow buttons
boolean upVisible = scrollUpButton.isVisible();
updateArrowButtons();
if( !upVisible && scrollUpButton.isVisible() ) {
// if "up" button becomes visible, make sure that bottom menu item stays visible
Point viewPosition = viewport.getViewPosition();
int newY = viewPosition.y + scrollUpButton.getPreferredSize().height;
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
}
} );
}
@Override public void menuKeyTyped( MenuKeyEvent e ) {}
@Override public void menuKeyReleased( MenuKeyEvent e ) {}
//---- class ArrowButton ----------------------------------------------
private class ArrowButton
extends FlatArrowButton
implements MouseListener, ActionListener
{
private Timer timer;
ArrowButton( int direction ) {
super( direction, arrowType, scrollArrowColor, null, null, hoverScrollArrowBackground, null, null );
addMouseListener( this );
}
@Override
public void paint( Graphics g ) {
// always fill background to paint over border on HiDPI screens
g.setColor( popup.getBackground() );
g.fillRect( 0, 0, getWidth(), getHeight() );
super.paint( g );
}
//---- interface MouseListener ----
@Override public void mouseClicked( MouseEvent e ) {}
@Override public void mousePressed( MouseEvent e ) {}
@Override public void mouseReleased( MouseEvent e ) {}
@Override
public void mouseEntered( MouseEvent e ) {
if( timer == null )
timer = new Timer( 50, this );
timer.start();
}
@Override
public void mouseExited( MouseEvent e ) {
if( timer != null )
timer.stop();
}
//---- interface ActionListener ----
@Override
public void actionPerformed( ActionEvent e ) {
if( timer != null && !isDisplayable() ) {
timer.stop();
return;
}
scroll( direction == SwingConstants.NORTH ? -1 : 1 );
}
}
}
}

View File

@@ -199,7 +199,7 @@ public class FlatRadioButtonUI
return infos;
}
private static Insets tempInsets = new Insets( 0, 0, 0, 0 );
private static final Insets tempInsets = new Insets( 0, 0, 0, 0 );
@Override
public Dimension getPreferredSize( JComponent c ) {
@@ -212,7 +212,7 @@ public class FlatRadioButtonUI
if( focusWidth > 0 ) {
// Increase preferred width and height if insets were explicitly reduced (e.g. with
// an EmptyBorder) and icon has a focus width, which is not included in icon size.
// Otherwise the component may be too small and outer focus border may be cut off.
// Otherwise, the component may be too small and outer focus border may be cut off.
Insets insets = c.getInsets( tempInsets );
size.width += Math.max( focusWidth - insets.left, 0 ) + Math.max( focusWidth - insets.right, 0 );
size.height += Math.max( focusWidth - insets.top, 0 ) + Math.max( focusWidth - insets.bottom, 0 );

View File

@@ -179,8 +179,8 @@ public class FlatRootPaneUI
super.installListeners( root );
if( SystemInfo.isJava_9_orLater ) {
// On HiDPI screens, where scaling is used, there may be white lines at the
// bottom and at the right side of the window when it is initially shown.
// On HiDPI screens, where scaling is used, there may be white lines on the
// bottom and on the right side of the window when it is initially shown.
// This is very disturbing in dark themes, but hard to notice in light themes.
// Seems to be a rounding issue when Swing adds dirty region of window
// using RepaintManager.nativeAddDirtyRegion().
@@ -510,7 +510,7 @@ public class FlatRootPaneUI
return;
Container parent = c.getParent();
boolean active = parent instanceof Window ? ((Window)parent).isActive() : false;
boolean active = parent instanceof Window && ((Window)parent).isActive();
g.setColor( FlatUIUtils.deriveColor( active ? activeBorderColor : inactiveBorderColor, baseBorderColor ) );
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, this::paintImpl );
@@ -522,9 +522,7 @@ public class FlatRootPaneUI
protected boolean isWindowMaximized( Component c ) {
Container parent = c.getParent();
return parent instanceof Frame
? (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
: false;
return parent instanceof Frame && (((Frame)parent).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
}
}

View File

@@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
*
* <!-- FlatScrollBarUI -->
*
* @uiDefault ScrollBar.minimumButtonSize Dimension
* @uiDefault ScrollBar.trackInsets Insets
* @uiDefault ScrollBar.thumbInsets Insets
* @uiDefault ScrollBar.trackArc int
@@ -83,6 +84,7 @@ public class FlatScrollBarUI
// overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
@Styleable protected boolean allowsAbsolutePositioning;
/** @since 2.1 */ @Styleable protected Dimension minimumButtonSize;
@Styleable protected Insets trackInsets;
@Styleable protected Insets thumbInsets;
@Styleable protected int trackArc;
@@ -142,6 +144,7 @@ public class FlatScrollBarUI
allowsAbsolutePositioning = super.getSupportsAbsolutePositioning();
minimumButtonSize = UIManager.getDimension( "ScrollBar.minimumButtonSize" );
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
trackArc = UIManager.getInt( "ScrollBar.trackArc" );
@@ -171,6 +174,7 @@ public class FlatScrollBarUI
protected void uninstallDefaults() {
super.uninstallDefaults();
minimumButtonSize = null;
trackInsets = null;
thumbInsets = null;
hoverTrackColor = null;
@@ -451,7 +455,6 @@ public class FlatScrollBarUI
super( direction, type, foreground, disabledForeground,
hoverForeground, hoverBackground, pressedForeground, pressedBackground );
setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
setFocusable( false );
setRequestFocusEnabled( false );
}
@@ -461,6 +464,18 @@ public class FlatScrollBarUI
null, hoverButtonBackground, null, pressedButtonBackground );
}
@Override
public int getArrowWidth() {
// scale arrow size depending on scroll bar width
// (6 is default arrow width; 10 is base scroll bar width)
int arrowWidth = Math.round( 6 * (scrollBarWidth / 10f) );
// compute arrow size that leaves equal space on both sides (arrow is centered)
arrowWidth = scrollBarWidth - (((scrollBarWidth - arrowWidth) / 2) * 2);
return arrowWidth;
}
@Override
protected Color deriveBackground( Color background ) {
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
@@ -469,8 +484,9 @@ public class FlatScrollBarUI
@Override
public Dimension getPreferredSize() {
if( isShowButtons() ) {
int w = UIScale.scale( scrollBarWidth );
return new Dimension( w, w );
int w = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.width : 0 ) );
int h = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.height : 0 ) );
return new Dimension( w, h );
} else
return new Dimension();
}

View File

@@ -291,6 +291,10 @@ public class FlatScrollPaneUI
}
break;
case FlatClientProperties.OUTLINE:
scrollpane.repaint();
break;
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
installStyle();

View File

@@ -21,6 +21,7 @@ import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
@@ -28,6 +29,7 @@ import javax.swing.JSeparator;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSeparatorUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -50,7 +52,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
*/
public class FlatSeparatorUI
extends BasicSeparatorUI
implements StyleableUI
implements StyleableUI, PropertyChangeListener
{
@Styleable protected int height;
@Styleable protected int stripeWidth;
@@ -58,7 +60,6 @@ public class FlatSeparatorUI
private final boolean shared;
private boolean defaults_initialized = false;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
@@ -109,28 +110,33 @@ public class FlatSeparatorUI
protected void installListeners( JSeparator s ) {
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, () -> stylePropertyChange( s ), null );
s.addPropertyChangeListener( propertyChangeListener );
s.addPropertyChangeListener( this );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
s.removePropertyChangeListener( this );
}
private void stylePropertyChange( JSeparator s ) {
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
s.updateUI();
} else
installStyle( s );
s.revalidate();
s.repaint();
/** @since 2.0.1 */
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
JSeparator s = (JSeparator) e.getSource();
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
s.updateUI();
} else
installStyle( s );
s.revalidate();
s.repaint();
break;
}
}
/** @since 2 */

View File

@@ -234,7 +234,7 @@ public class FlatSliderUI
return -1;
// use default font (instead of slider font) because the slider font size
// may be different to label font size, but we want align the track/thumb with labels
// may be different to label font size, but we want to align the track/thumb with labels
Font font = UIManager.getFont( "defaultFont" );
if( font == null )
font = slider.getFont();

View File

@@ -293,9 +293,7 @@ public class FlatSpinnerUI
return true;
JTextField textField = getEditorTextField( spinner.getEditor() );
return (textField != null)
? FlatUIUtils.isPermanentFocusOwner( textField )
: false;
return textField != null && FlatUIUtils.isPermanentFocusOwner( textField );
}
protected Color getBackground( boolean enabled ) {
@@ -447,7 +445,7 @@ public class FlatSpinnerUI
Insets padding = scale( FlatSpinnerUI.this.padding );
Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 );
// the arrows width is the same as the inner height so that the arrows area is square
// the arrow buttons width is the same as the inner height so that the arrow buttons area is square
int minimumWidth = FlatUIUtils.minimumWidth( spinner, FlatSpinnerUI.this.minimumWidth );
int innerHeight = editorSize.height + padding.top + padding.bottom;
float focusWidth = FlatUIUtils.getBorderFocusWidth( spinner );
@@ -538,6 +536,7 @@ public class FlatSpinnerUI
break;
case FlatClientProperties.COMPONENT_ROUND_RECT:
case FlatClientProperties.OUTLINE:
spinner.repaint();
break;

View File

@@ -359,7 +359,7 @@ public class FlatStylingSupport
* @param key the name of the field
* @param value the new value
* @return the old value of the field
* @throws UnknownStyleException if object does not have a annotated field with given name
* @throws UnknownStyleException if object does not have an annotated field with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
public static Object applyToAnnotatedObject( Object obj, String key, Object value )
@@ -517,7 +517,7 @@ public class FlatStylingSupport
* @param key the name of the field
* @param value the new value
* @return the old value of the field
* @throws UnknownStyleException if object does not have a annotated field with given name
* @throws UnknownStyleException if object does not have an annotated field with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
public static Object applyToAnnotatedObjectOrComponent( Object obj, Object comp, String key, Object value )

View File

@@ -650,7 +650,7 @@ public class FlatTabbedPaneUI
case "tabIconPlacement": value = parseTabIconPlacement( (String) value ); break;
}
} else {
Object oldValue = null;
Object oldValue;
switch( key ) {
// BasicTabbedPaneUI
case "tabInsets": oldValue = tabInsets; tabInsets = (Insets) value; return oldValue;
@@ -1841,7 +1841,7 @@ public class FlatTabbedPaneUI
super( direction, arrowType,
FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground,
null, buttonHoverBackground, null, buttonPressedBackground );
setArrowWidth( 10 );
setArrowWidth( 11 );
}
protected void updateStyle() {
@@ -1983,7 +1983,7 @@ public class FlatTabbedPaneUI
}
protected JMenuItem createTabMenuItem( int tabIndex ) {
// search for tab name in this places
// search for tab name in these places
// 1. tab title
// 2. text of label or text component in custom tab component (including children)
// 3. accessible name of tab
@@ -2016,7 +2016,7 @@ public class FlatTabbedPaneUI
menuItem.setOpaque( true );
}
if( !tabPane.isEnabledAt( tabIndex ) )
if( !tabPane.isEnabled() || !tabPane.isEnabledAt( tabIndex ) )
menuItem.setEnabled( false );
menuItem.addActionListener( e -> selectTab( tabIndex ) );
@@ -2412,7 +2412,7 @@ public class FlatTabbedPaneUI
if( tabPane == null || tabViewport == null )
return;
if( !scrolled || tabViewport == null )
if( !scrolled )
return;
scrolled = false;
@@ -2525,9 +2525,7 @@ public class FlatTabbedPaneUI
setRolloverTab( tabIndex );
// check whether mouse hit tab close area
boolean hitClose = isTabClosable( tabIndex )
? getTabCloseHitArea( tabIndex ).contains( x, y )
: false;
boolean hitClose = isTabClosable( tabIndex ) && getTabCloseHitArea( tabIndex ).contains( x, y );
if( e.getID() == MouseEvent.MOUSE_PRESSED )
pressedTabIndex = hitClose ? tabIndex : -1;
setRolloverTabClose( hitClose );
@@ -2550,8 +2548,7 @@ public class FlatTabbedPaneUI
if( tabIndex == lastTipTabIndex )
return; // closeTip already set
if( tabIndex != lastTipTabIndex )
restoreTabToolTip();
restoreTabToolTip();
lastTipTabIndex = tabIndex;
lastTip = tabPane.getToolTipTextAt( lastTipTabIndex );

View File

@@ -72,7 +72,7 @@ public class FlatTableCellBorder
}
/**
* Because this borders are always shared for all tables,
* Because this border is always shared for all tables,
* get border specific style from FlatTableUI.
*/
static <T> T getStyleFromTableUI( Component c, Function<FlatTableUI, T> f ) {

View File

@@ -288,7 +288,7 @@ public class FlatTableUI
/**
* Toggle selection colors from focused to inactive and vice versa.
*
* This is not a optimal solution but much easier than rewriting the whole paint methods.
* This is not an optimal solution but much easier than rewriting the whole paint methods.
*
* Using a LaF specific renderer was avoided because often a custom renderer is
* already used in applications. Then either the inactive colors are not used,

View File

@@ -232,6 +232,7 @@ public class FlatTextFieldUI
switch( e.getPropertyName() ) {
case PLACEHOLDER_TEXT:
case COMPONENT_ROUND_RECT:
case OUTLINE:
case TEXT_FIELD_PADDING:
c.repaint();
break;
@@ -368,7 +369,7 @@ public class FlatTextFieldUI
if( !(oldBackground instanceof UIResource) )
return;
// do not update background if it currently has a unknown color (assigned from outside)
// do not update background if it currently has an unknown color (assigned from outside)
if( oldBackground != background &&
oldBackground != disabledBackground &&
oldBackground != inactiveBackground &&
@@ -609,7 +610,7 @@ debug*/
* Returns the rectangle used to paint leading and trailing icons.
* It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
* right margin if the text field has leading or trailing icons or components.
* Also the preferred widths of leading and trailing components are removed.
* Also, the preferred widths of leading and trailing components are removed.
*
* @since 2
*/

View File

@@ -248,7 +248,7 @@ public class FlatTitlePane
if( rootPane.getWindowDecorationStyle() == JRootPane.FRAME ) {
// JRootPane.FRAME works only for frames (and not for dialogs)
// but at this time the owner window type is unknown (not yet added)
// so we add the iconify/maximize/restore buttons and they are shown
// so we add the iconify/maximize/restore buttons, and they are shown
// later in frameStateChanged(), which is invoked from addNotify()
buttonPanel.add( iconifyButton );
@@ -420,7 +420,7 @@ public class FlatTitlePane
}
/**
* Returns whether this title pane currently has an visible and embedded menubar.
* Returns whether this title pane currently has a visible and embedded menubar.
*/
protected boolean hasVisibleEmbeddedMenuBar( JMenuBar menuBar ) {
return menuBar != null && menuBar.isVisible() && isMenuBarEmbedded();
@@ -615,7 +615,7 @@ debug*/
int maximizedWidth = screenBounds.width;
int maximizedHeight = screenBounds.height;
if( !isMaximizedBoundsFixed() ) {
if( SystemInfo.isWindows && !isMaximizedBoundsFixed() ) {
// on Java 8 to 14, maximized x,y are 0,0 based on all screens in a multi-screen environment
maximizedX = 0;
maximizedY = 0;
@@ -772,7 +772,7 @@ debug*/
if( horizontalGlue != null ) {
// If menu bar is embedded and contains a horizontal glue component,
// then split the hit test spot into two spots so that
// the glue component area can used to move the window.
// the glue component area can be used to move the window.
Point glueLocation = SwingUtilities.convertPoint( horizontalGlue, 0, 0, window );
int x2 = glueLocation.x + horizontalGlue.getWidth();
@@ -883,9 +883,7 @@ debug*/
}
protected boolean isWindowMaximized( Component c ) {
return window instanceof Frame
? (((Frame)window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0
: false;
return window instanceof Frame && (((Frame) window).getExtendedState() & Frame.MAXIMIZED_BOTH) != 0;
}
}
@@ -911,7 +909,7 @@ debug*/
boolean center = hasEmbeddedMenuBar ? centerTitleIfMenuBarEmbedded : centerTitle;
if( center ) {
// If window is wide enough, center title within window bounds.
// Otherwise leave it centered within free space (label bounds).
// Otherwise, leave it centered within free space (label bounds).
int centeredTextX = ((l.getParent().getWidth() - textWidth) / 2) - l.getX();
if( centeredTextX >= gap && centeredTextX + textWidth <= labelWidth - gap )
textX = centeredTextX;

View File

@@ -21,7 +21,6 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.util.Iterator;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
@@ -164,11 +163,7 @@ public class FlatToggleButtonUI
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = super.getStyleableInfos( c );
Iterator<String> it = infos.keySet().iterator();
while( it.hasNext() ) {
if( it.next().startsWith( "help." ) )
it.remove();
}
infos.keySet().removeIf( s -> s.startsWith( "help." ) );
return infos;
}

View File

@@ -22,6 +22,7 @@ import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
@@ -31,6 +32,7 @@ import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -47,7 +49,7 @@ import com.formdev.flatlaf.util.LoggingFacade;
*/
public class FlatToolBarSeparatorUI
extends BasicToolBarSeparatorUI
implements StyleableUI
implements StyleableUI, PropertyChangeListener
{
private static final int LINE_WIDTH = 1;
@@ -56,7 +58,6 @@ public class FlatToolBarSeparatorUI
private final boolean shared;
private boolean defaults_initialized = false;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) {
@@ -105,28 +106,33 @@ public class FlatToolBarSeparatorUI
protected void installListeners( JSeparator s ) {
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, () -> stylePropertyChange( s ), null );
s.addPropertyChangeListener( propertyChangeListener );
s.addPropertyChangeListener( this );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
s.removePropertyChangeListener( this );
}
private void stylePropertyChange( JSeparator s ) {
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
s.updateUI();
} else
installStyle( s );
s.revalidate();
s.repaint();
/** @since 2.0.1 */
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
JSeparator s = (JSeparator) e.getSource();
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes installStyle() from installUI()
s.updateUI();
} else
installStyle( s );
s.revalidate();
s.repaint();
break;
}
}
/** @since 2 */

View File

@@ -282,7 +282,7 @@ public class FlatToolBarUI
return comboBox.getUI().isFocusTraversable( comboBox );
}
// check whether component has a empty input map to skip components that
// check whether component has an empty input map to skip components that
// are focusable, but do nothing when focused (e.g. JLabel)
// see LayoutFocusTraversalPolicy.accept()
if( c instanceof JComponent ) {

View File

@@ -21,6 +21,7 @@ import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JComponent;
@@ -49,9 +50,8 @@ import com.formdev.flatlaf.util.StringUtils;
*/
public class FlatToolTipUI
extends BasicToolTipUI
implements PropertyChangeListener
{
private static PropertyChangeListener sharedPropertyChangedListener;
public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatToolTipUI.class, FlatToolTipUI::new );
}
@@ -68,24 +68,24 @@ public class FlatToolTipUI
protected void installListeners( JComponent c ) {
super.installListeners( c );
if( sharedPropertyChangedListener == null ) {
sharedPropertyChangedListener = e -> {
String name = e.getPropertyName();
if( name == "tiptext" || name == "font" || name == "foreground" ) {
JToolTip toolTip = (JToolTip) e.getSource();
FlatLabelUI.updateHTMLRenderer( toolTip, toolTip.getTipText(), false );
}
};
}
c.addPropertyChangeListener( sharedPropertyChangedListener );
c.addPropertyChangeListener( this );
}
@Override
protected void uninstallListeners( JComponent c ) {
super.uninstallListeners( c );
c.removePropertyChangeListener( sharedPropertyChangedListener );
c.removePropertyChangeListener( this );
}
/** @since 2.0.1 */
@Override
public void propertyChange( PropertyChangeEvent e ) {
String name = e.getPropertyName();
if( name == "tiptext" || name == "font" || name == "foreground" ) {
JToolTip toolTip = (JToolTip) e.getSource();
FlatLabelUI.updateHTMLRenderer( toolTip, toolTip.getTipText(), false );
}
}
@Override

View File

@@ -71,7 +71,7 @@ public class FlatUIUtils
public static final boolean MAC_USE_QUARTZ = Boolean.getBoolean( "apple.awt.graphics.UseQuartz" );
private static boolean useSharedUIs = true;
private static WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
private static final WeakHashMap<LookAndFeel, IdentityHashMap<Object, ComponentUI>> sharedUIinstances = new WeakHashMap<>();
public static Rectangle addInsets( Rectangle r, Insets insets ) {
return new Rectangle(
@@ -777,8 +777,8 @@ public class FlatUIUtils
* {@link SwingConstants#WEST} or {@link SwingConstants#EAST})
* @param chevron {@code true} for chevron arrow, {@code false} for triangle arrow
* @param arrowSize the width of the painted arrow (for vertical direction) (will be scaled)
* @param xOffset a offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
* @param yOffset a offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
* @param xOffset an offset added to the x coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
* @param yOffset an offset added to the y coordinate of the arrow to paint it out-of-center. Usually zero. (will be scaled)
*
* @since 1.1
*/
@@ -786,13 +786,15 @@ public class FlatUIUtils
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
{
// compute arrow width/height
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) );
int ah = UIScale.scale( (arrowSize / 2) + (chevron ? 0 : 1) );
// - make chevron arrows one pixel smaller because coordinates are based on center of pixels (0.5/0.5)
// - make triangle arrows one pixel taller (and round height up) to make them look stronger
float aw = UIScale.scale( arrowSize + (chevron ? -1 : 0) );
float ah = chevron ? (aw / 2) : UIScale.scale( (arrowSize / 2) + 1 );
// rotate arrow width/height for horizontal directions
boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH);
if( !vert ) {
int temp = aw;
float temp = aw;
aw = ah;
ah = temp;
}
@@ -804,19 +806,19 @@ public class FlatUIUtils
// compute arrow location
float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset );
float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset );
int ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -ox ) : Math.round( ox ));
int ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -oy ) : Math.round( oy ));
float ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -(ox + aw) ) - aw : Math.round( ox ));
float ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -(oy + ah) ) - ah : Math.round( oy ));
// paint arrow
g.translate( ax, ay );
/*debug
debugPaintArrow( g, Color.red, vert, aw + extra, ah + extra );
debugPaintArrow( g, Color.red, vert, Math.round( aw + extra ), Math.round( ah + extra ) );
debug*/
Shape arrowShape = createArrowShape( direction, chevron, aw, ah );
if( chevron ) {
Stroke oldStroke = g.getStroke();
g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) );
g.draw( arrowShape );
drawShapePure( g, arrowShape );
g.setStroke( oldStroke );
} else {
// triangle
@@ -828,7 +830,7 @@ debug*/
/**
* Creates a chevron or triangle arrow shape for the given direction and size.
* <p>
* The chevron shape is a open path that can be painted with {@link Graphics2D#draw(Shape)}.
* The chevron shape is an open path that can be painted with {@link Graphics2D#draw(Shape)}.
* The triangle shape is a close path that can be painted with {@link Graphics2D#fill(Shape)}.
*
* @param direction the arrow direction ({@link SwingConstants#NORTH}, {@link SwingConstants#SOUTH}
@@ -880,7 +882,7 @@ debug*/
}
/**
* Creates a open or closed path for the given points.
* Creates an open or closed path for the given points.
*/
public static Path2D createPath( boolean close, double... points ) {
Path2D path = new Path2D.Float();
@@ -892,6 +894,23 @@ debug*/
return path;
}
/**
* Draws the given shape with disabled stroke normalization.
* The x/y coordinates of the shape are translated by a half pixel.
*
* @since 2.1
*/
public static void drawShapePure( Graphics2D g, Shape shape ) {
Object oldStrokeControl = g.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE );
g.translate( 0.5, 0.5 );
g.draw( shape );
g.translate( -0.5, -0.5 );
g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldStrokeControl );
}
/**
* Draws the given string at the specified location.
* The provided component is used to query text properties and anti-aliasing hints.

View File

@@ -23,6 +23,7 @@ import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
@@ -43,6 +44,7 @@ import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -231,8 +233,15 @@ public abstract class FlatWindowResizer
{
protected Window window;
private final boolean limitResizeToScreenBounds;
public WindowResizer( JRootPane rootPane ) {
super( rootPane );
// On Linux, limit window resizing to screen bounds because otherwise
// there would be a strange effect when the mouse is moved over a sidebar
// while resizing and the opposite window side is also resized.
limitResizeToScreenBounds = SystemInfo.isLinux;
}
@Override
@@ -289,11 +298,19 @@ public abstract class FlatWindowResizer
@Override
protected boolean limitToParentBounds() {
return false;
return limitResizeToScreenBounds && window != null;
}
@Override
protected Rectangle getParentBounds() {
if( limitResizeToScreenBounds && window != null ) {
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle bounds = gc.getBounds();
Insets insets = window.getToolkit().getScreenInsets( gc );
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
bounds.width - insets.left - insets.right,
bounds.height - insets.top - insets.bottom );
}
return null;
}
@@ -385,7 +402,7 @@ public abstract class FlatWindowResizer
@Override
protected Rectangle getParentBounds() {
return getFrame().getParent().getBounds();
return new Rectangle( getFrame().getParent().getSize() );
}
@Override
@@ -579,8 +596,8 @@ debug*/
// top
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
newBounds.y = yOnScreen - dragTopOffset;
if( limitToParentBounds() && newBounds.y < 0 )
newBounds.y = 0;
if( limitToParentBounds() )
newBounds.y = Math.max( newBounds.y, getParentBounds().y );
newBounds.height += (oldBounds.y - newBounds.y);
}
@@ -597,8 +614,8 @@ debug*/
// left
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
newBounds.x = xOnScreen - dragLeftOffset;
if( limitToParentBounds() && newBounds.x < 0 )
newBounds.x = 0;
if( limitToParentBounds() )
newBounds.x = Math.max( newBounds.x, getParentBounds().x );
newBounds.width += (oldBounds.x - newBounds.x);
}

View File

@@ -155,7 +155,7 @@ class FlatWindowsNativeWindowBorder
}
/**
* Tell the window whether the application wants use custom decorations.
* Tell the window whether the application wants to use custom decorations.
* If {@code true}, the Windows 10 title bar is hidden (including minimize,
* maximize and close buttons), but not the resize borders (including drop shadow).
*/

View File

@@ -284,7 +284,7 @@ public class JBRCustomDecorations
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Window window = SwingUtilities.windowForComponent( c );
boolean active = (window != null) ? window.isActive() : false;
boolean active = window != null && window.isActive();
// paint top border
// - in light themes

View File

@@ -59,7 +59,7 @@ import com.formdev.flatlaf.util.Animator.Interpolator;
* </pre>
*
* Animation works only if the component passed to {@link #paintIcon(Component, Graphics, int, int)}
* is a instance of {@link JComponent}.
* is an instance of {@link JComponent}.
* A client property is set on the component to store the animation state.
*
* @author Karl Tauber
@@ -68,7 +68,7 @@ public interface AnimatedIcon
extends Icon
{
@Override
public default void paintIcon( Component c, Graphics g, int x, int y ) {
default void paintIcon( Component c, Graphics g, int x, int y ) {
AnimationSupport.paintIcon( this, c, g, x, y );
}

View File

@@ -47,7 +47,7 @@ public class DerivedColor
Color result = ColorFunctions.applyFunctions( baseColor, functions );
// if the result is equal to the default color, then the original base color
// was passed and we can cache this to avoid color calculations
// was passed, and we can cache this to avoid color calculations
if( !hasBaseOfDefaultColor && result.getRGB() == this.getRGB() ) {
hasBaseOfDefaultColor = true;
baseOfDefaultColorRGB = baseColor.getRGB();

View File

@@ -76,7 +76,7 @@ public class HSLColor
}
/**
* Create a HSLColor object using an an array containing the
* Create a HSLColor object using an array containing the
* individual HSL values and with a default alpha value of 1.
*
* @param hsl array containing HSL values
@@ -87,7 +87,7 @@ public class HSLColor
}
/**
* Create a HSLColor object using an an array containing the
* Create a HSLColor object using an array containing the
* individual HSL values.
*
* @param hsl array containing HSL values
@@ -291,7 +291,7 @@ public class HSLColor
// Calculate the Saturation
float s = 0;
float s;
if (max == min)
s = 0;
@@ -386,7 +386,7 @@ public class HSLColor
s /= 100f;
l /= 100f;
float q = 0;
float q;
if (l < 0.5)
q = l * (1 + s);

View File

@@ -31,7 +31,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
public class HiDPIUtils
{
public interface Painter {
public void paint( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
void paint( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
}
public static void paintAtScale1x( Graphics2D g, JComponent c, Painter painter ) {
@@ -114,7 +114,7 @@ public class HiDPIUtils
* painted too far down on some operating systems.
* The higher the system scale factor is, the more.
* <p>
* This methods computes a correction value for the Y position.
* This method computes a correction value for the Y position.
*/
public static float computeTextYCorrection( Graphics2D g ) {
if( !useTextYCorrection() || !SystemInfo.isWindows )

View File

@@ -89,7 +89,7 @@ public class JavaCompatibility
getClippedStringMethod = cls.getMethod( SystemInfo.isJava_9_orLater
? "getClippedString"
: "clipStringIfNecessary",
new Class[] { JComponent.class, FontMetrics.class, String.class, int.class } );
JComponent.class, FontMetrics.class, String.class, int.class );
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
throw new RuntimeException( ex );

View File

@@ -72,7 +72,7 @@ public class MultiResolutionImageSupport
* <p>
* The given dimensions array is only used for {@link #getResolutionVariants(Image)}.
* The producer function may be invoked with any dimension (that is not contained in
* dimensions array) and is expected to produce a image for the passed in dimension.
* dimensions array) and is expected to produce an image for the passed in dimension.
*
* @param baseImageIndex index of the base image in the dimensions array
* @param dimensions dimensions of resolution variants (sorted by size; smallest first)
@@ -92,7 +92,7 @@ public class MultiResolutionImageSupport
* for "disabled" state.
*
* @param image a multi-resolution image that is mapped using the given mapper function
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying an filter)
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying a filter)
* @return a multi-resolution image on Java 9 or later; a mapped image on Java 8
*/
public static Image map( Image image, Function<Image, Image> mapper ) {
@@ -104,7 +104,7 @@ public class MultiResolutionImageSupport
* <p>
* If the given image is a multi-resolution image then invokes
* {@code java.awt.image.MultiResolutionImage.getResolutionVariant(destImageWidth, destImageHeight)}.
* Otherwise returns the given image.
* Otherwise, returns the given image.
*/
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
return image;
@@ -115,7 +115,7 @@ public class MultiResolutionImageSupport
* <p>
* If the given image is a multi-resolution image then invokes
* {@code java.awt.image.MultiResolutionImage.getResolutionVariants()}.
* Otherwise returns a list containing only the given image.
* Otherwise, returns a list containing only the given image.
*/
public static List<Image> getResolutionVariants( Image image ) {
return Collections.singletonList( image );

View File

@@ -195,7 +195,7 @@ public class NativeLibrary
// for loaded native libraries, they will be deleted on next application startup.
// The default temporary directory may contain hundreds or thousands of files.
// To make searching for "marked for deletion" files as fast as possible,
// use a sub directory that contains only our temporary native libraries.
// use a subdirectory that contains only our temporary native libraries.
tmpdir += "\\flatlaf.temp";
}

View File

@@ -103,7 +103,7 @@ public class UIScale
// Java 9 and later supports per-monitor scaling
jreHiDPI = true;
} else if( SystemInfo.isJetBrainsJVM ) {
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may support per-monitor scaling
// see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled()
try {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
@@ -411,7 +411,7 @@ public class UIScale
* Scales the given dimension with the user scale factor.
* <p>
* If user scale factor is 1, then the given dimension is simply returned.
* Otherwise a new instance of {@link Dimension} or {@link DimensionUIResource}
* Otherwise, a new instance of {@link Dimension} or {@link DimensionUIResource}
* is returned, depending on whether the passed dimension implements {@link UIResource}.
*/
public static Dimension scale( Dimension dimension ) {
@@ -427,7 +427,7 @@ public class UIScale
* Scales the given insets with the user scale factor.
* <p>
* If user scale factor is 1, then the given insets is simply returned.
* Otherwise a new instance of {@link Insets} or {@link InsetsUIResource}
* Otherwise, a new instance of {@link Insets} or {@link InsetsUIResource}
* is returned, depending on whether the passed dimension implements {@link UIResource}.
*/
public static Insets scale( Insets insets ) {

View File

@@ -24,7 +24,7 @@
#
# NOTE: Avoid copying the whole content of this file to own properties files.
# This will make upgrading to newer FlatLaf versions complex and error-prone.
# Instead copy and modify only those properties that you need to alter.
# Instead, copy and modify only those properties that you need to alter.
#
# Colors and style mostly based on Darcula theme from IntelliJ IDEA Community Edition,

View File

@@ -23,7 +23,7 @@
#
# NOTE: Avoid copying the whole content of this file to own properties files.
# This will make upgrading to newer FlatLaf versions complex and error-prone.
# Instead copy and modify only those properties that you need to alter.
# Instead, copy and modify only those properties that you need to alter.
#
# Colors and style mostly based on Darcula theme from IntelliJ IDEA Community Edition,
@@ -240,6 +240,7 @@ MenuBar.borderColor = $Separator.foreground
#---- PasswordField ----
PasswordField.capsLockIconColor = #ffffff64
PasswordField.revealIconColor = @foreground
#---- Popup ----
@@ -251,6 +252,7 @@ Popup.dropShadowOpacity = 0.25
#---- PopupMenu ----
PopupMenu.borderColor = tint(@background,17%)
PopupMenu.hoverScrollArrowBackground = lighten(@background,5%)
#---- ProgressBar ----
@@ -367,6 +369,6 @@ Tree.hash = lighten($Tree.background,5%)
focusable: false; \
toolbar.margin: 1,1,1,1; \
toolbar.spacingInsets: 1,1,1,1; \
toolbar.hoverBackground: fade(Actions.GreyInline,30%,lazy); \
toolbar.pressedBackground: fade(Actions.GreyInline,40%,lazy); \
toolbar.selectedBackground: fade(Actions.GreyInline,50%,lazy)
toolbar.hoverBackground: lighten($TextField.background,5%); \
toolbar.pressedBackground: lighten($TextField.background,10%); \
toolbar.selectedBackground: lighten($TextField.background,15%)

View File

@@ -24,7 +24,7 @@
#
# NOTE: Avoid copying the whole content of this file to own properties files.
# This will make upgrading to newer FlatLaf versions complex and error-prone.
# Instead copy and modify only those properties that you need to alter.
# Instead, copy and modify only those properties that you need to alter.
#
# Colors and style mostly based on IntelliJ theme from IntelliJ IDEA Community Edition,

View File

@@ -23,7 +23,7 @@
#
# NOTE: Avoid copying the whole content of this file to own properties files.
# This will make upgrading to newer FlatLaf versions complex and error-prone.
# Instead copy and modify only those properties that you need to alter.
# Instead, copy and modify only those properties that you need to alter.
#
#---- typography / fonts ----
@@ -487,7 +487,6 @@ PasswordField.showCapsLock = true
PasswordField.showRevealButton = false
PasswordField.capsLockIcon = com.formdev.flatlaf.icons.FlatCapsLockIcon
PasswordField.revealIcon = com.formdev.flatlaf.icons.FlatRevealIcon
PasswordField.revealIconColor = lazy(Actions.Grey)
#---- Popup ----
@@ -501,6 +500,7 @@ Popup.dropShadowInsets = -4,-4,4,4
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
PopupMenu.borderInsets = 4,1,4,1
PopupMenu.background = @menuBackground
PopupMenu.scrollArrowColor = @buttonArrowColor
#---- PopupMenuSeparator ----
@@ -555,6 +555,7 @@ RootPane.honorDialogMinimumSizeOnResize = true
#---- ScrollBar ----
ScrollBar.width = 10
ScrollBar.minimumButtonSize = 12,12
ScrollBar.minimumThumbSize = 10,10
ScrollBar.maximumThumbSize = 100000,100000
ScrollBar.trackInsets = 0,0,0,0

View File

@@ -23,7 +23,7 @@
#
# NOTE: Avoid copying the whole content of this file to own properties files.
# This will make upgrading to newer FlatLaf versions complex and error-prone.
# Instead copy and modify only those properties that you need to alter.
# Instead, copy and modify only those properties that you need to alter.
#
# Colors and style mostly based on IntelliJ theme from IntelliJ IDEA Community Edition,
@@ -247,6 +247,7 @@ MenuBar.borderColor = $Separator.foreground
#---- PasswordField ----
PasswordField.capsLockIconColor = #00000064
PasswordField.revealIconColor = tint(@foreground,40%)
#---- Popup ----
@@ -258,6 +259,7 @@ Popup.dropShadowOpacity = 0.15
#---- PopupMenu ----
PopupMenu.borderColor = shade(@background,28%)
PopupMenu.hoverScrollArrowBackground = darken(@background,5%)
#---- ProgressBar ----
@@ -374,6 +376,6 @@ Tree.hash = darken($Tree.background,10%)
focusable: false; \
toolbar.margin: 1,1,1,1; \
toolbar.spacingInsets: 1,1,1,1; \
toolbar.hoverBackground: fade(Actions.GreyInline,10%,lazy); \
toolbar.pressedBackground: fade(Actions.GreyInline,20%,lazy); \
toolbar.selectedBackground: fade(Actions.GreyInline,30%,lazy)
toolbar.hoverBackground: darken($TextField.background,4%); \
toolbar.pressedBackground: darken($TextField.background,8%); \
toolbar.selectedBackground: darken($TextField.background,12%)

View File

@@ -152,13 +152,17 @@ ToggleButton.endBackground = $ToggleButton.background
[Hiberbee_Dark]TabbedPane.focusColor = #5A5A5A
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
[Hiberbee_Dark]ToggleButton.selectedBackground = $ToggleButton.selectedBackground
[Hiberbee_Dark]ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
[High_contrast]ToggleButton.selectedBackground = #fff
[High_contrast]ToggleButton.selectedForeground = #000
[High_contrast]ToggleButton.disabledSelectedBackground = #444
[High_contrast]ToggleButton.toolbar.selectedBackground = #fff
[High_contrast][style]Button.inTextField = \
toolbar.hoverBackground: #444; \
toolbar.pressedBackground: #666; \
toolbar.selectedBackground: #fff
[High_contrast][style]ToggleButton.inTextField = $[High_contrast][style]Button.inTextField
[Light_Flat]TableHeader.background = #E5E5E9

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import com.formdev.flatlaf.ui.TestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
class TestFlatIconPaintingNullComponent
{
static Graphics graphics;
@BeforeAll
static void setup() {
TestUtils.setup( false );
graphics = new BufferedImage( 32, 32, BufferedImage.TYPE_INT_ARGB ).getGraphics();
graphics.setColor( Color.white );
}
@AfterAll
static void cleanup() {
TestUtils.cleanup();
graphics = null;
}
@Test
void flatHelpButtonIcon() {
paintWithoutException( new FlatHelpButtonIcon() );
}
@Test
void flatMenuArrowIcon() {
paintWithoutException( new FlatMenuArrowIcon() );
}
@Test
void flatSearchIcon() {
paintWithoutException( new FlatSearchIcon() );
}
private void paintWithoutException( Icon icon ) {
graphics.clearRect( 0, 0, 32, 32 );
assertDoesNotThrow( () -> icon.paintIcon( null, graphics, 0, 0 ) );
}
}

View File

@@ -422,6 +422,10 @@ public class TestFlatStyleableInfo
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
Map<String, Class<?>> expected = expectedMap(
"arrowType", String.class,
"scrollArrowColor", Color.class,
"hoverScrollArrowBackground", Color.class,
"borderInsets", Insets.class,
"borderColor", Color.class
);
@@ -539,6 +543,7 @@ public class TestFlatStyleableInfo
"maximumThumbSize", Dimension.class,
"allowsAbsolutePositioning", boolean.class,
"minimumButtonSize", Dimension.class,
"trackInsets", Insets.class,
"thumbInsets", Insets.class,
"trackArc", int.class,

View File

@@ -565,6 +565,10 @@ public class TestFlatStyling
JPopupMenu c = new JPopupMenu();
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
ui.applyStyle( "arrowType: chevron" );
ui.applyStyle( "scrollArrowColor: #fff" );
ui.applyStyle( "hoverScrollArrowBackground: #fff" );
ui.applyStyle( "borderInsets: 1,2,3,4" );
ui.applyStyle( "borderColor: #fff" );
@@ -684,6 +688,7 @@ public class TestFlatStyling
ui.applyStyle( "maximumThumbSize: 1,2" );
ui.applyStyle( "allowsAbsolutePositioning: true" );
ui.applyStyle( "minimumButtonSize: 1,2" );
ui.applyStyle( "trackInsets: 1,2,3,4" );
ui.applyStyle( "thumbInsets: 1,2,3,4" );
ui.applyStyle( "trackArc: 5" );

View File

@@ -464,6 +464,7 @@ class DemoFrame
JMenuItem projectViewMenuItem = new JMenuItem();
JMenuItem structureViewMenuItem = new JMenuItem();
JMenuItem propertiesViewMenuItem = new JMenuItem();
scrollingPopupMenu = new JMenu();
JMenuItem menuItem2 = new JMenuItem();
htmlMenuItem = new JMenuItem();
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
@@ -668,6 +669,12 @@ class DemoFrame
}
viewMenu.add(menu1);
//======== scrollingPopupMenu ========
{
scrollingPopupMenu.setText("Scrolling Popup Menu");
}
viewMenu.add(scrollingPopupMenu);
//---- menuItem2 ----
menuItem2.setText("Disabled Item");
menuItem2.setEnabled(false);
@@ -889,8 +896,17 @@ class DemoFrame
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
if( FlatLaf.supportsNativeWindowDecorations() ) {
windowDecorationsCheckBoxMenuItem.setSelected( FlatLaf.isUseNativeWindowDecorations() );
scrollingPopupMenu.add( "Large menus are scrollable" );
scrollingPopupMenu.add( "Use mouse wheel to scroll" );
scrollingPopupMenu.add( "Or use up/down arrows at top/bottom" );
for( int i = 1; i <= 100; i++ )
scrollingPopupMenu.add( "Item " + i );
if( FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated()) ) {
if( SystemInfo.isLinux )
unsupported( windowDecorationsCheckBoxMenuItem );
else
windowDecorationsCheckBoxMenuItem.setSelected( FlatLaf.isUseNativeWindowDecorations() );
menuBarEmbeddedCheckBoxMenuItem.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
unifiedTitleBarMenuItem.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
showTitleBarIconMenuItem.setSelected( UIManager.getBoolean( "TitlePane.showIcon" ) );
@@ -931,6 +947,7 @@ class DemoFrame
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenuItem exitMenuItem;
private JMenu scrollingPopupMenu;
private JMenuItem htmlMenuItem;
private JMenu fontMenu;
private JMenu optionsMenu;

View File

@@ -282,6 +282,13 @@ new FormModel {
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "scrollingPopupMenu"
"text": "Scrolling Popup Menu"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem2"
"text": "Disabled Item"

View File

@@ -17,6 +17,8 @@
package com.formdev.flatlaf.demo;
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.extras.FlatInspector;
@@ -52,6 +54,13 @@ public class FlatLafDemo
System.setProperty( "apple.awt.application.appearance", "system" );
}
// Linux
if( SystemInfo.isLinux ) {
// enable custom window decorations
JFrame.setDefaultLookAndFeelDecorated( true );
JDialog.setDefaultLookAndFeelDecorated( true );
}
if( FlatLafDemo.screenshotsMode && !SystemInfo.isJava_9_orLater && System.getProperty( "flatlaf.uiScale" ) == null )
System.setProperty( "flatlaf.uiScale", "2x" );

View File

@@ -284,6 +284,20 @@ public class FlatSVGIcon
}
}
/**
* Creates a copy of the given icon.
* <p>
* If the icon has a color filter, then it is shared with the new icon.
*
* @since 2.0.1
*/
public FlatSVGIcon( FlatSVGIcon icon ) {
this( icon.name, icon.width, icon.height, icon.scale, icon.disabled, icon.classLoader, icon.uri );
colorFilter = icon.colorFilter;
diagram = icon.diagram;
dark = icon.dark;
}
protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader, URI uri ) {
this.name = name;
this.width = width;
@@ -466,7 +480,7 @@ public class FlatSVGIcon
if( url == null ) {
loadFailed = true;
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
return;
}

View File

@@ -20,7 +20,6 @@ import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import com.formdev.flatlaf.ui.FlatPopupMenuUI;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.plaf.basic.BasicJidePopupMenuUI;
/**
* Provides the Flat LaF UI delegate for {@link com.jidesoft.swing.JidePopupMenu}.
@@ -38,7 +37,9 @@ public class FlatJidePopupMenuUI
@Override
public Popup getPopup( JPopupMenu popupMenu, int x, int y ) {
Popup popup = BasicJidePopupMenuUI.addScrollPaneIfNecessary( popupMenu, x, y );
return popup == null ? super.getPopup( popupMenu, x, y ) : popup;
// not using BasicJidePopupMenuUI.addScrollPaneIfNecessary() anymore because
// FlatLaf supports menu scrolling that works better than JIDE menu scrolling
// (support mouse wheel scrolling, scales arrows)
return super.getPopup( popupMenu, x, y );
}
}

View File

@@ -288,6 +288,7 @@ public class FlatWindowsNativeWindowBorder
private static final int GWLP_WNDPROC = -4;
private static final int
WM_MOVE = 0x0003,
WM_ERASEBKGND = 0x0014,
WM_NCCALCSIZE = 0x0083,
WM_NCHITTEST = 0x0084,
@@ -301,6 +302,10 @@ public class FlatWindowsNativeWindowBorder
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOVING = 0x0216,
WM_ENTERSIZEMOVE = 0x0231,
WM_EXITSIZEMOVE = 0x0232,
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
// WM_SIZE wParam
@@ -341,6 +346,8 @@ public class FlatWindowsNativeWindowBorder
private final LONG_PTR defaultWndProc;
private int wmSizeWParam = -1;
private HBRUSH background;
private boolean isMovingOrSizing;
private boolean isMoving;
// Swing coordinates/values may be scaled on a HiDPI screen
private int titleBarHeight;
@@ -477,7 +484,27 @@ public class FlatWindowsNativeWindowBorder
wParam = new WPARAM( wmSizeWParam );
break;
case WM_ENTERSIZEMOVE:
isMovingOrSizing = true;
break;
case WM_EXITSIZEMOVE:
isMovingOrSizing = isMoving = false;
break;
case WM_MOVE:
case WM_MOVING:
if( isMovingOrSizing )
isMoving = true;
break;
case WM_ERASEBKGND:
// do not erase background while the user is moving the window,
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
// when dragging the window partly offscreen and back into the screen bounds
if( isMoving )
return new LRESULT( 0 );
return WmEraseBkgnd( hwnd, uMsg, wParam, lParam );
case WM_DESTROY:

View File

@@ -88,6 +88,8 @@ FlatWndProc::FlatWndProc() {
defaultWndProc = NULL;
wmSizeWParam = -1;
background = NULL;
isMovingOrSizing = false;
isMoving = false;
}
HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
@@ -250,7 +252,27 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
wParam = wmSizeWParam;
break;
case WM_ENTERSIZEMOVE:
isMovingOrSizing = true;
break;
case WM_EXITSIZEMOVE:
isMovingOrSizing = isMoving = false;
break;
case WM_MOVE:
case WM_MOVING:
if( isMovingOrSizing )
isMoving = true;
break;
case WM_ERASEBKGND:
// do not erase background while the user is moving the window,
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
// when dragging the window partly offscreen and back into the screen bounds
if( isMoving )
return FALSE;
return WmEraseBkgnd( hwnd, uMsg, wParam, lParam );
case WM_DESTROY:

View File

@@ -43,6 +43,8 @@ private:
WNDPROC defaultWndProc;
int wmSizeWParam;
HBRUSH background;
bool isMovingOrSizing;
bool isMoving;
FlatWndProc();
static void initIDs( JNIEnv *env, jobject obj );

View File

@@ -4,7 +4,7 @@ FlatLaf addon for SwingX
This addon for FlatLaf adds support for **some** widely used SwingX components.
Many SwingX components that do not use UI delegates (e.g. `JXButton`, `JXLabel`,
`JXList`, etc) work with FlatLaf without adaptation.
`JXList`, `JXStatusBar`, etc) work with FlatLaf without adaptation.
Following SwingX components, which use UI delegates, are currently supported by
this addon:

View File

@@ -217,8 +217,8 @@ public class FlatTaskPaneUI
Graphics2D g2 = (Graphics2D) g;
// scale chevron size
float cw = scale( 6f );
float ch = scale( 3f );
float cw = scale( 7f );
float ch = scale( 3.5f );
// create arrow shape
int direction = group.isCollapsed() ? SwingConstants.SOUTH : SwingConstants.NORTH;
@@ -237,9 +237,9 @@ public class FlatTaskPaneUI
// paint
g2.translate( cx, cy );
g2.draw( arrowShape );
FlatUIUtils.drawShapePure( g2, arrowShape );
g2.translate( 0, offset );
g2.draw( arrowShape );
FlatUIUtils.drawShapePure( g2, arrowShape );
g2.translate( -cx, -(cy + offset) );
}

View File

@@ -712,7 +712,7 @@ PasswordField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.Co
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
PasswordField.revealIconColor [lazy] #afb1b3 HSL 210 3 69 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIconColor #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
@@ -737,6 +737,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #484c4e HSL 200 4 29 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.scrollArrowColor #9b9b9b HSL 0 0 61 javax.swing.plaf.ColorUIResource [UI]
#---- PopupMenuSeparator ----
@@ -862,6 +864,7 @@ ScrollBar.hoverThumbColor #6e767a HSL 200 5 45 com.formdev.flatlaf.u
ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(4%)
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #54595c HSL 203 5 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
ScrollBar.pressedThumbColor #7a8387 HSL 198 5 50 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%)
@@ -1425,12 +1428,12 @@ ViewportUI com.formdev.flatlaf.ui.FlatViewportUI
#---- [style]Button ----
[style]Button.clearButton icon: com.formdev.flatlaf.icons.FlatClearIcon; focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: null; toolbar.pressedBackground: null
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: fade(Actions.GreyInline,30%,lazy); toolbar.pressedBackground: fade(Actions.GreyInline,40%,lazy); toolbar.selectedBackground: fade(Actions.GreyInline,50%,lazy)
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: lighten($TextField.background,5%); toolbar.pressedBackground: lighten($TextField.background,10%); toolbar.selectedBackground: lighten($TextField.background,15%)
#---- [style]ToggleButton ----
[style]ToggleButton.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: fade(Actions.GreyInline,30%,lazy); toolbar.pressedBackground: fade(Actions.GreyInline,40%,lazy); toolbar.selectedBackground: fade(Actions.GreyInline,50%,lazy)
[style]ToggleButton.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: lighten($TextField.background,5%); toolbar.pressedBackground: lighten($TextField.background,10%); toolbar.selectedBackground: lighten($TextField.background,15%)
#---- [style]ToolBar ----

View File

@@ -717,7 +717,7 @@ PasswordField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.Co
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
PasswordField.revealIconColor [lazy] #6e6e6e HSL 0 0 43 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIconColor #666666 HSL 0 0 40 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
@@ -742,6 +742,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #e5e5e5 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.scrollArrowColor #666666 HSL 0 0 40 javax.swing.plaf.ColorUIResource [UI]
#---- PopupMenuSeparator ----
@@ -867,6 +869,7 @@ ScrollBar.hoverThumbColor #c3c3c3 HSL 0 0 76 com.formdev.flatlaf.u
ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #ededed HSL 0 0 93 com.formdev.flatlaf.util.DerivedColor [UI] darken(3%)
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #d9d9d9 HSL 0 0 85 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%)
ScrollBar.pressedThumbColor #a9a9a9 HSL 0 0 66 com.formdev.flatlaf.util.DerivedColor [UI] darken(20%)
@@ -1430,12 +1433,12 @@ ViewportUI com.formdev.flatlaf.ui.FlatViewportUI
#---- [style]Button ----
[style]Button.clearButton icon: com.formdev.flatlaf.icons.FlatClearIcon; focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: null; toolbar.pressedBackground: null
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: fade(Actions.GreyInline,10%,lazy); toolbar.pressedBackground: fade(Actions.GreyInline,20%,lazy); toolbar.selectedBackground: fade(Actions.GreyInline,30%,lazy)
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: darken($TextField.background,4%); toolbar.pressedBackground: darken($TextField.background,8%); toolbar.selectedBackground: darken($TextField.background,12%)
#---- [style]ToggleButton ----
[style]ToggleButton.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: fade(Actions.GreyInline,10%,lazy); toolbar.pressedBackground: fade(Actions.GreyInline,20%,lazy); toolbar.selectedBackground: fade(Actions.GreyInline,30%,lazy)
[style]ToggleButton.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; toolbar.hoverBackground: darken($TextField.background,4%); toolbar.pressedBackground: darken($TextField.background,8%); toolbar.selectedBackground: darken($TextField.background,12%)
#---- [style]ToolBar ----

View File

@@ -727,7 +727,7 @@ PasswordField.inactiveForeground #000088 HSL 240 100 27 javax.swing.plaf.Co
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
PasswordField.revealIconColor [lazy] #6e6e6e HSL 0 0 43 javax.swing.plaf.ColorUIResource [UI]
PasswordField.revealIconColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
@@ -752,6 +752,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
PopupMenu.consumeEventOnClose false
PopupMenu.font [active] $defaultFont [UI]
PopupMenu.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.hoverScrollArrowBackground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
PopupMenu.scrollArrowColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
#---- PopupMenuSeparator ----
@@ -874,6 +876,7 @@ ScrollBar.hoverThumbColor #ff0000 HSL 0 100 50 javax.swing.plaf.Colo
ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedThumbWithTrack false
ScrollBar.showButtons false

View File

@@ -162,7 +162,6 @@ public class FlatComponentsTest
((JComponent)c).putClientProperty( FlatClientProperties.OUTLINE, outline );
} );
repaint();
textField1.requestFocusInWindow();
}

View File

@@ -80,13 +80,24 @@ public class FlatMenusTest
FlatLaf.updateUI();
}
private void showPopupMenuButtonActionPerformed(ActionEvent e) {
private void showPopupMenuButton(ActionEvent e) {
Component invoker = (Component) e.getSource();
PopupMenu popupMenu = new PopupMenu();
popupMenu.applyComponentOrientation( getComponentOrientation() );
popupMenu.show( invoker, 0, invoker.getHeight() );
}
private void showScrollingPopupMenu(ActionEvent e) {
Component invoker = (Component) e.getSource();
JPopupMenu popupMenu = new JPopupMenu();
for( int i = 1; i <= 100; i++ ) {
popupMenu.add( "menu item " + i + (i % 5 == 0 ? " test" : "") )
.addActionListener( e2 -> System.out.println( ((JMenuItem)e2.getSource()).getText() ) );
}
popupMenu.applyComponentOrientation( getComponentOrientation() );
popupMenu.show( invoker, 0, invoker.getHeight() );
}
private void largerChanged() {
LargerMenuItem.useLargerSize = largerCheckBox.isSelected();
menuBar2.revalidate();
@@ -230,6 +241,7 @@ public class FlatMenusTest
JRadioButtonMenuItem radioButtonMenuItem11 = new JRadioButtonMenuItem();
JLabel popupMenuLabel = new JLabel();
JButton showPopupMenuButton = new JButton();
showScrollingPopupMenuButton = new JButton();
armedCheckBox = new JCheckBox();
underlineCheckBox = new JCheckBox();
popupMenubackgroundCheckBox = new JCheckBox();
@@ -839,9 +851,14 @@ public class FlatMenusTest
//---- showPopupMenuButton ----
showPopupMenuButton.setText("show JPopupMenu");
showPopupMenuButton.addActionListener(e -> showPopupMenuButtonActionPerformed(e));
showPopupMenuButton.addActionListener(e -> showPopupMenuButton(e));
add(showPopupMenuButton, "cell 1 2");
//---- showScrollingPopupMenuButton ----
showScrollingPopupMenuButton.setText("show scrolling JPopupMenu");
showScrollingPopupMenuButton.addActionListener(e -> showScrollingPopupMenu(e));
add(showScrollingPopupMenuButton, "cell 2 2");
//---- armedCheckBox ----
armedCheckBox.setText("armed");
armedCheckBox.setMnemonic('A');
@@ -884,6 +901,7 @@ public class FlatMenusTest
private JMenuBar menuBar2;
private JCheckBox largerCheckBox;
private JCheckBox accelCheckBox;
private JButton showScrollingPopupMenuButton;
private JCheckBox armedCheckBox;
private JCheckBox underlineCheckBox;
private JCheckBox popupMenubackgroundCheckBox;

View File

@@ -629,10 +629,20 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "showPopupMenuButton"
"text": "show JPopupMenu"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButtonActionPerformed", true ) )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButton", true ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showScrollingPopupMenuButton"
"text": "show scrolling JPopupMenu"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showScrollingPopupMenu", true ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "armedCheckBox"
"text": "armed"

View File

@@ -673,7 +673,7 @@ public class FlatPaintingTest
panel5.add(arrowSizeLabel, "cell 0 2");
//---- arrowSizeSpinner ----
arrowSizeSpinner.setModel(new SpinnerNumberModel(8, 2, null, 1));
arrowSizeSpinner.setModel(new SpinnerNumberModel(9, 2, null, 1));
arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged());
panel5.add(arrowSizeSpinner, "cell 1 2");

View File

@@ -564,7 +564,7 @@ new FormModel {
name: "arrowSizeSpinner"
"model": new javax.swing.SpinnerNumberModel {
minimum: 2
value: 8
value: 9
}
auxiliary() {
"JavaCodeGenerator.variableLocal": false

View File

@@ -0,0 +1,622 @@
/*
* Copyright 2022 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatSubMenusTest
extends FlatTestPanel
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatSubMenusTest" );
UIManager.put( "FlatLaf.debug.menu.showSafeTriangle", true );
frame.applyComponentOrientationToFrame = true;
frame.showFrame( FlatSubMenusTest::new, panel -> ((FlatSubMenusTest)panel).menuBar );
} );
}
FlatSubMenusTest() {
initComponents();
}
private void showPopupMenuButtonActionPerformed(ActionEvent e) {
Component invoker = (Component) e.getSource();
PopupMenu popupMenu = new PopupMenu();
popupMenu.applyComponentOrientation( getComponentOrientation() );
popupMenu.show( invoker, 0, invoker.getHeight() );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JButton showPopupMenuButton = new JButton();
menuBar = new JMenuBar();
JMenu menu3 = new JMenu();
JMenuItem menuItem1 = new JMenuItem();
JMenuItem menuItem50 = new JMenuItem();
JMenu menu4 = new JMenu();
JMenuItem menuItem9 = new JMenuItem();
JMenuItem menuItem10 = new JMenuItem();
JMenuItem menuItem11 = new JMenuItem();
JMenu menu8 = new JMenu();
JMenu menu21 = new JMenu();
JMenuItem menuItem81 = new JMenuItem();
JMenuItem menuItem82 = new JMenuItem();
JMenuItem menuItem83 = new JMenuItem();
JMenuItem menuItem41 = new JMenuItem();
JMenuItem menuItem42 = new JMenuItem();
JMenuItem menuItem43 = new JMenuItem();
JMenuItem menuItem44 = new JMenuItem();
JMenuItem menuItem45 = new JMenuItem();
JMenuItem menuItem46 = new JMenuItem();
JMenuItem menuItem12 = new JMenuItem();
JMenuItem menuItem13 = new JMenuItem();
JMenuItem menuItem14 = new JMenuItem();
JMenuItem menuItem2 = new JMenuItem();
JMenu menu5 = new JMenu();
JMenuItem menuItem15 = new JMenuItem();
JMenuItem menuItem16 = new JMenuItem();
JMenuItem menuItem17 = new JMenuItem();
JMenuItem menuItem18 = new JMenuItem();
JMenuItem menuItem19 = new JMenuItem();
JMenuItem menuItem20 = new JMenuItem();
JMenuItem menuItem21 = new JMenuItem();
JMenuItem menuItem22 = new JMenuItem();
JMenuItem menuItem23 = new JMenuItem();
JMenuItem menuItem24 = new JMenuItem();
JMenuItem menuItem25 = new JMenuItem();
JMenuItem menuItem26 = new JMenuItem();
JMenuItem menuItem27 = new JMenuItem();
JMenuItem menuItem28 = new JMenuItem();
JMenuItem menuItem29 = new JMenuItem();
JMenu menu6 = new JMenu();
JMenuItem menuItem30 = new JMenuItem();
JMenuItem menuItem31 = new JMenuItem();
JMenuItem menuItem32 = new JMenuItem();
JMenu menu9 = new JMenu();
JMenuItem menuItem47 = new JMenuItem();
JMenuItem menuItem48 = new JMenuItem();
JMenuItem menuItem49 = new JMenuItem();
JMenuItem menuItem33 = new JMenuItem();
JMenuItem menuItem34 = new JMenuItem();
JMenuItem menuItem3 = new JMenuItem();
JMenuItem menuItem4 = new JMenuItem();
JMenuItem menuItem5 = new JMenuItem();
JMenuItem menuItem6 = new JMenuItem();
JMenuItem menuItem7 = new JMenuItem();
JMenuItem menuItem8 = new JMenuItem();
JMenu menu7 = new JMenu();
JMenuItem menuItem35 = new JMenuItem();
JMenuItem menuItem37 = new JMenuItem();
JMenuItem menuItem36 = new JMenuItem();
JMenuItem menuItem38 = new JMenuItem();
JMenuItem menuItem39 = new JMenuItem();
JMenuItem menuItem40 = new JMenuItem();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]",
// rows
"[]"));
//---- showPopupMenuButton ----
showPopupMenuButton.setText("show JPopupMenu");
showPopupMenuButton.addActionListener(e -> showPopupMenuButtonActionPerformed(e));
add(showPopupMenuButton, "cell 0 0");
//======== menuBar ========
{
//======== menu3 ========
{
menu3.setText("main menu");
//---- menuItem1 ----
menuItem1.setText("text");
menu3.add(menuItem1);
//---- menuItem50 ----
menuItem50.setText("text");
menu3.add(menuItem50);
//======== menu4 ========
{
menu4.setText("text");
//---- menuItem9 ----
menuItem9.setText("text");
menu4.add(menuItem9);
//---- menuItem10 ----
menuItem10.setText("text text");
menu4.add(menuItem10);
//---- menuItem11 ----
menuItem11.setText("text");
menu4.add(menuItem11);
//======== menu8 ========
{
menu8.setText("text");
//======== menu21 ========
{
menu21.setText("text");
//---- menuItem81 ----
menuItem81.setText("text");
menu21.add(menuItem81);
//---- menuItem82 ----
menuItem82.setText("text");
menu21.add(menuItem82);
//---- menuItem83 ----
menuItem83.setText("text");
menu21.add(menuItem83);
}
menu8.add(menu21);
//---- menuItem41 ----
menuItem41.setText("text");
menu8.add(menuItem41);
//---- menuItem42 ----
menuItem42.setText("text");
menu8.add(menuItem42);
//---- menuItem43 ----
menuItem43.setText("text");
menu8.add(menuItem43);
//---- menuItem44 ----
menuItem44.setText("text");
menu8.add(menuItem44);
//---- menuItem45 ----
menuItem45.setText("text");
menu8.add(menuItem45);
//---- menuItem46 ----
menuItem46.setText("text");
menu8.add(menuItem46);
}
menu4.add(menu8);
//---- menuItem12 ----
menuItem12.setText("text");
menu4.add(menuItem12);
//---- menuItem13 ----
menuItem13.setText("text");
menu4.add(menuItem13);
//---- menuItem14 ----
menuItem14.setText("text");
menu4.add(menuItem14);
}
menu3.add(menu4);
//---- menuItem2 ----
menuItem2.setText("text");
menu3.add(menuItem2);
//======== menu5 ========
{
menu5.setText("text");
//---- menuItem15 ----
menuItem15.setText("text bla bla");
menu5.add(menuItem15);
//---- menuItem16 ----
menuItem16.setText("text");
menu5.add(menuItem16);
//---- menuItem17 ----
menuItem17.setText("text");
menu5.add(menuItem17);
//---- menuItem18 ----
menuItem18.setText("text");
menu5.add(menuItem18);
//---- menuItem19 ----
menuItem19.setText("text");
menu5.add(menuItem19);
//---- menuItem20 ----
menuItem20.setText("text");
menu5.add(menuItem20);
//---- menuItem21 ----
menuItem21.setText("text");
menu5.add(menuItem21);
//---- menuItem22 ----
menuItem22.setText("text");
menu5.add(menuItem22);
//---- menuItem23 ----
menuItem23.setText("text");
menu5.add(menuItem23);
//---- menuItem24 ----
menuItem24.setText("text");
menu5.add(menuItem24);
//---- menuItem25 ----
menuItem25.setText("text");
menu5.add(menuItem25);
//---- menuItem26 ----
menuItem26.setText("text");
menu5.add(menuItem26);
//---- menuItem27 ----
menuItem27.setText("text");
menu5.add(menuItem27);
//---- menuItem28 ----
menuItem28.setText("text");
menu5.add(menuItem28);
//---- menuItem29 ----
menuItem29.setText("text");
menu5.add(menuItem29);
}
menu3.add(menu5);
//======== menu6 ========
{
menu6.setText("text");
//---- menuItem30 ----
menuItem30.setText("text o text");
menu6.add(menuItem30);
//---- menuItem31 ----
menuItem31.setText("text");
menu6.add(menuItem31);
//---- menuItem32 ----
menuItem32.setText("text");
menu6.add(menuItem32);
//======== menu9 ========
{
menu9.setText("text");
//---- menuItem47 ----
menuItem47.setText("text");
menu9.add(menuItem47);
//---- menuItem48 ----
menuItem48.setText("text");
menu9.add(menuItem48);
//---- menuItem49 ----
menuItem49.setText("text");
menu9.add(menuItem49);
}
menu6.add(menu9);
//---- menuItem33 ----
menuItem33.setText("text");
menu6.add(menuItem33);
//---- menuItem34 ----
menuItem34.setText("text");
menu6.add(menuItem34);
}
menu3.add(menu6);
//---- menuItem3 ----
menuItem3.setText("text");
menu3.add(menuItem3);
//---- menuItem4 ----
menuItem4.setText("longer text");
menu3.add(menuItem4);
//---- menuItem5 ----
menuItem5.setText("text");
menu3.add(menuItem5);
//---- menuItem6 ----
menuItem6.setText("text");
menu3.add(menuItem6);
//---- menuItem7 ----
menuItem7.setText("text");
menu3.add(menuItem7);
//---- menuItem8 ----
menuItem8.setText("text");
menu3.add(menuItem8);
//======== menu7 ========
{
menu7.setText("text");
//---- menuItem35 ----
menuItem35.setText("text abc");
menu7.add(menuItem35);
//---- menuItem37 ----
menuItem37.setText("text");
menu7.add(menuItem37);
//---- menuItem36 ----
menuItem36.setText("text");
menu7.add(menuItem36);
//---- menuItem38 ----
menuItem38.setText("text");
menu7.add(menuItem38);
//---- menuItem39 ----
menuItem39.setText("text");
menu7.add(menuItem39);
//---- menuItem40 ----
menuItem40.setText("text");
menu7.add(menuItem40);
}
menu3.add(menu7);
}
menuBar.add(menu3);
}
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenuBar menuBar;
// JFormDesigner - End of variables declaration //GEN-END:variables
//---- class PopupMenu ----------------------------------------------------
private class PopupMenu extends JPopupMenu {
private PopupMenu() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JMenuItem menuItem54 = new JMenuItem();
JMenuItem menuItem51 = new JMenuItem();
JMenu menu10 = new JMenu();
JMenuItem menuItem57 = new JMenuItem();
JMenuItem menuItem58 = new JMenuItem();
JMenu menu14 = new JMenu();
JMenu menu18 = new JMenu();
JMenu menu19 = new JMenu();
JMenuItem menuItem76 = new JMenuItem();
JMenuItem menuItem77 = new JMenuItem();
JMenuItem menuItem78 = new JMenuItem();
JMenu menu20 = new JMenu();
JMenuItem menuItem73 = new JMenuItem();
JMenuItem menuItem74 = new JMenuItem();
JMenuItem menuItem75 = new JMenuItem();
JMenuItem menuItem79 = new JMenuItem();
JMenuItem menuItem80 = new JMenuItem();
JMenuItem menuItem70 = new JMenuItem();
JMenuItem menuItem71 = new JMenuItem();
JMenuItem menuItem72 = new JMenuItem();
JMenuItem menuItem59 = new JMenuItem();
JMenuItem menuItem60 = new JMenuItem();
JMenuItem menuItem52 = new JMenuItem();
JMenu menu11 = new JMenu();
JMenuItem menuItem61 = new JMenuItem();
JMenuItem menuItem62 = new JMenuItem();
JMenuItem menuItem63 = new JMenuItem();
JMenu menu12 = new JMenu();
JMenuItem menuItem64 = new JMenuItem();
JMenuItem menuItem65 = new JMenuItem();
JMenuItem menuItem66 = new JMenuItem();
JMenuItem menuItem53 = new JMenuItem();
JMenuItem menuItem55 = new JMenuItem();
JMenuItem menuItem56 = new JMenuItem();
JMenu menu13 = new JMenu();
JMenuItem menuItem67 = new JMenuItem();
JMenuItem menuItem68 = new JMenuItem();
JMenuItem menuItem69 = new JMenuItem();
//======== this ========
//---- menuItem54 ----
menuItem54.setText("text");
add(menuItem54);
//---- menuItem51 ----
menuItem51.setText("text text");
add(menuItem51);
//======== menu10 ========
{
menu10.setText("text");
//---- menuItem57 ----
menuItem57.setText("text");
menu10.add(menuItem57);
//---- menuItem58 ----
menuItem58.setText("text");
menu10.add(menuItem58);
//======== menu14 ========
{
menu14.setText("text");
//======== menu18 ========
{
menu18.setText("text");
//======== menu19 ========
{
menu19.setText("text");
//---- menuItem76 ----
menuItem76.setText("text");
menu19.add(menuItem76);
//---- menuItem77 ----
menuItem77.setText("text");
menu19.add(menuItem77);
//---- menuItem78 ----
menuItem78.setText("text");
menu19.add(menuItem78);
}
menu18.add(menu19);
//======== menu20 ========
{
menu20.setText("text");
//---- menuItem73 ----
menuItem73.setText("text");
menu20.add(menuItem73);
//---- menuItem74 ----
menuItem74.setText("text");
menu20.add(menuItem74);
//---- menuItem75 ----
menuItem75.setText("text");
menu20.add(menuItem75);
}
menu18.add(menu20);
//---- menuItem79 ----
menuItem79.setText("text");
menu18.add(menuItem79);
//---- menuItem80 ----
menuItem80.setText("text");
menu18.add(menuItem80);
}
menu14.add(menu18);
//---- menuItem70 ----
menuItem70.setText("text");
menu14.add(menuItem70);
//---- menuItem71 ----
menuItem71.setText("text");
menu14.add(menuItem71);
//---- menuItem72 ----
menuItem72.setText("text");
menu14.add(menuItem72);
}
menu10.add(menu14);
//---- menuItem59 ----
menuItem59.setText("text");
menu10.add(menuItem59);
//---- menuItem60 ----
menuItem60.setText("text");
menu10.add(menuItem60);
}
add(menu10);
//---- menuItem52 ----
menuItem52.setText("text");
add(menuItem52);
//======== menu11 ========
{
menu11.setText("text");
//---- menuItem61 ----
menuItem61.setText("text");
menu11.add(menuItem61);
//---- menuItem62 ----
menuItem62.setText("text");
menu11.add(menuItem62);
//---- menuItem63 ----
menuItem63.setText("text");
menu11.add(menuItem63);
}
add(menu11);
//======== menu12 ========
{
menu12.setText("text");
//---- menuItem64 ----
menuItem64.setText("text");
menu12.add(menuItem64);
//---- menuItem65 ----
menuItem65.setText("text");
menu12.add(menuItem65);
//---- menuItem66 ----
menuItem66.setText("text");
menu12.add(menuItem66);
}
add(menu12);
//---- menuItem53 ----
menuItem53.setText("text");
add(menuItem53);
//---- menuItem55 ----
menuItem55.setText("text");
add(menuItem55);
//---- menuItem56 ----
menuItem56.setText("text");
add(menuItem56);
//======== menu13 ========
{
menu13.setText("text");
//---- menuItem67 ----
menuItem67.setText("text");
menu13.add(menuItem67);
//---- menuItem68 ----
menuItem68.setText("text");
menu13.add(menuItem68);
//---- menuItem69 ----
menuItem69.setText("text");
menu13.add(menuItem69);
}
add(menu13);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// JFormDesigner - End of variables declaration //GEN-END:variables
}
}

View File

@@ -0,0 +1,439 @@
JFDML JFormDesigner: "7.0.5.0.404" Java: "17" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[]"
"$rowConstraints": "[]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JButton" ) {
name: "showPopupMenuButton"
"text": "show JPopupMenu"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButtonActionPerformed", true ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 390, 130 )
} )
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
name: "menuBar"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu3"
"text": "main menu"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem50"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu4"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem9"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem10"
"text": "text text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem11"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu8"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu21"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem81"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem82"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem83"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem41"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem42"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem43"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem44"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem45"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem46"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem12"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem13"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem14"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem2"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu5"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem15"
"text": "text bla bla"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem16"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem17"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem18"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem19"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem20"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem21"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem22"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem23"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem24"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem25"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem26"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem27"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem28"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem29"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu6"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem30"
"text": "text o text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem31"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem32"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu9"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem47"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem48"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem49"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem33"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem34"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem3"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem4"
"text": "longer text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem5"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem6"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem7"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem8"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu7"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem35"
"text": "text abc"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem37"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem36"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem38"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem39"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem40"
"text": "text"
} )
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 175 )
} )
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
name: "popupMenu1"
auxiliary() {
"JavaCodeGenerator.className": "PopupMenu"
}
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem54"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem51"
"text": "text text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu10"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem57"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem58"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu14"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu18"
"text": "text"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu19"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem76"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem77"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem78"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu20"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem73"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem74"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem75"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem79"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem80"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem70"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem71"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem72"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem59"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem60"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem52"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu11"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem61"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem62"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem63"
"text": "text"
} )
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu12"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem64"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem65"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem66"
"text": "text"
} )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem53"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem55"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem56"
"text": "text"
} )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu13"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem67"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem68"
"text": "text"
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem69"
"text": "text"
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 275, 175 )
} )
}
}

View File

@@ -24,6 +24,7 @@ import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
@@ -56,20 +57,22 @@ public class FlatScreenshotsBackground
black.setOpaque( false );
black.setVerticalAlignment( SwingConstants.TOP );
black.addActionListener( e -> {
if( black.isSelected() ) {
if( black.isSelected() )
FlatDarkLaf.setup();
FlatLaf.updateUI();
frame.getContentPane().setBackground( Color.black );
} else {
else
FlatLightLaf.setup();
FlatLaf.updateUI();
frame.getContentPane().setBackground( Color.white );
}
FlatLaf.updateUI();
Color color = black.isSelected() ? Color.black : Color.white;
frame.getContentPane().setBackground( color );
frame.getRootPane().putClientProperty( FlatClientProperties.TITLE_BAR_BACKGROUND, color );
frame.repaint();
} );
frame.getContentPane().add( black );
frame.getContentPane().setBackground( Color.white );
frame.getRootPane().putClientProperty( FlatClientProperties.TITLE_BAR_BACKGROUND, Color.white );
frame.setExtendedState( JFrame.MAXIMIZED_BOTH );
frame.setVisible( true );
} );

View File

@@ -62,6 +62,13 @@ public class FlatSwingXTest
monthView1.setUnselectableDates( calendar.getTime() );
table.setDefaultEditor( Date.class, new DatePickerCellEditor() );
// status bar
statusBar1.add( new JLabel( "Ready" ), new JXStatusBar.Constraint( 100 ) );
statusBar1.add( new JLabel( "0 files loaded" ), new JXStatusBar.Constraint( 100 ) );
JProgressBar statusProgressBar = new JProgressBar();
statusProgressBar.setValue( 50 );
statusBar1.add( statusProgressBar, new JXStatusBar.Constraint( JXStatusBar.Constraint.ResizeBehavior.FILL ) );
}
private void busyChanged() {
@@ -129,6 +136,8 @@ public class FlatSwingXTest
JXSearchField xSearchField2 = new JXSearchField();
JXSearchField xSearchField3 = new JXSearchField();
JXSearchField xSearchField4 = new JXSearchField();
JLabel label12 = new JLabel();
statusBar1 = new JXStatusBar();
JButton button1 = new JButton();
JButton button2 = new JButton();
@@ -153,6 +162,7 @@ public class FlatSwingXTest
"[]" +
"[]" +
"[]" +
"[]" +
"[37]"));
//---- label1 ----
@@ -456,6 +466,11 @@ public class FlatSwingXTest
xSearchField4.setText("abc");
add(xSearchField4, "cell 2 10,growx");
//---- label12 ----
label12.setText("JXStatusBar:");
add(label12, "cell 0 11");
add(statusBar1, "cell 1 11 3 1,grow");
//---- button1 ----
button1.setText("<");
@@ -476,5 +491,6 @@ public class FlatSwingXTest
private JXBusyLabel xBusyLabel2;
private JCheckBox busyCheckBox;
private JTable table;
private JXStatusBar statusBar1;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
JFDML JFormDesigner: "7.0.5.0.404" Java: "17" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left][][][][fill]"
"$rowConstraints": "[]0[][]0[top][][][][][][][][37]"
"$rowConstraints": "[]0[][]0[top][][][][][][][][][37]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
@@ -388,9 +388,23 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 10,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label12"
"text": "JXStatusBar:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 11"
} )
add( new FormComponent( "org.jdesktop.swingx.JXStatusBar" ) {
name: "statusBar1"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 11 3 1,grow"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 700, 600 )
"size": new java.awt.Dimension( 795, 600 )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button1"

View File

@@ -263,6 +263,7 @@ OptionPane.icon.foreground = #fff
#---- PasswordField ----
PasswordField.focusedBackground = #ff8
PasswordField.revealIconColor = #00f
#---- Popup ----
@@ -275,6 +276,8 @@ Popup.dropShadowInsets = -6,6,6,6
#---- PopupMenu ----
PopupMenu.borderColor = #00f
PopupMenu.scrollArrowColor = #00f
PopupMenu.hoverScrollArrowBackground = #0f0
#---- PopupMenuSeparator ----

View File

@@ -2,15 +2,23 @@ FlatLaf Theme Editor
====================
This sub-project contains the FlatLaf Theme Editor that supports editing FlatLaf
theme properties files.
theme properties files. See
[Theme Editor documentation](https://www.formdev.com/flatlaf/theme-editor/) for
details and downloads.
![Theme Editor](../images/theme-editor@1.5x.png)
Download
--------
[![Download Demo](https://download.formdev.com/flatlaf/images/download-theme-editor.svg)](https://download.formdev.com/flatlaf/flatlaf-theme-editor-latest.jar)
Run with `java -jar flatlaf-theme-editor-<version>.jar` (or double-click it).
Requires Java 8 or newer.
### Snapshot
[![Download Demo](https://download.formdev.com/flatlaf/images/download-theme-editor-snapshot.svg)](https://download.formdev.com/flatlaf/snapshots/flatlaf-theme-editor-latest.jar)
Run with `java -jar flatlaf-theme-editor-<version>.jar` (or double-click it).
Requires Java 8 or newer.

View File

@@ -575,6 +575,8 @@ PopupMenu.borderInsets
PopupMenu.consumeEventOnClose
PopupMenu.font
PopupMenu.foreground
PopupMenu.hoverScrollArrowBackground
PopupMenu.scrollArrowColor
PopupMenu.selectedWindowInputMapBindings
PopupMenu.selectedWindowInputMapBindings.RightToLeft
PopupMenuSeparator.height
@@ -658,6 +660,7 @@ ScrollBar.hoverThumbColor
ScrollBar.hoverThumbWithTrack
ScrollBar.hoverTrackColor
ScrollBar.maximumThumbSize
ScrollBar.minimumButtonSize
ScrollBar.minimumThumbSize
ScrollBar.pressedButtonBackground
ScrollBar.pressedThumbColor

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB