mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
Merge branch 'windows-full-window-content'
This commit is contained in:
@@ -5,6 +5,9 @@ FlatLaf Change Log
|
||||
|
||||
#### 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)
|
||||
|
||||
@@ -257,13 +257,36 @@ 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
|
||||
*/
|
||||
@@ -274,7 +297,7 @@ public interface FlatClientProperties
|
||||
|
||||
/**
|
||||
* Marks the panel as placeholder for the iconfify/maximize/close buttons
|
||||
* in fullWindowContent mode.
|
||||
* 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}.
|
||||
@@ -462,6 +485,32 @@ 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.
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -269,15 +269,28 @@ 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;
|
||||
|
||||
// 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( newTitlePane != null )
|
||||
layeredPane.add( newTitlePane, TITLE_PANE_LAYER );
|
||||
if( newTitlePane != null ) {
|
||||
layeredPane.add( newTitlePane, getLayerForTitlePane() );
|
||||
layeredPane.add( newTitlePane.mouseLayer, TITLE_PANE_MOUSE_LAYER );
|
||||
}
|
||||
|
||||
titlePane = newTitlePane;
|
||||
}
|
||||
@@ -430,6 +443,17 @@ public class FlatRootPaneUI
|
||||
titlePane.titleBarColorsChanged();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.FULL_WINDOW_CONTENT:
|
||||
if( titlePane != null ) {
|
||||
rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() );
|
||||
titlePane.updateIcon();
|
||||
titlePane.updateVisibility();
|
||||
titlePane.updateFullWindowContentButtonsBoundsProperty();
|
||||
}
|
||||
FullWindowContentSupport.revalidatePlaceholders( rootPane );
|
||||
rootPane.revalidate();
|
||||
break;
|
||||
|
||||
case FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS:
|
||||
FullWindowContentSupport.revalidatePlaceholders( rootPane );
|
||||
break;
|
||||
@@ -471,11 +495,14 @@ public class FlatRootPaneUI
|
||||
}
|
||||
}
|
||||
|
||||
/** @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 */
|
||||
@@ -511,23 +538,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();
|
||||
@@ -552,12 +577,23 @@ 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( !isFullWindowContent )
|
||||
nextY += prefHeight;
|
||||
}
|
||||
|
||||
// glass pane
|
||||
@@ -568,7 +604,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();
|
||||
@@ -576,13 +612,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 @@ 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";
|
||||
|
||||
/** @since 2.5 */ protected final Font titleFont;
|
||||
protected final Color activeBackground;
|
||||
@@ -131,7 +131,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 +149,23 @@ 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;
|
||||
|
||||
public FlatTitlePane( JRootPane rootPane ) {
|
||||
this.rootPane = rootPane;
|
||||
|
||||
@@ -178,7 +194,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 +202,10 @@ public class FlatTitlePane
|
||||
addSubComponents();
|
||||
activeChanged( true );
|
||||
|
||||
addMouseListener( handler );
|
||||
addMouseMotionListener( handler );
|
||||
|
||||
// necessary for closing window with double-click on icon
|
||||
iconLabel.addMouseListener( handler );
|
||||
mouseLayer = new JPanel();
|
||||
mouseLayer.setOpaque( false );
|
||||
mouseLayer.addMouseListener( handler );
|
||||
mouseLayer.addMouseMotionListener( handler );
|
||||
|
||||
applyComponentOrientation( rootPane.getComponentOrientation() );
|
||||
}
|
||||
@@ -234,6 +248,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 +266,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 +314,9 @@ public class FlatTitlePane
|
||||
horizontalGlue.getWidth(), titleLabel.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
// clear hit-test cache
|
||||
lastCaptionHitTestTime = 0;
|
||||
}
|
||||
} );
|
||||
|
||||
@@ -338,6 +360,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 +446,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 +474,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 +499,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 +560,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 +576,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 +666,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 +715,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)
|
||||
@@ -866,11 +939,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 +1004,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 +1029,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;
|
||||
@@ -1116,7 +1221,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 +1230,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(),
|
||||
@@ -1275,7 +1380,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 +1407,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 +1520,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 ------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
@@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -209,9 +209,11 @@ class FullWindowContentSupport
|
||||
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, r.width - 1, r.height - 1 );
|
||||
g.drawLine( r.x, r.height - 1, r.width - 1, r.y );
|
||||
g.drawLine( r.x, r.y, x2, y2 );
|
||||
g.drawLine( r.x, y2, x2, r.y );
|
||||
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,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
|
||||
|
||||
@@ -73,6 +73,7 @@ class DemoFrame
|
||||
initComponents();
|
||||
updateFontMenuItems();
|
||||
initAccentColors();
|
||||
initFullWindowContent();
|
||||
controlBar.initialize( this, tabbedPane );
|
||||
|
||||
setIconImages( FlatSVGUtils.createWindowIconImages( "/com/formdev/flatlaf/demo/FlatLaf.svg" ) );
|
||||
@@ -101,9 +102,6 @@ class DemoFrame
|
||||
rootPane.putClientProperty( "apple.awt.windowTitleVisible", false );
|
||||
else
|
||||
setTitle( null );
|
||||
|
||||
// uncomment this line to see title bar buttons placeholders in fullWindowContent mode
|
||||
// UIManager.put( "FlatLaf.debug.panel.showPlaceholders", true );
|
||||
}
|
||||
|
||||
// enable full screen mode for this window (for Java 8 - 10; not necessary for Java 11+)
|
||||
@@ -463,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();
|
||||
@@ -528,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 ========
|
||||
@@ -538,7 +566,7 @@ class DemoFrame
|
||||
Container contentPane = getContentPane();
|
||||
contentPane.setLayout(new BorderLayout());
|
||||
|
||||
//======== menuBar1 ========
|
||||
//======== menuBar ========
|
||||
{
|
||||
|
||||
//======== fileMenu ========
|
||||
@@ -583,7 +611,7 @@ class DemoFrame
|
||||
exitMenuItem.addActionListener(e -> exitActionPerformed());
|
||||
fileMenu.add(exitMenuItem);
|
||||
}
|
||||
menuBar1.add(fileMenu);
|
||||
menuBar.add(fileMenu);
|
||||
|
||||
//======== editMenu ========
|
||||
{
|
||||
@@ -636,7 +664,7 @@ class DemoFrame
|
||||
deleteMenuItem.addActionListener(e -> menuItemActionPerformed(e));
|
||||
editMenu.add(deleteMenuItem);
|
||||
}
|
||||
menuBar1.add(editMenu);
|
||||
menuBar.add(editMenu);
|
||||
|
||||
//======== viewMenu ========
|
||||
{
|
||||
@@ -736,7 +764,7 @@ class DemoFrame
|
||||
radioButtonMenuItem3.addActionListener(e -> menuItemActionPerformed(e));
|
||||
viewMenu.add(radioButtonMenuItem3);
|
||||
}
|
||||
menuBar1.add(viewMenu);
|
||||
menuBar.add(viewMenu);
|
||||
|
||||
//======== fontMenu ========
|
||||
{
|
||||
@@ -760,7 +788,7 @@ class DemoFrame
|
||||
decrFontMenuItem.addActionListener(e -> decrFont());
|
||||
fontMenu.add(decrFontMenuItem);
|
||||
}
|
||||
menuBar1.add(fontMenu);
|
||||
menuBar.add(fontMenu);
|
||||
|
||||
//======== optionsMenu ========
|
||||
{
|
||||
@@ -812,7 +840,7 @@ class DemoFrame
|
||||
showUIDefaultsInspectorMenuItem.addActionListener(e -> showUIDefaultsInspector());
|
||||
optionsMenu.add(showUIDefaultsInspectorMenuItem);
|
||||
}
|
||||
menuBar1.add(optionsMenu);
|
||||
menuBar.add(optionsMenu);
|
||||
|
||||
//======== helpMenu ========
|
||||
{
|
||||
@@ -825,9 +853,9 @@ class DemoFrame
|
||||
aboutMenuItem.addActionListener(e -> aboutActionPerformed());
|
||||
helpMenu.add(aboutMenuItem);
|
||||
}
|
||||
menuBar1.add(helpMenu);
|
||||
menuBar.add(helpMenu);
|
||||
}
|
||||
setJMenuBar(menuBar1);
|
||||
setJMenuBar(menuBar);
|
||||
|
||||
//======== toolBarPanel ========
|
||||
{
|
||||
@@ -884,7 +912,7 @@ class DemoFrame
|
||||
}
|
||||
toolBarPanel.add(toolBar, BorderLayout.CENTER);
|
||||
}
|
||||
contentPane.add(toolBarPanel, BorderLayout.NORTH);
|
||||
contentPane.add(toolBarPanel, BorderLayout.PAGE_START);
|
||||
|
||||
//======== contentPanel ========
|
||||
{
|
||||
@@ -904,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();
|
||||
@@ -925,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() );
|
||||
@@ -938,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
|
||||
@@ -959,9 +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() );
|
||||
@@ -982,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;
|
||||
|
||||
@@ -74,7 +74,7 @@ new FormModel {
|
||||
"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"
|
||||
@@ -115,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"
|
||||
} )
|
||||
@@ -131,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 |
@@ -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 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1266,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
|
||||
|
||||
@@ -1271,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
|
||||
|
||||
@@ -1276,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
|
||||
|
||||
@@ -1280,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
|
||||
|
||||
@@ -1307,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
|
||||
|
||||
@@ -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(
|
||||
@@ -117,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" );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,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 )
|
||||
@@ -515,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() {
|
||||
@@ -538,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();
|
||||
@@ -548,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();
|
||||
@@ -578,6 +620,7 @@ debug*/
|
||||
typeNormalRadioButton = new JRadioButton();
|
||||
typeUtilityRadioButton = new JRadioButton();
|
||||
typeSmallRadioButton = new JRadioButton();
|
||||
showRectanglesCheckBox = new JCheckBox();
|
||||
menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu();
|
||||
JMenuItem newMenuItem = new JMenuItem();
|
||||
@@ -616,6 +659,7 @@ debug*/
|
||||
// rows
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
|
||||
//======== panel7 ========
|
||||
@@ -673,6 +717,8 @@ debug*/
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]rel" +
|
||||
"[]rel" +
|
||||
"[]"));
|
||||
|
||||
//---- showIconCheckBox ----
|
||||
@@ -703,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");
|
||||
|
||||
@@ -761,6 +820,7 @@ debug*/
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]" +
|
||||
"[]unrel" +
|
||||
"[]"));
|
||||
|
||||
@@ -779,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");
|
||||
|
||||
@@ -969,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 ========
|
||||
{
|
||||
|
||||
@@ -1176,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;
|
||||
@@ -1184,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;
|
||||
@@ -1209,6 +1283,7 @@ debug*/
|
||||
private JRadioButton typeNormalRadioButton;
|
||||
private JRadioButton typeUtilityRadioButton;
|
||||
private JRadioButton typeSmallRadioButton;
|
||||
private JCheckBox showRectanglesCheckBox;
|
||||
private JMenuBar menuBar;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -552,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 )
|
||||
|
||||
@@ -1039,7 +1039,6 @@ TitlePane.inactiveBackground
|
||||
TitlePane.inactiveForeground
|
||||
TitlePane.maximizeIcon
|
||||
TitlePane.menuBarEmbedded
|
||||
TitlePane.menuBarResizeHeight
|
||||
TitlePane.menuBarTitleGap
|
||||
TitlePane.menuBarTitleMinimumGap
|
||||
TitlePane.noIconLeftGap
|
||||
@@ -1071,7 +1070,6 @@ TitlePane.small.iconifyIcon
|
||||
TitlePane.small.inactiveBackground
|
||||
TitlePane.small.inactiveForeground
|
||||
TitlePane.small.maximizeIcon
|
||||
TitlePane.small.menuBarResizeHeight
|
||||
TitlePane.small.menuBarTitleGap
|
||||
TitlePane.small.menuBarTitleMinimumGap
|
||||
TitlePane.small.noIconLeftGap
|
||||
|
||||
Reference in New Issue
Block a user