Skip to content

Commit

Permalink
FlatAnimatorTest: added test for wheel scrolling (including chart)
Browse files Browse the repository at this point in the history
  • Loading branch information
DevCharly committed Oct 9, 2020
1 parent d137d6d commit 5294ca6
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand All @@ -40,6 +45,9 @@ public static void main( String[] args ) {

FlatAnimatorTest() {
initComponents();

lineChartPanel.setSecondWidth( 500 );
mouseWheelTestPanel.lineChartPanel = lineChartPanel;
}

private void start() {
Expand Down Expand Up @@ -72,13 +80,28 @@ private void startEaseInOut() {
}
}

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();
linearScrollBar = new JScrollBar();
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(
Expand All @@ -89,6 +112,10 @@ private void initComponents() {
// rows
"[]" +
"[]" +
"[]" +
"[]" +
"[top]" +
"[400,grow,fill]" +
"[]"));

//---- label1 ----
Expand All @@ -113,12 +140,106 @@ private void initComponents() {
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
}

// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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" ) {
Expand Down Expand Up @@ -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 )
} )
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -460,20 +460,23 @@ public Point getViewPosition() {

//---- 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;
}

Expand All @@ -497,8 +500,12 @@ public String toString() {
}

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;

Expand All @@ -521,6 +528,10 @@ void setUpdateDelayed( boolean updateDelayed ) {
this.updateDelayed = updateDelayed;
}

void setSecondWidth( int secondWidth ) {
this.secondWidth = secondWidth;
}

private void repaintAndRevalidate() {
repaint();
revalidate();
Expand All @@ -546,7 +557,7 @@ protected void paintComponent( Graphics g ) {
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 );
Expand Down Expand Up @@ -591,20 +602,32 @@ private void paintImpl( Graphics2D g, int x, int y, int width, int height, doubl

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 )
Expand Down Expand Up @@ -634,8 +657,14 @@ private boolean isTemporaryValue( List<Data> chartData, int i ) {
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) ||
Expand Down Expand Up @@ -666,7 +695,7 @@ private int chartWidth( List<Data> chartData, int[] lastSeqX ) {
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;
}

Expand All @@ -691,7 +720,7 @@ public Dimension getPreferredScrollableViewportSize() {

@Override
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
return SECOND_WIDTH;
return secondWidth;
}

@Override
Expand Down

0 comments on commit 5294ca6

Please sign in to comment.