mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 14:37:13 -06:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde25f6ac8 | ||
|
|
c989b97ffa | ||
|
|
5f5c225300 | ||
|
|
36e4071b7f | ||
|
|
1068884bce | ||
|
|
32d102dbc9 | ||
|
|
4e1f092b98 | ||
|
|
bd60a18ff4 | ||
|
|
3b3d7d76eb | ||
|
|
ec76448e9f | ||
|
|
872c84974c | ||
|
|
5dd2008969 | ||
|
|
55ddac2bc7 | ||
|
|
a62dd22f83 | ||
|
|
a503879858 | ||
|
|
14f19dd735 | ||
|
|
9a727f68ce | ||
|
|
d26819d268 | ||
|
|
44752cc9aa | ||
|
|
11e0757387 | ||
|
|
1f1ebc3c44 | ||
|
|
4be97b6ea6 | ||
|
|
3facca5499 | ||
|
|
bfbd25012a | ||
|
|
063fff2ab4 | ||
|
|
fbdc8d5b99 | ||
|
|
625c0a3321 | ||
|
|
2972300112 | ||
|
|
a8e71895ee | ||
|
|
d7a76081e3 | ||
|
|
fd925a6718 | ||
|
|
4fc890a77c | ||
|
|
b804463b73 | ||
|
|
8f161b4b5a | ||
|
|
c6338169f3 | ||
|
|
6cea24ed9e | ||
|
|
3d8eb9eb66 | ||
|
|
a84aceb1ba | ||
|
|
8adb7e3021 | ||
|
|
bc0d5dc9b5 | ||
|
|
1d935d6659 | ||
|
|
445466acd0 | ||
|
|
30af74f806 | ||
|
|
16ddd100d3 | ||
|
|
c946ec170d | ||
|
|
ca514dd76e | ||
|
|
cf44a5c50b | ||
|
|
91b8c02c7f | ||
|
|
ca3b2b4b07 | ||
|
|
722dde63df | ||
|
|
c85baf4dc6 | ||
|
|
96b7770ab2 | ||
|
|
0c00117820 | ||
|
|
3465fa68b4 | ||
|
|
28278a75a7 | ||
|
|
f68a871dd6 | ||
|
|
93d424cfe1 | ||
|
|
a1adde0888 | ||
|
|
13528b49cb | ||
|
|
f3be3f2d1c | ||
|
|
241fe855cc | ||
|
|
ea2447dcb7 | ||
|
|
f40baed65e | ||
|
|
eed11d211b |
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -9,6 +9,14 @@ on:
|
||||
- '*'
|
||||
tags:
|
||||
- '[0-9]*'
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '.*'
|
||||
- '**/.settings/**'
|
||||
- 'flatlaf-core/svg/**'
|
||||
- 'flatlaf-testing/dumps/**'
|
||||
- 'flatlaf-testing/misc/**'
|
||||
- 'images/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -24,22 +32,23 @@ jobs:
|
||||
- 8
|
||||
- 11 # LTS
|
||||
- 17 # LTS
|
||||
- 21 # LTS
|
||||
toolchain: [""]
|
||||
include:
|
||||
- java: 17
|
||||
toolchain: 21 # latest
|
||||
- java: 21
|
||||
toolchain: 22 # latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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 }}
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: temurin # Java 8, 11 and 17 are pre-installed on ubuntu-latest
|
||||
distribution: temurin # Java 8, 11, 17 and 21 are pre-installed on ubuntu-latest
|
||||
cache: gradle
|
||||
|
||||
- name: Check with Error Prone
|
||||
@@ -50,7 +59,7 @@ jobs:
|
||||
run: ./gradlew build -Dtoolchain=${{ matrix.toolchain }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: matrix.java == '11'
|
||||
with:
|
||||
name: FlatLaf-build-artifacts
|
||||
@@ -70,10 +79,10 @@ jobs:
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: temurin # pre-installed on ubuntu-latest
|
||||
@@ -106,10 +115,10 @@ jobs:
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: temurin # pre-installed on ubuntu-latest
|
||||
|
||||
6
.github/workflows/fonts.yml
vendored
6
.github/workflows/fonts.yml
vendored
@@ -13,6 +13,8 @@ on:
|
||||
- 'flatlaf-fonts/**'
|
||||
- '.github/workflows/fonts.yml'
|
||||
- 'gradle/wrapper/gradle-wrapper.properties'
|
||||
- '!**.md'
|
||||
- '!**/.settings/**'
|
||||
|
||||
jobs:
|
||||
Fonts:
|
||||
@@ -30,10 +32,10 @@ jobs:
|
||||
github.repository == 'JFormDesigner/FlatLaf'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: temurin # pre-installed on ubuntu-latest
|
||||
|
||||
10
.github/workflows/natives.yml
vendored
10
.github/workflows/natives.yml
vendored
@@ -13,6 +13,8 @@ on:
|
||||
- 'flatlaf-natives/**'
|
||||
- '.github/workflows/natives.yml'
|
||||
- 'gradle/wrapper/gradle-wrapper.properties'
|
||||
- '!**.md'
|
||||
- '!**/.settings/**'
|
||||
|
||||
jobs:
|
||||
Natives:
|
||||
@@ -26,12 +28,12 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- uses: gradle/wrapper-validation-action@v2
|
||||
|
||||
- name: Setup Java 11
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: temurin
|
||||
@@ -43,7 +45,7 @@ jobs:
|
||||
run: ./gradlew build-natives --no-daemon
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: FlatLaf-natives-build-artifacts-${{ matrix.os }}
|
||||
path: |
|
||||
|
||||
37
.github/workflows/pr-snapshots.yml
vendored
Normal file
37
.github/workflows/pr-snapshots.yml
vendored
Normal 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 }}
|
||||
64
CHANGELOG.md
64
CHANGELOG.md
@@ -1,6 +1,70 @@
|
||||
FlatLaf Change Log
|
||||
==================
|
||||
|
||||
## 3.4.1
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
- SplitPane: Update divider when client property `JSplitPane.expandableSide`
|
||||
changed.
|
||||
- TabbedPane: Fixed swapped back and forward scroll buttons when using
|
||||
`TabbedPane.scrollButtonsPlacement = trailing` (regression in FlatLaf 3.3).
|
||||
- Fixed missing window top border on Windows 10 in "full window content" mode.
|
||||
(issue 809)
|
||||
- Extras:
|
||||
- `FlatSVGIcon` color filters now support linear gradients. (PR #817)
|
||||
- `FlatSVGIcon`: Use log level `CONFIG` instead of `SEVERE` and allow
|
||||
disabling logging. (issue #823)
|
||||
- Added support for `JSplitPane.expandableSide` client property to
|
||||
`FlatSplitPane`.
|
||||
- Native libraries: Added API version check to test whether native library
|
||||
matches the JAR (bad builds could e.g. ship a newer JAR with an older
|
||||
incompatible native library) and to test whether native methods can be invoked
|
||||
(some security software allows loading native library but blocks method
|
||||
invocation).
|
||||
- macOS: Fixed crash when running in WebSwing. (issue #826; regression in 3.4)
|
||||
|
||||
#### Incompatibilities
|
||||
|
||||
- File names of custom properties files for nested Laf classes now must include
|
||||
name of enclosing class name. E.g. nested Laf class `IntelliJTheme.ThemeLaf`
|
||||
used `ThemeLaf.properties` in previous versions, but now needs to be named
|
||||
`IntelliJTheme$ThemeLaf.properties`.
|
||||
|
||||
|
||||
## 3.4
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
- 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)
|
||||
|
||||
|
||||
## 3.3
|
||||
|
||||
#### New features and improvements
|
||||
|
||||
@@ -311,6 +311,9 @@ Applications using FlatLaf
|
||||
|
||||
-  
|
||||
[BGBlitz](https://www.bgblitz.com/) (**commercial**) - professional Backgammon
|
||||
-  [MCreator](https://github.com/MCreator/MCreator) -
|
||||
software used to make Minecraft Java Edition mods, Minecraft Bedrock Edition Add-Ons,
|
||||
and data packs without programming knowledge
|
||||
-  [MapTool](https://github.com/RPTools/maptool) - virtual
|
||||
Tabletop for playing role-playing games
|
||||
- [MegaMek](https://github.com/MegaMek/megamek),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ library {
|
||||
}
|
||||
with( linkTask.get() ) {
|
||||
if( name.contains( "Release" ) )
|
||||
debuggable.set( false )
|
||||
debuggable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,34 +44,34 @@ publishing {
|
||||
|
||||
pom {
|
||||
afterEvaluate {
|
||||
this@pom.name.set( extension.name )
|
||||
this@pom.description.set( extension.description )
|
||||
this@pom.name = extension.name
|
||||
this@pom.description = extension.description
|
||||
}
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
url = "https://github.com/JFormDesigner/FlatLaf"
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set( "The Apache License, Version 2.0" )
|
||||
url.set( "https://www.apache.org/licenses/LICENSE-2.0.txt" )
|
||||
name = "The Apache License, Version 2.0"
|
||||
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name.set( "Karl Tauber" )
|
||||
organization.set( "FormDev Software GmbH" )
|
||||
organizationUrl.set( "https://www.formdev.com/" )
|
||||
name = "Karl Tauber"
|
||||
organization = "FormDev Software GmbH"
|
||||
organizationUrl = "https://www.formdev.com/"
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set( "scm:git:git://github.com/JFormDesigner/FlatLaf.git" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf" )
|
||||
connection = "scm:git:git://github.com/JFormDesigner/FlatLaf.git"
|
||||
url = "https://github.com/JFormDesigner/FlatLaf"
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system.set( "GitHub" )
|
||||
url.set( "https://github.com/JFormDesigner/FlatLaf/issues" )
|
||||
system = "GitHub"
|
||||
url = "https://github.com/JFormDesigner/FlatLaf/issues"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'." )
|
||||
|
||||
@@ -21,6 +21,6 @@ plugins {
|
||||
val toolchainJavaVersion = System.getProperty( "toolchain" )
|
||||
if( !toolchainJavaVersion.isNullOrEmpty() ) {
|
||||
java.toolchain {
|
||||
languageVersion.set( JavaLanguageVersion.of( toolchainJavaVersion ) )
|
||||
languageVersion = JavaLanguageVersion.of( toolchainJavaVersion )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ plugins {
|
||||
val sigtest = configurations.create( "sigtest" )
|
||||
|
||||
dependencies {
|
||||
testImplementation( libs.bundles.junit )
|
||||
testRuntimeOnly( libs.junit.engine )
|
||||
testImplementation( libs.junit )
|
||||
testRuntimeOnly( libs.junit.launcher )
|
||||
|
||||
// https://github.com/jtulach/netbeans-apitest
|
||||
sigtest( libs.sigtest )
|
||||
@@ -42,11 +42,11 @@ java {
|
||||
tasks {
|
||||
compileJava {
|
||||
// generate JNI headers
|
||||
options.headerOutputDirectory.set( layout.buildDirectory.dir( "generated/jni-headers" ) )
|
||||
options.headerOutputDirectory = layout.buildDirectory.dir( "generated/jni-headers" )
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveBaseName = "flatlaf"
|
||||
|
||||
doLast {
|
||||
ReorderJarEntries.reorderJarEntries( outputs.files.singleFile );
|
||||
@@ -54,11 +54,32 @@ tasks {
|
||||
}
|
||||
|
||||
named<Jar>( "sourcesJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveBaseName = "flatlaf"
|
||||
}
|
||||
|
||||
named<Jar>( "javadocJar" ) {
|
||||
archiveBaseName.set( "flatlaf" )
|
||||
archiveBaseName = "flatlaf"
|
||||
}
|
||||
|
||||
register<Zip>( "jarNoNatives" ) {
|
||||
group = "build"
|
||||
dependsOn( "jar" )
|
||||
|
||||
archiveBaseName = "flatlaf"
|
||||
archiveClassifier = "no-natives"
|
||||
archiveExtension = "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 {
|
||||
@@ -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" ),
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -102,6 +102,17 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String BUTTON_TYPE_BORDERLESS = "borderless";
|
||||
|
||||
/**
|
||||
* Specifies whether the button preferred size will be made square (quadratically).
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SQUARE_SIZE = "JButton.squareSize";
|
||||
|
||||
|
||||
//---- JCheckBox ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Specifies selected state of a checkbox.
|
||||
* <p>
|
||||
@@ -118,14 +129,6 @@ public interface FlatClientProperties
|
||||
*/
|
||||
String SELECTED_STATE_INDETERMINATE = "indeterminate";
|
||||
|
||||
/**
|
||||
* Specifies whether the button preferred size will be made square (quadratically).
|
||||
* <p>
|
||||
* <strong>Components</strong> {@link javax.swing.JButton} and {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Boolean}
|
||||
*/
|
||||
String SQUARE_SIZE = "JButton.squareSize";
|
||||
|
||||
|
||||
//---- JComponent ---------------------------------------------------------
|
||||
|
||||
@@ -257,19 +260,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}<Point, Boolean>
|
||||
*
|
||||
* @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 +488,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}.
|
||||
@@ -847,7 +987,7 @@ public interface FlatClientProperties
|
||||
* <strong>Component</strong> {@link javax.swing.JTabbedPane}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer} or {@link java.lang.String}<br>
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEADING} (default)
|
||||
* {@link SwingConstants#LEADING} (default),
|
||||
* {@link SwingConstants#TRAILING},
|
||||
* {@link SwingConstants#CENTER},
|
||||
* {@link #TABBED_PANE_ALIGN_LEADING} (default),
|
||||
@@ -959,7 +1099,7 @@ public interface FlatClientProperties
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#LEFT},
|
||||
* {@link SwingConstants#RIGHT},
|
||||
* {@link #TABBED_PANE_TAB_ROTATION_NONE}, (default)
|
||||
* {@link #TABBED_PANE_TAB_ROTATION_NONE} (default),
|
||||
* {@link #TABBED_PANE_TAB_ROTATION_AUTO},
|
||||
* {@link #TABBED_PANE_TAB_ROTATION_LEFT} or
|
||||
* {@link #TABBED_PANE_TAB_ROTATION_RIGHT}
|
||||
@@ -1208,8 +1348,8 @@ public interface FlatClientProperties
|
||||
* <p>
|
||||
* <strong>Component</strong> {@link javax.swing.JToggleButton}<br>
|
||||
* <strong>Value type</strong> {@link java.lang.Integer}<br>
|
||||
* <strong>SupportedValues:</strong>
|
||||
* {@link SwingConstants#BOTTOM} (default)
|
||||
* <strong>Allowed Values</strong>
|
||||
* {@link SwingConstants#BOTTOM} (default),
|
||||
* {@link SwingConstants#TOP},
|
||||
* {@link SwingConstants#LEFT} or
|
||||
* {@link SwingConstants#RIGHT}
|
||||
@@ -1263,6 +1403,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 -----------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class FlatDefaultsAddon
|
||||
public InputStream getDefaults( Class<?> lafClass ) {
|
||||
Class<?> addonClass = this.getClass();
|
||||
String propertiesName = '/' + addonClass.getPackage().getName().replace( '.', '/' )
|
||||
+ '/' + lafClass.getSimpleName() + ".properties";
|
||||
+ '/' + UIDefaultsLoader.simpleClassName( lafClass ) + ".properties";
|
||||
return addonClass.getResourceAsStream( propertiesName );
|
||||
}
|
||||
|
||||
|
||||
@@ -172,19 +172,33 @@ public interface FlatSystemProperties
|
||||
String USE_NATIVE_LIBRARY = "flatlaf.useNativeLibrary";
|
||||
|
||||
/**
|
||||
* Specifies a directory in which the native FlatLaf libraries have been extracted.
|
||||
* Specifies a directory in which the FlatLaf native libraries are searched for.
|
||||
* The path can be absolute or relative to current application working directory.
|
||||
* This can be used to avoid extraction of the native libraries to the temporary directory at runtime.
|
||||
* <p>
|
||||
* If the value is {@code "system"}, then {@link System#loadLibrary(String)} is
|
||||
* used to load the native library.
|
||||
* Searches for the native library in classloader of caller
|
||||
* If the value is {@code "system"} (supported since FlatLaf 2.6),
|
||||
* then {@link System#loadLibrary(String)} is used to load the native library.
|
||||
* This searches for the native library in classloader of caller
|
||||
* (using {@link ClassLoader#findLibrary(String)}) and in paths specified
|
||||
* in system properties {@code sun.boot.library.path} and {@code java.library.path}.
|
||||
* (supported since FlatLaf 2.6)
|
||||
* <p>
|
||||
* If the native library can not be loaded from the given path (or via {@link System#loadLibrary(String)}),
|
||||
* then the embedded native library is extracted to the temporary directory and loaded from there.
|
||||
* <p>
|
||||
* The file names of the native libraries must be either:
|
||||
* <ul>
|
||||
* <li>the same as in flatlaf.jar in package 'com/formdev/flatlaf/natives' (required for "system") or
|
||||
* <li>when downloaded from Maven central then as described here:
|
||||
* <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
|
||||
* (requires FlatLaf 3.4)
|
||||
* </ul>
|
||||
* <p>
|
||||
* <strong>Note</strong>: Since FlatLaf 3.1 it is recommended to download the
|
||||
* FlatLaf native libraries from Maven central and distribute them with your
|
||||
* application in the same directory as flatlaf.jar.
|
||||
* Then it is <strong>not necessary</strong> to set this system property.
|
||||
* See <a href="https://www.formdev.com/flatlaf/native-libraries/">https://www.formdev.com/flatlaf/native-libraries/</a>
|
||||
* for details.
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
|
||||
@@ -161,7 +161,7 @@ class UIDefaultsLoader
|
||||
classLoader = FlatLaf.class.getClassLoader();
|
||||
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
String propertiesName = packageName + '/' + lafClass.getSimpleName() + ".properties";
|
||||
String propertiesName = packageName + '/' + simpleClassName( lafClass ) + ".properties";
|
||||
try( InputStream in = classLoader.getResourceAsStream( propertiesName ) ) {
|
||||
if( in != null )
|
||||
properties.load( in );
|
||||
@@ -171,7 +171,7 @@ class UIDefaultsLoader
|
||||
// load from package URL
|
||||
URL packageUrl = (URL) source;
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
URL propertiesUrl = new URL( packageUrl + lafClass.getSimpleName() + ".properties" );
|
||||
URL propertiesUrl = new URL( packageUrl + simpleClassName( lafClass ) + ".properties" );
|
||||
|
||||
try( InputStream in = propertiesUrl.openStream() ) {
|
||||
properties.load( in );
|
||||
@@ -183,7 +183,7 @@ class UIDefaultsLoader
|
||||
// load from folder
|
||||
File folder = (File) source;
|
||||
for( Class<?> lafClass : lafClasses ) {
|
||||
File propertiesFile = new File( folder, lafClass.getSimpleName() + ".properties" );
|
||||
File propertiesFile = new File( folder, simpleClassName( lafClass ) + ".properties" );
|
||||
if( !propertiesFile.isFile() )
|
||||
continue;
|
||||
|
||||
@@ -294,6 +294,14 @@ class UIDefaultsLoader
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to Class.getSimpleName(), but includes enclosing class for nested classes.
|
||||
*/
|
||||
static String simpleClassName( Class<?> cls ) {
|
||||
String className = cls.getName();
|
||||
return className.substring( className.lastIndexOf( '.' ) + 1 );
|
||||
}
|
||||
|
||||
static void logParseError( String key, String value, RuntimeException ex, boolean severe ) {
|
||||
String message = "FlatLaf: Failed to parse: '" + key + '=' + value + '\'';
|
||||
if( severe )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
@@ -271,7 +272,7 @@ public class FlatMenuUI
|
||||
if( !isHover() )
|
||||
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground, menuBarSelectionBackground, selectionBackground );
|
||||
|
||||
JMenuBar menuBar = (JMenuBar) menuItem.getParent();
|
||||
Container menuBar = menuItem.getParent();
|
||||
JRootPane rootPane = SwingUtilities.getRootPane( menuBar );
|
||||
if( rootPane != null && rootPane.getParent() instanceof Window &&
|
||||
rootPane.getJMenuBar() == menuBar &&
|
||||
@@ -321,12 +322,17 @@ public class FlatMenuUI
|
||||
}
|
||||
|
||||
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
|
||||
MenuBarUI ui = ((JMenuBar)menuItem.getParent()).getUI();
|
||||
if( !(ui instanceof FlatMenuBarUI) )
|
||||
return defaultValue;
|
||||
|
||||
T value = f.apply( (FlatMenuBarUI) ui );
|
||||
return (value != null) ? value : defaultValue;
|
||||
Container menuItemParent = menuItem.getParent();
|
||||
if( menuItemParent instanceof JMenuBar ) {
|
||||
MenuBarUI ui = ((JMenuBar) menuItemParent).getUI();
|
||||
if( ui instanceof FlatMenuBarUI ) {
|
||||
T value = f.apply( (FlatMenuBarUI) ui );
|
||||
if( value != null ) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -36,16 +37,18 @@ class FlatNativeLibrary
|
||||
private static boolean initialized;
|
||||
private static NativeLibrary nativeLibrary;
|
||||
|
||||
private native static int getApiVersion();
|
||||
|
||||
/**
|
||||
* Loads native library (if available) and returns whether loaded successfully.
|
||||
* Returns {@code false} if no native library is available.
|
||||
*/
|
||||
static synchronized boolean isLoaded() {
|
||||
initialize();
|
||||
static synchronized boolean isLoaded( int apiVersion ) {
|
||||
initialize( apiVersion );
|
||||
return (nativeLibrary != null) ? nativeLibrary.isLoaded() : false;
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
private static void initialize( int apiVersion ) {
|
||||
if( initialized )
|
||||
return;
|
||||
initialized = true;
|
||||
@@ -103,7 +106,26 @@ class FlatNativeLibrary
|
||||
return; // no native library available for current OS or CPU architecture
|
||||
|
||||
// load native library
|
||||
nativeLibrary = createNativeLibrary( classifier, ext );
|
||||
NativeLibrary nativeLibrary = createNativeLibrary( classifier, ext );
|
||||
if( !nativeLibrary.isLoaded() )
|
||||
return;
|
||||
|
||||
// check API version (and check whether library works)
|
||||
try {
|
||||
int actualApiVersion = getApiVersion();
|
||||
if( actualApiVersion != apiVersion ) {
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Wrong API version in native library (expected "
|
||||
+ apiVersion + ", actual " + actualApiVersion + "). Ignoring native library.", null );
|
||||
return;
|
||||
}
|
||||
} catch( Throwable ex ) {
|
||||
// could be a UnsatisfiedLinkError in case that loading native library
|
||||
// from temp directory was blocked by some OS security mechanism
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to get API version of native library. Ignoring native library.", ex );
|
||||
return;
|
||||
}
|
||||
|
||||
FlatNativeLibrary.nativeLibrary = nativeLibrary;
|
||||
}
|
||||
|
||||
private static NativeLibrary createNativeLibrary( String classifier, String ext ) {
|
||||
@@ -117,13 +139,32 @@ class FlatNativeLibrary
|
||||
if( library.isLoaded() )
|
||||
return library;
|
||||
|
||||
LoggingFacade.INSTANCE.logSevere( "Did not find library " + libraryName + " in java.library.path, using extracted library instead", null );
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '" + System.mapLibraryName( libraryName )
|
||||
+ "' not found in java.library.path '" + System.getProperty( "java.library.path" )
|
||||
+ "'. Using extracted native library instead.", null );
|
||||
} else {
|
||||
// try standard library naming scheme
|
||||
// (same as in flatlaf.jar in package 'com/formdev/flatlaf/natives')
|
||||
File libraryFile = new File( libraryPath, System.mapLibraryName( libraryName ) );
|
||||
if( libraryFile.exists() )
|
||||
return new NativeLibrary( libraryFile, true );
|
||||
|
||||
LoggingFacade.INSTANCE.logSevere( "Did not find external library " + libraryFile + ", using extracted library instead", null );
|
||||
// try Maven naming scheme
|
||||
// (see https://www.formdev.com/flatlaf/native-libraries/)
|
||||
String libraryName2 = null;
|
||||
File jarFile = getJarFile();
|
||||
if( jarFile != null ) {
|
||||
libraryName2 = buildLibraryName( jarFile, classifier, ext );
|
||||
File libraryFile2 = new File( libraryPath, libraryName2 );
|
||||
if( libraryFile2.exists() )
|
||||
return new NativeLibrary( libraryFile2, true );
|
||||
}
|
||||
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Native library '"
|
||||
+ libraryFile.getName()
|
||||
+ (libraryName2 != null ? ("' or '" + libraryName2) : "")
|
||||
+ "' not found in '" + libraryFile.getParentFile().getAbsolutePath()
|
||||
+ "'. Using extracted native library instead.", null );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +192,51 @@ class FlatNativeLibrary
|
||||
* flatlaf-3.1-linux-x86_64.so
|
||||
*/
|
||||
private static File findLibraryBesideJar( String classifier, String ext ) {
|
||||
// get location of FlatLaf jar (or fat/uber application jar)
|
||||
File jarFile = getJarFile();
|
||||
if( jarFile == null )
|
||||
return null;
|
||||
|
||||
// build library file
|
||||
String libraryName = buildLibraryName( jarFile, classifier, ext );
|
||||
File jarDir = jarFile.getParentFile();
|
||||
|
||||
// check whether native library exists in same directory as jar
|
||||
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( 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;
|
||||
}
|
||||
|
||||
private static File getJarFile() {
|
||||
try {
|
||||
// get location of FlatLaf jar
|
||||
CodeSource codeSource = FlatNativeLibrary.class.getProtectionDomain().getCodeSource();
|
||||
@@ -168,31 +254,23 @@ class FlatNativeLibrary
|
||||
if( !jarFile.isFile() )
|
||||
return null;
|
||||
|
||||
// build library file
|
||||
String jarName = jarFile.getName();
|
||||
String jarBasename = jarName.substring( 0, jarName.lastIndexOf( '.' ) );
|
||||
File parent = jarFile.getParentFile();
|
||||
String libraryName = jarBasename
|
||||
+ (jarBasename.contains( "flatlaf" ) ? "" : "-flatlaf")
|
||||
+ '-' + classifier + '.' + ext;
|
||||
|
||||
// check whether native library exists in same directory as jar
|
||||
File libraryFile = new File( parent, libraryName );
|
||||
if( libraryFile.isFile() )
|
||||
return libraryFile;
|
||||
|
||||
// if jar is in "lib" directory, then also check whether library exists
|
||||
// in "../bin" directory
|
||||
if( parent.getName().equalsIgnoreCase( "lib" ) ) {
|
||||
libraryFile = new File( parent.getParentFile(), "bin/" + libraryName );
|
||||
if( libraryFile.isFile() )
|
||||
return libraryFile;
|
||||
}
|
||||
return jarFile;
|
||||
} catch( Exception ex ) {
|
||||
LoggingFacade.INSTANCE.logSevere( ex.getMessage(), ex );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
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;
|
||||
}
|
||||
|
||||
private static void loadJAWT() {
|
||||
|
||||
@@ -35,6 +35,8 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
*/
|
||||
class FlatNativeLinuxLibrary
|
||||
{
|
||||
private static int API_VERSION_LINUX = 3001;
|
||||
|
||||
/**
|
||||
* Checks whether native library is loaded/available.
|
||||
* <p>
|
||||
@@ -42,7 +44,7 @@ class FlatNativeLinuxLibrary
|
||||
* method of this class. Otherwise, the native library may not be loaded.
|
||||
*/
|
||||
static boolean isLoaded() {
|
||||
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded();
|
||||
return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX );
|
||||
}
|
||||
|
||||
// direction for _NET_WM_MOVERESIZE message
|
||||
|
||||
@@ -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.
|
||||
@@ -42,6 +44,8 @@ import java.awt.Window;
|
||||
*/
|
||||
public class FlatNativeMacLibrary
|
||||
{
|
||||
private static int API_VERSION_MACOS = 2001;
|
||||
|
||||
/**
|
||||
* Checks whether native library is loaded/available.
|
||||
* <p>
|
||||
@@ -49,8 +53,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( API_VERSION_MACOS );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ import com.formdev.flatlaf.util.SystemInfo;
|
||||
*/
|
||||
public class FlatNativeWindowsLibrary
|
||||
{
|
||||
private static int API_VERSION_WINDOWS = 1001;
|
||||
|
||||
private static long osBuildNumber = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
@@ -39,7 +41,7 @@ public class FlatNativeWindowsLibrary
|
||||
* method of this class. Otherwise, the native library may not be loaded.
|
||||
*/
|
||||
public static boolean isLoaded() {
|
||||
return SystemInfo.isWindows && FlatNativeLibrary.isLoaded();
|
||||
return SystemInfo.isWindows && FlatNativeLibrary.isLoaded( API_VERSION_WINDOWS );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,141 @@ 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;
|
||||
private final static Integer WINDOW_TOP_BORDER_LAYER = Integer.MAX_VALUE;
|
||||
|
||||
// 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( titlePane.windowTopBorderLayer != null )
|
||||
layeredPane.remove( titlePane.windowTopBorderLayer );
|
||||
}
|
||||
|
||||
if( newTitlePane != null )
|
||||
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
|
||||
if( newTitlePane != null ) {
|
||||
layeredPane.add( newTitlePane, getLayerForTitlePane() );
|
||||
layeredPane.add( newTitlePane.mouseLayer, TITLE_PANE_MOUSE_LAYER );
|
||||
if( newTitlePane.windowTopBorderLayer != null && newTitlePane.isWindowTopBorderNeeded() && isFullWindowContent( rootPane ) )
|
||||
layeredPane.add( newTitlePane.windowTopBorderLayer, WINDOW_TOP_BORDER_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 +448,28 @@ public class FlatRootPaneUI
|
||||
titlePane.titleBarColorsChanged();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.FULL_WINDOW_CONTENT:
|
||||
if( titlePane != null ) {
|
||||
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
|
||||
if( titlePane.windowTopBorderLayer != null ) {
|
||||
JLayeredPane layeredPane = rootPane.getLayeredPane();
|
||||
if( titlePane.isWindowTopBorderNeeded() && isFullWindowContent( rootPane ) )
|
||||
layeredPane.add( titlePane.windowTopBorderLayer, WINDOW_TOP_BORDER_LAYER );
|
||||
else
|
||||
layeredPane.remove( titlePane.windowTopBorderLayer );
|
||||
}
|
||||
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 +478,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 +550,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 +589,29 @@ 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( titlePane.windowTopBorderLayer != null ) {
|
||||
boolean show = isFullWindowContent && !titlePane.isWindowMaximized() && !isFullScreen;
|
||||
if( show )
|
||||
titlePane.windowTopBorderLayer.setBounds( 0, 0, width, 1 );
|
||||
titlePane.windowTopBorderLayer.setVisible( show );
|
||||
}
|
||||
|
||||
if( !isFullWindowContent )
|
||||
nextY += prefHeight;
|
||||
}
|
||||
|
||||
// glass pane
|
||||
@@ -467,7 +622,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 +630,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 ) );
|
||||
|
||||
@@ -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
|
||||
@@ -292,6 +301,10 @@ public class FlatSplitPaneUI
|
||||
// necessary to show/hide one-touch buttons on expand/collapse
|
||||
doLayout();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.SPLIT_PANE_EXPANDABLE_SIDE:
|
||||
revalidate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -3756,9 +3767,20 @@ debug*/
|
||||
boolean hideDisabledScrollButtons = (scrollButtonsPolicy == AS_NEEDED_SINGLE && scrollButtonsPlacement == BOTH);
|
||||
boolean trailingScrollButtons = (scrollButtonsPlacement == TRAILING);
|
||||
|
||||
// for right-to-left always use "more tabs" button for horizontal scrolling
|
||||
// For right-to-left, always use "more tabs" button for horizontal scrolling
|
||||
// because methods scrollForward() and scrollBackward() in class
|
||||
// BasicTabbedPaneUI.ScrollableTabSupport do not work for right-to-left
|
||||
// BasicTabbedPaneUI.ScrollableTabSupport do not work for right-to-left.
|
||||
//
|
||||
// One problem is that BasicTabbedPaneUI.getClosestTab(), which is used
|
||||
// to compute leadingTabIndex, does not work for right-to-left because is uses "binary" search
|
||||
// on rects[] to find tab, but rects[] is ordered in reverse order for right-to-left.
|
||||
// So leadingTabIndex is either zero or tabCount.
|
||||
// Therefore increasing/decreasing leadingTabIndex in scrollForward()
|
||||
// and scrollBackward() does not work as expected.
|
||||
// Also backward/forward scroll buttons are not correctly enabled/disabled.
|
||||
//
|
||||
// Fixing this would require replacing nearly whole functionality of class
|
||||
// BasicTabbedPaneUI.ScrollableTabSupport, which is not possible because it is private.
|
||||
boolean leftToRight = isLeftToRight();
|
||||
if( !leftToRight && isHorizontalTabPlacement( tabPane.getTabPlacement() ) ) {
|
||||
useMoreTabsButton = true;
|
||||
@@ -3840,6 +3862,8 @@ debug*/
|
||||
w -= buttonWidth;
|
||||
moreTabsButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout scroll buttons
|
||||
if( useScrollButtons ) {
|
||||
// the tabViewport view size is set in
|
||||
// BasicTabbedPaneUI.TabbedPaneScrollLayout.calculateTabRects(),
|
||||
@@ -3847,30 +3871,28 @@ debug*/
|
||||
Point viewPosition = tabViewport.getViewPosition();
|
||||
Dimension viewSize = tabViewport.getViewSize();
|
||||
|
||||
// layout forward button on trailing side
|
||||
if( !hideDisabledScrollButtons || viewSize.width - viewPosition.x > w ) {
|
||||
int buttonWidth = forwardButton.getPreferredSize().width;
|
||||
forwardButton.setBounds( x + w - buttonWidth, y, buttonWidth, h );
|
||||
w -= buttonWidth;
|
||||
forwardButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout backward button
|
||||
if( !hideDisabledScrollButtons || viewPosition.x > 0 ) {
|
||||
int buttonWidth = backwardButton.getPreferredSize().width;
|
||||
if( trailingScrollButtons ) {
|
||||
// on trailing side
|
||||
backwardButton.setBounds( leftToRight ? (x + w - buttonWidth) : x, y, buttonWidth, h );
|
||||
x += leftToRight ? 0 : buttonWidth;
|
||||
backwardButton.setBounds( x + w - buttonWidth, y, buttonWidth, h );
|
||||
} else {
|
||||
// on leading side
|
||||
backwardButton.setBounds( leftToRight ? x : (x + w - buttonWidth), y, buttonWidth, h );
|
||||
x += leftToRight ? buttonWidth : 0;
|
||||
backwardButton.setBounds( x, y, buttonWidth, h );
|
||||
x += buttonWidth;
|
||||
}
|
||||
w -= buttonWidth;
|
||||
backwardButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout forward button on trailing side
|
||||
if( !hideDisabledScrollButtons || viewSize.width - viewPosition.x > w ) {
|
||||
int buttonWidth = forwardButton.getPreferredSize().width;
|
||||
forwardButton.setBounds( leftToRight ? (x + w - buttonWidth) : x, y, buttonWidth, h );
|
||||
x += leftToRight ? 0 : buttonWidth;
|
||||
w -= buttonWidth;
|
||||
forwardButtonVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3916,6 +3938,8 @@ debug*/
|
||||
h -= buttonHeight;
|
||||
moreTabsButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout scroll buttons
|
||||
if( useScrollButtons ) {
|
||||
// the tabViewport view size is set in
|
||||
// BasicTabbedPaneUI.TabbedPaneScrollLayout.calculateTabRects(),
|
||||
@@ -3923,6 +3947,14 @@ debug*/
|
||||
Point viewPosition = tabViewport.getViewPosition();
|
||||
Dimension viewSize = tabViewport.getViewSize();
|
||||
|
||||
// layout forward button on bottom side
|
||||
if( !hideDisabledScrollButtons || viewSize.height - viewPosition.y > h ) {
|
||||
int buttonHeight = forwardButton.getPreferredSize().height;
|
||||
forwardButton.setBounds( x, y + h - buttonHeight, w, buttonHeight );
|
||||
h -= buttonHeight;
|
||||
forwardButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout backward button
|
||||
if( !hideDisabledScrollButtons || viewPosition.y > 0 ) {
|
||||
int buttonHeight = backwardButton.getPreferredSize().height;
|
||||
@@ -3937,14 +3969,6 @@ debug*/
|
||||
h -= buttonHeight;
|
||||
backwardButtonVisible = true;
|
||||
}
|
||||
|
||||
// layout forward button on bottom side
|
||||
if( !hideDisabledScrollButtons || viewSize.height - viewPosition.y > h ) {
|
||||
int buttonHeight = forwardButton.getPreferredSize().height;
|
||||
forwardButton.setBounds( x, y + h - buttonHeight, w, buttonHeight );
|
||||
h -= buttonHeight;
|
||||
forwardButtonVisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3985,10 +4009,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 +4020,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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,8 @@ 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";
|
||||
private static final boolean isWindows_10 = SystemInfo.isWindows_10_orLater && !SystemInfo.isWindows_11_orLater;
|
||||
|
||||
/** @since 2.5 */ protected final Font titleFont;
|
||||
protected final Color activeBackground;
|
||||
@@ -131,7 +132,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 +150,33 @@ 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;
|
||||
|
||||
/**
|
||||
* This panel paint a border at the top of the window in fullWindowContent mode,
|
||||
* if FlatLaf window decorations are enabled.
|
||||
* Only used on Windows 10.
|
||||
* <p>
|
||||
* This panel is not a child of the title pane.
|
||||
* Instead it is added by FlatRootPaneUI to the layered pane at a layer over all other layers.
|
||||
*/
|
||||
final JPanel windowTopBorderLayer;
|
||||
|
||||
public FlatTitlePane( JRootPane rootPane ) {
|
||||
this.rootPane = rootPane;
|
||||
|
||||
@@ -178,7 +205,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 +213,18 @@ public class FlatTitlePane
|
||||
addSubComponents();
|
||||
activeChanged( true );
|
||||
|
||||
addMouseListener( handler );
|
||||
addMouseMotionListener( handler );
|
||||
mouseLayer = new JPanel();
|
||||
mouseLayer.setOpaque( false );
|
||||
mouseLayer.addMouseListener( handler );
|
||||
mouseLayer.addMouseMotionListener( handler );
|
||||
|
||||
// necessary for closing window with double-click on icon
|
||||
iconLabel.addMouseListener( handler );
|
||||
if( isWindows_10 && FlatNativeWindowBorder.isSupported() ) {
|
||||
windowTopBorderLayer = new JPanel();
|
||||
windowTopBorderLayer.setVisible( false );
|
||||
windowTopBorderLayer.setOpaque( false );
|
||||
windowTopBorderLayer.setBorder( FlatUIUtils.nonUIResource( FlatNativeWindowBorder.WindowTopBorder.getInstance() ) );
|
||||
} else
|
||||
windowTopBorderLayer = null;
|
||||
|
||||
applyComponentOrientation( rootPane.getComponentOrientation() );
|
||||
}
|
||||
@@ -234,6 +267,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 +285,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 +333,9 @@ public class FlatTitlePane
|
||||
horizontalGlue.getWidth(), titleLabel.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
// clear hit-test cache
|
||||
lastCaptionHitTestTime = 0;
|
||||
}
|
||||
} );
|
||||
|
||||
@@ -338,6 +379,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 +465,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 +493,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 +518,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 +579,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 +595,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 +685,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 +734,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)
|
||||
@@ -846,6 +938,10 @@ public class FlatTitlePane
|
||||
return window != null && FlatNativeWindowBorder.hasCustomDecoration( window );
|
||||
}
|
||||
|
||||
boolean isWindowTopBorderNeeded() {
|
||||
return isWindows_10 && hasNativeCustomDecoration();
|
||||
}
|
||||
|
||||
// used to invoke updateNativeTitleBarHeightAndHitTestSpots() only once from latest invokeLater()
|
||||
private int laterCounter;
|
||||
|
||||
@@ -866,11 +962,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 +1027,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 +1052,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;
|
||||
@@ -1041,7 +1169,7 @@ public class FlatTitlePane
|
||||
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) )
|
||||
insets.bottom += UIScale.scale( 1 );
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() )
|
||||
if( isWindowTopBorderNeeded() && !isWindowMaximized() )
|
||||
insets = FlatUIUtils.addInsets( insets, WindowTopBorder.getInstance().getBorderInsets() );
|
||||
|
||||
return insets;
|
||||
@@ -1060,7 +1188,7 @@ public class FlatTitlePane
|
||||
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
|
||||
}
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() && !isWindowMaximized() )
|
||||
if( isWindowTopBorderNeeded() && !isWindowMaximized() && !isFullWindowContent() )
|
||||
WindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
|
||||
}
|
||||
|
||||
@@ -1116,7 +1244,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 +1253,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(),
|
||||
@@ -1224,7 +1352,7 @@ public class FlatTitlePane
|
||||
activeChanged( true );
|
||||
updateNativeTitleBarHeightAndHitTestSpots();
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() )
|
||||
if( isWindowTopBorderNeeded() )
|
||||
WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
|
||||
repaintWindowBorder();
|
||||
@@ -1235,7 +1363,7 @@ public class FlatTitlePane
|
||||
activeChanged( false );
|
||||
updateNativeTitleBarHeightAndHitTestSpots();
|
||||
|
||||
if( !SystemInfo.isWindows_11_orLater && hasNativeCustomDecoration() )
|
||||
if( isWindowTopBorderNeeded() )
|
||||
WindowTopBorder.getInstance().repaintBorder( FlatTitlePane.this );
|
||||
|
||||
repaintWindowBorder();
|
||||
@@ -1275,7 +1403,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 +1430,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 +1543,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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 ) {}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
@@ -89,7 +89,7 @@ class FlatWindowsNativeWindowBorder
|
||||
return null;
|
||||
|
||||
// check whether native library was successfully loaded
|
||||
if( !FlatNativeLibrary.isLoaded() )
|
||||
if( !FlatNativeWindowsLibrary.isLoaded() )
|
||||
return null;
|
||||
|
||||
// create new instance
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,8 @@ public class HiDPIUtils
|
||||
|
||||
case "Inter":
|
||||
case "Inter Light":
|
||||
case "Inter Semi Bold":
|
||||
case "Inter Semi Bold": // Inter v3
|
||||
case "Inter SemiBold": // Inter v4
|
||||
case "Roboto":
|
||||
case "Roboto Light":
|
||||
case "Roboto Medium":
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -25,6 +25,7 @@ import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.LinearGradientPaint;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RGBImageFilter;
|
||||
import java.io.File;
|
||||
@@ -62,6 +63,8 @@ public class FlatSVGIcon
|
||||
extends ImageIcon
|
||||
implements DisabledIconProvider
|
||||
{
|
||||
private static boolean loggingEnabled = true;
|
||||
private static boolean svgCacheEnabled = true;
|
||||
// cache that uses soft references for values, which allows freeing SVG documents if no longer used
|
||||
private static final SoftCache<String, SVGDocument> svgCache = new SoftCache<>();
|
||||
private static final SVGLoader svgLoader = new SVGLoader();
|
||||
@@ -271,7 +274,8 @@ public class FlatSVGIcon
|
||||
|
||||
if( document == null ) {
|
||||
loadFailed = true;
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load SVG icon from input stream", null );
|
||||
if( loggingEnabled )
|
||||
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: failed to load SVG icon from input stream", null );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,8 +453,9 @@ public class FlatSVGIcon
|
||||
* @param colorFilter The color filter
|
||||
* @since 1.2
|
||||
*/
|
||||
public void setColorFilter( ColorFilter colorFilter ) {
|
||||
public FlatSVGIcon setColorFilter( ColorFilter colorFilter ) {
|
||||
this.colorFilter = colorFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void update() {
|
||||
@@ -474,7 +479,8 @@ public class FlatSVGIcon
|
||||
|
||||
if( url == null ) {
|
||||
loadFailed = true;
|
||||
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
|
||||
if( loggingEnabled )
|
||||
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: resource '" + name + "' not found (if using Java modules, check whether icon package is opened in module-info.java)", null );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -484,6 +490,9 @@ public class FlatSVGIcon
|
||||
}
|
||||
|
||||
static synchronized SVGDocument loadSVG( URL url ) {
|
||||
if( !svgCacheEnabled )
|
||||
return loadSVGUncached( url );
|
||||
|
||||
// get from our cache
|
||||
String cacheKey = url.toString();
|
||||
SVGDocument document = svgCache.get( cacheKey );
|
||||
@@ -491,18 +500,25 @@ public class FlatSVGIcon
|
||||
return document;
|
||||
|
||||
// load SVG document
|
||||
document = svgLoader.load( url );
|
||||
|
||||
if( document == null ) {
|
||||
LoggingFacade.INSTANCE.logSevere( "FlatSVGIcon: failed to load '" + url + "'", null );
|
||||
return null;
|
||||
}
|
||||
document = loadSVGUncached( url );
|
||||
|
||||
svgCache.put( cacheKey, document );
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private static SVGDocument loadSVGUncached( URL url ) {
|
||||
SVGDocument document = svgLoader.load( url );
|
||||
|
||||
if( document == null ) {
|
||||
if( loggingEnabled )
|
||||
LoggingFacade.INSTANCE.logConfig( "FlatSVGIcon: failed to load '" + url + "'", null );
|
||||
return null;
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private URL getIconURL( String name, boolean dark ) {
|
||||
if( dark ) {
|
||||
int dotIndex = name.lastIndexOf( '.' );
|
||||
@@ -611,7 +627,10 @@ public class FlatSVGIcon
|
||||
}
|
||||
|
||||
private void paintSvgError( Graphics2D g, int x, int y ) {
|
||||
g.setColor( Color.red );
|
||||
if( g instanceof GraphicsFilter )
|
||||
((GraphicsFilter)g).setColorUnfiltered( Color.red );
|
||||
else
|
||||
g.setColor( Color.red );
|
||||
g.fillRect( x, y, getIconWidth(), getIconHeight() );
|
||||
}
|
||||
|
||||
@@ -692,6 +711,34 @@ public class FlatSVGIcon
|
||||
darkLaf = FlatLaf.isLafDark();
|
||||
}
|
||||
|
||||
/** @since 3.4.1 */
|
||||
public static boolean isLoggingEnabled() {
|
||||
return loggingEnabled;
|
||||
}
|
||||
|
||||
/** @since 3.4.1 */
|
||||
public static void setLoggingEnabled( boolean loggingEnabled ) {
|
||||
FlatSVGIcon.loggingEnabled = loggingEnabled;
|
||||
}
|
||||
|
||||
/** @since 3.4.1 */
|
||||
public static boolean isSVGDocumentEnabled() {
|
||||
return svgCacheEnabled;
|
||||
}
|
||||
|
||||
/** @since 3.4.1 */
|
||||
public static void setSVGDocumentEnabled( boolean svgCacheEnabled ) {
|
||||
FlatSVGIcon.svgCacheEnabled = svgCacheEnabled;
|
||||
|
||||
if( !svgCacheEnabled )
|
||||
clearSVGDocumentCache();
|
||||
}
|
||||
|
||||
/** @since 3.4.1 */
|
||||
public static void clearSVGDocumentCache() {
|
||||
svgCache.clear();
|
||||
}
|
||||
|
||||
//---- class ColorFilter --------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -978,10 +1025,23 @@ public class FlatSVGIcon
|
||||
super.setColor( filterColor( c ) );
|
||||
}
|
||||
|
||||
void setColorUnfiltered( Color c ) {
|
||||
super.setColor( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaint( Paint paint ) {
|
||||
if( paint instanceof Color )
|
||||
paint = filterColor( (Color) paint );
|
||||
else if( paint instanceof LinearGradientPaint ) {
|
||||
LinearGradientPaint oldPaint = (LinearGradientPaint) paint;
|
||||
Color[] newColors = filterColors( oldPaint.getColors() );
|
||||
if( newColors != null ) {
|
||||
paint = new LinearGradientPaint( oldPaint.getStartPoint(), oldPaint.getEndPoint(),
|
||||
oldPaint.getFractions(), newColors, oldPaint.getCycleMethod(),
|
||||
oldPaint.getColorSpace(), oldPaint.getTransform() );
|
||||
}
|
||||
}
|
||||
super.setPaint( paint );
|
||||
}
|
||||
|
||||
@@ -1001,5 +1061,15 @@ public class FlatSVGIcon
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
private Color[] filterColors( Color[] colors ) {
|
||||
Color[] newColors = new Color[colors.length];
|
||||
boolean changed = false;
|
||||
for( int i = 0; i < colors.length; i++ ) {
|
||||
newColors[i] = filterColor( colors[i] );
|
||||
changed = (changed || newColors[i] != colors[i]);
|
||||
}
|
||||
return changed ? newColors : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.extras.components;
|
||||
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import javax.swing.JSplitPane;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,29 @@ import javax.swing.JSplitPane;
|
||||
*/
|
||||
public class FlatSplitPane
|
||||
extends JSplitPane
|
||||
implements FlatStyleableComponent
|
||||
implements FlatComponentExtension, FlatStyleableComponent
|
||||
{
|
||||
// NOTE: enum names must be equal to allowed strings
|
||||
/** @since 3.4.1 */ public enum ExpandableSide { both, left, right }
|
||||
|
||||
/**
|
||||
* Returns what side of the spilt pane is allowed to expand
|
||||
* via one-touch expanding arrow buttons.
|
||||
*
|
||||
* @since 3.4.1
|
||||
*/
|
||||
public ExpandableSide getExpandableSide() {
|
||||
return getClientPropertyEnumString( SPLIT_PANE_EXPANDABLE_SIDE, ExpandableSide.class,
|
||||
null, ExpandableSide.both );
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies what side of the spilt pane is allowed to expand
|
||||
* via one-touch expanding arrow buttons.
|
||||
*
|
||||
* @since 3.4.1
|
||||
*/
|
||||
public void setExpandableSide( ExpandableSide expandableSide ) {
|
||||
putClientPropertyEnumString( SPLIT_PANE_EXPANDABLE_SIDE, expandableSide );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
// For maven compatibility, <font-version> should be in format <major>.<minor>[.<micro>].
|
||||
// <build-number> is optional and should be incremented only if a new release is
|
||||
// necessary, but the <font-version> has not changed.
|
||||
version = "3.19"
|
||||
version = "4.0"
|
||||
|
||||
if( !rootProject.hasProperty( "release" ) )
|
||||
version = version.toString() + "-SNAPSHOT"
|
||||
@@ -33,8 +33,8 @@ plugins {
|
||||
dependencies {
|
||||
implementation( project( ":flatlaf-core" ) )
|
||||
|
||||
testImplementation( libs.bundles.junit )
|
||||
testRuntimeOnly( libs.junit.engine )
|
||||
testImplementation( libs.junit )
|
||||
testRuntimeOnly( libs.junit.launcher )
|
||||
}
|
||||
|
||||
flatlafModuleInfo {
|
||||
@@ -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" ) }
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,8 @@ publishing {
|
||||
pom {
|
||||
licenses {
|
||||
license {
|
||||
name.set( "SIL OPEN FONT LICENSE Version 1.1" )
|
||||
url.set( "https://choosealicense.com/licenses/ofl-1.1/" )
|
||||
name = "SIL OPEN FONT LICENSE Version 1.1"
|
||||
url = "https://choosealicense.com/licenses/ofl-1.1/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class FlatInterFont
|
||||
* new Font( FlatInterFont.FAMILY_SEMIBOLD, Font.ITALIC, 12 );
|
||||
* }</pre>
|
||||
*/
|
||||
public static final String FAMILY_SEMIBOLD = "Inter Semi Bold";
|
||||
public static final String FAMILY_SEMIBOLD = "Inter SemiBold";
|
||||
|
||||
/**
|
||||
* Use for {@link #installStyle(String)} to install single font style.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,4 @@
|
||||
Copyright (c) 2016-2020 The Inter Project Authors.
|
||||
"Inter" is trademark of Rasmus Andersson.
|
||||
https://github.com/rsms/inter
|
||||
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
|
||||
@@ -33,8 +33,8 @@ plugins {
|
||||
dependencies {
|
||||
implementation( project( ":flatlaf-core" ) )
|
||||
|
||||
testImplementation( libs.bundles.junit )
|
||||
testRuntimeOnly( libs.junit.engine )
|
||||
testImplementation( libs.junit )
|
||||
testRuntimeOnly( libs.junit.launcher )
|
||||
}
|
||||
|
||||
flatlafModuleInfo {
|
||||
@@ -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" ) }
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,8 @@ publishing {
|
||||
pom {
|
||||
licenses {
|
||||
license {
|
||||
name.set( "SIL OPEN FONT LICENSE Version 1.1" )
|
||||
url.set( "https://choosealicense.com/licenses/ofl-1.1/" )
|
||||
name = "SIL OPEN FONT LICENSE Version 1.1"
|
||||
url = "https://choosealicense.com/licenses/ofl-1.1/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ plugins {
|
||||
dependencies {
|
||||
implementation( project( ":flatlaf-core" ) )
|
||||
|
||||
testImplementation( libs.bundles.junit )
|
||||
testRuntimeOnly( libs.junit.engine )
|
||||
testImplementation( libs.junit )
|
||||
testRuntimeOnly( libs.junit.launcher )
|
||||
}
|
||||
|
||||
flatlafModuleInfo {
|
||||
@@ -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" ) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ plugins {
|
||||
dependencies {
|
||||
implementation( project( ":flatlaf-core" ) )
|
||||
|
||||
testImplementation( libs.bundles.junit )
|
||||
testRuntimeOnly( libs.junit.engine )
|
||||
testImplementation( libs.junit )
|
||||
testRuntimeOnly( libs.junit.launcher )
|
||||
}
|
||||
|
||||
flatlafModuleInfo {
|
||||
@@ -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" ) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,11 +21,14 @@ plugins {
|
||||
}
|
||||
|
||||
flatlafJniHeaders {
|
||||
headers = listOf( "com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h" )
|
||||
headers = listOf(
|
||||
"com_formdev_flatlaf_ui_FlatNativeLibrary.h",
|
||||
"com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h"
|
||||
)
|
||||
}
|
||||
|
||||
library {
|
||||
targetMachines.set( listOf( machines.linux.x86_64 ) )
|
||||
targetMachines = listOf( machines.linux.x86_64 )
|
||||
}
|
||||
|
||||
var javaHome = System.getProperty( "java.home" )
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h"
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
|
||||
// increase this version if changing API or functionality of native library
|
||||
// also update version in Java class com.formdev.flatlaf.ui.FlatNativeLinuxLibrary
|
||||
#define API_VERSION_LINUX 3001
|
||||
|
||||
|
||||
//---- JNI methods ------------------------------------------------------------
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
( JNIEnv* env, jclass cls )
|
||||
{
|
||||
return API_VERSION_LINUX;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */
|
||||
|
||||
#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
* Method: getApiVersion
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -26,14 +26,17 @@ plugins {
|
||||
}
|
||||
|
||||
flatlafJniHeaders {
|
||||
headers = listOf( "com_formdev_flatlaf_ui_FlatNativeMacLibrary.h" )
|
||||
headers = listOf(
|
||||
"com_formdev_flatlaf_ui_FlatNativeLibrary.h",
|
||||
"com_formdev_flatlaf_ui_FlatNativeMacLibrary.h"
|
||||
)
|
||||
}
|
||||
|
||||
library {
|
||||
targetMachines.set( listOf(
|
||||
targetMachines = listOf(
|
||||
machines.macOS.architecture( "arm64" ),
|
||||
machines.macOS.x86_64
|
||||
) )
|
||||
)
|
||||
}
|
||||
|
||||
var javaHome = System.getProperty( "java.home" )
|
||||
|
||||
@@ -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, jclass cls, const char* fieldName, const char* fieldSignature, bool staticField );
|
||||
jmethodID getMethodID( JNIEnv *env, jclass cls, const char* methodName, const char* methodSignature, bool staticMethod );
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */
|
||||
|
||||
#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
* Method: getApiVersion
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h"
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
|
||||
// increase this version if changing API or functionality of native library
|
||||
// also update version in Java class com.formdev.flatlaf.ui.FlatNativeMacLibrary
|
||||
#define API_VERSION_MACOS 2001
|
||||
|
||||
|
||||
//---- JNI methods ------------------------------------------------------------
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
( JNIEnv* env, jclass cls )
|
||||
{
|
||||
return API_VERSION_MACOS;
|
||||
}
|
||||
@@ -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,9 +32,23 @@ 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, jclass cls, const char* fieldName, const char* fieldSignature, bool staticField ) {
|
||||
// NSLog( @"getFieldID %s %s", fieldName, fieldSignature );
|
||||
|
||||
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 );
|
||||
NSLog( @"FlatLaf: failed to lookup field '%s' of type '%s'", fieldName, fieldSignature );
|
||||
env->ExceptionDescribe(); // print stack trace
|
||||
env->ExceptionClear();
|
||||
return NULL;
|
||||
@@ -42,3 +56,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;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <jni.h>
|
||||
#import "JNIUtils.h"
|
||||
#import "JNFRunLoop.h"
|
||||
@@ -24,31 +25,70 @@
|
||||
* @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 class IDs (done only once because variables are static)
|
||||
static jclass lwWindowPeerClass = findClass( env, "sun/lwawt/LWWindowPeer", true );
|
||||
static jclass cfRetainedResourceClass = findClass( env, "sun/lwawt/macosx/CFRetainedResource", true );
|
||||
if( lwWindowPeerClass == NULL || cfRetainedResourceClass == NULL )
|
||||
return NULL;
|
||||
|
||||
// initialize field IDs (done only once because variables are static)
|
||||
static jfieldID peerID = getFieldID( env, findClass( env, "java/awt/Component", false ), "peer", "Ljava/awt/peer/ComponentPeer;", false );
|
||||
static jfieldID platformWindowID = getFieldID( env, lwWindowPeerClass, "platformWindow", "Lsun/lwawt/PlatformWindow;", false );
|
||||
static jfieldID ptrID = getFieldID( env, cfRetainedResourceClass, "ptr", "J", false );
|
||||
if( peerID == NULL || platformWindowID == NULL || ptrID == NULL )
|
||||
return NULL;
|
||||
|
||||
// get field java.awt.Component.peer
|
||||
jobject peer = env->GetObjectField( window, peerID );
|
||||
if( peer == NULL )
|
||||
if( peer == NULL || !env->IsInstanceOf( peer, lwWindowPeerClass ) )
|
||||
return NULL;
|
||||
|
||||
// get field sun.lwawt.LWWindowPeer.platformWindow
|
||||
jobject platformWindow = env->GetObjectField( peer, platformWindowID );
|
||||
if( platformWindow == NULL )
|
||||
if( platformWindow == NULL || !env->IsInstanceOf( platformWindow, cfRetainedResourceClass ) )
|
||||
return NULL;
|
||||
|
||||
// get field sun.lwawt.macosx.CFRetainedResource.ptr
|
||||
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 +127,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;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ plugins {
|
||||
|
||||
flatlafJniHeaders {
|
||||
headers = listOf(
|
||||
"com_formdev_flatlaf_ui_FlatNativeLibrary.h",
|
||||
"com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h",
|
||||
"com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder.h",
|
||||
"com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h"
|
||||
@@ -29,11 +30,11 @@ flatlafJniHeaders {
|
||||
}
|
||||
|
||||
library {
|
||||
targetMachines.set( listOf(
|
||||
targetMachines = listOf(
|
||||
machines.windows.x86,
|
||||
machines.windows.x86_64,
|
||||
machines.windows.architecture( "aarch64" )
|
||||
) )
|
||||
)
|
||||
}
|
||||
|
||||
var javaHome = System.getProperty( "java.home" )
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h"
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
|
||||
// increase this version if changing API or functionality of native library
|
||||
// also update version in Java class com.formdev.flatlaf.ui.FlatNativeWindowsLibrary
|
||||
#define API_VERSION_WINDOWS 1001
|
||||
|
||||
|
||||
//---- JNI methods ------------------------------------------------------------
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
( JNIEnv* env, jclass cls )
|
||||
{
|
||||
return API_VERSION_WINDOWS;
|
||||
}
|
||||
@@ -377,6 +377,7 @@ LRESULT FlatWndProc::WmNcCalcSize( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lP
|
||||
// (using MONITOR_DEFAULTTONEAREST finds right monitor when restoring from minimized)
|
||||
HMONITOR hMonitor = ::MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
|
||||
MONITORINFO monitorInfo{ 0 };
|
||||
monitorInfo.cbSize = sizeof( monitorInfo );
|
||||
::GetMonitorInfo( hMonitor, &monitorInfo );
|
||||
|
||||
// If there's a taskbar on any side of the monitor, reduce our size
|
||||
@@ -537,7 +538,6 @@ void FlatWndProc::setMenuItemState( HMENU systemMenu, int item, bool enabled ) {
|
||||
MENUITEMINFO mii{ 0 };
|
||||
mii.cbSize = sizeof( mii );
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.fState = enabled ? MF_ENABLED : MF_DISABLED;
|
||||
::SetMenuItemInfo( systemMenu, item, FALSE, &mii );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_formdev_flatlaf_ui_FlatNativeLibrary */
|
||||
|
||||
#ifndef _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#define _Included_com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_formdev_flatlaf_ui_FlatNativeLibrary
|
||||
* Method: getApiVersion
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLibrary_getApiVersion
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -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 )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.util.Random;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
@@ -178,6 +179,20 @@ public class FlatContainerTest
|
||||
tabbedPane.addTab( "Tab 4", new JLabel( "non-opaque content", SwingConstants.CENTER ) );
|
||||
break;
|
||||
|
||||
case 4:
|
||||
tabbedPane.addTab( "Tab 5", new JLabel( "random background content", SwingConstants.CENTER ) {
|
||||
Random random = new Random();
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
g.setColor( new Color( random.nextInt() ) );
|
||||
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
|
||||
super.paintComponent( g );
|
||||
}
|
||||
} );
|
||||
break;
|
||||
|
||||
default:
|
||||
int index = tabbedPane.getTabCount() + 1;
|
||||
tabbedPane.addTab( "Tab " + index, createTab( "tab content " + index ) );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 )
|
||||
} )
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user