Native window decorations: support changing title bar background and foreground colors per window (via client property)

This commit is contained in:
Karl Tauber
2021-04-05 14:19:41 +02:00
parent 801b555835
commit f456185f7d
6 changed files with 99 additions and 29 deletions

View File

@@ -9,6 +9,10 @@ FlatLaf Change Log
supports window decorations (`FlatLaf.supportsNativeWindowDecorations()`) and supports window decorations (`FlatLaf.supportsNativeWindowDecorations()`) and
to toggle window decorations of all windows to toggle window decorations of all windows
(`FlatLaf.setUseNativeWindowDecorations(boolean)`). (`FlatLaf.setUseNativeWindowDecorations(boolean)`).
- Native window decorations: Support changing title bar background and
foreground colors per window. (set client properties
`JRootPane.titleBarBackground` and `JRootPane.titleBarForeground` on root pane
to a `java.awt.Color`).
#### Fixed bugs #### Fixed bugs
@@ -30,8 +34,8 @@ FlatLaf Change Log
#### New features and improvements #### New features and improvements
- Native window decorations: Support disabling native window decorations per - Native window decorations: Support disabling native window decorations per
window. (set client property `JRootPane.useWindowDecorations` to `false` on window. (set client property `JRootPane.useWindowDecorations` on root pane to
root pane). `false`).
- Support running on WinPE. (issue #279) - Support running on WinPE. (issue #279)
#### Fixed bugs #### Fixed bugs

View File

@@ -269,6 +269,26 @@ public interface FlatClientProperties
*/ */
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"; String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/**
* Background color of window title bar (requires enabled window decorations).
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
*
* @since 1.1.2
*/
String TITLE_BAR_BACKGROUND = "JRootPane.titleBarBackground";
/**
* Foreground color of window title bar (requires enabled window decorations).
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.awt.Color}
*
* @since 1.1.2
*/
String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground";
//---- JScrollBar / JScrollPane ------------------------------------------- //---- JScrollBar / JScrollPane -------------------------------------------
/** /**

View File

@@ -256,6 +256,12 @@ public class FlatRootPaneUI
rootPane.repaint(); rootPane.repaint();
} }
break; break;
case FlatClientProperties.TITLE_BAR_BACKGROUND:
case FlatClientProperties.TITLE_BAR_FOREGROUND:
if( titlePane != null )
titlePane.titleBarColorsChanged();
break;
} }
} }

View File

@@ -265,10 +265,17 @@ public class FlatTitlePane
} }
protected void activeChanged( boolean active ) { protected void activeChanged( boolean active ) {
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ); Color background = FlatClientProperties.clientPropertyColor( rootPane, FlatClientProperties.TITLE_BAR_BACKGROUND, null );
Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground ); Color foreground = FlatClientProperties.clientPropertyColor( rootPane, FlatClientProperties.TITLE_BAR_FOREGROUND, null );
Color foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground ); Color titleForeground = foreground;
Color titleForeground = (hasEmbeddedMenuBar && active) ? FlatUIUtils.nonUIResource( embeddedForeground ) : foreground; if( background == null )
background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground );
if( foreground == null ) {
foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground );
titleForeground = (active && hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ))
? FlatUIUtils.nonUIResource( embeddedForeground )
: foreground;
}
setBackground( background ); setBackground( background );
titleLabel.setForeground( titleForeground ); titleLabel.setForeground( titleForeground );
@@ -480,6 +487,11 @@ public class FlatTitlePane
return null; return null;
} }
protected void titleBarColorsChanged() {
activeChanged( window == null || window.isActive() );
repaint();
}
protected void menuBarChanged() { protected void menuBarChanged() {
menuBarPlaceholder.invalidate(); menuBarPlaceholder.invalidate();

View File

@@ -170,6 +170,16 @@ public class FlatWindowDecorationsTest
} }
} }
private void colorizeTitleBar() {
JRootPane rootPane = getWindowRootPane();
if( rootPane == null )
return;
boolean colorize = colorizeTitleBarCheckBox.isSelected();
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_BACKGROUND, colorize ? Color.green : null );
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_FOREGROUND, colorize ? Color.blue : null );
}
private void colorizeMenuBar() { private void colorizeMenuBar() {
boolean colorize = colorizeMenuBarCheckBox.isSelected(); boolean colorize = colorizeMenuBarCheckBox.isSelected();
Color menuBarBackground = colorize ? new Color( 0xffccff ) : UIManager.getColor( "MenuBar.background" ); Color menuBarBackground = colorize ? new Color( 0xffccff ) : UIManager.getColor( "MenuBar.background" );
@@ -372,6 +382,7 @@ public class FlatWindowDecorationsTest
colorizeMenuBarCheckBox = new JCheckBox(); colorizeMenuBarCheckBox = new JCheckBox();
unifiedBackgroundCheckBox = new JCheckBox(); unifiedBackgroundCheckBox = new JCheckBox();
colorizeMenusCheckBox = new JCheckBox(); colorizeMenusCheckBox = new JCheckBox();
colorizeTitleBarCheckBox = new JCheckBox();
resizableCheckBox = new JCheckBox(); resizableCheckBox = new JCheckBox();
maximizedBoundsCheckBox = new JCheckBox(); maximizedBoundsCheckBox = new JCheckBox();
undecoratedCheckBox = new JCheckBox(); undecoratedCheckBox = new JCheckBox();
@@ -432,6 +443,7 @@ public class FlatWindowDecorationsTest
"para[]0" + "para[]0" +
"[]0" + "[]0" +
"[]0" + "[]0" +
"[]0" +
"[]unrel" + "[]unrel" +
"[]0" + "[]0" +
"[]unrel" + "[]unrel" +
@@ -488,7 +500,7 @@ public class FlatWindowDecorationsTest
changeTitleButton.addActionListener(e -> changeTitle()); changeTitleButton.addActionListener(e -> changeTitle());
panel3.add(changeTitleButton, "cell 0 4"); panel3.add(changeTitleButton, "cell 0 4");
} }
add(panel3, "cell 2 0 1 7,aligny top,growy 0"); add(panel3, "cell 2 0 1 8,aligny top,growy 0");
//---- menuBarEmbeddedCheckBox ---- //---- menuBarEmbeddedCheckBox ----
menuBarEmbeddedCheckBox.setText("embedded menu bar"); menuBarEmbeddedCheckBox.setText("embedded menu bar");
@@ -522,34 +534,39 @@ public class FlatWindowDecorationsTest
colorizeMenusCheckBox.addActionListener(e -> colorizeMenus()); colorizeMenusCheckBox.addActionListener(e -> colorizeMenus());
add(colorizeMenusCheckBox, "cell 1 3"); add(colorizeMenusCheckBox, "cell 1 3");
//---- colorizeTitleBarCheckBox ----
colorizeTitleBarCheckBox.setText("colorize title bar");
colorizeTitleBarCheckBox.addActionListener(e -> colorizeTitleBar());
add(colorizeTitleBarCheckBox, "cell 0 4");
//---- resizableCheckBox ---- //---- resizableCheckBox ----
resizableCheckBox.setText("resizable"); resizableCheckBox.setText("resizable");
resizableCheckBox.setSelected(true); resizableCheckBox.setSelected(true);
resizableCheckBox.addActionListener(e -> resizableChanged()); resizableCheckBox.addActionListener(e -> resizableChanged());
add(resizableCheckBox, "cell 0 4"); add(resizableCheckBox, "cell 0 5");
//---- maximizedBoundsCheckBox ---- //---- maximizedBoundsCheckBox ----
maximizedBoundsCheckBox.setText("maximized bounds (50,100, 1000,700)"); maximizedBoundsCheckBox.setText("maximized bounds (50,100, 1000,700)");
maximizedBoundsCheckBox.addActionListener(e -> maximizedBoundsChanged()); maximizedBoundsCheckBox.addActionListener(e -> maximizedBoundsChanged());
add(maximizedBoundsCheckBox, "cell 1 4"); add(maximizedBoundsCheckBox, "cell 1 5");
//---- undecoratedCheckBox ---- //---- undecoratedCheckBox ----
undecoratedCheckBox.setText("undecorated"); undecoratedCheckBox.setText("undecorated");
undecoratedCheckBox.addActionListener(e -> undecoratedChanged()); undecoratedCheckBox.addActionListener(e -> undecoratedChanged());
add(undecoratedCheckBox, "cell 0 5"); add(undecoratedCheckBox, "cell 0 6");
//---- fullScreenCheckBox ---- //---- fullScreenCheckBox ----
fullScreenCheckBox.setText("full screen"); fullScreenCheckBox.setText("full screen");
fullScreenCheckBox.addActionListener(e -> fullScreenChanged()); fullScreenCheckBox.addActionListener(e -> fullScreenChanged());
add(fullScreenCheckBox, "cell 1 5"); add(fullScreenCheckBox, "cell 1 6");
//---- label1 ---- //---- label1 ----
label1.setText("Style:"); label1.setText("Style:");
add(label1, "cell 0 6"); add(label1, "cell 0 7");
//---- label2 ---- //---- label2 ----
label2.setText("Icon:"); label2.setText("Icon:");
add(label2, "cell 1 6"); add(label2, "cell 1 7");
//======== panel1 ======== //======== panel1 ========
{ {
@@ -614,7 +631,7 @@ public class FlatWindowDecorationsTest
styleFileChooserRadioButton.addActionListener(e -> decorationStyleChanged()); styleFileChooserRadioButton.addActionListener(e -> decorationStyleChanged());
panel1.add(styleFileChooserRadioButton, "cell 0 8"); panel1.add(styleFileChooserRadioButton, "cell 0 8");
} }
add(panel1, "cell 0 7"); add(panel1, "cell 0 8");
//======== panel2 ======== //======== panel2 ========
{ {
@@ -643,18 +660,18 @@ public class FlatWindowDecorationsTest
iconTestRandomRadioButton.addActionListener(e -> iconChanged()); iconTestRandomRadioButton.addActionListener(e -> iconChanged());
panel2.add(iconTestRandomRadioButton, "cell 0 2"); panel2.add(iconTestRandomRadioButton, "cell 0 2");
} }
add(panel2, "cell 1 7"); add(panel2, "cell 1 8");
//---- openDialogButton ---- //---- openDialogButton ----
openDialogButton.setText("Open Dialog"); openDialogButton.setText("Open Dialog");
openDialogButton.addActionListener(e -> openDialog()); openDialogButton.addActionListener(e -> openDialog());
add(openDialogButton, "cell 0 8 2 1"); add(openDialogButton, "cell 0 9 2 1");
//---- openFrameButton ---- //---- openFrameButton ----
openFrameButton.setText("Open Frame"); openFrameButton.setText("Open Frame");
openFrameButton.setMnemonic('A'); openFrameButton.setMnemonic('A');
openFrameButton.addActionListener(e -> openFrame()); openFrameButton.addActionListener(e -> openFrame());
add(openFrameButton, "cell 0 8 2 1"); add(openFrameButton, "cell 0 9 2 1");
//======== menuBar ======== //======== menuBar ========
{ {
@@ -858,6 +875,7 @@ public class FlatWindowDecorationsTest
private JCheckBox colorizeMenuBarCheckBox; private JCheckBox colorizeMenuBarCheckBox;
private JCheckBox unifiedBackgroundCheckBox; private JCheckBox unifiedBackgroundCheckBox;
private JCheckBox colorizeMenusCheckBox; private JCheckBox colorizeMenusCheckBox;
private JCheckBox colorizeTitleBarCheckBox;
private JCheckBox resizableCheckBox; private JCheckBox resizableCheckBox;
private JCheckBox maximizedBoundsCheckBox; private JCheckBox maximizedBoundsCheckBox;
private JCheckBox undecoratedCheckBox; private JCheckBox undecoratedCheckBox;

View File

@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[left]para[left][fill]" "$columnConstraints": "[left]para[left][fill]"
"$rowConstraints": "para[]0[]0[]0[]unrel[]0[]unrel[][top][]" "$rowConstraints": "para[]0[]0[]0[]0[]unrel[]0[]unrel[][top][]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
@@ -90,7 +90,7 @@ new FormModel {
"value": "cell 0 4" "value": "cell 0 4"
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0 1 7,aligny top,growy 0" "value": "cell 2 0 1 8,aligny top,growy 0"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "menuBarEmbeddedCheckBox" name: "menuBarEmbeddedCheckBox"
@@ -154,6 +154,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3" "value": "cell 1 3"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "colorizeTitleBarCheckBox"
"text": "colorize title bar"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "colorizeTitleBar", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "resizableCheckBox" name: "resizableCheckBox"
"text": "resizable" "text": "resizable"
@@ -163,7 +173,7 @@ new FormModel {
} }
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "resizableChanged", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "resizableChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4" "value": "cell 0 5"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "maximizedBoundsCheckBox" name: "maximizedBoundsCheckBox"
@@ -173,7 +183,7 @@ new FormModel {
} }
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "maximizedBoundsChanged", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "maximizedBoundsChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4" "value": "cell 1 5"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "undecoratedCheckBox" name: "undecoratedCheckBox"
@@ -183,7 +193,7 @@ new FormModel {
} }
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "undecoratedChanged", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "undecoratedChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5" "value": "cell 0 6"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) { add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "fullScreenCheckBox" name: "fullScreenCheckBox"
@@ -193,19 +203,19 @@ new FormModel {
} }
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fullScreenChanged", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fullScreenChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5" "value": "cell 1 6"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1" name: "label1"
"text": "Style:" "text": "Style:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6" "value": "cell 0 7"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "label2" name: "label2"
"text": "Icon:" "text": "Icon:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6" "value": "cell 1 7"
} ) } )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[fill]"
@@ -314,7 +324,7 @@ new FormModel {
"value": "cell 0 8" "value": "cell 0 8"
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 7" "value": "cell 0 8"
} ) } )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[fill]"
@@ -357,14 +367,14 @@ new FormModel {
"value": "cell 0 2" "value": "cell 0 2"
} ) } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7" "value": "cell 1 8"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "openDialogButton" name: "openDialogButton"
"text": "Open Dialog" "text": "Open Dialog"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openDialog", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openDialog", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 8 2 1" "value": "cell 0 9 2 1"
} ) } )
add( new FormComponent( "javax.swing.JButton" ) { add( new FormComponent( "javax.swing.JButton" ) {
name: "openFrameButton" name: "openFrameButton"
@@ -372,7 +382,7 @@ new FormModel {
"mnemonic": 65 "mnemonic": 65
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openFrame", false ) ) addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openFrame", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 8 2 1" "value": "cell 0 9 2 1"
} ) } )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )