InternalFrame: limit internal frame bounds to parent bounds on resize; honor maximum size of internal frame (issue #362)

This commit is contained in:
Karl Tauber
2021-07-29 16:44:50 +02:00
parent ca7f5045ae
commit 60e5861de4
4 changed files with 134 additions and 22 deletions

View File

@@ -3,6 +3,8 @@ FlatLaf Change Log
## 1.5-SNAPSHOT
- InternalFrame: Limit internal frame bounds to parent bounds on resize. Also
honor maximum size of internal frame. (issue #362)
- Popup: Fixed incorrectly placed drop shadow for medium-weight popups in
maximized windows. (issue #358)

View File

@@ -181,8 +181,12 @@ public abstract class FlatWindowResizer
protected abstract boolean isWindowResizable();
protected abstract Rectangle getWindowBounds();
protected abstract void setWindowBounds( Rectangle r );
protected abstract boolean limitToParentBounds();
protected abstract Rectangle getParentBounds();
protected abstract boolean honorMinimumSizeOnResize();
protected abstract boolean honorMaximumSizeOnResize();
protected abstract Dimension getWindowMinimumSize();
protected abstract Dimension getWindowMaximumSize();
protected void beginResizing( int direction ) {}
protected void endResizing() {}
@@ -283,6 +287,16 @@ public abstract class FlatWindowResizer
}
}
@Override
protected boolean limitToParentBounds() {
return false;
}
@Override
protected Rectangle getParentBounds() {
return null;
}
@Override
protected boolean honorMinimumSizeOnResize() {
return
@@ -290,11 +304,21 @@ public abstract class FlatWindowResizer
(honorDialogMinimumSizeOnResize && window instanceof Dialog);
}
@Override
protected boolean honorMaximumSizeOnResize() {
return false;
}
@Override
protected Dimension getWindowMinimumSize() {
return window.getMinimumSize();
}
@Override
protected Dimension getWindowMaximumSize() {
return window.getMaximumSize();
}
@Override
boolean isDialog() {
return window instanceof Dialog;
@@ -354,16 +378,36 @@ public abstract class FlatWindowResizer
desktopManager.get().resizeFrame( getFrame(), r.x, r.y, r.width, r.height );
}
@Override
protected boolean limitToParentBounds() {
return true;
}
@Override
protected Rectangle getParentBounds() {
return getFrame().getParent().getBounds();
}
@Override
protected boolean honorMinimumSizeOnResize() {
return true;
}
@Override
protected boolean honorMaximumSizeOnResize() {
return true;
}
@Override
protected Dimension getWindowMinimumSize() {
return getFrame().getMinimumSize();
}
@Override
protected Dimension getWindowMaximumSize() {
return getFrame().getMaximumSize();
}
@Override
protected void beginResizing( int direction ) {
desktopManager.get().beginResizingFrame( getFrame(), direction );
@@ -521,7 +565,7 @@ debug*/
int xOnScreen = e.getXOnScreen();
int yOnScreen = e.getYOnScreen();
// Get current window bounds and compute new bounds based them.
// Get current window bounds and compute new bounds based on them.
// This is necessary because window manager may alter window bounds while resizing.
// E.g. when having two monitors with different scale factors and resizing
// a window on first screen to the second screen, then the window manager may
@@ -535,41 +579,72 @@ debug*/
// top
if( resizeDir == N_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR ) {
newBounds.y = yOnScreen - dragTopOffset;
if( limitToParentBounds() && newBounds.y < 0 )
newBounds.y = 0;
newBounds.height += (oldBounds.y - newBounds.y);
}
// bottom
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
if( resizeDir == S_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.height = (yOnScreen + dragBottomOffset) - newBounds.y;
if( limitToParentBounds() ) {
int parentHeight = getParentBounds().height;
if( newBounds.y + newBounds.height > parentHeight )
newBounds.height = parentHeight - newBounds.y;
}
}
// left
if( resizeDir == W_RESIZE_CURSOR || resizeDir == NW_RESIZE_CURSOR || resizeDir == SW_RESIZE_CURSOR ) {
newBounds.x = xOnScreen - dragLeftOffset;
if( limitToParentBounds() && newBounds.x < 0 )
newBounds.x = 0;
newBounds.width += (oldBounds.x - newBounds.x);
}
// right
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR )
if( resizeDir == E_RESIZE_CURSOR || resizeDir == NE_RESIZE_CURSOR || resizeDir == SE_RESIZE_CURSOR ) {
newBounds.width = (xOnScreen + dragRightOffset) - newBounds.x;
if( limitToParentBounds() ) {
int parentWidth = getParentBounds().width;
if( newBounds.x + newBounds.width > parentWidth )
newBounds.width = parentWidth - newBounds.x;
}
}
// apply minimum window size
Dimension minimumSize = honorMinimumSizeOnResize() ? getWindowMinimumSize() : null;
if( minimumSize == null )
minimumSize = UIScale.scale( new Dimension( 150, 50 ) );
if( newBounds.width < minimumSize.width ) {
if( newBounds.x != oldBounds.x )
newBounds.x -= (minimumSize.width - newBounds.width);
newBounds.width = minimumSize.width;
}
if( newBounds.height < minimumSize.height ) {
if( newBounds.y != oldBounds.y )
newBounds.y -= (minimumSize.height - newBounds.height);
newBounds.height = minimumSize.height;
if( newBounds.width < minimumSize.width )
changeWidth( oldBounds, newBounds, minimumSize.width );
if( newBounds.height < minimumSize.height )
changeHeight( oldBounds, newBounds, minimumSize.height );
// apply maximum window size
if( honorMaximumSizeOnResize() ) {
Dimension maximumSize = getWindowMaximumSize();
if( newBounds.width > maximumSize.width )
changeWidth( oldBounds, newBounds, maximumSize.width );
if( newBounds.height > maximumSize.height )
changeHeight( oldBounds, newBounds, maximumSize.height );
}
// set window bounds
if( !newBounds.equals( oldBounds ) )
setWindowBounds( newBounds );
}
private void changeWidth( Rectangle oldBounds, Rectangle newBounds, int width ) {
if( newBounds.x != oldBounds.x )
newBounds.x -= (width - newBounds.width);
newBounds.width = width;
}
private void changeHeight( Rectangle oldBounds, Rectangle newBounds, int height ) {
if( newBounds.y != oldBounds.y )
newBounds.y -= (height - newBounds.height);
newBounds.height = height;
}
}
}

