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;
import java.awt.*;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
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.CubicBezierEasing;
import net.miginfocom.swing.*;
@@ -40,6 +45,9 @@ public class FlatAnimatorTest
FlatAnimatorTest() {
initComponents();
lineChartPanel.setSecondWidth( 500 );
mouseWheelTestPanel.lineChartPanel = lineChartPanel;
}
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() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel();
@@ -79,6 +95,13 @@ public class FlatAnimatorTest
JLabel label2 = new JLabel();
easeInOutScrollBar = new JScrollBar();
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 ========
setLayout(new MigLayout(
@@ -89,6 +112,10 @@ public class FlatAnimatorTest
// rows
"[]" +
"[]" +
"[]" +
"[]" +
"[top]" +
"[400,grow,fill]" +
"[]"));
//---- label1 ----
@@ -113,6 +140,37 @@ public class FlatAnimatorTest
startButton.setText("Start");
startButton.addActionListener(e -> start());
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
}
@@ -120,5 +178,68 @@ public class FlatAnimatorTest
private JScrollBar linearScrollBar;
private JScrollBar easeInOutScrollBar;
private JButton startButton;
private FlatAnimatorTest.MouseWheelTestPanel mouseWheelTestPanel;
private FlatSmoothScrollingTest.LineChartPanel lineChartPanel;
private JCheckBox updateChartDelayedCheckBox;
// 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 {
contentType: "form/swing"
@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[fill][grow,fill]"
"$rowConstraints": "[][][]"
"$rowConstraints": "[][][][][top][400,grow,fill][]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
@@ -54,9 +54,61 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"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 ) {
"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 -----------------------------------------------
private static class LineChartPanel
static class LineChartPanel
extends JComponent
implements Scrollable
{
private static final int SECOND_WIDTH = 200;
private static final int NEW_SEQUENCE_TIME_LAG = 500;
private static final int NEW_SEQUENCE_GAP = 20;
private int secondWidth = 1000;
private static class Data {
final double value;
final boolean dot;
final long time; // in milliseconds
Data( double value, long time ) {
Data( double value, boolean dot, long time ) {
this.value = value;
this.dot = dot;
this.time = time;
}
@@ -497,8 +500,12 @@ public class FlatSmoothScrollingTest
}
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<>() );
chartData.add( new Data( value, System.nanoTime() / 1000000) );
chartData.add( new Data( value, dot, System.nanoTime() / 1000000) );
lastUsedChartColor = chartColor;
@@ -521,6 +528,10 @@ public class FlatSmoothScrollingTest
this.updateDelayed = updateDelayed;
}
void setSecondWidth( int secondWidth ) {
this.secondWidth = secondWidth;
}
private void repaintAndRevalidate() {
repaint();
revalidate();
@@ -546,7 +557,7 @@ public class FlatSmoothScrollingTest
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
FlatUIUtils.setRenderingHints( g );
int secondWidth = (int) (SECOND_WIDTH * scaleFactor);
int secondWidth = (int) (this.secondWidth * scaleFactor);
int seqGapWidth = (int) (NEW_SEQUENCE_GAP * scaleFactor);
Color lineColor = FlatUIUtils.getUIColor( "Component.borderColor", Color.lightGray );
@@ -591,20 +602,32 @@ public class FlatSmoothScrollingTest
g.setColor( chartColor );
boolean first = true;
int size = chartData.size();
for( int i = 0; i < size; i++ ) {
Data data = chartData.get( i );
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( i > 0 && pcount == 0 )
if( !first && pcount == 0 )
g.drawLine( px, py, px + (int) (4 * scaleFactor), py );
// start new sequence
seqTime = data.time;
seqX = (i > 0) ? px + seqGapWidth : 0;
seqX = !first ? px + seqGapWidth : 0;
px = seqX;
pcount = 0;
first = false;
} else {
boolean isTemporaryValue = isTemporaryValue( chartData, i ) || isTemporaryValue( chartData, i - 1 );
if( isTemporaryValue )
@@ -634,8 +657,14 @@ public class FlatSmoothScrollingTest
if( i == 0 || i == chartData.size() - 1 )
return false;
double valueBefore = chartData.get( i - 1 ).value;
double valueAfter = chartData.get( i + 1 ).value;
Data dataBefore = chartData.get( i - 1 );
Data dataAfter = chartData.get( i + 1 );
if( dataBefore.dot || dataAfter.dot )
return false;
double valueBefore = dataBefore.value;
double valueAfter = dataAfter.value;
return valueBefore == valueAfter ||
(i < chartData.size() - 2 && valueBefore == chartData.get( i + 2 ).value) ||
@@ -666,7 +695,7 @@ public class FlatSmoothScrollingTest
px = seqX;
} else {
// line in sequence
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * SECOND_WIDTH));
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * secondWidth));
px = dx;
}
@@ -691,7 +720,7 @@ public class FlatSmoothScrollingTest
@Override
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
return SECOND_WIDTH;
return secondWidth;
}
@Override