FlatAnimatorTest: added test for wheel scrolling (including chart)

This commit is contained in:
Karl Tauber
2020-10-09 16:01:45 +02:00
parent 865a56875f
commit 419a689ca4
3 changed files with 216 additions and 14 deletions

View File

@@ -17,7 +17,12 @@
package com.formdev.flatlaf.testing; package com.formdev.flatlaf.testing;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*;
import com.formdev.flatlaf.testing.FlatSmoothScrollingTest.LineChartPanel;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.Animator; import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.CubicBezierEasing; import com.formdev.flatlaf.util.CubicBezierEasing;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -40,6 +45,9 @@ public class FlatAnimatorTest
FlatAnimatorTest() { FlatAnimatorTest() {
initComponents(); initComponents();
lineChartPanel.setSecondWidth( 500 );
mouseWheelTestPanel.lineChartPanel = lineChartPanel;
} }
private void start() { private void start() {
@@ -72,6 +80,14 @@ public class FlatAnimatorTest
} }
} }
private void updateChartDelayedChanged() {
lineChartPanel.setUpdateDelayed( updateChartDelayedCheckBox.isSelected() );
}
private void clearChart() {
lineChartPanel.clear();
}
private void initComponents() { private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel(); JLabel label1 = new JLabel();
@@ -79,6 +95,13 @@ public class FlatAnimatorTest
JLabel label2 = new JLabel(); JLabel label2 = new JLabel();
easeInOutScrollBar = new JScrollBar(); easeInOutScrollBar = new JScrollBar();
startButton = new JButton(); startButton = new JButton();
JLabel label3 = new JLabel();
mouseWheelTestPanel = new FlatAnimatorTest.MouseWheelTestPanel();
JScrollPane scrollPane1 = new JScrollPane();
lineChartPanel = new FlatSmoothScrollingTest.LineChartPanel();
JLabel label4 = new JLabel();
updateChartDelayedCheckBox = new JCheckBox();
JButton clearChartButton = new JButton();
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
@@ -89,6 +112,10 @@ public class FlatAnimatorTest
// rows // rows
"[]" + "[]" +
"[]" + "[]" +
"[]" +
"[]" +
"[top]" +
"[400,grow,fill]" +
"[]")); "[]"));
//---- label1 ---- //---- label1 ----
@@ -113,6 +140,37 @@ public class FlatAnimatorTest
startButton.setText("Start"); startButton.setText("Start");
startButton.addActionListener(e -> start()); startButton.addActionListener(e -> start());
add(startButton, "cell 0 2"); add(startButton, "cell 0 2");
//---- label3 ----
label3.setText("Mouse wheel test:");
add(label3, "cell 0 4");
//---- mouseWheelTestPanel ----
mouseWheelTestPanel.setBorder(new LineBorder(Color.red));
add(mouseWheelTestPanel, "cell 1 4,height 100");
//======== scrollPane1 ========
{
scrollPane1.setViewportView(lineChartPanel);
}
add(scrollPane1, "cell 0 5 2 1");
//---- label4 ----
label4.setText("X: time (500ms per line) / Y: value (10% per line)");
add(label4, "cell 0 6 2 1");
//---- updateChartDelayedCheckBox ----
updateChartDelayedCheckBox.setText("Update chart delayed");
updateChartDelayedCheckBox.setMnemonic('U');
updateChartDelayedCheckBox.setSelected(true);
updateChartDelayedCheckBox.addActionListener(e -> updateChartDelayedChanged());
add(updateChartDelayedCheckBox, "cell 0 6 2 1,alignx right,growx 0");
//---- clearChartButton ----
clearChartButton.setText("Clear Chart");
clearChartButton.setMnemonic('C');
clearChartButton.addActionListener(e -> clearChart());
add(clearChartButton, "cell 0 6 2 1,alignx right,growx 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents // JFormDesigner - End of component initialization //GEN-END:initComponents
} }
@@ -120,5 +178,68 @@ public class FlatAnimatorTest
private JScrollBar linearScrollBar; private JScrollBar linearScrollBar;
private JScrollBar easeInOutScrollBar; private JScrollBar easeInOutScrollBar;
private JButton startButton; private JButton startButton;
private FlatAnimatorTest.MouseWheelTestPanel mouseWheelTestPanel;
private FlatSmoothScrollingTest.LineChartPanel lineChartPanel;
private JCheckBox updateChartDelayedCheckBox;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
//---- class MouseWheelTestPanel ------------------------------------------
static class MouseWheelTestPanel
extends JPanel
implements MouseWheelListener
{
private static final int MAX_VALUE = 1000;
private static final int STEP = 100;
private final JLabel valueLabel;
private final Animator animator;
LineChartPanel lineChartPanel;
private int value;
private int startValue;
private int targetValue = -1;
MouseWheelTestPanel() {
super( new BorderLayout() );
valueLabel = new JLabel( String.valueOf( value ), SwingConstants.CENTER );
valueLabel.setFont( valueLabel.getFont().deriveFont( (float) valueLabel.getFont().getSize() * 2 ) );
add( valueLabel, BorderLayout.CENTER );
add( new JLabel( " " ), BorderLayout.NORTH );
add( new JLabel( "(move mouse into rectangle and rotate mouse wheel)", SwingConstants.CENTER ), BorderLayout.SOUTH );
int duration = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.duration", 200 );
int resolution = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.resolution", 10 );
animator = new Animator( duration, fraction -> {
value = startValue + Math.round( (targetValue - startValue) * fraction );
valueLabel.setText( String.valueOf( value ) );
lineChartPanel.addValue( value / (double) MAX_VALUE, Color.red );
}, () -> {
targetValue = -1;
} );
animator.setResolution( resolution );
animator.setInterpolator( new CubicBezierEasing( 0.5f, 0.5f, 0.5f, 1 ) );
addMouseWheelListener( this );
}
@Override
public void mouseWheelMoved( MouseWheelEvent e ) {
lineChartPanel.addValue( 0.5 + (e.getWheelRotation() / 10.), true, Color.red );
// start next animation at the current value
startValue = value;
// increase/decrease target value if animation is in progress
targetValue = (targetValue < 0 ? value : targetValue) + (STEP * e.getWheelRotation());
targetValue = Math.min( Math.max( targetValue, 0 ), MAX_VALUE );
// restart animator
animator.cancel();
animator.start();
}
}
} }

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.2.0.298" Java: "14.0.2" encoding: "UTF-8" JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8"
new FormModel { new FormModel {
contentType: "form/swing" contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[fill][grow,fill]" "$columnConstraints": "[fill][grow,fill]"
"$rowConstraints": "[][][]" "$rowConstraints": "[][][][][top][400,grow,fill][]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
@@ -54,9 +54,61 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2" "value": "cell 0 2"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label3"
"text": "Mouse wheel test:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "com.formdev.flatlaf.testing.FlatAnimatorTest$MouseWheelTestPanel" ) {
name: "mouseWheelTestPanel"
"border": new javax.swing.border.LineBorder( sfield java.awt.Color red, 1, false )
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4,height 100"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane1"
add( new FormComponent( "com.formdev.flatlaf.testing.FlatSmoothScrollingTest$LineChartPanel" ) {
name: "lineChartPanel"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5 2 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label4"
"text": "X: time (500ms per line) / Y: value (10% per line)"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6 2 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "updateChartDelayedCheckBox"
"text": "Update chart delayed"
"mnemonic": 85
"selected": true
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "updateChartDelayedChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6 2 1,alignx right,growx 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "clearChartButton"
"text": "Clear Chart"
"mnemonic": 67
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "clearChart", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6 2 1,alignx right,growx 0"
} )
}, new FormLayoutConstraints( null ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 415, 350 ) "size": new java.awt.Dimension( 625, 625 )
} ) } )
} }
} }

