mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-10 22:17:13 -06:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ba9fc6c1c | ||
|
|
0a9ecd66a9 | ||
|
|
6991d6729e | ||
|
|
1462636e97 | ||
|
|
7e59a7f4af | ||
|
|
e9a21848bc | ||
|
|
1dcb251ecb | ||
|
|
3f33543cee | ||
|
|
84bd2088f2 | ||
|
|
4f4a3132c5 | ||
|
|
e064c934cb | ||
|
|
16fc3cabf2 | ||
|
|
7e002ff6c2 | ||
|
|
323c0c62c3 | ||
|
|
ff5bd301cc | ||
|
|
c37712b0f0 | ||
|
|
ee9e238592 | ||
|
|
da5d6fa157 | ||
|
|
d471f08b15 | ||
|
|
b97424f767 | ||
|
|
c29a276188 | ||
|
|
d1694aa8bd | ||
|
|
570cf6fc51 | ||
|
|
8eab86e489 | ||
|
|
566568f61a | ||
|
|
56a73a4d17 | ||
|
|
656d25b75e | ||
|
|
dcdc80ade3 | ||
|
|
09f2d65d5e | ||
|
|
b304d46f7e | ||
|
|
3391f971ec | ||
|
|
778fed27a5 | ||
|
|
1755dbc877 | ||
|
|
4e6f538519 | ||
|
|
a6ecb0ef85 | ||
|
|
438ec6ac5c | ||
|
|
8089e66642 | ||
|
|
d27e0561f2 | ||
|
|
97b21bfa8b | ||
|
|
ec4343ed30 | ||
|
|
948decb3b5 | ||
|
|
d510fee7f6 | ||
|
|
70b7a3d662 | ||
|
|
b142a6f31e | ||
|
|
14705a9b30 | ||
|
|
32b0f1ba10 | ||
|
|
cbffdf4900 | ||
|
|
1238da5e54 | ||
|
|
cba203be09 | ||
|
|
d89c6156b9 | ||
|
|
e06475b3b7 | ||
|
|
5ff99bd45e | ||
|
|
127dd6ac41 | ||
|
|
9e05384513 | ||
|
|
9ffda72ae3 | ||
|
|
72a4c00e72 | ||
|
|
c95e95ef67 | ||
|
|
0c0d4bffbf | ||
|
|
2a494b1d60 | ||
|
|
1463723e52 | ||
|
|
9ade48d078 | ||
|
|
7ba8274fd4 | ||
|
|
238443074c | ||
|
|
0decbec595 | ||
|
|
0eb77c7f72 | ||
|
|
f05df0db0a | ||
|
|
13fbaf1f74 | ||
|
|
969d2642de | ||
|
|
17ce6d39b4 | ||
|
|
261d2b1fe8 | ||
|
|
a54aeb3838 | ||
|
|
cc4f9a9db5 | ||
|
|
a311bac89b | ||
|
|
029f273dd9 | ||
|
|
bbbdd7e4d3 | ||
|
|
3f3ef6b24f | ||
|
|
8c3dfd4a36 | ||
|
|
af57599df9 |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -33,10 +33,11 @@ jobs:
|
||||
- 11 # LTS
|
||||
- 17 # LTS
|
||||
- 21 # LTS
|
||||
- 23 # latest
|
||||
toolchain: [""]
|
||||
include:
|
||||
- java: 21
|
||||
toolchain: 22 # latest
|
||||
# include:
|
||||
# - java: 21
|
||||
# toolchain: 22 # latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
153
CHANGELOG.md
153
CHANGELOG.md
@@ -1,6 +1,149 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 3.5.4
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- HTML: Fixed NPE when using HTML text on a component with `null` font. (issue
|
||||
#930; PR #931; regression in 3.5)
|
||||
- Linux: Fixed NPE when using FlatLaf window decorations and switching theme.
|
||||
(issue #933; regression in 3.5.3)
|
||||
|
||||
|
||||
## 3.5.3
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- HTML: Fixed wrong rendering if HTML text contains `<style>` tag with
|
||||
attributes (e.g. `<style type='text/css'>`). (issue #905; regression in 3.5.1)
|
||||
- FlatLaf window decorations:
|
||||
- Windows: Fixed possible deadlock with TabbedPane in window title area in
|
||||
"full window content" mode. (issue #909)
|
||||
- Windows: Fixed wrong layout in maximized frame after changing screen scale
|
||||
factor. (issue #904)
|
||||
- Linux: Fixed continuous cursor toggling between resize and standard cursor
|
||||
when resizing window. (issue #907)
|
||||
- Fixed sometimes broken window moving with SplitPane in window title area in
|
||||
"full window content" mode. (issue #926)
|
||||
- Popup: On Windows 10, fixed misplaced popup drop shadow. (issue #911;
|
||||
regression in 3.5)
|
||||
- Popup: Fixed NPE if `GraphicsConfiguration` is `null` on Windows. (issue #921)
|
||||
- Theme Editor: Fixed using color picker on secondary screen.
|
||||
- Fixed detection of Windows 11 if custom exe launcher does not specify Windows
|
||||
10+ compatibility in application manifest. (issue #916)
|
||||
- Linux: Fixed slightly different font size (or letter width) used to paint HTML
|
||||
text when default font family is _Cantarell_ (e.g. on Fedora). (issue #912)
|
||||
|
||||
#### Other Changes
|
||||
|
||||
- Class `FlatPropertiesLaf` now supports FlatLaf macOS themes as base themes.
|
||||
|
||||
|
||||
## 3.5.2
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- Windows: Fixed repaint issues (ghosting) on some systems (probably depending
|
||||
on graphics card/driver). This is done by setting Java system property
|
||||
`sun.java2d.d3d.onscreen` to `false` (but only if `sun.java2d.d3d.onscreen`,
|
||||
`sun.java2d.d3d` and `sun.java2d.noddraw` are not yet set), which disables
|
||||
usage of Windows Direct3D (DirectX) onscreen surfaces. Component rendering
|
||||
still uses Direct3D. (issue #887)
|
||||
- FlatLaf window decorations:
|
||||
- Iconify/maximize/close buttons did not fill whole title bar height, if some
|
||||
custom component in menu bar increases title bar height. (issue #897)
|
||||
- Windows: Fixed possible application freeze when using custom component that
|
||||
overrides `Component.contains(int x, int y)` and invokes
|
||||
`SwingUtilities.convertPoint()` (or similar) from the overridden method.
|
||||
(issue #878)
|
||||
- TextComponents: Fixed too fast scrolling in multi-line text components when
|
||||
using touchpads (e.g. on macOS). (issue #892)
|
||||
- ToolBar: Fixed endless loop if button in Toolbar has focus and is made
|
||||
invisible. (issue #884)
|
||||
|
||||
#### Other Changes
|
||||
|
||||
- FlatLaf window decorations: Added client property `JRootPane.titleBarHeight`
|
||||
to allow specifying a (larger) preferred height for the title bar. (issue
|
||||
#897)
|
||||
- Added system property `flatlaf.useRoundedPopupBorder` to allow disabling
|
||||
native rounded popup borders on Windows 11 and macOS. On macOS 14.4+, where
|
||||
rounded popup borders are disabled since FlatLaf 3.5 because of occasional
|
||||
problems, you can use this to enable rounded popup borders (at your risk).
|
||||
|
||||
|
||||
## 3.5.1
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- HTML: Fixed occasional cutoff wrapped text when using multi-line text in HTML
|
||||
tags `<h1>`...`<h6>`, `<code>`, `<kbd>`, `<big>`, `<small>` or `<samp>`.
|
||||
(issue #873; regression in 3.5)
|
||||
- Popup: Fixed `UnsupportedOperationException: PERPIXEL_TRANSLUCENT translucency
|
||||
is not supported` exception on Haiku OS when showing popup (partly) outside of
|
||||
window. (issue #869)
|
||||
- HiDPI: Fixed occasional wrong repaint areas when using
|
||||
`HiDPIUtils.installHiDPIRepaintManager()`. (see PR #864)
|
||||
- Added system property `flatlaf.useSubMenuSafeTriangle` to allow disabling
|
||||
submenu safe triangle (PR #490) for
|
||||
[SWTSwing](https://github.com/Chrriis/SWTSwing). (issue #870)
|
||||
|
||||
|
||||
## 3.5
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- Table: Support rounded selection. (PR #856)
|
||||
- Button and ToggleButton: Added border colors for pressed and selected states.
|
||||
(issue #848)
|
||||
- Label: Support painting background with rounded corners. (issue #842)
|
||||
- Popup: Fixed flicker of popups (e.g. tooltips) while they are moving (e.g.
|
||||
following mouse pointer). (issues #832 and #672)
|
||||
- FileChooser: Wrap shortcuts in scroll pane. (issue #828)
|
||||
- Theme Editor: On macOS, use larger window title bar. (PR #779)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- macOS: Disabled rounded popup border (see PR #772) on macOS 14.4+ because it
|
||||
may freeze the application and crash the macOS WindowServer process (reports
|
||||
vary from Finder restarts to OS restarts). This is a temporary change until a
|
||||
solution is found. See NetBeans issues
|
||||
[apache/netbeans#7560](https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215)
|
||||
and
|
||||
[apache/netbeans#6647](https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442).
|
||||
- FlatLaf window decorations: Window top border on Windows 10 in "full window
|
||||
content" mode was not fully repainted when activating or deactivating window.
|
||||
(issue #809)
|
||||
- Button and ToggleButton: UI properties `[Toggle]Button.selectedForeground` and
|
||||
`[Toggle]Button.pressedForeground` did not work for HTML text. (issue #848)
|
||||
- HTML: Fixed font sizes for HTML tags `<h1>`...`<h6>`, `<code>`, `<kbd>`,
|
||||
`<big>`, `<small>` and `<samp>` in HTML text for components Button, CheckBox,
|
||||
RadioButton, MenuItem (and subclasses), JideLabel, JideButton, JXBusyLabel and
|
||||
JXHyperlink. Also fixed for Label and ToolTip if using Java 11+.
|
||||
- ScrollPane: Fixed/improved border painting at 125% - 175% scaling to avoid
|
||||
different border thicknesses. (issue #743)
|
||||
- Table: Fixed painting of alternating rows below table if auto-resize mode is
|
||||
`JTable.AUTO_RESIZE_OFF` and table width is smaller than scroll pane (was not
|
||||
updated when table width changed and was painted on wrong side in
|
||||
right-to-left component orientation).
|
||||
- Theme Editor: Fixed occasional empty window on startup on macOS.
|
||||
- FlatLaf window decorations: Fixed black line sometimes painted on top of
|
||||
(native) window border on Windows 11. (issue #852)
|
||||
- HiDPI: Fixed incomplete component paintings at 125% or 175% scaling on Windows
|
||||
where sometimes a 1px wide area at the right or bottom component edge is not
|
||||
repainted. E.g. ScrollPane focus indicator border. (issues #860 and #582)
|
||||
|
||||
#### Incompatibilities
|
||||
|
||||
- ProgressBar: Log warning (including stack trace) when uninstalling
|
||||
indeterminate progress bar UI or using `JProgressBar.setIndeterminate(false)`
|
||||
not on AWT thread, because this may throw NPE in `FlatProgressBarUI.paint()`.
|
||||
(issues #841 and #830)
|
||||
- Panel: Rounded background of panel with rounded corners is now painted even if
|
||||
panel is not opaque. (issue #840)
|
||||
|
||||
|
||||
## 3.4.1
|
||||
|
||||
#### Fixed bugs
|
||||
@@ -10,7 +153,7 @@ FlatLaf Change Log
|
||||
- TabbedPane: Fixed swapped back and forward scroll buttons when using
|
||||
`TabbedPane.scrollButtonsPlacement = trailing` (regression in FlatLaf 3.3).
|
||||
- Fixed missing window top border on Windows 10 in "full window content" mode.
|
||||
(issue 809)
|
||||
(issue #809)
|
||||
- Extras:
|
||||
- `FlatSVGIcon` color filters now support linear gradients. (PR #817)
|
||||
- `FlatSVGIcon`: Use log level `CONFIG` instead of `SEVERE` and allow
|
||||
@@ -54,8 +197,8 @@ FlatLaf Change Log
|
||||
- Improved log messages for loading fails.
|
||||
- Fonts: Updated **Inter** to
|
||||
[v4.0](https://github.com/rsms/inter/releases/tag/v4.0).
|
||||
- Table: Select all text in cell editor when starting editing using `F2` key.
|
||||
(issue 652)
|
||||
- Table: Select all text in cell editor when starting editing using `F2` key on
|
||||
Windows or Linux. (issue #652)
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
@@ -83,7 +226,7 @@ FlatLaf Change Log
|
||||
#### Fixed bugs
|
||||
|
||||
- Button and ToggleButton: Selected buttons did not use explicitly set
|
||||
foreground color. (issue 756)
|
||||
foreground color. (issue #756)
|
||||
- FileChooser: Catch NPE in Java 21 when getting icon for `.exe` files that use
|
||||
default Windows exe icon. (see
|
||||
[JDK-8320692](https://bugs.openjdk.org/browse/JDK-8320692))
|
||||
@@ -836,7 +979,7 @@ FlatLaf Change Log
|
||||
- Native window decorations (Windows 10 only):
|
||||
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
|
||||
- When window is initially shown, fill background with window background color
|
||||
(instead of white), which avoids flickering in dark themes. (issue 339)
|
||||
(instead of white), which avoids flickering in dark themes. (issue #339)
|
||||
- When resizing a window at the right/bottom edge, then first fill the new
|
||||
space with the window background color (instead of black) before the layout
|
||||
is updated.
|
||||
|
||||
10
README.md
10
README.md
@@ -33,14 +33,20 @@ FlatLaf can use 3rd party themes created for IntelliJ Platform (see
|
||||
Sponsors
|
||||
--------
|
||||
|
||||
### Current Sponsors
|
||||
|
||||
[](https://www.formdev.com/flatlaf/sponsor/)
|
||||
|
||||
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
||||
|
||||
### Previous Sponsors
|
||||
|
||||
<a href="https://www.ej-technologies.com/"><img src="https://www.formdev.com/flatlaf/sponsor/ej-technologies.png" width="200" alt="ej-technologies" title="ej-technologies - Java APM, Java Profiler, Java Installer Builder"></a>
|
||||
|
||||
<a href="https://www.dbvis.com/"><img src="https://www.formdev.com/flatlaf/sponsor/dbvisualizer.svg" width="200" alt="DbVisualizer" title="DbVisualizer - SQL Client and Editor"></a>
|
||||
|
||||
<a href="https://www.dscsag.com/"><img src="https://www.formdev.com/flatlaf/sponsor/DSC.png" height="48" alt="DSC Software AG" title="DSC Software AG - Your Companion for Integrative PLM"></a>
|
||||
|
||||
[Become a Sponsor](https://www.formdev.com/flatlaf/sponsor/)
|
||||
|
||||
Demo
|
||||
----
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Signature file v4.1
|
||||
#Version 3.4
|
||||
#Version 3.5.2
|
||||
|
||||
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
|
||||
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
|
||||
@@ -100,6 +100,7 @@ fld public final static java.lang.String TEXT_FIELD_TRAILING_COMPONENT = "JTextF
|
||||
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_HEIGHT = "JRootPane.titleBarHeight"
|
||||
fld public final static java.lang.String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"
|
||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"
|
||||
fld public final static java.lang.String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"
|
||||
@@ -223,6 +224,7 @@ meth public static java.util.Map<java.lang.String,java.lang.Class<?>> getStyleab
|
||||
meth public static java.util.Map<java.lang.String,java.lang.String> getGlobalExtraDefaults()
|
||||
meth public static java.util.function.Function<java.lang.String,java.awt.Color> getSystemColorGetter()
|
||||
meth public static javax.swing.UIDefaults$ActiveValue createActiveFontValue(float)
|
||||
meth public static void disableWindowsD3Donscreen()
|
||||
meth public static void hideMnemonics()
|
||||
meth public static void initIconColors(javax.swing.UIDefaults,boolean)
|
||||
meth public static void installLafInfo(java.lang.String,java.lang.Class<? extends javax.swing.LookAndFeel>)
|
||||
@@ -296,6 +298,8 @@ fld public final static java.lang.String UPDATE_UI_ON_SYSTEM_FONT_CHANGE = "flat
|
||||
fld public final static java.lang.String USE_JETBRAINS_CUSTOM_DECORATIONS = "flatlaf.useJetBrainsCustomDecorations"
|
||||
anno 0 java.lang.Deprecated()
|
||||
fld public final static java.lang.String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary"
|
||||
fld public final static java.lang.String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder"
|
||||
fld public final static java.lang.String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle"
|
||||
fld public final static java.lang.String USE_TEXT_Y_CORRECTION = "flatlaf.useTextYCorrection"
|
||||
fld public final static java.lang.String USE_UBUNTU_FONT = "flatlaf.useUbuntuFont"
|
||||
fld public final static java.lang.String USE_WINDOW_DECORATIONS = "flatlaf.useWindowDecorations"
|
||||
@@ -629,16 +633,33 @@ hfds alpha,hsl,rgb
|
||||
|
||||
CLSS public com.formdev.flatlaf.util.HiDPIUtils
|
||||
cons public init()
|
||||
innr public abstract interface static DirtyRegionCallback
|
||||
innr public abstract interface static Painter
|
||||
innr public static HiDPIRepaintManager
|
||||
meth public static float computeTextYCorrection(java.awt.Graphics2D)
|
||||
meth public static java.awt.Graphics2D createGraphicsTextYCorrection(java.awt.Graphics2D)
|
||||
meth public static void addDirtyRegion(javax.swing.JComponent,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$DirtyRegionCallback)
|
||||
meth public static void drawStringUnderlineCharAtWithYCorrection(javax.swing.JComponent,java.awt.Graphics2D,java.lang.String,int,int,int)
|
||||
meth public static void drawStringWithYCorrection(javax.swing.JComponent,java.awt.Graphics2D,java.lang.String,int,int)
|
||||
meth public static void installHiDPIRepaintManager()
|
||||
meth public static void paintAtScale1x(java.awt.Graphics2D,int,int,int,int,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||
meth public static void paintAtScale1x(java.awt.Graphics2D,javax.swing.JComponent,com.formdev.flatlaf.util.HiDPIUtils$Painter)
|
||||
meth public static void repaint(java.awt.Component)
|
||||
meth public static void repaint(java.awt.Component,int,int,int,int)
|
||||
meth public static void repaint(java.awt.Component,java.awt.Rectangle)
|
||||
supr java.lang.Object
|
||||
hfds CORRECTION_INTER,CORRECTION_OPEN_SANS,CORRECTION_SEGOE_UI,CORRECTION_TAHOMA,SCALE_FACTORS,useDebugScaleFactor,useTextYCorrection
|
||||
|
||||
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$DirtyRegionCallback
|
||||
outer com.formdev.flatlaf.util.HiDPIUtils
|
||||
meth public abstract void addDirtyRegion(javax.swing.JComponent,int,int,int,int)
|
||||
|
||||
CLSS public static com.formdev.flatlaf.util.HiDPIUtils$HiDPIRepaintManager
|
||||
outer com.formdev.flatlaf.util.HiDPIUtils
|
||||
cons public init()
|
||||
meth public void addDirtyRegion(javax.swing.JComponent,int,int,int,int)
|
||||
supr javax.swing.RepaintManager
|
||||
|
||||
CLSS public abstract interface static com.formdev.flatlaf.util.HiDPIUtils$Painter
|
||||
outer com.formdev.flatlaf.util.HiDPIUtils
|
||||
meth public abstract void paint(java.awt.Graphics2D,int,int,int,int,double)
|
||||
@@ -1137,6 +1158,31 @@ meth public void provideErrorFeedback(java.awt.Component)
|
||||
meth public void uninitialize()
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public javax.swing.RepaintManager
|
||||
cons public init()
|
||||
meth public boolean isCompletelyDirty(javax.swing.JComponent)
|
||||
meth public boolean isDoubleBufferingEnabled()
|
||||
meth public java.awt.Dimension getDoubleBufferMaximumSize()
|
||||
meth public java.awt.Image getOffscreenBuffer(java.awt.Component,int,int)
|
||||
meth public java.awt.Image getVolatileOffscreenBuffer(java.awt.Component,int,int)
|
||||
meth public java.awt.Rectangle getDirtyRegion(javax.swing.JComponent)
|
||||
meth public java.lang.String toString()
|
||||
meth public static javax.swing.RepaintManager currentManager(java.awt.Component)
|
||||
meth public static javax.swing.RepaintManager currentManager(javax.swing.JComponent)
|
||||
meth public static void setCurrentManager(javax.swing.RepaintManager)
|
||||
meth public void addDirtyRegion(java.applet.Applet,int,int,int,int)
|
||||
meth public void addDirtyRegion(java.awt.Window,int,int,int,int)
|
||||
meth public void addDirtyRegion(javax.swing.JComponent,int,int,int,int)
|
||||
meth public void addInvalidComponent(javax.swing.JComponent)
|
||||
meth public void markCompletelyClean(javax.swing.JComponent)
|
||||
meth public void markCompletelyDirty(javax.swing.JComponent)
|
||||
meth public void paintDirtyRegions()
|
||||
meth public void removeInvalidComponent(javax.swing.JComponent)
|
||||
meth public void setDoubleBufferMaximumSize(java.awt.Dimension)
|
||||
meth public void setDoubleBufferingEnabled(boolean)
|
||||
meth public void validateInvalidComponents()
|
||||
supr java.lang.Object
|
||||
|
||||
CLSS public abstract javax.swing.border.AbstractBorder
|
||||
cons public init()
|
||||
intf java.io.Serializable
|
||||
|
||||
@@ -461,7 +461,7 @@ public interface FlatClientProperties
|
||||
* {@link FlatSystemProperties#USE_WINDOW_DECORATIONS}, but higher priority
|
||||
* than UI default {@code TitlePane.useWindowDecorations}.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
@@ -481,7 +481,7 @@ public interface FlatClientProperties
|
||||
* {@link FlatSystemProperties#MENUBAR_EMBEDDED}, but higher priority
|
||||
* than UI default {@code TitlePane.menuBarEmbedded}.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
@@ -507,6 +507,8 @@ public interface FlatClientProperties
|
||||
* The user can left-click-and-drag on the title bar area to move the window,
|
||||
* except when clicking on a component that processes mouse events (e.g. buttons or menus).
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
@@ -537,7 +539,7 @@ public interface FlatClientProperties
|
||||
* <p>
|
||||
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
@@ -553,6 +555,8 @@ public interface FlatClientProperties
|
||||
* Setting this shows/hides the windows title
|
||||
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
@@ -567,6 +571,8 @@ public interface FlatClientProperties
|
||||
* Setting this shows/hides the "iconify" button
|
||||
* for the {@code JFrame} that contains the root pane.
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
@@ -581,6 +587,8 @@ public interface FlatClientProperties
|
||||
* Setting this shows/hides the "maximize/restore" button
|
||||
* for the {@code JFrame} that contains the root pane.
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
@@ -595,6 +603,8 @@ public interface FlatClientProperties
|
||||
* Setting this shows/hides the "close" button
|
||||
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
@@ -605,7 +615,7 @@ public interface FlatClientProperties
|
||||
/**
|
||||
* Background color of window title bar (requires enabled window decorations).
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Color}
|
||||
@@ -617,7 +627,7 @@ public interface FlatClientProperties
|
||||
/**
|
||||
* Foreground color of window title bar (requires enabled window decorations).
|
||||
* <p>
|
||||
* (requires Window 10)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.awt.Color}
|
||||
@@ -626,10 +636,24 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
|
||||
|
||||
/**
|
||||
* Specifies the preferred height of title bar (requires enabled window decorations).
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}
|
||||
*
|
||||
* @since 3.5.2
|
||||
*/
|
||||
String TITLE_BAR_HEIGHT = "JRootPane.titleBarHeight";
|
||||
|
||||
/**
|
||||
* Specifies whether the glass pane should have full height and overlap the title bar,
|
||||
* if FlatLaf window decorations are enabled. Default is {@code false}.
|
||||
* <p>
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Toolkit;
|
||||
@@ -119,6 +120,46 @@ public abstract class FlatLaf
|
||||
private static String preferredSemiboldFontFamily;
|
||||
private static String preferredMonospacedFontFamily;
|
||||
|
||||
static {
|
||||
// see disableWindowsD3Donscreen() for details
|
||||
// https://github.com/JFormDesigner/FlatLaf/issues/887
|
||||
if( SystemInfo.isWindows &&
|
||||
System.getProperty( "sun.java2d.d3d.onscreen" ) == null &&
|
||||
System.getProperty( "sun.java2d.d3d" ) == null &&
|
||||
System.getProperty( "sun.java2d.noddraw" ) == null )
|
||||
System.setProperty( "sun.java2d.d3d.onscreen", "false" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable usage of Windows Direct3D (DirectX) onscreen surfaces because this may lead to
|
||||
* repaint issues (ghosting) on some systems (probably depending on graphics card/driver).
|
||||
* Problem occurs usually when a small heavy-weight popup window (menu, combobox, tooltip) is shown.
|
||||
* <p>
|
||||
* Sets system property {@code sun.java2d.d3d.onscreen} to {@code false},
|
||||
* but only if {@code sun.java2d.d3d.onscreen}, {@code sun.java2d.d3d}
|
||||
* and {@code sun.java2d.noddraw} are not yet set.
|
||||
* <p>
|
||||
* <strong>Note</strong>: Must be invoked very early before the graphics environment is created.
|
||||
* <p>
|
||||
* This method is automatically invoked when loading this class,
|
||||
* which is usually before the graphics environment is created.
|
||||
* E.g. when doing {@code FlatLightLaf.setup()} or
|
||||
* {@code UIManager.setLookAndFeel( "com.formdev.flatlaf.FlatLightLaf" )}.
|
||||
* <p>
|
||||
* However, it may be invoked too late if you use some methods from {@link UIManager}
|
||||
* of {@link GraphicsEnvironment} before setting look and feel.
|
||||
* E.g. {@link UIManager#put(Object, Object)}.
|
||||
* In that case invoke this method yourself very early.
|
||||
* <p>
|
||||
* <strong>Tip</strong>: How to find out when the graphics environment is created?
|
||||
* Set a breakpoint at constructor of class {@link GraphicsEnvironment} and look at the stack.
|
||||
*
|
||||
* @since 3.5.2
|
||||
*/
|
||||
public static void disableWindowsD3Donscreen() {
|
||||
// dummy method used to trigger invocation of "static {...}" block
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the application look and feel to the given LaF
|
||||
* using {@link UIManager#setLookAndFeel(javax.swing.LookAndFeel)}.
|
||||
|
||||
@@ -23,13 +23,15 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
||||
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
||||
|
||||
/**
|
||||
* A Flat LaF that is able to load UI defaults from properties passed to the constructor.
|
||||
* <p>
|
||||
* Specify the base theme in the properties with {@code @baseTheme=<baseTheme>}.
|
||||
* Allowed values for {@code <baseTheme>} are {@code light} (the default), {@code dark},
|
||||
* {@code intellij} or {@code darcula}.
|
||||
* {@code intellij}, {@code darcula}, {@code maclight} or {@code macdark}.
|
||||
* <p>
|
||||
* The properties are applied after loading the base theme and may overwrite base properties.
|
||||
* All features of FlatLaf properties files are available.
|
||||
@@ -71,7 +73,8 @@ public class FlatPropertiesLaf
|
||||
this.properties = properties;
|
||||
|
||||
baseTheme = properties.getProperty( "@baseTheme", "light" );
|
||||
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme );
|
||||
dark = "dark".equalsIgnoreCase( baseTheme ) || "darcula".equalsIgnoreCase( baseTheme ) ||
|
||||
"macdark".equalsIgnoreCase( baseTheme );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,6 +119,16 @@ public class FlatPropertiesLaf
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
lafClasses.add( FlatDarculaLaf.class );
|
||||
break;
|
||||
|
||||
case "maclight":
|
||||
lafClasses.add( FlatLightLaf.class );
|
||||
lafClasses.add( FlatMacLightLaf.class );
|
||||
break;
|
||||
|
||||
case "macdark":
|
||||
lafClasses.add( FlatDarkLaf.class );
|
||||
lafClasses.add( FlatMacDarkLaf.class );
|
||||
break;
|
||||
}
|
||||
return lafClasses;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public interface FlatSystemProperties
|
||||
* {@link FlatClientProperties#USE_WINDOW_DECORATIONS} and
|
||||
* UI default {@code TitlePane.useWindowDecorations}.
|
||||
* <p>
|
||||
* (requires Window 10/11)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> none
|
||||
@@ -99,7 +99,7 @@ public interface FlatSystemProperties
|
||||
* Setting this to {@code false} disables using JetBrains Runtime custom window decorations.
|
||||
* Then FlatLaf native window decorations are used.
|
||||
* <p>
|
||||
* (requires Window 10/11)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code false} (since v2; was {@code true} in v1)
|
||||
@@ -120,7 +120,7 @@ public interface FlatSystemProperties
|
||||
* {@link FlatClientProperties#MENU_BAR_EMBEDDED} and
|
||||
* UI default {@code TitlePane.menuBarEmbedded}.
|
||||
* <p>
|
||||
* (requires Window 10/11)
|
||||
* (requires Windows 10/11)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> none
|
||||
@@ -135,6 +135,18 @@ public interface FlatSystemProperties
|
||||
*/
|
||||
String ANIMATION = "flatlaf.animation";
|
||||
|
||||
/**
|
||||
* Specifies whether native rounded popup borders should be used (if supported by operating system).
|
||||
* <p>
|
||||
* (requires Windows 11 or macOS)
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}; except on macOS 14.4+ where it is {@code false}
|
||||
*
|
||||
* @since 3.5.2
|
||||
*/
|
||||
String USE_ROUNDED_POPUP_BORDER = "flatlaf.useRoundedPopupBorder";
|
||||
|
||||
/**
|
||||
* Specifies whether vertical text position is corrected when UI is scaled on HiDPI screens.
|
||||
* <p>
|
||||
@@ -204,6 +216,16 @@ public interface FlatSystemProperties
|
||||
*/
|
||||
String NATIVE_LIBRARY_PATH = "flatlaf.nativeLibraryPath";
|
||||
|
||||
/**
|
||||
* Specifies whether safe triangle is used to improve usability of submenus.
|
||||
* <p>
|
||||
* <strong>Allowed Values</strong> {@code false} and {@code true}<br>
|
||||
* <strong>Default</strong> {@code true}
|
||||
*
|
||||
* @since 3.5.1
|
||||
*/
|
||||
String USE_SUB_MENU_SAFE_TRIANGLE = "flatlaf.useSubMenuSafeTriangle";
|
||||
|
||||
/**
|
||||
* Checks whether a system property is set and returns {@code true} if its value
|
||||
* is {@code "true"} (case-insensitive), otherwise it returns {@code false}.
|
||||
|
||||
@@ -111,7 +111,7 @@ class LinuxFontPolicy
|
||||
if( logicalFamily != null )
|
||||
family = logicalFamily;
|
||||
|
||||
return createFontEx( family, style, size, dsize );
|
||||
return createFontEx( family, style, size );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,9 +121,9 @@ class LinuxFontPolicy
|
||||
* E.g. family 'URW Bookman Light' is not found, but 'URW Bookman' is found.
|
||||
* If still not found, then font of family 'Dialog' is returned.
|
||||
*/
|
||||
private static Font createFontEx( String family, int style, int size, double dsize ) {
|
||||
private static Font createFontEx( String family, int style, int size ) {
|
||||
for(;;) {
|
||||
Font font = createFont( family, style, size, dsize );
|
||||
Font font = FlatLaf.createCompositeFont( family, style, size );
|
||||
|
||||
if( Font.DIALOG.equals( family ) )
|
||||
return font;
|
||||
@@ -135,7 +135,7 @@ class LinuxFontPolicy
|
||||
// - character width is zero (e.g. font Cantarell; Fedora; Oracle Java 8)
|
||||
FontMetrics fm = StyleContext.getDefaultStyleContext().getFontMetrics( font );
|
||||
if( fm.getHeight() > size * 2 || fm.stringWidth( "a" ) == 0 )
|
||||
return createFont( Font.DIALOG, style, size, dsize );
|
||||
return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
|
||||
|
||||
return font;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ class LinuxFontPolicy
|
||||
// find last word in family
|
||||
int index = family.lastIndexOf( ' ' );
|
||||
if( index < 0 )
|
||||
return createFont( Font.DIALOG, style, size, dsize );
|
||||
return FlatLaf.createCompositeFont( Font.DIALOG, style, size );
|
||||
|
||||
// check whether last work contains some font weight (e.g. Ultra-Bold or Heavy)
|
||||
String lastWord = family.substring( index + 1 ).toLowerCase( Locale.ENGLISH );
|
||||
@@ -155,15 +155,6 @@ class LinuxFontPolicy
|
||||
}
|
||||
}
|
||||
|
||||
private static Font createFont( String family, int style, int size, double dsize ) {
|
||||
Font font = FlatLaf.createCompositeFont( family, style, size );
|
||||
|
||||
// set font size in floating points
|
||||
font = font.deriveFont( style, (float) dsize );
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
private static double getGnomeFontScale() {
|
||||
// do not scale font here if JRE scales
|
||||
if( isSystemScaling() )
|
||||
@@ -257,7 +248,7 @@ class LinuxFontPolicy
|
||||
if( size < 1 )
|
||||
size = 1;
|
||||
|
||||
return createFont( family, style, size, dsize );
|
||||
return FlatLaf.createCompositeFont( family, style, size );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "MixedMutabilityReturnType" ) // Error Prone
|
||||
|
||||
@@ -45,6 +45,7 @@ import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
* Improves usability of submenus by using a
|
||||
@@ -64,6 +65,7 @@ class SubMenuUsabilityHelper
|
||||
// https://github.com/apache/netbeans/issues/4231#issuecomment-1179616607
|
||||
private static SubMenuUsabilityHelper instance;
|
||||
|
||||
private boolean eventQueuePushNotSupported;
|
||||
private SubMenuEventQueue subMenuEventQueue;
|
||||
private SafeTrianglePainter safeTrianglePainter;
|
||||
private boolean changePending;
|
||||
@@ -83,6 +85,9 @@ class SubMenuUsabilityHelper
|
||||
if( instance != null )
|
||||
return false;
|
||||
|
||||
if( !FlatSystemProperties.getBoolean( FlatSystemProperties.USE_SUB_MENU_SAFE_TRIANGLE, true ) )
|
||||
return false;
|
||||
|
||||
instance = new SubMenuUsabilityHelper();
|
||||
MenuSelectionManager.defaultManager().addChangeListener( instance );
|
||||
return true;
|
||||
@@ -99,7 +104,7 @@ class SubMenuUsabilityHelper
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
if( !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
|
||||
if( eventQueuePushNotSupported || !FlatUIUtils.getUIBoolean( KEY_USE_SAFE_TRIANGLE, true ))
|
||||
return;
|
||||
|
||||
// handle menu selection change later, but only once in case of temporary changes
|
||||
@@ -173,8 +178,29 @@ debug*/
|
||||
targetBottomY = popupLocation.y + popupSize.height;
|
||||
|
||||
// install own event queue to suppress mouse events when mouse is moved within safe triangle
|
||||
if( subMenuEventQueue == null )
|
||||
subMenuEventQueue = new SubMenuEventQueue();
|
||||
if( subMenuEventQueue == null ) {
|
||||
SubMenuEventQueue queue = new SubMenuEventQueue();
|
||||
|
||||
try {
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
toolkit.getSystemEventQueue().push( queue );
|
||||
|
||||
// check whether push() worked
|
||||
// (e.g. SWTSwing uses own event queue that does not support push())
|
||||
if( toolkit.getSystemEventQueue() != queue ) {
|
||||
eventQueuePushNotSupported = true;
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to push submenu event queue. Disabling submenu safe triangle.", null );
|
||||
return;
|
||||
}
|
||||
|
||||
subMenuEventQueue = queue;
|
||||
} catch( RuntimeException ex ) {
|
||||
// catch runtime exception from EventQueue.push()
|
||||
eventQueuePushNotSupported = true;
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to push submenu event queue. Disabling submenu safe triangle.", ex );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// create safe triangle painter
|
||||
if( safeTrianglePainter == null && UIManager.getBoolean( KEY_SHOW_SAFE_TRIANGLE ) )
|
||||
@@ -247,8 +273,6 @@ debug*/
|
||||
}
|
||||
} );
|
||||
timeoutTimer.setRepeats( false );
|
||||
|
||||
Toolkit.getDefaultToolkit().getSystemEventQueue().push( this );
|
||||
}
|
||||
|
||||
void uninstall() {
|
||||
|
||||
@@ -638,14 +638,18 @@ class UIDefaultsLoader
|
||||
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
|
||||
List<String> parts = splitFunctionParams( value, ',' );
|
||||
Insets insets = parseInsets( value );
|
||||
ColorUIResource lineColor = (parts.size() >= 5)
|
||||
ColorUIResource lineColor = (parts.size() >= 5 && !parts.get( 4 ).isEmpty())
|
||||
? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
|
||||
: null;
|
||||
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty()) ? parseFloat( parts.get( 5 ) ) : 1f;
|
||||
int arc = (parts.size() >= 7) ? parseInteger( parts.get( 6 ) ) : 0;
|
||||
float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty())
|
||||
? parseFloat( parts.get( 5 ) )
|
||||
: 1f;
|
||||
int arc = (parts.size() >= 7) && !parts.get( 6 ).isEmpty()
|
||||
? parseInteger( parts.get( 6 ) )
|
||||
: -1;
|
||||
|
||||
return (LazyValue) t -> {
|
||||
return (lineColor != null)
|
||||
return (lineColor != null || arc > 0)
|
||||
? new FlatLineBorder( insets, lineColor, lineThickness, arc )
|
||||
: new FlatEmptyBorder( insets );
|
||||
};
|
||||
|
||||
@@ -57,6 +57,8 @@ public abstract class FlatAbstractIcon
|
||||
// g2.setColor( Color.blue );
|
||||
// g2.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
|
||||
|
||||
paintBackground( c, g2, x, y );
|
||||
|
||||
g2.translate( x, y );
|
||||
UIScale.scaleGraphics( g2 );
|
||||
|
||||
@@ -69,7 +71,11 @@ public abstract class FlatAbstractIcon
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void paintIcon( Component c, Graphics2D g2 );
|
||||
/** @since 3.5.2 */
|
||||
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||
}
|
||||
|
||||
protected abstract void paintIcon( Component c, Graphics2D g );
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
|
||||
@@ -60,23 +60,24 @@ public abstract class FlatWindowAbstractIcon
|
||||
|
||||
@Override
|
||||
protected void paintIcon( Component c, Graphics2D g ) {
|
||||
paintBackground( c, g );
|
||||
|
||||
g.setColor( getForeground( c ) );
|
||||
HiDPIUtils.paintAtScale1x( g, 0, 0, width, height, this::paintIconAt1x );
|
||||
}
|
||||
|
||||
protected abstract void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor );
|
||||
|
||||
protected void paintBackground( Component c, Graphics2D g ) {
|
||||
/** @since 3.5.2 */
|
||||
@Override
|
||||
protected void paintBackground( Component c, Graphics2D g, int x, int y ) {
|
||||
Color background = FlatButtonUI.buttonStateColor( c, null, null, null, hoverBackground, pressedBackground );
|
||||
if( background != null ) {
|
||||
// disable antialiasing for background rectangle painting to avoid blurry edges when scaled (e.g. at 125% or 175%)
|
||||
Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
|
||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
|
||||
|
||||
// fill background of whole component
|
||||
g.setColor( FlatUIUtils.deriveColor( background, c.getBackground() ) );
|
||||
g.fillRect( 0, 0, width, height );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
|
||||
g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public class FlatBorder
|
||||
Paint borderColor = (outlineColor != null) ? outlineColor : getBorderColor( c );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
focusWidth, 1, focusInnerWidth, borderWidth, arc,
|
||||
focusColor, borderColor, null );
|
||||
focusColor, borderColor, null, c instanceof JScrollPane );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
@@ -277,7 +277,7 @@ public class FlatBorder
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (unscaled) arc diameter of the border.
|
||||
* Returns the (unscaled) arc diameter of the border corners.
|
||||
*/
|
||||
protected int getArc( Component c ) {
|
||||
return 0;
|
||||
|
||||
@@ -42,6 +42,13 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.disabledBorderColor Color
|
||||
* @uiDefault Button.focusedBorderColor Color
|
||||
* @uiDefault Button.hoverBorderColor Color optional
|
||||
* @uiDefault Button.pressedBorderColor Color optional
|
||||
*
|
||||
* @uiDefault Button.selectedBorderColor Color optional
|
||||
* @uiDefault Button.disabledSelectedBorderColor Color optional
|
||||
* @uiDefault Button.focusedSelectedBorderColor Color optional
|
||||
* @uiDefault Button.hoverSelectedBorderColor Color optional
|
||||
* @uiDefault Button.pressedSelectedBorderColor Color optional
|
||||
*
|
||||
* @uiDefault Button.default.borderWidth int or float
|
||||
* @uiDefault Button.default.borderColor Color
|
||||
@@ -49,6 +56,7 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Button.default.endBorderColor Color optional; if set, a gradient paint is used
|
||||
* @uiDefault Button.default.focusedBorderColor Color
|
||||
* @uiDefault Button.default.focusColor Color
|
||||
* @uiDefault Button.default.pressedBorderColor Color optional
|
||||
* @uiDefault Button.default.hoverBorderColor Color optional
|
||||
*
|
||||
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1.5
|
||||
@@ -65,6 +73,13 @@ public class FlatButtonBorder
|
||||
|
||||
protected Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
|
||||
@Styleable protected Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
|
||||
/** @since 3.5 */ @Styleable protected Color pressedBorderColor = UIManager.getColor( "Button.pressedBorderColor" );
|
||||
|
||||
/** @since 3.5 */ @Styleable protected Color selectedBorderColor = UIManager.getColor( "Button.selectedBorderColor" );
|
||||
/** @since 3.5 */ @Styleable protected Color disabledSelectedBorderColor = UIManager.getColor( "Button.disabledSelectedBorderColor" );
|
||||
/** @since 3.5 */ @Styleable protected Color focusedSelectedBorderColor = UIManager.getColor( "Button.focusedSelectedBorderColor" );
|
||||
/** @since 3.5 */ @Styleable protected Color hoverSelectedBorderColor = UIManager.getColor( "Button.hoverSelectedBorderColor" );
|
||||
/** @since 3.5 */ @Styleable protected Color pressedSelectedBorderColor = UIManager.getColor( "Button.pressedSelectedBorderColor" );
|
||||
|
||||
@Styleable(dot=true) protected float defaultBorderWidth = FlatUIUtils.getUIFloat( "Button.default.borderWidth", 1 );
|
||||
@Styleable(dot=true) protected Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
|
||||
@@ -72,6 +87,7 @@ public class FlatButtonBorder
|
||||
@Styleable(dot=true) protected Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
|
||||
@Styleable(dot=true) protected Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
|
||||
@Styleable(dot=true) protected Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
|
||||
/** @since 3.5 */ @Styleable(dot=true) protected Color defaultPressedBorderColor = UIManager.getColor( "Button.default.pressedBorderColor" );
|
||||
|
||||
/** @since 1.4 */ @Styleable(dot=true) protected float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
|
||||
/** @since 1.4 */ @Styleable(dot=true) protected Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
|
||||
@@ -139,12 +155,13 @@ public class FlatButtonBorder
|
||||
@Override
|
||||
protected Paint getBorderColor( Component c ) {
|
||||
boolean def = FlatButtonUI.isDefaultButton( c );
|
||||
boolean selected = (c instanceof AbstractButton && ((AbstractButton)c).isSelected());
|
||||
Paint color = FlatButtonUI.buttonStateColor( c,
|
||||
def ? defaultBorderColor : borderColor,
|
||||
disabledBorderColor,
|
||||
def ? defaultFocusedBorderColor : focusedBorderColor,
|
||||
def ? defaultHoverBorderColor : hoverBorderColor,
|
||||
null );
|
||||
def ? defaultBorderColor : ((selected && selectedBorderColor != null) ? selectedBorderColor : borderColor),
|
||||
(selected && disabledSelectedBorderColor != null) ? disabledSelectedBorderColor : disabledBorderColor,
|
||||
def ? defaultFocusedBorderColor : ((selected && focusedSelectedBorderColor != null) ? focusedSelectedBorderColor : focusedBorderColor),
|
||||
def ? defaultHoverBorderColor : ((selected && hoverSelectedBorderColor != null) ? hoverSelectedBorderColor : hoverBorderColor),
|
||||
def ? defaultPressedBorderColor : ((selected && pressedSelectedBorderColor != null) ? pressedSelectedBorderColor : pressedBorderColor) );
|
||||
|
||||
// change to gradient paint if start/end colors are specified
|
||||
Color startBg = def ? defaultBorderColor : borderColor;
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Map;
|
||||
@@ -61,6 +62,7 @@ import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -300,6 +302,10 @@ public class FlatButtonUI
|
||||
|
||||
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case BasicHTML.propertyKey:
|
||||
FlatHTML.updateRendererCSSFontBaseSize( b );
|
||||
break;
|
||||
|
||||
case SQUARE_SIZE:
|
||||
case MINIMUM_WIDTH:
|
||||
case MINIMUM_HEIGHT:
|
||||
@@ -308,11 +314,11 @@ public class FlatButtonUI
|
||||
|
||||
case BUTTON_TYPE:
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
|
||||
case OUTLINE:
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
@@ -324,7 +330,7 @@ public class FlatButtonUI
|
||||
} else
|
||||
installStyle( b );
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -583,9 +589,16 @@ public class FlatButtonUI
|
||||
// paint text
|
||||
if( clippedText != null && !clippedText.isEmpty() ) {
|
||||
View view = (View) b.getClientProperty( BasicHTML.propertyKey );
|
||||
if( view != null )
|
||||
if( view != null ) {
|
||||
// update foreground color in HTML view, which is necessary
|
||||
// for selected and pressed states
|
||||
// (only for enabled buttons, because UIManager.getColor("textInactiveText")
|
||||
// is used for disabled components; see: javax.swing.text.GlyphView.paint())
|
||||
if( b.isEnabled() )
|
||||
FlatHTML.updateRendererCSSForeground( view, getForeground( b ) );
|
||||
|
||||
view.paint( g, textR ); // HTML text
|
||||
else
|
||||
} else
|
||||
paintText( g, b, textR, clippedText );
|
||||
}
|
||||
|
||||
@@ -631,8 +644,6 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
public static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
|
||||
if(foreground == null)
|
||||
foreground=Color.red;
|
||||
FontMetrics fm = b.getFontMetrics( b.getFont() );
|
||||
int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -906,7 +917,7 @@ public class FlatButtonUI
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
super.stateChanged( e );
|
||||
HiDPIUtils.repaint( b );
|
||||
|
||||
// if button is in toolbar, repaint button groups
|
||||
AbstractButton b = (AbstractButton) e.getSource();
|
||||
@@ -918,5 +929,17 @@ public class FlatButtonUI
|
||||
((FlatToolBarUI)ui).repaintButtonGroup( b );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
super.focusGained( e );
|
||||
HiDPIUtils.repaint( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
super.focusLost( e );
|
||||
HiDPIUtils.repaint( b );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
|
||||
@@ -102,13 +103,23 @@ public class FlatCheckBoxMenuItemUI
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JMenuItem menuItem ) {
|
||||
super.installComponents( menuItem );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( menuItem );
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
return FlatHTML.createPropertyChangeListener(
|
||||
FlatStylingSupport.createPropertyChangeListener( c, this::installStyle,
|
||||
super.createPropertyChangeListener( c ) ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -78,6 +78,7 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
@@ -220,7 +221,7 @@ public class FlatComboBoxUI
|
||||
|
||||
private void repaintArrowButton() {
|
||||
if( arrowButton != null && !comboBox.isEditable() )
|
||||
arrowButton.repaint();
|
||||
HiDPIUtils.repaint( arrowButton );
|
||||
}
|
||||
};
|
||||
comboBox.addMouseListener( hoverListener );
|
||||
@@ -351,15 +352,15 @@ public class FlatComboBoxUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
super.focusGained( e );
|
||||
if( comboBox != null && comboBox.isEditable() )
|
||||
comboBox.repaint();
|
||||
if( comboBox != null )
|
||||
HiDPIUtils.repaint( comboBox );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
super.focusLost( e );
|
||||
if( comboBox != null && comboBox.isEditable() )
|
||||
comboBox.repaint();
|
||||
if( comboBox != null )
|
||||
HiDPIUtils.repaint( comboBox );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -386,12 +387,12 @@ public class FlatComboBoxUI
|
||||
switch( propertyName ) {
|
||||
case PLACEHOLDER_TEXT:
|
||||
if( editor != null )
|
||||
editor.repaint();
|
||||
HiDPIUtils.repaint( editor );
|
||||
break;
|
||||
|
||||
case COMPONENT_ROUND_RECT:
|
||||
case OUTLINE:
|
||||
comboBox.repaint();
|
||||
HiDPIUtils.repaint( comboBox );
|
||||
break;
|
||||
|
||||
case MINIMUM_WIDTH:
|
||||
@@ -402,7 +403,7 @@ public class FlatComboBoxUI
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
comboBox.revalidate();
|
||||
comboBox.repaint();
|
||||
HiDPIUtils.repaint( comboBox );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -584,7 +585,7 @@ public class FlatComboBoxUI
|
||||
FlatUIUtils.paintComponentBackground( g2, 0, 0, width, height, focusWidth, arc );
|
||||
|
||||
// paint arrow button background
|
||||
if( enabled && !isCellRenderer ) {
|
||||
if( enabled && !isCellRenderer && arrowButton.isVisible() ) {
|
||||
Color buttonColor = paintButton
|
||||
? buttonEditableBackground
|
||||
: (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox )
|
||||
@@ -611,7 +612,7 @@ public class FlatComboBoxUI
|
||||
}
|
||||
|
||||
// paint vertical line between value and arrow button
|
||||
if( paintButton ) {
|
||||
if( paintButton && arrowButton.isVisible() ) {
|
||||
Color separatorColor = enabled ? buttonSeparatorColor : buttonDisabledSeparatorColor;
|
||||
if( separatorColor != null && buttonSeparatorWidth > 0 ) {
|
||||
g2.setColor( separatorColor );
|
||||
|
||||
@@ -171,7 +171,7 @@ public class FlatEditorPaneUI
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle.run();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
@@ -32,6 +33,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
@@ -46,6 +48,7 @@ import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.Scrollable;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
@@ -164,6 +167,7 @@ public class FlatFileChooserUI
|
||||
{
|
||||
private final FlatFileView fileView = new FlatFileView();
|
||||
private FlatShortcutsPanel shortcutsPanel;
|
||||
private JScrollPane shortcutsScrollPane;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatFileChooserUI( (JFileChooser) c );
|
||||
@@ -183,7 +187,10 @@ public class FlatFileChooserUI
|
||||
FlatShortcutsPanel panel = createShortcutsPanel( fc );
|
||||
if( panel.getComponentCount() > 0 ) {
|
||||
shortcutsPanel = panel;
|
||||
fc.add( shortcutsPanel, BorderLayout.LINE_START );
|
||||
shortcutsScrollPane = new JScrollPane( shortcutsPanel,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
|
||||
shortcutsScrollPane.setBorder( BorderFactory.createEmptyBorder() );
|
||||
fc.add( shortcutsScrollPane, BorderLayout.LINE_START );
|
||||
fc.addPropertyChangeListener( shortcutsPanel );
|
||||
}
|
||||
}
|
||||
@@ -196,6 +203,7 @@ public class FlatFileChooserUI
|
||||
if( shortcutsPanel != null ) {
|
||||
fc.removePropertyChangeListener( shortcutsPanel );
|
||||
shortcutsPanel = null;
|
||||
shortcutsScrollPane = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +332,7 @@ public class FlatFileChooserUI
|
||||
public Dimension getPreferredSize( JComponent c ) {
|
||||
Dimension prefSize = super.getPreferredSize( c );
|
||||
Dimension minSize = getMinimumSize( c );
|
||||
int shortcutsPanelWidth = (shortcutsPanel != null) ? shortcutsPanel.getPreferredSize().width : 0;
|
||||
int shortcutsPanelWidth = (shortcutsScrollPane != null) ? shortcutsScrollPane.getPreferredSize().width : 0;
|
||||
return new Dimension(
|
||||
Math.max( prefSize.width, minSize.width + shortcutsPanelWidth ),
|
||||
Math.max( prefSize.height, minSize.height ) );
|
||||
@@ -401,7 +409,7 @@ public class FlatFileChooserUI
|
||||
/** @since 2.3 */
|
||||
public static class FlatShortcutsPanel
|
||||
extends JToolBar
|
||||
implements PropertyChangeListener
|
||||
implements PropertyChangeListener, Scrollable
|
||||
{
|
||||
private final JFileChooser fc;
|
||||
|
||||
@@ -420,6 +428,7 @@ public class FlatFileChooserUI
|
||||
super( JToolBar.VERTICAL );
|
||||
this.fc = fc;
|
||||
setFloatable( false );
|
||||
putClientProperty( FlatClientProperties.STYLE, "hoverButtonGroupBackground: null" );
|
||||
|
||||
buttonSize = UIScale.scale( getUIDimension( "FileChooser.shortcuts.buttonSize", 84, 64 ) );
|
||||
iconSize = getUIDimension( "FileChooser.shortcuts.iconSize", 32, 32 );
|
||||
@@ -461,7 +470,7 @@ public class FlatFileChooserUI
|
||||
icon = new ShortcutIcon( icon, iconSize.width, iconSize.height );
|
||||
|
||||
// create button
|
||||
JToggleButton button = createButton( name, icon );
|
||||
JToggleButton button = createButton( name, icon, file.toString() );
|
||||
File f = file;
|
||||
button.addActionListener( e -> {
|
||||
fc.setCurrentDirectory( f );
|
||||
@@ -487,8 +496,10 @@ public class FlatFileChooserUI
|
||||
return size;
|
||||
}
|
||||
|
||||
protected JToggleButton createButton( String name, Icon icon ) {
|
||||
/** @since 3.5 */
|
||||
protected JToggleButton createButton( String name, Icon icon, String toolTip ) {
|
||||
JToggleButton button = new JToggleButton( name, icon );
|
||||
button.setToolTipText( toolTip );
|
||||
button.setVerticalTextPosition( SwingConstants.BOTTOM );
|
||||
button.setHorizontalTextPosition( SwingConstants.CENTER );
|
||||
button.setAlignmentX( Component.CENTER_ALIGNMENT );
|
||||
@@ -566,6 +577,8 @@ public class FlatFileChooserUI
|
||||
buttonGroup.clearSelection();
|
||||
}
|
||||
|
||||
//---- interface PropertyChangeListener ----
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
@@ -574,6 +587,41 @@ public class FlatFileChooserUI
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//---- interface Scrollable ----
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredScrollableViewportSize() {
|
||||
if( getComponentCount() > 0 ) {
|
||||
Insets insets = getInsets();
|
||||
int height = (getComponent( 0 ).getPreferredSize().height * 5) + insets.top + insets.bottom;
|
||||
return new Dimension( getPreferredSize().width, height );
|
||||
}
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
||||
if( orientation == SwingConstants.VERTICAL && getComponentCount() > 0 )
|
||||
return getComponent( 0 ).getPreferredSize().height;
|
||||
|
||||
return getScrollableBlockIncrement( visibleRect, orientation, direction ) / 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
||||
return (orientation == SwingConstants.VERTICAL) ? visibleRect.height : visibleRect.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getScrollableTracksViewportWidth() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getScrollableTracksViewportHeight() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ShortcutIcon -------------------------------------------------
|
||||
|
||||
290
flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatHTML.java
Normal file
290
flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatHTML.java
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright 2024 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JToolTip;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.LabelView;
|
||||
import javax.swing.text.Style;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.html.CSS;
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
import javax.swing.text.html.StyleSheet;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
* @since 3.5
|
||||
*/
|
||||
public class FlatHTML
|
||||
{
|
||||
private FlatHTML() {}
|
||||
|
||||
/**
|
||||
* Adds CSS rule BASE_SIZE to the style sheet of the HTML view,
|
||||
* which re-calculates font sizes based on current component font size.
|
||||
* This is necessary for "absolute-size" keywords (e.g. "x-large")
|
||||
* for "font-size" attributes in default style sheet (see javax/swing/text/html/default.css).
|
||||
* See also <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-size#values">CSS font-size</a>.
|
||||
* <p>
|
||||
* This method should be invoked after {@link BasicHTML#updateRenderer(JComponent, String)}.
|
||||
*/
|
||||
public static void updateRendererCSSFontBaseSize( JComponent c ) {
|
||||
View view = (View) c.getClientProperty( BasicHTML.propertyKey );
|
||||
if( view == null )
|
||||
return;
|
||||
|
||||
// dumpViews( view, 0 );
|
||||
|
||||
Document doc = view.getDocument();
|
||||
if( !(doc instanceof HTMLDocument) )
|
||||
return;
|
||||
|
||||
// add BASE_SIZE rule if necessary
|
||||
// - if point size at index 7 is not 36, then probably HTML text contains BASE_SIZE rule
|
||||
// - if point size at index 4 is equal to given font size, then it is not necessary to add BASE_SIZE rule
|
||||
StyleSheet styleSheet = ((HTMLDocument)doc).getStyleSheet();
|
||||
/*debug
|
||||
for( int i = 1; i <= 7; i++ )
|
||||
System.out.println( i+": "+ styleSheet.getPointSize( i ) );
|
||||
debug*/
|
||||
Font font = c.getFont();
|
||||
if( styleSheet.getPointSize( 7 ) != 36f ||
|
||||
font == null || styleSheet.getPointSize( 4 ) == font.getSize() )
|
||||
return;
|
||||
|
||||
// check whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
|
||||
if( !usesAbsoluteSizeKeywordForFontSize( view ) )
|
||||
return;
|
||||
|
||||
// get HTML text from component
|
||||
String text;
|
||||
if( c instanceof JLabel )
|
||||
text = ((JLabel)c).getText();
|
||||
else if( c instanceof AbstractButton )
|
||||
text = ((AbstractButton)c).getText();
|
||||
else if( c instanceof JToolTip )
|
||||
text = ((JToolTip)c).getTipText();
|
||||
else
|
||||
return;
|
||||
if( text == null || !BasicHTML.isHTMLString( text ) )
|
||||
return;
|
||||
|
||||
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
||||
String style = "<style>BASE_SIZE " + font.getSize() + "</style>";
|
||||
String openTag = "";
|
||||
String closeTag = "";
|
||||
|
||||
int headIndex;
|
||||
int styleIndex;
|
||||
|
||||
int insertIndex;
|
||||
if( (headIndex = indexOfTag( text, "head", true )) >= 0 ) {
|
||||
// there is a <head> tag --> insert after <head> tag
|
||||
insertIndex = headIndex;
|
||||
} else if( (styleIndex = indexOfTag( text, "style", false )) >= 0 ) {
|
||||
// there is a <style> tag --> insert before <style> tag
|
||||
insertIndex = styleIndex;
|
||||
} else {
|
||||
// no <head> or <style> tag --> insert <head> tag after <html> tag
|
||||
insertIndex = "<html>".length();
|
||||
openTag = "<head>";
|
||||
closeTag = "</head>";
|
||||
}
|
||||
|
||||
String newText = text.substring( 0, insertIndex )
|
||||
+ openTag + style + closeTag
|
||||
+ text.substring( insertIndex );
|
||||
|
||||
BasicHTML.updateRenderer( c, newText );
|
||||
|
||||
// for unit tests
|
||||
if( testUpdateRenderer != null )
|
||||
testUpdateRenderer.accept( c, newText );
|
||||
}
|
||||
|
||||
// for unit tests
|
||||
static BiConsumer<JComponent, String> testUpdateRenderer;
|
||||
|
||||
/**
|
||||
* Returns start or end index of a HTML tag.
|
||||
* Checks only for leading '<' character and (case-ignore) tag name.
|
||||
*/
|
||||
private static int indexOfTag( String html, String tag, boolean endIndex ) {
|
||||
int tagLength = tag.length();
|
||||
int maxLength = html.length() - tagLength - 2;
|
||||
char lastTagChar = tag.charAt( tagLength - 1 );
|
||||
|
||||
for( int i = "<html>".length(); i < maxLength; i++ ) {
|
||||
// check for leading '<' and last tag name character
|
||||
if( html.charAt( i ) == '<' && Character.toLowerCase( html.charAt( i + tagLength ) ) == lastTagChar ) {
|
||||
// compare tag characters from last to first
|
||||
for( int j = tagLength - 2; j >= 0; j-- ) {
|
||||
if( Character.toLowerCase( html.charAt( i + 1 + j ) ) != tag.charAt( j ) )
|
||||
break; // not equal
|
||||
|
||||
if( j == 0 ) {
|
||||
// tag found
|
||||
return endIndex ? html.indexOf( '>', i + tagLength ) + 1 : i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static final Set<String> absoluteSizeKeywordsSet = new HashSet<>( Arrays.asList(
|
||||
"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large" ) );
|
||||
|
||||
/**
|
||||
* Checks whether view uses "absolute-size" keywords (e.g. "x-large") for font-size
|
||||
* (see javax/swing/text/html/default.css).
|
||||
*/
|
||||
private static boolean usesAbsoluteSizeKeywordForFontSize( View view ) {
|
||||
AttributeSet attributes = view.getAttributes();
|
||||
if( attributes != null ) {
|
||||
Object fontSize = attributes.getAttribute( CSS.Attribute.FONT_SIZE );
|
||||
if( fontSize != null ) {
|
||||
if( absoluteSizeKeywordsSet.contains( fontSize.toString() ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int viewCount = view.getViewCount();
|
||||
for( int i = 0; i < viewCount; i++ ) {
|
||||
if( usesAbsoluteSizeKeywordForFontSize( view.getView( i ) ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates foreground in style sheet of the HTML view.
|
||||
* Adds "body { color: #<foreground-hex>; }"
|
||||
*/
|
||||
public static void updateRendererCSSForeground( View view, Color foreground ) {
|
||||
Document doc = view.getDocument();
|
||||
if( !(doc instanceof HTMLDocument) || foreground == null )
|
||||
return;
|
||||
|
||||
// add foreground rule if necessary
|
||||
// - use tag 'body' because BasicHTML.createHTMLView() also uses this tag
|
||||
// to set font and color styles to component font/color
|
||||
// see: SwingUtilities2.displayPropertiesToCSS()
|
||||
// - this color is not used if component is disabled;
|
||||
// JTextComponent.getDisabledTextColor() is used for disabled text components;
|
||||
// UIManager.getColor("textInactiveText") is used for other disabled components
|
||||
// see: javax.swing.text.GlyphView.paint()
|
||||
Style bodyStyle = ((HTMLDocument)doc).getStyle( "body" );
|
||||
if( bodyStyle == null ) {
|
||||
StyleSheet styleSheet = ((HTMLDocument)doc).getStyleSheet();
|
||||
styleSheet.addRule( String.format( "body { color: #%06x; }", foreground.getRGB() & 0xffffff ) );
|
||||
clearViewCaches( view );
|
||||
} else if( !foreground.equals( bodyStyle.getAttribute( StyleConstants.Foreground ) ) ) {
|
||||
bodyStyle.addAttribute( StyleConstants.Foreground, foreground );
|
||||
clearViewCaches( view );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears cached values in view so that CSS changes take effect.
|
||||
*/
|
||||
private static void clearViewCaches( View view ) {
|
||||
if( view instanceof LabelView )
|
||||
((LabelView)view).changedUpdate( null, null, null );
|
||||
|
||||
int viewCount = view.getViewCount();
|
||||
for( int i = 0; i < viewCount; i++ )
|
||||
clearViewCaches( view.getView( i ) );
|
||||
}
|
||||
|
||||
public static PropertyChangeListener createPropertyChangeListener( PropertyChangeListener superListener ) {
|
||||
return e -> {
|
||||
if( superListener != null )
|
||||
superListener.propertyChange( e );
|
||||
propertyChange( e );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link #updateRendererCSSFontBaseSize(JComponent)}
|
||||
* for {@link BasicHTML#propertyKey} property change events,
|
||||
* which are fired when {@link BasicHTML#updateRenderer(JComponent, String)}
|
||||
* updates the HTML view.
|
||||
*/
|
||||
public static void propertyChange( PropertyChangeEvent e ) {
|
||||
if( BasicHTML.propertyKey.equals( e.getPropertyName() ) && e.getNewValue() instanceof View )
|
||||
updateRendererCSSFontBaseSize( (JComponent) e.getSource() );
|
||||
}
|
||||
|
||||
/*debug
|
||||
public static void dumpView( JComponent c ) {
|
||||
View view = (View) c.getClientProperty( BasicHTML.propertyKey );
|
||||
if( view != null )
|
||||
dumpViews( view, 0 );
|
||||
}
|
||||
|
||||
public static void dumpViews( View view, int indent ) {
|
||||
for( int i = 0; i < indent; i++ )
|
||||
System.out.print( " " );
|
||||
|
||||
System.out.printf( "%s @%-8x %3d,%2d",
|
||||
view.getClass().isAnonymousClass() ? view.getClass().getName() : view.getClass().getSimpleName(),
|
||||
System.identityHashCode( view ),
|
||||
(int) view.getPreferredSpan( View.X_AXIS ),
|
||||
(int) view.getPreferredSpan( View.Y_AXIS ) );
|
||||
|
||||
AttributeSet attrs = view.getAttributes();
|
||||
if( attrs != null ) {
|
||||
Object fontSize = attrs.getAttribute( CSS.Attribute.FONT_SIZE );
|
||||
System.out.printf( " %-8s", fontSize );
|
||||
}
|
||||
|
||||
if( view instanceof javax.swing.text.GlyphView ) {
|
||||
javax.swing.text.GlyphView gview = ((javax.swing.text.GlyphView)view);
|
||||
java.awt.Font font = gview.getFont();
|
||||
System.out.printf( " %3d-%-3d %s %2d (@%x) #%06x '%s'",
|
||||
gview.getStartOffset(), gview.getEndOffset() - 1,
|
||||
font.getName(), font.getSize(), System.identityHashCode( font ),
|
||||
gview.getForeground().getRGB() & 0xffffff,
|
||||
gview.getText( gview.getStartOffset(), gview.getEndOffset() ) );
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
int viewCount = view.getViewCount();
|
||||
for( int i = 0; i < viewCount; i++ ) {
|
||||
View child = view.getView( i );
|
||||
dumpViews( child, indent + 1 );
|
||||
}
|
||||
}
|
||||
debug*/
|
||||
}
|
||||
@@ -22,11 +22,7 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
@@ -64,6 +60,9 @@ public class FlatLabelUI
|
||||
{
|
||||
@Styleable protected Color disabledForeground;
|
||||
|
||||
// only used via styling (not in UI defaults)
|
||||
/** @since 3.5 */ @Styleable protected int arc = -1;
|
||||
|
||||
private final boolean shared;
|
||||
private boolean defaults_initialized = false;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
@@ -110,16 +109,13 @@ public class FlatLabelUI
|
||||
super.installComponents( c );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
updateHTMLRenderer( c, c.getText(), false );
|
||||
FlatHTML.updateRendererCSSFontBaseSize( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
String name = e.getPropertyName();
|
||||
if( name == "text" || name == "font" || name == "foreground" ) {
|
||||
JLabel label = (JLabel) e.getSource();
|
||||
updateHTMLRenderer( label, label.getText(), true );
|
||||
} else if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) {
|
||||
if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) {
|
||||
JLabel label = (JLabel) e.getSource();
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( label ) ) {
|
||||
// unshare component UI if necessary
|
||||
@@ -128,9 +124,11 @@ public class FlatLabelUI
|
||||
} else
|
||||
installStyle( label );
|
||||
label.revalidate();
|
||||
label.repaint();
|
||||
} else
|
||||
super.propertyChange( e );
|
||||
HiDPIUtils.repaint( label );
|
||||
}
|
||||
|
||||
super.propertyChange( e );
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@@ -165,83 +163,10 @@ public class FlatLabelUI
|
||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether text contains HTML tags that use "absolute-size" keywords
|
||||
* (e.g. "x-large") for font-size in default style sheet
|
||||
* (see javax/swing/text/html/default.css).
|
||||
* If yes, adds a special CSS rule (BASE_SIZE) to the HTML text, which
|
||||
* re-calculates font sizes based on current component font size.
|
||||
*/
|
||||
static void updateHTMLRenderer( JComponent c, String text, boolean always ) {
|
||||
if( BasicHTML.isHTMLString( text ) &&
|
||||
c.getClientProperty( "html.disable" ) != Boolean.TRUE &&
|
||||
needsFontBaseSize( text ) )
|
||||
{
|
||||
// BASE_SIZE rule is parsed in javax.swing.text.html.StyleSheet.addRule()
|
||||
String style = "<style>BASE_SIZE " + c.getFont().getSize() + "</style>";
|
||||
|
||||
String lowerText = text.toLowerCase( Locale.ENGLISH );
|
||||
int headIndex;
|
||||
int styleIndex;
|
||||
|
||||
int insertIndex;
|
||||
if( (headIndex = lowerText.indexOf( "<head>" )) >= 0 ) {
|
||||
// there is a <head> tag --> insert after <head> tag
|
||||
insertIndex = headIndex + "<head>".length();
|
||||
} else if( (styleIndex = lowerText.indexOf( "<style>" )) >= 0 ) {
|
||||
// there is a <style> tag --> insert before <style> tag
|
||||
insertIndex = styleIndex;
|
||||
} else {
|
||||
// no <head> or <style> tag --> insert <head> tag after <html> tag
|
||||
style = "<head>" + style + "</head>";
|
||||
insertIndex = "<html>".length();
|
||||
}
|
||||
|
||||
text = text.substring( 0, insertIndex )
|
||||
+ style
|
||||
+ text.substring( insertIndex );
|
||||
} else if( !always )
|
||||
return; // not necessary to invoke BasicHTML.updateRenderer()
|
||||
|
||||
BasicHTML.updateRenderer( c, text );
|
||||
}
|
||||
|
||||
private static Set<String> tagsUseFontSizeSet;
|
||||
|
||||
private static boolean needsFontBaseSize( String text ) {
|
||||
if( tagsUseFontSizeSet == null ) {
|
||||
// tags that use font-size in javax/swing/text/html/default.css
|
||||
tagsUseFontSizeSet = new HashSet<>( Arrays.asList(
|
||||
"h1", "h2", "h3", "h4", "h5", "h6", "code", "kbd", "big", "small", "samp" ) );
|
||||
}
|
||||
|
||||
// search for tags in HTML text
|
||||
int textLength = text.length();
|
||||
for( int i = 6; i < textLength - 1; i++ ) {
|
||||
if( text.charAt( i ) == '<' ) {
|
||||
switch( text.charAt( i + 1 ) ) {
|
||||
// first letters of tags in tagsUseFontSizeSet
|
||||
case 'b': case 'B':
|
||||
case 'c': case 'C':
|
||||
case 'h': case 'H':
|
||||
case 'k': case 'K':
|
||||
case 's': case 'S':
|
||||
int tagBegin = i + 1;
|
||||
for( i += 2; i < textLength; i++ ) {
|
||||
if( !Character.isLetterOrDigit( text.charAt( i ) ) ) {
|
||||
String tag = text.substring( tagBegin, i ).toLowerCase( Locale.ENGLISH );
|
||||
if( tagsUseFontSizeSet.contains( tag ) )
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
FlatPanelUI.fillRoundedBackground( g, c, arc );
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
static Graphics createGraphicsHTMLTextYCorrection( Graphics g, JComponent c ) {
|
||||
|
||||
@@ -23,13 +23,20 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
|
||||
/**
|
||||
* Line border for various components.
|
||||
*
|
||||
* <p>
|
||||
* Paints a scaled (usually 1px thick) line around the component.
|
||||
* The line thickness is not added to the border insets.
|
||||
* The insets should be at least have line thickness (usually 1,1,1,1).
|
||||
* <p>
|
||||
* For {@link javax.swing.JPanel} and {@link javax.swing.JLabel}, this border
|
||||
* can be used paint rounded background (if line color is {@code null}) or
|
||||
* paint rounded line border with rounded background.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -41,7 +48,7 @@ public class FlatLineBorder
|
||||
/** @since 2 */ private final int arc;
|
||||
|
||||
public FlatLineBorder( Insets insets, Color lineColor ) {
|
||||
this( insets, lineColor, 1f, 0 );
|
||||
this( insets, lineColor, 1f, -1 );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
@@ -52,15 +59,28 @@ public class FlatLineBorder
|
||||
this.arc = arc;
|
||||
}
|
||||
|
||||
/** @since 3.5 */
|
||||
public FlatLineBorder( Insets insets, int arc ) {
|
||||
this( insets, null, 0, arc );
|
||||
}
|
||||
|
||||
public Color getLineColor() {
|
||||
return lineColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (unscaled) line thickness used to paint the border.
|
||||
* The line thickness does not affect the border insets.
|
||||
*/
|
||||
public float getLineThickness() {
|
||||
return lineThickness;
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
/**
|
||||
* Returns the (unscaled) arc diameter of the border corners.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public int getArc() {
|
||||
return arc;
|
||||
}
|
||||
@@ -70,11 +90,31 @@ public class FlatLineBorder
|
||||
if( c instanceof JComponent && ((JComponent)c).getClientProperty( FlatPopupFactory.KEY_POPUP_USES_NATIVE_BORDER ) != null )
|
||||
return;
|
||||
|
||||
Color lineColor = getLineColor();
|
||||
float lineThickness = getLineThickness();
|
||||
if( lineColor == null || lineThickness <= 0 )
|
||||
return;
|
||||
|
||||
int arc = getArc();
|
||||
if( arc < 0 ) {
|
||||
// get arc from label or panel
|
||||
ComponentUI ui = (c instanceof JLabel)
|
||||
? ((JLabel)c).getUI()
|
||||
: (c instanceof JPanel ? ((JPanel)c).getUI() : null);
|
||||
if( ui instanceof FlatLabelUI )
|
||||
arc = ((FlatLabelUI)ui).arc;
|
||||
else if( ui instanceof FlatPanelUI )
|
||||
arc = ((FlatPanelUI)ui).arc;
|
||||
|
||||
if( arc < 0 )
|
||||
arc = 0;
|
||||
}
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
0, 0, 0, scale( getLineThickness() ), scale( getArc() ), null, getLineColor(), null );
|
||||
0, 0, 0, scale( lineThickness ), scale( arc ), null, lineColor, null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -182,7 +183,7 @@ public class FlatListUI
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
list.revalidate();
|
||||
list.repaint();
|
||||
HiDPIUtils.repaint( list );
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -205,7 +206,7 @@ public class FlatListUI
|
||||
Rectangle r = getCellBounds( list, firstIndex, lastIndex );
|
||||
if( r != null ) {
|
||||
int arc = (int) Math.ceil( UIScale.scale( selectionArc / 2f ) );
|
||||
list.repaint( r.x - arc, r.y - arc, r.width + (arc * 2), r.height + (arc * 2) );
|
||||
HiDPIUtils.repaint( list, r.x - arc, r.y - arc, r.width + (arc * 2), r.height + (arc * 2) );
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -324,8 +325,7 @@ public class FlatListUI
|
||||
(rendererComponent instanceof DefaultListCellRenderer ||
|
||||
rendererComponent instanceof BasicComboBoxRenderer) &&
|
||||
(selectionArc > 0 ||
|
||||
(selectionInsets != null &&
|
||||
(selectionInsets.top != 0 || selectionInsets.left != 0 || selectionInsets.bottom != 0 || selectionInsets.right != 0))) )
|
||||
(selectionInsets != null && !FlatUIUtils.isInsetsEmpty( selectionInsets ))) )
|
||||
{
|
||||
// Because selection painting is done in the cell renderer, it would be
|
||||
// necessary to require a FlatLaf specific renderer to implement rounded selection.
|
||||
@@ -374,7 +374,15 @@ public class FlatListUI
|
||||
rendererPane.paintComponent( g, rendererComponent, list, cx, rowBounds.y, cw, rowBounds.height, true );
|
||||
}
|
||||
|
||||
/** @since 3 */
|
||||
/**
|
||||
* Paints (rounded) cell selection.
|
||||
* Supports {@link #selectionArc} and {@link #selectionInsets}.
|
||||
* <p>
|
||||
* <b>Note:</b> This method is only invoked if either selection arc
|
||||
* is greater than zero or if selection insets are not empty.
|
||||
*
|
||||
* @since 3
|
||||
*/
|
||||
protected void paintCellSelection( Graphics g, int row, int x, int y, int width, int height ) {
|
||||
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
||||
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
||||
@@ -440,7 +448,8 @@ public class FlatListUI
|
||||
* Paints a cell selection at the given coordinates.
|
||||
* The selection color must be set on the graphics context.
|
||||
* <p>
|
||||
* This method is intended for use in custom cell renderers.
|
||||
* This method is intended for use in custom cell renderers
|
||||
* to support {@link #selectionArc} and {@link #selectionInsets}.
|
||||
*
|
||||
* @since 3
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,9 @@ import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.InputEvent;
|
||||
@@ -35,6 +37,7 @@ import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -222,7 +225,7 @@ public class FlatMenuItemRenderer
|
||||
}
|
||||
|
||||
// arrow size
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
if( arrowIcon != null && (!isTopLevelMenu || isInVerticalMenuBar( menuItem )) ) {
|
||||
// gap between text and arrow
|
||||
if( accelText == null )
|
||||
width += scale( textNoAcceleratorGap );
|
||||
@@ -254,7 +257,8 @@ public class FlatMenuItemRenderer
|
||||
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
|
||||
|
||||
// layout arrow
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
boolean showArrowIcon = (arrowIcon != null && (!isTopLevelMenu || isInVerticalMenuBar( menuItem )));
|
||||
if( showArrowIcon ) {
|
||||
arrowRect.width = arrowIcon.getIconWidth();
|
||||
arrowRect.height = arrowIcon.getIconHeight();
|
||||
} else
|
||||
@@ -288,7 +292,7 @@ public class FlatMenuItemRenderer
|
||||
int accelArrowWidth = accelRect.width + arrowRect.width;
|
||||
if( accelText != null )
|
||||
accelArrowWidth += scale( !isTopLevelMenu ? textAcceleratorGap : menuItem.getIconTextGap() );
|
||||
if( !isTopLevelMenu && arrowIcon != null ) {
|
||||
if( showArrowIcon ) {
|
||||
if( accelText == null )
|
||||
accelArrowWidth += scale( textNoAcceleratorGap );
|
||||
accelArrowWidth += scale( acceleratorArrowGap );
|
||||
@@ -355,7 +359,7 @@ debug*/
|
||||
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
|
||||
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
|
||||
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
|
||||
if( !isTopLevelMenu( menuItem ) )
|
||||
if( arrowIcon != null && (!isTopLevelMenu( menuItem ) || isInVerticalMenuBar( menuItem )) )
|
||||
paintArrowIcon( g, arrowRect, arrowIcon );
|
||||
}
|
||||
|
||||
@@ -520,6 +524,15 @@ debug*/
|
||||
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
|
||||
}
|
||||
|
||||
/** @since 3.5 */
|
||||
public static boolean isInVerticalMenuBar( JMenuItem menuItem ) {
|
||||
if( !(menuItem instanceof JMenu) || !(menuItem.getParent() instanceof JMenuBar) )
|
||||
return false;
|
||||
|
||||
LayoutManager layout = menuItem.getParent().getLayout();
|
||||
return layout instanceof GridLayout && ((GridLayout)layout).getRows() != 1;
|
||||
}
|
||||
|
||||
protected boolean isUnderlineSelection() {
|
||||
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
|
||||
}
|
||||
|
||||
@@ -103,13 +103,23 @@ public class FlatMenuItemUI
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JMenuItem menuItem ) {
|
||||
super.installComponents( menuItem );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( menuItem );
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
return FlatHTML.createPropertyChangeListener(
|
||||
FlatStylingSupport.createPropertyChangeListener( c, this::installStyle,
|
||||
super.createPropertyChangeListener( c ) ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -47,6 +47,7 @@ import javax.swing.plaf.basic.BasicMenuUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
@@ -136,6 +137,14 @@ public class FlatMenuUI
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JMenuItem menuItem ) {
|
||||
super.installComponents( menuItem );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( menuItem );
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
@@ -159,7 +168,7 @@ public class FlatMenuUI
|
||||
JMenu menu = (JMenu) e.getSource();
|
||||
if( menu.isTopLevelMenu() && menu.isRolloverEnabled() ) {
|
||||
menu.getModel().setRollover( rollover );
|
||||
menu.repaint();
|
||||
HiDPIUtils.repaint( menu );
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -167,7 +176,9 @@ public class FlatMenuUI
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
return FlatHTML.createPropertyChangeListener(
|
||||
FlatStylingSupport.createPropertyChangeListener( c, this::installStyle,
|
||||
super.createPropertyChangeListener( c ) ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
@@ -96,7 +97,11 @@ class FlatNativeLinuxLibrary
|
||||
}
|
||||
|
||||
private static Point scale( Window window, Point pt ) {
|
||||
AffineTransform transform = window.getGraphicsConfiguration().getDefaultTransform();
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
if( gc == null )
|
||||
return pt;
|
||||
|
||||
AffineTransform transform = gc.getDefaultTransform();
|
||||
int x = (int) Math.round( pt.x * transform.getScaleX() );
|
||||
int y = (int) Math.round( pt.y * transform.getScaleY() );
|
||||
return new Point( x, y );
|
||||
|
||||
@@ -25,11 +25,13 @@ import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.border.Border;
|
||||
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.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -110,7 +112,7 @@ public class FlatPanelUI
|
||||
} else
|
||||
installStyle( c );
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER:
|
||||
@@ -160,32 +162,38 @@ public class FlatPanelUI
|
||||
|
||||
@Override
|
||||
public void update( Graphics g, JComponent c ) {
|
||||
// fill background
|
||||
if( c.isOpaque() ) {
|
||||
int width = c.getWidth();
|
||||
int height = c.getHeight();
|
||||
int arc = (this.arc >= 0)
|
||||
? this.arc
|
||||
: ((c.getBorder() instanceof FlatLineBorder)
|
||||
? ((FlatLineBorder)c.getBorder()).getArc()
|
||||
: 0);
|
||||
fillRoundedBackground( g, c, arc );
|
||||
paint( g, c );
|
||||
}
|
||||
|
||||
// fill background with parent color to avoid garbage in rounded corners
|
||||
if( arc > 0 )
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
|
||||
g.setColor( c.getBackground() );
|
||||
if( arc > 0 ) {
|
||||
// fill rounded rectangle if having rounded corners
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
FlatUIUtils.paintComponentBackground( (Graphics2D) g, 0, 0, width, height,
|
||||
0, UIScale.scale( arc ) );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
} else
|
||||
g.fillRect( 0, 0, width, height );
|
||||
/** @since 3.5 */
|
||||
public static void fillRoundedBackground( Graphics g, JComponent c, int arc ) {
|
||||
if( arc < 0 ) {
|
||||
Border border = c.getBorder();
|
||||
arc = ((border instanceof FlatLineBorder)
|
||||
? ((FlatLineBorder)border).getArc()
|
||||
: 0);
|
||||
}
|
||||
|
||||
paint( g, c );
|
||||
// fill background
|
||||
if( c.isOpaque() ) {
|
||||
if( arc > 0 ) {
|
||||
// fill background with parent color to avoid garbage in rounded corners
|
||||
FlatUIUtils.paintParentBackground( g, c );
|
||||
} else {
|
||||
g.setColor( c.getBackground() );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
// fill rounded rectangle if having rounded corners
|
||||
if( arc > 0 ) {
|
||||
g.setColor( c.getBackground() );
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||
FlatUIUtils.paintComponentBackground( (Graphics2D) g, 0, 0, c.getWidth(), c.getHeight(),
|
||||
0, UIScale.scale( arc ) );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,7 @@ import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.icons.FlatCapsLockIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -163,7 +164,7 @@ public class FlatPasswordFieldUI
|
||||
}
|
||||
private void repaint( KeyEvent e ) {
|
||||
if( e.getKeyCode() == KeyEvent.VK_CAPS_LOCK ) {
|
||||
e.getComponent().repaint();
|
||||
HiDPIUtils.repaint( e.getComponent() );
|
||||
scrollCaretToVisible();
|
||||
}
|
||||
}
|
||||
@@ -326,7 +327,7 @@ public class FlatPasswordFieldUI
|
||||
if( visible != revealButton.isVisible() ) {
|
||||
revealButton.setVisible( visible );
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
|
||||
if( !visible ) {
|
||||
revealButton.setSelected( false );
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
@@ -35,12 +36,16 @@ import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.HierarchyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
@@ -58,6 +63,7 @@ import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.plaf.basic.BasicComboPopup;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -76,6 +82,8 @@ public class FlatPopupFactory
|
||||
private MethodHandle java8getPopupMethod;
|
||||
private MethodHandle java9getPopupMethod;
|
||||
|
||||
private final ArrayList<NonFlashingPopup> stillShownHeavyWeightPopups = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Popup getPopup( Component owner, Component contents, int x, int y )
|
||||
throws IllegalArgumentException
|
||||
@@ -88,15 +96,28 @@ public class FlatPopupFactory
|
||||
|
||||
fixLinuxWaylandJava21focusIssue( owner );
|
||||
|
||||
// reuse a heavy weight popup window, which is still shown on screen,
|
||||
// to avoid flicker when popup (e.g. tooltip) is moving while mouse is moved
|
||||
for( NonFlashingPopup popup : stillShownHeavyWeightPopups ) {
|
||||
if( popup.delegate != null &&
|
||||
popup.owner == owner &&
|
||||
(popup.contents == contents ||
|
||||
(popup.contents instanceof JToolTip && contents instanceof JToolTip)) )
|
||||
{
|
||||
stillShownHeavyWeightPopups.remove( popup );
|
||||
return reuseStillShownHeavyWeightPopups( popup, contents, x, y );
|
||||
}
|
||||
}
|
||||
|
||||
boolean forceHeavyWeight = isOptionEnabled( owner, contents, FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, "Popup.forceHeavyWeight" );
|
||||
|
||||
if( !isOptionEnabled( owner, contents, FlatClientProperties.POPUP_DROP_SHADOW_PAINTED, "Popup.dropShadowPainted" ) || SystemInfo.isProjector || SystemInfo.isWebswing )
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), contents );
|
||||
return new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||
|
||||
// macOS and Linux adds drop shadow to heavy weight popups
|
||||
if( SystemInfo.isMacOS || SystemInfo.isLinux ) {
|
||||
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||
if( popup.popupWindow != null && SystemInfo.isMacOS && FlatNativeMacLibrary.isLoaded() )
|
||||
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
|
||||
if( popup.popupWindow != null && isMacOSBorderSupported() )
|
||||
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||
return popup;
|
||||
}
|
||||
@@ -105,7 +126,7 @@ public class FlatPopupFactory
|
||||
if( isWindows11BorderSupported() &&
|
||||
getBorderCornerRadius( owner, contents ) > 0 )
|
||||
{
|
||||
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), contents );
|
||||
NonFlashingPopup popup = new NonFlashingPopup( getPopupForScreenOfOwner( owner, contents, x, y, true ), owner, contents );
|
||||
if( popup.popupWindow != null )
|
||||
setupRoundedBorder( popup.popupWindow, owner, contents );
|
||||
return popup;
|
||||
@@ -116,7 +137,11 @@ public class FlatPopupFactory
|
||||
forceHeavyWeight = true;
|
||||
|
||||
// create drop shadow popup
|
||||
return new DropShadowPopup( getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight ), owner, contents );
|
||||
Popup popupForScreenOfOwner = getPopupForScreenOfOwner( owner, contents, x, y, forceHeavyWeight );
|
||||
GraphicsConfiguration gc = owner.getGraphicsConfiguration();
|
||||
return (gc != null && gc.isTranslucencyCapable())
|
||||
? new DropShadowPopup( popupForScreenOfOwner, owner, contents )
|
||||
: new NonFlashingPopup( popupForScreenOfOwner, owner, contents );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,6 +252,24 @@ public class FlatPopupFactory
|
||||
return UIManager.get( uiKey );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuse a heavy weight popup window, which is still shown on screen,
|
||||
* by updating window location and contents.
|
||||
* This avoid flicker when popup (e.g. a tooltip) is moving while mouse is moved.
|
||||
* E.g. overridden JComponent.getToolTipLocation(MouseEvent).
|
||||
* See ToolTipManager.checkForTipChange(MouseEvent).
|
||||
*/
|
||||
private static NonFlashingPopup reuseStillShownHeavyWeightPopups(
|
||||
NonFlashingPopup reusePopup, Component contents, int ownerX, int ownerY )
|
||||
{
|
||||
// clone popup because PopupFactory.getPopup() should not return old instance
|
||||
NonFlashingPopup popup = reusePopup.cloneForReuse();
|
||||
|
||||
// update popup location, size and contents
|
||||
popup.reset( contents, ownerX, ownerY );
|
||||
return popup;
|
||||
}
|
||||
|
||||
//---- tooltips -----------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -316,19 +359,29 @@ public class FlatPopupFactory
|
||||
//---- native rounded border ----------------------------------------------
|
||||
|
||||
private static boolean isWindows11BorderSupported() {
|
||||
return SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded();
|
||||
return SystemInfo.isWindows_11_orLater &&
|
||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, true ) &&
|
||||
FlatNativeWindowsLibrary.isLoaded();
|
||||
}
|
||||
|
||||
private static boolean isMacOSBorderSupported() {
|
||||
// do not use rounded border on macOS 14.4+ because it may freeze the application
|
||||
// and crash the macOS WindowServer process (reports vary from Finder restarts to OS restarts)
|
||||
// https://github.com/apache/netbeans/issues/7560#issuecomment-2226439215
|
||||
// https://github.com/apache/netbeans/issues/6647#issuecomment-2070124442
|
||||
boolean isMacOS_14_4_orLater = (SystemInfo.osVersion >= SystemInfo.toVersion( 14, 4, 0, 0 ));
|
||||
|
||||
return SystemInfo.isMacOS &&
|
||||
FlatSystemProperties.getBoolean( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, !isMacOS_14_4_orLater ) &&
|
||||
FlatNativeMacLibrary.isLoaded();
|
||||
}
|
||||
|
||||
private static void setupRoundedBorder( Window popupWindow, Component owner, Component contents ) {
|
||||
// make sure that the native window is created
|
||||
if( !popupWindow.isDisplayable() )
|
||||
popupWindow.addNotify();
|
||||
|
||||
int borderCornerRadius = getBorderCornerRadius( owner, contents );
|
||||
float borderWidth = getRoundedBorderWidth( owner, contents );
|
||||
|
||||
// get Swing border color
|
||||
Color borderColor = null; // use system default color
|
||||
Color borderColor;
|
||||
if( contents instanceof JComponent ) {
|
||||
Border border = ((JComponent)contents).getBorder();
|
||||
border = FlatUIUtils.unwrapNonUIResourceBorder( border );
|
||||
@@ -340,11 +393,33 @@ public class FlatPopupFactory
|
||||
borderColor = ((LineBorder)border).getLineColor();
|
||||
else if( border instanceof EmptyBorder )
|
||||
borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border
|
||||
else
|
||||
borderColor = null; // use system default color
|
||||
|
||||
// avoid that FlatLineBorder paints the Swing border
|
||||
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, true );
|
||||
}
|
||||
} else
|
||||
borderColor = null; // use system default color
|
||||
|
||||
if( popupWindow.isDisplayable() ) {
|
||||
// native window already created
|
||||
setupRoundedBorderImpl( popupWindow, borderCornerRadius, borderWidth, borderColor );
|
||||
} else {
|
||||
// native window not yet created --> add listener to set native border after window creation
|
||||
AtomicReference<HierarchyListener> l = new AtomicReference<>();
|
||||
l.set( e -> {
|
||||
if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED &&
|
||||
(e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 )
|
||||
{
|
||||
setupRoundedBorderImpl( popupWindow, borderCornerRadius, borderWidth, borderColor );
|
||||
popupWindow.removeHierarchyListener( l.get() );
|
||||
}
|
||||
} );
|
||||
popupWindow.addHierarchyListener( l.get() );
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupRoundedBorderImpl( Window popupWindow, int borderCornerRadius, float borderWidth, Color borderColor ) {
|
||||
if( SystemInfo.isWindows ) {
|
||||
// get native window handle
|
||||
long hwnd = FlatNativeWindowsLibrary.getHWND( popupWindow );
|
||||
@@ -490,18 +565,31 @@ public class FlatPopupFactory
|
||||
|
||||
//---- class NonFlashingPopup ---------------------------------------------
|
||||
|
||||
private static class NonFlashingPopup
|
||||
/**
|
||||
* Fixes popup background flashing effect when using dark theme on light platform theme,
|
||||
* where the light popup background is shown for a fraction of a second before
|
||||
* the dark popup content is shown.
|
||||
* This is fixed by setting popup background to content background.
|
||||
* <p>
|
||||
* Defers hiding of heavy weight popup window for an event cycle,
|
||||
* which allows reusing popup window to avoid flicker when "moving" popup.
|
||||
*/
|
||||
private class NonFlashingPopup
|
||||
extends Popup
|
||||
{
|
||||
private Popup delegate;
|
||||
Component owner;
|
||||
private Component contents;
|
||||
|
||||
// heavy weight
|
||||
protected Window popupWindow;
|
||||
Window popupWindow;
|
||||
private Color oldPopupWindowBackground;
|
||||
|
||||
NonFlashingPopup( Popup delegate, Component contents ) {
|
||||
private boolean disposed;
|
||||
|
||||
NonFlashingPopup( Popup delegate, Component owner, Component contents ) {
|
||||
this.delegate = delegate;
|
||||
this.owner = owner;
|
||||
this.contents = contents;
|
||||
|
||||
popupWindow = SwingUtilities.windowForComponent( contents );
|
||||
@@ -515,8 +603,27 @@ public class FlatPopupFactory
|
||||
}
|
||||
}
|
||||
|
||||
private NonFlashingPopup( NonFlashingPopup reusePopup ) {
|
||||
delegate = reusePopup.delegate;
|
||||
owner = reusePopup.owner;
|
||||
contents = reusePopup.contents;
|
||||
popupWindow = reusePopup.popupWindow;
|
||||
oldPopupWindowBackground = reusePopup.oldPopupWindowBackground;
|
||||
}
|
||||
|
||||
NonFlashingPopup cloneForReuse() {
|
||||
return new NonFlashingPopup( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
public final void show() {
|
||||
if( disposed )
|
||||
return;
|
||||
|
||||
showImpl();
|
||||
}
|
||||
|
||||
void showImpl() {
|
||||
if( delegate != null ) {
|
||||
showPopupAndFixLocation( delegate, popupWindow );
|
||||
|
||||
@@ -540,13 +647,36 @@ public class FlatPopupFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
public final void hide() {
|
||||
if( disposed )
|
||||
return;
|
||||
disposed = true;
|
||||
|
||||
// immediately hide non-heavy weight popups or combobox popups
|
||||
if( !(popupWindow instanceof JWindow) || contents instanceof BasicComboPopup ) {
|
||||
hideImpl();
|
||||
return;
|
||||
}
|
||||
|
||||
// defer hiding of heavy weight popup window for an event cycle,
|
||||
// which allows reusing popup window to avoid flicker when "moving" popup
|
||||
((JWindow)popupWindow).getContentPane().removeAll();
|
||||
stillShownHeavyWeightPopups.add( this );
|
||||
EventQueue.invokeLater( () -> {
|
||||
// hide popup if it was not reused
|
||||
if( stillShownHeavyWeightPopups.remove( this ) )
|
||||
hideImpl();
|
||||
} );
|
||||
}
|
||||
|
||||
void hideImpl() {
|
||||
if( contents instanceof JComponent )
|
||||
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, null );
|
||||
|
||||
if( delegate != null ) {
|
||||
delegate.hide();
|
||||
delegate = null;
|
||||
owner = null;
|
||||
contents = null;
|
||||
}
|
||||
|
||||
@@ -557,6 +687,28 @@ public class FlatPopupFactory
|
||||
popupWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
void reset( Component contents, int ownerX, int ownerY ) {
|
||||
// update popup window location
|
||||
popupWindow.setLocation( ownerX, ownerY );
|
||||
|
||||
// replace component in content pane
|
||||
Container contentPane = ((JWindow)popupWindow).getContentPane();
|
||||
contentPane.removeAll();
|
||||
contentPane.add( contents, BorderLayout.CENTER );
|
||||
popupWindow.pack();
|
||||
|
||||
// update client property on contents
|
||||
if( this.contents != contents ) {
|
||||
Object old = (this.contents instanceof JComponent)
|
||||
? ((JComponent)this.contents).getClientProperty( KEY_POPUP_USES_NATIVE_BORDER )
|
||||
: null;
|
||||
if( contents instanceof JComponent )
|
||||
((JComponent)contents).putClientProperty( KEY_POPUP_USES_NATIVE_BORDER, old );
|
||||
|
||||
this.contents = contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---- class DropShadowPopup ----------------------------------------------
|
||||
@@ -564,8 +716,6 @@ public class FlatPopupFactory
|
||||
private class DropShadowPopup
|
||||
extends NonFlashingPopup
|
||||
{
|
||||
private final Component owner;
|
||||
|
||||
// light weight
|
||||
private JComponent lightComp;
|
||||
private Border oldBorder;
|
||||
@@ -580,11 +730,11 @@ public class FlatPopupFactory
|
||||
// heavy weight
|
||||
private Popup dropShadowDelegate;
|
||||
private Window dropShadowWindow;
|
||||
private JPanel dropShadowPanel2;
|
||||
private Color oldDropShadowWindowBackground;
|
||||
|
||||
DropShadowPopup( Popup delegate, Component owner, Component contents ) {
|
||||
super( delegate, contents );
|
||||
this.owner = owner;
|
||||
super( delegate, owner, contents );
|
||||
|
||||
Dimension size = contents.getPreferredSize();
|
||||
if( size.width <= 0 || size.height <= 0 )
|
||||
@@ -600,24 +750,24 @@ public class FlatPopupFactory
|
||||
// the drop shadow and is positioned behind the popup window.
|
||||
|
||||
// create panel that paints the drop shadow
|
||||
JPanel dropShadowPanel = new JPanel();
|
||||
dropShadowPanel.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel.setOpaque( false );
|
||||
dropShadowPanel2 = new JPanel();
|
||||
dropShadowPanel2.setBorder( createDropShadowBorder() );
|
||||
dropShadowPanel2.setOpaque( false );
|
||||
|
||||
// set preferred size of drop shadow panel
|
||||
Dimension prefSize = popupWindow.getPreferredSize();
|
||||
Insets insets = dropShadowPanel.getInsets();
|
||||
dropShadowPanel.setPreferredSize( new Dimension(
|
||||
Insets insets = dropShadowPanel2.getInsets();
|
||||
dropShadowPanel2.setPreferredSize( new Dimension(
|
||||
prefSize.width + insets.left + insets.right,
|
||||
prefSize.height + insets.top + insets.bottom ) );
|
||||
|
||||
// create heavy weight popup for drop shadow
|
||||
int x = popupWindow.getX() - insets.left;
|
||||
int y = popupWindow.getY() - insets.top;
|
||||
dropShadowDelegate = getPopupForScreenOfOwner( owner, dropShadowPanel, x, y, true );
|
||||
dropShadowDelegate = getPopupForScreenOfOwner( owner, dropShadowPanel2, x, y, true );
|
||||
|
||||
// make drop shadow popup window translucent
|
||||
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel );
|
||||
dropShadowWindow = SwingUtilities.windowForComponent( dropShadowPanel2 );
|
||||
if( dropShadowWindow != null ) {
|
||||
oldDropShadowWindowBackground = dropShadowWindow.getBackground();
|
||||
dropShadowWindow.setBackground( new Color( 0, true ) );
|
||||
@@ -654,6 +804,23 @@ public class FlatPopupFactory
|
||||
}
|
||||
}
|
||||
|
||||
private DropShadowPopup( DropShadowPopup reusePopup ) {
|
||||
super( reusePopup );
|
||||
|
||||
// not necessary to clone fields used for light/medium weight popups
|
||||
|
||||
// heavy weight
|
||||
dropShadowDelegate = reusePopup.dropShadowDelegate;
|
||||
dropShadowWindow = reusePopup.dropShadowWindow;
|
||||
dropShadowPanel2 = reusePopup.dropShadowPanel2;
|
||||
oldDropShadowWindowBackground = reusePopup.oldDropShadowWindowBackground;
|
||||
}
|
||||
|
||||
@Override
|
||||
NonFlashingPopup cloneForReuse() {
|
||||
return new DropShadowPopup( this );
|
||||
}
|
||||
|
||||
private Border createDropShadowBorder() {
|
||||
return new FlatDropShadowBorder(
|
||||
UIManager.getColor( "Popup.dropShadowColor" ),
|
||||
@@ -662,14 +829,14 @@ public class FlatPopupFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
void showImpl() {
|
||||
if( dropShadowDelegate != null )
|
||||
showPopupAndFixLocation( dropShadowDelegate, dropShadowWindow );
|
||||
|
||||
if( mediumWeightPanel != null )
|
||||
showMediumWeightDropShadow();
|
||||
|
||||
super.show();
|
||||
super.showImpl();
|
||||
|
||||
// fix location of light weight popup in case it has left or top drop shadow
|
||||
if( lightComp != null ) {
|
||||
@@ -680,10 +847,11 @@ public class FlatPopupFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
void hideImpl() {
|
||||
if( dropShadowDelegate != null ) {
|
||||
dropShadowDelegate.hide();
|
||||
dropShadowDelegate = null;
|
||||
dropShadowPanel2 = null;
|
||||
}
|
||||
|
||||
if( mediumWeightPanel != null ) {
|
||||
@@ -692,7 +860,7 @@ public class FlatPopupFactory
|
||||
mediumWeightPanel = null;
|
||||
}
|
||||
|
||||
super.hide();
|
||||
super.hideImpl();
|
||||
|
||||
if( dropShadowWindow != null ) {
|
||||
dropShadowWindow.setBackground( oldDropShadowWindowBackground );
|
||||
@@ -776,5 +944,26 @@ public class FlatPopupFactory
|
||||
if( dropShadowPanel != null && mediumWeightPanel != null )
|
||||
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
void reset( Component contents, int ownerX, int ownerY ) {
|
||||
super.reset( contents, ownerX, ownerY );
|
||||
|
||||
if( dropShadowWindow != null ) {
|
||||
// set preferred size of drop shadow panel
|
||||
Dimension prefSize = popupWindow.getPreferredSize();
|
||||
Insets insets = dropShadowPanel2.getInsets();
|
||||
int w = prefSize.width + insets.left + insets.right;
|
||||
int h = prefSize.height + insets.top + insets.bottom;
|
||||
dropShadowPanel2.setPreferredSize( new Dimension( w, h ) );
|
||||
dropShadowPanel2.invalidate();
|
||||
dropShadowWindow.pack();
|
||||
|
||||
// update drop shadow popup window location
|
||||
int x = popupWindow.getX() - insets.left;
|
||||
int y = popupWindow.getY() - insets.top;
|
||||
dropShadowWindow.setLocation( x, y );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,11 +239,13 @@ public class FlatPopupMenuUI
|
||||
if( gc == null && popupMenu.getInvoker() != null )
|
||||
gc = popupMenu.getInvoker().getGraphicsConfiguration();
|
||||
|
||||
// compute screen height
|
||||
if( gc == null )
|
||||
return new Rectangle( Toolkit.getDefaultToolkit().getScreenSize() );
|
||||
|
||||
// compute screen bounds
|
||||
// (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() );
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
@@ -86,6 +87,17 @@ public class FlatProgressBarUI
|
||||
installStyle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
if( !EventQueue.isDispatchThread() && progressBar.isIndeterminate() ) {
|
||||
LoggingFacade.INSTANCE.logSevere(
|
||||
"FlatLaf: Uninstalling indeterminate progress bar UI not on AWT thread may throw NPE in FlatProgressBarUI.paint(). Use SwingUtilities.invokeLater().",
|
||||
new IllegalStateException() );
|
||||
}
|
||||
|
||||
super.uninstallUI( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -110,17 +122,25 @@ public class FlatProgressBarUI
|
||||
|
||||
propertyChangeListener = e -> {
|
||||
switch( e.getPropertyName() ) {
|
||||
case "indeterminate":
|
||||
if( !EventQueue.isDispatchThread() && !progressBar.isIndeterminate() ) {
|
||||
LoggingFacade.INSTANCE.logSevere(
|
||||
"FlatLaf: Using JProgressBar.setIndeterminate(false) not on AWT thread may throw NPE in FlatProgressBarUI.paint(). Use SwingUtilities.invokeLater().",
|
||||
new IllegalStateException() );
|
||||
}
|
||||
break;
|
||||
|
||||
case PROGRESS_BAR_LARGE_HEIGHT:
|
||||
case PROGRESS_BAR_SQUARE:
|
||||
progressBar.revalidate();
|
||||
progressBar.repaint();
|
||||
HiDPIUtils.repaint( progressBar );
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
progressBar.revalidate();
|
||||
progressBar.repaint();
|
||||
HiDPIUtils.repaint( progressBar );
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -274,6 +294,6 @@ public class FlatProgressBarUI
|
||||
// Only solution is to repaint whole progress bar.
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( progressBar.getGraphicsConfiguration() );
|
||||
if( (int) systemScaleFactor != systemScaleFactor )
|
||||
progressBar.repaint();
|
||||
HiDPIUtils.repaint( progressBar );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.util.Map;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||
@@ -102,13 +103,23 @@ public class FlatRadioButtonMenuItemUI
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JMenuItem menuItem ) {
|
||||
super.installComponents( menuItem );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( menuItem );
|
||||
}
|
||||
|
||||
protected FlatMenuItemRenderer createRenderer() {
|
||||
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
|
||||
return FlatHTML.createPropertyChangeListener(
|
||||
FlatStylingSupport.createPropertyChangeListener( c, this::installStyle,
|
||||
super.createPropertyChangeListener( c ) ) );
|
||||
}
|
||||
|
||||
/** @since 2 */
|
||||
|
||||
@@ -40,12 +40,14 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicRadioButtonUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -159,6 +161,10 @@ public class FlatRadioButtonUI
|
||||
/** @since 2 */
|
||||
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
|
||||
switch( e.getPropertyName() ) {
|
||||
case BasicHTML.propertyKey:
|
||||
FlatHTML.updateRendererCSSFontBaseSize( b );
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
|
||||
@@ -168,7 +174,7 @@ public class FlatRadioButtonUI
|
||||
} else
|
||||
installStyle( b );
|
||||
b.revalidate();
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,6 +448,11 @@ public class FlatRootPaneUI
|
||||
titlePane.titleBarColorsChanged();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.TITLE_BAR_HEIGHT:
|
||||
if( titlePane != null )
|
||||
titlePane.revalidate();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.FULL_WINDOW_CONTENT:
|
||||
if( titlePane != null ) {
|
||||
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableField;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableLookupProvider;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -212,14 +213,14 @@ public class FlatScrollBarUI
|
||||
switch( e.getPropertyName() ) {
|
||||
case FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS:
|
||||
scrollbar.revalidate();
|
||||
scrollbar.repaint();
|
||||
HiDPIUtils.repaint( scrollbar );
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
scrollbar.revalidate();
|
||||
scrollbar.repaint();
|
||||
HiDPIUtils.repaint( scrollbar );
|
||||
break;
|
||||
|
||||
case "componentOrientation":
|
||||
@@ -492,7 +493,7 @@ public class FlatScrollBarUI
|
||||
|
||||
private void repaint() {
|
||||
if( scrollbar.isEnabled() )
|
||||
scrollbar.repaint();
|
||||
HiDPIUtils.repaint( scrollbar );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import javax.swing.plaf.basic.BasicScrollPaneUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -209,7 +210,7 @@ public class FlatScrollPaneUI
|
||||
|
||||
// Use (0, 0) view position to obtain a constant unit increment of first item.
|
||||
// Unit increment may be different for each item.
|
||||
Rectangle visibleRect = new Rectangle( viewport.getViewSize() );
|
||||
Rectangle visibleRect = new Rectangle( viewport.getExtentSize() );
|
||||
unitIncrement = scrollable.getScrollableUnitIncrement( visibleRect, orientation, 1 );
|
||||
|
||||
if( unitIncrement > 0 ) {
|
||||
@@ -297,11 +298,11 @@ public class FlatScrollPaneUI
|
||||
JScrollBar hsb = scrollpane.getHorizontalScrollBar();
|
||||
if( vsb != null ) {
|
||||
vsb.revalidate();
|
||||
vsb.repaint();
|
||||
HiDPIUtils.repaint( vsb );
|
||||
}
|
||||
if( hsb != null ) {
|
||||
hsb.revalidate();
|
||||
hsb.repaint();
|
||||
HiDPIUtils.repaint( hsb );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -321,14 +322,14 @@ public class FlatScrollPaneUI
|
||||
break;
|
||||
|
||||
case FlatClientProperties.OUTLINE:
|
||||
scrollpane.repaint();
|
||||
HiDPIUtils.repaint( scrollpane );
|
||||
break;
|
||||
|
||||
case FlatClientProperties.STYLE:
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
scrollpane.revalidate();
|
||||
scrollpane.repaint();
|
||||
HiDPIUtils.repaint( scrollpane );
|
||||
break;
|
||||
|
||||
case "border":
|
||||
@@ -339,7 +340,7 @@ public class FlatScrollPaneUI
|
||||
borderShared = null;
|
||||
installStyle();
|
||||
scrollpane.revalidate();
|
||||
scrollpane.repaint();
|
||||
HiDPIUtils.repaint( scrollpane );
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -538,14 +539,14 @@ public class FlatScrollPaneUI
|
||||
public void focusGained( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||
scrollpane.repaint();
|
||||
HiDPIUtils.repaint( scrollpane );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
if( scrollpane.getBorder() instanceof FlatBorder )
|
||||
scrollpane.repaint();
|
||||
HiDPIUtils.repaint( scrollpane );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ 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.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
@@ -134,7 +135,7 @@ public class FlatSeparatorUI
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
HiDPIUtils.repaint( s );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Path2D;
|
||||
@@ -191,6 +193,23 @@ public class FlatSliderUI
|
||||
return new FlatTrackListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FocusListener createFocusListener( JSlider slider ) {
|
||||
return new BasicSliderUI.FocusHandler() {
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
super.focusGained( e );
|
||||
HiDPIUtils.repaint( slider );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
super.focusLost( e );
|
||||
HiDPIUtils.repaint( slider );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
|
||||
return FlatStylingSupport.createPropertyChangeListener( slider, this::installStyle,
|
||||
@@ -422,7 +441,7 @@ debug*/
|
||||
Color thumbColor, Color thumbBorderColor, Color focusedColor, float thumbBorderWidth, int focusWidth )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
if( systemScaleFactor != (int) systemScaleFactor ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
@@ -579,15 +598,15 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void setThumbLocation( int x, int y ) {
|
||||
// set new thumb location and compute union of old and new thumb bounds
|
||||
Rectangle r = new Rectangle( thumbRect );
|
||||
thumbRect.setLocation( x, y );
|
||||
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, r );
|
||||
|
||||
if( !isRoundThumb() ) {
|
||||
// the needle of the directional thumb is painted outside of thumbRect
|
||||
// --> must increase repaint rectangle
|
||||
|
||||
// set new thumb location and compute union of old and new thumb bounds
|
||||
Rectangle r = new Rectangle( thumbRect );
|
||||
thumbRect.setLocation( x, y );
|
||||
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, r );
|
||||
|
||||
// increase union rectangle for repaint
|
||||
int extra = (int) Math.ceil( UIScale.scale( focusWidth ) * 0.4142f );
|
||||
if( slider.getOrientation() == JSlider.HORIZONTAL )
|
||||
@@ -597,10 +616,9 @@ debug*/
|
||||
if( !slider.getComponentOrientation().isLeftToRight() )
|
||||
r.x -= extra;
|
||||
}
|
||||
}
|
||||
|
||||
slider.repaint( r );
|
||||
} else
|
||||
super.setThumbLocation( x, y );
|
||||
HiDPIUtils.repaint( slider, r );
|
||||
}
|
||||
|
||||
//---- class FlatTrackListener --------------------------------------------
|
||||
@@ -688,21 +706,21 @@ debug*/
|
||||
!UIManager.getBoolean( "Slider.snapToTicksOnReleased" ) )
|
||||
{
|
||||
calculateThumbLocation();
|
||||
slider.repaint();
|
||||
HiDPIUtils.repaint( slider );
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbHover( boolean hover ) {
|
||||
if( hover != thumbHover ) {
|
||||
thumbHover = hover;
|
||||
slider.repaint( thumbRect );
|
||||
HiDPIUtils.repaint( slider, thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
protected void setThumbPressed( boolean pressed ) {
|
||||
if( pressed != thumbPressed ) {
|
||||
thumbPressed = pressed;
|
||||
slider.repaint( thumbRect );
|
||||
HiDPIUtils.repaint( slider, thumbRect );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
@@ -586,7 +587,7 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
spinner.repaint();
|
||||
HiDPIUtils.repaint( spinner );
|
||||
|
||||
// if spinner gained focus, transfer it to the editor text field
|
||||
if( e.getComponent() == spinner ) {
|
||||
@@ -599,7 +600,7 @@ public class FlatSpinnerUI
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
// necessary to update focus border
|
||||
spinner.repaint();
|
||||
HiDPIUtils.repaint( spinner );
|
||||
}
|
||||
|
||||
//---- interface PropertyChangeListener ----
|
||||
@@ -614,7 +615,7 @@ public class FlatSpinnerUI
|
||||
|
||||
case FlatClientProperties.COMPONENT_ROUND_RECT:
|
||||
case FlatClientProperties.OUTLINE:
|
||||
spinner.repaint();
|
||||
HiDPIUtils.repaint( spinner );
|
||||
break;
|
||||
|
||||
case FlatClientProperties.MINIMUM_WIDTH:
|
||||
@@ -625,7 +626,7 @@ public class FlatSpinnerUI
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
spinner.revalidate();
|
||||
spinner.repaint();
|
||||
HiDPIUtils.repaint( spinner );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
@@ -709,7 +710,7 @@ public class FlatStylingSupport
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle.run();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -98,6 +98,7 @@ import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.Animator;
|
||||
import com.formdev.flatlaf.util.CubicBezierEasing;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
@@ -895,7 +896,7 @@ public class FlatTabbedPaneUI
|
||||
}
|
||||
}
|
||||
|
||||
tabPane.repaint( r );
|
||||
HiDPIUtils.repaint( tabPane, r );
|
||||
}
|
||||
|
||||
private boolean inCalculateEqual;
|
||||
@@ -1684,7 +1685,7 @@ debug*/
|
||||
w - (ci.left / 100f) - (ci.right / 100f), h - (ci.top / 100f) - (ci.bottom / 100f) ), false );
|
||||
|
||||
// add gap for selected tab to path
|
||||
if( getTabType() == TAB_TYPE_CARD ) {
|
||||
if( getTabType() == TAB_TYPE_CARD && selectedIndex >= 0 ) {
|
||||
float csh = scale( (float) contentSeparatorHeight );
|
||||
|
||||
Rectangle tabRect = getTabBounds( tabPane, selectedIndex );
|
||||
@@ -2305,8 +2306,23 @@ debug*/
|
||||
/** @since 3.4 */
|
||||
@Override
|
||||
public Boolean isTitleBarCaptionAt( int x, int y ) {
|
||||
if( tabForCoordinate( tabPane, x, y ) >= 0 )
|
||||
return false;
|
||||
// Note: not using tabForCoordinate() here because this may validate layout and cause dead lock
|
||||
|
||||
if( moreTabsButton != null ) {
|
||||
// convert x,y from JTabbedPane coordinate space to ScrollableTabPanel coordinate space
|
||||
Point viewPosition = tabViewport.getViewPosition();
|
||||
x = x - tabViewport.getX() + viewPosition.x;
|
||||
y = y - tabViewport.getY() + viewPosition.y;
|
||||
|
||||
// check whether point is within viewport
|
||||
if( !tabViewport.getViewRect().contains( x, y ) )
|
||||
return null; // check children
|
||||
}
|
||||
|
||||
for( int i = 0; i < rects.length; i++ ) {
|
||||
if( rects[i].contains( x, y ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return null; // check children
|
||||
}
|
||||
@@ -2581,19 +2597,19 @@ debug*/
|
||||
@Override
|
||||
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
|
||||
popupVisible = true;
|
||||
repaint();
|
||||
HiDPIUtils.repaint( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
|
||||
popupVisible = false;
|
||||
repaint();
|
||||
HiDPIUtils.repaint( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuCanceled( PopupMenuEvent e ) {
|
||||
popupVisible = false;
|
||||
repaint();
|
||||
HiDPIUtils.repaint( this );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3102,7 +3118,7 @@ debug*/
|
||||
|
||||
case TABBED_PANE_SHOW_TAB_SEPARATORS:
|
||||
case TABBED_PANE_TAB_TYPE:
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
break;
|
||||
|
||||
case TABBED_PANE_SHOW_CONTENT_SEPARATOR:
|
||||
@@ -3125,14 +3141,14 @@ debug*/
|
||||
case TABBED_PANE_TAB_ICON_PLACEMENT:
|
||||
case TABBED_PANE_TAB_CLOSABLE:
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
break;
|
||||
|
||||
case TABBED_PANE_LEADING_COMPONENT:
|
||||
uninstallLeadingComponent();
|
||||
installLeadingComponent();
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
ensureSelectedTabIsVisibleLater();
|
||||
break;
|
||||
|
||||
@@ -3140,7 +3156,7 @@ debug*/
|
||||
uninstallTrailingComponent();
|
||||
installTrailingComponent();
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
ensureSelectedTabIsVisibleLater();
|
||||
break;
|
||||
|
||||
@@ -3148,7 +3164,7 @@ debug*/
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3172,7 +3188,7 @@ debug*/
|
||||
case TABBED_PANE_TAB_ALIGNMENT:
|
||||
case TABBED_PANE_TAB_CLOSABLE:
|
||||
tabPane.revalidate();
|
||||
tabPane.repaint();
|
||||
HiDPIUtils.repaint( tabPane );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,28 @@ public class FlatTableCellBorder
|
||||
return super.getLineColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArc() {
|
||||
if( c != null ) {
|
||||
Integer selectionArc = getStyleFromTableUI( c, ui -> ui.selectionArc );
|
||||
if( selectionArc != null )
|
||||
return selectionArc;
|
||||
}
|
||||
return super.getArc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
|
||||
if( c != null ) {
|
||||
Insets selectionInsets = getStyleFromTableUI( c, ui -> ui.selectionInsets );
|
||||
if( selectionInsets != null ) {
|
||||
x += selectionInsets.left;
|
||||
y += selectionInsets.top;
|
||||
width -= selectionInsets.left + selectionInsets.right;
|
||||
height -= selectionInsets.top + selectionInsets.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
this.c = c;
|
||||
super.paintBorder( c, g, x, y, width, height );
|
||||
this.c = null;
|
||||
|
||||
@@ -45,6 +45,7 @@ import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -234,8 +235,8 @@ public class FlatTableHeaderUI
|
||||
|
||||
@Override
|
||||
protected void rolloverColumnUpdated( int oldColumn, int newColumn ) {
|
||||
header.repaint( header.getHeaderRect( oldColumn ) );
|
||||
header.repaint( header.getHeaderRect( newColumn ) );
|
||||
HiDPIUtils.repaint( header, header.getHeaderRect( oldColumn ) );
|
||||
HiDPIUtils.repaint( header, header.getHeaderRect( newColumn ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,7 +24,13 @@ import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
@@ -38,21 +44,29 @@ import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.event.TableColumnModelEvent;
|
||||
import javax.swing.event.TableColumnModelListener;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -92,6 +106,8 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
* @uiDefault Table.intercellSpacing Dimension
|
||||
* @uiDefault Table.selectionInactiveBackground Color
|
||||
* @uiDefault Table.selectionInactiveForeground Color
|
||||
* @uiDefault Table.selectionInsets Insets
|
||||
* @uiDefault Table.selectionArc int
|
||||
* @uiDefault Table.paintOutsideAlternateRows boolean
|
||||
* @uiDefault Table.editorSelectAllOnStartEditing boolean
|
||||
*
|
||||
@@ -120,6 +136,8 @@ public class FlatTableUI
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
/** @since 3.5 */ @Styleable protected Insets selectionInsets;
|
||||
/** @since 3.5 */ @Styleable protected int selectionArc;
|
||||
|
||||
// for FlatTableCellBorder
|
||||
/** @since 2 */ @Styleable protected Insets cellMargins;
|
||||
@@ -132,6 +150,9 @@ public class FlatTableUI
|
||||
private TableCellRenderer oldBooleanRenderer;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private ComponentListener outsideAlternateRowsListener;
|
||||
private ListSelectionListener rowSelectionListener;
|
||||
private TableColumnModelListener columnSelectionListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
@@ -158,6 +179,8 @@ public class FlatTableUI
|
||||
selectionForeground = UIManager.getColor( "Table.selectionForeground" );
|
||||
selectionInactiveBackground = UIManager.getColor( "Table.selectionInactiveBackground" );
|
||||
selectionInactiveForeground = UIManager.getColor( "Table.selectionInactiveForeground" );
|
||||
selectionInsets = UIManager.getInsets( "Table.selectionInsets" );
|
||||
selectionArc = UIManager.getInt( "Table.selectionArc" );
|
||||
|
||||
toggleSelectionColors();
|
||||
|
||||
@@ -245,6 +268,28 @@ public class FlatTableUI
|
||||
|
||||
propertyChangeListener = e -> {
|
||||
switch( e.getPropertyName() ) {
|
||||
case "selectionModel":
|
||||
if( rowSelectionListener != null ) {
|
||||
Object oldModel = e.getOldValue();
|
||||
Object newModel = e.getNewValue();
|
||||
if( oldModel != null )
|
||||
((ListSelectionModel)oldModel).removeListSelectionListener( rowSelectionListener );
|
||||
if( newModel != null )
|
||||
((ListSelectionModel)newModel).addListSelectionListener( rowSelectionListener );
|
||||
}
|
||||
break;
|
||||
|
||||
case "columnModel":
|
||||
if( columnSelectionListener != null ) {
|
||||
Object oldModel = e.getOldValue();
|
||||
Object newModel = e.getNewValue();
|
||||
if( oldModel != null )
|
||||
((TableColumnModel)oldModel).removeColumnModelListener( columnSelectionListener );
|
||||
if( newModel != null )
|
||||
((TableColumnModel)newModel).addColumnModelListener( columnSelectionListener );
|
||||
}
|
||||
break;
|
||||
|
||||
case FlatClientProperties.COMPONENT_FOCUS_OWNER:
|
||||
toggleSelectionColors();
|
||||
break;
|
||||
@@ -253,11 +298,14 @@ public class FlatTableUI
|
||||
case FlatClientProperties.STYLE_CLASS:
|
||||
installStyle();
|
||||
table.revalidate();
|
||||
table.repaint();
|
||||
HiDPIUtils.repaint( table );
|
||||
break;
|
||||
}
|
||||
};
|
||||
table.addPropertyChangeListener( propertyChangeListener );
|
||||
|
||||
if( selectionArc > 0 )
|
||||
installRepaintRoundedSelectionListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -266,6 +314,19 @@ public class FlatTableUI
|
||||
|
||||
table.removePropertyChangeListener( propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
|
||||
if( outsideAlternateRowsListener != null ) {
|
||||
table.removeComponentListener( outsideAlternateRowsListener );
|
||||
outsideAlternateRowsListener = null;
|
||||
}
|
||||
if( rowSelectionListener != null ) {
|
||||
table.getSelectionModel().removeListSelectionListener( rowSelectionListener );
|
||||
rowSelectionListener = null;
|
||||
}
|
||||
if( columnSelectionListener != null ) {
|
||||
table.getColumnModel().removeColumnModelListener( columnSelectionListener );
|
||||
columnSelectionListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -342,6 +403,8 @@ public class FlatTableUI
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
if( "rowHeight".equals( key ) && value instanceof Integer )
|
||||
value = UIScale.scale( (Integer) value );
|
||||
else if( "selectionArc".equals( key ) && value instanceof Integer && (Integer) value > 0 )
|
||||
installRepaintRoundedSelectionListeners();
|
||||
|
||||
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
|
||||
}
|
||||
@@ -404,6 +467,7 @@ public class FlatTableUI
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||
double lineThickness = (1. / systemScaleFactor) * (int) systemScaleFactor;
|
||||
double lineOffset = (1. - lineThickness) + 0.05; // adding 0.05 to fix line location in some cases
|
||||
|
||||
// Java 8 uses drawLine() to paint grid lines
|
||||
// Java 9+ uses fillRect() to paint grid lines (except for dragged column)
|
||||
@@ -446,11 +510,11 @@ public class FlatTableUI
|
||||
// reduce line thickness to avoid unstable painted line thickness
|
||||
if( lineThickness != 1 ) {
|
||||
if( horizontalLines && height == 1 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, width, lineThickness ) );
|
||||
super.fill( new Rectangle2D.Double( x, y + lineOffset, width, lineThickness ) );
|
||||
return;
|
||||
}
|
||||
if( verticalLines && width == 1 && y == 0 && wasInvokedFromPaintGrid() ) {
|
||||
super.fill( new Rectangle2D.Double( x, y, lineThickness, height ) );
|
||||
super.fill( new Rectangle2D.Double( x + lineOffset, y, lineThickness, height ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -468,6 +532,10 @@ public class FlatTableUI
|
||||
};
|
||||
}
|
||||
|
||||
// rounded selection or selection insets
|
||||
if( selectionArc > 0 || (selectionInsets != null && !FlatUIUtils.isInsetsEmpty( selectionInsets )) )
|
||||
g = new RoundedSelectionGraphics( g, UIManager.getColor( "Table.alternateRowColor" ) );
|
||||
|
||||
super.paint( g, c );
|
||||
}
|
||||
|
||||
@@ -513,8 +581,6 @@ public class FlatTableUI
|
||||
boolean paintOutside = UIManager.getBoolean( "Table.paintOutsideAlternateRows" );
|
||||
Color alternateColor;
|
||||
if( paintOutside && (alternateColor = UIManager.getColor( "Table.alternateRowColor" )) != null ) {
|
||||
g.setColor( alternateColor );
|
||||
|
||||
int rowCount = table.getRowCount();
|
||||
|
||||
// paint alternating empty rows below the table
|
||||
@@ -523,10 +589,350 @@ public class FlatTableUI
|
||||
int tableWidth = table.getWidth();
|
||||
int rowHeight = table.getRowHeight();
|
||||
|
||||
g.setColor( alternateColor );
|
||||
|
||||
int x = viewport.getComponentOrientation().isLeftToRight() ? 0 : viewportWidth - tableWidth;
|
||||
for( int y = tableHeight, row = rowCount; y < viewportHeight; y += rowHeight, row++ ) {
|
||||
if( row % 2 != 0 )
|
||||
g.fillRect( 0, y, tableWidth, rowHeight );
|
||||
paintAlternateRowBackground( g, -1, -1, x, y, tableWidth, rowHeight );
|
||||
}
|
||||
|
||||
// add listener on demand
|
||||
if( outsideAlternateRowsListener == null && table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF ) {
|
||||
outsideAlternateRowsListener = new FlatOutsideAlternateRowsListener();
|
||||
table.addComponentListener( outsideAlternateRowsListener );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints (rounded) alternate row background.
|
||||
* Supports {@link #selectionArc} and {@link #selectionInsets}.
|
||||
* <p>
|
||||
* <b>Note:</b> This method is only invoked if either selection arc
|
||||
* is greater than zero or if selection insets are not empty.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
protected void paintAlternateRowBackground( Graphics g, int row, int column, int x, int y, int width, int height ) {
|
||||
Insets insets = (selectionInsets != null) ? (Insets) selectionInsets.clone() : null;
|
||||
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
||||
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
||||
|
||||
if( column >= 0 ) {
|
||||
// selection insets
|
||||
|
||||
// selection arc
|
||||
if( column > 0 ) {
|
||||
if( insets != null )
|
||||
insets.left = 0;
|
||||
|
||||
if( table.getComponentOrientation().isLeftToRight() )
|
||||
arcTopLeft = arcBottomLeft = 0;
|
||||
else
|
||||
arcTopRight = arcBottomRight = 0;
|
||||
}
|
||||
if( column < table.getColumnCount() - 1 ) {
|
||||
if( insets != null )
|
||||
insets.right = 0;
|
||||
|
||||
if( table.getComponentOrientation().isLeftToRight() )
|
||||
arcTopRight = arcBottomRight = 0;
|
||||
else
|
||||
arcTopLeft = arcBottomLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FlatUIUtils.paintSelection( (Graphics2D) g, x, y, width, height,
|
||||
UIScale.scale( insets ), arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints (rounded) cell selection.
|
||||
* Supports {@link #selectionArc} and {@link #selectionInsets}.
|
||||
* <p>
|
||||
* <b>Note:</b> This method is only invoked if either selection arc
|
||||
* is greater than zero or if selection insets are not empty.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
protected void paintCellSelection( Graphics g, int row, int column, int x, int y, int width, int height ) {
|
||||
boolean rowSelAllowed = table.getRowSelectionAllowed();
|
||||
boolean colSelAllowed = table.getColumnSelectionAllowed();
|
||||
boolean rowSelOnly = rowSelAllowed && !colSelAllowed;
|
||||
boolean colSelOnly = colSelAllowed && !rowSelAllowed;
|
||||
boolean cellOnlySel = rowSelAllowed && colSelAllowed;
|
||||
|
||||
// get selection state of surrounding cells
|
||||
boolean leftSelected = (column > 0 && (rowSelOnly || table.isCellSelected( row, column - 1 )));
|
||||
boolean topSelected = (row > 0 && (colSelOnly || table.isCellSelected( row - 1, column )));
|
||||
boolean rightSelected = (column < table.getColumnCount() - 1 && (rowSelOnly || table.isCellSelected( row, column + 1 )));
|
||||
boolean bottomSelected = (row < table.getRowCount() - 1 && (colSelOnly || table.isCellSelected( row + 1, column )));
|
||||
if( !table.getComponentOrientation().isLeftToRight() ) {
|
||||
boolean temp = leftSelected;
|
||||
leftSelected = rightSelected;
|
||||
rightSelected = temp;
|
||||
}
|
||||
|
||||
// selection insets
|
||||
// (insets are applied to whole row if row-only selection is used,
|
||||
// or to whole column if column-only selection is used,
|
||||
// or to cell if cell selection is used)
|
||||
Insets insets = (selectionInsets != null) ? (Insets) selectionInsets.clone() : null;
|
||||
if( insets != null ) {
|
||||
if( rowSelOnly && leftSelected )
|
||||
insets.left = 0;
|
||||
if( rowSelOnly && rightSelected )
|
||||
insets.right = 0;
|
||||
if( colSelOnly && topSelected )
|
||||
insets.top = 0;
|
||||
if( colSelOnly && bottomSelected )
|
||||
insets.bottom = 0;
|
||||
}
|
||||
|
||||
// selection arc
|
||||
float arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight;
|
||||
arcTopLeft = arcTopRight = arcBottomLeft = arcBottomRight = UIScale.scale( selectionArc / 2f );
|
||||
if( selectionArc > 0 ) {
|
||||
// note that intercellSpacing is not considered as a gap because
|
||||
// grid lines are usually painted to intercell space
|
||||
boolean hasRowGap = (rowSelOnly || cellOnlySel) && insets != null && (insets.top != 0 || insets.bottom != 0);
|
||||
boolean hasColGap = (colSelOnly || cellOnlySel) && insets != null && (insets.left != 0 || insets.right != 0);
|
||||
|
||||
if( leftSelected && !hasColGap )
|
||||
arcTopLeft = arcBottomLeft = 0;
|
||||
if( rightSelected && !hasColGap )
|
||||
arcTopRight = arcBottomRight = 0;
|
||||
if( topSelected && !hasRowGap )
|
||||
arcTopLeft = arcTopRight = 0;
|
||||
if( bottomSelected && !hasRowGap )
|
||||
arcBottomLeft = arcBottomRight = 0;
|
||||
}
|
||||
|
||||
FlatUIUtils.paintSelection( (Graphics2D) g, x, y, width, height,
|
||||
UIScale.scale( insets ), arcTopLeft, arcTopRight, arcBottomLeft, arcBottomRight, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints a cell selection at the given coordinates.
|
||||
* The selection color must be set on the graphics context.
|
||||
* <p>
|
||||
* This method is intended for use in custom cell renderers to support
|
||||
* {@link #selectionArc} and {@link #selectionInsets}.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void paintCellSelection( JTable table, Graphics g, int row, int column, int x, int y, int width, int height ) {
|
||||
if( !(table.getUI() instanceof FlatTableUI) )
|
||||
return;
|
||||
|
||||
FlatTableUI ui = (FlatTableUI) table.getUI();
|
||||
ui.paintCellSelection( g, row, column, x, y, width, height );
|
||||
}
|
||||
|
||||
private void installRepaintRoundedSelectionListeners() {
|
||||
if( rowSelectionListener == null ) {
|
||||
rowSelectionListener = this::repaintRoundedRowSelection;
|
||||
table.getSelectionModel().addListSelectionListener( rowSelectionListener );
|
||||
}
|
||||
|
||||
if( columnSelectionListener == null ) {
|
||||
columnSelectionListener = new TableColumnModelListener() {
|
||||
@Override
|
||||
public void columnSelectionChanged( ListSelectionEvent e ) {
|
||||
repaintRoundedColumnSelection( e );
|
||||
}
|
||||
@Override public void columnRemoved( TableColumnModelEvent e ) {}
|
||||
@Override public void columnMoved( TableColumnModelEvent e ) {}
|
||||
@Override public void columnMarginChanged( ChangeEvent e ) {}
|
||||
@Override public void columnAdded( TableColumnModelEvent e ) {}
|
||||
};
|
||||
table.getColumnModel().addColumnModelListener( columnSelectionListener );
|
||||
}
|
||||
}
|
||||
|
||||
private void repaintRoundedRowSelection( ListSelectionEvent e ) {
|
||||
if( selectionArc <= 0 || !table.getRowSelectionAllowed() )
|
||||
return;
|
||||
|
||||
int rowCount = table.getRowCount();
|
||||
int columnCount = table.getColumnCount();
|
||||
if( rowCount <= 0 || columnCount <= 0 )
|
||||
return;
|
||||
|
||||
// repaint including rows before and after changed selection
|
||||
int firstRow = Math.max( 0, Math.min( e.getFirstIndex() - 1, rowCount - 1 ) );
|
||||
int lastRow = Math.max( 0, Math.min( e.getLastIndex() + 1, rowCount - 1 ) );
|
||||
Rectangle firstRect = table.getCellRect( firstRow, 0, false );
|
||||
Rectangle lastRect = table.getCellRect( lastRow, columnCount - 1, false );
|
||||
table.repaint( firstRect.union( lastRect ) );
|
||||
}
|
||||
|
||||
private void repaintRoundedColumnSelection( ListSelectionEvent e ) {
|
||||
if( selectionArc <= 0 || !table.getColumnSelectionAllowed() )
|
||||
return;
|
||||
|
||||
int rowCount = table.getRowCount();
|
||||
int columnCount = table.getColumnCount();
|
||||
if( rowCount <= 0 || columnCount <= 0 )
|
||||
return;
|
||||
|
||||
// limit to selected rows for cell selection
|
||||
int firstRow = 0;
|
||||
int lastRow = rowCount - 1;
|
||||
if( table.getRowSelectionAllowed() ) {
|
||||
firstRow = table.getSelectionModel().getMinSelectionIndex();
|
||||
lastRow = table.getSelectionModel().getMaxSelectionIndex();
|
||||
}
|
||||
|
||||
// repaint including columns before and after changed selection
|
||||
int firstColumn = Math.max( 0, Math.min( e.getFirstIndex() - 1, columnCount - 1 ) );
|
||||
int lastColumn = Math.max( 0, Math.min( e.getLastIndex() + 1, columnCount - 1 ) );
|
||||
Rectangle firstRect = table.getCellRect( firstRow, firstColumn, false );
|
||||
Rectangle lastRect = table.getCellRect( lastRow, lastColumn, false );
|
||||
table.repaint( firstRect.union( lastRect ) );
|
||||
}
|
||||
|
||||
//---- class RoundedSelectionGraphics -------------------------------------
|
||||
|
||||
/**
|
||||
* Because selection painting is done in the cell renderer, it would be
|
||||
* necessary to require a FlatLaf specific renderer to implement rounded selection.
|
||||
* Using a LaF specific renderer was avoided because often a custom renderer is
|
||||
* already used in applications. Then either the rounded selection is not used,
|
||||
* or the application has to be changed to extend a FlatLaf renderer.
|
||||
* <p>
|
||||
* To solve this, a graphics proxy is used that paints rounded selection
|
||||
* if row/column/cell is selected and the renderer wants to fill the background.
|
||||
*/
|
||||
private class RoundedSelectionGraphics
|
||||
extends Graphics2DProxy
|
||||
{
|
||||
private final Color alternateRowColor;
|
||||
|
||||
// used to avoid endless loop in case that paintCellSelection() invokes
|
||||
// g.fillRect() with full bounds (selectionInsets is 0,0,0,0)
|
||||
private boolean inPaintSelection;
|
||||
|
||||
RoundedSelectionGraphics( Graphics delegate, Color alternateRowColor ) {
|
||||
super( (Graphics2D) delegate );
|
||||
this.alternateRowColor = alternateRowColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics create() {
|
||||
return new RoundedSelectionGraphics( super.create(), alternateRowColor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics create( int x, int y, int width, int height ) {
|
||||
return new RoundedSelectionGraphics( super.create( x, y, width, height ), alternateRowColor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRect( int x, int y, int width, int height ) {
|
||||
if( fillCellSelection( x, y, width, height ) )
|
||||
return;
|
||||
|
||||
super.fillRect( x, y, width, height );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill( Shape shape ) {
|
||||
if( shape instanceof Rectangle2D ) {
|
||||
Rectangle2D r = (Rectangle2D) shape;
|
||||
double x = r.getX();
|
||||
double y = r.getY();
|
||||
double width = r.getWidth();
|
||||
double height = r.getHeight();
|
||||
if( x == (int) x && y == (int) y && width == (int) width && height == (int) height ) {
|
||||
if( fillCellSelection( (int) x, (int) y, (int) width, (int) height ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.fill( shape );
|
||||
}
|
||||
|
||||
private boolean fillCellSelection( int x, int y, int width, int height ) {
|
||||
if( inPaintSelection )
|
||||
return false;
|
||||
|
||||
Color color;
|
||||
Component rendererComponent;
|
||||
if( x == 0 && y == 0 &&
|
||||
((color = getColor()) == table.getSelectionBackground() ||
|
||||
(alternateRowColor != null && color == alternateRowColor)) &&
|
||||
(rendererComponent = findActiveRendererComponent()) != null &&
|
||||
width == rendererComponent.getWidth() &&
|
||||
height == rendererComponent.getHeight() )
|
||||
{
|
||||
Point location = rendererComponent.getLocation();
|
||||
int row = table.rowAtPoint( location );
|
||||
int column = table.columnAtPoint( location );
|
||||
if( row >= 0 && column >= 0 ) {
|
||||
inPaintSelection = true;
|
||||
if( color == table.getSelectionBackground() )
|
||||
paintCellSelection( this, row, column, x, y, width, height );
|
||||
else
|
||||
paintAlternateRowBackground( this, row, column, x, y, width, height );
|
||||
inPaintSelection = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CellRendererPane may contain multiple components, if multiple renderers
|
||||
* are used. Inactive renderer components have size {@code 0x0}.
|
||||
*/
|
||||
private Component findActiveRendererComponent() {
|
||||
int count = rendererPane.getComponentCount();
|
||||
for( int i = 0; i < count; i++ ) {
|
||||
Component c = rendererPane.getComponent( i );
|
||||
if( c.getWidth() > 0 && c.getHeight() > 0 )
|
||||
return c;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class OutsideAlternateRowsListener ---------------------------------
|
||||
|
||||
/**
|
||||
* Used if table auto-resize-mode is off to repaint outside alternate rows
|
||||
* when table width changed (column resized) or component orientation changed.
|
||||
*/
|
||||
private class FlatOutsideAlternateRowsListener
|
||||
extends ComponentAdapter
|
||||
{
|
||||
@Override
|
||||
public void componentHidden( ComponentEvent e ) {
|
||||
Container viewport = SwingUtilities.getUnwrappedParent( table );
|
||||
if( viewport instanceof JViewport )
|
||||
HiDPIUtils.repaint( viewport );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved( ComponentEvent e ) {
|
||||
repaintAreaBelowTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized( ComponentEvent e ) {
|
||||
repaintAreaBelowTable();
|
||||
}
|
||||
|
||||
private void repaintAreaBelowTable() {
|
||||
Container viewport = SwingUtilities.getUnwrappedParent( table );
|
||||
if( viewport instanceof JViewport ) {
|
||||
int viewportHeight = viewport.getHeight();
|
||||
int tableHeight = table.getHeight();
|
||||
if( tableHeight < viewportHeight )
|
||||
HiDPIUtils.repaint( viewport, 0, tableHeight, viewport.getWidth(), viewportHeight - tableHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ public class FlatTextFieldUI
|
||||
case COMPONENT_ROUND_RECT:
|
||||
case OUTLINE:
|
||||
case TEXT_FIELD_PADDING:
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case MINIMUM_WIDTH:
|
||||
@@ -250,38 +250,38 @@ public class FlatTextFieldUI
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_LEADING_ICON:
|
||||
leadingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_TRAILING_ICON:
|
||||
trailingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_LEADING_COMPONENT:
|
||||
uninstallLeadingComponent();
|
||||
installLeadingComponent();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_TRAILING_COMPONENT:
|
||||
uninstallTrailingComponent();
|
||||
installTrailingComponent();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case TEXT_FIELD_SHOW_CLEAR_BUTTON:
|
||||
uninstallClearButton();
|
||||
installClearButton();
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
break;
|
||||
|
||||
case "enabled":
|
||||
@@ -815,7 +815,7 @@ debug*/
|
||||
if( visible != clearButton.isVisible() ) {
|
||||
clearButton.setVisible( visible );
|
||||
c.revalidate();
|
||||
c.repaint();
|
||||
HiDPIUtils.repaint( c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ public class FlatTitlePane
|
||||
windowTopBorderLayer = new JPanel();
|
||||
windowTopBorderLayer.setVisible( false );
|
||||
windowTopBorderLayer.setOpaque( false );
|
||||
windowTopBorderLayer.setBorder( FlatUIUtils.nonUIResource( FlatNativeWindowBorder.WindowTopBorder.getInstance() ) );
|
||||
windowTopBorderLayer.setBorder( FlatUIUtils.nonUIResource( WindowTopBorder.getInstance() ) );
|
||||
} else
|
||||
windowTopBorderLayer = null;
|
||||
|
||||
@@ -359,6 +359,10 @@ public class FlatTitlePane
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
int titleBarHeight = clientPropertyInt( rootPane, TITLE_BAR_HEIGHT, -1 );
|
||||
if( titleBarHeight >= 0 )
|
||||
return new Dimension( size.width, UIScale.scale( titleBarHeight ) );
|
||||
|
||||
if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) {
|
||||
// make title pane height smaller when frame is maximized
|
||||
size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) );
|
||||
@@ -395,6 +399,12 @@ public class FlatTitlePane
|
||||
// allow the button to shrink if space is rare
|
||||
return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height );
|
||||
}
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
// allow the button to fill whole button area height
|
||||
// see also BasicMenuUI.getMaximumSize()
|
||||
return new Dimension( super.getMaximumSize().width, Short.MAX_VALUE );
|
||||
}
|
||||
};
|
||||
button.setFocusable( false );
|
||||
button.setContentAreaFilled( false );
|
||||
@@ -745,16 +755,6 @@ public class FlatTitlePane
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
protected void repaintWindowBorder() {
|
||||
int width = rootPane.getWidth();
|
||||
int height = rootPane.getHeight();
|
||||
Insets insets = rootPane.getInsets();
|
||||
rootPane.repaint( 0, 0, width, insets.top ); // top
|
||||
rootPane.repaint( 0, 0, insets.left, height ); // left
|
||||
rootPane.repaint( 0, height - insets.bottom, width, insets.bottom ); // bottom
|
||||
rootPane.repaint( width - insets.right, 0, insets.right, height ); // right
|
||||
}
|
||||
|
||||
/**
|
||||
* Iconifies the window.
|
||||
*/
|
||||
@@ -824,7 +824,8 @@ public class FlatTitlePane
|
||||
Rectangle oldMaximizedBounds = frame.getMaximizedBounds();
|
||||
if( !hasNativeCustomDecoration() &&
|
||||
(oldMaximizedBounds == null ||
|
||||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) )
|
||||
Objects.equals( oldMaximizedBounds, rootPane.getClientProperty( "_flatlaf.maximizedBounds" ) )) &&
|
||||
window.getGraphicsConfiguration() != null )
|
||||
{
|
||||
GraphicsConfiguration gc = window.getGraphicsConfiguration();
|
||||
|
||||
@@ -1058,10 +1059,11 @@ public class FlatTitlePane
|
||||
* <p>
|
||||
* Note:
|
||||
* <ul>
|
||||
* <li>This method is invoked often when mouse is moved over title bar
|
||||
* <li>This method is invoked often when mouse is moved over window title bar area
|
||||
* and should therefore return quickly.
|
||||
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
|
||||
* while processing Windows messages.
|
||||
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
|
||||
* </ul>
|
||||
*/
|
||||
private boolean captionHitTest( Point pt ) {
|
||||
@@ -1089,7 +1091,7 @@ public class FlatTitlePane
|
||||
}
|
||||
|
||||
private boolean isTitleBarCaptionAt( Component c, int x, int y ) {
|
||||
if( !c.isDisplayable() || !c.isVisible() || !c.contains( x, y ) || c == mouseLayer )
|
||||
if( !c.isDisplayable() || !c.isVisible() || !contains( c, x, y ) || c == mouseLayer )
|
||||
return true; // continue checking with next component
|
||||
|
||||
if( c.isEnabled() &&
|
||||
@@ -1107,8 +1109,18 @@ public class FlatTitlePane
|
||||
// if component is not fully layouted, do not invoke function
|
||||
// because it is too dangerous that the function tries to layout the component,
|
||||
// which could cause a dead lock
|
||||
if( !c.isValid() )
|
||||
if( !c.isValid() ) {
|
||||
// revalidate if necessary so that it is valid when invoked again later
|
||||
EventQueue.invokeLater( () -> {
|
||||
Window w = SwingUtilities.windowForComponent( c );
|
||||
if( w != null )
|
||||
w.revalidate();
|
||||
else
|
||||
c.revalidate();
|
||||
} );
|
||||
|
||||
return false; // assume that this is not a caption because the component has mouse listeners
|
||||
}
|
||||
|
||||
if( caption instanceof Function ) {
|
||||
// check client property function value
|
||||
@@ -1141,6 +1153,16 @@ public class FlatTitlePane
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link Component#contains(int, int)}, but not using that method
|
||||
* because it may be overridden by custom components and invoke code that
|
||||
* tries to request AWT tree lock on 'AWT-Windows' thread.
|
||||
* This could freeze the application if AWT tree is already locked on 'AWT-EventQueue' thread.
|
||||
*/
|
||||
private boolean contains( Component c, int x, int y ) {
|
||||
return x >= 0 && y >= 0 && x < c.getWidth() && y < c.getHeight();
|
||||
}
|
||||
|
||||
private int lastCaptionHitTestX;
|
||||
private int lastCaptionHitTestY;
|
||||
private long lastCaptionHitTestTime;
|
||||
@@ -1352,10 +1374,7 @@ public class FlatTitlePane
|
||||
activeChanged( true );
|
||||
updateNativeTitleBarHeightAndHitTestSpots();
|
||||
|
||||
if( isWindowTopBorderNeeded() )
|
||||
WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
|
||||
repaintWindowBorder();
|
||||
repaintBorder();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1363,10 +1382,22 @@ public class FlatTitlePane
|
||||
activeChanged( false );
|
||||
updateNativeTitleBarHeightAndHitTestSpots();
|
||||
|
||||
if( isWindowTopBorderNeeded() )
|
||||
repaintBorder();
|
||||
}
|
||||
|
||||
private void repaintBorder() {
|
||||
// Windows 10 top border
|
||||
if( windowTopBorderLayer != null && windowTopBorderLayer.isShowing())
|
||||
WindowTopBorder.getInstance().repaintBorder( windowTopBorderLayer );
|
||||
else if( isWindowTopBorderNeeded() && !isWindowMaximized() && !isFullWindowContent() )
|
||||
WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
|
||||
repaintWindowBorder();
|
||||
// Window border used for non-native window decorations
|
||||
if( rootPane.getBorder() instanceof FlatRootPaneUI.FlatWindowBorder ) {
|
||||
// not repainting four areas on the four sides because RepaintManager
|
||||
// unions dirty regions, which also results in repaint of whole rootpane
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1559,6 +1590,15 @@ debug*/
|
||||
* Useful for components that do not use mouse input on whole component bounds.
|
||||
* E.g. a tabbed pane with a few tabs has some empty space beside the tabs
|
||||
* that can be used to move the window.
|
||||
* <p>
|
||||
* Note:
|
||||
* <ul>
|
||||
* <li>This method is invoked often when mouse is moved over window title bar area
|
||||
* and should therefore return quickly.
|
||||
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
|
||||
* while processing Windows messages.
|
||||
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
|
||||
* </ul>
|
||||
*
|
||||
* @return {@code true} if the component is not interested in mouse input at the given location
|
||||
* {@code false} if the component wants process mouse input at the given location
|
||||
|
||||
@@ -26,6 +26,7 @@ import javax.swing.*;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -159,14 +160,14 @@ public class FlatToggleButtonUI
|
||||
b.revalidate();
|
||||
}
|
||||
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
|
||||
case TAB_BUTTON_UNDERLINE_PLACEMENT:
|
||||
case TAB_BUTTON_UNDERLINE_HEIGHT:
|
||||
case TAB_BUTTON_UNDERLINE_COLOR:
|
||||
case TAB_BUTTON_SELECTED_BACKGROUND:
|
||||
b.repaint();
|
||||
HiDPIUtils.repaint( b );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ 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.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
|
||||
/**
|
||||
@@ -131,7 +132,7 @@ public class FlatToolBarSeparatorUI
|
||||
} else
|
||||
installStyle( s );
|
||||
s.revalidate();
|
||||
s.repaint();
|
||||
HiDPIUtils.repaint( s );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import javax.swing.plaf.basic.BasicToolBarUI;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -443,7 +444,7 @@ public class FlatToolBarUI
|
||||
|
||||
// repaint button group
|
||||
if( gr != null )
|
||||
toolBar.repaint( gr );
|
||||
HiDPIUtils.repaint(toolBar, gr );
|
||||
}
|
||||
|
||||
private ButtonGroup getButtonGroup( AbstractButton b ) {
|
||||
@@ -530,8 +531,11 @@ public class FlatToolBarUI
|
||||
|
||||
private Component getRecentComponent( Container aContainer, boolean first ) {
|
||||
// if moving focus into the toolbar, focus recently focused toolbar button
|
||||
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() )
|
||||
return toolBar.getComponent( focusedCompIndex );
|
||||
if( focusedCompIndex >= 0 && focusedCompIndex < toolBar.getComponentCount() ) {
|
||||
Component c = toolBar.getComponent( focusedCompIndex );
|
||||
if( accept( c ) )
|
||||
return c;
|
||||
}
|
||||
|
||||
return first
|
||||
? super.getFirstComponent( aContainer )
|
||||
|
||||
@@ -61,7 +61,7 @@ public class FlatToolTipUI
|
||||
super.installUI( c );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatLabelUI.updateHTMLRenderer( c, ((JToolTip)c).getTipText(), false );
|
||||
FlatHTML.updateRendererCSSFontBaseSize( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,11 +81,7 @@ public class FlatToolTipUI
|
||||
/** @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 );
|
||||
}
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,6 +47,7 @@ import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreePath;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -310,7 +311,7 @@ public class FlatTreeUI
|
||||
switch( e.getPropertyName() ) {
|
||||
case TREE_WIDE_SELECTION:
|
||||
case TREE_PAINT_SELECTION:
|
||||
tree.repaint();
|
||||
HiDPIUtils.repaint( tree );
|
||||
break;
|
||||
|
||||
case "dropLocation":
|
||||
@@ -325,7 +326,7 @@ public class FlatTreeUI
|
||||
case STYLE_CLASS:
|
||||
installStyle();
|
||||
tree.revalidate();
|
||||
tree.repaint();
|
||||
HiDPIUtils.repaint( tree );
|
||||
break;
|
||||
|
||||
case "enabled":
|
||||
@@ -353,7 +354,7 @@ public class FlatTreeUI
|
||||
|
||||
Rectangle r = tree.getPathBounds( loc.getPath() );
|
||||
if( r != null )
|
||||
tree.repaint( 0, r.y, tree.getWidth(), r.height );
|
||||
HiDPIUtils.repaint( tree, 0, r.y, tree.getWidth(), r.height );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -370,14 +371,14 @@ public class FlatTreeUI
|
||||
{
|
||||
if( changedPaths.length > 4 ) {
|
||||
// same is done in BasicTreeUI.Handler.valueChanged()
|
||||
tree.repaint();
|
||||
HiDPIUtils.repaint( tree );
|
||||
} else {
|
||||
int arc = (int) Math.ceil( UIScale.scale( selectionArc / 2f ) );
|
||||
|
||||
for( TreePath path : changedPaths ) {
|
||||
Rectangle r = getPathBounds( tree, path );
|
||||
if( r != null )
|
||||
tree.repaint( r.x, r.y - arc, r.width, r.height + (arc * 2) );
|
||||
HiDPIUtils.repaint( tree, r.x, r.y - arc, r.width, r.height + (arc * 2) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,11 @@ public class FlatUIUtils
|
||||
dest.right = src.right;
|
||||
}
|
||||
|
||||
/** @since 3.5 */
|
||||
public static boolean isInsetsEmpty( Insets insets ) {
|
||||
return insets.top == 0 && insets.left == 0 && insets.bottom == 0 && insets.right == 0;
|
||||
}
|
||||
|
||||
public static Color getUIColor( String key, int defaultColorRGB ) {
|
||||
Color color = UIManager.getColor( key );
|
||||
return (color != null) ? color : new Color( defaultColorRGB );
|
||||
@@ -601,28 +606,55 @@ public class FlatUIUtils
|
||||
public static void paintOutlinedComponent( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
{
|
||||
paintOutlinedComponent( g, x, y, width, height, focusWidth, focusWidthFraction, focusInnerWidth,
|
||||
borderWidth, arc, focusColor, borderColor, background, false );
|
||||
}
|
||||
|
||||
static void paintOutlinedComponent( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background, boolean scrollPane )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
if( (int) systemScaleFactor != systemScaleFactor ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintOutlinedComponentImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), focusWidthFraction, (float) (focusInnerWidth * scaleFactor),
|
||||
(float) (borderWidth * scaleFactor), (float) (arc * scaleFactor),
|
||||
focusColor, borderColor, background );
|
||||
focusColor, borderColor, background, scrollPane, scaleFactor );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintOutlinedComponentImpl( g, x, y, width, height, focusWidth, focusWidthFraction, focusInnerWidth,
|
||||
borderWidth, arc, focusColor, borderColor, background );
|
||||
borderWidth, arc, focusColor, borderColor, background, scrollPane, systemScaleFactor );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "SelfAssignment" ) // Error Prone
|
||||
private static void paintOutlinedComponentImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
Paint focusColor, Paint borderColor, Paint background, boolean scrollPane, double scaleFactor )
|
||||
{
|
||||
// Special handling for scrollpane and fractional scale factors (e.g. 1.25 - 1.75),
|
||||
// where Swing scales one "logical" pixel (border insets) to either one or two physical pixels.
|
||||
// Antialiasing is used to paint the border, which usually needs two physical pixels
|
||||
// at small scale factors. 1px for the solid border and another 1px for antialiasing.
|
||||
// But scrollpane view is painted over the border, which results in a painted border
|
||||
// that is 1px thick at some sides and 2px thick at other sides.
|
||||
if( scrollPane && scaleFactor != (int) scaleFactor ) {
|
||||
if( focusWidth > 0 ) {
|
||||
// reduce outer border thickness (focusWidth) so that inner side of
|
||||
// component border (focusWidth + borderWidth) is at a full pixel
|
||||
int totalWidth = (int) (focusWidth + borderWidth);
|
||||
focusWidth = totalWidth - borderWidth;
|
||||
} else {// if( scaleFactor > 1 && scaleFactor < 2 ) {
|
||||
// reduce component border thickness (borderWidth) to full pixels
|
||||
borderWidth = (int) borderWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// outside bounds of the border and the background
|
||||
float x1 = x + focusWidth;
|
||||
float y1 = y + focusWidth;
|
||||
@@ -780,7 +812,7 @@ public class FlatUIUtils
|
||||
|
||||
if( arcTopLeft > 0 || arcTopRight > 0 || arcBottomLeft > 0 || arcBottomRight > 0 ) {
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
if( systemScaleFactor != (int) systemScaleFactor ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
@@ -1315,13 +1347,13 @@ debug*/
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||
repaintComponent.repaint();
|
||||
HiDPIUtils.repaint( repaintComponent );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
|
||||
repaintComponent.repaint();
|
||||
HiDPIUtils.repaint( repaintComponent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import javax.swing.DesktopManager;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JInternalFrame;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
@@ -191,7 +192,7 @@ public abstract class FlatWindowResizer
|
||||
protected abstract Dimension getWindowMinimumSize();
|
||||
protected abstract Dimension getWindowMaximumSize();
|
||||
|
||||
protected void beginResizing( int direction ) {}
|
||||
protected void beginResizing( int resizeDir ) {}
|
||||
protected void endResizing() {}
|
||||
|
||||
//---- interface PropertyChangeListener ----
|
||||
@@ -234,17 +235,47 @@ public abstract class FlatWindowResizer
|
||||
{
|
||||
protected Window window;
|
||||
|
||||
private final JComponent centerComp;
|
||||
private final boolean limitResizeToScreenBounds;
|
||||
|
||||
public WindowResizer( JRootPane rootPane ) {
|
||||
super( rootPane );
|
||||
|
||||
// Transparent "center" component that is made visible only while resizing window.
|
||||
// It uses same cursor as the area where resize dragging started.
|
||||
// This ensures that the cursor shape stays stable while dragging mouse
|
||||
// into the window to make window smaller. Otherwise it would toggling between
|
||||
// resize and standard cursor because the component layout is not updated
|
||||
// fast enough and the mouse cursor is always updated from the component
|
||||
// at the mouse location.
|
||||
centerComp = new JPanel();
|
||||
centerComp.setOpaque( false );
|
||||
centerComp.setVisible( false );
|
||||
Container cont = rootPane.getLayeredPane();
|
||||
cont.add( centerComp, WINDOW_RESIZER_LAYER, 4 );
|
||||
|
||||
// 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
|
||||
public void uninstall() {
|
||||
Container cont = topDragComp.getParent();
|
||||
cont.remove( centerComp );
|
||||
|
||||
super.uninstall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout() {
|
||||
super.doLayout();
|
||||
|
||||
if( centerComp != null && centerComp.isVisible() )
|
||||
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
Container parent = resizeComp.getParent();
|
||||
@@ -299,20 +330,17 @@ public abstract class FlatWindowResizer
|
||||
|
||||
@Override
|
||||
protected boolean limitToParentBounds() {
|
||||
return limitResizeToScreenBounds && window != null;
|
||||
return limitResizeToScreenBounds && window != null && window.getGraphicsConfiguration() != 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;
|
||||
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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -346,6 +374,19 @@ public abstract class FlatWindowResizer
|
||||
public void windowStateChanged( WindowEvent e ) {
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginResizing( int resizeDir ) {
|
||||
centerComp.setBounds( 0, 0, resizeComp.getWidth(), resizeComp.getHeight() );
|
||||
centerComp.setCursor( getPredefinedCursor( resizeDir ) );
|
||||
centerComp.setVisible( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endResizing() {
|
||||
centerComp.setVisible( false );
|
||||
centerComp.setCursor( null );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class InternalFrameResizer -----------------------------------------
|
||||
@@ -427,7 +468,18 @@ public abstract class FlatWindowResizer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginResizing( int direction ) {
|
||||
protected void beginResizing( int resizeDir ) {
|
||||
int direction = 0;
|
||||
switch( resizeDir ) {
|
||||
case N_RESIZE_CURSOR: direction = NORTH; break;
|
||||
case S_RESIZE_CURSOR: direction = SOUTH; break;
|
||||
case W_RESIZE_CURSOR: direction = WEST; break;
|
||||
case E_RESIZE_CURSOR: direction = EAST; break;
|
||||
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
|
||||
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
|
||||
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
|
||||
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
|
||||
}
|
||||
desktopManager.get().beginResizingFrame( getFrame(), direction );
|
||||
}
|
||||
|
||||
@@ -535,18 +587,7 @@ debug*/
|
||||
dragRightOffset = windowBounds.x + windowBounds.width - xOnScreen;
|
||||
dragBottomOffset = windowBounds.y + windowBounds.height - yOnScreen;
|
||||
|
||||
int direction = 0;
|
||||
switch( resizeDir ) {
|
||||
case N_RESIZE_CURSOR: direction = NORTH; break;
|
||||
case S_RESIZE_CURSOR: direction = SOUTH; break;
|
||||
case W_RESIZE_CURSOR: direction = WEST; break;
|
||||
case E_RESIZE_CURSOR: direction = EAST; break;
|
||||
case NW_RESIZE_CURSOR: direction = NORTH_WEST; break;
|
||||
case NE_RESIZE_CURSOR: direction = NORTH_EAST; break;
|
||||
case SW_RESIZE_CURSOR: direction = SOUTH_WEST; break;
|
||||
case SE_RESIZE_CURSOR: direction = SOUTH_EAST; break;
|
||||
}
|
||||
beginResizing( direction );
|
||||
beginResizing( resizeDir );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,14 +16,17 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.RepaintManager;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
@@ -322,4 +325,243 @@ public class HiDPIUtils
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the given component.
|
||||
* <p>
|
||||
* See {@link #repaint(Component, int, int, int, int)} for more details.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void repaint( Component c ) {
|
||||
repaint( c, 0, 0, c.getWidth(), c.getHeight() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the given component area.
|
||||
* <p>
|
||||
* See {@link #repaint(Component, int, int, int, int)} for more details.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void repaint( Component c, Rectangle r ) {
|
||||
repaint( c, r.x, r.y, r.width, r.height );
|
||||
}
|
||||
|
||||
/**
|
||||
* Repaints the given component area.
|
||||
* <p>
|
||||
* Invokes {@link Component#repaint(int, int, int, int)} on the given component,
|
||||
* <p>
|
||||
* Use this method, instead of {@code Component.repaint(...)},
|
||||
* to fix a problem in Swing when using scale factors that end on .25 or .75
|
||||
* (e.g. 1.25, 1.75, 2.25, etc) and repainting single components, which may not
|
||||
* repaint right and/or bottom 1px edge of component.
|
||||
* <p>
|
||||
* The problem may occur under following conditions:
|
||||
* <ul>
|
||||
* <li>using Java 9 or later
|
||||
* <li>system scale factor is 125%, 175%, 225%, ...
|
||||
* (Windows only; Java on macOS and Linux does not support fractional scale factors)
|
||||
* <li>repaint whole component or right/bottom area of component
|
||||
* <li>component is opaque; or component is contained in a opaque container
|
||||
* that has same right/bottom bounds as component
|
||||
* <li>component has bounds that Java/Swing scales different when repainting components
|
||||
* </ul>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void repaint( Component c, int x, int y, int width, int height ) {
|
||||
// repaint given component area
|
||||
// Always invoke repaint() on given component, even if also invoked (below)
|
||||
// on one of its ancestors, for the case that component overrides that method.
|
||||
// Also RepaintManager "merges" the two repaints into one.
|
||||
c.repaint( x, y, width, height );
|
||||
|
||||
if( RepaintManager.currentManager( c ) instanceof HiDPIRepaintManager )
|
||||
return;
|
||||
|
||||
// if necessary, also repaint given area in first ancestor that is larger than component
|
||||
// to avoid clipping issue (see needsSpecialRepaint())
|
||||
if( needsSpecialRepaint( c, x, y, width, height ) ) {
|
||||
int x2 = x + c.getX();
|
||||
int y2 = y + c.getY();
|
||||
for( Component p = c.getParent(); p != null; p = p.getParent() ) {
|
||||
x2 += p.getX();
|
||||
y2 += p.getY();
|
||||
if( x2 + width < p.getWidth() && y2 + height < p.getHeight() ) {
|
||||
p.repaint( x2, y2, width, height );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There is a problem in Swing, when using scale factors that end on .25 or .75
|
||||
* (e.g. 1.25, 1.75, 2.25, etc) and repainting single components, which may not
|
||||
* repaint right and/or bottom 1px edge of component.
|
||||
* <p>
|
||||
* The component is first painted to an in-memory image,
|
||||
* and then that image is copied to the screen.
|
||||
* See {@code javax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()}.
|
||||
* <p>
|
||||
* There are two clipping rectangles involved when copying the image to the screen:
|
||||
* {@code sun.java2d.SunGraphics2D#devClip} and
|
||||
* {@code sun.java2d.SunGraphics2D#usrClip}.
|
||||
* <p>
|
||||
* {@code devClip} is the device clipping in physical pixels.
|
||||
* It gets the bounds of the painting component, which is either the passed component,
|
||||
* or if it is non-opaque, then the first opaque ancestor of the passed component.
|
||||
* It is calculated in {@code sun.java2d.SunGraphics2D#constrain()} while
|
||||
* getting a graphics context via {@link JComponent#getGraphics()}.
|
||||
* <p>
|
||||
* {@code usrClip} is the user clipping, which is set via {@link Graphics} clipping methods.
|
||||
* This is done in {@code javax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()}.
|
||||
* <p>
|
||||
* The intersection of {@code devClip} and {@code usrClip}
|
||||
* (computed in {@code sun.java2d.SunGraphics2D#validateCompClip()})
|
||||
* is used to copy the image to the screen.
|
||||
* <p>
|
||||
* Unfortunately different scaling/rounding strategies are used to calculate
|
||||
* the two clipping rectangles, which is the reason of the issue.
|
||||
* <p>
|
||||
* {@code devClip} (see {@code sun.java2d.SunGraphics2D#constrain()}):
|
||||
* <pre>{@code
|
||||
* int devX = (int) (x * scale);
|
||||
* int devWidth = Math.round( width * scale )
|
||||
* }</pre>
|
||||
* {@code usrClip} (see {@code javax.swing.RepaintManager.PaintManager#paintDoubleBufferedFPScales()}):
|
||||
* <pre>{@code
|
||||
* int usrX = (int) Math.ceil( (x * scale) - 0.5 );
|
||||
* int usrWidth = ((int) Math.ceil( ((x + width) * scale) - 0.5 )) - usrX;
|
||||
* }</pre>
|
||||
* X/Y coordinates are always rounded down for {@code devClip}, but rounded up for {@code usrClip}.
|
||||
* Width/height calculation is also different.
|
||||
*/
|
||||
private static boolean needsSpecialRepaint( Component c, int x, int y, int width, int height ) {
|
||||
// no special repaint necessary for Java 8 or for macOS and Linux
|
||||
// (Java on those platforms does not support fractional scale factors)
|
||||
if( !SystemInfo.isJava_9_orLater || !SystemInfo.isWindows )
|
||||
return false;
|
||||
|
||||
// check whether repaint area is empty or no component given
|
||||
// (same checks as in javax.swing.RepaintManager.addDirtyRegion0())
|
||||
if( width <= 0 || height <= 0 || c == null )
|
||||
return false;
|
||||
|
||||
// check whether component has zero size
|
||||
// (same checks as in javax.swing.RepaintManager.addDirtyRegion0())
|
||||
int compWidth = c.getWidth();
|
||||
int compHeight = c.getHeight();
|
||||
if( compWidth <= 0 || compHeight <= 0 )
|
||||
return false;
|
||||
|
||||
// check whether repaint area does span to right or bottom component edges
|
||||
// (in this case, {@code devClip} is always larger than {@code usrClip})
|
||||
if( x + width < compWidth && y + height < compHeight )
|
||||
return false;
|
||||
|
||||
// if component is not opaque, Swing uses the first opaque ancestor for painting
|
||||
if( !c.isOpaque() ) {
|
||||
int x2 = x;
|
||||
int y2 = y;
|
||||
for( Component p = c.getParent(); p != null; p = p.getParent() ) {
|
||||
x2 += p.getX();
|
||||
y2 += p.getY();
|
||||
if( p.isOpaque() ) {
|
||||
// check whether repaint area does span to right or bottom edges
|
||||
// of the opaque ancestor component
|
||||
// (in this case, {@code devClip} is always larger than {@code usrClip})
|
||||
if( x2 + width < p.getWidth() && y2 + height < p.getHeight() )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check whether Special repaint is necessary for current scale factor
|
||||
// (doing this check late because it temporary allocates some memory)
|
||||
double scaleFactor = UIScale.getSystemScaleFactor( c.getGraphicsConfiguration() );
|
||||
double fraction = scaleFactor - (int) scaleFactor;
|
||||
if( fraction == 0 || fraction == 0.5 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a {@link HiDPIRepaintManager} on Windows when running in Java 9+,
|
||||
* but only if default repaint manager is currently installed.
|
||||
* <p>
|
||||
* Invoke once on application startup.
|
||||
* Compatible with all/other LaFs.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void installHiDPIRepaintManager() {
|
||||
if( !SystemInfo.isJava_9_orLater || !SystemInfo.isWindows )
|
||||
return;
|
||||
|
||||
RepaintManager manager = RepaintManager.currentManager( (Component) null );
|
||||
if( manager.getClass() == RepaintManager.class )
|
||||
RepaintManager.setCurrentManager( new HiDPIRepaintManager() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #repaint(Component, int, int, int, int)},
|
||||
* but invokes callback instead of invoking {@link Component#repaint(int, int, int, int)}.
|
||||
* <p>
|
||||
* For use in custom repaint managers.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static void addDirtyRegion( JComponent c, int x, int y, int width, int height, DirtyRegionCallback callback ) {
|
||||
if( needsSpecialRepaint( c, x, y, width, height ) ) {
|
||||
int x2 = x + c.getX();
|
||||
int y2 = y + c.getY();
|
||||
for( Component p = c.getParent(); p != null; p = p.getParent() ) {
|
||||
if( x2 + width < p.getWidth() && y2 + height < p.getHeight() && p instanceof JComponent ) {
|
||||
callback.addDirtyRegion( (JComponent) p, x2, y2, width, height );
|
||||
return;
|
||||
}
|
||||
x2 += p.getX();
|
||||
y2 += p.getY();
|
||||
}
|
||||
}
|
||||
|
||||
callback.addDirtyRegion( c, x, y, width, height );
|
||||
}
|
||||
|
||||
//---- interface DirtyRegionCallback --------------------------------------
|
||||
|
||||
/**
|
||||
* For {@link HiDPIUtils#addDirtyRegion(JComponent, int, int, int, int, DirtyRegionCallback)}.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public interface DirtyRegionCallback {
|
||||
void addDirtyRegion( JComponent c, int x, int y, int w, int h );
|
||||
}
|
||||
|
||||
//---- class HiDPIRepaintManager ------------------------------------------
|
||||
|
||||
/**
|
||||
* A repaint manager that fixes a problem in Swing when repainting components
|
||||
* at some scale factors (e.g. 125%, 175%, etc) on Windows.
|
||||
* <p>
|
||||
* Use {@link HiDPIUtils#installHiDPIRepaintManager()} to install it.
|
||||
* <p>
|
||||
* See {@link HiDPIUtils#repaint(Component, int, int, int, int)} for details.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static class HiDPIRepaintManager
|
||||
extends RepaintManager
|
||||
{
|
||||
@Override
|
||||
public void addDirtyRegion( JComponent c, int x, int y, int w, int h ) {
|
||||
HiDPIUtils.addDirtyRegion( c, x, y, w, h, super::addDirtyRegion );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import javax.swing.plaf.DimensionUIResource;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.InsetsUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
|
||||
/**
|
||||
@@ -188,7 +189,9 @@ public class UIScale
|
||||
// because even if we are on a HiDPI display it is not sure
|
||||
// that a larger font size is set by the current LaF
|
||||
// (e.g. can avoid large icons with small text)
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
Font font = null;
|
||||
if( UIManager.getLookAndFeel() instanceof FlatLaf )
|
||||
font = UIManager.getFont( "defaultFont" );
|
||||
if( font == null )
|
||||
font = UIManager.getFont( "Label.font" );
|
||||
|
||||
@@ -244,6 +247,16 @@ public class UIScale
|
||||
}
|
||||
|
||||
private static float computeScaleFactor( Font font ) {
|
||||
String customFontSizeDivider = System.getProperty( "flatlaf.uiScale.fontSizeDivider" );
|
||||
if( customFontSizeDivider != null ) {
|
||||
try {
|
||||
float fontSizeDivider = Math.max( Integer.parseInt( customFontSizeDivider ), 10 );
|
||||
return font.getSize() / fontSizeDivider;
|
||||
} catch( NumberFormatException ex ) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// default font size
|
||||
float fontSizeDivider = 12f;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -84,10 +84,12 @@ public class TestUIDefaultsLoader
|
||||
void parseBorders() {
|
||||
Insets insets = new Insets( 1,2,3,4 );
|
||||
assertBorderEquals( new FlatEmptyBorder( insets ), "1,2,3,4" );
|
||||
assertBorderEquals( new FlatEmptyBorder( insets ), "1,2,3,4,,," );
|
||||
assertBorderEquals( new FlatLineBorder( insets, Color.red ), "1,2,3,4,#f00" );
|
||||
assertBorderEquals( new FlatLineBorder( insets, Color.red, 2.5f, 0 ), "1,2,3,4,#f00,2.5" );
|
||||
assertBorderEquals( new FlatLineBorder( insets, Color.red, 2.5f, -1 ), "1,2,3,4,#f00,2.5" );
|
||||
assertBorderEquals( new FlatLineBorder( insets, Color.red, 2.5f, 6 ), "1,2,3,4,#f00,2.5,6" );
|
||||
assertBorderEquals( new FlatLineBorder( insets, Color.red, 1, 6 ), "1,2,3,4,#f00,,6" );
|
||||
assertBorderEquals( new FlatLineBorder( insets, null, 1, 6 ), "1,2,3,4,,,6" );
|
||||
}
|
||||
|
||||
private void assertBorderEquals( Border expected, String actualStyle ) {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2024 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import java.util.Locale;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.View;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class TestFlatHTML
|
||||
{
|
||||
private final String body = "some <small>small</small> text";
|
||||
private final String bodyInBody = "<body>" + body + "</body>";
|
||||
private final String bodyPlain = "some small text";
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
TestUtils.setup( false );
|
||||
TestUtils.scaleFont( 2 );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanup() {
|
||||
TestUtils.cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
void simple() {
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE_IN_HEAD}" + body + "</html>", bodyPlain );
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE_IN_HEAD}" + bodyInBody + "</html>", bodyPlain );
|
||||
}
|
||||
|
||||
@Test
|
||||
void htmlWithHeadTag() {
|
||||
testHtmlBaseSize( "<html><head>${BASE_SIZE}<title>test</title><head>" + body + "</html>", bodyPlain );
|
||||
testHtmlBaseSize( "<html><head>${BASE_SIZE}<title>test</title><head>" + bodyInBody + "</html>", bodyPlain );
|
||||
|
||||
testHtmlBaseSize( "<html><head id=\"abc\">${BASE_SIZE}<title>test</title><head>" + body + "</html>", bodyPlain );
|
||||
testHtmlBaseSize( "<html><head id=\"abc\">${BASE_SIZE}<title>test</title><head>" + bodyInBody + "</html>", bodyPlain );
|
||||
}
|
||||
|
||||
@Test
|
||||
void htmlWithStyleTag() {
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE}<style>body { color: #f00; }</style>" + bodyInBody + "</html>", bodyPlain );
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE}<style>body { color: #f00; }</style><h1>header1</h1>" + body + "</html>", "header1\n" + bodyPlain );
|
||||
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE}<style type='text/css'>body { color: #f00; }</style>" + bodyInBody + "</html>", bodyPlain );
|
||||
testHtmlBaseSize( "<html>${BASE_SIZE}<style type='text/css'>body { color: #f00; }</style><h1>header1</h1>" + body + "</html>", "header1\n" + bodyPlain );
|
||||
}
|
||||
|
||||
@Test
|
||||
void htmlOnComponentWithNullFont() {
|
||||
assertDoesNotThrow( () -> {
|
||||
JLabel label = new JLabel();
|
||||
label.setFont( null );
|
||||
label.setText( "<html>foo<br>bar</html>" );
|
||||
} );
|
||||
}
|
||||
|
||||
private void testHtmlBaseSize( String html, String expectedPlain ) {
|
||||
testHtmlBaseSizeImpl( html, expectedPlain );
|
||||
testHtmlBaseSizeImpl( html.toUpperCase( Locale.ENGLISH ), expectedPlain.toUpperCase( Locale.ENGLISH ) );
|
||||
}
|
||||
|
||||
private void testHtmlBaseSizeImpl( String html, String expectedPlain ) {
|
||||
String baseSize = "<style>BASE_SIZE " + UIManager.getFont( "Label.font" ).getSize() + "</style>";
|
||||
String baseSizeInHead = "<head>" + baseSize + "</head>";
|
||||
|
||||
String expectedHtml = html.replace( "${BASE_SIZE}", baseSize ).replace( "${BASE_SIZE_IN_HEAD}", baseSizeInHead );
|
||||
html = html.replace( "${BASE_SIZE}", "" ).replace( "${BASE_SIZE_IN_HEAD}", "" );
|
||||
|
||||
testHtml( html, expectedHtml, expectedPlain );
|
||||
}
|
||||
|
||||
private void testHtml( String html, String expectedHtml, String expectedPlain ) {
|
||||
FlatHTML.testUpdateRenderer = (c, newHtml) -> {
|
||||
assertEquals( expectedHtml, newHtml );
|
||||
assertEquals( expectedPlain, getPlainText( c ) );
|
||||
};
|
||||
new JLabel( html );
|
||||
FlatHTML.testUpdateRenderer = null;
|
||||
}
|
||||
|
||||
private String getPlainText( JComponent c ) {
|
||||
View view = (View) c.getClientProperty( BasicHTML.propertyKey );
|
||||
if( view == null )
|
||||
return null;
|
||||
|
||||
Document doc = view.getDocument();
|
||||
try {
|
||||
return doc.getText( 0, doc.getLength() ).trim();
|
||||
} catch( BadLocationException ex ) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,7 +253,8 @@ public class TestFlatStyleableInfo
|
||||
FlatLabelUI ui = (FlatLabelUI) c.getUI();
|
||||
|
||||
Map<String, Class<?>> expected = expectedMap(
|
||||
"disabledForeground", Color.class
|
||||
"disabledForeground", Color.class,
|
||||
"arc", int.class
|
||||
);
|
||||
|
||||
assertMapEquals( expected, ui.getStyleableInfos( c ) );
|
||||
@@ -799,6 +800,8 @@ public class TestFlatStyleableInfo
|
||||
"selectionForeground", Color.class,
|
||||
"selectionInactiveBackground", Color.class,
|
||||
"selectionInactiveForeground", Color.class,
|
||||
"selectionInsets", Insets.class,
|
||||
"selectionArc", int.class,
|
||||
|
||||
// FlatTableCellBorder
|
||||
"cellMargins", Insets.class,
|
||||
@@ -993,12 +996,20 @@ public class TestFlatStyleableInfo
|
||||
"disabledBorderColor", Color.class,
|
||||
"focusedBorderColor", Color.class,
|
||||
"hoverBorderColor", Color.class,
|
||||
"pressedBorderColor", Color.class,
|
||||
|
||||
"selectedBorderColor", Color.class,
|
||||
"disabledSelectedBorderColor", Color.class,
|
||||
"focusedSelectedBorderColor", Color.class,
|
||||
"hoverSelectedBorderColor", Color.class,
|
||||
"pressedSelectedBorderColor", Color.class,
|
||||
|
||||
"default.borderWidth", float.class,
|
||||
"default.borderColor", Color.class,
|
||||
"default.focusedBorderColor", Color.class,
|
||||
"default.focusColor", Color.class,
|
||||
"default.hoverBorderColor", Color.class,
|
||||
"default.pressedBorderColor", Color.class,
|
||||
|
||||
"toolbar.focusWidth", float.class,
|
||||
"toolbar.focusColor", Color.class,
|
||||
|
||||
@@ -305,6 +305,9 @@ public class TestFlatStyleableValue
|
||||
testColor( c, ui, "buttonPressedArrowColor", 0x123456 );
|
||||
|
||||
testColor( c, ui, "popupBackground", 0x123456 );
|
||||
testInsets( c, ui, "popupInsets", 1,2,3,4 );
|
||||
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
|
||||
testInteger( c, ui, "selectionArc", 123 );
|
||||
|
||||
// border
|
||||
flatRoundBorder( c, ui );
|
||||
@@ -355,6 +358,7 @@ public class TestFlatStyleableValue
|
||||
FlatLabelUI ui = (FlatLabelUI) c.getUI();
|
||||
|
||||
testColor( c, ui, "disabledForeground", 0x123456 );
|
||||
testInteger( c, ui, "arc", 123 );
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -366,6 +370,8 @@ public class TestFlatStyleableValue
|
||||
testColor( c, ui, "selectionForeground", 0x123456 );
|
||||
testColor( c, ui, "selectionInactiveBackground", 0x123456 );
|
||||
testColor( c, ui, "selectionInactiveForeground", 0x123456 );
|
||||
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
|
||||
testInteger( c, ui, "selectionArc", 123 );
|
||||
|
||||
// FlatListCellBorder
|
||||
testInsets( c, ui, "cellMargins", 1,2,3,4 );
|
||||
@@ -801,6 +807,8 @@ public class TestFlatStyleableValue
|
||||
testColor( c, ui, "selectionForeground", 0x123456 );
|
||||
testColor( c, ui, "selectionInactiveBackground", 0x123456 );
|
||||
testColor( c, ui, "selectionInactiveForeground", 0x901324 );
|
||||
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
|
||||
testInteger( c, ui, "selectionArc", 123 );
|
||||
|
||||
// FlatTableCellBorder
|
||||
testInsets( c, ui, "cellMargins", 1,2,3,4 );
|
||||
@@ -930,6 +938,8 @@ public class TestFlatStyleableValue
|
||||
testColor( c, ui, "selectionInactiveBackground", 0x123456 );
|
||||
testColor( c, ui, "selectionInactiveForeground", 0x123456 );
|
||||
testColor( c, ui, "selectionBorderColor", 0x123456 );
|
||||
testInsets( c, ui, "selectionInsets", 1,2,3,4 );
|
||||
testInteger( c, ui, "selectionArc", 123 );
|
||||
testBoolean( c, ui, "wideSelection", true );
|
||||
testBoolean( c, ui, "showCellFocusIndicator", true );
|
||||
|
||||
@@ -955,12 +965,20 @@ public class TestFlatStyleableValue
|
||||
testColor( c, ui, "disabledBorderColor", 0x123456 );
|
||||
testColor( c, ui, "focusedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "hoverBorderColor", 0x123456 );
|
||||
testColor( c, ui, "pressedBorderColor", 0x123456 );
|
||||
|
||||
testColor( c, ui, "selectedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "disabledSelectedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "focusedSelectedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "hoverSelectedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "pressedSelectedBorderColor", 0x123456 );
|
||||
|
||||
testFloat( c, ui, "default.borderWidth", 1.23f );
|
||||
testColor( c, ui, "default.borderColor", 0x123456 );
|
||||
testColor( c, ui, "default.focusedBorderColor", 0x123456 );
|
||||
testColor( c, ui, "default.focusColor", 0x123456 );
|
||||
testColor( c, ui, "default.hoverBorderColor", 0x123456 );
|
||||
testColor( c, ui, "default.pressedBorderColor", 0x123456 );
|
||||
|
||||
testFloat( c, ui, "toolbar.focusWidth", 1.23f );
|
||||
testColor( c, ui, "toolbar.focusColor", 0x123456 );
|
||||
@@ -1025,12 +1043,20 @@ public class TestFlatStyleableValue
|
||||
testValue( border, "disabledBorderColor", Color.WHITE );
|
||||
testValue( border, "focusedBorderColor", Color.WHITE );
|
||||
testValue( border, "hoverBorderColor", Color.WHITE );
|
||||
testValue( border, "pressedBorderColor", Color.WHITE );
|
||||
|
||||
testValue( border, "selectedBorderColor", Color.WHITE );
|
||||
testValue( border, "disabledSelectedBorderColor", Color.WHITE );
|
||||
testValue( border, "focusedSelectedBorderColor", Color.WHITE );
|
||||
testValue( border, "hoverSelectedBorderColor", Color.WHITE );
|
||||
testValue( border, "pressedSelectedBorderColor", Color.WHITE );
|
||||
|
||||
testValue( border, "default.borderWidth", 2f );
|
||||
testValue( border, "default.borderColor", Color.WHITE );
|
||||
testValue( border, "default.focusedBorderColor", Color.WHITE );
|
||||
testValue( border, "default.focusColor", Color.WHITE );
|
||||
testValue( border, "default.hoverBorderColor", Color.WHITE );
|
||||
testValue( border, "default.pressedBorderColor", Color.WHITE );
|
||||
|
||||
testValue( border, "toolbar.focusWidth", 1.5f );
|
||||
testValue( border, "toolbar.focusColor", Color.WHITE );
|
||||
|
||||
@@ -412,6 +412,7 @@ public class TestFlatStyling
|
||||
FlatLabelUI ui = (FlatLabelUI) c.getUI();
|
||||
|
||||
ui.applyStyle( c, "disabledForeground: #fff" );
|
||||
ui.applyStyle( c, "arc: 8" );
|
||||
|
||||
// JComponent properties
|
||||
ui.applyStyle( c, "background: #fff" );
|
||||
@@ -986,6 +987,8 @@ public class TestFlatStyling
|
||||
ui.applyStyle( "selectionForeground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveBackground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveForeground: #fff" );
|
||||
ui.applyStyle( "selectionInsets: 1,2,3,4" );
|
||||
ui.applyStyle( "selectionArc: 8" );
|
||||
|
||||
// FlatTableCellBorder
|
||||
ui.applyStyle( "cellMargins: 1,2,3,4" );
|
||||
@@ -1294,12 +1297,20 @@ public class TestFlatStyling
|
||||
border.applyStyleProperty( "disabledBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "focusedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "hoverBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "pressedBorderColor", Color.WHITE );
|
||||
|
||||
border.applyStyleProperty( "selectedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "disabledSelectedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "focusedSelectedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "hoverSelectedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "pressedSelectedBorderColor", Color.WHITE );
|
||||
|
||||
border.applyStyleProperty( "default.borderWidth", 2 );
|
||||
border.applyStyleProperty( "default.borderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "default.focusedBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "default.focusColor", Color.WHITE );
|
||||
border.applyStyleProperty( "default.hoverBorderColor", Color.WHITE );
|
||||
border.applyStyleProperty( "default.pressedBorderColor", Color.WHITE );
|
||||
|
||||
border.applyStyleProperty( "toolbar.focusWidth", 1.5f );
|
||||
border.applyStyleProperty( "toolbar.focusColor", Color.WHITE );
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# when the Demo window is activated.
|
||||
|
||||
|
||||
# base theme (light, dark, intellij or darcula)
|
||||
# base theme (light, dark, intellij, darcula, maclight or macdark)
|
||||
@baseTheme = light
|
||||
|
||||
# add you theme defaults here
|
||||
|
||||
@@ -140,8 +140,8 @@ class ControlBar
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.apple.laf.AquaLookAndFeel" );
|
||||
else if( SystemInfo.isLinux )
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F12, MetalLookAndFeel.class.getName() );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F11, NimbusLookAndFeel.class.getName() );
|
||||
registerSwitchToLookAndFeel( KeyEvent.VK_F12, MetalLookAndFeel.class.getName() );
|
||||
|
||||
// register Alt+UP and Alt+DOWN to switch to previous/next theme
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
@@ -153,6 +153,9 @@ class ControlBar
|
||||
KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, KeyEvent.ALT_DOWN_MASK ),
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||
|
||||
// register Alt+Shift+F1, F2, ... keys to change system scale factor
|
||||
DemoPrefs.registerSystemScaleFactors( frame );
|
||||
|
||||
// register ESC key to close frame
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
e -> {
|
||||
|
||||
@@ -25,6 +25,8 @@ import javax.swing.*;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.tree.*;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.ColorFunctions;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
/**
|
||||
@@ -93,10 +95,12 @@ class DataComponentsPanel
|
||||
|
||||
private void rowSelectionChanged() {
|
||||
table1.setRowSelectionAllowed( rowSelectionCheckBox.isSelected() );
|
||||
roundedSelectionChanged();
|
||||
}
|
||||
|
||||
private void columnSelectionChanged() {
|
||||
table1.setColumnSelectionAllowed( columnSelectionCheckBox.isSelected() );
|
||||
roundedSelectionChanged();
|
||||
}
|
||||
|
||||
private void showHorizontalLinesChanged() {
|
||||
@@ -127,6 +131,28 @@ class DataComponentsPanel
|
||||
intercellSpacingCheckBox.setSelected( table1.getRowMargin() != 0 );
|
||||
}
|
||||
|
||||
private void roundedSelectionChanged() {
|
||||
String style = null;
|
||||
if( roundedSelectionCheckBox.isSelected() ) {
|
||||
style = rowSelectionCheckBox.isSelected()
|
||||
? "selectionArc: 6; selectionInsets: 0,1,0,1"
|
||||
: "selectionArc: 6";
|
||||
}
|
||||
table1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
}
|
||||
|
||||
private void alternatingRowsChanged() {
|
||||
Color alternateRowColor = null;
|
||||
if( alternatingRowsCheckBox.isSelected() ) {
|
||||
Color background = table1.getBackground();
|
||||
alternateRowColor = FlatLaf.isLafDark()
|
||||
? ColorFunctions.lighten( background, 0.05f )
|
||||
: ColorFunctions.darken( background, 0.05f );
|
||||
}
|
||||
UIManager.put( "Table.alternateRowColor", alternateRowColor );
|
||||
table1.repaint();
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
@@ -151,12 +177,14 @@ class DataComponentsPanel
|
||||
JScrollPane scrollPane5 = new JScrollPane();
|
||||
table1 = new JTable();
|
||||
JPanel tableOptionsPanel = new JPanel();
|
||||
roundedSelectionCheckBox = new JCheckBox();
|
||||
showHorizontalLinesCheckBox = new JCheckBox();
|
||||
showVerticalLinesCheckBox = new JCheckBox();
|
||||
intercellSpacingCheckBox = new JCheckBox();
|
||||
redGridColorCheckBox = new JCheckBox();
|
||||
rowSelectionCheckBox = new JCheckBox();
|
||||
columnSelectionCheckBox = new JCheckBox();
|
||||
alternatingRowsCheckBox = new JCheckBox();
|
||||
dndCheckBox = new JCheckBox();
|
||||
JPopupMenu popupMenu2 = new JPopupMenu();
|
||||
JMenuItem menuItem3 = new JMenuItem();
|
||||
@@ -403,44 +431,56 @@ class DataComponentsPanel
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0"));
|
||||
|
||||
//---- roundedSelectionCheckBox ----
|
||||
roundedSelectionCheckBox.setText("rounded selection");
|
||||
roundedSelectionCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
tableOptionsPanel.add(roundedSelectionCheckBox, "cell 0 0");
|
||||
|
||||
//---- showHorizontalLinesCheckBox ----
|
||||
showHorizontalLinesCheckBox.setText("show horizontal lines");
|
||||
showHorizontalLinesCheckBox.addActionListener(e -> showHorizontalLinesChanged());
|
||||
tableOptionsPanel.add(showHorizontalLinesCheckBox, "cell 0 0");
|
||||
tableOptionsPanel.add(showHorizontalLinesCheckBox, "cell 0 1");
|
||||
|
||||
//---- showVerticalLinesCheckBox ----
|
||||
showVerticalLinesCheckBox.setText("show vertical lines");
|
||||
showVerticalLinesCheckBox.addActionListener(e -> showVerticalLinesChanged());
|
||||
tableOptionsPanel.add(showVerticalLinesCheckBox, "cell 0 1");
|
||||
tableOptionsPanel.add(showVerticalLinesCheckBox, "cell 0 2");
|
||||
|
||||
//---- intercellSpacingCheckBox ----
|
||||
intercellSpacingCheckBox.setText("intercell spacing");
|
||||
intercellSpacingCheckBox.addActionListener(e -> intercellSpacingChanged());
|
||||
tableOptionsPanel.add(intercellSpacingCheckBox, "cell 0 2");
|
||||
tableOptionsPanel.add(intercellSpacingCheckBox, "cell 0 3");
|
||||
|
||||
//---- redGridColorCheckBox ----
|
||||
redGridColorCheckBox.setText("red grid color");
|
||||
redGridColorCheckBox.addActionListener(e -> redGridColorChanged());
|
||||
tableOptionsPanel.add(redGridColorCheckBox, "cell 0 3");
|
||||
tableOptionsPanel.add(redGridColorCheckBox, "cell 0 4");
|
||||
|
||||
//---- rowSelectionCheckBox ----
|
||||
rowSelectionCheckBox.setText("row selection");
|
||||
rowSelectionCheckBox.setSelected(true);
|
||||
rowSelectionCheckBox.addActionListener(e -> rowSelectionChanged());
|
||||
tableOptionsPanel.add(rowSelectionCheckBox, "cell 0 4");
|
||||
tableOptionsPanel.add(rowSelectionCheckBox, "cell 0 5");
|
||||
|
||||
//---- columnSelectionCheckBox ----
|
||||
columnSelectionCheckBox.setText("column selection");
|
||||
columnSelectionCheckBox.addActionListener(e -> columnSelectionChanged());
|
||||
tableOptionsPanel.add(columnSelectionCheckBox, "cell 0 5");
|
||||
tableOptionsPanel.add(columnSelectionCheckBox, "cell 0 6");
|
||||
|
||||
//---- alternatingRowsCheckBox ----
|
||||
alternatingRowsCheckBox.setText("alternating rows");
|
||||
alternatingRowsCheckBox.addActionListener(e -> alternatingRowsChanged());
|
||||
tableOptionsPanel.add(alternatingRowsCheckBox, "cell 0 7");
|
||||
|
||||
//---- dndCheckBox ----
|
||||
dndCheckBox.setText("enable drag and drop");
|
||||
dndCheckBox.setMnemonic('D');
|
||||
dndCheckBox.addActionListener(e -> dndChanged());
|
||||
tableOptionsPanel.add(dndCheckBox, "cell 0 6");
|
||||
tableOptionsPanel.add(dndCheckBox, "cell 0 8");
|
||||
}
|
||||
add(tableOptionsPanel, "cell 4 3");
|
||||
|
||||
@@ -477,12 +517,14 @@ class DataComponentsPanel
|
||||
private JTree tree3;
|
||||
private JTree tree2;
|
||||
private JTable table1;
|
||||
private JCheckBox roundedSelectionCheckBox;
|
||||
private JCheckBox showHorizontalLinesCheckBox;
|
||||
private JCheckBox showVerticalLinesCheckBox;
|
||||
private JCheckBox intercellSpacingCheckBox;
|
||||
private JCheckBox redGridColorCheckBox;
|
||||
private JCheckBox rowSelectionCheckBox;
|
||||
private JCheckBox columnSelectionCheckBox;
|
||||
private JCheckBox alternatingRowsCheckBox;
|
||||
private JCheckBox dndCheckBox;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
|
||||
@@ -343,9 +343,19 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets 0,hidemode 3"
|
||||
"$columnConstraints": "[]"
|
||||
"$rowConstraints": "[]0[]0[]0[]0[]0[]0[]0"
|
||||
"$rowConstraints": "[]0[]0[]0[]0[]0[]0[]0[]0[]0"
|
||||
} ) {
|
||||
name: "tableOptionsPanel"
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "roundedSelectionCheckBox"
|
||||
"text": "rounded selection"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "showHorizontalLinesCheckBox"
|
||||
"text": "show horizontal lines"
|
||||
@@ -354,7 +364,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showHorizontalLinesChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
"value": "cell 0 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "showVerticalLinesCheckBox"
|
||||
@@ -364,7 +374,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showVerticalLinesChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
"value": "cell 0 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "intercellSpacingCheckBox"
|
||||
@@ -374,7 +384,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "intercellSpacingChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "redGridColorCheckBox"
|
||||
@@ -384,7 +394,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redGridColorChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
"value": "cell 0 4"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "rowSelectionCheckBox"
|
||||
@@ -395,7 +405,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 4"
|
||||
"value": "cell 0 5"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "columnSelectionCheckBox"
|
||||
@@ -405,7 +415,17 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "columnSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 5"
|
||||
"value": "cell 0 6"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "alternatingRowsCheckBox"
|
||||
"text": "alternating rows"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "alternatingRowsChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 7"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "dndCheckBox"
|
||||
@@ -416,7 +436,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dndChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 6"
|
||||
"value": "cell 0 8"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 3"
|
||||
|
||||
@@ -19,6 +19,10 @@ package com.formdev.flatlaf.demo;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.prefs.Preferences;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
@@ -27,6 +31,7 @@ import com.formdev.flatlaf.IntelliJTheme;
|
||||
import com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel;
|
||||
import com.formdev.flatlaf.util.LoggingFacade;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -35,6 +40,7 @@ public class DemoPrefs
|
||||
{
|
||||
public static final String KEY_LAF = "laf";
|
||||
public static final String KEY_LAF_THEME = "lafTheme";
|
||||
public static final String KEY_SYSTEM_SCALE_FACTOR = "systemScaleFactor";
|
||||
|
||||
public static final String RESOURCE_PREFIX = "res:";
|
||||
public static final String FILE_PREFIX = "file:";
|
||||
@@ -96,4 +102,66 @@ public class DemoPrefs
|
||||
state.put( KEY_LAF, UIManager.getLookAndFeel().getClass().getName() );
|
||||
} );
|
||||
}
|
||||
|
||||
public static void initSystemScale() {
|
||||
if( System.getProperty( "sun.java2d.uiScale" ) == null ) {
|
||||
String scaleFactor = getState().get( KEY_SYSTEM_SCALE_FACTOR, null );
|
||||
if( scaleFactor != null )
|
||||
System.setProperty( "sun.java2d.uiScale", scaleFactor );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* register Alt+Shift+F1, F2, ... F12 keys to change system scale factor
|
||||
*/
|
||||
public static void registerSystemScaleFactors( JFrame frame ) {
|
||||
registerSystemScaleFactor( frame, "alt shift F1", null );
|
||||
registerSystemScaleFactor( frame, "alt shift F2", "1" );
|
||||
|
||||
if( SystemInfo.isWindows ) {
|
||||
registerSystemScaleFactor( frame, "alt shift F3", "1.25" );
|
||||
registerSystemScaleFactor( frame, "alt shift F4", "1.5" );
|
||||
registerSystemScaleFactor( frame, "alt shift F5", "1.75" );
|
||||
registerSystemScaleFactor( frame, "alt shift F6", "2" );
|
||||
registerSystemScaleFactor( frame, "alt shift F7", "2.25" );
|
||||
registerSystemScaleFactor( frame, "alt shift F8", "2.5" );
|
||||
registerSystemScaleFactor( frame, "alt shift F9", "2.75" );
|
||||
registerSystemScaleFactor( frame, "alt shift F10", "3" );
|
||||
registerSystemScaleFactor( frame, "alt shift F11", "3.5" );
|
||||
registerSystemScaleFactor( frame, "alt shift F12", "4" );
|
||||
} else {
|
||||
// Java on macOS and Linux supports only integer scale factors
|
||||
registerSystemScaleFactor( frame, "alt shift F3", "2" );
|
||||
registerSystemScaleFactor( frame, "alt shift F4", "3" );
|
||||
registerSystemScaleFactor( frame, "alt shift F5", "4" );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerSystemScaleFactor( JFrame frame, String keyStrokeStr, String scaleFactor ) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke( keyStrokeStr );
|
||||
if( keyStroke == null )
|
||||
throw new IllegalArgumentException( "Invalid key stroke '" + keyStrokeStr + "'" );
|
||||
|
||||
((JComponent)frame.getContentPane()).registerKeyboardAction(
|
||||
e -> applySystemScaleFactor( frame, scaleFactor ),
|
||||
keyStroke,
|
||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||
}
|
||||
|
||||
private static void applySystemScaleFactor( JFrame frame, String scaleFactor ) {
|
||||
if( JOptionPane.showConfirmDialog( frame,
|
||||
"Change system scale factor to "
|
||||
+ (scaleFactor != null ? scaleFactor : "default")
|
||||
+ " and exit?",
|
||||
frame.getTitle(), JOptionPane.YES_NO_OPTION ) != JOptionPane.YES_OPTION )
|
||||
return;
|
||||
|
||||
if( scaleFactor != null )
|
||||
DemoPrefs.getState().put( KEY_SYSTEM_SCALE_FACTOR, scaleFactor );
|
||||
else
|
||||
DemoPrefs.getState().remove( KEY_SYSTEM_SCALE_FACTOR );
|
||||
|
||||
System.exit( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +70,10 @@ public class FlatLafDemo
|
||||
if( FlatLafDemo.screenshotsMode && !SystemInfo.isJava_9_orLater && System.getProperty( "flatlaf.uiScale" ) == null )
|
||||
System.setProperty( "flatlaf.uiScale", "2x" );
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
DemoPrefs.init( PREFS_ROOT_PATH );
|
||||
DemoPrefs.init( PREFS_ROOT_PATH );
|
||||
DemoPrefs.initSystemScale();
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
// install fonts for lazy loading
|
||||
FlatInterFont.installLazy();
|
||||
FlatJetBrainsMonoFont.installLazy();
|
||||
@@ -95,6 +96,9 @@ public class FlatLafDemo
|
||||
// use Roboto Mono font
|
||||
// FlatLaf.setPreferredMonospacedFontFamily( FlatRobotoMonoFont.FAMILY );
|
||||
|
||||
// install own repaint manager to fix repaint issues at 125%, 175%, 225%, ... on Windows
|
||||
// HiDPIUtils.installHiDPIRepaintManager();
|
||||
|
||||
// application specific UI defaults
|
||||
FlatLaf.registerCustomDefaultsSource( "com.formdev.flatlaf.demo" );
|
||||
|
||||
|
||||
@@ -118,6 +118,14 @@ class MoreComponentsPanel
|
||||
JLabel label5 = new JLabel();
|
||||
JPanel panel13 = new JPanel();
|
||||
JLabel label6 = new JLabel();
|
||||
JLabel panelLabel = new JLabel();
|
||||
JPanel panel5 = new JPanel();
|
||||
JLabel label9 = new JLabel();
|
||||
JPanel panel4 = new JPanel();
|
||||
JLabel label8 = new JLabel();
|
||||
JLabel labelLabel = new JLabel();
|
||||
JLabel label13 = new JLabel();
|
||||
JLabel label10 = new JLabel();
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
@@ -140,7 +148,9 @@ class MoreComponentsPanel
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[100,top]"));
|
||||
"[100,top]" +
|
||||
"[50,top]" +
|
||||
"[]"));
|
||||
|
||||
//---- scrollPaneLabel ----
|
||||
scrollPaneLabel.setText("JScrollPane:");
|
||||
@@ -441,7 +451,7 @@ class MoreComponentsPanel
|
||||
|
||||
//======== panel10 ========
|
||||
{
|
||||
panel10.setBackground(new Color(217, 163, 67));
|
||||
panel10.setBackground(new Color(0xd9a343));
|
||||
panel10.setLayout(new BorderLayout());
|
||||
|
||||
//---- label1 ----
|
||||
@@ -454,7 +464,7 @@ class MoreComponentsPanel
|
||||
|
||||
//======== panel11 ========
|
||||
{
|
||||
panel11.setBackground(new Color(98, 181, 67));
|
||||
panel11.setBackground(new Color(0x62b543));
|
||||
panel11.setLayout(new BorderLayout());
|
||||
|
||||
//---- label2 ----
|
||||
@@ -474,7 +484,7 @@ class MoreComponentsPanel
|
||||
|
||||
//======== panel12 ========
|
||||
{
|
||||
panel12.setBackground(new Color(242, 101, 34));
|
||||
panel12.setBackground(new Color(0xf26522));
|
||||
panel12.setLayout(new BorderLayout());
|
||||
|
||||
//---- label5 ----
|
||||
@@ -487,7 +497,7 @@ class MoreComponentsPanel
|
||||
|
||||
//======== panel13 ========
|
||||
{
|
||||
panel13.setBackground(new Color(64, 182, 224));
|
||||
panel13.setBackground(new Color(0x40b6e0));
|
||||
panel13.setLayout(new BorderLayout());
|
||||
|
||||
//---- label6 ----
|
||||
@@ -502,6 +512,52 @@ class MoreComponentsPanel
|
||||
}
|
||||
add(splitPane3, "cell 1 11 4 1,grow");
|
||||
|
||||
//---- panelLabel ----
|
||||
panelLabel.setText("JPanel:");
|
||||
add(panelLabel, "cell 0 12");
|
||||
|
||||
//======== panel5 ========
|
||||
{
|
||||
panel5.putClientProperty("FlatLaf.style", "arc: 16; background: darken($Panel.background,5%)");
|
||||
panel5.setLayout(new BorderLayout());
|
||||
|
||||
//---- label9 ----
|
||||
label9.setText("rounded background");
|
||||
label9.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
panel5.add(label9, BorderLayout.CENTER);
|
||||
}
|
||||
add(panel5, "cell 1 12 4 1,growy,width 150");
|
||||
|
||||
//======== panel4 ========
|
||||
{
|
||||
panel4.putClientProperty("FlatLaf.style", "border: 1,1,1,1,@disabledForeground,1,16; background: darken($Panel.background,5%)");
|
||||
panel4.setLayout(new BorderLayout());
|
||||
|
||||
//---- label8 ----
|
||||
label8.setText("rounded border");
|
||||
label8.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
panel4.add(label8, BorderLayout.CENTER);
|
||||
}
|
||||
add(panel4, "cell 1 12 4 1,growy,width 150");
|
||||
|
||||
//---- labelLabel ----
|
||||
labelLabel.setText("JLabel:");
|
||||
add(labelLabel, "cell 0 13");
|
||||
|
||||
//---- label13 ----
|
||||
label13.setText("rounded background");
|
||||
label13.putClientProperty("FlatLaf.style", "arc: 999; border: 2,10,2,10");
|
||||
label13.setBackground(new Color(0xb8e4f3));
|
||||
label13.setForeground(new Color(0x135b76));
|
||||
add(label13, "cell 1 13 4 1");
|
||||
|
||||
//---- label10 ----
|
||||
label10.setText("rounded border");
|
||||
label10.putClientProperty("FlatLaf.style", "arc: 999; border: 2,10,2,10,#135b76");
|
||||
label10.setBackground(new Color(0xb8e4f3));
|
||||
label10.setForeground(new Color(0x135b76));
|
||||
add(label10, "cell 1 13 4 1");
|
||||
|
||||
//---- buttonGroup1 ----
|
||||
ButtonGroup buttonGroup1 = new ButtonGroup();
|
||||
buttonGroup1.add(toggleButton1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -9,7 +9,7 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[][][][][]"
|
||||
"$rowConstraints": "[][][][][][][][][][][][100,top]"
|
||||
"$rowConstraints": "[][][][][][][][][][][][100,top][50,top][]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
@@ -467,6 +467,62 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 11 4 1,grow"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "panelLabel"
|
||||
"text": "JPanel:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 12"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||
name: "panel5"
|
||||
"$client.FlatLaf.style": "arc: 16; background: darken($Panel.background,5%)"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label9"
|
||||
"text": "rounded background"
|
||||
"horizontalAlignment": 0
|
||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||
"value": "Center"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 12 4 1,growy,width 150"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
|
||||
name: "panel4"
|
||||
"$client.FlatLaf.style": "border: 1,1,1,1,@disabledForeground,1,16; background: darken($Panel.background,5%)"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label8"
|
||||
"text": "rounded border"
|
||||
"horizontalAlignment": 0
|
||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||
"value": "Center"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 12 4 1,growy,width 150"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "labelLabel"
|
||||
"text": "JLabel:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 13"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label13"
|
||||
"text": "rounded background"
|
||||
"$client.FlatLaf.style": "arc: 999; border: 2,10,2,10"
|
||||
"background": new java.awt.Color( 184, 228, 243, 255 )
|
||||
"foreground": new java.awt.Color( 19, 91, 118, 255 )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 13 4 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label10"
|
||||
"text": "rounded border"
|
||||
"$client.FlatLaf.style": "arc: 999; border: 2,10,2,10,#135b76"
|
||||
"background": new java.awt.Color( 184, 228, 243, 255 )
|
||||
"foreground": new java.awt.Color( 19, 91, 118, 255 )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 13 4 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 700, 550 )
|
||||
@@ -474,7 +530,7 @@ new FormModel {
|
||||
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
|
||||
name: "buttonGroup1"
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 560 )
|
||||
"location": new java.awt.Point( 0, 600 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.LayoutManager;
|
||||
@@ -450,15 +451,18 @@ public class FlatInspector
|
||||
Dimension size = tip.getPreferredSize();
|
||||
|
||||
// position the tip in the visible area
|
||||
Rectangle visibleRect = rootPane.getGraphicsConfiguration().getBounds();
|
||||
if( tx + size.width > visibleRect.x + visibleRect.width )
|
||||
tx -= size.width + UIScale.scale( 16 );
|
||||
if( ty + size.height > visibleRect.y + visibleRect.height )
|
||||
ty -= size.height + UIScale.scale( 32 );
|
||||
if( tx < visibleRect.x )
|
||||
tx = visibleRect.x;
|
||||
if( ty < visibleRect.y )
|
||||
ty = visibleRect.y;
|
||||
GraphicsConfiguration gc = rootPane.getGraphicsConfiguration();
|
||||
if( gc != null ) {
|
||||
Rectangle visibleRect = gc.getBounds();
|
||||
if( tx + size.width > visibleRect.x + visibleRect.width )
|
||||
tx -= size.width + UIScale.scale( 16 );
|
||||
if( ty + size.height > visibleRect.y + visibleRect.height )
|
||||
ty -= size.height + UIScale.scale( 32 );
|
||||
if( tx < visibleRect.x )
|
||||
tx = visibleRect.x;
|
||||
if( ty < visibleRect.y )
|
||||
ty = visibleRect.y;
|
||||
}
|
||||
|
||||
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||
popup = popupFactory.getPopup( c, tip, tx, ty );
|
||||
@@ -547,6 +551,12 @@ public class FlatInspector
|
||||
appendRow( buf, "Left-to-right", String.valueOf( c.getComponentOrientation().isLeftToRight() ) );
|
||||
appendRow( buf, "Parent", (c.getParent() != null ? toString( c.getParent().getClass(), classHierarchy ) : "null") );
|
||||
|
||||
if( c instanceof JComponent ) {
|
||||
Object style = ((JComponent)c).getClientProperty( FlatClientProperties.STYLE );
|
||||
if( style != null )
|
||||
appendRow( buf, "FlatLaf Style", style.toString() );
|
||||
}
|
||||
|
||||
// append parent level
|
||||
buf.append( "<tr><td colspan=\"2\">" );
|
||||
if( parentLevel > 0 )
|
||||
|
||||
@@ -28,10 +28,10 @@ Otherwise, download `flatlaf-intellij-themes-<version>.jar` here:
|
||||
How to use?
|
||||
-----------
|
||||
|
||||
Choose a theme (see list below) and invoke its `install` method. E.g.:
|
||||
Choose a theme (see list below) and invoke its `setup` method. E.g.:
|
||||
|
||||
~~~java
|
||||
FlatArcOrangeIJTheme.install();
|
||||
FlatArcOrangeIJTheme.setup();
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package com.formdev.flatlaf.jideoss.ui;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import com.formdev.flatlaf.ui.FlatHTML;
|
||||
import com.jidesoft.plaf.LookAndFeelFactory;
|
||||
import com.jidesoft.plaf.basic.BasicJideButtonListener;
|
||||
import com.jidesoft.plaf.basic.BasicJideButtonUI;
|
||||
|
||||
/**
|
||||
@@ -37,4 +42,26 @@ public class FlatJideButtonUI
|
||||
|
||||
return new FlatJideButtonUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicButtonListener createButtonListener( AbstractButton b ) {
|
||||
return new FlatJideButtonListener( b );
|
||||
}
|
||||
|
||||
//---- class FlatJideButtonListener ---------------------------------------
|
||||
|
||||
/** @since 3.5 */
|
||||
protected static class FlatJideButtonListener
|
||||
extends BasicJideButtonListener
|
||||
{
|
||||
protected FlatJideButtonListener( AbstractButton b ) {
|
||||
super( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,13 @@ package com.formdev.flatlaf.jideoss.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.ui.FlatHTML;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.jidesoft.plaf.LookAndFeelFactory;
|
||||
import com.jidesoft.plaf.basic.BasicJideLabelUI;
|
||||
@@ -65,6 +67,20 @@ public class FlatJideLabelUI
|
||||
defaults_initialized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JLabel c ) {
|
||||
super.installComponents( c );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -60,8 +60,11 @@ import com.sun.jna.platform.win32.WinDef.LRESULT;
|
||||
import com.sun.jna.platform.win32.WinDef.RECT;
|
||||
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
|
||||
import com.sun.jna.platform.win32.WinDef.WPARAM;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinUser.HMONITOR;
|
||||
import com.sun.jna.platform.win32.WinUser.WindowProc;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import com.sun.jna.win32.StdCallLibrary;
|
||||
import com.sun.jna.win32.W32APIOptions;
|
||||
|
||||
//
|
||||
@@ -306,6 +309,8 @@ public class FlatWindowsNativeWindowBorder
|
||||
WM_ENTERSIZEMOVE = 0x0231,
|
||||
WM_EXITSIZEMOVE = 0x0232,
|
||||
|
||||
WM_DPICHANGED = 0x02E0,
|
||||
|
||||
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
|
||||
|
||||
// WM_SIZE wParam
|
||||
@@ -498,6 +503,22 @@ public class FlatWindowsNativeWindowBorder
|
||||
isMoving = true;
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED:
|
||||
LRESULT lResult = User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||
|
||||
// if window is maximized and DPI/scaling changed, then Windows
|
||||
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||
// which depend on scale factor, are not updated
|
||||
boolean isMaximized = User32Ex.INSTANCE.IsZoomed( hwnd );
|
||||
if( isMaximized ) {
|
||||
MyRECT r = new MyRECT( new Pointer( lParam.longValue() ) );
|
||||
int width = r.right - r.left;
|
||||
int height = r.bottom - r.top;
|
||||
User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, WM_SIZE, new WPARAM( SIZE_MAXIMIZED ), MAKELPARAM( width, height ) );
|
||||
}
|
||||
|
||||
return lResult;
|
||||
|
||||
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+
|
||||
@@ -615,6 +636,14 @@ public class FlatWindowsNativeWindowBorder
|
||||
if( hasAutohideTaskbar( ABE_RIGHT, monitorInfo.rcMonitor ) )
|
||||
params.rgrc[0].right--;
|
||||
}
|
||||
} else if( SystemInfo.isWindows_11_orLater ) {
|
||||
// For Windows 11, add border thickness to top, which is necessary to make the whole Java area visible.
|
||||
// This also avoids that a black line is sometimes painted on top window border.
|
||||
// Note: Do not increase top on Windows 10 because this would not hide Windows title bar.
|
||||
IntByReference borderThickness = new IntByReference();
|
||||
if( DWMApi.INSTANCE.DwmGetWindowAttribute( hwnd, DWMApi.DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
|
||||
borderThickness.getPointer(), 4 ) == WinError.S_OK.intValue() )
|
||||
params.rgrc[0].top += borderThickness.getValue();
|
||||
}
|
||||
|
||||
// write changed params back to native memory
|
||||
@@ -807,6 +836,13 @@ public class FlatWindowsNativeWindowBorder
|
||||
return (low & 0xffff) | ((high & 0xffff) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same implementation as MAKELPARAM(l, h) macro in winuser.h.
|
||||
*/
|
||||
private LPARAM MAKELPARAM( int low, int high ) {
|
||||
return new LPARAM( MAKELONG( low, high ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Same implementation as RGB(r,g,b) macro in wingdi.h.
|
||||
*/
|
||||
@@ -898,6 +934,18 @@ public class FlatWindowsNativeWindowBorder
|
||||
HBRUSH CreateSolidBrush( DWORD color );
|
||||
}
|
||||
|
||||
//---- interface DWMApi ---------------------------------------------------
|
||||
|
||||
private interface DWMApi
|
||||
extends StdCallLibrary
|
||||
{
|
||||
DWMApi INSTANCE = Native.load( "dwmapi", DWMApi.class, W32APIOptions.DEFAULT_OPTIONS );
|
||||
|
||||
int DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37;
|
||||
|
||||
int DwmGetWindowAttribute( HWND hwnd, int dwAttribute, Pointer pvAttribute, int cbAttribute );
|
||||
}
|
||||
|
||||
//---- class NCCALCSIZE_PARAMS --------------------------------------------
|
||||
|
||||
@FieldOrder( { "rgrc" } )
|
||||
@@ -914,6 +962,23 @@ public class FlatWindowsNativeWindowBorder
|
||||
}
|
||||
}
|
||||
|
||||
//---- class MyRECT -------------------------------------------------------
|
||||
|
||||
@FieldOrder( { "left", "top", "right", "bottom" } )
|
||||
public static class MyRECT
|
||||
extends Structure
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
|
||||
public MyRECT( Pointer pointer ) {
|
||||
super( pointer );
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
//---- class MENUITEMINFO -------------------------------------------------
|
||||
|
||||
@FieldOrder( { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu",
|
||||
|
||||
@@ -19,3 +19,32 @@ The DLLs were built on a GitHub server with the help of GitHub Actions. See:
|
||||
[Native Libraries](https://github.com/JFormDesigner/FlatLaf/actions/workflows/natives.yml)
|
||||
workflow. Then the produced Artifacts ZIP was downloaded, signed DLLs with
|
||||
FormDev Software code signing certificate and committed the DLLs to Git.
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
To build the library on Windows using Gradle, (parts of)
|
||||
[Visual Studio Community
|
||||
2022](https://visualstudio.microsoft.com/downloads/)
|
||||
needs to be installed. After downloading and running `VisualStudioSetup.exe` the
|
||||
**Visual Studio Installer** is installed and started. Once running, it shows the
|
||||
**Workloads** tab that allows you to install additional packages. Either choose
|
||||
**Desktop development with C++**, or to save some disk space switch to the
|
||||
**Single Components** tab and choose following components (newest versions):
|
||||
|
||||
- MSVC v143 - VS 2022 C++ x64/x86 Buildtools
|
||||
- MSVC v143 - VS 2022 C++ ARM64/ARM64EC Buildtools
|
||||
- Windows 11 SDK
|
||||
|
||||
Note that the Visual Studio Installer shows many similar named components for
|
||||
MSVC. Make sure to choose exactly those components listed above.
|
||||
|
||||
Using
|
||||
[Build Tools for Visual Studio 2022](https://visualstudio.microsoft.com/downloads/#remote-tools-for-visual-studio-2022)
|
||||
(installs only compiler and SDKs) instead of
|
||||
[Visual Studio Community
|
||||
2022](https://visualstudio.microsoft.com/downloads/)
|
||||
does not work with Gradle.
|
||||
|
||||
[Visual Studio Code](https://code.visualstudio.com/) with **C/C++** extension
|
||||
can be used for C++ code editing.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <shellapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <jawt.h>
|
||||
#include <jawt_md.h>
|
||||
#include "FlatWndProc.h"
|
||||
@@ -76,6 +77,7 @@ jmethodID FlatWndProc::isFullscreenMID;
|
||||
jmethodID FlatWndProc::fireStateChangedLaterOnceMID;
|
||||
|
||||
HWNDMap* FlatWndProc::hwndMap;
|
||||
DWORD FlatWndProc::osBuildNumber = 0;
|
||||
|
||||
#define java_awt_Frame_ICONIFIED 1
|
||||
#define java_awt_Frame_MAXIMIZED_BOTH (4 | 2)
|
||||
@@ -107,6 +109,14 @@ HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get OS build number
|
||||
if( osBuildNumber == 0 ) {
|
||||
OSVERSIONINFO info;
|
||||
info.dwOSVersionInfoSize = sizeof( info );
|
||||
if( ::GetVersionEx( &info ) )
|
||||
osBuildNumber = info.dwBuildNumber;
|
||||
}
|
||||
|
||||
// get window handle
|
||||
HWND hwnd = getWindowHandle( env, window );
|
||||
if( hwnd == NULL || hwndMap->get( hwnd ) != NULL )
|
||||
@@ -278,6 +288,23 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
|
||||
isMoving = true;
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED: {
|
||||
LRESULT lResult = ::CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||
|
||||
// if window is maximized and DPI/scaling changed, then Windows
|
||||
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||
// which depend on scale factor, are not updated
|
||||
bool isMaximized = ::IsZoomed( hwnd );
|
||||
if( isMaximized ) {
|
||||
RECT* r = reinterpret_cast<RECT*>( lParam );
|
||||
int width = r->right - r->left;
|
||||
int height = r->bottom - r->top;
|
||||
::CallWindowProc( defaultWndProc, hwnd, WM_SIZE, SIZE_MAXIMIZED, MAKELPARAM( width, height ) );
|
||||
}
|
||||
|
||||
return lResult;
|
||||
}
|
||||
|
||||
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+
|
||||
@@ -391,6 +418,13 @@ LRESULT FlatWndProc::WmNcCalcSize( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lP
|
||||
if( hasAutohideTaskbar( ABE_RIGHT, monitorInfo.rcMonitor ) )
|
||||
params->rgrc[0].right--;
|
||||
}
|
||||
} else if( osBuildNumber >= 22000 ) {
|
||||
// For Windows 11, add border thickness to top, which is necessary to make the whole Java area visible.
|
||||
// This also avoids that a black line is sometimes painted on top window border.
|
||||
// Note: Do not increase top on Windows 10 because this would not hide Windows title bar.
|
||||
UINT borderThickness = 0;
|
||||
if( ::DwmGetWindowAttribute( hwnd, DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &borderThickness, sizeof( borderThickness ) ) == S_OK )
|
||||
params->rgrc[0].top += borderThickness;
|
||||
}
|
||||
|
||||
return lResult;
|
||||
|
||||
@@ -35,6 +35,7 @@ private:
|
||||
static jmethodID fireStateChangedLaterOnceMID;
|
||||
|
||||
static HWNDMap* hwndMap;
|
||||
static DWORD osBuildNumber;
|
||||
|
||||
JavaVM* jvm;
|
||||
JNIEnv* env; // attached to AWT-Windows/Win32 thread
|
||||
|
||||
@@ -30,12 +30,26 @@ HWND getWindowHandle( JNIEnv* env, jobject window );
|
||||
|
||||
//---- Utility ----------------------------------------------------------------
|
||||
|
||||
typedef LONG (WINAPI *RtlGetVersion_Type)( OSVERSIONINFO* );
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_getOSBuildNumberImpl
|
||||
( JNIEnv* env, jclass cls )
|
||||
{
|
||||
OSVERSIONINFO info;
|
||||
info.dwOSVersionInfoSize = sizeof( info );
|
||||
info.dwBuildNumber = 0;
|
||||
|
||||
// use RtlGetVersion for the case that app manifest does not specify Windows 10+ compatibility
|
||||
// https://www.codeproject.com/Articles/5336372/Windows-Version-Detection
|
||||
HMODULE ntdllModule = ::GetModuleHandleA( "ntdll.dll" );
|
||||
if( ntdllModule != NULL ) {
|
||||
RtlGetVersion_Type pRtlGetVersion = (RtlGetVersion_Type) ::GetProcAddress( ntdllModule, "RtlGetVersion" );
|
||||
if( pRtlGetVersion != NULL && pRtlGetVersion( &info ) == 0 )
|
||||
return info.dwBuildNumber;
|
||||
}
|
||||
|
||||
// fallback
|
||||
if( !::GetVersionEx( &info ) )
|
||||
return 0;
|
||||
return info.dwBuildNumber;
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.swingx.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.UIManager;
|
||||
@@ -25,6 +26,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import org.jdesktop.swingx.JXBusyLabel;
|
||||
import org.jdesktop.swingx.plaf.basic.BasicBusyLabelUI;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.ui.FlatHTML;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
|
||||
//TODO scale busy spinner
|
||||
@@ -70,6 +72,20 @@ public class FlatBusyLabelUI
|
||||
disabledForeground = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installComponents( JLabel c ) {
|
||||
super.installComponents( c );
|
||||
|
||||
// update HTML renderer if necessary
|
||||
FlatHTML.updateRendererCSSFontBaseSize( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintDisabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -21,12 +21,15 @@ import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
import org.jdesktop.swingx.plaf.basic.BasicHyperlinkUI;
|
||||
import com.formdev.flatlaf.ui.FlatButtonUI;
|
||||
import com.formdev.flatlaf.ui.FlatHTML;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
@@ -60,6 +63,11 @@ public class FlatHyperlinkUI
|
||||
disabledText = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicButtonListener createButtonListener( AbstractButton b ) {
|
||||
return new FlatHyperlinkListener( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text ) {
|
||||
FlatButtonUI.paintText( g, b, textRect, text, b.isEnabled() ? b.getForeground() : disabledText );
|
||||
@@ -79,4 +87,21 @@ public class FlatHyperlinkUI
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
|
||||
//---- class FlatHyperlinkListener ----------------------------------------
|
||||
|
||||
/** @since 3.5 */
|
||||
protected static class FlatHyperlinkListener
|
||||
extends BasicHyperlinkListener
|
||||
{
|
||||
protected FlatHyperlinkListener( AbstractButton b ) {
|
||||
super( b );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
super.propertyChange( e );
|
||||
FlatHTML.propertyChange( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ Button.default.hoverBackground #ffff00 HSL 60 100 50 javax.swing.plaf.Colo
|
||||
Button.default.hoverBorderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.hoverForeground #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.pressedBackground #ffc800 HSL 47 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.pressedBorderColor #8888ff HSL 240 100 77 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.pressedForeground #0080ff HSL 210 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.startBackground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.default.startBorderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
@@ -87,6 +88,7 @@ Button.disabledBackground #e0e0e0 HSL 0 0 88 javax.swing.plaf.Colo
|
||||
Button.disabledBorderColor #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.disabledForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.disabledSelectedBackground #112233 HSL 210 50 13 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.disabledSelectedBorderColor #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.disabledSelectedForeground #ffcccc HSL 0 100 90 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.disabledText #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.endBackground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
||||
@@ -94,21 +96,26 @@ Button.endBorderColor #ff0000 HSL 0 100 50 javax.swing.plaf.Colo
|
||||
Button.focusedBackground #00ffff HSL 180 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.focusedBorderColor #466d94 HSL 210 36 43 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.focusedForeground #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.focusedSelectedBorderColor #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.font [active] $defaultFont [UI]
|
||||
Button.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.hoverBackground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.hoverBorderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.hoverForeground #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.hoverSelectedBorderColor #aaaaaa HSL 0 0 67 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.iconTextGap 4
|
||||
Button.innerFocusWidth 1
|
||||
Button.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.margin 2,14,2,14 javax.swing.plaf.InsetsUIResource [UI]
|
||||
Button.minimumWidth 72
|
||||
Button.pressedBackground #ffc800 HSL 47 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.pressedBorderColor #00ffff HSL 180 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.pressedForeground #0080ff HSL 210 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.pressedSelectedBorderColor #888888 HSL 0 0 53 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.rollover true
|
||||
Button.selectedBackground #ffbbbb HSL 0 100 87 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.selectedBorderColor #ff00ff HSL 300 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.selectedForeground #332211 HSL 30 50 13 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.shadow #a0a0a0 HSL 0 0 63 javax.swing.plaf.ColorUIResource [UI]
|
||||
Button.startBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
|
||||
import com.formdev.flatlaf.ui.FlatEmptyBorder;
|
||||
import com.formdev.flatlaf.ui.FlatListUI;
|
||||
import com.formdev.flatlaf.ui.FlatTableUI;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import com.jidesoft.swing.*;
|
||||
import com.jidesoft.swing.CheckBoxTreeCellRenderer;
|
||||
@@ -131,6 +132,14 @@ public class FlatComponents2Test
|
||||
initTableEditors( table1 );
|
||||
initTableEditors( xTable1 );
|
||||
|
||||
// table selection listeners
|
||||
table1.getSelectionModel().addListSelectionListener( e -> {
|
||||
System.out.printf( "row sel %d-%d adj=%b\n", e.getFirstIndex(), e.getLastIndex(), e.getValueIsAdjusting() );
|
||||
} );
|
||||
table1.getColumnModel().getSelectionModel().addListSelectionListener( e -> {
|
||||
System.out.printf( "column sel %d-%d adj=%b\n", e.getFirstIndex(), e.getLastIndex(), e.getValueIsAdjusting() );
|
||||
} );
|
||||
|
||||
// JXTable
|
||||
Highlighter simpleStriping = HighlighterFactory.createSimpleStriping();
|
||||
PatternPredicate patternPredicate = new PatternPredicate( "^J", 2 );
|
||||
@@ -164,6 +173,8 @@ public class FlatComponents2Test
|
||||
JComboBox<String> editableComboBox = new JComboBox<>( months );
|
||||
editableComboBox.setEditable( true );
|
||||
cm.getColumn(3).setCellEditor( new DefaultCellEditor( editableComboBox ) );
|
||||
|
||||
// table.setDefaultRenderer( Object.class, new TestLabelRoundedTableCellRenderer() );
|
||||
}
|
||||
|
||||
private void expandTree( JTree tree ) {
|
||||
@@ -229,6 +240,65 @@ public class FlatComponents2Test
|
||||
FlatLaf.updateUILater();
|
||||
}
|
||||
|
||||
private void roundedSelectionChanged() {
|
||||
String style = roundedSelectionCheckBox.isSelected() ? "selectionArc: 12; " : "";
|
||||
int left = leftSelectionInsetsCheckBox.isSelected() ? 2 : 0;
|
||||
int right = rightSelectionInsetsCheckBox.isSelected() ? 2 : 0;
|
||||
int top = topSelectionInsetsCheckBox.isSelected() ? 2 : 0;
|
||||
int bottom = bottomSelectionInsetsCheckBox.isSelected() ? 2 : 0;
|
||||
if( left > 0 || right > 0 || top > 0 || bottom > 0 )
|
||||
style += "selectionInsets: " + top + ',' + left + ',' + bottom + ',' + right;
|
||||
if( style.isEmpty() )
|
||||
style = null;
|
||||
|
||||
list1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
list2.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
tree1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
tree2.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
xTree1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
checkBoxTree1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
table1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
xTable1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
xTreeTable1.putClientProperty( FlatClientProperties.STYLE, style );
|
||||
|
||||
// initial selection
|
||||
if( style != null ) {
|
||||
initSelection( list1 );
|
||||
initSelection( list2 );
|
||||
initSelection( tree1 );
|
||||
initSelection( tree2 );
|
||||
initSelection( xTree1 );
|
||||
initSelection( checkBoxTree1 );
|
||||
initSelection( table1 );
|
||||
initSelection( xTable1 );
|
||||
initSelection( xTreeTable1 );
|
||||
}
|
||||
|
||||
if( paintOutsideAlternateRowsCheckBox.isSelected() )
|
||||
table1ScrollPane.repaint();
|
||||
}
|
||||
|
||||
private static void initSelection( JList<?> list ) {
|
||||
if( list.isSelectionEmpty() ) {
|
||||
list.addSelectionInterval( 1, 2 );
|
||||
list.addSelectionInterval( 5, 5 );
|
||||
}
|
||||
}
|
||||
|
||||
private static void initSelection( JTree tree ) {
|
||||
if( tree.isSelectionEmpty() ) {
|
||||
tree.addSelectionInterval( 1, 2 );
|
||||
tree.addSelectionInterval( 5, 5 );
|
||||
}
|
||||
}
|
||||
|
||||
private static void initSelection( JTable table ) {
|
||||
if( table.getSelectedRowCount() == 0 ) {
|
||||
table.addRowSelectionInterval( 1, 2 );
|
||||
table.addRowSelectionInterval( 5, 5 );
|
||||
}
|
||||
}
|
||||
|
||||
private void dndChanged() {
|
||||
boolean dnd = dndCheckBox.isSelected();
|
||||
list1.setDragEnabled( dnd );
|
||||
@@ -535,6 +605,12 @@ public class FlatComponents2Test
|
||||
public void applyComponentOrientation( ComponentOrientation o ) {
|
||||
super.applyComponentOrientation( o );
|
||||
|
||||
// always use left-to-right for options panels
|
||||
generalOptionsPanel.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT );
|
||||
listOptionsPanel.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT );
|
||||
treeOptionsPanel.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT );
|
||||
tableOptionsPanel.applyComponentOrientation( ComponentOrientation.LEFT_TO_RIGHT );
|
||||
|
||||
// swap upper right and left corners (other corners are not used in this app)
|
||||
Component leftCorner = table1ScrollPane.getCorner( ScrollPaneConstants.UPPER_LEFT_CORNER );
|
||||
Component rightCorner = table1ScrollPane.getCorner( ScrollPaneConstants.UPPER_RIGHT_CORNER );
|
||||
@@ -596,16 +672,22 @@ public class FlatComponents2Test
|
||||
JLabel label2 = new JLabel();
|
||||
xTreeTable1ScrollPane = new JScrollPane();
|
||||
xTreeTable1 = new JXTreeTable();
|
||||
JPanel panel5 = new JPanel();
|
||||
generalOptionsPanel = new JPanel();
|
||||
roundedSelectionCheckBox = new JCheckBox();
|
||||
JLabel label6 = new JLabel();
|
||||
topSelectionInsetsCheckBox = new JCheckBox();
|
||||
bottomSelectionInsetsCheckBox = new JCheckBox();
|
||||
leftSelectionInsetsCheckBox = new JCheckBox();
|
||||
rightSelectionInsetsCheckBox = new JCheckBox();
|
||||
dndCheckBox = new JCheckBox();
|
||||
JPanel panel6 = new JPanel();
|
||||
listOptionsPanel = new JPanel();
|
||||
JLabel listRendererLabel = new JLabel();
|
||||
listRendererComboBox = new JComboBox<>();
|
||||
JLabel listLayoutOrientationLabel = new JLabel();
|
||||
listLayoutOrientationField = new JComboBox<>();
|
||||
JLabel listVisibleRowCountLabel = new JLabel();
|
||||
listVisibleRowCountSpinner = new JSpinner();
|
||||
JPanel treeOptionsPanel = new JPanel();
|
||||
treeOptionsPanel = new JPanel();
|
||||
JLabel treeRendererLabel = new JLabel();
|
||||
treeRendererComboBox = new JComboBox<>();
|
||||
treeWideSelectionCheckBox = new JCheckBox();
|
||||
@@ -614,7 +696,7 @@ public class FlatComponents2Test
|
||||
treeRedLinesCheckBox = new JCheckBox();
|
||||
treeEditableCheckBox = new JCheckBox();
|
||||
treeShowDefaultIconsCheckBox = new JCheckBox();
|
||||
JPanel tableOptionsPanel = new JPanel();
|
||||
tableOptionsPanel = new JPanel();
|
||||
JLabel autoResizeModeLabel = new JLabel();
|
||||
autoResizeModeField = new JComboBox<>();
|
||||
JLabel sortIconPositionLabel = new JLabel();
|
||||
@@ -872,30 +954,68 @@ public class FlatComponents2Test
|
||||
}
|
||||
add(xTreeTable1ScrollPane, "cell 4 3 2 1");
|
||||
|
||||
//======== panel5 ========
|
||||
//======== generalOptionsPanel ========
|
||||
{
|
||||
panel5.setBorder(new TitledBorder("General Control"));
|
||||
panel5.putClientProperty("FlatLaf.internal.testing.ignore", true);
|
||||
panel5.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
generalOptionsPanel.setBorder(new TitledBorder("General Control"));
|
||||
generalOptionsPanel.putClientProperty("FlatLaf.internal.testing.ignore", true);
|
||||
generalOptionsPanel.setLayout(new MigLayout(
|
||||
"insets 8,hidemode 3",
|
||||
// columns
|
||||
"[fill]",
|
||||
"[left]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]rel" +
|
||||
"[]"));
|
||||
|
||||
//---- roundedSelectionCheckBox ----
|
||||
roundedSelectionCheckBox.setText("rounded selection");
|
||||
roundedSelectionCheckBox.setMnemonic('D');
|
||||
roundedSelectionCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
generalOptionsPanel.add(roundedSelectionCheckBox, "cell 0 0");
|
||||
|
||||
//---- label6 ----
|
||||
label6.setText("Selection insets:");
|
||||
generalOptionsPanel.add(label6, "cell 0 1");
|
||||
|
||||
//---- topSelectionInsetsCheckBox ----
|
||||
topSelectionInsetsCheckBox.setText("top");
|
||||
topSelectionInsetsCheckBox.setMnemonic('D');
|
||||
topSelectionInsetsCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
generalOptionsPanel.add(topSelectionInsetsCheckBox, "cell 0 2,gapx ind");
|
||||
|
||||
//---- bottomSelectionInsetsCheckBox ----
|
||||
bottomSelectionInsetsCheckBox.setText("bottom");
|
||||
bottomSelectionInsetsCheckBox.setMnemonic('D');
|
||||
bottomSelectionInsetsCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
generalOptionsPanel.add(bottomSelectionInsetsCheckBox, "cell 0 2");
|
||||
|
||||
//---- leftSelectionInsetsCheckBox ----
|
||||
leftSelectionInsetsCheckBox.setText("left");
|
||||
leftSelectionInsetsCheckBox.setMnemonic('D');
|
||||
leftSelectionInsetsCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
generalOptionsPanel.add(leftSelectionInsetsCheckBox, "cell 0 3,gapx ind");
|
||||
|
||||
//---- rightSelectionInsetsCheckBox ----
|
||||
rightSelectionInsetsCheckBox.setText("right");
|
||||
rightSelectionInsetsCheckBox.setMnemonic('D');
|
||||
rightSelectionInsetsCheckBox.addActionListener(e -> roundedSelectionChanged());
|
||||
generalOptionsPanel.add(rightSelectionInsetsCheckBox, "cell 0 3");
|
||||
|
||||
//---- dndCheckBox ----
|
||||
dndCheckBox.setText("drag and drop");
|
||||
dndCheckBox.setMnemonic('D');
|
||||
dndCheckBox.addActionListener(e -> dndChanged());
|
||||
panel5.add(dndCheckBox, "cell 0 0");
|
||||
generalOptionsPanel.add(dndCheckBox, "cell 0 4");
|
||||
}
|
||||
add(panel5, "cell 0 4 4 1");
|
||||
add(generalOptionsPanel, "cell 0 4 4 1");
|
||||
|
||||
//======== panel6 ========
|
||||
//======== listOptionsPanel ========
|
||||
{
|
||||
panel6.setBorder(new TitledBorder("JList Control"));
|
||||
panel6.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
listOptionsPanel.setBorder(new TitledBorder("JList Control"));
|
||||
listOptionsPanel.setLayout(new MigLayout(
|
||||
"insets 8,hidemode 3",
|
||||
// columns
|
||||
"[fill]" +
|
||||
"[fill]",
|
||||
@@ -906,7 +1026,7 @@ public class FlatComponents2Test
|
||||
|
||||
//---- listRendererLabel ----
|
||||
listRendererLabel.setText("Renderer:");
|
||||
panel6.add(listRendererLabel, "cell 0 0");
|
||||
listOptionsPanel.add(listRendererLabel, "cell 0 0");
|
||||
|
||||
//---- listRendererComboBox ----
|
||||
listRendererComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
@@ -916,11 +1036,11 @@ public class FlatComponents2Test
|
||||
"labelRounded"
|
||||
}));
|
||||
listRendererComboBox.addActionListener(e -> listRendererChanged());
|
||||
panel6.add(listRendererComboBox, "cell 1 0");
|
||||
listOptionsPanel.add(listRendererComboBox, "cell 1 0");
|
||||
|
||||
//---- listLayoutOrientationLabel ----
|
||||
listLayoutOrientationLabel.setText("Orientation:");
|
||||
panel6.add(listLayoutOrientationLabel, "cell 0 1");
|
||||
listOptionsPanel.add(listLayoutOrientationLabel, "cell 0 1");
|
||||
|
||||
//---- listLayoutOrientationField ----
|
||||
listLayoutOrientationField.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
@@ -929,25 +1049,25 @@ public class FlatComponents2Test
|
||||
"horzontal wrap"
|
||||
}));
|
||||
listLayoutOrientationField.addActionListener(e -> listLayoutOrientationChanged());
|
||||
panel6.add(listLayoutOrientationField, "cell 1 1");
|
||||
listOptionsPanel.add(listLayoutOrientationField, "cell 1 1");
|
||||
|
||||
//---- listVisibleRowCountLabel ----
|
||||
listVisibleRowCountLabel.setText("Visible row count:");
|
||||
panel6.add(listVisibleRowCountLabel, "cell 0 2");
|
||||
listOptionsPanel.add(listVisibleRowCountLabel, "cell 0 2");
|
||||
|
||||
//---- listVisibleRowCountSpinner ----
|
||||
listVisibleRowCountSpinner.setModel(new SpinnerNumberModel(8, 0, null, 1));
|
||||
listVisibleRowCountSpinner.addChangeListener(e -> listVisibleRowCountChanged());
|
||||
panel6.add(listVisibleRowCountSpinner, "cell 1 2");
|
||||
listOptionsPanel.add(listVisibleRowCountSpinner, "cell 1 2");
|
||||
}
|
||||
add(panel6, "cell 0 4 4 1");
|
||||
add(listOptionsPanel, "cell 0 4 4 1");
|
||||
|
||||
//======== treeOptionsPanel ========
|
||||
{
|
||||
treeOptionsPanel.setBorder(new TitledBorder("JTree Control"));
|
||||
treeOptionsPanel.putClientProperty("FlatLaf.internal.testing.ignore", true);
|
||||
treeOptionsPanel.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
"insets 8,hidemode 3",
|
||||
// columns
|
||||
"[left]",
|
||||
// rows
|
||||
@@ -1014,7 +1134,7 @@ public class FlatComponents2Test
|
||||
tableOptionsPanel.setBorder(new TitledBorder("JTable Control"));
|
||||
tableOptionsPanel.putClientProperty("FlatLaf.internal.testing.ignore", true);
|
||||
tableOptionsPanel.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
"insets 8,hidemode 3",
|
||||
// columns
|
||||
"[]" +
|
||||
"[fill]" +
|
||||
@@ -1132,10 +1252,18 @@ public class FlatComponents2Test
|
||||
private CheckBoxTree checkBoxTree1;
|
||||
private JScrollPane xTreeTable1ScrollPane;
|
||||
private JXTreeTable xTreeTable1;
|
||||
private JPanel generalOptionsPanel;
|
||||
private JCheckBox roundedSelectionCheckBox;
|
||||
private JCheckBox topSelectionInsetsCheckBox;
|
||||
private JCheckBox bottomSelectionInsetsCheckBox;
|
||||
private JCheckBox leftSelectionInsetsCheckBox;
|
||||
private JCheckBox rightSelectionInsetsCheckBox;
|
||||
private JCheckBox dndCheckBox;
|
||||
private JPanel listOptionsPanel;
|
||||
private JComboBox<String> listRendererComboBox;
|
||||
private JComboBox<String> listLayoutOrientationField;
|
||||
private JSpinner listVisibleRowCountSpinner;
|
||||
private JPanel treeOptionsPanel;
|
||||
private JComboBox<String> treeRendererComboBox;
|
||||
private JCheckBox treeWideSelectionCheckBox;
|
||||
private JCheckBox treePaintSelectionCheckBox;
|
||||
@@ -1143,6 +1271,7 @@ public class FlatComponents2Test
|
||||
private JCheckBox treeRedLinesCheckBox;
|
||||
private JCheckBox treeEditableCheckBox;
|
||||
private JCheckBox treeShowDefaultIconsCheckBox;
|
||||
private JPanel tableOptionsPanel;
|
||||
private JComboBox<String> autoResizeModeField;
|
||||
private JComboBox<String> sortIconPositionComboBox;
|
||||
private JCheckBox showHorizontalLinesCheckBox;
|
||||
@@ -1683,4 +1812,46 @@ public class FlatComponents2Test
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//---- class TestLabelRoundedTableCellRenderer ----------------------------
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
private static class TestLabelRoundedTableCellRenderer
|
||||
extends JLabel
|
||||
implements TableCellRenderer
|
||||
{
|
||||
private JTable table;
|
||||
private int row;
|
||||
private int column;
|
||||
private boolean isSelected;
|
||||
|
||||
TestLabelRoundedTableCellRenderer() {
|
||||
setBorder( new FlatEmptyBorder( 1, 6, 1, 6 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent( JTable table, Object value,
|
||||
boolean isSelected, boolean hasFocus, int row, int column )
|
||||
{
|
||||
this.table = table;
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
this.isSelected = isSelected;
|
||||
|
||||
setText( String.valueOf( value ) );
|
||||
setBackground( isSelected ? Color.green : table.getBackground() );
|
||||
setForeground( isSelected ? Color.blue : table.getForeground() );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
if( isSelected ) {
|
||||
g.setColor( getBackground() );
|
||||
FlatTableUI.paintCellSelection( table, g, row, column, 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
super.paintComponent( g );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "8.0.0.0.194" Java: "17.0.2" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -297,13 +297,77 @@ new FormModel {
|
||||
"value": "cell 4 3 2 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill]"
|
||||
"$rowConstraints": "[]"
|
||||
"$layoutConstraints": "insets 8,hidemode 3"
|
||||
"$columnConstraints": "[left]"
|
||||
"$rowConstraints": "[][]0[]0[]rel[]"
|
||||
} ) {
|
||||
name: "panel5"
|
||||
name: "generalOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "General Control" )
|
||||
"$client.FlatLaf.internal.testing.ignore": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "roundedSelectionCheckBox"
|
||||
"text": "rounded selection"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label6"
|
||||
"text": "Selection insets:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "topSelectionInsetsCheckBox"
|
||||
"text": "top"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2,gapx ind"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "bottomSelectionInsetsCheckBox"
|
||||
"text": "bottom"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "leftSelectionInsetsCheckBox"
|
||||
"text": "left"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3,gapx ind"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "rightSelectionInsetsCheckBox"
|
||||
"text": "right"
|
||||
"mnemonic": 68
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "roundedSelectionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "dndCheckBox"
|
||||
"text": "drag and drop"
|
||||
@@ -313,18 +377,21 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dndChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
"value": "cell 0 4"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 4 4 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$layoutConstraints": "insets 8,hidemode 3"
|
||||
"$columnConstraints": "[fill][fill]"
|
||||
"$rowConstraints": "[][][]"
|
||||
} ) {
|
||||
name: "panel6"
|
||||
name: "listOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "JList Control" )
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "listRendererLabel"
|
||||
"text": "Renderer:"
|
||||
@@ -392,13 +459,16 @@ new FormModel {
|
||||
"value": "cell 0 4 4 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$layoutConstraints": "insets 8,hidemode 3"
|
||||
"$columnConstraints": "[left]"
|
||||
"$rowConstraints": "[][]0[]0[]0[]"
|
||||
} ) {
|
||||
name: "treeOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "JTree Control" )
|
||||
"$client.FlatLaf.internal.testing.ignore": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "treeRendererLabel"
|
||||
"text": "Renderer:"
|
||||
@@ -491,13 +561,16 @@ new FormModel {
|
||||
"value": "cell 0 4 4 1"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$layoutConstraints": "insets 8,hidemode 3"
|
||||
"$columnConstraints": "[][fill][fill]"
|
||||
"$rowConstraints": "[][]0[]0[]0[]0"
|
||||
} ) {
|
||||
name: "tableOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "JTable Control" )
|
||||
"$client.FlatLaf.internal.testing.ignore": true
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "autoResizeModeLabel"
|
||||
"text": "Auto resize mode:"
|
||||
|
||||
@@ -59,6 +59,11 @@ public class FlatComponentsTest
|
||||
};
|
||||
for( JSlider slider : allSliders )
|
||||
slider.addChangeListener( sliderChanged );
|
||||
|
||||
UIManager.addPropertyChangeListener( e -> {
|
||||
if( "lookAndFeel".equals( e.getPropertyName() ) && hideArrowButtonCheckBox.isSelected() )
|
||||
SwingUtilities.invokeLater( () -> hideArrowButton() );
|
||||
} );
|
||||
}
|
||||
|
||||
private void changeProgress() {
|
||||
@@ -127,6 +132,18 @@ public class FlatComponentsTest
|
||||
}
|
||||
}
|
||||
|
||||
private void hideArrowButton() {
|
||||
boolean hideArrowButton = hideArrowButtonCheckBox.isSelected();
|
||||
|
||||
for( Component c : getComponents() ) {
|
||||
if( c instanceof JComboBox ) {
|
||||
Component b = ((JComboBox<?>)c).getComponent( 0 );
|
||||
if( b instanceof AbstractButton )
|
||||
b.setVisible( !hideArrowButton );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void roundRectChanged() {
|
||||
Boolean roundRect = roundRectCheckBox.isSelected() ? true : null;
|
||||
|
||||
@@ -380,6 +397,7 @@ public class FlatComponentsTest
|
||||
magentaOutlineRadioButton = new JRadioButton();
|
||||
magentaCyanOutlineRadioButton = new JRadioButton();
|
||||
focusPaintedCheckBox = new JCheckBox();
|
||||
hideArrowButtonCheckBox = new JCheckBox();
|
||||
JLabel scrollBarLabel = new JLabel();
|
||||
JScrollBar scrollBar1 = new JScrollBar();
|
||||
JScrollBar scrollBar4 = new JScrollBar();
|
||||
@@ -1234,9 +1252,10 @@ public class FlatComponentsTest
|
||||
"[]" +
|
||||
"[]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]"));
|
||||
|
||||
//---- buttonTypeComboBox ----
|
||||
@@ -1290,13 +1309,18 @@ public class FlatComponentsTest
|
||||
magentaCyanOutlineRadioButton.addActionListener(e -> outlineChanged());
|
||||
panel4.add(magentaCyanOutlineRadioButton);
|
||||
}
|
||||
panel5.add(panel4, "cell 0 2 1 2");
|
||||
panel5.add(panel4, "cell 0 2 1 3");
|
||||
|
||||
//---- focusPaintedCheckBox ----
|
||||
focusPaintedCheckBox.setText("focusPainted");
|
||||
focusPaintedCheckBox.setSelected(true);
|
||||
focusPaintedCheckBox.addActionListener(e -> focusPaintedChanged());
|
||||
panel5.add(focusPaintedCheckBox, "cell 1 2");
|
||||
|
||||
//---- hideArrowButtonCheckBox ----
|
||||
hideArrowButtonCheckBox.setText("hide arrow button");
|
||||
hideArrowButtonCheckBox.addActionListener(e -> hideArrowButton());
|
||||
panel5.add(hideArrowButtonCheckBox, "cell 1 3");
|
||||
}
|
||||
add(panel5, "cell 5 13 2 10,grow");
|
||||
|
||||
@@ -1703,6 +1727,7 @@ public class FlatComponentsTest
|
||||
private JRadioButton magentaOutlineRadioButton;
|
||||
private JRadioButton magentaCyanOutlineRadioButton;
|
||||
private JCheckBox focusPaintedCheckBox;
|
||||
private JCheckBox hideArrowButtonCheckBox;
|
||||
private JSlider slider1;
|
||||
private JSlider slider6;
|
||||
private JCheckBox sliderPaintTrackCheckBox;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -993,7 +993,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$columnConstraints": "[][]"
|
||||
"$rowConstraints": "[][][][]"
|
||||
"$rowConstraints": "[]0[]0[]0[]0[]"
|
||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||
} ) {
|
||||
name: "panel5"
|
||||
@@ -1092,7 +1092,7 @@ new FormModel {
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "outlineChanged", false ) )
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2 1 2"
|
||||
"value": "cell 0 2 1 3"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "focusPaintedCheckBox"
|
||||
@@ -1105,6 +1105,16 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "hideArrowButtonCheckBox"
|
||||
"text": "hide arrow button"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hideArrowButton", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 3"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 5 13 2 10,grow"
|
||||
} )
|
||||
|
||||
@@ -40,6 +40,8 @@ import net.miginfocom.swing.*;
|
||||
public class FlatFileChooserTest
|
||||
extends FlatTestPanel
|
||||
{
|
||||
private static ShortcutsCount shortcutsCount = ShortcutsCount.home;
|
||||
|
||||
public static void main( String[] args ) {
|
||||
// Locale.setDefault( Locale.FRENCH );
|
||||
// Locale.setDefault( Locale.GERMAN );
|
||||
@@ -52,8 +54,21 @@ public class FlatFileChooserTest
|
||||
FlatTestFrame frame = FlatTestFrame.create( args, "FlatFileChooserTest" );
|
||||
|
||||
UIManager.put( "FileChooser.shortcuts.filesFunction", (Function<File[], File[]>) files -> {
|
||||
if( shortcutsCount == null )
|
||||
return files;
|
||||
if( shortcutsCount == ShortcutsCount.empty )
|
||||
return new File[0];
|
||||
|
||||
ArrayList<File> list = new ArrayList<>( Arrays.asList( files ) );
|
||||
list.add( 0, new File( System.getProperty( "user.home" ) ) );
|
||||
if( shortcutsCount == ShortcutsCount.home )
|
||||
list.add( 0, new File( System.getProperty( "user.home" ) ) );
|
||||
else {
|
||||
File home = new File( System.getProperty( "user.home" ) );
|
||||
File[] homeFiles = home.listFiles();
|
||||
int count = shortcutsCount.value;
|
||||
for( int i = 0; i < count; i++ )
|
||||
list.add( i < homeFiles.length ? homeFiles[i] : new File( "Dummy " + i ) );
|
||||
}
|
||||
return list.toArray( new File[list.size()] );
|
||||
} );
|
||||
|
||||
@@ -78,6 +93,8 @@ public class FlatFileChooserTest
|
||||
dialogTypeField.init( DialogType.class, false );
|
||||
fileSelectionModeField.init( FileSelectionMode.class, false );
|
||||
localesField.init( Locales.class, false );
|
||||
shortcutsCountField.init( ShortcutsCount.class, true );
|
||||
shortcutsCountField.setSelectedValue( shortcutsCount );
|
||||
|
||||
showControlButtonsCheckBox.setSelected( fileChooser1.getControlButtonsAreShown() );
|
||||
multiSelectionCheckBox.setSelected( fileChooser1.isMultiSelectionEnabled() );
|
||||
@@ -197,6 +214,11 @@ public class FlatFileChooserTest
|
||||
} );
|
||||
}
|
||||
|
||||
private void shortcutsCountChanged() {
|
||||
shortcutsCount = shortcutsCountField.getSelectedValue();
|
||||
fileChooser1.updateUI();
|
||||
}
|
||||
|
||||
private void printShortcutFiles() {
|
||||
printFiles( JavaCompatibility2.getChooserShortcutPanelFiles( fileChooser1.getFileSystemView() ) );
|
||||
}
|
||||
@@ -263,6 +285,8 @@ public class FlatFileChooserTest
|
||||
printRootsButton = new JButton();
|
||||
JLabel localesLabel = new JLabel();
|
||||
localesField = new FlatTestEnumSelector<>();
|
||||
JLabel label12 = new JLabel();
|
||||
shortcutsCountField = new FlatTestEnumSelector<>();
|
||||
JLabel label1 = new JLabel();
|
||||
JLabel label2 = new JLabel();
|
||||
JLabel label3 = new JLabel();
|
||||
@@ -291,6 +315,7 @@ public class FlatFileChooserTest
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]para" +
|
||||
"[]"));
|
||||
|
||||
@@ -432,49 +457,57 @@ public class FlatFileChooserTest
|
||||
localesField.addActionListener(e -> localesChanged());
|
||||
add(localesField, "cell 1 8 2 1");
|
||||
|
||||
//---- label12 ----
|
||||
label12.setText("Shortcuts:");
|
||||
add(label12, "cell 0 9");
|
||||
|
||||
//---- shortcutsCountField ----
|
||||
shortcutsCountField.addActionListener(e -> shortcutsCountChanged());
|
||||
add(shortcutsCountField, "cell 1 9 2 1");
|
||||
|
||||
//---- label1 ----
|
||||
label1.setText("icons:");
|
||||
add(label1, "cell 0 9");
|
||||
add(label1, "cell 0 10");
|
||||
|
||||
//---- label2 ----
|
||||
label2.setIcon(UIManager.getIcon("FileView.directoryIcon"));
|
||||
add(label2, "cell 1 9 2 1");
|
||||
add(label2, "cell 1 10 2 1");
|
||||
|
||||
//---- label3 ----
|
||||
label3.setIcon(UIManager.getIcon("FileView.fileIcon"));
|
||||
add(label3, "cell 1 9 2 1");
|
||||
add(label3, "cell 1 10 2 1");
|
||||
|
||||
//---- label4 ----
|
||||
label4.setIcon(UIManager.getIcon("FileView.computerIcon"));
|
||||
add(label4, "cell 1 9 2 1");
|
||||
add(label4, "cell 1 10 2 1");
|
||||
|
||||
//---- label5 ----
|
||||
label5.setIcon(UIManager.getIcon("FileView.hardDriveIcon"));
|
||||
add(label5, "cell 1 9 2 1");
|
||||
add(label5, "cell 1 10 2 1");
|
||||
|
||||
//---- label6 ----
|
||||
label6.setIcon(UIManager.getIcon("FileView.floppyDriveIcon"));
|
||||
add(label6, "cell 1 9 2 1");
|
||||
add(label6, "cell 1 10 2 1");
|
||||
|
||||
//---- label7 ----
|
||||
label7.setIcon(UIManager.getIcon("FileChooser.newFolderIcon"));
|
||||
add(label7, "cell 1 9 2 1");
|
||||
add(label7, "cell 1 10 2 1");
|
||||
|
||||
//---- label8 ----
|
||||
label8.setIcon(UIManager.getIcon("FileChooser.upFolderIcon"));
|
||||
add(label8, "cell 1 9 2 1");
|
||||
add(label8, "cell 1 10 2 1");
|
||||
|
||||
//---- label9 ----
|
||||
label9.setIcon(UIManager.getIcon("FileChooser.homeFolderIcon"));
|
||||
add(label9, "cell 1 9 2 1");
|
||||
add(label9, "cell 1 10 2 1");
|
||||
|
||||
//---- label10 ----
|
||||
label10.setIcon(UIManager.getIcon("FileChooser.detailsViewIcon"));
|
||||
add(label10, "cell 1 9 2 1");
|
||||
add(label10, "cell 1 10 2 1");
|
||||
|
||||
//---- label11 ----
|
||||
label11.setIcon(UIManager.getIcon("FileChooser.listViewIcon"));
|
||||
add(label11, "cell 1 9 2 1");
|
||||
add(label11, "cell 1 10 2 1");
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||
}
|
||||
|
||||
@@ -500,6 +533,7 @@ public class FlatFileChooserTest
|
||||
private JButton printComboBoxFilesButton;
|
||||
private JButton printRootsButton;
|
||||
private FlatTestEnumSelector<Locales> localesField;
|
||||
private FlatTestEnumSelector<ShortcutsCount> shortcutsCountField;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
//---- enum DialogType ----------------------------------------------------
|
||||
@@ -553,4 +587,26 @@ public class FlatFileChooserTest
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
//---- enum ShortcutsCount ------------------------------------------------
|
||||
|
||||
enum ShortcutsCount {
|
||||
empty( -1 ),
|
||||
home( -2 ),
|
||||
zero( 0 ),
|
||||
one( 1 ),
|
||||
two( 2 ),
|
||||
three( 3 ),
|
||||
four( 4 ),
|
||||
five( 5 ),
|
||||
ten( 10 ),
|
||||
twenty( 20 ),
|
||||
thirty( 30 );
|
||||
|
||||
public final int value;
|
||||
|
||||
ShortcutsCount( int value ) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "8.2.0.0.331" Java: "21" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" 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": "[][][grow]"
|
||||
"$rowConstraints": "[grow,fill][][][][][][][][]para[]"
|
||||
"$rowConstraints": "[grow,fill][][][][][][][][][]para[]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
@@ -273,71 +273,87 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 8 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label12"
|
||||
"text": "Shortcuts:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 9"
|
||||
} )
|
||||
add( new FormComponent( "com.formdev.flatlaf.testing.FlatTestEnumSelector" ) {
|
||||
name: "shortcutsCountField"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
"JavaCodeGenerator.typeParameters": "ShortcutsCount"
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "shortcutsCountChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label1"
|
||||
"text": "icons:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 9"
|
||||
"value": "cell 0 10"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label2"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileView.directoryIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label3"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileView.fileIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label4"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileView.computerIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label5"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileView.hardDriveIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label6"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileView.floppyDriveIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label7"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileChooser.newFolderIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label8"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileChooser.upFolderIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label9"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileChooser.homeFolderIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label10"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileChooser.detailsViewIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label11"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 2, "FileChooser.listViewIcon" )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9 2 1"
|
||||
"value": "cell 1 10 2 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright 2024 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.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
public class FlatHiDPITest
|
||||
{
|
||||
private static final double scale = 1.25;
|
||||
|
||||
private final JFrame frame;
|
||||
private final JPanel testPanel;
|
||||
|
||||
private final Insets frameInsets;
|
||||
|
||||
public static void main( String[] args ) {
|
||||
System.setProperty( FlatSystemProperties.USE_WINDOW_DECORATIONS, "false" );
|
||||
System.setProperty( "sun.java2d.uiScale", Double.toString( scale ) );
|
||||
|
||||
System.out.println( "Scale factor: " + scale );
|
||||
for( int x = 0; x <= 100; x++ ) {
|
||||
int devX = devScaleXY( x, scale );
|
||||
int usrX = usrScaleXY( x, scale );
|
||||
if( usrX != devX )
|
||||
System.out.printf( "%d: %d != %d\n", x, devX, usrX );
|
||||
|
||||
/*
|
||||
for( int w = 0; w <= 10; w++ ) {
|
||||
int devW = devScaleWH( w, scale );
|
||||
int usrW = usrScaleWH( x, w, scale );
|
||||
if( usrW != devW )
|
||||
System.out.printf( " %d %d: %d != %d\n", x, w, devW, usrW );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater( () -> {
|
||||
if( !SystemInfo.isJava_9_orLater ) {
|
||||
JOptionPane.showMessageDialog( null, "Use Java 9+" );
|
||||
return;
|
||||
}
|
||||
|
||||
// HiDPIUtils.installHiDPIRepaintManager();
|
||||
|
||||
FlatLaf.setGlobalExtraDefaults( Collections.singletonMap( "@accentColor", "#f00" ) );
|
||||
FlatLightLaf.setup();
|
||||
|
||||
UIManager.put( "Button.pressedBorderColor", Color.blue );
|
||||
UIManager.put( "TextField.caretBlinkRate", 0 );
|
||||
UIManager.put( "FormattedTextField.caretBlinkRate", 0 );
|
||||
|
||||
new FlatHiDPITest();
|
||||
} );
|
||||
}
|
||||
|
||||
FlatHiDPITest() {
|
||||
frame = new JFrame( "FlatHiDPITest " + scale ) {
|
||||
@Override
|
||||
public Graphics getGraphics() {
|
||||
return TestGraphics2D.install( super.getGraphics(), "JFrame" );
|
||||
}
|
||||
};
|
||||
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
|
||||
|
||||
// get frame insets
|
||||
frame.addNotify();
|
||||
frameInsets = frame.getInsets();
|
||||
|
||||
testPanel = new JPanel( null ) {
|
||||
@Override
|
||||
public Graphics getGraphics() {
|
||||
return TestGraphics2D.install( super.getGraphics(), "JPanel" );
|
||||
}
|
||||
};
|
||||
|
||||
int y = 0;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "TestComp", TestComp::new );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "JButton", () -> new JButton( "B" ) );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "JTextField", () -> new JTextField( "Text" ) );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "JComboBox", JComboBox<String>::new );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "JComboBox editable", () -> {
|
||||
JComboBox<String> c = new JComboBox<>();
|
||||
c.setEditable( true );
|
||||
return c;
|
||||
} );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 40, 16, 48, "JSpinner", JSpinner::new );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 80, 16, 88, "JSlider", JSlider::new );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 80, 16, 88, "JScrollBar", () -> new JScrollBar( JScrollBar.HORIZONTAL ) );
|
||||
y += 20;
|
||||
addAtProblematicXY( 0, y, 16, 40, 20, "JScrollBar", () -> new JScrollBar( JScrollBar.VERTICAL ) );
|
||||
y += 60;
|
||||
addAtProblematicXY( 0, y, 82, 60, 88, "JScrollPane", () -> new JScrollPane( new JTree() ) );
|
||||
y += 80;
|
||||
addAtProblematicXY( 0, y, 80, 16, 88, "JProgressBar", () -> {
|
||||
JProgressBar c = new JProgressBar();
|
||||
c.setValue( 60 );
|
||||
c.addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
int value = c.getValue();
|
||||
c.setValue( (value >= 20) ? value - 20 : 100 );
|
||||
}
|
||||
} );
|
||||
return c;
|
||||
} );
|
||||
|
||||
frame.getContentPane().add( testPanel );
|
||||
frame.setSize( 400, 400 );
|
||||
frame.setVisible( true );
|
||||
}
|
||||
|
||||
private void addAtProblematicXY( int x, int y, int w, int h, int offset, String text, Supplier<Component> generator ) {
|
||||
// plain component
|
||||
addAtProblematicXY( x, y, w, h, generator.get() );
|
||||
|
||||
// component in (opaque) panel which has same bounds as component
|
||||
addAtProblematicXY( x + offset, y, w, h, wrapInPanel( generator.get(), false ) );
|
||||
|
||||
// component in (opaque) panel which is 1px larger than component
|
||||
addAtProblematicXY( x + (offset * 2), y, w + 1, h + 1, wrapInPanel( generator.get(), true ) );
|
||||
|
||||
JLabel l = new JLabel( text );
|
||||
testPanel.add( l );
|
||||
l.setLocation( x + (offset * 3) + 20, y );
|
||||
l.setSize( l.getPreferredSize() );
|
||||
}
|
||||
|
||||
private void addAtProblematicXY( int x, int y, int w, int h, Component c ) {
|
||||
int px = nextProblematicXY( x + frameInsets.left ) - frameInsets.left;
|
||||
int py = nextProblematicXY( y + frameInsets.top ) - frameInsets.top;
|
||||
testPanel.add( c );
|
||||
c.setBounds( px, py, w, h );
|
||||
}
|
||||
|
||||
private Component wrapInPanel( Component c, boolean emptyBorder ) {
|
||||
JPanel p = new JPanel( new BorderLayout() ) {
|
||||
@Override
|
||||
public Graphics getGraphics() {
|
||||
return TestGraphics2D.install( super.getGraphics(), "wrapping JPanel" );
|
||||
}
|
||||
};
|
||||
if( emptyBorder )
|
||||
p.setBorder( new EmptyBorder( 0, 0, 1, 1 ) );
|
||||
p.add( c, BorderLayout.CENTER );
|
||||
return p;
|
||||
}
|
||||
|
||||
private static int nextProblematicXY( int xy ) {
|
||||
for( int i = xy; i < xy + 20; i++ ) {
|
||||
if( devScaleXY( i, scale ) != usrScaleXY( i, scale ) )
|
||||
return i;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
private static int devScaleXY( int xy, double scale ) {
|
||||
return (int) (xy * scale);
|
||||
}
|
||||
|
||||
private static int usrScaleXY( int xy, double scale ) {
|
||||
// see sun.java2d.pipe.Region.clipRound(double);
|
||||
return (int) Math.ceil( (xy * scale) - 0.5 );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
private static int devScaleWH( int wh, double scale ) {
|
||||
return (int) Math.round( wh * scale );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unused" )
|
||||
private static int usrScaleWH( int xy, int wh, double scale ) {
|
||||
int usrXY = usrScaleXY( xy, scale );
|
||||
return ((int) Math.ceil( ((xy + wh) * scale) - 0.5 )) - usrXY;
|
||||
}
|
||||
|
||||
//---- class TestComp -----------------------------------------------------
|
||||
|
||||
private static class TestComp
|
||||
extends JComponent
|
||||
implements FocusListener
|
||||
{
|
||||
// used to avoid repainting when window is deactivated and activated (for easier debugging)
|
||||
private boolean permanentFocused;
|
||||
|
||||
TestComp() {
|
||||
setOpaque( true );
|
||||
setFocusable( true );
|
||||
|
||||
addFocusListener( this );
|
||||
addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
requestFocusInWindow();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
g.setColor( isFocusOwner() ? Color.green : Color.red );
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( permanentFocused )
|
||||
return;
|
||||
|
||||
if( !e.isTemporary() ) {
|
||||
repaint();
|
||||
permanentFocused = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent e ) {
|
||||
if( !e.isTemporary() ) {
|
||||
repaint();
|
||||
permanentFocused = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics getGraphics() {
|
||||
return TestGraphics2D.install( super.getGraphics(), "TestComp" );
|
||||
}
|
||||
}
|
||||
|
||||
//---- TestGraphics2D -----------------------------------------------------
|
||||
|
||||
private static class TestGraphics2D
|
||||
extends Graphics2DProxy
|
||||
{
|
||||
private final Graphics2D delegate;
|
||||
private final String id;
|
||||
|
||||
static Graphics install( Graphics g, String id ) {
|
||||
return wasInvokedFrom_safelyGetGraphics()
|
||||
? new TestGraphics2D( (Graphics2D) g, id )
|
||||
: g;
|
||||
}
|
||||
|
||||
private static boolean wasInvokedFrom_safelyGetGraphics() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement stackTraceElement = stackTrace[4];
|
||||
return "javax.swing.JComponent".equals( stackTraceElement.getClassName() ) &&
|
||||
"safelyGetGraphics".equals( stackTraceElement.getMethodName() );
|
||||
}
|
||||
|
||||
private TestGraphics2D( Graphics2D delegate, String id ) {
|
||||
super( delegate );
|
||||
this.delegate = delegate;
|
||||
this.id = id;
|
||||
|
||||
System.out.println();
|
||||
System.out.println( "---------------------------------------- " );
|
||||
System.out.println( id + ": construct" );
|
||||
printClipRects();
|
||||
}
|
||||
|
||||
private void printClipRects() {
|
||||
try {
|
||||
Class<?> sunGraphics2DClass = Class.forName( "sun.java2d.SunGraphics2D" );
|
||||
if( !sunGraphics2DClass.isInstance( delegate ) ) {
|
||||
System.out.println( " not a SunGraphics2D: " + delegate.getClass().getName() );
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle devClip = region2rect( getFieldValue( sunGraphics2DClass, delegate, "devClip" ) );
|
||||
Shape usrClip = (Shape) getFieldValue( sunGraphics2DClass, delegate, "usrClip" );
|
||||
Rectangle clipRegion = region2rect( getFieldValue( sunGraphics2DClass, delegate, "clipRegion" ) );
|
||||
|
||||
printField( devClip, "devClip" );
|
||||
printField( usrClip, "usrClip" );
|
||||
printField( clipRegion, "clipRegion" );
|
||||
|
||||
if( (usrClip instanceof Rectangle && !devClip.contains( (Rectangle) usrClip )) ||
|
||||
(usrClip instanceof Rectangle2D && !devClip.contains( (Rectangle2D) usrClip )) )
|
||||
{
|
||||
System.out.flush();
|
||||
System.err.println( "WARNING: devClip smaller than usrClip" );
|
||||
System.err.flush();
|
||||
}
|
||||
} catch( Exception ex ) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void printField( Object value, String name ) throws Exception {
|
||||
System.out.printf( " %-16s", name );
|
||||
|
||||
if( value instanceof Rectangle ) {
|
||||
Rectangle r = (Rectangle) value;
|
||||
System.out.printf( "xy %3d %3d -> %3d %3d wh %3d %3d\n",
|
||||
r.x, r.y, r.x + r.width, r.y + r.height, r.width, r.height );
|
||||
} else if( value instanceof Rectangle2D ) {
|
||||
Rectangle2D r = (Rectangle2D) value;
|
||||
System.out.printf( "xy %.2f %.2f -> %.2f %.2f wh %.2f %.2f\n",
|
||||
r.getX(), r.getY(), r.getX() + r.getWidth(), r.getY() + r.getHeight(), r.getWidth(), r.getHeight() );
|
||||
} else
|
||||
System.out.println( value );
|
||||
}
|
||||
|
||||
private static Rectangle region2rect( Object region ) throws Exception {
|
||||
Class<?> regionClass = Class.forName( "sun.java2d.pipe.Region" );
|
||||
int loX = (int) getMethodValue( regionClass, region, "getLoX" );
|
||||
int loY = (int) getMethodValue( regionClass, region, "getLoY" );
|
||||
int hiX = (int) getMethodValue( regionClass, region, "getHiX" );
|
||||
int hiY = (int) getMethodValue( regionClass, region, "getHiY" );
|
||||
return new Rectangle( loX, loY, hiX - loX, hiY - loY );
|
||||
}
|
||||
|
||||
private static Object getFieldValue( Class<?> cls, Object object, String name ) throws Exception {
|
||||
Field f = cls.getDeclaredField( name );
|
||||
f.setAccessible( true );
|
||||
return f.get( object );
|
||||
}
|
||||
|
||||
private static Object getMethodValue( Class<?> cls, Object object, String name ) throws Exception {
|
||||
Method m = cls.getDeclaredMethod( name );
|
||||
m.setAccessible( true );
|
||||
return m.invoke( object );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clipRect( int x, int y, int width, int height ) {
|
||||
System.out.printf( "\n%s: clipRect( %d, %d, %d, %d )\n", id, x, y, width, height );
|
||||
super.clipRect( x, y, width, height );
|
||||
printClipRects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip( int x, int y, int width, int height ) {
|
||||
System.out.printf( "\n%s: setClip( %d, %d, %d, %d )\n", id, x, y, width, height );
|
||||
super.setClip( x, y, width, height );
|
||||
printClipRects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip( Shape clip ) {
|
||||
System.out.printf( "\n%s: setClip( %s )\n", id, clip );
|
||||
super.setClip( clip );
|
||||
printClipRects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clip( Shape s ) {
|
||||
System.out.printf( "\n%s: clip( %s )\n", id, s );
|
||||
super.clip( s );
|
||||
printClipRects();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,10 @@ package com.formdev.flatlaf.testing;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import com.jidesoft.swing.*;
|
||||
import net.miginfocom.swing.*;
|
||||
import org.jdesktop.swingx.*;
|
||||
|
||||
@@ -53,6 +55,58 @@ public class FlatHtmlTest
|
||||
increaseFontSize();
|
||||
}
|
||||
|
||||
private void changeHtmlText() {
|
||||
changeHtmlText( this );
|
||||
}
|
||||
|
||||
private void changeHtmlText( Component c ) {
|
||||
if( c instanceof AbstractButton )
|
||||
((AbstractButton)c).setText( changeHtmlText( ((AbstractButton)c).getText() ) );
|
||||
else if( c instanceof JLabel )
|
||||
((JLabel)c).setText( changeHtmlText( ((JLabel)c).getText() ) );
|
||||
else if( c instanceof JTextComponent )
|
||||
((JTextComponent)c).setText( changeHtmlText( ((JTextComponent)c).getText() ) );
|
||||
else if( c instanceof JToolTip )
|
||||
((JToolTip)c).setTipText( changeHtmlText( ((JToolTip)c).getTipText() ) );
|
||||
else if( c instanceof JComboBox ) {
|
||||
@SuppressWarnings( "unchecked" )
|
||||
JComboBox<String> cb = (JComboBox<String>) c;
|
||||
DefaultComboBoxModel<String> model = (DefaultComboBoxModel<String>) cb.getModel();
|
||||
String text = model.getElementAt( 0 );
|
||||
String newText = changeHtmlText( text );
|
||||
if( newText != text ) {
|
||||
model.insertElementAt( newText, 1 );
|
||||
model.removeElementAt( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( c instanceof Container ) {
|
||||
for( Component child : ((Container)c).getComponents() )
|
||||
changeHtmlText( child );
|
||||
}
|
||||
}
|
||||
|
||||
private String changeHtmlText( String text ) {
|
||||
String htmlTag = "<html>";
|
||||
if( !text.startsWith( htmlTag ) )
|
||||
return text;
|
||||
|
||||
String bodyTag = "<body>";
|
||||
int bodyIndex = text.indexOf( bodyTag );
|
||||
if( bodyIndex < 0 )
|
||||
bodyIndex = htmlTag.length();
|
||||
else
|
||||
bodyIndex += bodyTag.length();
|
||||
|
||||
int insertIndex = text.indexOf( '>', bodyIndex );
|
||||
if( insertIndex < 0 )
|
||||
insertIndex = bodyIndex;
|
||||
else
|
||||
insertIndex++;
|
||||
|
||||
return text.substring( 0, insertIndex ) + "X" + text.substring( insertIndex );
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
JLabel labelLabel = new JLabel();
|
||||
@@ -88,14 +142,28 @@ public class FlatHtmlTest
|
||||
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
|
||||
JRadioButtonMenuItem radioButtonMenuItem2 = new JRadioButtonMenuItem();
|
||||
JLabel label14 = new JLabel();
|
||||
JLabel label15 = new JLabel();
|
||||
JLabel label16 = new JLabel();
|
||||
JToolTip toolTip3 = new JToolTip();
|
||||
JToolTip toolTip4 = new JToolTip();
|
||||
JLabel label17 = new JLabel();
|
||||
JComboBox<String> comboBox1 = new JComboBox<>();
|
||||
JComboBox<String> comboBox2 = new JComboBox<>();
|
||||
JLabel label56 = new JLabel();
|
||||
JXBusyLabel xBusyLabel1 = new JXBusyLabel();
|
||||
JXBusyLabel xBusyLabel2 = new JXBusyLabel();
|
||||
JLabel label18 = new JLabel();
|
||||
JXHyperlink xHyperlink1 = new JXHyperlink();
|
||||
JXHyperlink xHyperlink2 = new JXHyperlink();
|
||||
JLabel label33 = new JLabel();
|
||||
JideLabel jideLabel1 = new JideLabel();
|
||||
JideLabel jideLabel2 = new JideLabel();
|
||||
JLabel label16 = new JLabel();
|
||||
JideButton jideButton1 = new JideButton();
|
||||
JideButton jideButton2 = new JideButton();
|
||||
JLabel label54 = new JLabel();
|
||||
JideToggleButton jideToggleButton1 = new JideToggleButton();
|
||||
JideToggleButton jideToggleButton2 = new JideToggleButton();
|
||||
JButton changeHtmlTextButton = new JButton();
|
||||
JLabel label15 = new JLabel();
|
||||
label1 = new JLabel();
|
||||
JScrollPane scrollPane15 = new JScrollPane();
|
||||
editorPane1 = new JEditorPane();
|
||||
@@ -143,13 +211,10 @@ public class FlatHtmlTest
|
||||
JLabel label47 = new JLabel();
|
||||
JLabel label53 = new JLabel();
|
||||
JLabel label48 = new JLabel();
|
||||
JLabel label54 = new JLabel();
|
||||
JLabel label56 = new JLabel();
|
||||
JLabel label57 = new JLabel();
|
||||
|
||||
//======== this ========
|
||||
setLayout(new MigLayout(
|
||||
"ltr,insets dialog,hidemode 3",
|
||||
"flowy,ltr,insets dialog,hidemode 3",
|
||||
// columns
|
||||
"[grow,sizegroup 1,fill]" +
|
||||
"[grow,sizegroup 1,fill]" +
|
||||
@@ -196,6 +261,12 @@ public class FlatHtmlTest
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]unrel" +
|
||||
"[]" +
|
||||
"[]unrel" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]para" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
|
||||
@@ -204,7 +275,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label5, "cell 0 0");
|
||||
|
||||
//---- label6 ----
|
||||
label6.setText("<html>Some <b>Bold</b> Text");
|
||||
label6.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(label6, "cell 1 0");
|
||||
|
||||
//---- label7 ----
|
||||
@@ -212,11 +283,11 @@ public class FlatHtmlTest
|
||||
panel1.add(label7, "cell 2 0");
|
||||
|
||||
//---- label3 ----
|
||||
label3.setText("JButon:");
|
||||
label3.setText("JButton:");
|
||||
panel1.add(label3, "cell 0 1");
|
||||
|
||||
//---- button1 ----
|
||||
button1.setText("<html>Some <b>Bold</b> Text");
|
||||
button1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(button1, "cell 1 1");
|
||||
|
||||
//---- button2 ----
|
||||
@@ -228,7 +299,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label11, "cell 0 2");
|
||||
|
||||
//---- toggleButton1 ----
|
||||
toggleButton1.setText("<html>Some <b>Bold</b> Text");
|
||||
toggleButton1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
toggleButton1.setSelected(true);
|
||||
panel1.add(toggleButton1, "cell 1 2");
|
||||
|
||||
@@ -242,7 +313,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label12, "cell 0 3");
|
||||
|
||||
//---- checkBox1 ----
|
||||
checkBox1.setText("<html>Some <b>Bold</b> Text");
|
||||
checkBox1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(checkBox1, "cell 1 3");
|
||||
|
||||
//---- checkBox2 ----
|
||||
@@ -254,7 +325,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label13, "cell 0 4");
|
||||
|
||||
//---- radioButton1 ----
|
||||
radioButton1.setText("<html>Some <b>Bold</b> Text");
|
||||
radioButton1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(radioButton1, "cell 1 4");
|
||||
|
||||
//---- radioButton2 ----
|
||||
@@ -267,7 +338,7 @@ public class FlatHtmlTest
|
||||
|
||||
//======== menu1 ========
|
||||
{
|
||||
menu1.setText("<html>Some <b>Bold</b> Text");
|
||||
menu1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
}
|
||||
panel1.add(menu1, "cell 1 5");
|
||||
|
||||
@@ -282,7 +353,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label4, "cell 0 6");
|
||||
|
||||
//---- menuItem1 ----
|
||||
menuItem1.setText("<html>Some <b>Bold</b> Text");
|
||||
menuItem1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(menuItem1, "cell 1 6");
|
||||
|
||||
//---- menuItem2 ----
|
||||
@@ -294,7 +365,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label9, "cell 0 7");
|
||||
|
||||
//---- checkBoxMenuItem1 ----
|
||||
checkBoxMenuItem1.setText("<html>Some <b>Bold</b> Text");
|
||||
checkBoxMenuItem1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
checkBoxMenuItem1.setSelected(true);
|
||||
panel1.add(checkBoxMenuItem1, "cell 1 7");
|
||||
|
||||
@@ -308,7 +379,7 @@ public class FlatHtmlTest
|
||||
panel1.add(label10, "cell 0 8");
|
||||
|
||||
//---- radioButtonMenuItem1 ----
|
||||
radioButtonMenuItem1.setText("<html>Some <b>Bold</b> Text");
|
||||
radioButtonMenuItem1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
radioButtonMenuItem1.setSelected(true);
|
||||
panel1.add(radioButtonMenuItem1, "cell 1 8");
|
||||
|
||||
@@ -321,15 +392,13 @@ public class FlatHtmlTest
|
||||
label14.setText("JToolTip:");
|
||||
panel1.add(label14, "cell 0 9");
|
||||
|
||||
//---- label15 ----
|
||||
label15.setText("(move mouse here)");
|
||||
label15.setToolTipText("<html>Some <b>Bold</b> Text");
|
||||
panel1.add(label15, "cell 1 9");
|
||||
//---- toolTip3 ----
|
||||
toolTip3.setTipText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(toolTip3, "cell 1 9");
|
||||
|
||||
//---- label16 ----
|
||||
label16.setText("(move mouse here)");
|
||||
label16.setToolTipText("Some text");
|
||||
panel1.add(label16, "cell 2 9");
|
||||
//---- toolTip4 ----
|
||||
toolTip4.setTipText("Some text");
|
||||
panel1.add(toolTip4, "cell 2 9");
|
||||
|
||||
//---- label17 ----
|
||||
label17.setText("JComboBox:");
|
||||
@@ -337,7 +406,7 @@ public class FlatHtmlTest
|
||||
|
||||
//---- comboBox1 ----
|
||||
comboBox1.setModel(new DefaultComboBoxModel<>(new String[] {
|
||||
"<html>Some <b>Bold</b> Text",
|
||||
"<html>Some <b>Bold</b> Text <kbd>kbd</kbd>",
|
||||
"abc",
|
||||
"def"
|
||||
}));
|
||||
@@ -351,19 +420,76 @@ public class FlatHtmlTest
|
||||
}));
|
||||
panel1.add(comboBox2, "cell 2 10");
|
||||
|
||||
//---- label56 ----
|
||||
label56.setText("JXBusyLabel:");
|
||||
panel1.add(label56, "cell 0 11");
|
||||
|
||||
//---- xBusyLabel1 ----
|
||||
xBusyLabel1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(xBusyLabel1, "cell 1 11");
|
||||
|
||||
//---- xBusyLabel2 ----
|
||||
xBusyLabel2.setText("Some text");
|
||||
panel1.add(xBusyLabel2, "cell 2 11");
|
||||
|
||||
//---- label18 ----
|
||||
label18.setText("JXHyperlink:");
|
||||
panel1.add(label18, "cell 0 11");
|
||||
panel1.add(label18, "cell 0 12");
|
||||
|
||||
//---- xHyperlink1 ----
|
||||
xHyperlink1.setText("<html>Some <b>Bold</b> Text");
|
||||
panel1.add(xHyperlink1, "cell 1 11");
|
||||
xHyperlink1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(xHyperlink1, "cell 1 12");
|
||||
|
||||
//---- xHyperlink2 ----
|
||||
xHyperlink2.setText("Some text");
|
||||
panel1.add(xHyperlink2, "cell 2 11");
|
||||
panel1.add(xHyperlink2, "cell 2 12");
|
||||
|
||||
//---- label33 ----
|
||||
label33.setText("JideLabel:");
|
||||
panel1.add(label33, "cell 0 13");
|
||||
|
||||
//---- jideLabel1 ----
|
||||
jideLabel1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(jideLabel1, "cell 1 13");
|
||||
|
||||
//---- jideLabel2 ----
|
||||
jideLabel2.setText("Some text");
|
||||
panel1.add(jideLabel2, "cell 2 13");
|
||||
|
||||
//---- label16 ----
|
||||
label16.setText("JideButton:");
|
||||
panel1.add(label16, "cell 0 14");
|
||||
|
||||
//---- jideButton1 ----
|
||||
jideButton1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(jideButton1, "cell 1 14");
|
||||
|
||||
//---- jideButton2 ----
|
||||
jideButton2.setText("Some text");
|
||||
panel1.add(jideButton2, "cell 2 14");
|
||||
|
||||
//---- label54 ----
|
||||
label54.setText("JideToggleButton:");
|
||||
panel1.add(label54, "cell 0 15");
|
||||
|
||||
//---- jideToggleButton1 ----
|
||||
jideToggleButton1.setText("<html>Some <b>Bold</b> Text <kbd>kbd</kbd>");
|
||||
panel1.add(jideToggleButton1, "cell 1 15");
|
||||
|
||||
//---- jideToggleButton2 ----
|
||||
jideToggleButton2.setText("Some text");
|
||||
panel1.add(jideToggleButton2, "cell 2 15");
|
||||
|
||||
//---- changeHtmlTextButton ----
|
||||
changeHtmlTextButton.setText("Change HTML Text");
|
||||
changeHtmlTextButton.addActionListener(e -> changeHtmlText());
|
||||
panel1.add(changeHtmlTextButton, "cell 0 16");
|
||||
|
||||
//---- label15 ----
|
||||
label15.setText("(use to check whether CSS is updated on text changes)");
|
||||
panel1.add(label15, "cell 0 17 3 1");
|
||||
}
|
||||
add(panel1, "cell 4 0 1 2,aligny top,growy 0");
|
||||
add(panel1, "cell 4 0 1 3,aligny top,growy 0");
|
||||
|
||||
//---- label1 ----
|
||||
label1.setText("<html>HTML<br>Sample <b>content</b><br> <u>text</u> with <a href=\"#\">link</a><h1>Header 1</h1><h2>Header 2</h2><h3>Header 3</h3><h4>Header 4</h4><h5>Header 5</h5><h6>Header 6</h6><p>Paragraph</p><address>Address</address><hr><table border=\"1\"><tr><th>Col 1</th><th>Col 2</th></tr><tr><td>abc</td><td>def</td></tr></table><ul><li>item 1</li><li>item 2</li></ul></html>");
|
||||
@@ -441,10 +567,6 @@ public class FlatHtmlTest
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]para" +
|
||||
"[]para" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
|
||||
//---- label22 ----
|
||||
@@ -582,20 +704,8 @@ public class FlatHtmlTest
|
||||
//---- label48 ----
|
||||
label48.setText("<html><address>address</address></html>");
|
||||
panel2.add(label48, "cell 1 5");
|
||||
|
||||
//---- label54 ----
|
||||
label54.setText("Test whether inserted rule affects display:");
|
||||
panel2.add(label54, "cell 0 7 7 1");
|
||||
|
||||
//---- label56 ----
|
||||
label56.setText("<html><head><style>body { color: red }</style></head>leading <big>red</big> trailing</html>");
|
||||
panel2.add(label56, "cell 0 8 7 1");
|
||||
|
||||
//---- label57 ----
|
||||
label57.setText("<html><style>body { color: red }</style><p>leading <big>red</big> trailing</p></html>");
|
||||
panel2.add(label57, "cell 0 9 7 1");
|
||||
}
|
||||
add(panel2, "cell 4 2");
|
||||
add(panel2, "cell 4 0 1 3");
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -7,7 +7,7 @@ new FormModel {
|
||||
"JavaCodeGenerator.defaultVariableLocal": true
|
||||
}
|
||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||
"$layoutConstraints": "flowy,ltr,insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[grow,sizegroup 1,fill][grow,sizegroup 1,fill][grow,sizegroup 1,fill][grow,sizegroup 1,fill][fill]"
|
||||
"$rowConstraints": "[][fill][grow,fill]"
|
||||
} ) {
|
||||
@@ -39,7 +39,7 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets 0,hidemode 3"
|
||||
"$columnConstraints": "[fill][fill][fill]"
|
||||
"$rowConstraints": "[][][][][][][][][][][][]"
|
||||
"$rowConstraints": "[][][][][][][][][][][]unrel[][]unrel[][][]para[][]"
|
||||
} ) {
|
||||
name: "panel1"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
@@ -50,7 +50,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label6"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 0"
|
||||
} )
|
||||
@@ -62,13 +62,13 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label3"
|
||||
"text": "JButon:"
|
||||
"text": "JButton:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "button1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 1"
|
||||
} )
|
||||
@@ -86,7 +86,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JToggleButton" ) {
|
||||
name: "toggleButton1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
"selected": true
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 2"
|
||||
@@ -106,7 +106,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "checkBox1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 3"
|
||||
} )
|
||||
@@ -124,7 +124,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JRadioButton" ) {
|
||||
name: "radioButton1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 4"
|
||||
} )
|
||||
@@ -142,7 +142,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "menu1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 5"
|
||||
} )
|
||||
@@ -160,7 +160,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 6"
|
||||
} )
|
||||
@@ -178,7 +178,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
|
||||
name: "checkBoxMenuItem1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
"selected": true
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 7"
|
||||
@@ -198,7 +198,7 @@ new FormModel {
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
|
||||
name: "radioButtonMenuItem1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
"selected": true
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 8"
|
||||
@@ -216,17 +216,15 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 9"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label15"
|
||||
"text": "(move mouse here)"
|
||||
"toolTipText": "<html>Some <b>Bold</b> Text"
|
||||
add( new FormComponent( "javax.swing.JToolTip" ) {
|
||||
name: "toolTip3"
|
||||
"tipText": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 9"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label16"
|
||||
"text": "(move mouse here)"
|
||||
"toolTipText": "Some text"
|
||||
add( new FormComponent( "javax.swing.JToolTip" ) {
|
||||
name: "toolTip4"
|
||||
"tipText": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 9"
|
||||
} )
|
||||
@@ -239,8 +237,8 @@ new FormModel {
|
||||
add( new FormComponent( "javax.swing.JComboBox" ) {
|
||||
name: "comboBox1"
|
||||
"model": new javax.swing.DefaultComboBoxModel {
|
||||
selectedItem: "<html>Some <b>Bold</b> Text"
|
||||
addElement( "<html>Some <b>Bold</b> Text" )
|
||||
selectedItem: "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
addElement( "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>" )
|
||||
addElement( "abc" )
|
||||
addElement( "def" )
|
||||
}
|
||||
@@ -259,25 +257,110 @@ new FormModel {
|
||||
"value": "cell 2 10"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label18"
|
||||
"text": "JXHyperlink:"
|
||||
name: "label56"
|
||||
"text": "JXBusyLabel:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 11"
|
||||
} )
|
||||
add( new FormComponent( "org.jdesktop.swingx.JXHyperlink" ) {
|
||||
name: "xHyperlink1"
|
||||
"text": "<html>Some <b>Bold</b> Text"
|
||||
add( new FormComponent( "org.jdesktop.swingx.JXBusyLabel" ) {
|
||||
name: "xBusyLabel1"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 11"
|
||||
} )
|
||||
add( new FormComponent( "org.jdesktop.swingx.JXBusyLabel" ) {
|
||||
name: "xBusyLabel2"
|
||||
"text": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 11"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label18"
|
||||
"text": "JXHyperlink:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 12"
|
||||
} )
|
||||
add( new FormComponent( "org.jdesktop.swingx.JXHyperlink" ) {
|
||||
name: "xHyperlink1"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 12"
|
||||
} )
|
||||
add( new FormComponent( "org.jdesktop.swingx.JXHyperlink" ) {
|
||||
name: "xHyperlink2"
|
||||
"text": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 11"
|
||||
"value": "cell 2 12"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label33"
|
||||
"text": "JideLabel:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 13"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideLabel" ) {
|
||||
name: "jideLabel1"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 13"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideLabel" ) {
|
||||
name: "jideLabel2"
|
||||
"text": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 13"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label16"
|
||||
"text": "JideButton:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 14"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideButton" ) {
|
||||
name: "jideButton1"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 14"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideButton" ) {
|
||||
name: "jideButton2"
|
||||
"text": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 14"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label54"
|
||||
"text": "JideToggleButton:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 15"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideToggleButton" ) {
|
||||
name: "jideToggleButton1"
|
||||
"text": "<html>Some <b>Bold</b> Text <kbd>kbd</kbd>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 15"
|
||||
} )
|
||||
add( new FormComponent( "com.jidesoft.swing.JideToggleButton" ) {
|
||||
name: "jideToggleButton2"
|
||||
"text": "Some text"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 15"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "changeHtmlTextButton"
|
||||
"text": "Change HTML Text"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeHtmlText", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 16"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label15"
|
||||
"text": "(use to check whether CSS is updated on text changes)"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 17 3 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 0 1 2,aligny top,growy 0"
|
||||
"value": "cell 4 0 1 3,aligny top,growy 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label1"
|
||||
@@ -372,7 +455,7 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets 0,hidemode 3"
|
||||
"$columnConstraints": "[fill]para[fill][fill][fill][fill][fill][fill]"
|
||||
"$rowConstraints": "[][][][][][]para[]para[][][]"
|
||||
"$rowConstraints": "[][][][][][]"
|
||||
} ) {
|
||||
name: "panel2"
|
||||
auxiliary() {
|
||||
@@ -582,30 +665,12 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 5"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label54"
|
||||
"text": "Test whether inserted rule affects display:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 7 7 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label56"
|
||||
"text": "<html><head><style>body { color: red }</style></head>leading <big>red</big> trailing</html>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 8 7 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label57"
|
||||
"text": "<html><style>body { color: red }</style><p>leading <big>red</big> trailing</p></html>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 9 7 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 2"
|
||||
"value": "cell 4 0 1 3"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 905, 815 )
|
||||
"size": new java.awt.Dimension( 905, 880 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.*;
|
||||
import java.util.function.Supplier;
|
||||
import javax.swing.*;
|
||||
@@ -49,6 +50,7 @@ public class FlatMenusTest
|
||||
initComponents();
|
||||
|
||||
largerCheckBox.setSelected( LargerMenuItem.useLargerSize );
|
||||
verticalMenuBar.setLayout( new GridLayout( 0, 1 ) );
|
||||
}
|
||||
|
||||
private void armedChanged() {
|
||||
@@ -246,7 +248,15 @@ public class FlatMenusTest
|
||||
JLabel popupMenuLabel = new JLabel();
|
||||
JButton showPopupMenuButton = new JButton();
|
||||
showScrollingPopupMenuButton = new JButton();
|
||||
JLabel label1 = new JLabel();
|
||||
armedCheckBox = new JCheckBox();
|
||||
verticalMenuBar = new JMenuBar();
|
||||
JMenu menu14 = new JMenu();
|
||||
JMenuItem menuItem53 = new JMenuItem();
|
||||
JMenu menu15 = new JMenu();
|
||||
JMenuItem menuItem54 = new JMenuItem();
|
||||
JMenu menu16 = new JMenu();
|
||||
JMenuItem menuItem55 = new JMenuItem();
|
||||
underlineCheckBox = new JCheckBox();
|
||||
popupMenubackgroundCheckBox = new JCheckBox();
|
||||
|
||||
@@ -884,6 +894,10 @@ public class FlatMenusTest
|
||||
showScrollingPopupMenuButton.addActionListener(e -> showScrollingPopupMenu(e));
|
||||
add(showScrollingPopupMenuButton, "cell 2 2");
|
||||
|
||||
//---- label1 ----
|
||||
label1.setText("Vertical JMenuBar:");
|
||||
add(label1, "cell 4 2");
|
||||
|
||||
//---- armedCheckBox ----
|
||||
armedCheckBox.setText("armed");
|
||||
armedCheckBox.setMnemonic('A');
|
||||
@@ -891,6 +905,42 @@ public class FlatMenusTest
|
||||
armedCheckBox.addActionListener(e -> armedChanged());
|
||||
add(armedCheckBox, "cell 0 3");
|
||||
|
||||
//======== verticalMenuBar ========
|
||||
{
|
||||
|
||||
//======== menu14 ========
|
||||
{
|
||||
menu14.setText("menu");
|
||||
|
||||
//---- menuItem53 ----
|
||||
menuItem53.setText("text");
|
||||
menu14.add(menuItem53);
|
||||
}
|
||||
verticalMenuBar.add(menu14);
|
||||
|
||||
//======== menu15 ========
|
||||
{
|
||||
menu15.setText("another menu");
|
||||
|
||||
//---- menuItem54 ----
|
||||
menuItem54.setText("text");
|
||||
menu15.add(menuItem54);
|
||||
}
|
||||
verticalMenuBar.add(menu15);
|
||||
|
||||
//======== menu16 ========
|
||||
{
|
||||
menu16.setText("menu 3");
|
||||
menu16.setIcon(new ImageIcon(getClass().getResource("/com/formdev/flatlaf/testing/test16.png")));
|
||||
|
||||
//---- menuItem55 ----
|
||||
menuItem55.setText("text");
|
||||
menu16.add(menuItem55);
|
||||
}
|
||||
verticalMenuBar.add(menu16);
|
||||
}
|
||||
add(verticalMenuBar, "cell 4 3 1 3");
|
||||
|
||||
//---- underlineCheckBox ----
|
||||
underlineCheckBox.setText("underline menu selection");
|
||||
underlineCheckBox.putClientProperty("FlatLaf.internal.testing.ignore", true);
|
||||
@@ -931,6 +981,7 @@ public class FlatMenusTest
|
||||
private JCheckBox accelCheckBox;
|
||||
private JButton showScrollingPopupMenuButton;
|
||||
private JCheckBox armedCheckBox;
|
||||
private JMenuBar verticalMenuBar;
|
||||
private JCheckBox underlineCheckBox;
|
||||
private JCheckBox popupMenubackgroundCheckBox;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "16" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -662,6 +662,12 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label1"
|
||||
"text": "Vertical JMenuBar:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "armedCheckBox"
|
||||
"text": "armed"
|
||||
@@ -674,6 +680,39 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
|
||||
name: "verticalMenuBar"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "menu14"
|
||||
"text": "menu"
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem53"
|
||||
"text": "text"
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "menu15"
|
||||
"text": "another menu"
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem54"
|
||||
"text": "text"
|
||||
} )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||
name: "menu16"
|
||||
"text": "menu 3"
|
||||
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/testing/test16.png" )
|
||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||
name: "menuItem55"
|
||||
"text": "text"
|
||||
} )
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 3 1 3"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "underlineCheckBox"
|
||||
"text": "underline menu selection"
|
||||
|
||||
@@ -36,6 +36,8 @@ import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.extras.FlatInspector;
|
||||
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
|
||||
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
|
||||
import com.formdev.flatlaf.themes.FlatMacLightLaf;
|
||||
import com.formdev.flatlaf.ui.FlatLineBorder;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import net.miginfocom.swing.*;
|
||||
@@ -161,6 +163,8 @@ public class FlatNativeWindowBorderTest
|
||||
registerSwitchToLookAndFeel( "F2", FlatDarkLaf.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F3", FlatIntelliJLaf.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F4", FlatDarculaLaf.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F5", FlatMacLightLaf.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F6", FlatMacDarkLaf.class.getName() );
|
||||
|
||||
registerSwitchToLookAndFeel( "F8", FlatTestLaf.class.getName() );
|
||||
|
||||
@@ -170,8 +174,8 @@ public class FlatNativeWindowBorderTest
|
||||
registerSwitchToLookAndFeel( "F9", "com.apple.laf.AquaLookAndFeel" );
|
||||
else if( SystemInfo.isLinux )
|
||||
registerSwitchToLookAndFeel( "F9", "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" );
|
||||
registerSwitchToLookAndFeel( "F12", MetalLookAndFeel.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F11", NimbusLookAndFeel.class.getName() );
|
||||
registerSwitchToLookAndFeel( "F12", MetalLookAndFeel.class.getName() );
|
||||
}
|
||||
|
||||
private void updateInfo() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.demo.ScrollablePanel;
|
||||
import net.miginfocom.swing.*;
|
||||
|
||||
@@ -63,6 +64,15 @@ public class FlatOptionPaneTest
|
||||
UIManager.put( "OptionPane.showIcon", showTitleBarIconCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void showWithCustomIcon() {
|
||||
JOptionPane optionPane = new JOptionPane( "Hello world." );
|
||||
JDialog dialog = optionPane.createDialog( "With Custom Icon" );
|
||||
dialog.getRootPane().putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, true );
|
||||
dialog.setIconImage( new ImageIcon( FlatOptionPaneTest.class.getResource( "/com/formdev/flatlaf/testing/test32.png" ) ).getImage() );
|
||||
dialog.setVisible( true );
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
ScrollablePanel panel9 = new ScrollablePanel();
|
||||
@@ -75,6 +85,7 @@ public class FlatOptionPaneTest
|
||||
JPanel panel2 = new JPanel();
|
||||
JOptionPane errorOptionPane = new JOptionPane();
|
||||
errorShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel();
|
||||
JButton showWithCustomIconButton = new JButton();
|
||||
JLabel informationLabel = new JLabel();
|
||||
JPanel panel3 = new JPanel();
|
||||
JOptionPane informationOptionPane = new JOptionPane();
|
||||
@@ -173,6 +184,11 @@ public class FlatOptionPaneTest
|
||||
errorShowDialogLabel.setOptionPane(errorOptionPane);
|
||||
panel9.add(errorShowDialogLabel, "cell 1 1");
|
||||
|
||||
//---- showWithCustomIconButton ----
|
||||
showWithCustomIconButton.setText("Show with custom icon");
|
||||
showWithCustomIconButton.addActionListener(e -> showWithCustomIcon());
|
||||
panel9.add(showWithCustomIconButton, "cell 2 1");
|
||||
|
||||
//---- informationLabel ----
|
||||
informationLabel.setText("Information");
|
||||
panel9.add(informationLabel, "cell 0 2");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -83,6 +83,13 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "showWithCustomIconButton"
|
||||
"text": "Show with custom icon"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showWithCustomIcon", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "informationLabel"
|
||||
"text": "Information"
|
||||
|
||||
@@ -40,10 +40,15 @@ public class FlatPaintingHiDPITest
|
||||
|
||||
FlatPaintingHiDPITest() {
|
||||
initComponents();
|
||||
reset();
|
||||
sliderChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
reset();
|
||||
}
|
||||
|
||||
private void sliderChanged() {
|
||||
painter.originX = originXSlider.getValue();
|
||||
painter.originY = originYSlider.getValue();
|
||||
@@ -212,7 +217,7 @@ public class FlatPaintingHiDPITest
|
||||
scaleXSlider.setPaintTicks(true);
|
||||
scaleXSlider.setMajorTickSpacing(50);
|
||||
scaleXSlider.setSnapToTicks(true);
|
||||
scaleXSlider.setMinorTickSpacing(10);
|
||||
scaleXSlider.setMinorTickSpacing(5);
|
||||
scaleXSlider.setMinimum(-100);
|
||||
scaleXSlider.addChangeListener(e -> sliderChanged());
|
||||
add(scaleXSlider, "cell 1 4");
|
||||
@@ -228,7 +233,7 @@ public class FlatPaintingHiDPITest
|
||||
scaleYSlider.setPaintLabels(true);
|
||||
scaleYSlider.setMajorTickSpacing(50);
|
||||
scaleYSlider.setSnapToTicks(true);
|
||||
scaleYSlider.setMinorTickSpacing(10);
|
||||
scaleYSlider.setMinorTickSpacing(5);
|
||||
scaleYSlider.setMinimum(-100);
|
||||
scaleYSlider.addChangeListener(e -> sliderChanged());
|
||||
add(scaleYSlider, "cell 1 5");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user