diff --git a/CHANGELOG.md b/CHANGELOG.md index f46ac370..43a97ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FlatLaf Change Log ## Unreleased +- Animated theme change (see [FlatLaf Extras](flatlaf-extras)). - Custom window decorations: Fixed maximized window bounds when programmatically maximizing window. E.g. restoring window state at startup. (issue #129) - InternalFrame: Title pane height was too small when iconify, maximize and close diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/Animator.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/Animator.java index 67dfa94e..6eac10d0 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/Animator.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/Animator.java @@ -92,6 +92,7 @@ public class Animator /** * Sets the resolution of the animation in milliseconds. * + * @param resolution the resolution of the animation in milliseconds * @throws IllegalStateException if animation is running * @throws IllegalArgumentException if resolution is <= zero */ 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 cd6c07c1..b34c0a30 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 @@ -27,6 +27,7 @@ import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.nimbus.NimbusLookAndFeel; import com.formdev.flatlaf.*; +import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.UIScale; import net.miginfocom.swing.*; @@ -193,6 +194,8 @@ class ControlBar EventQueue.invokeLater( () -> { try { + FlatAnimatedLafChange.showSnapshot(); + // change look and feel UIManager.setLookAndFeel( lafClassName ); @@ -202,6 +205,7 @@ class ControlBar // update all components FlatLaf.updateUI(); + FlatAnimatedLafChange.hideSnapshotWithAnimation(); // increase size of frame if necessary int width = frame.getWidth(); 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 c7357383..8ddd8618 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 @@ -27,6 +27,7 @@ import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.demo.extras.*; import com.formdev.flatlaf.demo.intellijthemes.*; +import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.extras.SVGUtils; import com.formdev.flatlaf.ui.JBRCustomDecorations; @@ -105,14 +106,21 @@ class DemoFrame repaint(); } + private void animatedLafChangeChanged() { + System.setProperty( "flatlaf.animatedLafChange", String.valueOf( animatedLafChangeMenuItem.isSelected() ) ); + } + private void fontFamilyChanged( ActionEvent e ) { String fontFamily = e.getActionCommand(); + FlatAnimatedLafChange.showSnapshot(); + Font font = UIManager.getFont( "defaultFont" ); Font newFont = StyleContext.getDefaultStyleContext().getFont( fontFamily, font.getStyle(), font.getSize() ); UIManager.put( "defaultFont", newFont ); FlatLaf.updateUI(); + FlatAnimatedLafChange.hideSnapshotWithAnimation(); } private void fontSizeChanged( ActionEvent e ) { @@ -248,6 +256,7 @@ class DemoFrame menuBarEmbeddedCheckBoxMenuItem = new JCheckBoxMenuItem(); underlineMenuSelectionMenuItem = new JCheckBoxMenuItem(); alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem(); + animatedLafChangeMenuItem = new JCheckBoxMenuItem(); JMenu helpMenu = new JMenu(); JMenuItem aboutMenuItem = new JMenuItem(); JToolBar toolBar1 = new JToolBar(); @@ -501,6 +510,12 @@ class DemoFrame alwaysShowMnemonicsMenuItem.setText("Always show mnemonics"); alwaysShowMnemonicsMenuItem.addActionListener(e -> alwaysShowMnemonics()); optionsMenu.add(alwaysShowMnemonicsMenuItem); + + //---- animatedLafChangeMenuItem ---- + animatedLafChangeMenuItem.setText("Animated Laf Change"); + animatedLafChangeMenuItem.setSelected(true); + animatedLafChangeMenuItem.addActionListener(e -> animatedLafChangeChanged()); + optionsMenu.add(animatedLafChangeMenuItem); } menuBar1.add(optionsMenu); @@ -620,6 +635,7 @@ class DemoFrame private JCheckBoxMenuItem menuBarEmbeddedCheckBoxMenuItem; private JCheckBoxMenuItem underlineMenuSelectionMenuItem; private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem; + private JCheckBoxMenuItem animatedLafChangeMenuItem; private JTabbedPane tabbedPane; private ControlBar controlBar; // JFormDesigner - End of variables declaration //GEN-END:variables 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 0146ff6b..12f8061c 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: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.2.0.298" Java: "14.0.2" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -356,6 +356,15 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "alwaysShowMnemonics", false ) ) } ) + add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { + name: "animatedLafChangeMenuItem" + "text": "Animated Laf Change" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "animatedLafChangeChanged", false ) ) + } ) } ) add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { name: "helpMenu" diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/intellijthemes/IJThemesPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/intellijthemes/IJThemesPanel.java index f247b3d0..2fa7d4a5 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/intellijthemes/IJThemesPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/intellijthemes/IJThemesPanel.java @@ -49,6 +49,7 @@ import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.FlatPropertiesLaf; import com.formdev.flatlaf.IntelliJTheme; import com.formdev.flatlaf.demo.DemoPrefs; +import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.util.StringUtils; import net.miginfocom.swing.*; @@ -219,6 +220,8 @@ public class IJThemesPanel if( themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) ) return; + FlatAnimatedLafChange.showSnapshot(); + try { UIManager.setLookAndFeel( themeInfo.lafClassName ); } catch( Exception ex ) { @@ -226,6 +229,8 @@ public class IJThemesPanel showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex ); } } else if( themeInfo.themeFile != null ) { + FlatAnimatedLafChange.showSnapshot(); + try { if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) { FlatLaf.install( new FlatPropertiesLaf( themeInfo.name, themeInfo.themeFile ) ); @@ -238,12 +243,15 @@ public class IJThemesPanel showInformationDialog( "Failed to load '" + themeInfo.themeFile + "'.", ex ); } } else { + FlatAnimatedLafChange.showSnapshot(); + IntelliJTheme.install( getClass().getResourceAsStream( THEMES_PACKAGE + themeInfo.resourceName ) ); DemoPrefs.getState().put( DemoPrefs.KEY_LAF_THEME, DemoPrefs.RESOURCE_PREFIX + themeInfo.resourceName ); } // update all components FlatLaf.updateUI(); + FlatAnimatedLafChange.hideSnapshotWithAnimation(); } private void saveTheme() { diff --git a/flatlaf-extras/README.md b/flatlaf-extras/README.md index 6e6e5bcd..42b0499e 100644 --- a/flatlaf-extras/README.md +++ b/flatlaf-extras/README.md @@ -3,6 +3,8 @@ FlatLaf Extras This sub-project provides some additional components and classes: +- [FlatAnimatedLafChange](src/main/java/com/formdev/flatlaf/extras/FlatAnimatedLafChange.java): + Animated Laf changing. - [FlatInspector](src/main/java/com/formdev/flatlaf/extras/FlatInspector.java): A simple UI inspector that shows information about UI component at mouse location in a tooltip. diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatAnimatedLafChange.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatAnimatedLafChange.java new file mode 100644 index 00000000..e7689bb1 --- /dev/null +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatAnimatedLafChange.java @@ -0,0 +1,163 @@ +/* + * Copyright 2020 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.extras; + +import java.awt.AlphaComposite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Window; +import java.util.HashMap; +import java.util.Map; +import javax.swing.JComponent; +import javax.swing.JLayeredPane; +import javax.swing.RootPaneContainer; +import com.formdev.flatlaf.FlatSystemProperties; +import com.formdev.flatlaf.util.Animator; + +/** + * Animated look and feel changing. + *
+ * Invoke {@link #showSnapshot()} before setting look and feel and + * {@link #hideSnapshotWithAnimation()} after updating UI. E.g. + *
+ * FlatAnimatedLafChange.showSnapshot(); + * UIManager.setLookAndFeel( lafClassName ); + * FlatLaf.updateUI(); + * FlatAnimatedLafChange.hideSnapshotWithAnimation(); + *+ * + * @author Karl Tauber + */ +public class FlatAnimatedLafChange +{ + /** + * The duration of the animation in milliseconds. Default is 160 ms. + */ + public static int duration = 160; + + /** + * The resolution of the animation in milliseconds. Default is 40 ms. + */ + public static int resolution = 40; + + private static Animator animator; + private static final Map