View File

@@ -460,20 +460,23 @@ public class FlatSmoothScrollingTest
//---- class LineChartPanel ----------------------------------------------- //---- class LineChartPanel -----------------------------------------------
private static class LineChartPanel static class LineChartPanel
extends JComponent extends JComponent
implements Scrollable implements Scrollable
{ {
private static final int SECOND_WIDTH = 200;
private static final int NEW_SEQUENCE_TIME_LAG = 500; private static final int NEW_SEQUENCE_TIME_LAG = 500;
private static final int NEW_SEQUENCE_GAP = 20; private static final int NEW_SEQUENCE_GAP = 20;
private int secondWidth = 1000;
private static class Data { private static class Data {
final double value; final double value;
final boolean dot;
final long time; // in milliseconds final long time; // in milliseconds
Data( double value, long time ) { Data( double value, boolean dot, long time ) {
this.value = value; this.value = value;
this.dot = dot;
this.time = time; this.time = time;
} }
@@ -497,8 +500,12 @@ public class FlatSmoothScrollingTest
} }
void addValue( double value, Color chartColor ) { void addValue( double value, Color chartColor ) {
addValue( value, false, chartColor );
}
void addValue( double value, boolean dot, Color chartColor ) {
List<Data> chartData = color2dataMap.computeIfAbsent( chartColor, k -> new ArrayList<>() ); List<Data> chartData = color2dataMap.computeIfAbsent( chartColor, k -> new ArrayList<>() );
chartData.add( new Data( value, System.nanoTime() / 1000000) ); chartData.add( new Data( value, dot, System.nanoTime() / 1000000) );
lastUsedChartColor = chartColor; lastUsedChartColor = chartColor;
@@ -521,6 +528,10 @@ public class FlatSmoothScrollingTest
this.updateDelayed = updateDelayed; this.updateDelayed = updateDelayed;
} }
void setSecondWidth( int secondWidth ) {
this.secondWidth = secondWidth;
}
private void repaintAndRevalidate() { private void repaintAndRevalidate() {
repaint(); repaint();
revalidate(); revalidate();
@@ -546,7 +557,7 @@ public class FlatSmoothScrollingTest
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
FlatUIUtils.setRenderingHints( g ); FlatUIUtils.setRenderingHints( g );
int secondWidth = (int) (SECOND_WIDTH * scaleFactor); int secondWidth = (int) (this.secondWidth * scaleFactor);
int seqGapWidth = (int) (NEW_SEQUENCE_GAP * scaleFactor); int seqGapWidth = (int) (NEW_SEQUENCE_GAP * scaleFactor);
Color lineColor = FlatUIUtils.getUIColor( "Component.borderColor", Color.lightGray ); Color lineColor = FlatUIUtils.getUIColor( "Component.borderColor", Color.lightGray );
@@ -591,20 +602,32 @@ public class FlatSmoothScrollingTest
g.setColor( chartColor ); g.setColor( chartColor );
boolean first = true;
int size = chartData.size(); int size = chartData.size();
for( int i = 0; i < size; i++ ) { for( int i = 0; i < size; i++ ) {
Data data = chartData.get( i ); Data data = chartData.get( i );
int dy = (int) ((height - 1) * data.value); int dy = (int) ((height - 1) * data.value);
if( data.dot ) {
int dotx = px;
if( i > 0 && data.time > ptime + NEW_SEQUENCE_TIME_LAG )
dotx += seqGapWidth;
int o = UIScale.scale( 1 );
int s = UIScale.scale( 3 );
g.fillRect( dotx - o, dy - o, s, s );
continue;
}
if( data.time > ptime + NEW_SEQUENCE_TIME_LAG ) { if( data.time > ptime + NEW_SEQUENCE_TIME_LAG ) {
if( i > 0 && pcount == 0 ) if( !first && pcount == 0 )
g.drawLine( px, py, px + (int) (4 * scaleFactor), py ); g.drawLine( px, py, px + (int) (4 * scaleFactor), py );
// start new sequence // start new sequence
seqTime = data.time; seqTime = data.time;
seqX = (i > 0) ? px + seqGapWidth : 0; seqX = !first ? px + seqGapWidth : 0;
px = seqX; px = seqX;
pcount = 0; pcount = 0;
first = false;
} else { } else {
boolean isTemporaryValue = isTemporaryValue( chartData, i ) || isTemporaryValue( chartData, i - 1 ); boolean isTemporaryValue = isTemporaryValue( chartData, i ) || isTemporaryValue( chartData, i - 1 );
if( isTemporaryValue ) if( isTemporaryValue )
@@ -634,8 +657,14 @@ public class FlatSmoothScrollingTest
if( i == 0 || i == chartData.size() - 1 ) if( i == 0 || i == chartData.size() - 1 )
return false; return false;
double valueBefore = chartData.get( i - 1 ).value; Data dataBefore = chartData.get( i - 1 );
double valueAfter = chartData.get( i + 1 ).value; Data dataAfter = chartData.get( i + 1 );
if( dataBefore.dot || dataAfter.dot )
return false;
double valueBefore = dataBefore.value;
double valueAfter = dataAfter.value;
return valueBefore == valueAfter || return valueBefore == valueAfter ||
(i < chartData.size() - 2 && valueBefore == chartData.get( i + 2 ).value) || (i < chartData.size() - 2 && valueBefore == chartData.get( i + 2 ).value) ||
@@ -666,7 +695,7 @@ public class FlatSmoothScrollingTest
px = seqX; px = seqX;
} else { } else {
// line in sequence // line in sequence
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * SECOND_WIDTH)); int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * secondWidth));
px = dx; px = dx;
} }
@@ -691,7 +720,7 @@ public class FlatSmoothScrollingTest
@Override @Override
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) { public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
return SECOND_WIDTH; return secondWidth;
} }
@Override @Override