Skip to content

Commit

Permalink
macOS fullWindowContent mode:
Browse files Browse the repository at this point in the history
- added title bar buttons placeholder
- added client property to root pane that contains title bar buttons bounds
- undone toolbar extensions from commit ea2447d
  • Loading branch information
DevCharly committed Jan 21, 2024
1 parent f68a871 commit 28278a7
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 331 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,76 @@ public interface FlatClientProperties
String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption";


//---- Panel --------------------------------------------------------------

/**
* Marks the panel as placeholder for the iconfify/maximize/close buttons
* in fullWindowContent mode.
* <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]"}.
* <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 fullWindowContent mode
* is supported 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 {@code " horizontal"} or {@code " vertical"} to the value string
* to specify that the placeholder preferred size should be limited to one orientation.
* E.g. {@code "win horizontal"} means that the placeholder preferred width is
* equal to iconfify/maximize/close buttons width, but preferred height is zero.
* <p>
* 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 --------------------------------------------------------------

/**
Expand Down Expand Up @@ -388,6 +458,20 @@ public interface FlatClientProperties
*/
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";

/**
* 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}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.formdev.flatlaf.ui;

import java.awt.Rectangle;
import java.awt.Window;

/**
Expand Down Expand Up @@ -54,14 +55,14 @@ public static boolean isLoaded() {

public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor );

/** @since 3.4 */
public static final int
BUTTON_STYLE_DEFAULT = 0,
BUTTON_STYLE_MEDIUM = 1,
BUTTON_STYLE_LARGE = 2;

public native static boolean setWindowButtonStyle( Window window, int buttonStyle );
public native static int getWindowButtonAreaWidth( Window window );
public native static int getWindowTitleBarHeight( Window window );
public native static boolean isWindowFullScreen( Window window );
public native static boolean windowToggleFullScreen( Window window );
/** @since 3.4 */ public native static boolean setWindowButtonStyle( Window window, int buttonStyle );
/** @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 );
}
40 changes: 40 additions & 0 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPanelUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

package com.formdev.flatlaf.ui;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.beans.PropertyChangeEvent;
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;
Expand Down Expand Up @@ -69,6 +71,8 @@ public void installUI( JComponent c ) {
super.installUI( c );

c.addPropertyChangeListener( this );
if( c.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER ) != null )
FullWindowContentSupport.registerPlaceholder( c );

installStyle( (JPanel) c );
}
Expand All @@ -78,10 +82,20 @@ public void uninstallUI( JComponent c ) {
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 ) {
Expand All @@ -98,6 +112,17 @@ public void propertyChange( PropertyChangeEvent e ) {
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;
}
}

Expand Down Expand Up @@ -162,4 +187,19 @@ public void update( Graphics g, JComponent c ) {

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 );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public class FlatRootPaneUI
private LayoutManager oldLayout;
private PropertyChangeListener ancestorListener;
private ComponentListener componentListener;
private ComponentListener macFullWindowContentListener;

public static ComponentUI createUI( JComponent c ) {
return new FlatRootPaneUI();
Expand Down Expand Up @@ -207,6 +208,9 @@ public void componentShown( ComponentEvent e ) {
};
root.addPropertyChangeListener( "ancestor", ancestorListener );
}

if( SystemInfo.isMacFullWindowContentSupported )
macFullWindowContentListener = FullWindowContentSupport.macInstallListeners( root );
}

@Override
Expand All @@ -223,6 +227,11 @@ protected void uninstallListeners( JRootPane root ) {
root.removePropertyChangeListener( "ancestor", ancestorListener );
ancestorListener = null;
}

if( SystemInfo.isMacFullWindowContentSupported ) {
FullWindowContentSupport.macUninstallListeners( root, macFullWindowContentListener );
macFullWindowContentListener = null;
}
}

/** @since 1.1.2 */
Expand Down Expand Up @@ -359,6 +368,10 @@ public void propertyChange( PropertyChangeEvent e ) {
titlePane.titleBarColorsChanged();
break;

case FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS:
FullWindowContentSupport.revalidatePlaceholders( rootPane );
break;

case FlatClientProperties.GLASS_PANE_FULL_HEIGHT:
rootPane.revalidate();
break;
Expand All @@ -371,26 +384,30 @@ public void propertyChange( PropertyChangeEvent e ) {
case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE:
case "ancestor":
if( SystemInfo.isMacFullWindowContentSupported &&
SystemInfo.isJava_17_orLater &&
rootPane.isDisplayable() &&
FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) &&
FlatNativeMacLibrary.isLoaded() )
FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) )
{
int buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_DEFAULT;
Object value = rootPane.getClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE );
switch( String.valueOf( value ) ) {
case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_MEDIUM:
buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_MEDIUM;
break;

case "true":
case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_LARGE:
buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_LARGE;
break;
// set window button style
if( SystemInfo.isJava_17_orLater && FlatNativeMacLibrary.isLoaded() ) {
int buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_DEFAULT;
Object value = rootPane.getClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE );
switch( String.valueOf( value ) ) {
case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_MEDIUM:
buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_MEDIUM;
break;

case "true":
case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_LARGE:
buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_LARGE;
break;
}

Window window = SwingUtilities.windowForComponent( rootPane );
FlatNativeMacLibrary.setWindowButtonStyle( window, buttonStyle );
}

Window window = SwingUtilities.windowForComponent( rootPane );
FlatNativeMacLibrary.setWindowButtonStyle( window, buttonStyle );
// update buttons bounds client property
FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane );
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.function.Function;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ToolBarUI;
import com.formdev.flatlaf.util.UIScale;
Expand Down Expand Up @@ -115,18 +114,6 @@ public Insets getBorderInsets( Component c, Insets insets ) {
insets.top += gripInset;
}

// on macOS, add some extra space to left side for close/minimize/zoom buttons (if necessary)
if( c instanceof JToolBar && FlatToolBarUI.isMacOSMainToolbar( (JToolBar) c ) ) {
// get button area width from macOS
int buttonBarWidth = FlatNativeMacLibrary.isLoaded()
? FlatNativeMacLibrary.getWindowButtonAreaWidth( SwingUtilities.windowForComponent( c ) )
: -1;
if( buttonBarWidth < 0 )
buttonBarWidth = 68; // default width if NSWindow does not have a toolbar

insets.left += buttonBarWidth;
}

return insets;
}

Expand Down

0 comments on commit 28278a7

Please sign in to comment.