Compare commits

...

35 Commits

Author SHA1 Message Date
Karl Tauber
bfbd25012a release 3.4 2024-02-19 23:29:00 +01:00
Karl Tauber
063fff2ab4 gradle: fixed dependency of task ':flatlaf-core:signMavenPublication' (type 'Sign') 2024-02-19 23:28:31 +01:00
Karl Tauber
fbdc8d5b99 Merge branch 'windows-full-window-content' 2024-02-19 22:25:04 +01:00
Karl Tauber
625c0a3321 Tree: detect tree cell editor in FlatUIUtils.isCellEditor() 2024-02-19 22:12:29 +01:00
Karl Tauber
2972300112 Table: select all text in cell editor when starting editing using F2 key; can be disabled using Table.editorSelectAllOnStartEditing (issue 652)
also added missing `Table.paintOutsideAlternateRows`
2024-02-19 22:03:19 +01:00
Karl Tauber
a8e71895ee gradle: use AbstractPublishToMaven instead of PublishToMavenRepository to support publishing to local Maven repo (PublishToMavenLocal) 2024-02-19 18:47:48 +01:00
Karl Tauber
d7a76081e3 FileChooser: extended FlatFileChooserTest to support testing various locales (issue #795) 2024-02-12 12:05:01 +01:00
Karl Tauber
fd925a6718 FileChooser: extended FlatFileChooserTest to support testing all JFileChooser properties (issue #795) 2024-02-10 19:35:53 +01:00
Karl Tauber
4fc890a77c Testing: split FlatChooserTest into FlatFileChooserTest and FlatChooserTest 2024-02-10 14:16:45 +01:00
Karl Tauber
b804463b73 Window decorations:
- fixed updating of client property `FULL_WINDOW_CONTENT_BUTTONS_BOUNDS` when resizing window
- fixed title bar buttons placeholder debug painting
2024-02-06 11:30:11 +01:00
Karl Tauber
8f161b4b5a introduced FlatUIAction 2024-02-05 19:03:29 +01:00
Karl Tauber
c6338169f3 Testing: updated lafs.properties 2024-02-05 14:20:21 +01:00
Karl Tauber
6cea24ed9e GitHub Actions: updated versions of used actions 2024-02-05 11:34:58 +01:00
Karl Tauber
3d8eb9eb66 UIDefaultsKeysDump: exclude unused UI properties 2024-02-05 11:33:25 +01:00
Karl Tauber
a84aceb1ba Window decorations: improved caption hit testing to better support TabbedPane, SplitPane and ToolBar in title bar area (e.g. for fullWindowContent mode) 2024-02-04 16:30:38 +01:00
Karl Tauber
8adb7e3021 Native libraries: support Gradle cache when running in development environment (issue #800) 2024-02-02 19:02:56 +01:00
Karl Tauber
bc0d5dc9b5 Native libraries: publish flatlaf-<version>-no-natives.jar to Maven Central; this JAR is equal to flatlaf-<version>.jar, except that it does not contain the FlatLaf native libraries (issue #800) 2024-02-02 17:51:06 +01:00
Karl Tauber
1d935d6659 Window decorations: support fullWindowContent mode on Windows and Linux 2024-02-02 10:06:25 +01:00
Karl Tauber
445466acd0 Demo: removed toolbar button listeners used to test PR #779 2024-01-28 12:14:28 +01:00
Karl Tauber
30af74f806 macOS: setting window background (of undecorated window) to translucent color (alpha < 255) did not show the window translucent (issue #705) 2024-01-28 11:57:17 +01:00
Karl Tauber
16ddd100d3 RootPane: undone commits 7b248427f0 and c6d1ed91a7 because it seems to have no effect anymore
- on Windows with FlatLaf window decorations, maybe because of 7f02eb9cf0
- on Windows with standard window decorations, it seems not to work (still shows "white lines" @2.25x on Windows 10; Java 17)
- macOS and Linux do not support fractional scaling and "white lines" shown never be shown on that platforms
2024-01-27 11:19:18 +01:00
Karl Tauber
c946ec170d macOS window buttons spacing:
- uninstall when switching from FlatLaf to another Laf
- install when switching from another Laf to FlatLaf

(for PR #779)
2024-01-27 11:09:16 +01:00
Karl Tauber
ca514dd76e Merge PR #779: macOS: window title bar close/minimize/zoom buttons spacing 2024-01-25 14:06:38 +01:00
Karl Tauber
cf44a5c50b GitHub Actions: publish shapshots of PRs to Sonatype OSSRH 2024-01-25 13:26:31 +01:00
Karl Tauber
91b8c02c7f GitHub Actions: ignore changes to files that are not related to builds (e.g. readmes, etc.) 2024-01-24 19:23:47 +01:00
Karl Tauber
3465fa68b4 macOS window buttons spacing:
- renamed client property `MACOS_WINDOW_BUTTON_STYLE` to `MACOS_WINDOW_BUTTONS_SPACING`
- no longer allow value `true` for that client property
- enable using `MACOS_WINDOW_BUTTONS_SPACING` without `apple.awt.fullWindowContent`
- remove client property `FULL_WINDOW_CONTENT_BUTTONS_BOUNDS` when `apple.awt.fullWindowContent` is set to false or null
- added placeholder options `zeroInFullScreen`, `leftToRight` and `rightToLeft`
- hide close/min/max buttons during the transition from full-screen to non-full-screen to avoid that they "jump" when the nsToolbar is made visible
- fixed: full-screen listeners where added multiple times
- updated macOS native libraries
- added `FlatMacOSTest`
2024-01-22 00:31:40 +01:00
Karl Tauber
28278a75a7 macOS fullWindowContent mode:
- added title bar buttons placeholder
- added client property to root pane that contains title bar buttons bounds
- undone toolbar extensions from commit ea2447dcb7
2024-01-21 19:19:46 +01:00
Karl Tauber
f68a871dd6 macOS window button style: fixed javadoc 2024-01-12 22:49:49 +01:00
Karl Tauber
93d424cfe1 macOS native: added FlatNativeMacLibrary.windowToggleFullScreen() for easier testing 2024-01-12 22:49:49 +01:00
Karl Tauber
a1adde0888 macOS window button style: support NSWindowToolbarStyleUnified (availaible since macOS 11+; standard in macOS Finder, etc) to allow even larger space around close/minimize/zoom buttons 2024-01-12 22:48:31 +01:00
Karl Tauber
13528b49cb macOS large title bar: fixed wrong "main" JToolBar height and left inset after leaving full screen 2024-01-12 22:48:31 +01:00
Karl Tauber
f3be3f2d1c macOS large title bar: added client property FlatClientProperties.MACOS_LARGE_WINDOW_TITLE_BAR (or "FlatLaf.macOS.largeWindowTitleBar") 2024-01-12 22:48:31 +01:00
Karl Tauber
241fe855cc macOS large title bar: hide NSToolbar of window title bar when window becomes full screen 2024-01-12 22:47:33 +01:00
Karl Tauber
ea2447dcb7 macOS large title bar: main JToolBar automatically:
- uses height of macOS window title bar
- adds left insets for close/minimize/zoom buttons (except if full screen, where those buttons are hidden)
2024-01-12 22:47:33 +01:00
Karl Tauber
f40baed65e macOS large title bar: add NSToolbar to NSWindow 2024-01-12 22:45:54 +01:00
67 changed files with 3682 additions and 843 deletions

View File

@@ -9,6 +9,14 @@ on:
- '*'
tags:
- '[0-9]*'
paths-ignore:
- '**.md'
- '.*'
- '**/.settings/**'
- 'flatlaf-core/svg/**'
- 'flatlaf-testing/dumps/**'
- 'flatlaf-testing/misc/**'
- 'images/**'
jobs:
build:
@@ -32,7 +40,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v1
- uses: gradle/wrapper-validation-action@v2
if: matrix.java == '8'
- name: Setup Java ${{ matrix.java }}

View File

@@ -13,6 +13,8 @@ on:
- 'flatlaf-fonts/**'
- '.github/workflows/fonts.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
- '!**.md'
- '!**/.settings/**'
jobs:
Fonts:

View File

@@ -13,6 +13,8 @@ on:
- 'flatlaf-natives/**'
- '.github/workflows/natives.yml'
- 'gradle/wrapper/gradle-wrapper.properties'
- '!**.md'
- '!**/.settings/**'
jobs:
Natives:
@@ -28,7 +30,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v1
- uses: gradle/wrapper-validation-action@v2
- name: Setup Java 11
uses: actions/setup-java@v4

37
.github/workflows/pr-snapshots.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
name: PR Snapshots
on:
pull_request:
paths-ignore:
- '**.md'
- '.*'
- '**/.settings/**'
- 'flatlaf-core/svg/**'
- 'flatlaf-testing/dumps/**'
- 'flatlaf-testing/misc/**'
- 'images/**'
jobs:
snapshot:
runs-on: ubuntu-latest
if: github.repository == 'JFormDesigner/FlatLaf'
steps:
- uses: actions/checkout@v4
- name: Setup Java 11
uses: actions/setup-java@v4
with:
java-version: 11
distribution: temurin # pre-installed on ubuntu-latest
cache: gradle
- name: Publish PR snapshot to oss.sonatype.org
run: >
./gradlew publish -PskipFonts -Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.parallel=false
-Pgithub.event.pull_request.number=${{ github.event.pull_request.number }}
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}

View File

@@ -1,18 +1,35 @@
FlatLaf Change Log
==================
## 3.4-SNAPSHOT
## 3.4
#### New features and improvements
- Native libraries: System property `flatlaf.nativeLibraryPath` now supports
loading native libraries named the same as on Maven central. Improved log
messages for loading fails.
- FlatLaf window decorations (Windows 10/11 and Linux): Support "full window
content" mode, which allows you to extend the content into the window title
bar. (PR #801)
- macOS: Support larger window title bar close/minimize/zoom buttons spacing in
[full window content](https://www.formdev.com/flatlaf/macos/#full_window_content)
mode and introduced "buttons placeholder". (PR #779)
- Native libraries:
- System property `flatlaf.nativeLibraryPath` now supports loading native
libraries named the same as on Maven central.
- Published `flatlaf-<version>-no-natives.jar` to Maven Central. This JAR is
equal to `flatlaf-<version>.jar`, except that it does not contain the
FlatLaf native libraries. The Maven "classifier" to use this JAR is
`no-natives`. You need to distribute the FlatLaf native libraries with your
application.
See https://www.formdev.com/flatlaf/native-libraries/ for more details.
- 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)
#### Fixed bugs
- macOS: Setting window background (of undecorated window) to translucent color
(alpha < 255) did not show the window translucent. (issue #705)
- JIDE CommandMenuBar: Fixed `ClassCastException` when JIDE command bar displays
`JideMenu` in popup. (PR #794)

View File

@@ -18,6 +18,12 @@ import net.ltgt.gradle.errorprone.errorprone
version = property( if( hasProperty( "release" ) ) "flatlaf.releaseVersion" else "flatlaf.developmentVersion" ) as String
// for PR snapshots change version to 'PR-<pr_number>-SNAPSHOT'
val pullRequestNumber = findProperty( "github.event.pull_request.number" )
if( pullRequestNumber != null )
version = "PR-${pullRequestNumber}-SNAPSHOT"
allprojects {
version = rootProject.version

View File

@@ -124,7 +124,7 @@ tasks.withType<Sign>().configureEach {
}
// check whether parallel build is enabled
tasks.withType<PublishToMavenRepository>().configureEach {
tasks.withType<AbstractPublishToMaven>().configureEach {
doFirst {
if( System.getProperty( "org.gradle.parallel" ) == "true" )
throw RuntimeException( "Publishing does not work correctly with enabled parallel build. Disable parallel build with VM option '-Dorg.gradle.parallel=false'." )

View File

@@ -61,6 +61,27 @@ tasks {
archiveBaseName.set( "flatlaf" )
}
register<Zip>( "jarNoNatives" ) {
group = "build"
dependsOn( "jar" )
archiveBaseName.set( "flatlaf" )
archiveClassifier.set( "no-natives" )
archiveExtension.set( "jar" )
destinationDirectory = layout.buildDirectory.dir( "libs" )
from( zipTree( jar.get().archiveFile.get().asFile ) )
exclude( "com/formdev/flatlaf/natives/**" )
}
withType<AbstractPublishToMaven>().configureEach {
dependsOn( "jarNoNatives" )
}
withType<Sign>().configureEach {
dependsOn( "jarNoNatives" )
}
check {
dependsOn( "sigtestCheck" )
}
@@ -127,6 +148,8 @@ flatlafPublish {
val natives = "src/main/resources/com/formdev/flatlaf/natives"
nativeArtifacts = listOf(
NativeArtifact( tasks.getByName( "jarNoNatives" ).outputs.files.asPath, "no-natives", "jar" ),
NativeArtifact( "${natives}/flatlaf-windows-x86.dll", "windows-x86", "dll" ),
NativeArtifact( "${natives}/flatlaf-windows-x86_64.dll", "windows-x86_64", "dll" ),
NativeArtifact( "${natives}/flatlaf-windows-arm64.dll", "windows-arm64", "dll" ),

View File

@@ -1,5 +1,5 @@
#Signature file v4.1
#Version 3.3
#Version 3.4
CLSS public abstract interface com.formdev.flatlaf.FlatClientProperties
fld public final static java.lang.String BUTTON_TYPE = "JButton.buttonType"
@@ -12,7 +12,13 @@ fld public final static java.lang.String BUTTON_TYPE_TOOLBAR_BUTTON = "toolBarBu
fld public final static java.lang.String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"
fld public final static java.lang.String COMPONENT_ROUND_RECT = "JComponent.roundRect"
fld public final static java.lang.String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"
fld public final static java.lang.String FULL_WINDOW_CONTENT = "FlatLaf.fullWindowContent"
fld public final static java.lang.String FULL_WINDOW_CONTENT_BUTTONS_BOUNDS = "FlatLaf.fullWindowContent.buttonsBounds"
fld public final static java.lang.String FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER = "FlatLaf.fullWindowContent.buttonsPlaceholder"
fld public final static java.lang.String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight"
fld public final static java.lang.String MACOS_WINDOW_BUTTONS_SPACING = "FlatLaf.macOS.windowButtonsSpacing"
fld public final static java.lang.String MACOS_WINDOW_BUTTONS_SPACING_LARGE = "large"
fld public final static java.lang.String MACOS_WINDOW_BUTTONS_SPACING_MEDIUM = "medium"
fld public final static java.lang.String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"
fld public final static java.lang.String MINIMUM_HEIGHT = "JComponent.minimumHeight"
fld public final static java.lang.String MINIMUM_WIDTH = "JComponent.minimumWidth"

View File

@@ -257,19 +257,116 @@ public interface FlatClientProperties
String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner";
/**
* Specifies whether a component in an embedded menu bar should behave as caption
* Specifies whether a component shown in a window title bar area should behave as caption
* (left-click allows moving window, right-click shows window system menu).
* The component does not receive mouse pressed/released/clicked/dragged events,
* The caption component does not receive mouse pressed/released/clicked/dragged events,
* but it gets mouse entered/exited/moved events.
* <p>
* Since 3.4, this client property also supports using a function that can check
* whether a given location in the component should behave as caption.
* Useful for components that do not use mouse input on whole component bounds.
*
* <pre>{@code
* myComponent.putClientProperty( "JComponent.titleBarCaption",
* (Function<Point, Boolean>) pt -> {
* // parameter pt contains mouse location (in myComponent coordinates)
* // return true if the component is not interested in mouse input at the given location
* // return false if the component wants process mouse input at the given location
* // return null if the component children should be checked
* return ...; // check here
* } );
* }</pre>
* <b>Warning</b>:
* <ul>
* <li>This function is invoked often when mouse is moved over window title bar area
* and should therefore return quickly.
* <li>This function 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>
* <p>
* <strong>Component</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
* <strong>Value type</strong> {@link java.lang.Boolean} or {@link java.util.function.Function}&lt;Point, Boolean&gt;
*
* @since 2.5
*/
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
//---- Panel --------------------------------------------------------------
/**
* Marks the panel as placeholder for the iconfify/maximize/close buttons
* in fullWindowContent mode. See {@link #FULL_WINDOW_CONTENT}.
* <p>
* If fullWindowContent mode is enabled, the preferred size of the panel is equal
* to the size of the iconfify/maximize/close buttons. Otherwise is is {@code 0,0}.
* <p>
* You're responsible to layout that panel at the top-left or top-right corner,
* depending on platform, where the iconfify/maximize/close buttons are located.
* <p>
* Syntax of the value string is: {@code "win|mac [horizontal|vertical] [zeroInFullScreen] [leftToRight|rightToLeft]"}.
* <p>
* The string must start with {@code "win"} (for Windows or Linux) or
* with {@code "mac"} (for macOS) and specifies the platform where the placeholder
* should be used. On macOS, you need the placeholder in the top-left corner,
* but on Windows/Linux you need it in the top-right corner. So if your application supports
* fullWindowContent mode on both platforms, you can add two placeholders to your layout
* and FlatLaf automatically uses only one of them. The other gets size {@code 0,0}.
* <p>
* Optionally, you can append following options to the value string (separated by space characters):
* <ul>
* <li>{@code "horizontal"} - preferred height is zero
* <li>{@code "vertical"} - preferred width is zero
* <li>{@code "zeroInFullScreen"} - in full-screen mode on macOS, preferred size is {@code 0,0}
* <li>{@code "leftToRight"} - in right-to-left component orientation, preferred size is {@code 0,0}
* <li>{@code "rightToLeft"} - in left-to-right component orientation, preferred size is {@code 0,0}
* </ul>
*
* Example for adding placeholder to top-left corner on macOS:
* <pre>{@code
* JPanel placeholder = new JPanel();
* placeholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac" );
*
* JToolBar toolBar = new JToolBar();
* // add tool bar items
*
* JPanel toolBarPanel = new JPanel( new BorderLayout() );
* toolBarPanel.add( placeholder, BorderLayout.WEST );
* toolBarPanel.add( toolBar, BorderLayout.CENTER );
*
* frame.getContentPane().add( toolBarPanel, BorderLayout.NORTH );
* }</pre>
*
* Or add placeholder as first item to the tool bar:
* <pre>{@code
* JPanel placeholder = new JPanel();
* placeholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac" );
*
* JToolBar toolBar = new JToolBar();
* toolBar.add( placeholder );
* // add tool bar items
*
* frame.getContentPane().add( toolBar, BorderLayout.NORTH );
* }</pre>
*
* If a tabbed pane is located at the top, you can add the placeholder
* as leading component to that tabbed pane:
* <pre>{@code
* JPanel placeholder = new JPanel();
* placeholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac" );
*
* tabbedPane.putClientProperty( FlatClientProperties.TABBED_PANE_LEADING_COMPONENT, placeholder );
* }</pre>
* <p>
* <strong>Component</strong> {@link javax.swing.JPanel}<br>
* <strong>Value type</strong> {@link java.lang.String}
*
* @since 3.4
*/
String FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER = "FlatLaf.fullWindowContent.buttonsPlaceholder";
//---- Popup --------------------------------------------------------------
/**
@@ -388,6 +485,46 @@ public interface FlatClientProperties
*/
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/**
* Specifies whether the content pane (and the glass pane) should be extended
* into the window title bar area
* (requires enabled window decorations). Default is {@code false}.
* <p>
* On macOS, use client property {@code apple.awt.fullWindowContent}
* (see <a href="https://www.formdev.com/flatlaf/macos/#full_window_content">macOS Full window content</a>).
* <p>
* Setting this enables/disables full window content
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* If {@code true}, the content pane (and the glass pane) is extended into
* the title bar area. The window icon and title are hidden.
* Only the iconfify/maximize/close buttons stay visible in the upper right corner
* (and overlap the content pane).
* <p>
* 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>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3.4
*/
String FULL_WINDOW_CONTENT = "FlatLaf.fullWindowContent";
/**
* Contains the current bounds of the iconfify/maximize/close buttons
* (in root pane coordinates) if fullWindowContent mode is enabled.
* Otherwise its value is {@code null}.
* <p>
* <b>Note</b>: Do not set this client property. It is set by FlatLaf.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Rectangle}
*
* @since 3.4
*/
String FULL_WINDOW_CONTENT_BUTTONS_BOUNDS = "FlatLaf.fullWindowContent.buttonsBounds";
/**
* Specifies whether the window icon should be shown in the window title bar
* (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}.
@@ -1263,6 +1400,44 @@ public interface FlatClientProperties
String TREE_PAINT_SELECTION = "JTree.paintSelection";
//---- macOS --------------------------------------------------------------
/**
* Specifies the spacing around the macOS window close/minimize/zoom buttons.
* Useful if <a href="https://www.formdev.com/flatlaf/macos/#full_window_content">full window content</a>
* is enabled.
* <p>
* (requires macOS 10.14+ for "medium" spacing and macOS 11+ for "large" spacing, requires Java 17+)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.String}<br>
* <strong>Allowed Values</strong>
* {@link #MACOS_WINDOW_BUTTONS_SPACING_MEDIUM} or
* {@link #MACOS_WINDOW_BUTTONS_SPACING_LARGE} (requires macOS 11+)
*
* @since 3.4
*/
String MACOS_WINDOW_BUTTONS_SPACING = "FlatLaf.macOS.windowButtonsSpacing";
/**
* Add medium spacing around the macOS window close/minimize/zoom buttons.
*
* @see #MACOS_WINDOW_BUTTONS_SPACING
* @since 3.4
*/
String MACOS_WINDOW_BUTTONS_SPACING_MEDIUM = "medium";
/**
* Add large spacing around the macOS window close/minimize/zoom buttons.
* <p>
* (requires macOS 11+; "medium" is used on older systems)
*
* @see #MACOS_WINDOW_BUTTONS_SPACING
* @since 3.4
*/
String MACOS_WINDOW_BUTTONS_SPACING_LARGE = "large";
//---- helper methods -----------------------------------------------------
/**

View File

@@ -429,7 +429,7 @@ public class FlatFileChooserUI
iconFunction = (Function<File, Icon>) UIManager.get( "FileChooser.shortcuts.iconFunction" );
FileSystemView fsv = fc.getFileSystemView();
File[] files = getChooserShortcutPanelFiles( fsv );
File[] files = JavaCompatibility2.getChooserShortcutPanelFiles( fsv );
if( filesFunction != null )
files = filesFunction.apply( files );
@@ -498,32 +498,6 @@ public class FlatFileChooserUI
return button;
}
protected File[] getChooserShortcutPanelFiles( FileSystemView fsv ) {
try {
if( SystemInfo.isJava_12_orLater ) {
Method m = fsv.getClass().getMethod( "getChooserShortcutPanelFiles" );
File[] files = (File[]) m.invoke( fsv );
// on macOS and Linux, files consists only of the user home directory
if( files.length == 1 && files[0].equals( new File( System.getProperty( "user.home" ) ) ) )
files = new File[0];
return files;
} else if( SystemInfo.isWindows ) {
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
Method m = cls.getMethod( "get", String.class );
return (File[]) m.invoke( null, "fileChooserShortcutPanelFolders" );
}
} catch( IllegalAccessException ex ) {
// do not log because access may be denied via VM option '--illegal-access=deny'
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
// fallback
return new File[0];
}
protected String getDisplayName( FileSystemView fsv, File file ) {
if( displayNameFunction != null ) {
String name = displayNameFunction.apply( file );

View File

@@ -27,7 +27,6 @@ import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
@@ -39,7 +38,6 @@ import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI;
@@ -144,12 +142,10 @@ public class FlatMenuBarUI
protected void installKeyboardActions() {
super.installKeyboardActions();
// get shared action map, used for all menu bars
ActionMap map = SwingUtilities.getUIActionMap( menuBar );
if( map == null ) {
map = new ActionMapUIResource();
SwingUtilities.replaceUIActionMap( menuBar, map );
}
map.put( "takeFocus", new TakeFocus() );
if( map != null && !(map.get( "takeFocus" ) instanceof TakeFocusAction) )
map.put( "takeFocus", new TakeFocusAction( "takeFocus" ) );
}
/** @since 2 */
@@ -365,16 +361,20 @@ public class FlatMenuBarUI
}
}
//---- class TakeFocus ----------------------------------------------------
//---- class TakeFocusAction ----------------------------------------------
/**
* Activates the menu bar and shows mnemonics.
* On Windows, the popup of the first menu is not shown.
* On other platforms, the popup of the first menu is shown.
*/
private static class TakeFocus
extends AbstractAction
private static class TakeFocusAction
extends FlatUIAction
{
TakeFocusAction( String name ) {
super( name );
}
@Override
public void actionPerformed( ActionEvent e ) {
JMenuBar menuBar = (JMenuBar) e.getSource();

View File

@@ -22,6 +22,7 @@ import java.security.CodeSource;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.NativeLibrary;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
@@ -177,21 +178,39 @@ class FlatNativeLibrary
// build library file
String libraryName = buildLibraryName( jarFile, classifier, ext );
File parent = jarFile.getParentFile();
File jarDir = jarFile.getParentFile();
// check whether native library exists in same directory as jar
File libraryFile = new File( parent, libraryName );
File libraryFile = new File( jarDir, libraryName );
if( libraryFile.isFile() )
return libraryFile;
// if jar is in "lib" directory, then also check whether native library exists
// in "../bin" directory
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
if( jarDir.getName().equalsIgnoreCase( "lib" ) ) {
libraryFile = new File( jarDir.getParentFile(), "bin/" + libraryName );
if( libraryFile.isFile() )
return libraryFile;
}
// special case: support Gradle cache when running in development environment
// <user-home>/.gradle/caches/modules-2/files-2.1/com.formdev/flatlaf/<version>/<hash-1>/flatlaf-<version>.jar
// <user-home>/.gradle/caches/modules-2/files-2.1/com.formdev/flatlaf/<version>/<hash-2>/flatlaf-<version>-windows-x86_64.dll
String path = jarDir.getAbsolutePath().replace( '\\', '/' );
if( path.contains( "/.gradle/caches/" ) ) {
File versionDir = jarDir.getParentFile();
if( libraryName.contains( versionDir.getName() ) ) {
File[] dirs = versionDir.listFiles();
if( dirs != null ) {
for( File dir : dirs ) {
libraryFile = new File( dir, libraryName );
if( libraryFile.isFile() )
return libraryFile;
}
}
}
}
// native library not found
return null;
}
@@ -224,6 +243,10 @@ class FlatNativeLibrary
private static String buildLibraryName( File jarFile, String classifier, String ext ) {
String jarName = jarFile.getName();
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
// remove classifier "no-natives" (if used)
jarBasename = StringUtils.removeTrailing( jarBasename, "-no-natives" );
return jarBasename
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
+ '-' + classifier + '.' + ext;

View File

@@ -16,7 +16,9 @@
package com.formdev.flatlaf.ui;
import java.awt.Rectangle;
import java.awt.Window;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Native methods for macOS.
@@ -49,8 +51,19 @@ public class FlatNativeMacLibrary
* method of this class. Otherwise, the native library may not be loaded.
*/
public static boolean isLoaded() {
return FlatNativeLibrary.isLoaded();
return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded();
}
public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor );
/** @since 3.4 */
public static final int
BUTTONS_SPACING_DEFAULT = 0,
BUTTONS_SPACING_MEDIUM = 1,
BUTTONS_SPACING_LARGE = 2;
/** @since 3.4 */ public native static boolean setWindowButtonsSpacing( Window window, int buttonsSpacing );
/** @since 3.4 */ public native static Rectangle getWindowButtonsBounds( Window window );
/** @since 3.4 */ public native static boolean isWindowFullScreen( Window window );
/** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window );
}

View File

@@ -21,11 +21,12 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.function.Predicate;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JRootPane;
@@ -218,13 +219,13 @@ public class FlatNativeWindowBorder
}
static void setTitleBarHeightAndHitTestSpots( Window window, int titleBarHeight,
List<Rectangle> hitTestSpots, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
Predicate<Point> captionHitTestCallback, Rectangle appIconBounds, Rectangle minimizeButtonBounds,
Rectangle maximizeButtonBounds, Rectangle closeButtonBounds )
{
if( !isSupported() )
return;
nativeProvider.updateTitleBarInfo( window, titleBarHeight, hitTestSpots,
nativeProvider.updateTitleBarInfo( window, titleBarHeight, captionHitTestCallback,
appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
}
@@ -270,7 +271,7 @@ public class FlatNativeWindowBorder
{
boolean hasCustomDecoration( Window window );
void setHasCustomDecoration( Window window, boolean hasCustomDecoration );
void updateTitleBarInfo( Window window, int titleBarHeight, List<Rectangle> hitTestSpots,
void updateTitleBarInfo( Window window, int titleBarHeight, Predicate<Point> captionHitTestCallback,
Rectangle appIconBounds, Rectangle minimizeButtonBounds, Rectangle maximizeButtonBounds,
Rectangle closeButtonBounds );

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
@@ -23,6 +24,7 @@ import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPanelUI;
import com.formdev.flatlaf.FlatClientProperties;
@@ -69,6 +71,8 @@ public class FlatPanelUI
super.installUI( c );
c.addPropertyChangeListener( this );
if( c.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER ) != null )
FullWindowContentSupport.registerPlaceholder( c );
installStyle( (JPanel) c );
}
@@ -78,10 +82,20 @@ public class FlatPanelUI
super.uninstallUI( c );
c.removePropertyChangeListener( this );
if( c.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER ) != null )
FullWindowContentSupport.unregisterPlaceholder( c );
oldStyleValues = null;
}
@Override
protected void installDefaults( JPanel p ) {
super.installDefaults( p );
if( p.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER ) != null )
LookAndFeel.installProperty( p, "opaque", false );
}
/** @since 2.0.1 */
@Override
public void propertyChange( PropertyChangeEvent e ) {
@@ -98,6 +112,17 @@ public class FlatPanelUI
c.revalidate();
c.repaint();
break;
case FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER:
JPanel p = (JPanel) e.getSource();
if( e.getOldValue() != null )
FullWindowContentSupport.unregisterPlaceholder( p );
if( e.getNewValue() != null )
FullWindowContentSupport.registerPlaceholder( p );
// make panel non-opaque for placeholders
LookAndFeel.installProperty( p, "opaque", e.getNewValue() == null );
break;
}
}
@@ -162,4 +187,19 @@ public class FlatPanelUI
paint( g, c );
}
@Override
public Dimension getPreferredSize( JComponent c ) {
Object value = c.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER );
if( value != null )
return FullWindowContentSupport.getPlaceholderPreferredSize( c, (String) value );
return super.getPreferredSize( c );
}
@Override
public void paint( Graphics g, JComponent c ) {
if( c.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER ) != null )
FullWindowContentSupport.debugPaint( g, c );
}
}

View File

@@ -28,8 +28,6 @@ import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -41,7 +39,6 @@ import javax.swing.JLayeredPane;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.BorderUIResource;
@@ -50,6 +47,7 @@ import javax.swing.plaf.RootPaneUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRootPaneUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
@@ -87,8 +85,8 @@ public class FlatRootPaneUI
private Object nativeWindowBorderData;
private LayoutManager oldLayout;
private PropertyChangeListener ancestorListener;
private ComponentListener componentListener;
private ComponentListener macFullWindowContentListener;
private PropertyChangeListener macWindowBackgroundListener;
public static ComponentUI createUI( JComponent c ) {
return new FlatRootPaneUI();
@@ -106,6 +104,7 @@ public class FlatRootPaneUI
installBorder();
installNativeWindowBorder();
macInstallFullWindowContentSupport();
}
protected void installBorder() {
@@ -122,6 +121,7 @@ public class FlatRootPaneUI
uninstallNativeWindowBorder();
uninstallClientDecorations();
macUninstallFullWindowContentSupport();
rootPane = null;
}
@@ -155,6 +155,8 @@ public class FlatRootPaneUI
if( background == null || background instanceof UIResource )
parent.setBackground( UIManager.getColor( "control" ) );
}
macClearBackgroundForTranslucentWindow( c );
}
@Override
@@ -174,55 +176,20 @@ public class FlatRootPaneUI
protected void installListeners( JRootPane root ) {
super.installListeners( root );
if( SystemInfo.isJava_9_orLater ) {
// On HiDPI screens, where scaling is used, there may be white lines on the
// bottom and on the right side of the window when it is initially shown.
// This is very disturbing in dark themes, but hard to notice in light themes.
// Seems to be a rounding issue when Swing adds dirty region of window
// using RepaintManager.nativeAddDirtyRegion().
//
// Note: Not using a HierarchyListener here, which would be much easier,
// because this causes problems with mouse clicks in heavy-weight popups.
// Instead, add a listener to the root pane that waits until it is added
// to a window, then add a component listener to the window.
// See: https://github.com/JFormDesigner/FlatLaf/issues/371
ancestorListener = e -> {
Object oldValue = e.getOldValue();
Object newValue = e.getNewValue();
if( newValue instanceof Window ) {
if( componentListener == null ) {
componentListener = new ComponentAdapter() {
@Override
public void componentShown( ComponentEvent e ) {
// add whole root pane to dirty regions when window is initially shown
root.getParent().repaint( root.getX(), root.getY(), root.getWidth(), root.getHeight() );
}
};
}
((Window)newValue).addComponentListener( componentListener );
} else if( newValue == null && oldValue instanceof Window ) {
if( componentListener != null )
((Window)oldValue).removeComponentListener( componentListener );
}
};
root.addPropertyChangeListener( "ancestor", ancestorListener );
}
if( SystemInfo.isMacFullWindowContentSupported )
macFullWindowContentListener = FullWindowContentSupport.macInstallListeners( root );
macInstallWindowBackgroundListener( root );
}
@Override
protected void uninstallListeners( JRootPane root ) {
super.uninstallListeners( root );
if( SystemInfo.isJava_9_orLater ) {
if( componentListener != null ) {
Window window = SwingUtilities.windowForComponent( root );
if( window != null )
window.removeComponentListener( componentListener );
componentListener = null;
}
root.removePropertyChangeListener( "ancestor", ancestorListener );
ancestorListener = null;
if( SystemInfo.isMacFullWindowContentSupported ) {
FullWindowContentSupport.macUninstallListeners( root, macFullWindowContentListener );
macFullWindowContentListener = null;
}
macUninstallWindowBackgroundListener( root );
}
/** @since 1.1.2 */
@@ -302,19 +269,136 @@ public class FlatRootPaneUI
// layer title pane under frame content layer to allow placing menu bar over title pane
protected final static Integer TITLE_PANE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 1;
private final static Integer TITLE_PANE_MOUSE_LAYER = JLayeredPane.FRAME_CONTENT_LAYER - 2;
// for fullWindowContent mode, layer title pane over frame content layer to allow placing title bar buttons over content
/** @since 3.4 */
protected final static Integer TITLE_PANE_FULL_WINDOW_CONTENT_LAYER = JLayeredPane.FRAME_CONTENT_LAYER + 1;
private Integer getLayerForTitlePane() {
return isFullWindowContent( rootPane ) ? TITLE_PANE_FULL_WINDOW_CONTENT_LAYER : TITLE_PANE_LAYER;
}
protected void setTitlePane( FlatTitlePane newTitlePane ) {
JLayeredPane layeredPane = rootPane.getLayeredPane();
if( titlePane != null )
if( titlePane != null ) {
layeredPane.remove( titlePane );
layeredPane.remove( titlePane.mouseLayer );
}
if( newTitlePane != null )
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
if( newTitlePane != null ) {
layeredPane.add( newTitlePane, getLayerForTitlePane() );
layeredPane.add( newTitlePane.mouseLayer, TITLE_PANE_MOUSE_LAYER );
}
titlePane = newTitlePane;
}
private void macInstallFullWindowContentSupport() {
if( !SystemInfo.isMacOS )
return;
// set window buttons spacing
if( isMacButtonsSpacingSupported() && rootPane.isDisplayable() ) {
int buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_DEFAULT;
String value = (String) rootPane.getClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING );
if( value != null ) {
switch( value ) {
case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM:
buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_MEDIUM;
break;
case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE:
buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_LARGE;
break;
}
}
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow( rootPane ), buttonsSpacing );
}
// update buttons bounds client property
FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane );
}
private void macUninstallFullWindowContentSupport() {
if( !SystemInfo.isMacOS )
return;
// do not uninstall when switching to another FlatLaf theme
if( UIManager.getLookAndFeel() instanceof FlatLaf )
return;
// reset window buttons spacing
if( isMacButtonsSpacingSupported() )
FlatNativeMacLibrary.setWindowButtonsSpacing( getParentWindow( rootPane ), FlatNativeMacLibrary.BUTTONS_SPACING_DEFAULT );
// remove buttons bounds client property
FullWindowContentSupport.macUninstallFullWindowContentButtonsBoundsProperty( rootPane );
}
private boolean isMacButtonsSpacingSupported() {
return SystemInfo.isMacOS && SystemInfo.isJava_17_orLater && FlatNativeMacLibrary.isLoaded();
}
private void macInstallWindowBackgroundListener( JRootPane c ) {
if( !SystemInfo.isMacOS )
return;
Window window = getParentWindow( c );
if( window != null && macWindowBackgroundListener == null ) {
macWindowBackgroundListener = e -> macClearBackgroundForTranslucentWindow( c );
window.addPropertyChangeListener( "background", macWindowBackgroundListener );
}
}
private void macUninstallWindowBackgroundListener( JRootPane c ) {
if( !SystemInfo.isMacOS )
return;
Window window = getParentWindow( c );
if( window != null && macWindowBackgroundListener != null ) {
window.removePropertyChangeListener( "background", macWindowBackgroundListener );
macWindowBackgroundListener = null;
}
}
/**
* When setting window background to translucent color (alpha < 255),
* Swing paints that window translucent on Windows and Linux, but not on macOS.
* The reason for this is that FlatLaf sets the background color of the root pane,
* and Swing behaves a bit differently on macOS than on other platforms in that case.
* Other L&Fs do not set root pane background, which is {@code null} by default.
* <p>
* To fix this problem, set the root pane background to {@code null}
* if windows uses a translucent background.
*/
private void macClearBackgroundForTranslucentWindow( JRootPane c ) {
if( !SystemInfo.isMacOS )
return;
Window window = getParentWindow( c );
if( window != null ) {
Color windowBackground = window.getBackground();
if( windowBackground != null &&
windowBackground.getAlpha() < 255 &&
c.getBackground() instanceof UIResource )
{
// clear root pane background
c.setBackground( null );
}
}
}
private Window getParentWindow( JRootPane c ) {
// not using SwingUtilities.windowForComponent() or SwingUtilities.getWindowAncestor()
// here because root panes may be nested and used anywhere (e.g. in JInternalFrame)
// but we're only interested in the "root" root pane, which is a direct child of the window
Container parent = c.getParent();
return (parent instanceof Window) ? (Window) parent : null;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
@@ -359,6 +443,21 @@ public class FlatRootPaneUI
titlePane.titleBarColorsChanged();
break;
case FlatClientProperties.FULL_WINDOW_CONTENT:
if( titlePane != null ) {
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
titlePane.updateIcon();
titlePane.updateVisibility();
titlePane.updateFullWindowContentButtonsBoundsProperty();
}
FullWindowContentSupport.revalidatePlaceholders( rootPane );
rootPane.revalidate();
break;
case FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS:
FullWindowContentSupport.revalidatePlaceholders( rootPane );
break;
case FlatClientProperties.GLASS_PANE_FULL_HEIGHT:
rootPane.revalidate();
break;
@@ -367,14 +466,43 @@ public class FlatRootPaneUI
if( rootPane.isDisplayable() )
throw new IllegalComponentStateException( "The client property 'Window.style' must be set before the window becomes displayable." );
break;
case "ancestor":
if( e.getNewValue() instanceof Window )
macClearBackgroundForTranslucentWindow( rootPane );
macUninstallWindowBackgroundListener( rootPane );
macInstallWindowBackgroundListener( rootPane );
// FlatNativeMacLibrary.setWindowButtonsSpacing() and
// FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty()
// require a native window, but setting the client properties
// "apple.awt.fullWindowContent" or FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING
// is usually done before the native window is created
// --> try again when native window is created
if( e.getNewValue() instanceof Window )
macInstallFullWindowContentSupport();
break;
case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING:
macInstallFullWindowContentSupport();
break;
case "apple.awt.fullWindowContent":
if( SystemInfo.isMacFullWindowContentSupported )
FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane );
break;
}
}
/** @since 3.4 */
protected static boolean isFullWindowContent( JRootPane rootPane ) {
return FlatClientProperties.clientPropertyBoolean( rootPane, FlatClientProperties.FULL_WINDOW_CONTENT, false );
}
protected static boolean isMenuBarEmbedded( JRootPane rootPane ) {
RootPaneUI ui = rootPane.getUI();
return ui instanceof FlatRootPaneUI &&
((FlatRootPaneUI)ui).titlePane != null &&
((FlatRootPaneUI)ui).titlePane.isMenuBarEmbedded();
FlatTitlePane titlePane = getTitlePane( rootPane );
return titlePane != null && titlePane.isMenuBarEmbedded();
}
/** @since 2.4 */
@@ -410,23 +538,21 @@ public class FlatRootPaneUI
private Dimension computeLayoutSize( Container parent, Function<Component, Dimension> getSizeFunc ) {
JRootPane rootPane = (JRootPane) parent;
Dimension titlePaneSize = (titlePane != null)
? getSizeFunc.apply( titlePane )
: new Dimension();
Dimension contentSize = (rootPane.getContentPane() != null)
? getSizeFunc.apply( rootPane.getContentPane() )
: rootPane.getSize();
: rootPane.getSize(); // same as in JRootPane.RootLayout.preferredLayoutSize()
int width = contentSize.width; // title pane width is not considered here
int height = titlePaneSize.height + contentSize.height;
int height = contentSize.height;
if( titlePane != null && !isFullWindowContent( rootPane ) )
height += getSizeFunc.apply( titlePane ).height;
if( titlePane == null || !titlePane.isMenuBarEmbedded() ) {
JMenuBar menuBar = rootPane.getJMenuBar();
Dimension menuBarSize = (menuBar != null && menuBar.isVisible())
? getSizeFunc.apply( menuBar )
: new Dimension();
width = Math.max( width, menuBarSize.width );
height += menuBarSize.height;
if( menuBar != null && menuBar.isVisible() ) {
Dimension menuBarSize = getSizeFunc.apply( menuBar );
width = Math.max( width, menuBarSize.width );
height += menuBarSize.height;
}
}
Insets insets = rootPane.getInsets();
@@ -451,12 +577,23 @@ public class FlatRootPaneUI
if( rootPane.getLayeredPane() != null )
rootPane.getLayeredPane().setBounds( x, y, width, height );
// title pane
// title pane (is a child of layered pane)
int nextY = 0;
if( titlePane != null ) {
int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0;
titlePane.setBounds( 0, 0, width, prefHeight );
nextY += prefHeight;
boolean isFullWindowContent = isFullWindowContent( rootPane );
if( isFullWindowContent && !UIManager.getBoolean( FlatTitlePane.KEY_DEBUG_SHOW_RECTANGLES ) ) {
// place title bar into top-right corner
int tw = Math.min( titlePane.getPreferredSize().width, width );
int tx = titlePane.getComponentOrientation().isLeftToRight() ? width - tw : 0;
titlePane.setBounds( tx, 0, tw, prefHeight );
} else
titlePane.setBounds( 0, 0, width, prefHeight );
titlePane.mouseLayer.setBounds( 0, 0, width, prefHeight );
if( !isFullWindowContent )
nextY += prefHeight;
}
// glass pane
@@ -467,7 +604,7 @@ public class FlatRootPaneUI
rootPane.getGlassPane().setBounds( x, y + offset, width, height - offset );
}
// menu bar
// menu bar (is a child of layered pane)
JMenuBar menuBar = rootPane.getJMenuBar();
if( menuBar != null && menuBar.isVisible() ) {
boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded();
@@ -475,13 +612,23 @@ public class FlatRootPaneUI
titlePane.validate();
menuBar.setBounds( titlePane.getMenuBarBounds() );
} else {
int mx = 0;
int mw = width;
if( titlePane != null && isFullWindowContent( rootPane ) ) {
// make menu bar width smaller to avoid that it overlaps title bar buttons
int tw = Math.min( titlePane.getPreferredSize().width, width );
mw -= tw;
if( !titlePane.getComponentOrientation().isLeftToRight() )
mx = tw;
}
Dimension prefSize = menuBar.getPreferredSize();
menuBar.setBounds( 0, nextY, width, prefSize.height );
menuBar.setBounds( mx, nextY, mw, prefSize.height );
nextY += prefSize.height;
}
}
// content pane
// content pane (is a child of layered pane)
Container contentPane = rootPane.getContentPane();
if( contentPane != null )
contentPane.setBounds( 0, nextY, width, Math.max( height - nextY, 0 ) );

View File

@@ -84,7 +84,7 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatSplitPaneUI
extends BasicSplitPaneUI
implements StyleableUI
implements StyleableUI, FlatTitlePane.TitleBarCaptionHitTest
{
@Styleable protected String arrowType;
/** @since 3.3 */ @Styleable protected Color draggingColor;
@@ -227,6 +227,15 @@ public class FlatSplitPaneUI
((FlatSplitPaneDivider)divider).paintStyle( g, x, y, width, height );
}
//---- interface FlatTitlePane.TitleBarCaptionHitTest ----
/** @since 3.4 */
@Override
public Boolean isTitleBarCaptionAt( int x, int y ) {
// necessary because BasicSplitPaneDivider adds some mouse listeners for dragging divider
return null; // check children
}
//---- class FlatSplitPaneDivider -----------------------------------------
protected class FlatSplitPaneDivider

View File

@@ -182,7 +182,7 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatTabbedPaneUI
extends BasicTabbedPaneUI
implements StyleableUI
implements StyleableUI, FlatTitlePane.TitleBarCaptionHitTest
{
// tab type
/** @since 2 */ protected static final int TAB_TYPE_UNDERLINED = 0;
@@ -2300,6 +2300,17 @@ debug*/
return (rects[last].y + rects[last].height) - rects[0].y;
}
//---- interface FlatTitlePane.TitleBarCaptionHitTest ----
/** @since 3.4 */
@Override
public Boolean isTitleBarCaptionAt( int x, int y ) {
if( tabForCoordinate( tabPane, x, y ) >= 0 )
return false;
return null; // check children
}
//---- class TabCloseButton -----------------------------------------------
private static class TabCloseButton
@@ -3985,10 +3996,8 @@ debug*/
//---- class RunWithOriginalLayoutManagerDelegateAction -------------------
private static class RunWithOriginalLayoutManagerDelegateAction
implements Action
extends FlatUIAction
{
private final Action delegate;
static void install( ActionMap map, String key ) {
Action oldAction = map.get( key );
if( oldAction == null || oldAction instanceof RunWithOriginalLayoutManagerDelegateAction )
@@ -3998,24 +4007,9 @@ debug*/
}
private RunWithOriginalLayoutManagerDelegateAction( Action delegate ) {
this.delegate = delegate;
super( delegate );
}
@Override
public Object getValue( String key ) {
return delegate.getValue( key );
}
@Override
public boolean isEnabled() {
return delegate.isEnabled();
}
@Override public void putValue( String key, Object value ) {}
@Override public void setEnabled( boolean b ) {}
@Override public void addPropertyChangeListener( PropertyChangeListener listener ) {}
@Override public void removePropertyChangeListener( PropertyChangeListener listener ) {}
@Override
public void actionPerformed( ActionEvent e ) {
JTabbedPane tabbedPane = (JTabbedPane) e.getSource();

View File

@@ -24,15 +24,19 @@ import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
@@ -89,6 +93,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Table.selectionInactiveBackground Color
* @uiDefault Table.selectionInactiveForeground Color
* @uiDefault Table.paintOutsideAlternateRows boolean
* @uiDefault Table.editorSelectAllOnStartEditing boolean
*
* <!-- FlatTableCellBorder -->
*
@@ -284,6 +289,18 @@ public class FlatTableUI
};
}
@Override
protected void installKeyboardActions() {
super.installKeyboardActions();
if( UIManager.getBoolean( "Table.editorSelectAllOnStartEditing" ) ) {
// get shared action map, used for all tables
ActionMap map = SwingUtilities.getUIActionMap( table );
if( map != null )
StartEditingAction.install( map, "startEditing" );
}
}
/** @since 2 */
protected void installStyle() {
try {
@@ -579,4 +596,36 @@ public class FlatTableUI
selected = (value != null && (Boolean) value);
}
}
//---- class StartEditingAction -------------------------------------------
private static class StartEditingAction
extends FlatUIAction
{
static void install( ActionMap map, String key ) {
Action oldAction = map.get( key );
if( oldAction == null || oldAction instanceof StartEditingAction )
return; // not found or already installed
map.put( key, new StartEditingAction( oldAction ) );
}
private StartEditingAction( Action delegate ) {
super( delegate );
}
@Override
public void actionPerformed( ActionEvent e ) {
JTable table = (JTable) e.getSource();
Component oldEditorComp = table.getEditorComponent();
delegate.actionPerformed( e );
// select all text in editor if editing starts with F2 key
Component editorComp = table.getEditorComponent();
if( oldEditorComp == null && editorComp instanceof JTextField )
((JTextField)editorComp).selectAll();
}
}
}

View File

@@ -36,6 +36,7 @@ import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
@@ -46,9 +47,9 @@ import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import javax.accessibility.AccessibleContext;
import javax.swing.BorderFactory;
import javax.swing.Box;
@@ -57,7 +58,6 @@ import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
@@ -66,6 +66,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder.WindowTopBorder;
@@ -98,7 +99,6 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.showIconBesideTitle boolean
* @uiDefault TitlePane.menuBarTitleGap int
* @uiDefault TitlePane.menuBarTitleMinimumGap int
* @uiDefault TitlePane.menuBarResizeHeight int
* @uiDefault TitlePane.closeIcon Icon
* @uiDefault TitlePane.iconifyIcon Icon
* @uiDefault TitlePane.maximizeIcon Icon
@@ -109,7 +109,7 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatTitlePane
extends JComponent
{
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
/** @since 2.5 */ protected final Font titleFont;
protected final Color activeBackground;
@@ -131,7 +131,6 @@ public class FlatTitlePane
/** @since 2.4 */ protected final boolean showIconBesideTitle;
protected final int menuBarTitleGap;
/** @since 2.4 */ protected final int menuBarTitleMinimumGap;
/** @since 2.4 */ protected final int menuBarResizeHeight;
protected final JRootPane rootPane;
protected final String windowStyle;
@@ -150,6 +149,23 @@ public class FlatTitlePane
private final Handler handler;
/**
* This panel handles mouse events if FlatLaf window decorations are used
* without native window border. E.g. on Linux.
* <p>
* This panel usually has same bounds as the title pane,
* except if fullWindowContent mode is enabled.
* <p>
* This panel is not a child of the title pane.
* Instead it is added by FlatRootPaneUI to the layered pane at a layer
* under the title pane and under the frame content.
* The separation is necessary for fullWindowContent mode, where the title pane
* is layered over the frame content (for title pane buttons), but the mousePanel
* needs to be layered under the frame content so that components on content pane
* can receive mouse events when located in title area.
*/
final JPanel mouseLayer;
public FlatTitlePane( JRootPane rootPane ) {
this.rootPane = rootPane;
@@ -178,7 +194,6 @@ public class FlatTitlePane
showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false );
menuBarTitleGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleGap", windowStyle, 40 );
menuBarTitleMinimumGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleMinimumGap", windowStyle, 12 );
menuBarResizeHeight = FlatUIUtils.getSubUIInt( "TitlePane.menuBarResizeHeight", windowStyle, 4 );
handler = createHandler();
@@ -187,11 +202,10 @@ public class FlatTitlePane
addSubComponents();
activeChanged( true );
addMouseListener( handler );
addMouseMotionListener( handler );
// necessary for closing window with double-click on icon
iconLabel.addMouseListener( handler );
mouseLayer = new JPanel();
mouseLayer.setOpaque( false );
mouseLayer.addMouseListener( handler );
mouseLayer.addMouseMotionListener( handler );
applyComponentOrientation( rootPane.getComponentOrientation() );
}
@@ -234,6 +248,11 @@ public class FlatTitlePane
setLayout( new BorderLayout() {
@Override
public void layoutContainer( Container target ) {
if( isFullWindowContent() ) {
super.layoutContainer( target );
return;
}
// compute available bounds
Insets insets = target.getInsets();
int x = insets.left;
@@ -247,7 +266,7 @@ public class FlatTitlePane
int titleWidth = w - leftWidth - buttonsWidth;
int minTitleWidth = UIScale.scale( titleMinimumWidth );
// increase minimum width if icon is show besides the title
// increase minimum width if icon is shown besides the title
Icon icon = titleLabel.getIcon();
if( icon != null ) {
Insets iconInsets = iconLabel.getInsets();
@@ -295,6 +314,9 @@ public class FlatTitlePane
horizontalGlue.getWidth(), titleLabel.getHeight() );
}
}
// clear hit-test cache
lastCaptionHitTestTime = 0;
}
} );
@@ -338,6 +360,13 @@ public class FlatTitlePane
buttonPanel.add( restoreButton );
}
buttonPanel.add( closeButton );
ComponentListener l = new ComponentAdapter() {
@Override public void componentResized( ComponentEvent e ) { updateFullWindowContentButtonsBoundsProperty(); }
@Override public void componentMoved( ComponentEvent e ) { updateFullWindowContentButtonsBoundsProperty(); }
};
buttonPanel.addComponentListener( l );
addComponentListener( l );
}
protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) {
@@ -417,7 +446,9 @@ public class FlatTitlePane
/** @since 3 */
protected void updateVisibility() {
titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) );
boolean isFullWindowContent = isFullWindowContent();
leftPanel.setVisible( !isFullWindowContent );
titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) && !isFullWindowContent );
closeButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_CLOSE, true ) );
if( window instanceof Frame ) {
@@ -443,7 +474,7 @@ public class FlatTitlePane
// get window images
List<Image> images = null;
if( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICON, defaultShowIcon ) ) {
if( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICON, defaultShowIcon ) && !isFullWindowContent() ) {
images = window.getIconImages();
if( images.isEmpty() ) {
// search in owners
@@ -468,6 +499,13 @@ public class FlatTitlePane
updateNativeTitleBarHeightAndHitTestSpotsLater();
}
void updateFullWindowContentButtonsBoundsProperty() {
Rectangle bounds = isFullWindowContent()
? new Rectangle( SwingUtilities.convertPoint( buttonPanel, 0, 0, rootPane ), buttonPanel.getSize() )
: null;
rootPane.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, bounds );
}
@Override
public void addNotify() {
super.addNotify();
@@ -522,6 +560,11 @@ public class FlatTitlePane
window.removeComponentListener( handler );
}
/** @since 3.4 */
protected boolean isFullWindowContent() {
return FlatRootPaneUI.isFullWindowContent( rootPane );
}
/**
* Returns whether this title pane currently has a visible and embedded menubar.
*/
@@ -533,6 +576,9 @@ public class FlatTitlePane
* Returns whether the menubar should be embedded into the title pane.
*/
protected boolean isMenuBarEmbedded() {
if( isFullWindowContent() )
return false;
// not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime
return FlatUIUtils.getBoolean( rootPane,
FlatSystemProperties.MENUBAR_EMBEDDED,
@@ -620,21 +666,45 @@ public class FlatTitlePane
return;
if( debugTitleBarHeight > 0 ) {
// title bar height is measured from window top edge
int y = SwingUtilities.convertPoint( window, 0, debugTitleBarHeight, this ).y;
g.setColor( Color.green );
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
g.drawLine( 0, y, getWidth(), y );
}
if( debugHitTestSpots != null ) {
for( Rectangle r : debugHitTestSpots )
paintRect( g, Color.red, r );
}
paintRect( g, Color.cyan, debugCloseButtonBounds );
paintRect( g, Color.blue, debugAppIconBounds );
paintRect( g, Color.blue, debugMinimizeButtonBounds );
paintRect( g, Color.magenta, debugMaximizeButtonBounds );
paintRect( g, Color.cyan, debugCloseButtonBounds );
g.setColor( Color.red );
debugPaintComponentWithMouseListener( g, Color.red, rootPane.getLayeredPane(), 0, 0 );
debugPaintRect( g, Color.blue, debugAppIconBounds );
debugPaintRect( g, Color.blue, debugMinimizeButtonBounds );
debugPaintRect( g, Color.magenta, debugMaximizeButtonBounds );
debugPaintRect( g, Color.cyan, debugCloseButtonBounds );
}
private void paintRect( Graphics g, Color color, Rectangle r ) {
private void debugPaintComponentWithMouseListener( Graphics g, Color color, Component c, int x, int y ) {
if( !c.isDisplayable() || !c.isVisible() || c == mouseLayer ||
c == iconifyButton || c == maximizeButton || c == restoreButton || c == closeButton )
return;
if( c.getMouseListeners().length > 0 ||
c.getMouseMotionListeners().length > 0 ||
c.getMouseWheelListeners().length > 0 )
{
g.drawRect( x, y, c.getWidth(), c.getHeight() );
return;
}
if( c instanceof Container ) {
Rectangle titlePaneBoundsOnWindow = SwingUtilities.convertRectangle( this, new Rectangle( getSize() ), window );
for( Component child : ((Container)c).getComponents() ) {
Rectangle compBoundsOnWindow = SwingUtilities.convertRectangle( c, new Rectangle( c.getSize() ), window );
if( compBoundsOnWindow.intersects( titlePaneBoundsOnWindow ) )
debugPaintComponentWithMouseListener( g, color, child, x + child.getX(), y + child.getY() );
}
}
}
private void debugPaintRect( Graphics g, Color color, Rectangle r ) {
if( r == null )
return;
@@ -645,6 +715,9 @@ public class FlatTitlePane
@Override
protected void paintComponent( Graphics g ) {
if( isFullWindowContent() )
return;
// not storing value of "TitlePane.unifiedBackground" in class to allow changing at runtime
g.setColor( (UIManager.getBoolean( "TitlePane.unifiedBackground" ) &&
clientPropertyColor( rootPane, TITLE_BAR_BACKGROUND, null ) == null)
@@ -866,11 +939,14 @@ public class FlatTitlePane
return;
int titleBarHeight = getHeight();
// title bar height must be measured from window top edge
// (when window is maximized, window y location is e.g. -11 and window top inset is 11)
for( Component c = this; c != window && c != null; c = c.getParent() )
titleBarHeight += c.getY();
// slightly reduce height so that component receives mouseExit events
if( titleBarHeight > 0 )
titleBarHeight--;
List<Rectangle> hitTestSpots = new ArrayList<>();
Rectangle appIconBounds = null;
if( !showIconBesideTitle && iconLabel.isVisible() ) {
@@ -928,71 +1004,17 @@ public class FlatTitlePane
}
}
Rectangle r = getNativeHitTestSpot( buttonPanel );
if( r != null )
hitTestSpots.add( r );
JMenuBar menuBar = rootPane.getJMenuBar();
if( hasVisibleEmbeddedMenuBar( menuBar ) ) {
r = getNativeHitTestSpot( menuBar );
if( r != null ) {
// if frame is resizable and not maximized, make menu bar hit test spot smaller at top
// to have a small area above the menu bar to resize the window
if( window instanceof Frame && ((Frame)window).isResizable() && !isWindowMaximized() ) {
// limit to 8, because Windows does not use a larger height
int resizeHeight = UIScale.scale( Math.min( menuBarResizeHeight, 8 ) );
r.y += resizeHeight;
r.height -= resizeHeight;
}
int count = menuBar.getComponentCount();
for( int i = count - 1; i >= 0; i-- ) {
Component c = menuBar.getComponent( i );
if( c instanceof Box.Filler ||
(c instanceof JComponent && clientPropertyBoolean( (JComponent) c, COMPONENT_TITLE_BAR_CAPTION, false ) ) )
{
// If menu bar is embedded and contains a horizontal glue or caption component,
// then split the hit test spot so that
// the glue/caption component area can be used to move the window.
Point glueLocation = SwingUtilities.convertPoint( c, 0, 0, window );
int x2 = glueLocation.x + c.getWidth();
Rectangle r2;
if( getComponentOrientation().isLeftToRight() ) {
r2 = new Rectangle( x2, r.y, (r.x + r.width) - x2, r.height );
r.width = glueLocation.x - r.x;
} else {
r2 = new Rectangle( r.x, r.y, glueLocation.x - r.x, r.height );
r.width = (r.x + r.width) - x2;
r.x = x2;
}
if( r2.width > 0 )
hitTestSpots.add( r2 );
}
}
hitTestSpots.add( r );
}
}
// allow internal frames in layered pane to be moved/resized when placed over title bar
for( Component c : rootPane.getLayeredPane().getComponents() ) {
r = (c instanceof JInternalFrame) ? getNativeHitTestSpot( (JInternalFrame) c ) : null;
if( r != null )
hitTestSpots.add( r );
}
Rectangle minimizeButtonBounds = boundsInWindow( iconifyButton );
Rectangle maximizeButtonBounds = boundsInWindow( maximizeButton.isVisible() ? maximizeButton : restoreButton );
Rectangle closeButtonBounds = boundsInWindow( closeButton );
// clear hit-test cache
lastCaptionHitTestTime = 0;
FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight,
hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
this::captionHitTest, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
debugTitleBarHeight = titleBarHeight;
debugHitTestSpots = hitTestSpots;
debugAppIconBounds = appIconBounds;
debugMinimizeButtonBounds = minimizeButtonBounds;
debugMaximizeButtonBounds = maximizeButtonBounds;
@@ -1007,18 +1029,101 @@ public class FlatTitlePane
: null;
}
protected Rectangle getNativeHitTestSpot( JComponent c ) {
Dimension size = c.getSize();
if( size.width <= 0 || size.height <= 0 )
return null;
/**
* Returns whether there is a component at the given location, that processes
* mouse events. E.g. buttons, menus, etc.
* <p>
* Note:
* <ul>
* <li>This method is invoked often when mouse is moved over title bar
* and should therefore return quickly.
* <li>This method is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
* while processing Windows messages.
* </ul>
*/
private boolean captionHitTest( Point pt ) {
// Windows invokes this method every ~200ms, even if the mouse has not moved
long time = System.currentTimeMillis();
if( pt.x == lastCaptionHitTestX && pt.y == lastCaptionHitTestY && time < lastCaptionHitTestTime + 300 ) {
lastCaptionHitTestTime = time;
return lastCaptionHitTestResult;
}
Point location = SwingUtilities.convertPoint( c, 0, 0, window );
Rectangle r = new Rectangle( location, size );
return r;
// convert pt from window coordinates to layeredPane coordinates
Component layeredPane = rootPane.getLayeredPane();
int x = pt.x;
int y = pt.y;
for( Component c = layeredPane; c != window && c != null; c = c.getParent() ) {
x -= c.getX();
y -= c.getY();
}
lastCaptionHitTestX = pt.x;
lastCaptionHitTestY = pt.y;
lastCaptionHitTestTime = time;
lastCaptionHitTestResult = isTitleBarCaptionAt( layeredPane, x, y );
return lastCaptionHitTestResult;
}
private boolean isTitleBarCaptionAt( Component c, int x, int y ) {
if( !c.isDisplayable() || !c.isVisible() || !c.contains( x, y ) || c == mouseLayer )
return true; // continue checking with next component
if( c.isEnabled() &&
(c.getMouseListeners().length > 0 ||
c.getMouseMotionListeners().length > 0) )
{
if( !(c instanceof JComponent) )
return false; // assume that this is not a caption because the component has mouse listeners
// check client property boolean value
Object caption = ((JComponent)c).getClientProperty( COMPONENT_TITLE_BAR_CAPTION );
if( caption instanceof Boolean )
return (boolean) caption;
// 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() )
return false; // assume that this is not a caption because the component has mouse listeners
if( caption instanceof Function ) {
// check client property function value
@SuppressWarnings( "unchecked" )
Function<Point, Boolean> hitTest = (Function<Point, Boolean>) caption;
Boolean result = hitTest.apply( new Point( x, y ) );
if( result != null )
return result;
} else {
// check component UI
ComponentUI ui = JavaCompatibility2.getUI( (JComponent) c );
if( !(ui instanceof TitleBarCaptionHitTest) )
return false; // assume that this is not a caption because the component has mouse listeners
Boolean result = ((TitleBarCaptionHitTest)ui).isTitleBarCaptionAt( x, y );
if( result != null )
return result;
}
// else continue checking children
}
// check children
if( c instanceof Container ) {
for( Component child : ((Container)c).getComponents() ) {
if( !isTitleBarCaptionAt( child, x - child.getX(), y - child.getY() ) )
return false;
}
}
return true;
}
private int lastCaptionHitTestX;
private int lastCaptionHitTestY;
private long lastCaptionHitTestTime;
private boolean lastCaptionHitTestResult;
private int debugTitleBarHeight;
private List<Rectangle> debugHitTestSpots;
private Rectangle debugAppIconBounds;
private Rectangle debugMinimizeButtonBounds;
private Rectangle debugMaximizeButtonBounds;
@@ -1116,7 +1221,7 @@ public class FlatTitlePane
}
}
// compute icon width and gap (if icon is show besides the title)
// compute icon width and gap (if icon is shown besides the title)
int iconTextGap = 0;
int iconWidthAndGap = 0;
if( icon != null ) {
@@ -1125,7 +1230,7 @@ public class FlatTitlePane
iconWidthAndGap = icon.getIconWidth() + iconTextGap;
}
// layout title and icon (if show besides the title)
// layout title and icon (if shown besides the title)
String clippedText = SwingUtilities.layoutCompoundLabel( label, fontMetrics, text, icon,
label.getVerticalAlignment(), label.getHorizontalAlignment(),
label.getVerticalTextPosition(), label.getHorizontalTextPosition(),
@@ -1275,7 +1380,7 @@ debug*/
}
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
if( e.getSource() == iconLabel ) {
if( SwingUtilities.getDeepestComponentAt( FlatTitlePane.this, e.getX(), e.getY() ) == iconLabel ) {
// double-click on icon closes window
close();
} else if( !hasNativeCustomDecoration() ) {
@@ -1302,7 +1407,7 @@ debug*/
if( !SwingUtilities.isLeftMouseButton( e ) )
return;
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
dragOffset = SwingUtilities.convertPoint( mouseLayer, e.getPoint(), window );
linuxNativeMove = false;
// on Linux, move or maximize/restore window
@@ -1415,4 +1520,27 @@ debug*/
@Override public void componentMoved( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
}
//---- interface TitleBarCaptionHitTest -----------------------------------
/**
* For custom components use {@link FlatClientProperties#COMPONENT_TITLE_BAR_CAPTION}
* instead of this interface.
*
* @since 3.4
*/
public interface TitleBarCaptionHitTest {
/**
* Invoked for a component that is enabled and has mouse listeners,
* to check whether it processes mouse input at the given x/y location.
* 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.
*
* @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
* {@code null} if the component children should be checked
*/
Boolean isTitleBarCaptionAt( int x, int y );
}
}

View File

@@ -82,7 +82,7 @@ import com.formdev.flatlaf.util.UIScale;
*/
public class FlatToolBarUI
extends BasicToolBarUI
implements StyleableUI
implements StyleableUI, FlatTitlePane.TitleBarCaptionHitTest
{
/** @since 1.4 */ @Styleable protected boolean focusableButtons;
/** @since 2 */ @Styleable protected boolean arrowKeysOnlyNavigation;
@@ -453,6 +453,15 @@ public class FlatToolBarUI
: null;
}
//---- interface FlatTitlePane.TitleBarCaptionHitTest ----
/** @since 3.4 */
@Override
public Boolean isTitleBarCaptionAt( int x, int y ) {
// necessary because BasicToolBarUI adds some mouse listeners for dragging when toolbar is floatable
return null; // check children
}
//---- class FlatToolBarFocusTraversalPolicy ------------------------------
/**

View File

@@ -0,0 +1,62 @@
/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.ui;
import java.beans.PropertyChangeListener;
import javax.swing.Action;
/**
* Base class for UI actions used in ActionMap.
* (similar to class sun.swing.UIAction)
*
* @author Karl Tauber
* @since 3.4
*/
public abstract class FlatUIAction
implements Action
{
protected final String name;
protected final Action delegate;
protected FlatUIAction( String name ) {
this.name = name;
this.delegate = null;
}
protected FlatUIAction( Action delegate ) {
this.name = null;
this.delegate = delegate;
}
@Override
public Object getValue( String key ) {
if( key == NAME && delegate == null )
return name;
return (delegate != null) ? delegate.getValue( key ) : null;
}
@Override
public boolean isEnabled() {
return (delegate != null) ? delegate.isEnabled() : true;
}
// do nothing in following methods because this class is immutable
@Override public void putValue( String key, Object value ) {}
@Override public void setEnabled( boolean b ) {}
@Override public void addPropertyChangeListener( PropertyChangeListener listener ) {}
@Override public void removePropertyChangeListener( PropertyChangeListener listener ) {}
}

View File

@@ -60,6 +60,7 @@ import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.tree.DefaultTreeCellEditor;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLaf;
@@ -304,6 +305,10 @@ public class FlatUIUtils
if( parent instanceof JTable && ((JTable)parent).getEditorComponent() == c )
return true;
// check whether used as tree cell editor
if( parent instanceof DefaultTreeCellEditor.EditorContainer )
return true;
// check whether used as cell editor
// Table.editor is set in JTable.GenericEditor constructor
// Tree.cellEditor is set in sun.swing.FilePane.editFileName()

View File

@@ -29,8 +29,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.Timer;
@@ -159,7 +159,7 @@ class FlatWindowsNativeWindowBorder
}
@Override
public void updateTitleBarInfo( Window window, int titleBarHeight, List<Rectangle> hitTestSpots,
public void updateTitleBarInfo( Window window, int titleBarHeight, Predicate<Point> captionHitTestCallback,
Rectangle appIconBounds, Rectangle minimizeButtonBounds, Rectangle maximizeButtonBounds,
Rectangle closeButtonBounds )
{
@@ -168,7 +168,7 @@ class FlatWindowsNativeWindowBorder
return;
wndProc.titleBarHeight = titleBarHeight;
wndProc.hitTestSpots = hitTestSpots.toArray( new Rectangle[hitTestSpots.size()] );
wndProc.captionHitTestCallback = captionHitTestCallback;
wndProc.appIconBounds = cloneRectange( appIconBounds );
wndProc.minimizeButtonBounds = cloneRectange( minimizeButtonBounds );
wndProc.maximizeButtonBounds = cloneRectange( maximizeButtonBounds );
@@ -288,8 +288,8 @@ class FlatWindowsNativeWindowBorder
private final long hwnd;
// Swing coordinates/values may be scaled on a HiDPI screen
private int titleBarHeight;
private Rectangle[] hitTestSpots;
private int titleBarHeight; // measured from window top edge, which may be out-of-screen if maximized
private Predicate<Point> captionHitTestCallback;
private Rectangle appIconBounds;
private Rectangle minimizeButtonBounds;
private Rectangle maximizeButtonBounds;
@@ -340,50 +340,61 @@ class FlatWindowsNativeWindowBorder
private int onNcHitTest( int x, int y, boolean isOnResizeBorder ) {
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y );
int sx = pt.x;
int sy = pt.y;
// return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE
if( contains( appIconBounds, sx, sy ) )
if( contains( appIconBounds, pt ) )
return HTSYSMENU;
// return HTMINBUTTON if mouse is over minimize button
// - hovering mouse over HTMINBUTTON area shows tooltip on Windows 10/11
if( contains( minimizeButtonBounds, sx, sy ) )
if( contains( minimizeButtonBounds, pt ) )
return HTMINBUTTON;
// return HTMAXBUTTON if mouse is over maximize/restore button
// - hovering mouse over HTMAXBUTTON area shows tooltip on Windows 10
// - hovering mouse over HTMAXBUTTON area shows snap layouts menu on Windows 11
// https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/apply-snap-layout-menu
if( contains( maximizeButtonBounds, sx, sy ) )
if( contains( maximizeButtonBounds, pt ) )
return HTMAXBUTTON;
// return HTCLOSE if mouse is over close button
// - hovering mouse over HTCLOSE area shows tooltip on Windows 10/11
if( contains( closeButtonBounds, sx, sy ) )
if( contains( closeButtonBounds, pt ) )
return HTCLOSE;
boolean isOnTitleBar = (sy < titleBarHeight);
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click and drag vertically resizes window
if( isOnResizeBorder )
return HTTOP;
boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) {
// use a second reference to the array to avoid that it can be changed
// in another thread while processing the array
Rectangle[] hitTestSpots2 = hitTestSpots;
for( Rectangle spot : hitTestSpots2 ) {
if( spot.contains( sx, sy ) )
// return HTCLIENT if mouse is over any Swing component in title bar
// that processes mouse events (e.g. buttons, menus, etc)
// - Windows ignores mouse events in this area
try {
if( captionHitTestCallback != null && !captionHitTestCallback.test( pt ) )
return HTCLIENT;
} catch( Throwable ex ) {
// ignore
}
return isOnResizeBorder ? HTTOP : HTCAPTION;
// return HTCAPTION if mouse is over title bar
// - right-click shows system menu
// - double-left-click maximizes/restores window size
return HTCAPTION;
}
return isOnResizeBorder ? HTTOP : HTCLIENT;
// return HTCLIENT
// - Windows ignores mouse events in this area
return HTCLIENT;
}
private boolean contains( Rectangle rect, int x, int y ) {
return (rect != null && rect.contains( x, y ) );
private boolean contains( Rectangle rect, Point pt ) {
return (rect != null && rect.contains( pt ) );
}
/**

View File

@@ -0,0 +1,219 @@
/*
* 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.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JComponent;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.SystemInfo;
/**
* @author Karl Tauber
*/
class FullWindowContentSupport
{
private static final String KEY_DEBUG_SHOW_PLACEHOLDERS = "FlatLaf.debug.panel.showPlaceholders";
private static ArrayList<WeakReference<JComponent>> placeholders = new ArrayList<>();
static Dimension getPlaceholderPreferredSize( JComponent c, String options ) {
JRootPane rootPane;
Rectangle bounds;
if( !options.startsWith( SystemInfo.isMacOS ? "mac" : "win" ) ||
!c.isDisplayable() ||
(rootPane = SwingUtilities.getRootPane( c )) == null ||
(bounds = (Rectangle) rootPane.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS )) == null )
return new Dimension( 0, 0 );
if( options.length() > 3 ) {
if( (options.contains( "leftToRight" ) && !c.getComponentOrientation().isLeftToRight()) ||
(options.contains( "rightToLeft" ) && c.getComponentOrientation().isLeftToRight()) )
return new Dimension( 0, 0 );
}
// On macOS, the client property is updated very late when toggling full screen,
// which results in "jumping" layout after full screen toggle finished.
// To avoid that, get up-to-date buttons bounds from macOS.
if( SystemInfo.isMacFullWindowContentSupported && FlatNativeMacLibrary.isLoaded() ) {
Rectangle r = FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( c ) );
if( r != null )
bounds = r;
}
int width = bounds.width;
int height = bounds.height;
if( options.length() > 3 ) {
if( width == 0 && options.contains( "zeroInFullScreen" ) )
height = 0;
if( options.contains( "horizontal" ) )
height = 0;
if( options.contains( "vertical" ) )
width = 0;
}
return new Dimension( width, height );
}
static void registerPlaceholder( JComponent c ) {
synchronized( placeholders ) {
if( indexOfPlaceholder( c ) < 0 )
placeholders.add( new WeakReference<>( c ) );
}
}
static void unregisterPlaceholder( JComponent c ) {
synchronized( placeholders ) {
int index = indexOfPlaceholder( c );
if( index >= 0 )
placeholders.remove( index );
}
}
private static int indexOfPlaceholder( JComponent c ) {
int size = placeholders.size();
for( int i = 0; i < size; i++ ) {
if( placeholders.get( i ).get() == c )
return i;
}
return -1;
}
static void revalidatePlaceholders( Component container ) {
synchronized( placeholders ) {
if( placeholders.isEmpty() )
return;
for( Iterator<WeakReference<JComponent>> it = placeholders.iterator(); it.hasNext(); ) {
WeakReference<JComponent> ref = it.next();
JComponent c = ref.get();
// remove already released placeholder
if( c == null ) {
it.remove();
continue;
}
// revalidate placeholder if is in given container
if( SwingUtilities.isDescendingFrom( c, container ) )
c.revalidate();
}
}
}
static ComponentListener macInstallListeners( JRootPane rootPane ) {
ComponentListener l = new ComponentAdapter() {
boolean lastFullScreen;
@Override
public void componentResized( ComponentEvent e ) {
Window window = SwingUtilities.windowForComponent( rootPane );
if( window == null )
return;
boolean fullScreen = FlatNativeMacLibrary.isLoaded() && FlatNativeMacLibrary.isWindowFullScreen( window );
if( fullScreen == lastFullScreen )
return;
lastFullScreen = fullScreen;
macUpdateFullWindowContentButtonsBoundsProperty( rootPane );
}
};
rootPane.addComponentListener( l );
return l;
}
static void macUninstallListeners( JRootPane rootPane, ComponentListener l ) {
if( l != null )
rootPane.removeComponentListener( l );
}
static void macUpdateFullWindowContentButtonsBoundsProperty( JRootPane rootPane ) {
if( !SystemInfo.isMacFullWindowContentSupported || !rootPane.isDisplayable() )
return;
Rectangle bounds = null;
if( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) ) {
bounds = FlatNativeMacLibrary.isLoaded()
? FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( rootPane ) )
: new Rectangle( 68, 28 ); // default size
}
rootPane.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, bounds );
}
static void macUninstallFullWindowContentButtonsBoundsProperty( JRootPane rootPane ) {
if( !SystemInfo.isMacFullWindowContentSupported )
return;
rootPane.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, null );
}
static void debugPaint( Graphics g, JComponent c ) {
if( !UIManager.getBoolean( KEY_DEBUG_SHOW_PLACEHOLDERS ) )
return;
int width = c.getWidth();
int height = c.getHeight();
if( width <= 0 || height <= 0 )
return;
// draw red figure
g.setColor( Color.red );
debugPaintRect( g, new Rectangle( width, height ) );
// draw magenta figure if buttons bounds are not equal to placeholder bounds
JRootPane rootPane;
Rectangle bounds;
if( (rootPane = SwingUtilities.getRootPane( c )) != null &&
(bounds = (Rectangle) rootPane.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS )) != null &&
(bounds.width != width || bounds.height != height) )
{
g.setColor( Color.magenta );
debugPaintRect( g, SwingUtilities.convertRectangle( rootPane, bounds, c ) );
}
}
private static void debugPaintRect( Graphics g, Rectangle r ) {
// draw rectangle
g.drawRect( r.x, r.y, r.width - 1, r.height - 1 );
// draw diagonal cross
int x2 = r.x + r.width - 1;
int y2 = r.y + r.height - 1;
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
g.drawLine( r.x, r.y, x2, y2 );
g.drawLine( r.x, y2, x2, r.y );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
}
}

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui;
import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -25,6 +26,7 @@ import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.filechooser.FileSystemView;
import javax.swing.plaf.ComponentUI;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -88,4 +90,64 @@ public class JavaCompatibility2
return null;
}
}
/**
* Java 8 - 11 on Windows: sun.awt.shell.ShellFolder.get( "fileChooserShortcutPanelFolders" )
* <br>
* Java 12: javax.swing.filechooser.FileSystemView.getChooserShortcutPanelFiles()
*
* @since 3.4
*/
public static File[] getChooserShortcutPanelFiles( FileSystemView fsv ) {
try {
if( SystemInfo.isJava_12_orLater ) {
Method m = fsv.getClass().getMethod( "getChooserShortcutPanelFiles" );
File[] files = (File[]) m.invoke( fsv );
// on macOS and Linux, files consists only of the user home directory
if( files.length == 1 && files[0].equals( new File( System.getProperty( "user.home" ) ) ) )
files = new File[0];
return files;
} else if( SystemInfo.isWindows ) {
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
Method m = cls.getMethod( "get", String.class );
return (File[]) m.invoke( null, "fileChooserShortcutPanelFolders" );
}
} catch( IllegalAccessException ex ) {
// do not log because access may be denied via VM option '--illegal-access=deny'
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
// fallback
return new File[0];
}
/**
* Java 8: sun.awt.shell.ShellFolder.get( "fileChooserComboBoxFolders" )
* <br>
* Java 9: javax.swing.filechooser.FileSystemView.getChooserComboBoxFiles()
*
* @since 3.4
*/
public static File[] getChooserComboBoxFiles( FileSystemView fsv ) {
try {
if( SystemInfo.isJava_9_orLater ) {
Method m = fsv.getClass().getMethod( "getChooserComboBoxFiles" );
return (File[]) m.invoke( fsv );
} else {
Class<?> cls = Class.forName( "sun.awt.shell.ShellFolder" );
Method m = cls.getMethod( "get", String.class );
return (File[]) m.invoke( null, "fileChooserComboBoxFolders" );
}
} catch( IllegalAccessException ex ) {
// do not log because access may be denied via VM option '--illegal-access=deny'
} catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
// fallback
return new File[0];
}
}