View File

@@ -89,6 +89,15 @@ public class FlatInternalFrameTest
};
internalFrame.setContentPane( panel );
if( minSizeCheckBox.isSelected() ) {
internalFrame.setMinimumSize( new Dimension( 300, 150 ) );
panel.add( new JLabel( "min 300,150" ) );
}
if( maxSizeCheckBox.isSelected() ) {
internalFrame.setMaximumSize( new Dimension( 400, 200 ) );
panel.add( new JLabel( "max 400,200" ) );
}
if( !palette.getComponentOrientation().isLeftToRight() )
internalFrame.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
@@ -123,6 +132,8 @@ public class FlatInternalFrameTest
maximizableCheckBox = new JCheckBox();
iconCheckBox = new FlatTriStateCheckBox();
menuBarCheckBox = new JCheckBox();
minSizeCheckBox = new JCheckBox();
maxSizeCheckBox = new JCheckBox();
titleLabel = new JLabel();
titleField = new JTextField();
createFrameButton = new JButton();
@@ -158,6 +169,8 @@ public class FlatInternalFrameTest
"[fill]0" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]unrel" +
"[]unrel"));
@@ -189,18 +202,26 @@ public class FlatInternalFrameTest
menuBarCheckBox.setText("Menu Bar");
paletteContentPane.add(menuBarCheckBox, "cell 1 2");
//---- minSizeCheckBox ----
minSizeCheckBox.setText("Minimum size 300,150");
paletteContentPane.add(minSizeCheckBox, "cell 0 3 2 1,alignx left,growx 0");
//---- maxSizeCheckBox ----
maxSizeCheckBox.setText("Maximum size 400,200");
paletteContentPane.add(maxSizeCheckBox, "cell 0 4 2 1,alignx left,growx 0");
//---- titleLabel ----
titleLabel.setText("Frame title:");
paletteContentPane.add(titleLabel, "cell 0 3");
paletteContentPane.add(titleField, "cell 1 3");
paletteContentPane.add(titleLabel, "cell 0 5");
paletteContentPane.add(titleField, "cell 1 5");
//---- createFrameButton ----
createFrameButton.setText("Create Frame");
createFrameButton.addActionListener(e -> createInternalFrame());
paletteContentPane.add(createFrameButton, "cell 1 4,alignx right,growx 0");
paletteContentPane.add(createFrameButton, "cell 1 6,alignx right,growx 0");
}
desktopPane.add(palette, JLayeredPane.PALETTE_LAYER);
palette.setBounds(15, 25, 275, 185);
palette.setBounds(15, 25, 275, 275);
}
add(desktopPane, "cell 0 0,width 600,height 600");
@@ -234,6 +255,8 @@ public class FlatInternalFrameTest
private JCheckBox maximizableCheckBox;
private FlatTriStateCheckBox iconCheckBox;
private JCheckBox menuBarCheckBox;
private JCheckBox minSizeCheckBox;
private JCheckBox maxSizeCheckBox;
private JLabel titleLabel;
private JTextField titleField;
private JButton createFrameButton;

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8"
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -14,7 +14,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JInternalFrame", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill]"
"$rowConstraints": "[fill]0[]0[]0[]unrel[]unrel"
"$rowConstraints": "[fill]0[]0[]0[]0[]0[]unrel[]unrel"
} ) {
name: "palette"
"visible": true
@@ -62,29 +62,41 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "minSizeCheckBox"
"text": "Minimum size 300,150"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3 2 1,alignx left,growx 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "maxSizeCheckBox"
"text": "Maximum size 400,200"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4 2 1,alignx left,growx 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "titleLabel"
"text": "Frame title:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
"value": "cell 0 5"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "titleField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3"
"value": "cell 1 5"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "createFrameButton"
"text": "Create Frame"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "createInternalFrame", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4,alignx right,growx 0"
"value": "cell 1 6,alignx right,growx 0"
} )
}, new FormLayoutConstraints( null ) {
"x": 15
"y": 25
"width": 275
"height": 185
"height": 275
"layer": 100
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {