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
|
||||
named Java modules, it is no longer necessary to add `opens com.myapp.themes;`
|
||||
to `module-info.java`. (issue #1026)
|
||||
- Extras: Made animated theme change (class `FlatAnimatedLafChange`) smoother.
|
||||
|
||||
#### Fixed bugs
|
||||
|
||||
|
||||
@@ -53,15 +53,13 @@ public class FlatAnimatedLafChange
|
||||
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 final Map<JLayeredPane, JComponent> oldUIsnapshots = new WeakHashMap<>();
|
||||
private static final Map<JLayeredPane, JComponent> newUIsnapshots = new WeakHashMap<>();
|
||||
private static final Map<JLayeredPane, SnapshotLayer> snapshots = new WeakHashMap<>();
|
||||
private static float alpha;
|
||||
private static boolean inShowSnapshot;
|
||||
|
||||
/**
|
||||
* Create a snapshot of the old UI and shows it on top of the UI.
|
||||
@@ -78,63 +76,52 @@ public class FlatAnimatedLafChange
|
||||
alpha = 1;
|
||||
|
||||
// show snapshot of old UI
|
||||
showSnapshot( true, oldUIsnapshots );
|
||||
showSnapshot( true );
|
||||
}
|
||||
|
||||
private static void showSnapshot( boolean old, Map<JLayeredPane, JComponent> map ) {
|
||||
inShowSnapshot = true;
|
||||
|
||||
private static void showSnapshot( boolean old ) {
|
||||
// create snapshots for all shown windows
|
||||
Window[] windows = Window.getWindows();
|
||||
for( Window window : windows ) {
|
||||
if( !(window instanceof RootPaneContainer) || !window.isShowing() )
|
||||
continue;
|
||||
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
|
||||
// create snapshot image
|
||||
// (using volatile image to have correct sub-pixel text rendering on Java 9+)
|
||||
VolatileImage snapshot = window.createVolatileImage( window.getWidth(), window.getHeight() );
|
||||
if( snapshot == null )
|
||||
VolatileImage snapshotImage = layeredPane.createVolatileImage( layeredPane.getWidth(), layeredPane.getHeight() );
|
||||
if( snapshotImage == null )
|
||||
continue;
|
||||
|
||||
// paint window to snapshot image
|
||||
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
|
||||
layeredPane.paint( snapshot.getGraphics() );
|
||||
layeredPane.paint( snapshotImage.getGraphics() );
|
||||
|
||||
// create snapshot layer, which is added to layered pane and paints
|
||||
// snapshot with animated alpha
|
||||
JComponent snapshotLayer = new JComponent() {
|
||||
@Override
|
||||
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 )
|
||||
if( old ) {
|
||||
// create snapshot layer, which is added to layered pane and paints
|
||||
// snapshot with animated alpha
|
||||
SnapshotLayer snapshotLayer = new SnapshotLayer();
|
||||
snapshotLayer.setOpaque( true );
|
||||
snapshotLayer.setSize( layeredPane.getSize() );
|
||||
snapshotLayer.setSize( layeredPane.getSize() );
|
||||
snapshotLayer.oldSnapshotImage = snapshotImage;
|
||||
|
||||
// add image layer to layered pane
|
||||
layeredPane.add( snapshotLayer, Integer.valueOf( JLayeredPane.DRAG_LAYER + (old ? 2 : 1) ) );
|
||||
map.put( layeredPane, snapshotLayer );
|
||||
snapshots.put( layeredPane, snapshotLayer );
|
||||
} else {
|
||||
SnapshotLayer snapshotLayer = snapshots.get( layeredPane );
|
||||
if( snapshotLayer == null ) {
|
||||
snapshotImage.flush();
|
||||
continue;
|
||||
}
|
||||
|
||||
// let FlatRootPaneUI know that animated Laf change is in progress
|
||||
if( old )
|
||||
snapshotLayer.newSnapshotImage = snapshotImage;
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
inShowSnapshot = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,23 +133,22 @@ public class FlatAnimatedLafChange
|
||||
if( !FlatSystemProperties.getBoolean( "flatlaf.animatedLafChange", true ) )
|
||||
return;
|
||||
|
||||
if( oldUIsnapshots.isEmpty() )
|
||||
if( snapshots.isEmpty() )
|
||||
return;
|
||||
|
||||
// show snapshot of new UI
|
||||
showSnapshot( false, newUIsnapshots );
|
||||
showSnapshot( false );
|
||||
|
||||
// create animator
|
||||
animator = new Animator( duration, fraction -> {
|
||||
if( fraction < 0.1 || fraction > 0.9 )
|
||||
return; // ignore initial and last events
|
||||
|
||||
alpha = 1f - fraction;
|
||||
|
||||
// repaint snapshots
|
||||
for( Map.Entry<JLayeredPane, JComponent> e : oldUIsnapshots.entrySet() ) {
|
||||
if( e.getKey().isShowing() )
|
||||
e.getValue().repaint();
|
||||
for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
|
||||
if( e.getKey().isShowing() ) {
|
||||
SnapshotLayer snapshotLayer = e.getValue();
|
||||
snapshotLayer.paintImmediately( 0, 0, snapshotLayer.getWidth(),snapshotLayer.getHeight() );
|
||||
}
|
||||
}
|
||||
|
||||
Toolkit.getDefaultToolkit().sync();
|
||||
@@ -176,18 +162,18 @@ public class FlatAnimatedLafChange
|
||||
}
|
||||
|
||||
private static void hideSnapshot() {
|
||||
hideSnapshot( oldUIsnapshots );
|
||||
hideSnapshot( newUIsnapshots );
|
||||
}
|
||||
|
||||
private static void hideSnapshot( Map<JLayeredPane, JComponent> map ) {
|
||||
// remove snapshots
|
||||
for( Map.Entry<JLayeredPane, JComponent> e : map.entrySet() ) {
|
||||
e.getKey().remove( e.getValue() );
|
||||
e.getKey().repaint();
|
||||
for( Map.Entry<JLayeredPane, SnapshotLayer> e : snapshots.entrySet() ) {
|
||||
JLayeredPane layeredPane = e.getKey();
|
||||
SnapshotLayer snapshotLayer = e.getValue();
|
||||
|
||||
layeredPane.remove( snapshotLayer );
|
||||
layeredPane.repaint();
|
||||
|
||||
snapshotLayer.flushSnapshotImages();
|
||||
|
||||
// run Runnable that FlatRootPaneUI put into client properties
|
||||
JRootPane rootPane = e.getKey().getRootPane();
|
||||
JRootPane rootPane = layeredPane.getRootPane();
|
||||
rootPane.putClientProperty( "FlatLaf.internal.animatedLafChange", null );
|
||||
Runnable r = (Runnable) rootPane.getClientProperty( "FlatLaf.internal.animatedLafChange.runWhenFinished" );
|
||||
if( r != null ) {
|
||||
@@ -196,7 +182,7 @@ public class FlatAnimatedLafChange
|
||||
}
|
||||
}
|
||||
|
||||
map.clear();
|
||||
snapshots.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,4 +194,40 @@ public class FlatAnimatedLafChange
|
||||
else
|
||||
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