View File

@@ -739,6 +739,8 @@ Table.rowHeight = 20
Table.showHorizontalLines = false
Table.showVerticalLines = false
Table.showTrailingVerticalLine = false
Table.paintOutsideAlternateRows = false
Table.editorSelectAllOnStartEditing = true
Table.consistentHomeEndKeyBehavior = true
Table.intercellSpacing = 0,0
Table.scrollPaneBorder = com.formdev.flatlaf.ui.FlatScrollPaneBorder
@@ -829,7 +831,6 @@ TitlePane.centerTitleIfMenuBarEmbedded = true
TitlePane.showIconBesideTitle = false
TitlePane.menuBarTitleGap = 40
TitlePane.menuBarTitleMinimumGap = 12
TitlePane.menuBarResizeHeight = 4
TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon
TitlePane.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon
TitlePane.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon

View File

@@ -73,6 +73,7 @@ class DemoFrame
initComponents();
updateFontMenuItems();
initAccentColors();
initFullWindowContent();
controlBar.initialize( this, tabbedPane );
setIconImages( FlatSVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
@@ -89,24 +90,23 @@ class DemoFrame
// do not use HTML text in menu items because this is not supported in macOS screen menu
htmlMenuItem.setText( "some text" );
JRootPane rootPane = getRootPane();
if( SystemInfo.isMacFullWindowContentSupported ) {
// expand window content into window title bar and make title bar transparent
getRootPane().putClientProperty( "apple.awt.fullWindowContent", true );
getRootPane().putClientProperty( "apple.awt.transparentTitleBar", true );
rootPane.putClientProperty( "apple.awt.fullWindowContent", true );
rootPane.putClientProperty( "apple.awt.transparentTitleBar", true );
rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE );
// hide window title
if( SystemInfo.isJava_17_orLater )
getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false );
rootPane.putClientProperty( "apple.awt.windowTitleVisible", false );
else
setTitle( null );
// add gap to left side of toolbar
toolBar.add( Box.createHorizontalStrut( 70 ), 0 );
}
// enable full screen mode for this window (for Java 8 - 10; not necessary for Java 11+)
if( !SystemInfo.isJava_11_orLater )
getRootPane().putClientProperty( "apple.awt.fullscreenable", true );
rootPane.putClientProperty( "apple.awt.fullscreenable", true );
}
// integrate into macOS screen menu
@@ -461,9 +461,37 @@ class DemoFrame
accentColorButtons[i].setVisible( isAccentColorSupported );
}
private void initFullWindowContent() {
if( !supportsFlatLafWindowDecorations() )
return;
// create fullWindowContent mode toggle button
Icon expandIcon = new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/expand.svg" );
Icon collapseIcon = new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/collapse.svg" );
JToggleButton fullWindowContentButton = new JToggleButton( expandIcon );
fullWindowContentButton.setToolTipText( "Toggle full window content" );
fullWindowContentButton.addActionListener( e -> {
boolean fullWindowContent = fullWindowContentButton.isSelected();
fullWindowContentButton.setIcon( fullWindowContent ? collapseIcon : expandIcon );
menuBar.setVisible( !fullWindowContent );
toolBar.setVisible( !fullWindowContent );
getRootPane().putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT, fullWindowContent );
} );
// add fullWindowContent mode toggle button to tabbed pane
JToolBar trailingToolBar = new JToolBar();
trailingToolBar.add( Box.createGlue() );
trailingToolBar.add( fullWindowContentButton );
tabbedPane.putClientProperty( FlatClientProperties.TABBED_PANE_TRAILING_COMPONENT, trailingToolBar );
}
private boolean supportsFlatLafWindowDecorations() {
return FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated());
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JMenuBar menuBar1 = new JMenuBar();
menuBar = new JMenuBar();
JMenu fileMenu = new JMenu();
JMenuItem newMenuItem = new JMenuItem();
JMenuItem openMenuItem = new JMenuItem();
@@ -509,6 +537,8 @@ class DemoFrame
JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem();
JMenu helpMenu = new JMenu();
aboutMenuItem = new JMenuItem();
JPanel toolBarPanel = new JPanel();
JPanel macFullWindowContentButtonsPlaceholder = new JPanel();
toolBar = new JToolBar();
JButton backButton = new JButton();
JButton forwardButton = new JButton();
@@ -524,8 +554,10 @@ class DemoFrame
DataComponentsPanel dataComponentsPanel = new DataComponentsPanel();
TabsPanel tabsPanel = new TabsPanel();
OptionPanePanel optionPanePanel = new OptionPanePanel();
ExtrasPanel extrasPanel1 = new ExtrasPanel();
ExtrasPanel extrasPanel = new ExtrasPanel();
controlBar = new ControlBar();
JPanel themesPanelPanel = new JPanel();
JPanel winFullWindowContentButtonsPlaceholder = new JPanel();
themesPanel = new IJThemesPanel();
//======== this ========
@@ -534,7 +566,7 @@ class DemoFrame
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
//======== menuBar1 ========
//======== menuBar ========
{
//======== fileMenu ========
@@ -579,7 +611,7 @@ class DemoFrame
exitMenuItem.addActionListener(e -> exitActionPerformed());
fileMenu.add(exitMenuItem);
}
menuBar1.add(fileMenu);
menuBar.add(fileMenu);
//======== editMenu ========
{
@@ -632,7 +664,7 @@ class DemoFrame
deleteMenuItem.addActionListener(e -> menuItemActionPerformed(e));
editMenu.add(deleteMenuItem);
}
menuBar1.add(editMenu);
menuBar.add(editMenu);
//======== viewMenu ========
{
@@ -732,7 +764,7 @@ class DemoFrame
radioButtonMenuItem3.addActionListener(e -> menuItemActionPerformed(e));
viewMenu.add(radioButtonMenuItem3);
}
menuBar1.add(viewMenu);
menuBar.add(viewMenu);
//======== fontMenu ========
{
@@ -756,7 +788,7 @@ class DemoFrame
decrFontMenuItem.addActionListener(e -> decrFont());
fontMenu.add(decrFontMenuItem);
}
menuBar1.add(fontMenu);
menuBar.add(fontMenu);
//======== optionsMenu ========
{
@@ -808,7 +840,7 @@ class DemoFrame
showUIDefaultsInspectorMenuItem.addActionListener(e -> showUIDefaultsInspector());
optionsMenu.add(showUIDefaultsInspectorMenuItem);
}
menuBar1.add(optionsMenu);
menuBar.add(optionsMenu);
//======== helpMenu ========
{
@@ -821,54 +853,66 @@ class DemoFrame
aboutMenuItem.addActionListener(e -> aboutActionPerformed());
helpMenu.add(aboutMenuItem);
}
menuBar1.add(helpMenu);
menuBar.add(helpMenu);
}
setJMenuBar(menuBar1);
setJMenuBar(menuBar);
//======== toolBar ========
//======== toolBarPanel ========
{
toolBar.setMargin(new Insets(3, 3, 3, 3));
toolBarPanel.setLayout(new BorderLayout());
//---- backButton ----
backButton.setToolTipText("Back");
backButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/back.svg"));
toolBar.add(backButton);
//======== macFullWindowContentButtonsPlaceholder ========
{
macFullWindowContentButtonsPlaceholder.setLayout(new FlowLayout());
}
toolBarPanel.add(macFullWindowContentButtonsPlaceholder, BorderLayout.WEST);
//---- forwardButton ----
forwardButton.setToolTipText("Forward");
forwardButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/forward.svg"));
toolBar.add(forwardButton);
toolBar.addSeparator();
//======== toolBar ========
{
toolBar.setMargin(new Insets(3, 3, 3, 3));
//---- cutButton ----
cutButton.setToolTipText("Cut");
cutButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-cut.svg"));
toolBar.add(cutButton);
//---- backButton ----
backButton.setToolTipText("Back");
backButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/back.svg"));
toolBar.add(backButton);
//---- copyButton ----
copyButton.setToolTipText("Copy");
copyButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/copy.svg"));
toolBar.add(copyButton);
//---- forwardButton ----
forwardButton.setToolTipText("Forward");
forwardButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/forward.svg"));
toolBar.add(forwardButton);
toolBar.addSeparator();
//---- pasteButton ----
pasteButton.setToolTipText("Paste");
pasteButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-paste.svg"));
toolBar.add(pasteButton);
toolBar.addSeparator();
//---- cutButton ----
cutButton.setToolTipText("Cut");
cutButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-cut.svg"));
toolBar.add(cutButton);
//---- refreshButton ----
refreshButton.setToolTipText("Refresh");
refreshButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/refresh.svg"));
toolBar.add(refreshButton);
toolBar.addSeparator();
//---- copyButton ----
copyButton.setToolTipText("Copy");
copyButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/copy.svg"));
toolBar.add(copyButton);
//---- showToggleButton ----
showToggleButton.setSelected(true);
showToggleButton.setToolTipText("Show Details");
showToggleButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/show.svg"));
toolBar.add(showToggleButton);
//---- pasteButton ----
pasteButton.setToolTipText("Paste");
pasteButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/menu-paste.svg"));
toolBar.add(pasteButton);
toolBar.addSeparator();
//---- refreshButton ----
refreshButton.setToolTipText("Refresh");
refreshButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/refresh.svg"));
toolBar.add(refreshButton);
toolBar.addSeparator();
//---- showToggleButton ----
showToggleButton.setSelected(true);
showToggleButton.setToolTipText("Show Details");
showToggleButton.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/show.svg"));
toolBar.add(showToggleButton);
}
toolBarPanel.add(toolBar, BorderLayout.CENTER);
}
contentPane.add(toolBar, BorderLayout.NORTH);
contentPane.add(toolBarPanel, BorderLayout.PAGE_START);
//======== contentPanel ========
{
@@ -888,13 +932,25 @@ class DemoFrame
tabbedPane.addTab("Data Components", dataComponentsPanel);
tabbedPane.addTab("Tabs", tabsPanel);
tabbedPane.addTab("Option Pane", optionPanePanel);
tabbedPane.addTab("Extras", extrasPanel1);
tabbedPane.addTab("Extras", extrasPanel);
}
contentPanel.add(tabbedPane, "cell 0 0");
}
contentPane.add(contentPanel, BorderLayout.CENTER);
contentPane.add(controlBar, BorderLayout.SOUTH);
contentPane.add(themesPanel, BorderLayout.EAST);
contentPane.add(controlBar, BorderLayout.PAGE_END);
//======== themesPanelPanel ========
{
themesPanelPanel.setLayout(new BorderLayout());
//======== winFullWindowContentButtonsPlaceholder ========
{
winFullWindowContentButtonsPlaceholder.setLayout(new FlowLayout());
}
themesPanelPanel.add(winFullWindowContentButtonsPlaceholder, BorderLayout.NORTH);
themesPanelPanel.add(themesPanel, BorderLayout.CENTER);
}
contentPane.add(themesPanelPanel, BorderLayout.LINE_END);
//---- buttonGroup1 ----
ButtonGroup buttonGroup1 = new ButtonGroup();
@@ -909,8 +965,8 @@ class DemoFrame
usersButton.setButtonType( ButtonType.toolBarButton );
usersButton.setFocusable( false );
usersButton.addActionListener( e -> JOptionPane.showMessageDialog( null, "Hello User! How are you?", "User", JOptionPane.INFORMATION_MESSAGE ) );
menuBar1.add( Box.createGlue() );
menuBar1.add( usersButton );
menuBar.add( Box.createGlue() );
menuBar.add( usersButton );
cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() );
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
@@ -922,7 +978,7 @@ class DemoFrame
for( int i = 1; i <= 100; i++ )
scrollingPopupMenu.add( "Item " + i );
if( FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated()) ) {
if( supportsFlatLafWindowDecorations() ) {
if( SystemInfo.isLinux )
unsupported( windowDecorationsCheckBoxMenuItem );
else
@@ -943,6 +999,17 @@ class DemoFrame
if( "false".equals( System.getProperty( "flatlaf.animatedLafChange" ) ) )
animatedLafChangeMenuItem.setSelected( false );
// on macOS, panel left to toolBar is a placeholder for title bar buttons in fullWindowContent mode
macFullWindowContentButtonsPlaceholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac zeroInFullScreen" );
// on Windows/Linux, panel above themesPanel is a placeholder for title bar buttons in fullWindowContent mode
winFullWindowContentButtonsPlaceholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "win" );
// uncomment this line to see title bar buttons placeholders in fullWindowContent mode
// UIManager.put( "FlatLaf.debug.panel.showPlaceholders", true );
// remove contentPanel bottom insets
MigLayout layout = (MigLayout) contentPanel.getLayout();
LC lc = ConstraintParser.parseLayoutConstraint( (String) layout.getLayoutConstraints() );
@@ -963,6 +1030,7 @@ class DemoFrame
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenuBar menuBar;
private JMenuItem exitMenuItem;
private JMenu scrollingPopupMenu;
private JMenuItem htmlMenuItem;

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -12,59 +12,69 @@ new FormModel {
"defaultCloseOperation": 2
"$locationPolicy": 2
"$sizePolicy": 2
add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) {
name: "toolBar"
"margin": new java.awt.Insets( 3, 3, 3, 3 )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormComponent( "javax.swing.JButton" ) {
name: "backButton"
"toolTipText": "Back"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/back.svg" )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "toolBarPanel"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "macFullWindowContentButtonsPlaceholder"
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "West"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "forwardButton"
"toolTipText": "Forward"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/forward.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator5"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "cutButton"
"toolTipText": "Cut"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-cut.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "copyButton"
"toolTipText": "Copy"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/copy.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "pasteButton"
"toolTipText": "Paste"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-paste.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator6"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "refreshButton"
"toolTipText": "Refresh"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/refresh.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator7"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "showToggleButton"
"selected": true
"toolTipText": "Show Details"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/show.svg" )
add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) {
name: "toolBar"
"margin": new java.awt.Insets( 3, 3, 3, 3 )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormComponent( "javax.swing.JButton" ) {
name: "backButton"
"toolTipText": "Back"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/back.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "forwardButton"
"toolTipText": "Forward"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/forward.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator5"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "cutButton"
"toolTipText": "Cut"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-cut.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "copyButton"
"toolTipText": "Copy"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/copy.svg" )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "pasteButton"
"toolTipText": "Paste"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/menu-paste.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator6"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "refreshButton"
"toolTipText": "Refresh"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/refresh.svg" )
} )
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator7"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "showToggleButton"
"selected": true
"toolTipText": "Show Details"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/show.svg" )
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "North"
"value": "First"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3"
@@ -105,7 +115,7 @@ new FormModel {
"title": "Option Pane"
} )
add( new FormComponent( "com.formdev.flatlaf.demo.extras.ExtrasPanel" ) {
name: "extrasPanel1"
name: "extrasPanel"
}, new FormLayoutConstraints( null ) {
"title": "Extras"
} )
@@ -121,19 +131,32 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "South"
"value": "Last"
} )
add( new FormComponent( "com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel" ) {
name: "themesPanel"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.variableModifiers": 0
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "themesPanelPanel"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "winFullWindowContentButtonsPlaceholder"
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "North"
} )
add( new FormComponent( "com.formdev.flatlaf.demo.intellijthemes.IJThemesPanel" ) {
name: "themesPanel"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.variableModifiers": 0
}
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "East"
"value": "After"
} )
menuBar: new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
name: "menuBar1"
name: "menuBar"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "fileMenu"
"text": "File"

