mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 22:10:54 +03:00
TabbedPane: support precise scrolling tabs with trackpad (issue #40)
This commit is contained in:
@@ -132,6 +132,7 @@ public class FlatTabbedPaneUI
|
|||||||
protected FlatWheelTabScroller wheelTabScroller;
|
protected FlatWheelTabScroller wheelTabScroller;
|
||||||
|
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
private boolean blockRollover;
|
||||||
|
|
||||||
public static ComponentUI createUI( JComponent c ) {
|
public static ComponentUI createUI( JComponent c ) {
|
||||||
return new FlatTabbedPaneUI();
|
return new FlatTabbedPaneUI();
|
||||||
@@ -282,6 +283,9 @@ public class FlatTabbedPaneUI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setRolloverTab( int index ) {
|
protected void setRolloverTab( int index ) {
|
||||||
|
if( blockRollover )
|
||||||
|
return;
|
||||||
|
|
||||||
int oldIndex = getRolloverTab();
|
int oldIndex = getRolloverTab();
|
||||||
super.setRolloverTab( index );
|
super.setRolloverTab( index );
|
||||||
|
|
||||||
@@ -659,19 +663,23 @@ public class FlatTabbedPaneUI
|
|||||||
protected class FlatWheelTabScroller
|
protected class FlatWheelTabScroller
|
||||||
extends MouseAdapter
|
extends MouseAdapter
|
||||||
{
|
{
|
||||||
|
private int lastMouseX;
|
||||||
|
private int lastMouseY;
|
||||||
|
|
||||||
private boolean inViewport;
|
private boolean inViewport;
|
||||||
private boolean scrolled;
|
private boolean scrolled;
|
||||||
private Timer timer;
|
private Timer rolloverTimer;
|
||||||
|
private Timer exitedTimer;
|
||||||
|
|
||||||
private Animator animator;
|
private Animator animator;
|
||||||
private Point startViewPosition;
|
private Point startViewPosition;
|
||||||
private Point targetViewPosition;
|
private Point targetViewPosition;
|
||||||
private int lastMouseX;
|
|
||||||
private int lastMouseY;
|
|
||||||
|
|
||||||
protected void uninstall() {
|
protected void uninstall() {
|
||||||
if( timer != null )
|
if( rolloverTimer != null )
|
||||||
timer.stop();
|
rolloverTimer.stop();
|
||||||
|
if( exitedTimer != null )
|
||||||
|
exitedTimer.stop();
|
||||||
if( animator != null )
|
if( animator != null )
|
||||||
animator.cancel();
|
animator.cancel();
|
||||||
}
|
}
|
||||||
@@ -686,6 +694,8 @@ public class FlatTabbedPaneUI
|
|||||||
lastMouseX = e.getX();
|
lastMouseX = e.getX();
|
||||||
lastMouseY = e.getY();
|
lastMouseY = e.getY();
|
||||||
|
|
||||||
|
double preciseWheelRotation = e.getPreciseWheelRotation();
|
||||||
|
|
||||||
// compute new view position
|
// compute new view position
|
||||||
Point viewPosition = (targetViewPosition != null)
|
Point viewPosition = (targetViewPosition != null)
|
||||||
? targetViewPosition
|
? targetViewPosition
|
||||||
@@ -695,19 +705,34 @@ public class FlatTabbedPaneUI
|
|||||||
int y = viewPosition.y;
|
int y = viewPosition.y;
|
||||||
int tabPlacement = tabPane.getTabPlacement();
|
int tabPlacement = tabPane.getTabPlacement();
|
||||||
if( tabPlacement == TOP || tabPlacement == BOTTOM ) {
|
if( tabPlacement == TOP || tabPlacement == BOTTOM ) {
|
||||||
x += maxTabHeight * e.getWheelRotation();
|
x += maxTabHeight * preciseWheelRotation;
|
||||||
x = Math.min( Math.max( x, 0 ), viewSize.width - tabViewport.getWidth() );
|
x = Math.min( Math.max( x, 0 ), viewSize.width - tabViewport.getWidth() );
|
||||||
} else {
|
} else {
|
||||||
y += maxTabHeight * e.getWheelRotation();
|
y += maxTabHeight * preciseWheelRotation;
|
||||||
y = Math.min( Math.max( y, 0 ), viewSize.height - tabViewport.getHeight() );
|
y = Math.min( Math.max( y, 0 ), viewSize.height - tabViewport.getHeight() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// update view position
|
// check whether view position has changed
|
||||||
Point newViewPosition = new Point( x, y );
|
Point newViewPosition = new Point( x, y );
|
||||||
setViewPositionAnimated( newViewPosition );
|
if( newViewPosition.equals( viewPosition ) )
|
||||||
|
return;
|
||||||
|
|
||||||
if( !newViewPosition.equals( viewPosition ))
|
// update view position
|
||||||
scrolled = true;
|
if( preciseWheelRotation != 0 &&
|
||||||
|
preciseWheelRotation != e.getWheelRotation() )
|
||||||
|
{
|
||||||
|
// do not use animation for precise scrolling (e.g. with trackpad)
|
||||||
|
|
||||||
|
// stop running animation (if any)
|
||||||
|
if( animator != null )
|
||||||
|
animator.stop();
|
||||||
|
|
||||||
|
tabViewport.setViewPosition( newViewPosition );
|
||||||
|
updateRolloverDelayed();
|
||||||
|
} else
|
||||||
|
setViewPositionAnimated( newViewPosition );
|
||||||
|
|
||||||
|
scrolled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setViewPositionAnimated( Point viewPosition ) {
|
protected void setViewPositionAnimated( Point viewPosition ) {
|
||||||
@@ -718,7 +743,7 @@ public class FlatTabbedPaneUI
|
|||||||
// do not use animation if disabled
|
// do not use animation if disabled
|
||||||
if( !isSmoothScrollingEnabled() ) {
|
if( !isSmoothScrollingEnabled() ) {
|
||||||
tabViewport.setViewPosition( viewPosition );
|
tabViewport.setViewPosition( viewPosition );
|
||||||
setRolloverTab( lastMouseX, lastMouseY );
|
updateRolloverDelayed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,8 +779,38 @@ public class FlatTabbedPaneUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// restart animator
|
// restart animator
|
||||||
animator.cancel();
|
animator.restart();
|
||||||
animator.start();
|
}
|
||||||
|
|
||||||
|
protected void updateRolloverDelayed() {
|
||||||
|
blockRollover = true;
|
||||||
|
|
||||||
|
// keep rollover on last tab until it would move to another tab, then clear it
|
||||||
|
int oldIndex = getRolloverTab();
|
||||||
|
if( oldIndex >= 0 ) {
|
||||||
|
int index = tabForCoordinate( tabPane, lastMouseX, lastMouseY );
|
||||||
|
if( index >= 0 && index != oldIndex ) {
|
||||||
|
// clear if moved to another tab
|
||||||
|
blockRollover = false;
|
||||||
|
setRolloverTab( -1 );
|
||||||
|
blockRollover = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create timer
|
||||||
|
if( rolloverTimer == null ) {
|
||||||
|
rolloverTimer = new Timer( 150, e -> {
|
||||||
|
blockRollover = false;
|
||||||
|
|
||||||
|
// highlight tab at mouse location
|
||||||
|
if( tabPane != null )
|
||||||
|
setRolloverTab( lastMouseX, lastMouseY );
|
||||||
|
} );
|
||||||
|
rolloverTimer.setRepeats( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
// restart timer
|
||||||
|
rolloverTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -790,8 +845,8 @@ public class FlatTabbedPaneUI
|
|||||||
if( inViewport != wasInViewport ) {
|
if( inViewport != wasInViewport ) {
|
||||||
if( !inViewport )
|
if( !inViewport )
|
||||||
viewportExited();
|
viewportExited();
|
||||||
else if( timer != null )
|
else if( exitedTimer != null )
|
||||||
timer.stop();
|
exitedTimer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,12 +854,12 @@ public class FlatTabbedPaneUI
|
|||||||
if( !scrolled )
|
if( !scrolled )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( timer == null ) {
|
if( exitedTimer == null ) {
|
||||||
timer = new Timer( 500, e -> ensureSelectedTabVisible() );
|
exitedTimer = new Timer( 500, e -> ensureSelectedTabVisible() );
|
||||||
timer.setRepeats( false );
|
exitedTimer.setRepeats( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.start();
|
exitedTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ensureSelectedTabVisible() {
|
protected void ensureSelectedTabVisible() {
|
||||||
|
|||||||
@@ -216,6 +216,9 @@ public class Animator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void stop( boolean cancel ) {
|
private void stop( boolean cancel ) {
|
||||||
|
if( !running )
|
||||||
|
return;
|
||||||
|
|
||||||
if( timer != null )
|
if( timer != null )
|
||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
||||||
@@ -226,6 +229,15 @@ public class Animator
|
|||||||
timeToStop = false;
|
timeToStop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restarts the animation.
|
||||||
|
* Invokes {@link #cancel()} and {@link #start()}.
|
||||||
|
*/
|
||||||
|
public void restart() {
|
||||||
|
cancel();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this animation is running.
|
* Returns whether this animation is running.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user