mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
Extras: FlatAnimatedLafChange: made transition smoother:
- use a single component in layered pane to paint new and old UI snapshots (previously used two components) - the snapshot layer component is now opaque, which avoids that window component hierarchy is involved when painting snapshots - snapshots are now painted immediately, which should result in a smoother transition - changed animation resolution from 30ms to 16ms
This commit is contained in:
@@ -8,6 +8,7 @@ FlatLaf Change Log
|
|||||||
- If using `FlatLaf.registerCustomDefaultsSource( "com.myapp.themes" )` and
|
- If using `FlatLaf.registerCustomDefaultsSource( "com.myapp.themes" )` and
|
||||||
named Java modules, it is no longer necessary to add `opens com.myapp.themes;`
|
named Java modules, it is no longer necessary to add `opens com.myapp.themes;`
|
||||||
to `module-info.java`. (issue #1026)
|
to `module-info.java`. (issue #1026)
|
||||||
|
- Extras: Made animated theme change (class `FlatAnimatedLafChange`) smoother.
|
||||||
|
|
||||||
#### Fixed bugs
|
#### Fixed bugs
|
||||||
|
|
||||||
|
|||||||
@@ -53,15 +53,13 @@ public class FlatAnimatedLafChange
|
|||||||
public static int duration = 160;
|
public static int duration = 160;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The resolution of the animation in milliseconds. Default is 30 ms.
|
* The resolution of the animation in milliseconds. Default is 16 ms.
|
||||||
*/
|
*/
|
||||||
public static int resolution = 30;
|
public static int resolution = 16;
|
||||||
|
|
||||||
private static Animator animator;
|
private static Animator animator;
|
||||||
private static final Map<JLayeredPane, JComponent> oldUIsnapshots = new WeakHashMap<>();
|
private static final Map<JLayeredPane, SnapshotLayer> snapshots = new WeakHashMap<>();
|
||||||
private static final Map<JLayeredPane, JComponent> newUIsnapshots = new WeakHashMap<>();
|
|
||||||
private static float alpha;
|
private static float alpha;
|
||||||
private static boolean inShowSnapshot;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a snapshot of the old UI and shows it on top of the UI.
|
* Create a snapshot of the old UI and shows it on top of the UI.
|
||||||
@@ -78,63 +76,52 @@ public class FlatAnimatedLafChange
|
|||||||
alpha = 1;
|
alpha = 1;
|
||||||
|
|
||||||
// show snapshot of old UI
|
// show snapshot of old UI
|
||||||
showSnapshot( true, oldUIsnapshots );
|
showSnapshot( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void showSnapshot( boolean old, Map<JLayeredPane, JComponent> map ) {
|
private static void showSnapshot( boolean old ) {
|
||||||
inShowSnapshot = true;
|
|
||||||
|
|
||||||
// create snapshots for all shown windows
|
// create snapshots for all shown windows
|
||||||
Window[] windows = Window.getWindows();
|
Window[] windows = Window.getWindows();
|
||||||
for( Window window : windows ) {
|
for( Window window : windows ) {
|
||||||
if( !(window instanceof RootPaneContainer) || !window.isShowing() )
|
if( !(window instanceof RootPaneContainer) || !window.isShowing() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||||
|
|
||||||
// create snapshot image
|
// create snapshot image
|
||||||
// (using volatile image to have correct sub-pixel text rendering on Java 9+)
|
// (using volatile image to have correct sub-pixel text rendering on Java 9+)
|
||||||
VolatileImage snapshot = window.createVolatileImage( window.getWidth(), window.getHeight() );
|
VolatileImage snapshotImage = layeredPane.createVolatileImage( layeredPane.getWidth(), layeredPane.getHeight() );
|
||||||
if( snapshot == null )
|
if( snapshotImage == null )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// paint window to snapshot image
|
// paint window to snapshot image
|
||||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
layeredPane.paint( snapshotImage.getGraphics() );
|
||||||
layeredPane.paint( snapshot.getGraphics() );
|
|
||||||
|
|
||||||
// create snapshot layer, which is added to layered pane and paints
|
if( old ) {
|
||||||
// snapshot with animated alpha
|
// create snapshot layer, which is added to layered pane and paints
|
||||||
JComponent snapshotLayer = new JComponent() {
|
// snapshot with animated alpha
|
||||||
@Override
|
SnapshotLayer snapshotLayer = new SnapshotLayer();
|
||||||
public void paint( Graphics g ) {
|
|
||||||
if( inShowSnapshot || snapshot.contentsLost() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( old )
|
|
||||||
((Graphics2D)g).setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) );
|
|
||||||
g.drawImage( snapshot, 0, 0, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeNotify() {
|
|
||||||
super.removeNotify();
|
|
||||||
|
|
||||||
// release system resources used by volatile image
|
|
||||||
snapshot.flush();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if( !old )
|
|
||||||
snapshotLayer.setOpaque( true );
|
snapshotLayer.setOpaque( true );
|
||||||
snapshotLayer.setSize( layeredPane.getSize() );
|
snapshotLayer.setSize( layeredPane.getSize() );
|
||||||
|
snapshotLayer.oldSnapshotImage = snapshotImage;
|
||||||
|
|
||||||
// add image layer to layered pane
|
snapshots.put( layeredPane, snapshotLayer );
|
||||||
layeredPane.add( snapshotLayer, Integer.valueOf( JLayeredPane.DRAG_LAYER + (old ? 2 : 1) ) );
|
} else {
|
||||||
map.put( layeredPane, snapshotLayer );
|
SnapshotLayer snapshotLayer = snapshots.get( layeredPane );
|
||||||
|
if( snapshotLayer == null ) {
|
||||||
|
snapshotImage.flush();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// let FlatRootPaneUI know that animated Laf change is in progress
|
snapshotLayer.newSnapshotImage = snapshotImage;
|
||||||
if( old )
|
|
||||||
|
// add snapshot layer to layered pane
|
||||||
|
layeredPane.add( snapshotLayer, Integer.valueOf( JLayeredPane.DRAG_LAYER + 1 ) );
|
||||||
|
|
||||||
|
// let FlatRootPaneUI know that animated Laf change is in progress
|
||||||
layeredPane.getRootPane().putClientProperty( "FlatLaf.internal.animatedLafChange", true );
|
layeredPane.getRootPane().putClientProperty( "FlatLaf.internal.animatedLafChange", true );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inShowSnapshot = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,23 +133,22 @@ public class FlatAnimatedLafChange
|
|||||||
if( !FlatSystemProperties.getBoolean( "flatlaf.animatedLafChange", true ) )
|
if( !FlatSystemProperties.getBoolean( "flatlaf.animatedLafChange", true ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( oldUIsnapshots.isEmpty() )
|
if( snapshots.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// show snapshot of new UI
|
// show snapshot of new UI
|
||||||
showSnapshot( false, newUIsnapshots );
|
showSnapshot( false );
|
||||||
|
|
||||||
// create animator
|
// create animator
|
||||||
animator = new Animator( duration, fraction -> {
|
animator = new Animator( duration, fraction -> {
|
||||||
if( fraction < 0.1 || fraction > 0.9 )
|
|
||||||
return; // ignore initial and last events
|
|
||||||
|
|
||||||
alpha = 1f - fraction;
|
alpha = 1f - fraction;
|
||||||
|
|
||||||
// repaint snapshots
|
// repaint snapshots
|
||||||
for( Map.Entry<JLayeredPane, JComponent> e : oldUIsnapshots.entrySet() ) {
|
for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
|
||||||
if( e.getKey().isShowing() )
|
if( e.getKey().isShowing() ) {
|
||||||
e.getValue().repaint();
|
SnapshotLayer snapshotLayer = e.getValue();
|
||||||
|
snapshotLayer.paintImmediately( 0, 0, snapshotLayer.getWidth(),snapshotLayer.getHeight() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Toolkit.getDefaultToolkit().sync();
|
Toolkit.getDefaultToolkit().sync();
|
||||||
@@ -176,18 +162,18 @@ public class FlatAnimatedLafChange
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void hideSnapshot() {
|
private static void hideSnapshot() {
|
||||||
hideSnapshot( oldUIsnapshots );
|
|
||||||
hideSnapshot( newUIsnapshots );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void hideSnapshot( Map<JLayeredPane, JComponent> map ) {
|
|
||||||
// remove snapshots
|
// remove snapshots
|
||||||
for( Map.Entry<JLayeredPane, JComponent> e : map.entrySet() ) {
|
for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
|
||||||
e.getKey().remove( e.getValue() );
|
JLayeredPane layeredPane = e.getKey();
|
||||||
e.getKey().repaint();
|
SnapshotLayer snapshotLayer = e.getValue();
|
||||||
|
|
||||||
|
layeredPane.remove( snapshotLayer );
|
||||||
|
layeredPane.repaint();
|
||||||
|
|
||||||
|
snapshotLayer.flushSnapshotImages();
|
||||||
|
|
||||||
// run Runnable that FlatRootPaneUI put into client properties
|
// run Runnable that FlatRootPaneUI put into client properties
|
||||||
JRootPane rootPane = e.getKey().getRootPane();
|
JRootPane rootPane = layeredPane.getRootPane();
|
||||||
rootPane.putClientProperty( "FlatLaf.internal.animatedLafChange", null );
|
rootPane.putClientProperty( "FlatLaf.internal.animatedLafChange", null );
|
||||||
Runnable r = (Runnable) rootPane.getClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished" );
|
Runnable r = (Runnable) rootPane.getClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished" );
|
||||||
if( r != null ) {
|
if( r != null ) {
|
||||||
@@ -196,7 +182,7 @@ public class FlatAnimatedLafChange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
map.clear();
|
snapshots.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,4 +194,40 @@ public class FlatAnimatedLafChange
|
|||||||
else
|
else
|
||||||
hideSnapshot();
|
hideSnapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class SnapshotLayer ------------------------------------------------
|
||||||
|
|
||||||
|
private static class SnapshotLayer
|
||||||
|
extends JComponent
|
||||||
|
{
|
||||||
|
VolatileImage oldSnapshotImage;
|
||||||
|
VolatileImage newSnapshotImage;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g ) {
|
||||||
|
if( oldSnapshotImage.contentsLost() ||
|
||||||
|
newSnapshotImage == null || newSnapshotImage.contentsLost() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// draw new UI snapshot
|
||||||
|
g.drawImage( newSnapshotImage, 0, 0, null );
|
||||||
|
|
||||||
|
// draw old UI snapshot
|
||||||
|
((Graphics2D)g).setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha ) );
|
||||||
|
g.drawImage( oldSnapshotImage, 0, 0, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeNotify() {
|
||||||
|
super.removeNotify();
|
||||||
|
flushSnapshotImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushSnapshotImages() {
|
||||||
|
// release system resources used by volatile image
|
||||||
|
oldSnapshotImage.flush();
|
||||||
|
if( newSnapshotImage != null )
|
||||||
|
newSnapshotImage.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user