View File

@@ -0,0 +1,4 @@
<!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 14.5L6 10M14.5 1.5L9.99998 6.00001M2.5 9.50001H6.5L6.5 13.5M13.5 6.5L9.5 6.50003V2.5" stroke="#6E6E6E" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 396 B

View File

@@ -0,0 +1,4 @@
<!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.5 9.5L2 14M9.50003 6.50004L14 2.00001M5.5 14.5H1.5V10.5M10.5 1.5L14.5 1.50002V5.5" stroke="#6E6E6E" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 391 B

View File

@@ -56,7 +56,7 @@ tasks {
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
withType<PublishToMavenRepository>().configureEach {
withType<AbstractPublishToMaven>().configureEach {
onlyIf { !rootProject.hasProperty( "skipFonts" ) }
}
}

View File

@@ -56,7 +56,7 @@ tasks {
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
withType<PublishToMavenRepository>().configureEach {
withType<AbstractPublishToMaven>().configureEach {
onlyIf { !rootProject.hasProperty( "skipFonts" ) }
}
}

View File

@@ -56,7 +56,7 @@ tasks {
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
withType<PublishToMavenRepository>().configureEach {
withType<AbstractPublishToMaven>().configureEach {
onlyIf { !rootProject.hasProperty( "skipFonts" ) }
}
}

View File

@@ -56,7 +56,7 @@ tasks {
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
withType<PublishToMavenRepository>().configureEach {
withType<AbstractPublishToMaven>().configureEach {
onlyIf { !rootProject.hasProperty( "skipFonts" ) }
}
}

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.jideoss.ui;
import static com.formdev.flatlaf.FlatClientProperties.COMPONENT_TITLE_BAR_CAPTION;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_HAS_FULL_BORDER;
import static com.formdev.flatlaf.FlatClientProperties.TABBED_PANE_SHOW_TAB_SEPARATORS;
import static com.formdev.flatlaf.FlatClientProperties.clientPropertyBoolean;
@@ -30,6 +31,7 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseListener;
@@ -37,6 +39,7 @@ import java.awt.event.MouseMotionListener;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.util.function.Function;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
@@ -100,6 +103,25 @@ public class FlatJideTabbedPaneUI
return new FlatJideTabbedPaneUI();
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
c.putClientProperty( COMPONENT_TITLE_BAR_CAPTION,
(Function<Point, Boolean>) pt -> {
if( tabForCoordinate( _tabPane, pt.x, pt.y ) >= 0 )
return false;
return null; // check children
} );
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
c.putClientProperty( COMPONENT_TITLE_BAR_CAPTION, null );
}
@Override
protected void installDefaults() {
super.installDefaults();

View File

@@ -32,8 +32,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.Timer;
@@ -164,7 +164,7 @@ public class FlatWindowsNativeWindowBorder
}
@Override
public void updateTitleBarInfo( Window window, int titleBarHeight, List<Rectangle> hitTestSpots,
public void updateTitleBarInfo( Window window, int titleBarHeight, Predicate<Point> captionHitTestCallback,
Rectangle appIconBounds, Rectangle minimizeButtonBounds, Rectangle maximizeButtonBounds,
Rectangle closeButtonBounds )
{
@@ -173,7 +173,7 @@ public class FlatWindowsNativeWindowBorder
return;
wndProc.titleBarHeight = titleBarHeight;
wndProc.hitTestSpots = hitTestSpots.toArray( new Rectangle[hitTestSpots.size()] );
wndProc.captionHitTestCallback = captionHitTestCallback;
wndProc.appIconBounds = cloneRectange( appIconBounds );
wndProc.minimizeButtonBounds = cloneRectange( minimizeButtonBounds );
wndProc.maximizeButtonBounds = cloneRectange( maximizeButtonBounds );
@@ -351,7 +351,7 @@ public class FlatWindowsNativeWindowBorder
// Swing coordinates/values may be scaled on a HiDPI screen
private int titleBarHeight;
private Rectangle[] hitTestSpots;
private Predicate<Point> captionHitTestCallback;
private Rectangle appIconBounds;
private Rectangle minimizeButtonBounds;
private Rectangle maximizeButtonBounds;
@@ -644,53 +644,65 @@ public class FlatWindowsNativeWindowBorder
// scale-down mouse x/y because Swing coordinates/values may be scaled on a HiDPI screen
Point pt = scaleDown( x, y );
int sx = pt.x;
int sy = pt.y;
// return HTSYSMENU if mouse is over application icon
// - left-click on HTSYSMENU area shows system menu
// - double-left-click sends WM_CLOSE
if( contains( appIconBounds, sx, sy ) )
if( contains( appIconBounds, pt ) )
return new LRESULT( HTSYSMENU );
// return HTMINBUTTON if mouse is over minimize button
// - hovering mouse over HTMINBUTTON area shows tooltip on Windows 10/11
if( contains( minimizeButtonBounds, sx, sy ) )
if( contains( minimizeButtonBounds, pt ) )
return new LRESULT( HTMINBUTTON );
// return HTMAXBUTTON if mouse is over maximize/restore button
// - hovering mouse over HTMAXBUTTON area shows tooltip on Windows 10
// - hovering mouse over HTMAXBUTTON area shows snap layouts menu on Windows 11
// https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/apply-snap-layout-menu
if( contains( maximizeButtonBounds, sx, sy ) )
if( contains( maximizeButtonBounds, pt ) )
return new LRESULT( HTMAXBUTTON );
// return HTCLOSE if mouse is over close button
// - hovering mouse over HTCLOSE area shows tooltip on Windows 10/11
if( contains( closeButtonBounds, sx, sy ) )
if( contains( closeButtonBounds, pt ) )
return new LRESULT( HTCLOSE );
int resizeBorderHeight = getResizeHandleHeight();
boolean isOnResizeBorder = (y < resizeBorderHeight) &&
(User32.INSTANCE.GetWindowLong( hwnd, GWL_STYLE ) & WS_THICKFRAME) != 0;
boolean isOnTitleBar = (sy < titleBarHeight);
// return HTTOP if mouse is over top resize border
// - hovering mouse shows vertical resize cursor
// - left-click and drag vertically resizes window
if( isOnResizeBorder )
return new LRESULT( HTTOP );
boolean isOnTitleBar = (pt.y < titleBarHeight);
if( isOnTitleBar ) {
// use a second reference to the array to avoid that it can be changed
// in another thread while processing the array
Rectangle[] hitTestSpots2 = hitTestSpots;
for( Rectangle spot : hitTestSpots2 ) {
if( spot.contains( sx, sy ) )
// return HTCLIENT if mouse is over any Swing component in title bar
// that processes mouse events (e.g. buttons, menus, etc)
// - Windows ignores mouse events in this area
try {
if( captionHitTestCallback != null && !captionHitTestCallback.test( pt ) )
return new LRESULT( HTCLIENT );
} catch( Throwable ex ) {
// ignore
}
return new LRESULT( isOnResizeBorder ? HTTOP : HTCAPTION );
// return HTCAPTION if mouse is over title bar
// - right-click shows system menu
// - double-left-click maximizes/restores window size
return new LRESULT( HTCAPTION );
}
return new LRESULT( isOnResizeBorder ? HTTOP : HTCLIENT );
// return HTCLIENT
// - Windows ignores mouse events in this area
return new LRESULT( HTCLIENT );
}
private boolean contains( Rectangle rect, int x, int y ) {
return (rect != null && rect.contains( x, y ) );
private boolean contains( Rectangle rect, Point pt ) {
return (rect != null && rect.contains( pt ) );
}
/**

View File

@@ -41,4 +41,6 @@
}
jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature );
jclass findClass( JNIEnv *env, const char* className, bool globalRef );
jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature, bool staticField );
jmethodID getMethodID( JNIEnv *env, jclass cls, const char* methodName, const char* methodSignature, bool staticMethod );

View File

@@ -7,6 +7,12 @@
#ifdef __cplusplus
extern "C" {
#endif
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT 0L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM 1L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE 2L
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: setWindowRoundedBorder
@@ -15,6 +21,38 @@ extern "C" {
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder
(JNIEnv *, jclass, jobject, jfloat, jfloat, jint);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: setWindowButtonsSpacing
* Signature: (Ljava/awt/Window;I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonsSpacing
(JNIEnv *, jclass, jobject, jint);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: getWindowButtonsBounds
* Signature: (Ljava/awt/Window;)Ljava/awt/Rectangle;
*/
JNIEXPORT jobject JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_getWindowButtonsBounds
(JNIEnv *, jclass, jobject);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: isWindowFullScreen
* Signature: (Ljava/awt/Window;)Z
*/
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_isWindowFullScreen
(JNIEnv *, jclass, jobject);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: toggleWindowFullScreen
* Signature: (Ljava/awt/Window;)Z
*/
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_toggleWindowFullScreen
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif

View File

@@ -21,8 +21,8 @@
* @author Karl Tauber
*/
jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature ) {
// NSLog( @"getFieldID %s %s %s", className, fieldName, fieldSignature );
jclass findClass( JNIEnv *env, const char* className, bool globalRef ) {
// NSLog( @"findClass %s", className );
jclass cls = env->FindClass( className );
if( cls == NULL ) {
@@ -32,7 +32,22 @@ jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName,
return NULL;
}
jfieldID fieldID = env->GetFieldID( cls, fieldName, fieldSignature );
if( globalRef )
cls = reinterpret_cast<jclass>( env->NewGlobalRef( cls ) );
return cls;
}
jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName, const char* fieldSignature, bool staticField ) {
// NSLog( @"getFieldID %s %s %s", className, fieldName, fieldSignature );
jclass cls = findClass( env, className, false );
if( cls == NULL )
return NULL;
jfieldID fieldID = staticField
? env->GetStaticFieldID( cls, fieldName, fieldSignature )
: env->GetFieldID( cls, fieldName, fieldSignature );
if( fieldID == NULL ) {
NSLog( @"FlatLaf: failed to lookup field '%s' of type '%s' in class '%s'", fieldName, fieldSignature, className );
env->ExceptionDescribe(); // print stack trace
@@ -42,3 +57,22 @@ jfieldID getFieldID( JNIEnv *env, const char* className, const char* fieldName,
return fieldID;
}
jmethodID getMethodID( JNIEnv *env, jclass cls, const char* methodName, const char* methodSignature, bool staticMethod ) {
// NSLog( @"getMethodID %s %s", methodName, methodSignature );
if( cls == NULL )
return NULL;
jmethodID methodID = staticMethod
? env->GetStaticMethodID( cls, methodName, methodSignature )
: env->GetMethodID( cls, methodName, methodSignature );
if( methodID == NULL ) {
NSLog( @"FlatLaf: failed to lookup method '%s' of type '%s'", methodName, methodSignature );
env->ExceptionDescribe(); // print stack trace
env->ExceptionClear();
return NULL;
}
return methodID;
}

View File

@@ -15,6 +15,7 @@
*/
#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>
#import <jni.h>
#import "JNIUtils.h"
#import "JNFRunLoop.h"
@@ -24,14 +25,37 @@
* @author Karl Tauber
*/
@interface WindowData : NSObject
// used when window is full screen
@property (nonatomic) int lastWindowButtonAreaWidth;
@property (nonatomic) int lastWindowTitleBarHeight;
// full screen observers
@property (nonatomic) id willEnterFullScreenObserver;
@property (nonatomic) id willExitFullScreenObserver;
@property (nonatomic) id didExitFullScreenObserver;
@end
@implementation WindowData
@end
// declare internal methods
NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window );
WindowData* getWindowData( NSWindow* nsWindow, bool allocate );
void setWindowButtonsHidden( NSWindow* nsWindow, bool hidden );
int getWindowButtonAreaWidth( NSWindow* nsWindow );
int getWindowTitleBarHeight( NSWindow* nsWindow );
bool isWindowFullScreen( NSWindow* nsWindow );
NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window ) {
if( window == NULL )
return NULL;
// initialize field IDs (done only once because fields are static)
static jfieldID peerID = getFieldID( env, "java/awt/Component", "peer", "Ljava/awt/peer/ComponentPeer;" );
static jfieldID platformWindowID = getFieldID( env, "sun/lwawt/LWWindowPeer", "platformWindow", "Lsun/lwawt/PlatformWindow;" );
static jfieldID ptrID = getFieldID( env, "sun/lwawt/macosx/CFRetainedResource", "ptr", "J" );
// initialize field IDs (done only once because variables are static)
static jfieldID peerID = getFieldID( env, "java/awt/Component", "peer", "Ljava/awt/peer/ComponentPeer;", false );
static jfieldID platformWindowID = getFieldID( env, "sun/lwawt/LWWindowPeer", "platformWindow", "Lsun/lwawt/PlatformWindow;", false );
static jfieldID ptrID = getFieldID( env, "sun/lwawt/macosx/CFRetainedResource", "ptr", "J", false );
if( peerID == NULL || platformWindowID == NULL || ptrID == NULL )
return NULL;
@@ -49,6 +73,16 @@ NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window ) {
return (NSWindow *) jlong_to_ptr( env->GetLongField( platformWindow, ptrID ) );
}
WindowData* getWindowData( NSWindow* nsWindow, bool allocate ) {
static char key;
WindowData* windowData = objc_getAssociatedObject( nsWindow, &key );
if( windowData == NULL && allocate ) {
windowData = [WindowData new];
objc_setAssociatedObject( nsWindow, &key, windowData, OBJC_ASSOCIATION_RETAIN_NONATOMIC );
}
return windowData;
}
extern "C"
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowRoundedBorder
( JNIEnv* env, jclass cls, jobject window, jfloat radius, jfloat borderWidth, jint borderColor )
@@ -87,3 +121,259 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW
JNI_COCOA_EXIT()
return FALSE;
}
extern "C"
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonsSpacing
( JNIEnv* env, jclass cls, jobject window, jint buttonsSpacing )
{
JNI_COCOA_ENTER()
NSWindow* nsWindow = getNSWindow( env, cls, window );
if( nsWindow == NULL )
return FALSE;
#define SPACING_DEFAULT com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT
#define SPACING_MEDIUM com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM
#define SPACING_LARGE com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE
bool isMacOS_11_orLater = @available( macOS 11, * );
if( !isMacOS_11_orLater && buttonsSpacing == SPACING_LARGE )
buttonsSpacing = SPACING_MEDIUM;
int oldButtonsSpacing = (nsWindow.toolbar != NULL)
? ((isMacOS_11_orLater && nsWindow.toolbarStyle == NSWindowToolbarStyleUnified)
? SPACING_LARGE
: SPACING_MEDIUM)
: SPACING_DEFAULT;
if( buttonsSpacing == oldButtonsSpacing )
return TRUE;
WindowData* windowData = getWindowData( nsWindow, true );
[FlatJNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
// NSLog( @"\n%@\n\n", [nsWindow.contentView.superview _subtreeDescription] );
// add/remove toolbar
NSToolbar* toolbar = NULL;
bool needsToolbar = (buttonsSpacing != SPACING_DEFAULT);
if( needsToolbar ) {
toolbar = [NSToolbar new];
toolbar.showsBaselineSeparator = NO; // necessary for older macOS versions
if( isWindowFullScreen( nsWindow ) )
toolbar.visible = NO;
}
nsWindow.toolbar = toolbar;
if( isMacOS_11_orLater ) {
nsWindow.toolbarStyle = (buttonsSpacing == SPACING_LARGE)
? NSWindowToolbarStyleUnified
: (buttonsSpacing == SPACING_MEDIUM)
? NSWindowToolbarStyleUnifiedCompact
: NSWindowToolbarStyleAutomatic;
}
windowData.lastWindowButtonAreaWidth = 0;
windowData.lastWindowTitleBarHeight = 0;
// NSLog( @"\n%@\n\n", [nsWindow.contentView.superview _subtreeDescription] );
// when window becomes full screen, it is necessary to hide the toolbar
// because it otherwise is shown non-transparent and hides Swing components
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
if( needsToolbar && windowData.willEnterFullScreenObserver == NULL ) {
// NSLog( @"add observers %@", nsWindow );
windowData.willEnterFullScreenObserver = [center addObserverForName:NSWindowWillEnterFullScreenNotification
object:nsWindow queue:nil usingBlock:^(NSNotification *note) {
// NSLog( @"enter full screen %@", nsWindow );
if( nsWindow.toolbar != NULL ) {
// remember button area width, which is used later when window exits full screen
// remembar title bar height so that "main" JToolBar keeps its height in full screen
windowData.lastWindowButtonAreaWidth = getWindowButtonAreaWidth( nsWindow );
windowData.lastWindowTitleBarHeight = getWindowTitleBarHeight( nsWindow );
// NSLog( @"%d %d", windowData.lastWindowButtonAreaWidth, windowData.lastWindowTitleBarHeight );
nsWindow.toolbar.visible = NO;
}
}];
windowData.willExitFullScreenObserver = [center addObserverForName:NSWindowWillExitFullScreenNotification
object:nsWindow queue:nil usingBlock:^(NSNotification *note) {
// NSLog( @"will exit full screen %@", nsWindow );
if( nsWindow.toolbar != NULL )
setWindowButtonsHidden( nsWindow, true );
}];
windowData.didExitFullScreenObserver = [center addObserverForName:NSWindowDidExitFullScreenNotification
object:nsWindow queue:nil usingBlock:^(NSNotification *note) {
// NSLog( @"exit full screen %@", nsWindow );
if( nsWindow.toolbar != NULL ) {
setWindowButtonsHidden( nsWindow, false );
nsWindow.toolbar.visible = YES;
}
windowData.lastWindowButtonAreaWidth = 0;
windowData.lastWindowTitleBarHeight = 0;
}];
} else if( !needsToolbar ) {
// NSLog( @"remove observers %@", nsWindow );
if( windowData.willEnterFullScreenObserver != NULL ) {
[center removeObserver:windowData.willEnterFullScreenObserver];
windowData.willEnterFullScreenObserver = nil;
}
if( windowData.willExitFullScreenObserver != NULL ) {
[center removeObserver:windowData.willExitFullScreenObserver];
windowData.willExitFullScreenObserver = nil;
}
if( windowData.didExitFullScreenObserver != NULL ) {
[center removeObserver:windowData.didExitFullScreenObserver];
windowData.didExitFullScreenObserver = nil;
}
}
}];
return TRUE;
JNI_COCOA_EXIT()
return FALSE;
}
void setWindowButtonsHidden( NSWindow* nsWindow, bool hidden ) {
// get buttons
NSView* buttons[3] = {
[nsWindow standardWindowButton:NSWindowCloseButton],
[nsWindow standardWindowButton:NSWindowMiniaturizeButton],
[nsWindow standardWindowButton:NSWindowZoomButton]
};
for( int i = 0; i < 3; i++ ) {
NSView* button = buttons[i];
if( button != NULL )
button.hidden = hidden;
}
}
extern "C"
JNIEXPORT jobject JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_getWindowButtonsBounds
( JNIEnv* env, jclass cls, jobject window )
{
JNI_COCOA_ENTER()
NSWindow* nsWindow = getNSWindow( env, cls, window );
if( nsWindow == NULL )
return NULL;
WindowData* windowData = getWindowData( nsWindow, false );
int width = 0;
int height = 0;
// get width
if( isWindowFullScreen( nsWindow ) ) {
// use zero if window is full screen because close/minimize/zoom buttons are hidden
width = 0;
} else if( windowData != NULL && windowData.lastWindowButtonAreaWidth > 0 ) {
// use remembered value if window is in transition from full screen to non-full screen
// because NSToolbar is not yet visible
width = windowData.lastWindowButtonAreaWidth;
} else
width = getWindowButtonAreaWidth( nsWindow );
// get height
if( windowData != NULL && windowData.lastWindowTitleBarHeight > 0 ) {
// use remembered value if window is full screen because NSToolbar is hidden
height = windowData.lastWindowTitleBarHeight;
} else
height = getWindowTitleBarHeight( nsWindow );
// initialize class and method ID (done only once because variables are static)
static jclass cls = findClass( env, "java/awt/Rectangle", true );
static jmethodID methodID = getMethodID( env, cls, "<init>", "(IIII)V", false );
if( cls == NULL || methodID == NULL )
return NULL;
// create and return Rectangle
return env->NewObject( cls, methodID, 0, 0, width, height );
JNI_COCOA_EXIT()
return NULL;
}
int getWindowButtonAreaWidth( NSWindow* nsWindow ) {
// get buttons
NSView* buttons[3] = {
[nsWindow standardWindowButton:NSWindowCloseButton],
[nsWindow standardWindowButton:NSWindowMiniaturizeButton],
[nsWindow standardWindowButton:NSWindowZoomButton]
};
// get most left and right coordinates
int left = -1;
int right = -1;
for( int i = 0; i < 3; i++ ) {
NSView* button = buttons[i];
if( button == NULL )
continue;
int x = [button convertRect: [button bounds] toView:button.superview].origin.x;
int width = button.bounds.size.width;
if( left == -1 || x < left )
left = x;
if( right == -1 || x + width > right )
right = x + width;
}
if( left == -1 || right == -1 )
return -1;
// 'right' is the actual button area width (from left window edge)
// adding 'left' to add same empty space on right side as on left side
return right + left;
}
int getWindowTitleBarHeight( NSWindow* nsWindow ) {
NSView* closeButton = [nsWindow standardWindowButton:NSWindowCloseButton];
if( closeButton == NULL )
return -1;
NSView* titlebar = closeButton.superview;
return titlebar.bounds.size.height;
}
extern "C"
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_isWindowFullScreen
( JNIEnv* env, jclass cls, jobject window )
{
JNI_COCOA_ENTER()
NSWindow* nsWindow = getNSWindow( env, cls, window );
if( nsWindow == NULL )
return FALSE;
return (jboolean) isWindowFullScreen( nsWindow );
JNI_COCOA_EXIT()
return FALSE;
}
bool isWindowFullScreen( NSWindow* nsWindow ) {
return ((nsWindow.styleMask & NSWindowStyleMaskFullScreen) != 0);
}
extern "C"
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_toggleWindowFullScreen
( JNIEnv* env, jclass cls, jobject window )
{
JNI_COCOA_ENTER()
NSWindow* nsWindow = getNSWindow( env, cls, window );
if( nsWindow == NULL )
return FALSE;
[FlatJNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
[nsWindow toggleFullScreen:nil];
}];
return TRUE;
JNI_COCOA_EXIT()
return FALSE;
}

View File

@@ -41,6 +41,8 @@ dependencies {
implementation( libs.jide.oss )
implementation( libs.glazedlists )
implementation( libs.netbeans.api.awt )
components.all<TargetJvmVersion8Rule>()
}
applyLafs()
@@ -58,3 +60,13 @@ fun applyLafs() {
dependencies.implementation( parts[2] )
}
}
// rule that overrides 'org.gradle.jvm.version' with '8'
// (required for Radiance, which requires Java 9, but FlatLaf build uses Java 8)
abstract class TargetJvmVersion8Rule : ComponentMetadataRule {
override fun execute( context: ComponentMetadataContext ) {
context.details.allVariants {
attributes.attribute( TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8 )
}
}
}

View File

@@ -1111,6 +1111,7 @@ Table.dropCellBackground [lazy] #3c588b HSL 219 40 39 javax.swing.pl
Table.dropCellForeground [lazy] #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineColor [lazy] #6d8ac0 HSL 219 40 59 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineShortColor [lazy] #b4c3df HSL 219 40 79 javax.swing.plaf.ColorUIResource [UI]
Table.editorSelectAllOnStartEditing true
Table.focusCellBackground #46494b HSL 204 3 28 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellHighlightBorder [lazy] 2,3,2,3 false com.formdev.flatlaf.ui.FlatTableCellBorder$Focused [UI] lineColor=#6d8ac0 HSL 219 40 59 javax.swing.plaf.ColorUIResource [UI] lineThickness=1.000000
@@ -1119,6 +1120,7 @@ Table.font [active] $defaultFont [UI]
Table.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
Table.gridColor #5a5e60 HSL 200 3 36 javax.swing.plaf.ColorUIResource [UI]
Table.intercellSpacing 0,0 javax.swing.plaf.DimensionUIResource [UI]
Table.paintOutsideAlternateRows false
Table.rowHeight 20
Table.scrollPaneBorder [lazy] 1,1,1,1 false com.formdev.flatlaf.ui.FlatScrollPaneBorder [UI]
Table.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
@@ -1264,7 +1266,6 @@ TitlePane.inactiveBackground #303234 HSL 210 4 20 javax.swing.plaf.Colo
TitlePane.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8

View File

@@ -1116,6 +1116,7 @@ Table.dropCellBackground [lazy] #3f8fd9 HSL 209 67 55 javax.swing.pl
Table.dropCellForeground [lazy] #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineColor [lazy] #6aa7e1 HSL 209 66 65 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineShortColor [lazy] #15416a HSL 209 67 25 javax.swing.plaf.ColorUIResource [UI]
Table.editorSelectAllOnStartEditing true
Table.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellForeground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellHighlightBorder [lazy] 2,3,2,3 false com.formdev.flatlaf.ui.FlatTableCellBorder$Focused [UI] lineColor=#15416a HSL 209 67 25 javax.swing.plaf.ColorUIResource [UI] lineThickness=1.000000
@@ -1124,6 +1125,7 @@ Table.font [active] $defaultFont [UI]
Table.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
Table.gridColor #ebebeb HSL 0 0 92 javax.swing.plaf.ColorUIResource [UI]
Table.intercellSpacing 0,0 javax.swing.plaf.DimensionUIResource [UI]
Table.paintOutsideAlternateRows false
Table.rowHeight 20
Table.scrollPaneBorder [lazy] 1,1,1,1 false com.formdev.flatlaf.ui.FlatScrollPaneBorder [UI]
Table.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
@@ -1269,7 +1271,6 @@ TitlePane.inactiveBackground #ffffff HSL 0 0 100 javax.swing.plaf.Colo
TitlePane.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8

View File

@@ -322,7 +322,7 @@ OS Windows 10
#---- javax.swing.JMenuBar ----
1 javax.swing.plaf.basic.LazyActionMap [UI]
takeFocus com.formdev.flatlaf.ui.FlatMenuBarUI$TakeFocus (null)
takeFocus com.formdev.flatlaf.ui.FlatMenuBarUI$TakeFocusAction
#---- javax.swing.JMenuItem ----
@@ -613,7 +613,7 @@ OS Windows 10
selectPreviousRowCell javax.swing.plaf.basic.BasicTableUI$Actions
selectPreviousRowChangeLead javax.swing.plaf.basic.BasicTableUI$Actions
selectPreviousRowExtendSelection javax.swing.plaf.basic.BasicTableUI$Actions
startEditing javax.swing.plaf.basic.BasicTableUI$Actions
startEditing com.formdev.flatlaf.ui.FlatTableUI$StartEditingAction
toggleAndAnchor javax.swing.plaf.basic.BasicTableUI$Actions

View File

@@ -1121,6 +1121,7 @@ Table.dropCellBackground [lazy] #003f99 HSL 215 100 30 javax.swing.pl
Table.dropCellForeground [lazy] #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineColor [lazy] #0069ff HSL 215 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineShortColor [lazy] #66a5ff HSL 215 100 70 javax.swing.plaf.ColorUIResource [UI]
Table.editorSelectAllOnStartEditing true
Table.focusCellBackground #282828 HSL 0 0 16 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellForeground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellHighlightBorder [lazy] 2,3,2,3 false com.formdev.flatlaf.ui.FlatTableCellBorder$Focused [UI] lineColor=#0069ff HSL 215 100 50 javax.swing.plaf.ColorUIResource [UI] lineThickness=1.000000
@@ -1129,6 +1130,7 @@ Table.font [active] $defaultFont [UI]
Table.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
Table.gridColor #3c3c3c HSL 0 0 24 javax.swing.plaf.ColorUIResource [UI]
Table.intercellSpacing 0,0 javax.swing.plaf.DimensionUIResource [UI]
Table.paintOutsideAlternateRows false
Table.rowHeight 20
Table.scrollPaneBorder [lazy] 3,3,3,3 false com.formdev.flatlaf.ui.FlatScrollPaneBorder [UI]
Table.selectionBackground #0054cc HSL 215 100 40 javax.swing.plaf.ColorUIResource [UI]
@@ -1274,7 +1276,6 @@ TitlePane.inactiveBackground #323232 HSL 0 0 20 javax.swing.plaf.Colo
TitlePane.inactiveForeground #9a9a9a HSL 0 0 60 javax.swing.plaf.ColorUIResource [UI]
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8

View File

@@ -1125,6 +1125,7 @@ Table.dropCellBackground [lazy] #1a79ff HSL 215 100 55 javax.swing.pl
Table.dropCellForeground [lazy] #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineColor [lazy] #4d97ff HSL 215 100 65 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineShortColor [lazy] #003580 HSL 215 100 25 javax.swing.plaf.ColorUIResource [UI]
Table.editorSelectAllOnStartEditing true
Table.focusCellBackground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellForeground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellHighlightBorder [lazy] 2,3,2,3 false com.formdev.flatlaf.ui.FlatTableCellBorder$Focused [UI] lineColor=#003580 HSL 215 100 25 javax.swing.plaf.ColorUIResource [UI] lineThickness=1.000000
@@ -1133,6 +1134,7 @@ Table.font [active] $defaultFont [UI]
Table.foreground #262626 HSL 0 0 15 javax.swing.plaf.ColorUIResource [UI]
Table.gridColor #ebebeb HSL 0 0 92 javax.swing.plaf.ColorUIResource [UI]
Table.intercellSpacing 0,0 javax.swing.plaf.DimensionUIResource [UI]
Table.paintOutsideAlternateRows false
Table.rowHeight 20
Table.scrollPaneBorder [lazy] 3,3,3,3 false com.formdev.flatlaf.ui.FlatScrollPaneBorder [UI]
Table.selectionBackground #005fe6 HSL 215 100 45 javax.swing.plaf.ColorUIResource [UI]
@@ -1278,7 +1280,6 @@ TitlePane.inactiveBackground #ececec HSL 0 0 93 javax.swing.plaf.Colo
TitlePane.inactiveForeground #b6b6b6 HSL 0 0 71 javax.swing.plaf.ColorUIResource [UI]
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8

View File

@@ -1149,6 +1149,7 @@ Table.dropCellBackground #ff0000 HSL 0 100 50 javax.swing.plaf.Colo
Table.dropCellForeground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.dropLineShortColor #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.editorSelectAllOnStartEditing true
Table.focusCellBackground #fffff0 HSL 60 100 97 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellForeground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.focusCellHighlightBorder [lazy] 2,3,2,3 false com.formdev.flatlaf.ui.FlatTableCellBorder$Focused [UI] lineColor=#ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] lineThickness=1.000000
@@ -1157,6 +1158,7 @@ Table.font [active] $defaultFont [UI]
Table.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.gridColor #00ffff HSL 180 100 50 javax.swing.plaf.ColorUIResource [UI]
Table.intercellSpacing 0,0 javax.swing.plaf.DimensionUIResource [UI]
Table.paintOutsideAlternateRows false
Table.rowHeight 25
Table.scrollPaneBorder [lazy] 1,9,1,9 false com.formdev.flatlaf.ui.FlatScrollPaneBorder [UI]
Table.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
@@ -1305,7 +1307,6 @@ TitlePane.inactiveBackground #008800 HSL 120 100 27 javax.swing.plaf.Colo
TitlePane.inactiveForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8

View File

@@ -1,5 +1,9 @@
org.pushingpixels.substance.api.skin.SubstanceBusinessLookAndFeel = Substance Business;ctrl F5;org.pushing-pixels:radiance-substance:3.5.1
org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel = Substance Graphite Aqua;ctrl F6
com.alee.laf.WebLookAndFeel = WebLaf;ctrl F11;com.weblookandfeel:weblaf-ui:1.2.13
org.pushingpixels.radiance.theming.api.skin.RadianceBusinessLookAndFeel = Radiance Business;ctrl F5;org.pushing-pixels:radiance-theming:7.0.1
org.pushingpixels.radiance.theming.api.skin.RadianceGraphiteAquaLookAndFeel = Radiance Graphite Aqua;ctrl F6
com.alee.laf.WebLookAndFeel = WebLaf;ctrl F11;com.weblookandfeel:weblaf-ui:1.2.14
com.jgoodies.looks.plastic.PlasticLookAndFeel = JGoodies Looks Plastic;ctrl F12;com.jgoodies:jgoodies-looks:2.7.0
com.jgoodies.looks.windows.WindowsLookAndFeel = JGoodies Looks Windows;ctrl F9
mdlaf.MaterialLookAndFeel = Material-UI-Swing;shift F11;io.github.vincenzopalazzo:material-ui-swing:1.1.4
com.github.weisj.darklaf.DarkLaf = DarkLaf;shift F12;com.github.weisj:darklaf-core:3.0.2
com.github.weisj.darklaf.theme.laf.DarculaThemeDarklafLookAndFeel = DarkLaf Darcula;ctrl shift F12
com.jtattoo.plaf.smart.SmartLookAndFeel = JTattoo;ctrl shift F11;com.jtattoo:JTattoo:1.6.13

View File

@@ -1,221 +0,0 @@
/*
* Copyright 2019 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Function;
import javax.swing.*;
import javax.swing.border.*;
import com.formdev.flatlaf.icons.FlatFileChooserHomeFolderIcon;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatChooserTest
extends FlatTestPanel
{
public static void main( String[] args ) {
// Locale.setDefault( Locale.FRENCH );
// Locale.setDefault( Locale.GERMAN );
// Locale.setDefault( Locale.ITALIAN );
// Locale.setDefault( Locale.JAPANESE );
// Locale.setDefault( Locale.SIMPLIFIED_CHINESE );
// Locale.setDefault( Locale.TRADITIONAL_CHINESE );
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatChooserTest" );
UIManager.put( "FileChooser.shortcuts.filesFunction", (Function<File[], File[]>) files -> {
ArrayList<File> list = new ArrayList<>( Arrays.asList( files ) );
list.add( 0, new File( System.getProperty( "user.home" ) ) );
return list.toArray( new File[list.size()] );
} );
UIManager.put( "FileChooser.shortcuts.displayNameFunction", (Function<File, String>) file -> {
if( file.getAbsolutePath().equals( System.getProperty( "user.home" ) ) )
return "Home";
return null;
} );
UIManager.put( "FileChooser.shortcuts.iconFunction", (Function<File, Icon>) file -> {
if( file.getAbsolutePath().equals( System.getProperty( "user.home" ) ) )
return new FlatFileChooserHomeFolderIcon();
return null;
} );
frame.showFrame( FlatChooserTest::new );
} );
}
FlatChooserTest() {
initComponents();
}
private void showShortcuts() {
UIManager.put( "FileChooser.noPlacesBar", !showShortcutsCheckBox.isSelected() ? true : null );
fileChooser1.updateUI();
}
private void showAccessory() {
JPanel accessory = null;
if( showAccessoryCheckBox.isSelected() ) {
accessory = new JPanel( new BorderLayout() );
accessory.setBackground( Color.green );
accessory.add( new JLabel( " Accessory " ), BorderLayout.CENTER );
}
fileChooser1.setAccessory( accessory );
fileChooser1.revalidate();
fileChooser1.repaint();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel colorChooserLabel = new JLabel();
JPanel panel2 = new JPanel();
JColorChooser colorChooser1 = new JColorChooser();
JLabel fileChooserLabel = new JLabel();
JPanel panel1 = new JPanel();
fileChooser1 = new JFileChooser();
JPanel panel3 = new JPanel();
showShortcutsCheckBox = new JCheckBox();
showAccessoryCheckBox = new JCheckBox();
JLabel label1 = new JLabel();
JLabel label2 = new JLabel();
JLabel label3 = new JLabel();
JLabel label4 = new JLabel();
JLabel label5 = new JLabel();
JLabel label6 = new JLabel();
JLabel label7 = new JLabel();
JLabel label8 = new JLabel();
JLabel label9 = new JLabel();
JLabel label10 = new JLabel();
JLabel label11 = new JLabel();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]" +
"[grow]",
// rows
"[top]" +
"[grow,fill]" +
"[]" +
"[]"));
//---- colorChooserLabel ----
colorChooserLabel.setText("JColorChooser:");
add(colorChooserLabel, "cell 0 0");
//======== panel2 ========
{
panel2.setBorder(new MatteBorder(4, 4, 4, 4, Color.red));
panel2.setLayout(new BorderLayout());
panel2.add(colorChooser1, BorderLayout.CENTER);
}
add(panel2, "cell 1 0");
//---- fileChooserLabel ----
fileChooserLabel.setText("JFileChooser:");
add(fileChooserLabel, "cell 0 1,aligny top,growy 0");
//======== panel1 ========
{
panel1.setBorder(new MatteBorder(4, 4, 4, 4, Color.red));
panel1.setLayout(new BorderLayout());
panel1.add(fileChooser1, BorderLayout.CENTER);
}
add(panel1, "cell 1 1,growx");
//======== panel3 ========
{
panel3.setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
"[fill]",
// rows
"[]"));
//---- showShortcutsCheckBox ----
showShortcutsCheckBox.setText("Show Shortcuts");
showShortcutsCheckBox.setSelected(true);
showShortcutsCheckBox.addActionListener(e -> showShortcuts());
panel3.add(showShortcutsCheckBox, "cell 0 0");
//---- showAccessoryCheckBox ----
showAccessoryCheckBox.setText("Show Accessory");
showAccessoryCheckBox.addActionListener(e -> showAccessory());
panel3.add(showAccessoryCheckBox, "cell 1 0");
}
add(panel3, "cell 1 2");
//---- label1 ----
label1.setText("icons:");
add(label1, "cell 0 3");
//---- label2 ----
label2.setIcon(UIManager.getIcon("FileView.directoryIcon"));
add(label2, "cell 1 3");
//---- label3 ----
label3.setIcon(UIManager.getIcon("FileView.fileIcon"));
add(label3, "cell 1 3");
//---- label4 ----
label4.setIcon(UIManager.getIcon("FileView.computerIcon"));
add(label4, "cell 1 3");
//---- label5 ----
label5.setIcon(UIManager.getIcon("FileView.hardDriveIcon"));
add(label5, "cell 1 3");
//---- label6 ----
label6.setIcon(UIManager.getIcon("FileView.floppyDriveIcon"));
add(label6, "cell 1 3");
//---- label7 ----
label7.setIcon(UIManager.getIcon("FileChooser.newFolderIcon"));
add(label7, "cell 1 3");
//---- label8 ----
label8.setIcon(UIManager.getIcon("FileChooser.upFolderIcon"));
add(label8, "cell 1 3");
//---- label9 ----
label9.setIcon(UIManager.getIcon("FileChooser.homeFolderIcon"));
add(label9, "cell 1 3");
//---- label10 ----
label10.setIcon(UIManager.getIcon("FileChooser.detailsViewIcon"));
add(label10, "cell 1 3");
//---- label11 ----
label11.setIcon(UIManager.getIcon("FileChooser.listViewIcon"));
add(label11, "cell 1 3");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JFileChooser fileChooser1;
private JCheckBox showShortcutsCheckBox;
private JCheckBox showAccessoryCheckBox;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -1,153 +0,0 @@
JFDML JFormDesigner: "8.0.0.0.194" Java: "17.0.2" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][grow]"
"$rowConstraints": "[top][grow,fill][][]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "colorChooserLabel"
"text": "JColorChooser:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "panel2"
"border": new javax.swing.border.MatteBorder( 4, 4, 4, 4, sfield java.awt.Color red )
add( new FormComponent( "javax.swing.JColorChooser" ) {
name: "colorChooser1"
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fileChooserLabel"
"text": "JFileChooser:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1,aligny top,growy 0"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "panel1"
"border": new javax.swing.border.MatteBorder( 4, 4, 4, 4, sfield java.awt.Color red )
add( new FormComponent( "javax.swing.JFileChooser" ) {
name: "fileChooser1"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1,growx"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill]"
"$rowConstraints": "[]"
} ) {
name: "panel3"
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showShortcutsCheckBox"
"text": "Show Shortcuts"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showShortcuts", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showAccessoryCheckBox"
"text": "Show Accessory"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showAccessory", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "icons:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
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 3"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 790, 790 )
} )
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2019 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatColorChooserTest
extends FlatTestPanel
{
public static void main( String[] args ) {
// Locale.setDefault( Locale.FRENCH );
// Locale.setDefault( Locale.GERMAN );
// Locale.setDefault( Locale.ITALIAN );
// Locale.setDefault( Locale.JAPANESE );
// Locale.setDefault( Locale.SIMPLIFIED_CHINESE );
// Locale.setDefault( Locale.TRADITIONAL_CHINESE );
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatColorChooserTest" );
frame.showFrame( FlatColorChooserTest::new );
} );
}
FlatColorChooserTest() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel colorChooserLabel = new JLabel();
JPanel panel2 = new JPanel();
JColorChooser colorChooser1 = new JColorChooser();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]" +
"[grow]",
// rows
"[top]"));
//---- colorChooserLabel ----
colorChooserLabel.setText("JColorChooser:");
add(colorChooserLabel, "cell 0 0");
//======== panel2 ========
{
panel2.setBorder(new MatteBorder(4, 4, 4, 4, Color.red));
panel2.setLayout(new BorderLayout());
panel2.add(colorChooser1, BorderLayout.CENTER);
}
add(panel2, "cell 1 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,37 @@
JFDML JFormDesigner: "8.2.0.0.331" Java: "21" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][grow]"
"$rowConstraints": "[top]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "colorChooserLabel"
"text": "JColorChooser:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "panel2"
"border": new javax.swing.border.MatteBorder( 4, 4, 4, 4, sfield java.awt.Color red )
add( new FormComponent( "javax.swing.JColorChooser" ) {
name: "colorChooser1"
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 790, 790 )
} )
}
}

View File

@@ -0,0 +1,556 @@
/*
* Copyright 2019 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.function.Function;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatFileChooserHomeFolderIcon;
import com.formdev.flatlaf.ui.JavaCompatibility2;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatFileChooserTest
extends FlatTestPanel
{
public static void main( String[] args ) {
// Locale.setDefault( Locale.FRENCH );
// Locale.setDefault( Locale.GERMAN );
// Locale.setDefault( Locale.ITALIAN );
// Locale.setDefault( Locale.JAPANESE );
// Locale.setDefault( Locale.SIMPLIFIED_CHINESE );
// Locale.setDefault( Locale.TRADITIONAL_CHINESE );
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatFileChooserTest" );
UIManager.put( "FileChooser.shortcuts.filesFunction", (Function<File[], File[]>) files -> {
ArrayList<File> list = new ArrayList<>( Arrays.asList( files ) );
list.add( 0, new File( System.getProperty( "user.home" ) ) );
return list.toArray( new File[list.size()] );
} );
UIManager.put( "FileChooser.shortcuts.displayNameFunction", (Function<File, String>) file -> {
if( file.getAbsolutePath().equals( System.getProperty( "user.home" ) ) )
return "Home";
return null;
} );
UIManager.put( "FileChooser.shortcuts.iconFunction", (Function<File, Icon>) file -> {
if( file.getAbsolutePath().equals( System.getProperty( "user.home" ) ) )
return new FlatFileChooserHomeFolderIcon();
return null;
} );
frame.showFrame( FlatFileChooserTest::new );
} );
}
FlatFileChooserTest() {
initComponents();
dialogTypeField.init( DialogType.class, false );
fileSelectionModeField.init( FileSelectionMode.class, false );
localesField.init( Locales.class, false );
showControlButtonsCheckBox.setSelected( fileChooser1.getControlButtonsAreShown() );
multiSelectionCheckBox.setSelected( fileChooser1.isMultiSelectionEnabled() );
fileHidingCheckBox.setSelected( fileChooser1.isFileHidingEnabled() );
dragCheckBox.setSelected( fileChooser1.getDragEnabled() );
filterAllFilesCheckBox.setSelected( fileChooser1.isAcceptAllFileFilterUsed() );
updateOutput();
}
private void fileChooser1PropertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case JFileChooser.DIRECTORY_CHANGED_PROPERTY:
case JFileChooser.SELECTED_FILE_CHANGED_PROPERTY:
case JFileChooser.SELECTED_FILES_CHANGED_PROPERTY:
updateOutput();
break;
}
}
private void updateOutput() {
currentDirectoryField.setText( String.valueOf( fileChooser1.getCurrentDirectory() ) );
selectedFileField.setText( String.valueOf( fileChooser1.getSelectedFile() ) );
selectedFilesField.setText( Arrays.toString( fileChooser1.getSelectedFiles() ) );
}
private void dialogTypeChanged() {
DialogType value = dialogTypeField.getSelectedValue();
int dialogType = (value != null) ? value.value : JFileChooser.OPEN_DIALOG;
if( dialogType == JFileChooser.CUSTOM_DIALOG )
fileChooser1.setApproveButtonText( "Custom" );
fileChooser1.setDialogType( dialogType );
}
private void fileSelectionModeChanged() {
FileSelectionMode value = fileSelectionModeField.getSelectedValue();
int mode = (value != null) ? value.value : JFileChooser.FILES_ONLY;
fileChooser1.setFileSelectionMode( mode );
}
private void showControlButtons() {
fileChooser1.setControlButtonsAreShown( showControlButtonsCheckBox.isSelected() );
fileChooser1.revalidate();
fileChooser1.repaint();
}
private void showShortcuts() {
UIManager.put( "FileChooser.noPlacesBar", !showShortcutsCheckBox.isSelected() ? true : null );
fileChooser1.updateUI();
}
private void showAccessory() {
JPanel accessory = null;
if( showAccessoryCheckBox.isSelected() ) {
accessory = new JPanel( new BorderLayout() );
accessory.setBackground( Color.green );
accessory.add( new JLabel( " Accessory " ), BorderLayout.CENTER );
}
fileChooser1.setAccessory( accessory );
fileChooser1.revalidate();
fileChooser1.repaint();
}
private void multiSelection() {
fileChooser1.setMultiSelectionEnabled( multiSelectionCheckBox.isSelected() );
}
private void fileHiding() {
fileChooser1.setFileHidingEnabled( fileHidingCheckBox.isSelected() );
}
private void drag() {
fileChooser1.setDragEnabled( dragCheckBox.isSelected() );
}
private final FileFilter TEXT_FILTER = new FileNameExtensionFilter( "Text Files", "txt", "md" );
private final FileFilter IMAGES_FILTER = new FileNameExtensionFilter( "Images", "png", "git", "jpg", "jpeg" );
private final FileFilter LONG_DESC_FILTER = new FileNameExtensionFilter( "Some long description (.abc, .def, .ghi, .jkl)", "dummy" );
private final FileFilter EXTRA_LONG_DESC_FILTER = new FileNameExtensionFilter( "Some super extra long description (.abc, .def, .ghi, .jkl, .mno, .pqr, .stu)", "dummy" );
private void filterChanged() {
boolean all = filterAllFilesCheckBox.isSelected();
if( all != fileChooser1.isAcceptAllFileFilterUsed() )
fileChooser1.setAcceptAllFileFilterUsed( all );
addRemoveFilter( filterTextFilesCheckBox.isSelected(), TEXT_FILTER );
addRemoveFilter( filterImagesCheckBox.isSelected(), IMAGES_FILTER );
addRemoveFilter( filterLongDescCheckBox.isSelected(), LONG_DESC_FILTER );
addRemoveFilter( filterExtraLongDescCheckBox.isSelected(), EXTRA_LONG_DESC_FILTER );
}
private void addRemoveFilter( boolean add, FileFilter filter ) {
if( add )
fileChooser1.addChoosableFileFilter( filter );
else
fileChooser1.removeChoosableFileFilter( filter );
}
private void localesChanged() {
Locales value = localesField.getSelectedValue();
Locale locale = (value != null) ? value.value : Locale.ENGLISH;
SwingUtilities.invokeLater( () -> {
Locale.setDefault( locale );
JComponent.setDefaultLocale( locale );
fileChooser1.setLocale( locale );
ResourceBundle.clearCache();
try {
UIManager.setLookAndFeel( UIManager.getLookAndFeel().getClass().getName() );
FlatLaf.updateUI();
} catch( Exception ex ) {
ex.printStackTrace();
}
} );
}
private void printShortcutFiles() {
printFiles( JavaCompatibility2.getChooserShortcutPanelFiles( fileChooser1.getFileSystemView() ) );
}
private void printComboBoxFiles() {
printFiles( JavaCompatibility2.getChooserComboBoxFiles( fileChooser1.getFileSystemView() ) );
}
private void printRoots() {
FileSystemView fsv = fileChooser1.getFileSystemView();
File[] roots = fsv.getRoots();
printFiles( roots );
for( File root : roots )
printFiles( fsv.getFiles( root, true ) );
}
private void printFiles( File[] files ) {
System.out.println( "--------------------------------" );
FileSystemView fsv = fileChooser1.getFileSystemView();
for( File file : files ) {
System.out.printf( "%-30s ", file );
System.out.println(
(fsv.isComputerNode( file ) ? "computer " : "") +
(fsv.isDrive( file ) ? "drive " : "") +
(fsv.isFileSystem( file ) ? "fileSystem " : "") +
(fsv.isFileSystemRoot( file ) ? "fileSystemRoot " : "") +
(fsv.isFloppyDrive( file ) ? "floppyDrive " : "") +
(fsv.isHiddenFile( file ) ? "hiddenFile " : "") +
(fsv.isRoot( file ) ? "root " : "") +
(fsv.isTraversable( file ) ? "traversable " : "") );
}
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel fileChooserLabel = new JLabel();
JPanel panel1 = new JPanel();
fileChooser1 = new JFileChooser();
JLabel currentDirectoryLabel = new JLabel();
currentDirectoryField = new JTextField();
JLabel selectedFileLabel = new JLabel();
selectedFileField = new JTextField();
JLabel selectedFilesLabel = new JLabel();
selectedFilesField = new JTextField();
JLabel dialogTypeLabel = new JLabel();
dialogTypeField = new FlatTestEnumSelector<>();
showControlButtonsCheckBox = new JCheckBox();
showShortcutsCheckBox = new JCheckBox();
showAccessoryCheckBox = new JCheckBox();
JLabel fileSelectionModeLabel = new JLabel();
fileSelectionModeField = new FlatTestEnumSelector<>();
multiSelectionCheckBox = new JCheckBox();
fileHidingCheckBox = new JCheckBox();
dragCheckBox = new JCheckBox();
JLabel filtersLabel = new JLabel();
filterAllFilesCheckBox = new JCheckBox();
filterTextFilesCheckBox = new JCheckBox();
filterImagesCheckBox = new JCheckBox();
filterLongDescCheckBox = new JCheckBox();
filterExtraLongDescCheckBox = new JCheckBox();
printShortcutFilesButton = new JButton();
printComboBoxFilesButton = new JButton();
printRootsButton = new JButton();
JLabel localesLabel = new JLabel();
localesField = new FlatTestEnumSelector<>();
JLabel label1 = new JLabel();
JLabel label2 = new JLabel();
JLabel label3 = new JLabel();
JLabel label4 = new JLabel();
JLabel label5 = new JLabel();
JLabel label6 = new JLabel();
JLabel label7 = new JLabel();
JLabel label8 = new JLabel();
JLabel label9 = new JLabel();
JLabel label10 = new JLabel();
JLabel label11 = new JLabel();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[]" +
"[]" +
"[grow]",
// rows
"[grow,fill]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]para" +
"[]"));
//---- fileChooserLabel ----
fileChooserLabel.setText("JFileChooser:");
add(fileChooserLabel, "cell 0 0,aligny top,growy 0");
//======== panel1 ========
{
panel1.setBorder(new MatteBorder(4, 4, 4, 4, Color.red));
panel1.setLayout(new BorderLayout());
//---- fileChooser1 ----
fileChooser1.addPropertyChangeListener(e -> fileChooser1PropertyChange(e));
panel1.add(fileChooser1, BorderLayout.CENTER);
}
add(panel1, "cell 1 0 2 1,growx");
//---- currentDirectoryLabel ----
currentDirectoryLabel.setText("Current Directory:");
add(currentDirectoryLabel, "cell 0 1");
//---- currentDirectoryField ----
currentDirectoryField.setEditable(false);
add(currentDirectoryField, "cell 1 1 2 1,growx");
//---- selectedFileLabel ----
selectedFileLabel.setText("Selected File:");
add(selectedFileLabel, "cell 0 2");
//---- selectedFileField ----
selectedFileField.setEditable(false);
add(selectedFileField, "cell 1 2 2 1,growx");
//---- selectedFilesLabel ----
selectedFilesLabel.setText("Selected Files:");
add(selectedFilesLabel, "cell 0 3");
//---- selectedFilesField ----
selectedFilesField.setEditable(false);
add(selectedFilesField, "cell 1 3 2 1,growx");
//---- dialogTypeLabel ----
dialogTypeLabel.setText("Dialog Type:");
add(dialogTypeLabel, "cell 0 4");
//---- dialogTypeField ----
dialogTypeField.addActionListener(e -> dialogTypeChanged());
add(dialogTypeField, "cell 1 4");
//---- showControlButtonsCheckBox ----
showControlButtonsCheckBox.setText("Show Control Buttons");
showControlButtonsCheckBox.addActionListener(e -> showControlButtons());
add(showControlButtonsCheckBox, "cell 2 4");
//---- showShortcutsCheckBox ----
showShortcutsCheckBox.setText("Show Shortcuts");
showShortcutsCheckBox.setSelected(true);
showShortcutsCheckBox.addActionListener(e -> showShortcuts());
add(showShortcutsCheckBox, "cell 2 4");
//---- showAccessoryCheckBox ----
showAccessoryCheckBox.setText("Show Accessory");
showAccessoryCheckBox.addActionListener(e -> showAccessory());
add(showAccessoryCheckBox, "cell 2 4");
//---- fileSelectionModeLabel ----
fileSelectionModeLabel.setText("File Selection Mode:");
add(fileSelectionModeLabel, "cell 0 5");
//---- fileSelectionModeField ----
fileSelectionModeField.addActionListener(e -> fileSelectionModeChanged());
add(fileSelectionModeField, "cell 1 5");
//---- multiSelectionCheckBox ----
multiSelectionCheckBox.setText("Multi Selection");
multiSelectionCheckBox.addActionListener(e -> multiSelection());
add(multiSelectionCheckBox, "cell 2 5");
//---- fileHidingCheckBox ----
fileHidingCheckBox.setText("File Hiding");
fileHidingCheckBox.addActionListener(e -> fileHiding());
add(fileHidingCheckBox, "cell 2 5");
//---- dragCheckBox ----
dragCheckBox.setText("Drag");
dragCheckBox.addActionListener(e -> drag());
add(dragCheckBox, "cell 2 5");
//---- filtersLabel ----
filtersLabel.setText("Filters:");
add(filtersLabel, "cell 0 6");
//---- filterAllFilesCheckBox ----
filterAllFilesCheckBox.setText("All Files");
filterAllFilesCheckBox.addActionListener(e -> filterChanged());
add(filterAllFilesCheckBox, "cell 1 6 2 1");
//---- filterTextFilesCheckBox ----
filterTextFilesCheckBox.setText("Text Files");
filterTextFilesCheckBox.addActionListener(e -> filterChanged());
add(filterTextFilesCheckBox, "cell 1 6 2 1");
//---- filterImagesCheckBox ----
filterImagesCheckBox.setText("Images");
filterImagesCheckBox.addActionListener(e -> filterChanged());
add(filterImagesCheckBox, "cell 1 6 2 1");
//---- filterLongDescCheckBox ----
filterLongDescCheckBox.setText("Long description");
filterLongDescCheckBox.addActionListener(e -> filterChanged());
add(filterLongDescCheckBox, "cell 1 6 2 1");
//---- filterExtraLongDescCheckBox ----
filterExtraLongDescCheckBox.setText("Extra Long description");
filterExtraLongDescCheckBox.addActionListener(e -> filterChanged());
add(filterExtraLongDescCheckBox, "cell 1 6 2 1");
//---- printShortcutFilesButton ----
printShortcutFilesButton.setText("Print Shortcut Files");
printShortcutFilesButton.addActionListener(e -> printShortcutFiles());
add(printShortcutFilesButton, "cell 1 7 2 1");
//---- printComboBoxFilesButton ----
printComboBoxFilesButton.setText("Print ComboBox Files");
printComboBoxFilesButton.addActionListener(e -> printComboBoxFiles());
add(printComboBoxFilesButton, "cell 1 7 2 1");
//---- printRootsButton ----
printRootsButton.setText("Print Roots");
printRootsButton.addActionListener(e -> printRoots());
add(printRootsButton, "cell 1 7 2 1");
//---- localesLabel ----
localesLabel.setText("Locales:");
add(localesLabel, "cell 0 8");
//---- localesField ----
localesField.addActionListener(e -> localesChanged());
add(localesField, "cell 1 8 2 1");
//---- label1 ----
label1.setText("icons:");
add(label1, "cell 0 9");
//---- label2 ----
label2.setIcon(UIManager.getIcon("FileView.directoryIcon"));
add(label2, "cell 1 9 2 1");
//---- label3 ----
label3.setIcon(UIManager.getIcon("FileView.fileIcon"));
add(label3, "cell 1 9 2 1");
//---- label4 ----
label4.setIcon(UIManager.getIcon("FileView.computerIcon"));
add(label4, "cell 1 9 2 1");
//---- label5 ----
label5.setIcon(UIManager.getIcon("FileView.hardDriveIcon"));
add(label5, "cell 1 9 2 1");
//---- label6 ----
label6.setIcon(UIManager.getIcon("FileView.floppyDriveIcon"));
add(label6, "cell 1 9 2 1");
//---- label7 ----
label7.setIcon(UIManager.getIcon("FileChooser.newFolderIcon"));
add(label7, "cell 1 9 2 1");
//---- label8 ----
label8.setIcon(UIManager.getIcon("FileChooser.upFolderIcon"));
add(label8, "cell 1 9 2 1");
//---- label9 ----
label9.setIcon(UIManager.getIcon("FileChooser.homeFolderIcon"));
add(label9, "cell 1 9 2 1");
//---- label10 ----
label10.setIcon(UIManager.getIcon("FileChooser.detailsViewIcon"));
add(label10, "cell 1 9 2 1");
//---- label11 ----
label11.setIcon(UIManager.getIcon("FileChooser.listViewIcon"));
add(label11, "cell 1 9 2 1");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JFileChooser fileChooser1;
private JTextField currentDirectoryField;
private JTextField selectedFileField;
private JTextField selectedFilesField;
private FlatTestEnumSelector<DialogType> dialogTypeField;
private JCheckBox showControlButtonsCheckBox;
private JCheckBox showShortcutsCheckBox;
private JCheckBox showAccessoryCheckBox;
private FlatTestEnumSelector<FileSelectionMode> fileSelectionModeField;
private JCheckBox multiSelectionCheckBox;
private JCheckBox fileHidingCheckBox;
private JCheckBox dragCheckBox;
private JCheckBox filterAllFilesCheckBox;
private JCheckBox filterTextFilesCheckBox;
private JCheckBox filterImagesCheckBox;
private JCheckBox filterLongDescCheckBox;
private JCheckBox filterExtraLongDescCheckBox;
private JButton printShortcutFilesButton;
private JButton printComboBoxFilesButton;
private JButton printRootsButton;
private FlatTestEnumSelector<Locales> localesField;
// JFormDesigner - End of variables declaration //GEN-END:variables
//---- enum DialogType ----------------------------------------------------
enum DialogType {
open( JFileChooser.OPEN_DIALOG ),
save( JFileChooser.SAVE_DIALOG ),
custom( JFileChooser.CUSTOM_DIALOG );
public final int value;
DialogType( int value ) {
this.value = value;
}
}
//---- enum FileSelectionMode ---------------------------------------------
enum FileSelectionMode {
files_only( JFileChooser.FILES_ONLY ),
directories_only( JFileChooser.DIRECTORIES_ONLY ),
files_and_directories( JFileChooser.FILES_AND_DIRECTORIES );
public final int value;
FileSelectionMode( int value ) {
this.value = value;
}
}
//---- enum Locales -------------------------------------------------------
// locales supported by Swing
// (see https://github.com/openjdk/jdk/tree/master/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources)
enum Locales {
english( Locale.ENGLISH ),
german( Locale.GERMAN ),
spanish( new Locale( "es" ) ),
french( Locale.FRENCH ),
italian( Locale.ITALIAN ),
japanese( Locale.JAPANESE ),
korean( Locale.KOREAN ),
brazilian_portuguese( new Locale( "pt", "BR" ) ),
swedish( new Locale( "sv" ) ),
simplified_chinese( Locale.SIMPLIFIED_CHINESE ),
traditional_chinese( Locale.TRADITIONAL_CHINESE );
public final Locale value;
Locales( Locale value ) {
this.value = value;
}
}
}

View File

@@ -0,0 +1,347 @@
JFDML JFormDesigner: "8.2.0.0.331" Java: "21" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[][][grow]"
"$rowConstraints": "[grow,fill][][][][][][][][]para[]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fileChooserLabel"
"text": "JFileChooser:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0,aligny top,growy 0"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "panel1"
"border": new javax.swing.border.MatteBorder( 4, 4, 4, 4, sfield java.awt.Color red )
add( new FormComponent( "javax.swing.JFileChooser" ) {
name: "fileChooser1"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.beans.PropertyChangeListener", "propertyChange", "fileChooser1PropertyChange", true ) )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0 2 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "currentDirectoryLabel"
"text": "Current Directory:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "currentDirectoryField"
"editable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1 2 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "selectedFileLabel"
"text": "Selected File:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "selectedFileField"
"editable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2 2 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "selectedFilesLabel"
"text": "Selected Files:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "selectedFilesField"
"editable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3 2 1,growx"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "dialogTypeLabel"
"text": "Dialog Type:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "com.formdev.flatlaf.testing.FlatTestEnumSelector" ) {
name: "dialogTypeField"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.typeParameters": "DialogType"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dialogTypeChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showControlButtonsCheckBox"
"text": "Show Control Buttons"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showControlButtons", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showShortcutsCheckBox"
"text": "Show Shortcuts"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showShortcuts", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showAccessoryCheckBox"
"text": "Show Accessory"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showAccessory", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 4"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fileSelectionModeLabel"
"text": "File Selection Mode:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
add( new FormComponent( "com.formdev.flatlaf.testing.FlatTestEnumSelector" ) {
name: "fileSelectionModeField"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.typeParameters": "FileSelectionMode"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fileSelectionModeChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "multiSelectionCheckBox"
"text": "Multi Selection"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "multiSelection", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 5"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "fileHidingCheckBox"
"text": "File Hiding"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fileHiding", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 5"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "dragCheckBox"
"text": "Drag"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "drag", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 5"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "filtersLabel"
"text": "Filters:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "filterAllFilesCheckBox"
"text": "All Files"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "filterTextFilesCheckBox"
"text": "Text Files"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "filterImagesCheckBox"
"text": "Images"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "filterLongDescCheckBox"
"text": "Long description"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "filterExtraLongDescCheckBox"
"text": "Extra Long description"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "filterChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "printShortcutFilesButton"
"text": "Print Shortcut Files"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "printShortcutFiles", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "printComboBoxFilesButton"
"text": "Print ComboBox Files"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "printComboBoxFiles", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "printRootsButton"
"text": "Print Roots"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "printRoots", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "localesLabel"
"text": "Locales:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 8"
} )
add( new FormComponent( "com.formdev.flatlaf.testing.FlatTestEnumSelector" ) {
name: "localesField"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
"JavaCodeGenerator.typeParameters": "Locales"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "localesChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 8 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "icons:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 9"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
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"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 715, 660 )
} )
}
}

View File

@@ -0,0 +1,291 @@
/*
* 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 javax.swing.*;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatNativeMacLibrary;
import com.formdev.flatlaf.util.SystemInfo;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatMacOSTest
extends FlatTestPanel
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, FlatMacOSTest.class.getSimpleName() );
frame.applyComponentOrientationToFrame = true;
JRootPane rootPane = frame.getRootPane();
rootPane.putClientProperty( "apple.awt.fullWindowContent", true );
rootPane.putClientProperty( "apple.awt.transparentTitleBar", true );
rootPane.putClientProperty( "apple.awt.windowTitleVisible", false );
frame.showFrame( FlatMacOSTest::new );
} );
}
FlatMacOSTest() {
initComponents();
if( SystemInfo.isMacFullWindowContentSupported ) {
fullWindowContentHint.setVisible( false );
transparentTitleBarHint.setVisible( false );
}
if( SystemInfo.isJava_17_orLater ) {
windowTitleVisibleHint.setVisible( false );
buttonsSpacingHint.setVisible( false );
}
placeholderPanel.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac zeroInFullScreen" );
UIManager.put( "FlatLaf.debug.panel.showPlaceholders", true );
}
@Override
public void addNotify() {
super.addNotify();
JRootPane rootPane = getRootPane();
fullWindowContentCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) );
transparentTitleBarCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.transparentTitleBar", false ) );
windowTitleVisibleCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.windowTitleVisible", true ) );
rootPane.addPropertyChangeListener( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, e -> {
Rectangle bounds = (Rectangle) e.getNewValue();
fullWindowContentButtonsBoundsField.setText( bounds2string( bounds ) );
} );
updateNativeButtonBounds();
}
@Override
public void updateUI() {
super.updateUI();
if( nativeButtonsBoundsField != null )
updateNativeButtonBounds();
}
private void fullWindowContentChanged() {
getRootPane().putClientProperty( "apple.awt.fullWindowContent", fullWindowContentCheckBox.isSelected() );
}
private void transparentTitleBarChanged() {
getRootPane().putClientProperty( "apple.awt.transparentTitleBar", transparentTitleBarCheckBox.isSelected() );
}
private void windowTitleVisibleChanged() {
getRootPane().putClientProperty( "apple.awt.windowTitleVisible", windowTitleVisibleCheckBox.isSelected() );
}
private void buttonsSpacingChanged() {
String buttonsSpacing = null;
if( buttonsSpacingMediumRadioButton.isSelected() )
buttonsSpacing = FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM;
else if( buttonsSpacingLargeRadioButton.isSelected() )
buttonsSpacing = FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE;
getRootPane().putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, buttonsSpacing );
updateNativeButtonBounds();
}
private void updateNativeButtonBounds() {
if( !FlatNativeMacLibrary.isLoaded() )
return;
Window window = SwingUtilities.windowForComponent( this );
Rectangle bounds = FlatNativeMacLibrary.getWindowButtonsBounds( window );
nativeButtonsBoundsField.setText( bounds2string( bounds ) );
}
private String bounds2string( Rectangle bounds ) {
return (bounds != null)
? bounds.width + ", " + bounds.height + " @ " + bounds.x + ", " + bounds.y
: "null";
}
private void toggleFullScreen() {
if( !FlatNativeMacLibrary.isLoaded() )
return;
Window window = SwingUtilities.windowForComponent( this );
FlatNativeMacLibrary.toggleWindowFullScreen( window );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JPanel panel1 = new JPanel();
placeholderPanel = new JPanel();
JPanel panel2 = new JPanel();
fullWindowContentCheckBox = new JCheckBox();
fullWindowContentHint = new JLabel();
transparentTitleBarCheckBox = new JCheckBox();
transparentTitleBarHint = new JLabel();
windowTitleVisibleCheckBox = new JCheckBox();
windowTitleVisibleHint = new JLabel();
JLabel buttonsSpacingLabel = new JLabel();
buttonsSpacingDefaultRadioButton = new JRadioButton();
buttonsSpacingMediumRadioButton = new JRadioButton();
buttonsSpacingLargeRadioButton = new JRadioButton();
buttonsSpacingHint = new JLabel();
JLabel fullWindowContentButtonsBoundsLabel = new JLabel();
fullWindowContentButtonsBoundsField = new JLabel();
JLabel nativeButtonsBoundsLabel = new JLabel();
nativeButtonsBoundsField = new JLabel();
JButton toggleFullScreenButton = new JButton();
//======== this ========
setLayout(new BorderLayout());
//======== panel1 ========
{
panel1.setLayout(new BorderLayout());
//======== placeholderPanel ========
{
placeholderPanel.setBackground(Color.green);
placeholderPanel.setLayout(new FlowLayout());
}
panel1.add(placeholderPanel, BorderLayout.WEST);
}
add(panel1, BorderLayout.PAGE_START);
//======== panel2 ========
{
panel2.setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[left]" +
"[left]" +
"[left]" +
"[left]para" +
"[fill]",
// rows
"[]" +
"[]" +
"[]" +
"[fill]" +
"[]" +
"[]para" +
"[]"));
//---- fullWindowContentCheckBox ----
fullWindowContentCheckBox.setText("fullWindowContent");
fullWindowContentCheckBox.addActionListener(e -> fullWindowContentChanged());
panel2.add(fullWindowContentCheckBox, "cell 0 0");
//---- fullWindowContentHint ----
fullWindowContentHint.setText("requires Java 12, 11.0.8 or 8u292");
fullWindowContentHint.setForeground(Color.red);
panel2.add(fullWindowContentHint, "cell 4 0");
//---- transparentTitleBarCheckBox ----
transparentTitleBarCheckBox.setText("transparentTitleBar");
transparentTitleBarCheckBox.addActionListener(e -> transparentTitleBarChanged());
panel2.add(transparentTitleBarCheckBox, "cell 0 1");
//---- transparentTitleBarHint ----
transparentTitleBarHint.setText("requires Java 12, 11.0.8 or 8u292");
transparentTitleBarHint.setForeground(Color.red);
panel2.add(transparentTitleBarHint, "cell 4 1");
//---- windowTitleVisibleCheckBox ----
windowTitleVisibleCheckBox.setText("windowTitleVisible");
windowTitleVisibleCheckBox.addActionListener(e -> windowTitleVisibleChanged());
panel2.add(windowTitleVisibleCheckBox, "cell 0 2");
//---- windowTitleVisibleHint ----
windowTitleVisibleHint.setText("requires Java 17");
windowTitleVisibleHint.setForeground(Color.red);
panel2.add(windowTitleVisibleHint, "cell 4 2");
//---- buttonsSpacingLabel ----
buttonsSpacingLabel.setText("Buttons spacing:");
panel2.add(buttonsSpacingLabel, "cell 0 3");
//---- buttonsSpacingDefaultRadioButton ----
buttonsSpacingDefaultRadioButton.setText("Default");
buttonsSpacingDefaultRadioButton.setSelected(true);
buttonsSpacingDefaultRadioButton.addActionListener(e -> buttonsSpacingChanged());
panel2.add(buttonsSpacingDefaultRadioButton, "cell 1 3");
//---- buttonsSpacingMediumRadioButton ----
buttonsSpacingMediumRadioButton.setText("Medium");
buttonsSpacingMediumRadioButton.addActionListener(e -> buttonsSpacingChanged());
panel2.add(buttonsSpacingMediumRadioButton, "cell 2 3");
//---- buttonsSpacingLargeRadioButton ----
buttonsSpacingLargeRadioButton.setText("Large");
buttonsSpacingLargeRadioButton.addActionListener(e -> buttonsSpacingChanged());
panel2.add(buttonsSpacingLargeRadioButton, "cell 3 3");
//---- buttonsSpacingHint ----
buttonsSpacingHint.setText("requires Java 17");
buttonsSpacingHint.setForeground(Color.red);
panel2.add(buttonsSpacingHint, "cell 4 3");
//---- fullWindowContentButtonsBoundsLabel ----
fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:");
panel2.add(fullWindowContentButtonsBoundsLabel, "cell 0 4");
//---- fullWindowContentButtonsBoundsField ----
fullWindowContentButtonsBoundsField.setText("null");
panel2.add(fullWindowContentButtonsBoundsField, "cell 1 4 3 1");
//---- nativeButtonsBoundsLabel ----
nativeButtonsBoundsLabel.setText("Native buttons bounds:");
panel2.add(nativeButtonsBoundsLabel, "cell 0 5");
//---- nativeButtonsBoundsField ----
nativeButtonsBoundsField.setText("null");
panel2.add(nativeButtonsBoundsField, "cell 1 5 3 1");
//---- toggleFullScreenButton ----
toggleFullScreenButton.setText("Toggle Full Screen");
toggleFullScreenButton.addActionListener(e -> toggleFullScreen());
panel2.add(toggleFullScreenButton, "cell 0 6");
}
add(panel2, BorderLayout.CENTER);
//---- buttonsSpacingButtonGroup ----
ButtonGroup buttonsSpacingButtonGroup = new ButtonGroup();
buttonsSpacingButtonGroup.add(buttonsSpacingDefaultRadioButton);
buttonsSpacingButtonGroup.add(buttonsSpacingMediumRadioButton);
buttonsSpacingButtonGroup.add(buttonsSpacingLargeRadioButton);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JPanel placeholderPanel;
private JCheckBox fullWindowContentCheckBox;
private JLabel fullWindowContentHint;
private JCheckBox transparentTitleBarCheckBox;
private JLabel transparentTitleBarHint;
private JCheckBox windowTitleVisibleCheckBox;
private JLabel windowTitleVisibleHint;
private JRadioButton buttonsSpacingDefaultRadioButton;
private JRadioButton buttonsSpacingMediumRadioButton;
private JRadioButton buttonsSpacingLargeRadioButton;
private JLabel buttonsSpacingHint;
private JLabel fullWindowContentButtonsBoundsField;
private JLabel nativeButtonsBoundsField;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,191 @@
JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "this"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) {
name: "panel1"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "placeholderPanel"
"background": sfield java.awt.Color green
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "West"
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "First"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left][left][left][left]para[fill]"
"$rowConstraints": "[][][][fill][][]para[]"
} ) {
name: "panel2"
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "fullWindowContentCheckBox"
"text": "fullWindowContent"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fullWindowContentChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentHint"
"text": "requires Java 12, 11.0.8 or 8u292"
"foreground": sfield java.awt.Color red
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "transparentTitleBarCheckBox"
"text": "transparentTitleBar"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "transparentTitleBarChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "transparentTitleBarHint"
"text": "requires Java 12, 11.0.8 or 8u292"
"foreground": sfield java.awt.Color red
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "windowTitleVisibleCheckBox"
"text": "windowTitleVisible"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "windowTitleVisibleChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "windowTitleVisibleHint"
"text": "requires Java 17"
"foreground": sfield java.awt.Color red
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "buttonsSpacingLabel"
"text": "Buttons spacing:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "buttonsSpacingDefaultRadioButton"
"text": "Default"
"$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" )
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3"
} )
add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "buttonsSpacingMediumRadioButton"
"text": "Medium"
"$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 3"
} )
add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "buttonsSpacingLargeRadioButton"
"text": "Large"
"$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 3"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "buttonsSpacingHint"
"text": "requires Java 17"
"foreground": sfield java.awt.Color red
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 3"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsLabel"
"text": "Buttons bounds:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsField"
"text": "null"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4 3 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "nativeButtonsBoundsLabel"
"text": "Native buttons bounds:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "nativeButtonsBoundsField"
"text": "null"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5 3 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "toggleFullScreenButton"
"text": "Toggle Full Screen"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "toggleFullScreen", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "Center"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 725, 350 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "buttonsSpacingButtonGroup"
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 360 )
} )
}
}

View File

@@ -32,8 +32,10 @@ public class FlatTestPanel
int width = getWidth();
int height = getHeight();
g.setColor( super.getBackground() );
g.fillRect( 0, 0, width, height );
if( isOpaque() ) {
g.setColor( super.getBackground() );
g.fillRect( 0, 0, width, height );
}
if( isPaintBackgroundPattern() ) {
g.setColor( Color.magenta );

View File

@@ -41,6 +41,9 @@ import net.miginfocom.swing.*;
public class FlatWindowDecorationsTest
extends FlatTestPanel
{
// same as in FlatTitlePane
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
if( SystemInfo.isLinux ) {
@@ -51,7 +54,7 @@ public class FlatWindowDecorationsTest
FlatTestFrame frame = FlatTestFrame.create( args, "FlatWindowDecorationsTest" );
frame.applyComponentOrientationToFrame = true;
UIManager.put( "FlatLaf.debug.titlebar.showRectangles", true );
UIManager.put( KEY_DEBUG_SHOW_RECTANGLES, true );
Class<?> cls = FlatWindowDecorationsTest.class;
List<Image> images = Arrays.asList(
@@ -76,6 +79,14 @@ public class FlatWindowDecorationsTest
initComponents();
}
@Override
public void updateUI() {
super.updateUI();
if( translucentWindowBackgroundCheckBox != null )
translucentWindowBackgroundChanged();
}
@Override
public void addNotify() {
super.addNotify();
@@ -109,6 +120,14 @@ public class FlatWindowDecorationsTest
rootPane.addPropertyChangeListener( "windowDecorationStyle", e -> {
updateDecorationStyleRadioButtons( rootPane );
} );
rootPane.addPropertyChangeListener( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, e -> {
Rectangle bounds = (Rectangle) e.getNewValue();
if( bounds != null ) {
fullWindowContentButtonsBoundsField.setText( bounds.width + ", " + bounds.height
+ " @ " + bounds.x + ", " + bounds.y );
} else
fullWindowContentButtonsBoundsField.setText( "null" );
} );
}
}
@@ -237,6 +256,27 @@ public class FlatWindowDecorationsTest
}
}
private void translucentWindowBackgroundChanged() {
boolean selected = translucentWindowBackgroundCheckBox.isSelected();
if( selected && !undecoratedCheckBox.isSelected() ) {
undecoratedCheckBox.setSelected( true );
undecoratedChanged();
}
undecoratedCheckBox.setEnabled( !selected );
Color background = selected
? new Color( 100, 0, 0, 100 )
: UIManager.getColor( "control" );
Window window = SwingUtilities.windowForComponent( this );
window.setBackground( background );
for( Component c = this; c != null; c = c.getParent() ) {
if( c instanceof JComponent )
LookAndFeel.installProperty( (JComponent) c, "opaque", !selected );
}
}
private void addMenu() {
JMenu menu = new JMenu( "Hello" );
menu.add( new JMenuItem( "world" ) );
@@ -280,12 +320,21 @@ debug*/
JLabel caption = new JLabel( "Caption" );
caption.setBackground( Color.green );
caption.setOpaque( true );
caption.putClientProperty( FlatClientProperties.COMPONENT_TITLE_BAR_CAPTION, true );
menuBar.add( caption );
menuBar.revalidate();
}
private void addTextField() {
JTextField textField = new JTextField( "text", 10 );
JPanel panel = new JPanel( new GridBagLayout() );
panel.add( textField, new GridBagConstraints() );
menuBar.add( panel );
menuBar.revalidate();
}
private void removeMenu() {
int menuCount = menuBar.getMenuCount();
if( menuCount <= 0 )
@@ -486,13 +535,31 @@ debug*/
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_CLOSE, showCloseCheckBox.isSelected() ? null : false );
}
private void fullWindowContentChanged() {
JRootPane rootPane = getWindowRootPane();
if( rootPane != null ) {
boolean selected = fullWindowContentCheckBox.isSelected();
rootPane.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT, selected ? true : null );
showIconCheckBox.setEnabled( !selected );
showTitleCheckBox.setEnabled( !selected );
}
}
private JRootPane getWindowRootPane() {
Window window = SwingUtilities.windowForComponent( this );
if( window instanceof JFrame )
return ((JFrame)window).getRootPane();
else if( window instanceof JDialog )
return ((JDialog)window).getRootPane();
return null;
return (window instanceof RootPaneContainer)
? ((RootPaneContainer)window).getRootPane()
: null;
}
private void showRectangles() {
JRootPane rootPane = getWindowRootPane();
if( rootPane != null ) {
UIManager.put( KEY_DEBUG_SHOW_RECTANGLES, showRectanglesCheckBox.isSelected() );
rootPane.revalidate();
rootPane.repaint();
}
}
private void initComponents() {
@@ -509,6 +576,9 @@ debug*/
showIconifyCheckBox = new JCheckBox();
showMaximizeCheckBox = new JCheckBox();
showCloseCheckBox = new JCheckBox();
fullWindowContentCheckBox = new JCheckBox();
JLabel fullWindowContentButtonsBoundsLabel = new JLabel();
fullWindowContentButtonsBoundsField = new JLabel();
JPanel panel6 = new JPanel();
menuBarCheckBox = new JCheckBox();
menuBarEmbeddedCheckBox = new JCheckBox();
@@ -519,6 +589,7 @@ debug*/
addMenuButton = new JButton();
addGlueButton = new JButton();
addCaptionButton = new JButton();
addTextFieldButton = new JButton();
removeMenuButton = new JButton();
changeMenuButton = new JButton();
changeTitleButton = new JButton();
@@ -543,11 +614,13 @@ debug*/
colorizeTitleBarCheckBox = new JCheckBox();
colorizeMenuBarCheckBox = new JCheckBox();
colorizeMenusCheckBox = new JCheckBox();
translucentWindowBackgroundCheckBox = new JCheckBox();
JButton openDialogButton = new JButton();
JButton openFrameButton = new JButton();
typeNormalRadioButton = new JRadioButton();
typeUtilityRadioButton = new JRadioButton();
typeSmallRadioButton = new JRadioButton();
showRectanglesCheckBox = new JCheckBox();
menuBar = new JMenuBar();
JMenu fileMenu = new JMenu();
JMenuItem newMenuItem = new JMenuItem();
@@ -586,6 +659,7 @@ debug*/
// rows
"[fill]" +
"[fill]" +
"[]" +
"[]"));
//======== panel7 ========
@@ -643,6 +717,8 @@ debug*/
"[]" +
"[]" +
"[]" +
"[]rel" +
"[]rel" +
"[]"));
//---- showIconCheckBox ----
@@ -673,6 +749,19 @@ debug*/
showCloseCheckBox.setSelected(true);
showCloseCheckBox.addActionListener(e -> showCloseChanged());
panel4.add(showCloseCheckBox, "cell 0 4");
//---- fullWindowContentCheckBox ----
fullWindowContentCheckBox.setText("full window content");
fullWindowContentCheckBox.addActionListener(e -> fullWindowContentChanged());
panel4.add(fullWindowContentCheckBox, "cell 0 5");
//---- fullWindowContentButtonsBoundsLabel ----
fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:");
panel4.add(fullWindowContentButtonsBoundsLabel, "cell 0 6");
//---- fullWindowContentButtonsBoundsField ----
fullWindowContentButtonsBoundsField.setText("null");
panel4.add(fullWindowContentButtonsBoundsField, "cell 0 6");
}
add(panel4, "cell 1 0");
@@ -731,6 +820,7 @@ debug*/
"[]" +
"[]" +
"[]" +
"[]" +
"[]unrel" +
"[]"));
@@ -749,20 +839,25 @@ debug*/
addCaptionButton.addActionListener(e -> addCaption());
panel3.add(addCaptionButton, "cell 0 2");
//---- addTextFieldButton ----
addTextFieldButton.setText("Add text field");
addTextFieldButton.addActionListener(e -> addTextField());
panel3.add(addTextFieldButton, "cell 0 3");
//---- removeMenuButton ----
removeMenuButton.setText("Remove menu");
removeMenuButton.addActionListener(e -> removeMenu());
panel3.add(removeMenuButton, "cell 0 3");
panel3.add(removeMenuButton, "cell 0 4");
//---- changeMenuButton ----
changeMenuButton.setText("Change menu");
changeMenuButton.addActionListener(e -> changeMenu());
panel3.add(changeMenuButton, "cell 0 4");
panel3.add(changeMenuButton, "cell 0 5");
//---- changeTitleButton ----
changeTitleButton.setText("Change title");
changeTitleButton.addActionListener(e -> changeTitle());
panel3.add(changeTitleButton, "cell 0 5");
panel3.add(changeTitleButton, "cell 0 6");
}
add(panel3, "cell 3 0 1 2,aligny top,growy 0");
@@ -885,6 +980,7 @@ debug*/
"[]" +
"[]" +
"[]" +
"[]para" +
"[]"));
//---- unifiedBackgroundCheckBox ----
@@ -906,6 +1002,11 @@ debug*/
colorizeMenusCheckBox.setText("colorize menus");
colorizeMenusCheckBox.addActionListener(e -> colorizeMenus());
panel5.add(colorizeMenusCheckBox, "cell 0 3");
//---- translucentWindowBackgroundCheckBox ----
translucentWindowBackgroundCheckBox.setText("translucent window background");
translucentWindowBackgroundCheckBox.addActionListener(e -> translucentWindowBackgroundChanged());
panel5.add(translucentWindowBackgroundCheckBox, "cell 0 4");
}
add(panel5, "cell 2 1");
@@ -933,6 +1034,12 @@ debug*/
typeSmallRadioButton.setText("Small");
add(typeSmallRadioButton, "cell 0 2 3 1");
//---- showRectanglesCheckBox ----
showRectanglesCheckBox.setText("Show debug title bar rectangles");
showRectanglesCheckBox.setSelected(true);
showRectanglesCheckBox.addActionListener(e -> showRectangles());
add(showRectanglesCheckBox, "cell 0 3");
//======== menuBar ========
{
@@ -1140,6 +1247,8 @@ debug*/
private JCheckBox showIconifyCheckBox;
private JCheckBox showMaximizeCheckBox;
private JCheckBox showCloseCheckBox;
private JCheckBox fullWindowContentCheckBox;
private JLabel fullWindowContentButtonsBoundsField;
private JCheckBox menuBarCheckBox;
private JCheckBox menuBarEmbeddedCheckBox;
private JCheckBox menuBarVisibleCheckBox;
@@ -1148,6 +1257,7 @@ debug*/
private JButton addMenuButton;
private JButton addGlueButton;
private JButton addCaptionButton;
private JButton addTextFieldButton;
private JButton removeMenuButton;
private JButton changeMenuButton;
private JButton changeTitleButton;
@@ -1169,9 +1279,11 @@ debug*/
private JCheckBox colorizeTitleBarCheckBox;
private JCheckBox colorizeMenuBarCheckBox;
private JCheckBox colorizeMenusCheckBox;
private JCheckBox translucentWindowBackgroundCheckBox;
private JRadioButton typeNormalRadioButton;
private JRadioButton typeUtilityRadioButton;
private JRadioButton typeSmallRadioButton;
private JCheckBox showRectanglesCheckBox;
private JMenuBar menuBar;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left][fill][fill][fill]"
"$rowConstraints": "[fill][fill][]"
"$rowConstraints": "[fill][fill][][]"
} ) {
name: "this"
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
@@ -77,7 +77,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
"$columnConstraints": "[grow,left]"
"$rowConstraints": "[][][][][]"
"$rowConstraints": "[][][][][]rel[]rel[]"
} ) {
name: "panel4"
"border": new javax.swing.border.TitledBorder( "Title Bar" )
@@ -135,6 +135,31 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "fullWindowContentCheckBox"
"text": "full window content"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fullWindowContentChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsLabel"
"text": "Buttons bounds:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fullWindowContentButtonsBoundsField"
"text": "null"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
@@ -204,7 +229,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill]"
"$rowConstraints": "[][][][][]unrel[]"
"$rowConstraints": "[][][][][][]unrel[]"
} ) {
name: "panel3"
add( new FormComponent( "javax.swing.JButton" ) {
@@ -237,6 +262,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "addTextFieldButton"
"text": "Add text field"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addTextField", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "removeMenuButton"
"text": "Remove menu"
@@ -245,7 +280,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "removeMenu", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "changeMenuButton"
@@ -255,7 +290,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeMenu", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
"value": "cell 0 5"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "changeTitleButton"
@@ -265,7 +300,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeTitle", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
"value": "cell 0 6"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 0 1 2,aligny top,growy 0"
@@ -449,7 +484,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,hidemode 3,gap 0 0"
"$columnConstraints": "[left]"
"$rowConstraints": "[][][][]"
"$rowConstraints": "[][][][]para[]"
} ) {
name: "panel5"
"border": new javax.swing.border.TitledBorder( "Color" )
@@ -493,6 +528,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "translucentWindowBackgroundCheckBox"
"text": "translucent window background"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "translucentWindowBackgroundChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1"
} )
@@ -542,6 +587,17 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2 3 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showRectanglesCheckBox"
"text": "Show debug title bar rectangles"
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showRectangles", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 960, 495 )

