Skip to content

Commit

Permalink
support painting separator line between window title and content (issue
Browse files Browse the repository at this point in the history
  • Loading branch information
DevCharly committed Oct 14, 2020
1 parent 4b7ef6e commit ad7ff2b
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 21 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ FlatLaf Change Log

## 0.44-SNAPSHOT

#### New features and improvements

- Support painting separator line between window title and content (use UI value
`TitlePane.borderColor`). (issue #184)


#### Fixed bugs

- Custom window decorations: Not visible menu bar is now ignored in layout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import javax.swing.JMenuBar;
import javax.swing.UIManager;

Expand All @@ -40,16 +38,8 @@ public class FlatMenuBarBorder

@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
float lineHeight = scale( (float) 1 );

FlatUIUtils.setRenderingHints( g2 );
g2.setColor( borderColor );
g2.fill( new Rectangle2D.Float( x, y + height - lineHeight, width, lineHeight ) );
} finally {
g2.dispose();
}
float lineHeight = scale( (float) 1 );
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.BorderUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
Expand All @@ -45,6 +46,7 @@
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;

/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRootPane}.
Expand All @@ -54,6 +56,7 @@
* @uiDefault RootPane.border Border
* @uiDefault RootPane.activeBorderColor Color
* @uiDefault RootPane.inactiveBorderColor Color
* @uiDefault TitlePane.borderColor Color optional
*
* <!-- FlatWindowResizer -->
*
Expand All @@ -71,6 +74,8 @@ public class FlatRootPaneUI
static final boolean canUseJBRCustomDecorations
= SystemInfo.isJetBrainsJVM_11_orLater && SystemInfo.isWindows_10_orLater;

protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );

protected JRootPane rootPane;
protected FlatTitlePane titlePane;
protected FlatWindowResizer windowResizer;
Expand All @@ -89,11 +94,21 @@ public void installUI( JComponent c ) {

if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
installClientDecorations();
else
installBorder();

if( canUseJBRCustomDecorations )
JBRCustomDecorations.install( rootPane );
}

protected void installBorder() {
if( borderColor != null ) {
Border b = rootPane.getBorder();
if( b == null || b instanceof UIResource )
rootPane.setBorder( new FlatWindowTitleBorder( borderColor ) );
}
}

@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
Expand All @@ -119,11 +134,8 @@ protected void installDefaults( JRootPane c ) {
}

// enable dark window appearance on macOS when running in JetBrains Runtime
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater ) {
LookAndFeel laf = UIManager.getLookAndFeel();
boolean isDark = laf instanceof FlatLaf && ((FlatLaf)laf).isDark();
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", isDark );
}
if( SystemInfo.isJetBrainsJVM && SystemInfo.isMacOS_10_14_Mojave_orLater )
c.putClientProperty( "jetbrains.awt.windowDarkAppearance", FlatLaf.isLafDark() );
}

protected void installClientDecorations() {
Expand Down Expand Up @@ -203,6 +215,8 @@ public void propertyChange( PropertyChangeEvent e ) {
uninstallClientDecorations();
if( rootPane.getWindowDecorationStyle() != JRootPane.NONE )
installClientDecorations();
else
installBorder();
break;

case FlatClientProperties.MENU_BAR_EMBEDDED:
Expand Down Expand Up @@ -373,4 +387,40 @@ protected boolean isWindowMaximized( Component c ) {
: false;
}
}

//---- class FlatWindowTitleBorder ----------------------------------------

private static class FlatWindowTitleBorder
extends BorderUIResource.EmptyBorderUIResource
{
private final Color borderColor;

FlatWindowTitleBorder( Color borderColor ) {
super( 0, 0, 0, 0 );
this.borderColor = borderColor;
}

@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( showBorder( c ) ) {
float lineHeight = UIScale.scale( (float) 1 );
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y, width, lineHeight );
}
}

@Override
public Insets getBorderInsets( Component c, Insets insets ) {
insets.set( showBorder( c ) ? 1 : 0, 0, 0, 0 );
return insets;
}

private boolean showBorder( Component c ) {
Container parent = c.getParent();
return
(parent instanceof JFrame &&
(((JFrame)parent).getJMenuBar() == null ||
!((JFrame)parent).getJMenuBar().isVisible())) ||
parent instanceof JDialog;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
* @uiDefault TitlePane.foreground Color
* @uiDefault TitlePane.inactiveForeground Color
* @uiDefault TitlePane.embeddedForeground Color
* @uiDefault TitlePane.borderColor Color optional
* @uiDefault TitlePane.iconSize Dimension
* @uiDefault TitlePane.iconMargins Insets
* @uiDefault TitlePane.titleMargins Insets
Expand All @@ -97,6 +98,7 @@ public class FlatTitlePane
protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" );
protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" );
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );

protected final Insets menuBarMargins = UIManager.getInsets( "TitlePane.menuBarMargins" );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
Expand Down Expand Up @@ -422,6 +424,10 @@ protected Insets getMenuBarMargins() {
protected void menuBarChanged() {
menuBarPlaceholder.invalidate();

// necessary for the case that an embedded menu bar is made invisible
// and a border color is specified
repaint();

// update title foreground color
EventQueue.invokeLater( () -> {
activeChanged( window == null || window.isActive() );
Expand Down Expand Up @@ -662,12 +668,13 @@ protected class FlatTitlePaneBorder
public Insets getBorderInsets( Component c, Insets insets ) {
super.getBorderInsets( c, insets );

// if menu bar is embedded, add bottom insets of menu bar border
Border menuBarBorder = getMenuBarBorder();
if( menuBarBorder != null ) {
// if menu bar is embedded, add bottom insets of menu bar border
Insets menuBarInsets = menuBarBorder.getBorderInsets( c );
insets.bottom += menuBarInsets.bottom;
}
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) )
insets.bottom += UIScale.scale( 1 );

if( hasJBRCustomDecoration() )
insets = FlatUIUtils.addInsets( insets, JBRWindowTopBorder.getInstance().getBorderInsets() );
Expand All @@ -677,10 +684,16 @@ public Insets getBorderInsets( Component c, Insets insets ) {

@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
// if menu bar is embedded, paint menu bar border
// paint bottom border
Border menuBarBorder = getMenuBarBorder();
if( menuBarBorder != null )
if( menuBarBorder != null ) {
// if menu bar is embedded, paint menu bar border
menuBarBorder.paintBorder( c, g, x, y, width, height );
} else if( borderColor != null && (rootPane.getJMenuBar() == null || !rootPane.getJMenuBar().isVisible()) ) {
// paint border between title pane and content if border color is specified
float lineHeight = UIScale.scale( (float) 1 );
FlatUIUtils.paintFilledRectangle( g, borderColor, x, y + height - lineHeight, width, lineHeight );
}

if( hasJBRCustomDecoration() )
JBRWindowTopBorder.getInstance().paintBorder( c, g, x, y, width, height );
Expand Down
11 changes: 11 additions & 0 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,17 @@ public static Shape createComponentRectangle( float x, float y, float w, float h
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
}

static void paintFilledRectangle( Graphics g, Color color, float x, float y, float w, float h ) {
Graphics2D g2 = (Graphics2D) g.create();
try {
FlatUIUtils.setRenderingHints( g2 );
g2.setColor( color );
g2.fill( new Rectangle2D.Float( x, y, w, h ) );
} finally {
g2.dispose();
}
}

/**
* Fill background with parent's background color because the visible component
* is smaller than its bounds (for the focus decoration).
Expand Down

0 comments on commit ad7ff2b

Please sign in to comment.