diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4304a79a..274674e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@ FlatLaf Change Log
## 3.7-SNAPSHOT
+#### New features and improvements
+
+- Zooming API. (PR #1051)
+
+#### Fixed bugs
+
- TextField: Fixed wrong leading/trailing icon placement if border is set to
`null`. (issue #1047)
- Extras: UI defaults inspector: Exclude inspector window from being blocked by
@@ -10,6 +16,7 @@ FlatLaf Change Log
- JideButton, JideToggleButton, JideSplitButton and JideToggleSplitButton: Paint
border in button style `TOOLBAR_STYLE` if in selected state. (issue #1045)
+
## 3.6.2
#### New features and improvements
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
index dfa9764f..6f5c3169 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java
@@ -368,6 +368,22 @@ public abstract class FlatLaf
String.format( "a, address { color: #%06x; }", linkColor.getRGB() & 0xffffff ) );
}
};
+
+ // Initialize UIScale user scale factor immediately after FlatLaf was activated,
+ // which is necessary to ensure that UIScale.setZoomFactor(float)
+ // scales FlatLaf defaultDont correctly even if UIScale.scale() was not yet used.
+ // In other words: Without this, UIScale.setZoomFactor(float) would
+ // not work correctly if invoked between FlatLaf.setup() and crating UI.
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ @Override
+ public void propertyChange( PropertyChangeEvent e ) {
+ if( "lookAndFeel".equals( e.getPropertyName() ) ) {
+ UIManager.removePropertyChangeListener( this );
+ UIScale.getUserScaleFactor();
+ }
+ }
+ };
+ UIManager.addPropertyChangeListener( listener );
}
@Override
@@ -707,11 +723,22 @@ public abstract class FlatLaf
uiFont = ((ActiveFont)defaultFont).derive( baseFont, fontSize -> {
return Math.round( fontSize * UIScale.computeFontScaleFactor( baseFont ) );
} );
- }
+ } else if( defaultFont instanceof LazyValue )
+ uiFont = ActiveFont.toUIResource( (Font) ((LazyValue)defaultFont).createValue( defaults ) );
// increase font size if system property "flatlaf.uiScale" is set
uiFont = UIScale.applyCustomScaleFactor( uiFont );
+ // apply zoom factor to font size
+ float zoomFactor = UIScale.getZoomFactor();
+ if( zoomFactor != 1 ) {
+ // see also UIScale.setZoomFactor()
+ int unzoomedFontSize = uiFont.getSize();
+ defaults.put( "defaultFont.unzoomedSize", unzoomedFontSize );
+ int newFontSize = Math.max( Math.round( unzoomedFontSize * zoomFactor ), 1 );
+ uiFont = new FontUIResource( uiFont.deriveFont( (float) newFontSize ) );
+ }
+
// set default font
defaults.put( "defaultFont", uiFont );
}
@@ -1768,7 +1795,7 @@ public abstract class FlatLaf
return toUIResource( baseFont );
}
- private FontUIResource toUIResource( Font font ) {
+ private static FontUIResource toUIResource( Font font ) {
// make sure that font is a UIResource for LaF switching
return (font instanceof FontUIResource)
? (FontUIResource) font
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java
index 01c17ab6..cd3bafae 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java
@@ -27,7 +27,9 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.Method;
+import java.util.Arrays;
import javax.swing.LookAndFeel;
+import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource;
@@ -61,16 +63,28 @@ import com.formdev.flatlaf.FlatSystemProperties;
* or if the default font is changed.
* The user scale factor is computed based on the used font.
* The JRE does not scale anything.
- * So we have to invoke {@link #scale(float)} where necessary.
+ * So we have to invoke {@link #scale(int)} where necessary.
* There is only one user scale factor for all displays.
* The user scale factor may change if the active LaF, "defaultFont" or "Label.font" has changed.
* If system scaling mode is available the user scale factor is usually 1,
* but may be larger on Linux or if the default font is changed.
*
+ *
Zooming
+ *
+ * Zooming allows appliations to easily zoom their UI, if FlatLaf is active Laf.
+ * This is done by changing user scale factor and default font.
+ * There are methods to increase, decrease and reset zoom factor.
+ *
+ * Note: Only standard Swing components are zoomed.
+ * Custom components need to use {@link #scale(int)} to zoom their UI.
+ *
* @author Karl Tauber
*/
public class UIScale
{
+ /** @since 3.7 */ public static final String PROP_USER_SCALE_FACTOR = "userScaleFactor";
+ /** @since 3.7 */ public static final String PROP_ZOOM_FACTOR = "zoomFactor";
+
private static final boolean DEBUG = false;
private static PropertyChangeSupport changeSupport;
@@ -87,7 +101,7 @@ public class UIScale
changeSupport.removePropertyChangeListener( listener );
}
- //---- system scaling (Java 9) --------------------------------------------
+ //---- system scaling (Java 9+) -------------------------------------------
private static Boolean jreHiDPI;
@@ -135,10 +149,13 @@ public class UIScale
return (isSystemScalingEnabled() && gc != null) ? gc.getDefaultTransform().getScaleX() : 1;
}
- //---- user scaling (Java 8) ----------------------------------------------
+ //---- user scaling (Java 8 / zooming) ------------------------------------
+ private static float unzoomedScaleFactor = 1;
private static float scaleFactor = 1;
private static boolean initialized;
+ private static boolean listenerInitialized; // use extra flag for unit tests
+ private static boolean ignoreFontChange;
private static void initialize() {
if( initialized )
@@ -148,33 +165,43 @@ public class UIScale
if( !isUserScalingEnabled() )
return;
+ initializeListener();
+
+ updateScaleFactor( true );
+ }
+
+ private static void initializeListener() {
+ if( listenerInitialized )
+ return;
+ listenerInitialized = true;
+
// listener to update scale factor if LaF changed, "defaultFont" or "Label.font" changed
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case "lookAndFeel":
- // it is not necessary (and possible) to remove listener of old LaF defaults
+ // it is not possible (and necessary) to remove listener of old LaF defaults
+ // because it is not possible to access the UIDefault object of the old LaF
if( e.getNewValue() instanceof LookAndFeel )
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( this );
- updateScaleFactor();
+ updateScaleFactor( true );
break;
case "defaultFont":
case "Label.font":
- updateScaleFactor();
+ if( !ignoreFontChange )
+ updateScaleFactor( false );
break;
}
}
};
- UIManager.addPropertyChangeListener( listener );
UIManager.getDefaults().addPropertyChangeListener( listener );
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( listener );
-
- updateScaleFactor();
+ UIManager.addPropertyChangeListener( listener );
}
- private static void updateScaleFactor() {
+ private static void updateScaleFactor( boolean lafChanged ) {
if( !isUserScalingEnabled() )
return;
@@ -185,17 +212,20 @@ public class UIScale
return;
}
- // use font size to calculate scale factor (instead of DPI)
- // because even if we are on a HiDPI display it is not sure
- // that a larger font size is set by the current LaF
- // (e.g. can avoid large icons with small text)
+ // get font that is used to calculate scale factor
Font font = null;
if( UIManager.getLookAndFeel() instanceof FlatLaf )
font = UIManager.getFont( "defaultFont" );
if( font == null )
font = UIManager.getFont( "Label.font" );
- setUserScaleFactor( computeFontScaleFactor( font ), true );
+ float fontScaleFactor = computeFontScaleFactor( font );
+ if( lafChanged && UIManager.getLookAndFeel() instanceof FlatLaf ) {
+ // FlatLaf has applied zoom factor in FlatLaf.initDefaultFont() to defaultFont,
+ // so we need to take it into account to get correct user scale factor
+ fontScaleFactor /= zoomFactor;
+ }
+ setUserScaleFactor( fontScaleFactor, true );
}
/**
@@ -204,7 +234,7 @@ public class UIScale
* @since 2
*/
public static float computeFontScaleFactor( Font font ) {
- if( SystemInfo.isWindows ) {
+ if( SystemInfo.isWindows && !inUnitTests ) {
// Special handling for Windows to be compatible with OS scaling,
// which distinguish between "screen scaling" and "text scaling".
// - Windows "screen scaling" scales everything (text, icon, gaps, etc.)
@@ -335,7 +365,7 @@ public class UIScale
}
/**
- * Returns the user scale factor.
+ * Returns the user scale factor (including zoom factor).
*/
public static float getUserScaleFactor() {
initialize();
@@ -345,27 +375,49 @@ public class UIScale
/**
* Sets the user scale factor.
*/
- private static void setUserScaleFactor( float scaleFactor, boolean normalize ) {
- if( normalize ) {
- if( scaleFactor < 1f ) {
- scaleFactor = FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ALLOW_SCALE_DOWN, false )
- ? Math.round( scaleFactor * 10f ) / 10f // round small scale factor to 1/10
- : 1f;
- } else if( scaleFactor > 1f ) // round scale factor to 1/4
- scaleFactor = Math.round( scaleFactor * 4f ) / 4f;
- }
+ private static void setUserScaleFactor( float unzoomedScaleFactor, boolean normalize ) {
+ if( normalize )
+ unzoomedScaleFactor = normalizeScaleFactor( unzoomedScaleFactor );
// minimum scale factor
- scaleFactor = Math.max( scaleFactor, 0.1f );
+ unzoomedScaleFactor = Math.max( unzoomedScaleFactor, 0.1f );
+
+ if( unzoomedScaleFactor == UIScale.unzoomedScaleFactor )
+ return;
+
+ if( DEBUG )
+ System.out.println( "Unzoomed scale factor " + UIScale.unzoomedScaleFactor + " --> " + unzoomedScaleFactor );
+
+ UIScale.unzoomedScaleFactor = unzoomedScaleFactor;
+ setScaleFactor( unzoomedScaleFactor * zoomFactor );
+ }
+
+ private static void setScaleFactor( float scaleFactor ) {
+ // round scale factor to 1/100
+ scaleFactor = Math.round( scaleFactor * 100f ) / 100f;
+
+ if( scaleFactor == UIScale.scaleFactor )
+ return;
float oldScaleFactor = UIScale.scaleFactor;
UIScale.scaleFactor = scaleFactor;
if( DEBUG )
- System.out.println( "HiDPI scale factor " + scaleFactor );
+ System.out.println( "Scale factor " + oldScaleFactor + " --> " + scaleFactor + " (unzoomed " + UIScale.unzoomedScaleFactor + ")" );
if( changeSupport != null )
- changeSupport.firePropertyChange( "userScaleFactor", oldScaleFactor, scaleFactor );
+ changeSupport.firePropertyChange( PROP_USER_SCALE_FACTOR, oldScaleFactor, scaleFactor );
+ }
+
+ private static float normalizeScaleFactor( float scaleFactor ) {
+ if( scaleFactor < 1f ) {
+ return FlatSystemProperties.getBoolean( FlatSystemProperties.UI_SCALE_ALLOW_SCALE_DOWN, false )
+ ? Math.round( scaleFactor * 10f ) / 10f // round small scale factor to 1/10
+ : 1f;
+ } else if( scaleFactor > 1f ) // round scale factor to 1/4
+ return Math.round( scaleFactor * 4f ) / 4f;
+ else
+ return scaleFactor;
}
/**
@@ -451,4 +503,185 @@ public class UIScale
? new InsetsUIResource( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) )
: new Insets ( scale( insets.top ), scale( insets.left ), scale( insets.bottom ), scale( insets.right ) ));
}
+
+ //---- zoom ---------------------------------------------------------------
+
+ private static float zoomFactor = 1;
+ private static float[] supportedZoomFactors = { 1f, 1.1f, 1.25f, 1.5f, 1.75f, 2f };
+
+ /**
+ * Returns the current zoom factor. Default is {@code 1}.
+ *
+ * @since 3.7
+ */
+ public static float getZoomFactor() {
+ return zoomFactor;
+ }
+
+ /**
+ * Sets the zoom factor.
+ * Also updates user scale factor and default font (if FlatLaf is active Laf).
+ *
+ * UI needs to be updated if zoom factor has changed. E.g.:
+ *
{@code
+ * if( UIScale.setZoomFactor( newZoomFactor ) )
+ * FlatLaf.updateUI();
+ * }
+ *
+ * @param zoomFactor new zoom factor
+ * @return {@code true} if zoom factor has changed
+ * @since 3.7
+ */
+ public static boolean setZoomFactor( float zoomFactor ) {
+ // minimum zoom factor
+ zoomFactor = Math.max( zoomFactor, 0.1f );
+
+ if( UIScale.zoomFactor == zoomFactor )
+ return false;
+
+ float oldZoomFactor = UIScale.zoomFactor;
+ UIScale.zoomFactor = zoomFactor;
+
+ if( DEBUG )
+ System.out.println( "Zoom factor " + oldZoomFactor + " --> " + zoomFactor );
+
+ setScaleFactor( UIScale.unzoomedScaleFactor * zoomFactor );
+
+ if( initialized && UIManager.getLookAndFeel() instanceof FlatLaf ) {
+ // see also FlatLaf.initDefaultFont()
+ UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+ Font font = defaults.getFont( "defaultFont" );
+ int unzoomedSize = defaults.getInt( "defaultFont.unzoomedSize" );
+ if( unzoomedSize == 0 ) {
+ unzoomedSize = font.getSize();
+ defaults.put( "defaultFont.unzoomedSize", unzoomedSize );
+ }
+
+ // update "defaultFont"
+ ignoreFontChange = true;
+ try {
+ // get application default font before updating Laf default font
+ Font appFont = UIManager.getFont( "defaultFont" );
+
+ // update Laf default font
+ int newFontSize = Math.max( Math.round( unzoomedSize * zoomFactor ), 1 );
+ defaults.put( "defaultFont", new FontUIResource( font.deriveFont( (float) newFontSize ) ) );
+
+ if( DEBUG )
+ System.out.println( "Zoom Laf font " + font.getSize() + " --> " + newFontSize + " (unzoomed " + unzoomedSize + ")" );
+
+ // check whether application has changed default font
+ if( appFont != font ) {
+ // application has own default font --> also zoom it
+ int newAppFontSize = Math.max( Math.round( (appFont.getSize() / oldZoomFactor) * zoomFactor ), 1 );
+ UIManager.put( "defaultFont", appFont.deriveFont( (float) newAppFontSize ) );
+
+ if( DEBUG )
+ System.out.println( "Zoom app font " + appFont.getSize() + " --> " + newAppFontSize );
+ }
+ } finally {
+ ignoreFontChange = false;
+ }
+ }
+
+ if( changeSupport != null )
+ changeSupport.firePropertyChange( PROP_ZOOM_FACTOR, oldZoomFactor, zoomFactor );
+
+ return true;
+ }
+
+ /**
+ * Increases zoom factor using next greater factor in supported factors array.
+ *
+ * UI needs to be updated if zoom factor has changed. E.g.:
+ *
{@code
+ * if( UIScale.zoomIn() )
+ * FlatLaf.updateUI();
+ * }
+ *
+ * @return {@code true} if zoom factor has changed
+ * @see #getSupportedZoomFactors()
+ * @since 3.7
+ */
+ public static boolean zoomIn() {
+ int i = Arrays.binarySearch( supportedZoomFactors, zoomFactor );
+ int next = (i >= 0) ? i + 1 : -i - 1;
+ if( next >= supportedZoomFactors.length )
+ return false;
+
+ return setZoomFactor( supportedZoomFactors[next] );
+ }
+
+ /**
+ * Decreases zoom factor using next smaller factor in supported factors array.
+ *
+ * UI needs to be updated if zoom factor has changed. E.g.:
+ *
{@code
+ * if( UIScale.zoomOut() )
+ * FlatLaf.updateUI();
+ * }
+ *
+ * @return {@code true} if zoom factor has changed
+ * @see #getSupportedZoomFactors()
+ * @since 3.7
+ */
+ public static boolean zoomOut() {
+ int i = Arrays.binarySearch( supportedZoomFactors, zoomFactor );
+ int prev = (i >= 0) ? i - 1 : -i - 2;
+ if( prev < 0 )
+ return false;
+
+ return setZoomFactor( supportedZoomFactors[prev] );
+ }
+
+ /**
+ * Resets zoom factor to {@code 1}.
+ *
+ * UI needs to be updated if zoom factor has changed. E.g.:
+ *
{@code
+ * if( UIScale.zoomReset() )
+ * FlatLaf.updateUI();
+ * }
+ *
+ * @return {@code true} if zoom factor has changed
+ * @since 3.7
+ */
+ public static boolean zoomReset() {
+ return setZoomFactor( 1 );
+ }
+
+ /**
+ * Returns the supported zoom factors used for {@link #zoomIn()} and {@link #zoomOut()}.
+ *
+ * Default is {@code [ 1f, 1.1f, 1.25f, 1.5f, 1.75f, 2f ]}.
+ *
+ * @since 3.7
+ */
+ public static float[] getSupportedZoomFactors() {
+ return supportedZoomFactors.clone();
+ }
+
+ /**
+ * Sets the supported zoom factors used for {@link #zoomIn()} and {@link #zoomOut()}.
+ *
+ * @since 3.7
+ */
+ public static void setSupportedZoomFactors( float[] supportedZoomFactors ) {
+ UIScale.supportedZoomFactors = supportedZoomFactors.clone();
+ Arrays.sort( UIScale.supportedZoomFactors );
+
+ if( Arrays.binarySearch( UIScale.supportedZoomFactors, 1f ) < 0 )
+ throw new IllegalArgumentException( "supportedZoomFactors array must contain value 1f" );
+ }
+
+ //---- unit testing -------------------------------------------------------
+
+ static boolean inUnitTests;
+
+ static void tests_uninitialize() {
+ initialized = false;
+ unzoomedScaleFactor = 1;
+ scaleFactor = 1;
+ zoomFactor = 1;
+ }
}
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/util/TestUIScale.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/util/TestUIScale.java
new file mode 100644
index 00000000..a9246062
--- /dev/null
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/util/TestUIScale.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2025 FormDev Software GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.formdev.flatlaf.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import java.awt.Font;
+import java.util.Collections;
+import java.util.Map;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import com.formdev.flatlaf.FlatDarkLaf;
+import com.formdev.flatlaf.FlatLaf;
+import com.formdev.flatlaf.FlatLightLaf;
+import com.formdev.flatlaf.FlatSystemProperties;
+
+/**
+ * @author Karl Tauber
+ */
+public class TestUIScale
+{
+ private static Map FONT_EXTRA_DEFAULTS_1x = Collections.singletonMap(
+ "defaultFont", "{instance}java.awt.Font,Dialog,0,12" );
+ private static Map FONT_EXTRA_DEFAULTS_1_5x = Collections.singletonMap(
+ "defaultFont", "{instance}java.awt.Font,Dialog,0,18" );
+
+ @BeforeAll
+ static void setup() {
+ UIScale.inUnitTests = true;
+
+ // disable platform specific fonts
+ System.setProperty( "flatlaf.uiScale.fontSizeDivider", "12" );
+ FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1x );
+ }
+
+ @AfterAll
+ static void cleanup() throws UnsupportedLookAndFeelException {
+ System.clearProperty( "flatlaf.uiScale.fontSizeDivider" );
+ FlatLaf.setGlobalExtraDefaults( null );
+
+ UIScale.inUnitTests = false;
+ }
+
+ @AfterEach
+ void afterEach() throws UnsupportedLookAndFeelException {
+ UIManager.setLookAndFeel( new MetalLookAndFeel() );
+ UIManager.put( "defaultFont", null );
+ UIManager.put( "Label.font", null );
+ FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1x );
+
+ UIScale.tests_uninitialize();
+ }
+
+ @Test
+ void testCustomScaleFactor() {
+ System.setProperty( FlatSystemProperties.UI_SCALE, "1.25x" );
+ assertScaleFactor( 1.25f );
+
+ System.setProperty( FlatSystemProperties.UI_SCALE, "2x" );
+ UIScale.tests_uninitialize();
+ assertScaleFactor( 2f );
+
+ System.clearProperty( FlatSystemProperties.UI_SCALE );
+ }
+
+ @Test
+ void testLabelFontScaling() {
+ assertInstanceOf( MetalLookAndFeel.class, UIManager.getLookAndFeel() );
+
+ testLabelFont( 8, 1f );
+ testLabelFont( 9, 1f );
+ testLabelFont( 10, 1f );
+ testLabelFont( 11, 1f );
+ testLabelFont( 12, 1f );
+ testLabelFont( 13, 1f );
+ testLabelFont( 14, 1.25f );
+ testLabelFont( 15, 1.25f );
+ testLabelFont( 16, 1.25f );
+ testLabelFont( 17, 1.5f );
+ testLabelFont( 18, 1.5f );
+ testLabelFont( 19, 1.5f );
+ testLabelFont( 20, 1.75f );
+ testLabelFont( 21, 1.75f );
+ testLabelFont( 22, 1.75f );
+ testLabelFont( 23, 2f );
+ testLabelFont( 24, 2f );
+ testLabelFont( 25, 2f );
+ testLabelFont( 26, 2.25f );
+ }
+
+ private void testLabelFont( int fontSize, float expectedScaleFactor ) {
+ UIManager.put( "Label.font", new Font( Font.DIALOG, Font.PLAIN, fontSize ) );
+ assertScaleFactor( expectedScaleFactor );
+ }
+
+ @Test
+ void testDefaultFontScaling() {
+ FlatLightLaf.setup();
+
+ testDefaultFont( 8, 1f );
+ testDefaultFont( 9, 1f );
+ testDefaultFont( 10, 1f );
+ testDefaultFont( 11, 1f );
+ testDefaultFont( 12, 1f );
+ testDefaultFont( 13, 1f );
+ testDefaultFont( 14, 1.25f );
+ testDefaultFont( 15, 1.25f );
+ testDefaultFont( 16, 1.25f );
+ testDefaultFont( 17, 1.5f );
+ testDefaultFont( 18, 1.5f );
+ testDefaultFont( 19, 1.5f );
+ testDefaultFont( 20, 1.75f );
+ testDefaultFont( 21, 1.75f );
+ testDefaultFont( 22, 1.75f );
+ testDefaultFont( 23, 2f );
+ testDefaultFont( 24, 2f );
+ testDefaultFont( 25, 2f );
+ testDefaultFont( 26, 2.25f );
+ }
+
+ private void testDefaultFont( int fontSize, float expectedScaleFactor ) {
+ UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, fontSize ) );
+ assertScaleFactor( expectedScaleFactor );
+ }
+
+ @Test
+ void testInitialScaleFactorAndFontSizes() {
+ FlatLightLaf.setup();
+ assertScaleFactorAndFontSizes( 1f, 12, -1 );
+
+ FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
+ FlatDarkLaf.setup();
+ assertScaleFactorAndFontSizes( 1.5f, 18, -1 );
+ }
+
+ @Test
+ void zoom_Metal() {
+ UIScale.setZoomFactor( 1.1f );
+ assertScaleFactor( 1.1f );
+
+ UIScale.setZoomFactor( 1.3f );
+ assertScaleFactor( 1.3f );
+
+ UIScale.setZoomFactor( 2.3f );
+ assertScaleFactor( 2.3f );
+ }
+
+ @Test
+ void zoom_1x() {
+ FlatLightLaf.setup();
+ testZoom( 0.7f, 0.7f, 8, -1 );
+ testZoom( 0.75f, 0.75f, 9, -1 );
+ testZoom( 0.8f, 0.8f, 10, -1 );
+ testZoom( 0.9f, 0.9f, 11, -1 );
+ testZoom( 1f, 1f, 12, -1 );
+ testZoom( 1.1f, 1.1f, 13, -1 );
+ testZoom( 1.2f, 1.2f, 14, -1 );
+ testZoom( 1.25f, 1.25f, 15, -1 );
+ testZoom( 1.3f, 1.3f, 16, -1 );
+ testZoom( 1.4f, 1.4f, 17, -1 );
+ testZoom( 1.5f, 1.5f, 18, -1 );
+ testZoom( 1.6f, 1.6f, 19, -1 );
+ testZoom( 1.7f, 1.7f, 20, -1 );
+ testZoom( 1.75f, 1.75f, 21, -1 );
+ testZoom( 1.8f, 1.8f, 22, -1 );
+ testZoom( 1.9f, 1.9f, 23, -1 );
+ testZoom( 2f, 2f, 24, -1 );
+ testZoom( 2.25f, 2.25f, 27, -1 );
+ testZoom( 2.5f, 2.5f, 30, -1 );
+ testZoom( 2.75f, 2.75f, 33, -1 );
+ testZoom( 3f, 3f, 36, -1 );
+ testZoom( 4f, 4f, 48, -1 );
+ }
+
+ @Test
+ void zoom_1_5x() {
+ FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
+ FlatLightLaf.setup();
+
+ testZoom( 0.7f, 1.05f, 13, -1 );
+ testZoom( 0.75f, 1.13f, 14, -1 );
+ testZoom( 0.8f, 1.2f, 14, -1 );
+ testZoom( 0.9f, 1.35f, 16, -1 );
+ testZoom( 1f, 1.5f, 18, -1 );
+ testZoom( 1.1f, 1.65f, 20, -1 );
+ testZoom( 1.2f, 1.8f, 22, -1 );
+ testZoom( 1.25f, 1.88f, 23, -1 );
+ testZoom( 1.3f, 1.95f, 23, -1 );
+ testZoom( 1.4f, 2.1f, 25, -1 );
+ testZoom( 1.5f, 2.25f, 27, -1 );
+ testZoom( 1.6f, 2.4f, 29, -1 );
+ testZoom( 1.7f, 2.55f, 31, -1 );
+ testZoom( 1.75f, 2.63f, 32, -1 );
+ testZoom( 1.8f, 2.7f, 32, -1 );
+ testZoom( 1.9f, 2.85f, 34, -1 );
+ testZoom( 2f, 3f, 36, -1 );
+ testZoom( 2.25f, 3.38f, 41, -1 );
+ testZoom( 2.5f, 3.75f, 45, -1 );
+ testZoom( 2.75f, 4.13f, 50, -1 );
+ testZoom( 3f, 4.5f, 54, -1 );
+ testZoom( 4f, 6f, 72, -1 );
+ }
+
+ @Test
+ void zoomAppFont_1x() {
+ FlatLightLaf.setup();
+ UIManager.put( "defaultFont", new Font( Font.DIALOG, Font.PLAIN, 14 ) );
+
+ testZoom( 1f, 1.25f, 12, 14 );
+ testZoom( 1.1f, 1.38f, 13, 15 );
+ testZoom( 1.25f, 1.56f, 15, 17 );
+ testZoom( 1.5f, 1.88f, 18, 20 );
+ testZoom( 1.75f, 2.19f, 21, 23 );
+ testZoom( 2f, 2.5f, 24, 26 );
+ testZoom( 1f, 1.25f, 12, 13 );
+ testZoom( 2f, 2.5f, 24, 26 );
+ }
+
+ @Test
+ void zoomWithLafChange() {
+ FlatLightLaf.setup();
+ assertScaleFactorAndFontSizes( 1f, 12, -1 );
+ testZoom( 1.1f, 1.1f, 13, -1 );
+
+ FlatDarkLaf.setup();
+ assertScaleFactorAndFontSizes( 1.1f, 13, -1 );
+ testZoom( 1.2f, 1.2f, 14, -1 );
+
+ FlatLightLaf.setup();
+ assertScaleFactorAndFontSizes( 1.2f, 14, -1 );
+ testZoom( 1.3f, 1.3f, 16, -1 );
+
+ FlatLaf.setGlobalExtraDefaults( FONT_EXTRA_DEFAULTS_1_5x );
+ FlatDarkLaf.setup();
+ assertScaleFactorAndFontSizes( 1.95f, 23, -1 );
+ testZoom( 1.4f, 2.1f, 25, -1 );
+
+ FlatLightLaf.setup();
+ assertScaleFactorAndFontSizes( 2.1f, 25, -1 );
+ testZoom( 1.5f, 2.25f, 27, -1 );
+ }
+
+ @Test
+ void zoomWithDefaultFontChange() {
+ FlatLightLaf.setup();
+ assertScaleFactorAndFontSizes( 1f, 12, -1 );
+
+ float zoom1 = 1.4f;
+ testZoom( zoom1, zoom1, 17, -1 );
+ testDefaultFont( 8, z( zoom1, 1f ) );
+ testDefaultFont( 9, z( zoom1, 1f ) );
+ testDefaultFont( 10, z( zoom1, 1f ) );
+ testDefaultFont( 11, z( zoom1, 1f ) );
+ testDefaultFont( 12, z( zoom1, 1f ) );
+ testDefaultFont( 13, z( zoom1, 1f ) );
+ testDefaultFont( 14, z( zoom1, 1.25f ) );
+ testDefaultFont( 15, z( zoom1, 1.25f ) );
+ testDefaultFont( 16, z( zoom1, 1.25f ) );
+ testDefaultFont( 17, z( zoom1, 1.5f ) );
+ testDefaultFont( 18, z( zoom1, 1.5f ) );
+ testDefaultFont( 19, z( zoom1, 1.5f ) );
+ testDefaultFont( 20, z( zoom1, 1.75f ) );
+ testDefaultFont( 21, z( zoom1, 1.75f ) );
+ testDefaultFont( 22, z( zoom1, 1.75f ) );
+ testDefaultFont( 23, z( zoom1, 2f ) );
+ testDefaultFont( 24, z( zoom1, 2f ) );
+ testDefaultFont( 25, z( zoom1, 2f ) );
+ testDefaultFont( 26, z( zoom1, 2.25f ) );
+
+ float zoom2 = 1.8f;
+ testZoom( zoom2, 4.05f, 22, 33 );
+ testDefaultFont( 8, z( zoom2, 1f ) );
+ testDefaultFont( 9, z( zoom2, 1f ) );
+ testDefaultFont( 10, z( zoom2, 1f ) );
+ testDefaultFont( 11, z( zoom2, 1f ) );
+ testDefaultFont( 12, z( zoom2, 1f ) );
+ testDefaultFont( 13, z( zoom2, 1f ) );
+ testDefaultFont( 14, z( zoom2, 1.25f ) );
+ testDefaultFont( 15, z( zoom2, 1.25f ) );
+ testDefaultFont( 16, z( zoom2, 1.25f ) );
+ testDefaultFont( 17, z( zoom2, 1.5f ) );
+ testDefaultFont( 18, z( zoom2, 1.5f ) );
+ testDefaultFont( 19, z( zoom2, 1.5f ) );
+ testDefaultFont( 20, z( zoom2, 1.75f ) );
+ testDefaultFont( 21, z( zoom2, 1.75f ) );
+ testDefaultFont( 22, z( zoom2, 1.75f ) );
+ testDefaultFont( 23, z( zoom2, 2f ) );
+ testDefaultFont( 24, z( zoom2, 2f ) );
+ testDefaultFont( 25, z( zoom2, 2f ) );
+ testDefaultFont( 26, z( zoom2, 2.25f ) );
+ }
+
+ private static float z( float zoom, float scale ) {
+ // round scale factor to 1/100
+ return Math.round( (zoom * scale) * 100f ) / 100f;
+ }
+
+ private static void testZoom( float zoomFactor, float expectedScaleFactor,
+ int expectedLafFontSize, int expectedAppFontSize )
+ {
+ UIScale.setZoomFactor( zoomFactor );
+ assertScaleFactorAndFontSizes( expectedScaleFactor, expectedLafFontSize, expectedAppFontSize );
+ }
+
+ private static void assertScaleFactorAndFontSizes( float expectedScaleFactor,
+ int expectedLafFontSize, int expectedAppFontSize )
+ {
+ assertScaleFactor( expectedScaleFactor );
+
+ Font lafFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" );
+ Font appFont = UIManager.getFont( "defaultFont" );
+ assertEquals( expectedLafFontSize, lafFont.getSize() );
+ if( expectedAppFontSize > 0 ) {
+ assertNotEquals( lafFont, appFont );
+ assertEquals( expectedAppFontSize, appFont.getSize() );
+ } else
+ assertEquals( lafFont, appFont );
+ }
+
+ private static void assertScaleFactor( float expectedScaleFactor ) {
+ assertEquals( expectedScaleFactor, UIScale.getUserScaleFactor() );
+ }
+}
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java
index 095b101c..55354e04 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/ControlBar.java
@@ -111,6 +111,10 @@ class ControlBar
UIScale.addPropertyChangeListener( e -> {
// update info label because user scale factor may change
updateInfoLabel();
+
+ // update "Font" menu (e.g. if zoom factor changed)
+ if( UIScale.PROP_ZOOM_FACTOR.equals( e.getPropertyName() ) )
+ frame.updateFontMenuItems();
} );
}
@@ -192,13 +196,15 @@ class ControlBar
String javaVendor = System.getProperty( "java.vendor" );
if( "Oracle Corporation".equals( javaVendor ) )
javaVendor = null;
+ float zoomFactor = UIScale.getZoomFactor();
double systemScaleFactor = UIScale.getSystemScaleFactor( getGraphicsConfiguration() );
float userScaleFactor = UIScale.getUserScaleFactor();
Font font = UIManager.getFont( "Label.font" );
String newInfo = "(Java " + System.getProperty( "java.version" )
+ (javaVendor != null ? ("; " + javaVendor) : "")
- + (systemScaleFactor != 1 ? ("; system scale factor " + systemScaleFactor) : "")
- + (userScaleFactor != 1 ? ("; user scale factor " + userScaleFactor) : "")
+ + (zoomFactor != 1 ? ("; zoom " + zoomFactor) : "")
+ + (systemScaleFactor != 1 ? ("; system scale " + systemScaleFactor) : "")
+ + (userScaleFactor != 1 ? ("; user scale " + userScaleFactor) : "")
+ (systemScaleFactor == 1 && userScaleFactor == 1 ? "; no scaling" : "")
+ "; " + font.getFamily() + " " + font.getSize()
+ (font.isBold() ? " BOLD" : "")
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
index 54b0e33e..4ad71d83 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
@@ -24,6 +24,7 @@ import java.net.URISyntaxException;
import java.time.Year;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
@@ -45,11 +46,13 @@ import com.formdev.flatlaf.extras.components.FlatButton.ButtonType;
import com.formdev.flatlaf.icons.FlatAbstractIcon;
import com.formdev.flatlaf.themes.FlatMacDarkLaf;
import com.formdev.flatlaf.themes.FlatMacLightLaf;
+import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.extras.FlatSVGUtils;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.FontUtils;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.SystemInfo;
+import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.layout.LC;
import net.miginfocom.layout.UnitValue;
@@ -71,6 +74,7 @@ class DemoFrame
Arrays.sort( availableFontFamilyNames );
initComponents();
+ initZommMenuItems();
updateFontMenuItems();
initAccentColors();
initFullWindowContent();
@@ -286,6 +290,92 @@ class DemoFrame
showHints();
}
+ private void initZommMenuItems() {
+ float currentZoomFactor = UIScale.getZoomFactor();
+ UIScale.setSupportedZoomFactors( new float[] { 0.7f, 0.8f, 0.9f, 1f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.75f, 2f } );
+
+ ButtonGroup group = new ButtonGroup();
+ HashMap items = new HashMap<>();
+
+ // add supported zoom factors to "Zoom" menu
+ zoomMenu.addSeparator();
+ for( float zoomFactor : UIScale.getSupportedZoomFactors() ) {
+ JCheckBoxMenuItem item = new JCheckBoxMenuItem( (int)(zoomFactor * 100) + "%" );
+ item.setSelected( zoomFactor == currentZoomFactor );
+ item.addActionListener( this::zoomFactorChanged );
+ zoomMenu.add( item );
+
+ group.add( item );
+ items.put( zoomFactor, item );
+ }
+
+ // update menu item selection if zoom factor changed
+ UIScale.addPropertyChangeListener( e -> {
+ if( UIScale.PROP_ZOOM_FACTOR.equals( e.getPropertyName() ) ) {
+ float newZoomFactor = UIScale.getZoomFactor();
+ JCheckBoxMenuItem item = items.get( newZoomFactor );
+ if( item != null )
+ item.setSelected( true );
+
+ zoomWindowBounds( this, (float) e.getOldValue(), (float) e.getNewValue() );
+ }
+ } );
+ }
+
+ private static void zoomWindowBounds( Window window, float oldZoomFactor, float newZoomFactor ) {
+ if( window instanceof Frame && ((Frame)window).getExtendedState() != Frame.NORMAL )
+ return;
+
+ Rectangle oldBounds = window.getBounds();
+
+ // zoom window bounds
+ float factor = (1f / oldZoomFactor) * newZoomFactor;
+ int newWidth = (int) (oldBounds.width * factor);
+ int newHeight = (int) (oldBounds.height * factor);
+ int newX = oldBounds.x - ((newWidth - oldBounds.width) / 2);
+ int newY = oldBounds.y - ((newHeight - oldBounds.height) / 2);
+
+ // get maximum window bounds (screen bounds minus screen insets)
+ GraphicsConfiguration gc = window.getGraphicsConfiguration();
+ Rectangle screenBounds = gc.getBounds();
+ Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
+ Rectangle maxBounds = FlatUIUtils.subtractInsets( screenBounds, screenInsets );
+
+ // limit new window width/height
+ newWidth = Math.min( newWidth, maxBounds.width );
+ newHeight = Math.min( newHeight, maxBounds.height );
+
+ // move window into screen bounds
+ newX = Math.max( Math.min( newX, maxBounds.width - newWidth ), maxBounds.x );
+ newY = Math.max( Math.min( newY, maxBounds.height - newHeight ), maxBounds.y );
+
+ // set new window bounds
+ window.setBounds( newX, newY, newWidth, newHeight );
+ }
+
+ private void zoomFactorChanged( ActionEvent e ) {
+ String zoomFactor = e.getActionCommand();
+ float zoom = Integer.parseInt( zoomFactor.substring( 0, zoomFactor.length() - 1 ) ) / 100f;
+
+ if( UIScale.setZoomFactor( zoom ) )
+ FlatLaf.updateUI();
+ }
+
+ private void zoomReset() {
+ if( UIScale.zoomReset() )
+ FlatLaf.updateUI();
+ }
+
+ private void zoomIn() {
+ if( UIScale.zoomIn() )
+ FlatLaf.updateUI();
+ }
+
+ private void zoomOut() {
+ if( UIScale.zoomOut() )
+ FlatLaf.updateUI();
+ }
+
private void fontFamilyChanged( ActionEvent e ) {
String fontFamily = e.getActionCommand();
@@ -533,6 +623,10 @@ class DemoFrame
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
JRadioButtonMenuItem radioButtonMenuItem2 = new JRadioButtonMenuItem();
JRadioButtonMenuItem radioButtonMenuItem3 = new JRadioButtonMenuItem();
+ zoomMenu = new JMenu();
+ JMenuItem resetZoomMenuItem = new JMenuItem();
+ JMenuItem incrZoomMenuItem = new JMenuItem();
+ JMenuItem decrZoomMenuItem = new JMenuItem();
fontMenu = new JMenu();
JMenuItem restoreFontMenuItem = new JMenuItem();
JMenuItem incrFontMenuItem = new JMenuItem();
@@ -778,25 +872,49 @@ class DemoFrame
}
menuBar.add(viewMenu);
+ //======== zoomMenu ========
+ {
+ zoomMenu.setText("Zoom");
+
+ //---- resetZoomMenuItem ----
+ resetZoomMenuItem.setText("Reset Zoom");
+ resetZoomMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ resetZoomMenuItem.addActionListener(e -> zoomReset());
+ zoomMenu.add(resetZoomMenuItem);
+
+ //---- incrZoomMenuItem ----
+ incrZoomMenuItem.setText("Zoom In");
+ incrZoomMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ incrZoomMenuItem.addActionListener(e -> zoomIn());
+ zoomMenu.add(incrZoomMenuItem);
+
+ //---- decrZoomMenuItem ----
+ decrZoomMenuItem.setText("Zoom Out");
+ decrZoomMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ decrZoomMenuItem.addActionListener(e -> zoomOut());
+ zoomMenu.add(decrZoomMenuItem);
+ }
+ menuBar.add(zoomMenu);
+
//======== fontMenu ========
{
fontMenu.setText("Font");
//---- restoreFontMenuItem ----
restoreFontMenuItem.setText("Restore Font");
- restoreFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ restoreFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()|KeyEvent.ALT_DOWN_MASK));
restoreFontMenuItem.addActionListener(e -> restoreFont());
fontMenu.add(restoreFontMenuItem);
//---- incrFontMenuItem ----
incrFontMenuItem.setText("Increase Font Size");
- incrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ incrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()|KeyEvent.ALT_DOWN_MASK));
incrFontMenuItem.addActionListener(e -> incrFont());
fontMenu.add(incrFontMenuItem);
//---- decrFontMenuItem ----
decrFontMenuItem.setText("Decrease Font Size");
- decrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+ decrFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()|KeyEvent.ALT_DOWN_MASK));
decrFontMenuItem.addActionListener(e -> decrFont());
fontMenu.add(decrFontMenuItem);
}
@@ -1045,6 +1163,7 @@ class DemoFrame
private JMenuItem exitMenuItem;
private JMenu scrollingPopupMenu;
private JMenuItem htmlMenuItem;
+ private JMenu zoomMenu;
private JMenu fontMenu;
private JMenu optionsMenu;
private JCheckBoxMenuItem windowDecorationsCheckBoxMenuItem;
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
index 08248c1d..190f8d9f 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
@@ -1,4 +1,4 @@
-JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8"
+JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -362,6 +362,31 @@ new FormModel {
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
} )
} )
+ add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
+ name: "zoomMenu"
+ "text": "Zoom"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ add( new FormComponent( "javax.swing.JMenuItem" ) {
+ name: "resetZoomMenuItem"
+ "text": "Reset Zoom"
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 48, 4226, false )
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "zoomReset", false ) )
+ } )
+ add( new FormComponent( "javax.swing.JMenuItem" ) {
+ name: "incrZoomMenuItem"
+ "text": "Zoom In"
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 521, 4226, false )
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "zoomIn", false ) )
+ } )
+ add( new FormComponent( "javax.swing.JMenuItem" ) {
+ name: "decrZoomMenuItem"
+ "text": "Zoom Out"
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 45, 4226, false )
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "zoomOut", false ) )
+ } )
+ } )
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "fontMenu"
"text": "Font"
@@ -371,19 +396,19 @@ new FormModel {
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "restoreFontMenuItem"
"text": "Restore Font"
- "accelerator": static javax.swing.KeyStroke getKeyStroke( 48, 4226, false )
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 48, 4746, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "restoreFont", false ) )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "incrFontMenuItem"
"text": "Increase Font Size"
- "accelerator": static javax.swing.KeyStroke getKeyStroke( 521, 4226, false )
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 521, 4746, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "incrFont", false ) )
} )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "decrFontMenuItem"
"text": "Decrease Font Size"
- "accelerator": static javax.swing.KeyStroke getKeyStroke( 45, 4226, false )
+ "accelerator": static javax.swing.KeyStroke getKeyStroke( 45, 4746, false )
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "decrFont", false ) )
} )
} )