View File

@@ -119,10 +119,9 @@ public class UIDefaultsDump
//
// dump( "com.jgoodies.looks.plastic.PlasticLookAndFeel", dir, false );
// dump( "com.jgoodies.looks.windows.WindowsLookAndFeel", dir, false );
// dump( "com.alee.laf.WebLookAndFeel", dir, false );
// try {
// EventQueue.invokeAndWait( () -> {
// dump( "org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel", dir, false );
// SwingUtilities.invokeAndWait( () -> {
// dump( "org.pushingpixels.radiance.theming.api.skin.RadianceGraphiteAquaLookAndFeel", dir, false );
// } );
// } catch( Exception ex ) {
// // TODO Auto-generated catch block
@@ -673,7 +672,7 @@ public class UIDefaultsDump
switch( borderClassName ) {
case "com.apple.laf.AquaToolBarUI$ToolBarBorder":
case "org.pushingpixels.substance.internal.utils.border.SubstanceToolBarBorder":
case "org.pushingpixels.radiance.theming.internal.utils.border.RadianceToolBarBorder":
c = new JToolBar();
break;

View File

@@ -68,6 +68,20 @@ public class UIDefaultsKeysDump
collectKeys( FlatDarculaLaf.class.getName(), keys );
collectKeys( FlatTestLaf.class.getName(), keys );
// remove unused keys (defined in BasicLookAndFeel)
keys.remove( "Button.textIconGap" );
keys.remove( "Button.textShiftOffset" );
keys.remove( "CheckBox.textIconGap" );
keys.remove( "CheckBox.textShiftOffset" );
keys.remove( "RadioButton.textIconGap" );
keys.remove( "RadioButton.textShiftOffset" );
keys.remove( "TabbedPane.contentOpaque" );
keys.remove( "TabbedPane.selectedTabPadInsets" );
keys.remove( "TabbedPane.shadow" );
keys.remove( "TabbedPane.tabsOverlapBorder" );
keys.remove( "ToggleButton.textIconGap" );
keys.remove( "ToggleButton.textShiftOffset" );
// write key file
try( Writer fileWriter = new BufferedWriter( new OutputStreamWriter(
new FileOutputStream( keysFile ), StandardCharsets.UTF_8 ) ) )

View File

@@ -64,8 +64,6 @@ Button.selectedForeground
Button.shadow
Button.startBackground
Button.startBorderColor
Button.textIconGap
Button.textShiftOffset
Button.toolbar.disabledSelectedBackground
Button.toolbar.disabledSelectedForeground
Button.toolbar.hoverBackground
@@ -149,8 +147,6 @@ CheckBox.icon[filled].selectedBorderColor
CheckBox.icon[filled].selectedBorderWidth
CheckBox.margin
CheckBox.rollover
CheckBox.textIconGap
CheckBox.textShiftOffset
CheckBoxMenuItem.acceleratorForeground
CheckBoxMenuItem.acceleratorSelectionForeground
CheckBoxMenuItem.arrowIcon
@@ -655,8 +651,6 @@ RadioButton.light
RadioButton.margin
RadioButton.rollover
RadioButton.shadow
RadioButton.textIconGap
RadioButton.textShiftOffset
RadioButtonMenuItem.acceleratorForeground
RadioButtonMenuItem.acceleratorSelectionForeground
RadioButtonMenuItem.arrowIcon
@@ -855,7 +849,6 @@ TabbedPane.closePressedBackground
TabbedPane.closePressedForeground
TabbedPane.closeSize
TabbedPane.contentAreaColor
TabbedPane.contentOpaque
TabbedPane.contentSeparatorHeight
TabbedPane.darkShadow
TabbedPane.disabledForeground
@@ -881,9 +874,7 @@ TabbedPane.selectedBackground
TabbedPane.selectedForeground
TabbedPane.selectedInsets
TabbedPane.selectedLabelShift
TabbedPane.selectedTabPadInsets
TabbedPane.selectionFollowsFocus
TabbedPane.shadow
TabbedPane.showTabSeparators
TabbedPane.tabAlignment
TabbedPane.tabArc
@@ -901,7 +892,6 @@ TabbedPane.tabSeparatorsFullHeight
TabbedPane.tabType
TabbedPane.tabWidthMode
TabbedPane.tabsOpaque
TabbedPane.tabsOverlapBorder
TabbedPane.tabsPopupPolicy
TabbedPane.textIconGap
TabbedPane.underlineColor
@@ -920,6 +910,7 @@ Table.dropCellBackground
Table.dropCellForeground
Table.dropLineColor
Table.dropLineShortColor
Table.editorSelectAllOnStartEditing
Table.focusCellBackground
Table.focusCellForeground
Table.focusCellHighlightBorder
@@ -928,6 +919,7 @@ Table.font
Table.foreground
Table.gridColor
Table.intercellSpacing
Table.paintOutsideAlternateRows
Table.rowHeight
Table.scrollPaneBorder
Table.selectionBackground
@@ -1047,7 +1039,6 @@ TitlePane.inactiveBackground
TitlePane.inactiveForeground
TitlePane.maximizeIcon
TitlePane.menuBarEmbedded
TitlePane.menuBarResizeHeight
TitlePane.menuBarTitleGap
TitlePane.menuBarTitleMinimumGap
TitlePane.noIconLeftGap
@@ -1079,7 +1070,6 @@ TitlePane.small.iconifyIcon
TitlePane.small.inactiveBackground
TitlePane.small.inactiveForeground
TitlePane.small.maximizeIcon
TitlePane.small.menuBarResizeHeight
TitlePane.small.menuBarTitleGap
TitlePane.small.menuBarTitleMinimumGap
TitlePane.small.noIconLeftGap
@@ -1130,8 +1120,6 @@ ToggleButton.tab.selectedBackground
ToggleButton.tab.selectedForeground
ToggleButton.tab.underlineColor
ToggleButton.tab.underlineHeight
ToggleButton.textIconGap
ToggleButton.textShiftOffset
ToggleButton.toolbar.disabledSelectedBackground
ToggleButton.toolbar.disabledSelectedForeground
ToggleButton.toolbar.hoverBackground

View File

@@ -14,8 +14,8 @@
# limitations under the License.
#
flatlaf.releaseVersion = 3.3
flatlaf.developmentVersion = 3.4-SNAPSHOT
flatlaf.releaseVersion = 3.4
flatlaf.developmentVersion = 3.5-SNAPSHOT
org.gradle.parallel = true
# org.gradle.warning.mode = all