203 lines
8.3 KiB
Java
203 lines
8.3 KiB
Java
package com.minres.scviewer.database.ui.swt.sb;
|
|
|
|
import static com.minres.scviewer.database.ui.swt.sb.FlatScrollBar.BAR_BREADTH;
|
|
import static java.lang.Math.max;
|
|
|
|
import org.eclipse.swt.SWT;
|
|
import org.eclipse.swt.graphics.Point;
|
|
import org.eclipse.swt.graphics.Rectangle;
|
|
import org.eclipse.swt.widgets.Composite;
|
|
import org.eclipse.swt.widgets.Control;
|
|
|
|
enum Direction {
|
|
|
|
HORIZONTAL( SWT.HORIZONTAL ) {
|
|
|
|
@Override
|
|
protected void layout( FlatScrollBar scrollBar, int buttonLength ) {
|
|
ComponentDistribution distribution = calculateComponentDistribution( scrollBar, buttonLength );
|
|
Rectangle[] componentBounds = calculateComponentBounds( distribution, scrollBar );
|
|
applyComponentBounds( scrollBar, componentBounds );
|
|
}
|
|
|
|
private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) {
|
|
return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).width );
|
|
}
|
|
|
|
private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) {
|
|
int width = getControlBounds( scrollBar ).width;
|
|
int height = getControlBounds( scrollBar ).height - FlatScrollBar.BAR_BREADTH + 1;
|
|
int balance = getRoundingBalance( distribution, scrollBar );
|
|
return new Rectangle[] {
|
|
calcButtons( distribution, width, $( 0, CLEARANCE, distribution.buttonLen, height ) ),
|
|
$( distribution.buttonLen, CLEARANCE, distribution.upFastLength, height ),
|
|
calcDrag( distribution, $( distribution.dragStart, CLEARANCE, distribution.dragLength + balance, height ) ),
|
|
$( distribution.downFastStart, CLEARANCE, distribution.downFastLength - balance, height ),
|
|
calcButtons( distribution, width, $( distribution.downStart, CLEARANCE, distribution.buttonLen, height ) )
|
|
};
|
|
}
|
|
|
|
private Rectangle calcButtons( ComponentDistribution distribution, int length, Rectangle bounds ) {
|
|
Rectangle result = bounds;
|
|
if( length <= distribution.buttonLen* 2 ) {
|
|
int downStart = calcDownStartForSmallLength( bounds.x, length );
|
|
result = $( downStart, CLEARANCE, length / 2, bounds.height );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
protected void setDefaultSize( Control control ) {
|
|
Point size = control.getSize();
|
|
control.setSize( size.x, FlatScrollBar.BAR_BREADTH );
|
|
}
|
|
|
|
@Override
|
|
protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) {
|
|
int x = wHint == SWT.DEFAULT ? composite.getParent().getClientArea().width : wHint;
|
|
return new Point( x, FlatScrollBar.BAR_BREADTH );
|
|
}
|
|
|
|
@Override
|
|
protected void expand( Control control, int maxExpansion ) {
|
|
Rectangle bounds = control.getBounds();
|
|
int expand = expand( bounds.height, maxExpansion );
|
|
control.setBounds( bounds.x, bounds.y - expand, bounds.width, bounds.height + expand );
|
|
}
|
|
},
|
|
|
|
VERTICAL( SWT.VERTICAL ) {
|
|
|
|
@Override
|
|
protected void layout( FlatScrollBar scrollBar, int buttonLength ) {
|
|
ComponentDistribution calculation = calculateComponentDistribution( scrollBar, buttonLength );
|
|
applyComponentBounds( scrollBar, calculateComponentBounds( calculation, scrollBar ) );
|
|
}
|
|
|
|
private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) {
|
|
return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).height );
|
|
}
|
|
|
|
private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) {
|
|
int width = getControlBounds( scrollBar ).width - FlatScrollBar.BAR_BREADTH + 1;
|
|
int height = getControlBounds( scrollBar ).height;
|
|
int balance = getRoundingBalance( distribution, scrollBar );
|
|
return new Rectangle[] {
|
|
calculateButtons( distribution, height, $( CLEARANCE, 0, width, distribution.buttonLen ) ),
|
|
$( CLEARANCE, distribution.buttonLen, width, distribution.upFastLength ),
|
|
calcDrag( distribution, $( CLEARANCE, distribution.dragStart, width, distribution.dragLength + balance ) ),
|
|
$( CLEARANCE, distribution.downFastStart, width, distribution.downFastLength - balance ),
|
|
calculateButtons( distribution, height, $( CLEARANCE, distribution.downStart, width, distribution.buttonLen ) )
|
|
};
|
|
}
|
|
|
|
private Rectangle calculateButtons( ComponentDistribution distribution, int length, Rectangle bounds ) {
|
|
Rectangle result = bounds;
|
|
if( length <= distribution.buttonLen * 2 ) {
|
|
int downStart = calcDownStartForSmallLength( bounds.y, length );
|
|
result = $( CLEARANCE, downStart, bounds.width, length / 2 );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
protected void setDefaultSize( Control control ) {
|
|
Point size = control.getSize();
|
|
control.setSize( FlatScrollBar.BAR_BREADTH, size.y );
|
|
}
|
|
|
|
@Override
|
|
protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) {
|
|
int y = hHint == SWT.DEFAULT ? composite.getParent().getClientArea().height : hHint;
|
|
return new Point( FlatScrollBar.BAR_BREADTH, y );
|
|
}
|
|
|
|
@Override
|
|
protected void expand( Control control, int maxExpansion ) {
|
|
Rectangle bounds = control.getBounds();
|
|
int expand = expand( bounds.width, maxExpansion );
|
|
control.setBounds( bounds.x - expand, bounds.y, bounds.width + expand, bounds.height );
|
|
}
|
|
};
|
|
|
|
static final Rectangle EMPTY_RECTANGLE = $( 0, 0, 0, 0 );
|
|
static final int CLEARANCE = BAR_BREADTH - 2;
|
|
|
|
private final int value;
|
|
|
|
protected abstract void layout( FlatScrollBar scrollBar, int buttonLength );
|
|
protected abstract void setDefaultSize( Control control );
|
|
protected abstract Point computeSize( Composite comp, int wHint, int hHint, boolean changed );
|
|
protected abstract void expand( Control control, int maxExpansion );
|
|
|
|
Direction( int value ) {
|
|
this.value = value;
|
|
}
|
|
|
|
public int value() {
|
|
return value;
|
|
}
|
|
|
|
private static ComponentDistribution calculateComponentDistribution(
|
|
FlatScrollBar scrollBar , int buttonLength , int length )
|
|
{
|
|
int range = scrollBar.getMaximum() - scrollBar.getMinimum();
|
|
int position = scrollBar.getSelection() - scrollBar.getMinimum();
|
|
int thumb = scrollBar.getThumb();
|
|
return new ComponentDistribution( buttonLength, length, range, position, thumb );
|
|
}
|
|
|
|
private static Rectangle getControlBounds( FlatScrollBar scrollBar ) {
|
|
return scrollBar.getClientArea();
|
|
}
|
|
|
|
private static void applyComponentBounds( FlatScrollBar scrollBar, Rectangle[] bounds ) {
|
|
scrollBar.up.getControl().setBounds( bounds[ 0 ] );
|
|
scrollBar.upFast.getControl().setBounds( bounds[ 1 ] );
|
|
scrollBar.drag.getControl().setBounds( bounds[ 2 ] );
|
|
scrollBar.downFast.getControl().setBounds( bounds[ 3 ] );
|
|
scrollBar.down.getControl().setBounds( bounds[ 4 ] );
|
|
}
|
|
|
|
// TODO [fappel]: There is a 1 pixel rounding problem at the seam of drag/downFast with down.
|
|
// Seems to work but I would prefer a better solution if possible
|
|
private static int getRoundingBalance( ComponentDistribution calculation, FlatScrollBar scrollBar ) {
|
|
int result = 0;
|
|
int maximumSelection = scrollBar.getMaximum() - scrollBar.getThumb();
|
|
if( scrollBar.getSelection() == maximumSelection && 0 != calculation.downFastLength ) {
|
|
result = 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static int expand( int toExpand, int maxExpansion ) {
|
|
return max( 0, FlatScrollBar.BAR_BREADTH + maxExpansion - max( FlatScrollBar.BAR_BREADTH, toExpand ) );
|
|
}
|
|
|
|
private static Rectangle calcDrag( ComponentDistribution distribution, Rectangle bounds ) {
|
|
Rectangle result = bounds;
|
|
if( isUndercutOfDragVisibility( distribution ) ) {
|
|
result = EMPTY_RECTANGLE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static boolean isUndercutOfDragVisibility( ComponentDistribution distribution ) {
|
|
return distribution.dragLength + distribution.buttonLen >= distribution.downStart;
|
|
}
|
|
|
|
private static int calcDownStartForSmallLength( int position, int length ) {
|
|
int result = position;
|
|
if( isDownStartPosition( position ) ) {
|
|
result = length / 2;
|
|
}
|
|
return result;
|
|
}
|
|
private static boolean isDownStartPosition( int position ) {
|
|
return position > 0 || position < 0;
|
|
}
|
|
|
|
private static Rectangle $( int x, int y, int width, int height ) {
|
|
return new Rectangle( x, y , width , height );
|
|
}
|
|
} |