diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d6bca82..b44ee9e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ FlatLaf Change Log - TabbedPane: New option to disable tab run rotation in wrap layout. Set UI value `TabbedPane.rotateTabRuns` to `false`. (issue #574) +- Native window decorations (Windows 10/11 only): Added client property to mark + components in embedded menu bar as "caption" (allow moving window). (issue + #569) #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 18c64934..5819e274 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -253,6 +253,19 @@ public interface FlatClientProperties */ String COMPONENT_FOCUS_OWNER = "JComponent.focusOwner"; + /** + * Specifies whether a component in a embedded menu bar 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, + * but it gets mouse entered/exited/moved events. + *
+ * Component {@link javax.swing.JComponent}
+ * Value type {@link java.lang.Boolean}
+ *
+ * @since 2.5
+ */
+ String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";
+
//---- Popup --------------------------------------------------------------
/**
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
index 48301ab9..aa40c63b 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
@@ -861,26 +861,32 @@ debug*/
r.height -= resizeHeight;
}
- Component horizontalGlue = findHorizontalGlue( menuBar );
- if( horizontalGlue != null ) {
- // If menu bar is embedded and contains a horizontal glue component,
- // then split the hit test spot into two spots so that
- // the glue component area can be used to move the window.
+ 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( horizontalGlue, 0, 0, window );
- int x2 = glueLocation.x + horizontalGlue.getWidth();
- Rectangle r2;
- if( getComponentOrientation().isLeftToRight() ) {
- r2 = new Rectangle( x2, r.y, (r.x + r.width) - x2, r.height );
+ 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 = 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;
+ r.width = (r.x + r.width) - x2;
+ r.x = x2;
+ }
+ if( r2.width > 0 )
+ hitTestSpots.add( r2 );
}
- hitTestSpots.add( r2 );
}
hitTestSpots.add( r );
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java
index c7e2937f..e605dd3c 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java
@@ -262,6 +262,16 @@ debug*/
menuBar.revalidate();
}
+ private void addCaption() {
+ 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 removeMenu() {
int menuCount = menuBar.getMenuCount();
if( menuCount <= 0 )
@@ -445,6 +455,7 @@ debug*/
JPanel panel3 = new JPanel();
addMenuButton = new JButton();
addGlueButton = new JButton();
+ addCaptionButton = new JButton();
removeMenuButton = new JButton();
changeMenuButton = new JButton();
changeTitleButton = new JButton();
@@ -547,6 +558,7 @@ debug*/
"[]" +
"[]" +
"[]" +
+ "[]" +
"[]unrel" +
"[]"));
@@ -560,20 +572,25 @@ debug*/
addGlueButton.addActionListener(e -> addGlue());
panel3.add(addGlueButton, "cell 0 1");
+ //---- addCaptionButton ----
+ addCaptionButton.setText("Add caption");
+ addCaptionButton.addActionListener(e -> addCaption());
+ panel3.add(addCaptionButton, "cell 0 2");
+
//---- removeMenuButton ----
removeMenuButton.setText("Remove menu");
removeMenuButton.addActionListener(e -> removeMenu());
- panel3.add(removeMenuButton, "cell 0 2");
+ panel3.add(removeMenuButton, "cell 0 3");
//---- changeMenuButton ----
changeMenuButton.setText("Change menu");
changeMenuButton.addActionListener(e -> changeMenu());
- panel3.add(changeMenuButton, "cell 0 3");
+ panel3.add(changeMenuButton, "cell 0 4");
//---- changeTitleButton ----
changeTitleButton.setText("Change title");
changeTitleButton.addActionListener(e -> changeTitle());
- panel3.add(changeTitleButton, "cell 0 4");
+ panel3.add(changeTitleButton, "cell 0 5");
}
add(panel3, "cell 2 0 1 8,aligny top,growy 0");
@@ -961,6 +978,7 @@ debug*/
private JCheckBox rightCompCheckBox;
private JButton addMenuButton;
private JButton addGlueButton;
+ private JButton addCaptionButton;
private JButton removeMenuButton;
private JButton changeMenuButton;
private JButton changeTitleButton;
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd
index c5aa442e..048d768f 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd
@@ -36,7 +36,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" ) {
@@ -59,6 +59,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "addCaptionButton"
+ "text": "Add caption"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addCaption", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 2"
+ } )
add( new FormComponent( "javax.swing.JButton" ) {
name: "removeMenuButton"
"text": "Remove menu"
@@ -67,7 +77,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "removeMenu", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
- "value": "cell 0 2"
+ "value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "changeMenuButton"
@@ -77,7 +87,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeMenu", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
- "value": "cell 0 3"
+ "value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "changeTitleButton"
@@ -87,7 +97,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeTitle", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
- "value": "cell 0 4"
+ "value": "cell 0 5"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0 1 8,aligny top,growy 0"