Skip to content

Commit

Permalink
ttools: add graphics for old-style 'frame' zoom to plot2 navigators
Browse files Browse the repository at this point in the history
The frame drag zoom that was the main way to zoom in the classic plot
windows has its enthusiasts.  This commit adds the rubber-band
graphics for implementing this to the plot2 windows, using drag with
mouse button 2 (or shift).  The actual associated zoom actions are not
yet present.
  • Loading branch information
mbtaylor committed Mar 20, 2014
1 parent 37988ad commit fd8fb56
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 58 deletions.
259 changes: 224 additions & 35 deletions ttools/src/main/uk/ac/starlink/ttools/plot2/geom/NavDecorations.java
Expand Up @@ -24,6 +24,7 @@
public class NavDecorations {

private static final int BASE_SIZE = 32;
private static final int BAND_SIZE = 16;
private static final int CENTER_SIZE = 5;
private static final double WHEEL_MAG = 2.0;
private static final Color COLOR = new Color( 0x3030f0 );
Expand All @@ -42,7 +43,7 @@ private NavDecorations() {
* @return position marker centered at <code>p</code>
*/
public static Decoration createCenterDecoration( Point p ) {
return center( p, CENTER );
return center( CENTER, p );
}

/**
Expand All @@ -61,17 +62,17 @@ public static Decoration createWheelDecoration( Point p,
boolean xuse, boolean yuse,
Rectangle bounds ) {
if ( xuse && yuse ) {
return center( p, new WheelZoomIcon2d( BASE_SIZE, xfact, yfact ) );
return center( new WheelZoomIcon2d( BASE_SIZE, xfact, yfact ), p );
}
else if ( xuse ) {
Icon icon = new WheelZoomIcon1d( BASE_SIZE, false, xfact, bounds );
return new Decoration( icon,
p.x - icon.getIconWidth() / 2, bounds.y );
return center1d( new WheelZoomIcon1d( BASE_SIZE, false,
xfact, bounds ),
false, p, bounds );
}
else if ( yuse ) {
Icon icon = new WheelZoomIcon1d( BASE_SIZE, true, yfact, bounds );
return new Decoration( icon,
bounds.x, p.y - icon.getIconHeight() / 2 );
return center1d( new WheelZoomIcon1d( BASE_SIZE, true,
yfact, bounds ),
true, p, bounds );
}
else {
return null;
Expand All @@ -94,17 +95,63 @@ public static Decoration createDragDecoration( Point p,
boolean xuse, boolean yuse,
Rectangle bounds ) {
if ( xuse && yuse ) {
return center( p, new DragZoomIcon2d( BASE_SIZE, xfact, yfact ) );
return center( new DragZoomIcon2d( BASE_SIZE, xfact, yfact ), p );
}
else if ( xuse ) {
Icon icon = new DragZoomIcon1d( BASE_SIZE, false, xfact, bounds );
return new Decoration( icon,
p.x - icon.getIconWidth() / 2, bounds.y );
return center1d( new DragZoomIcon1d( BASE_SIZE, false,
xfact, bounds ),
false, p, bounds );
}
else if ( yuse ) {
Icon icon = new DragZoomIcon1d( BASE_SIZE, true, yfact, bounds );
return new Decoration( icon,
bounds.x, p.y - icon.getIconHeight() / 2 );
return center1d( new DragZoomIcon1d( BASE_SIZE, true,
yfact, bounds ),
true, p, bounds );
}
else {
return null;
}
}

/**
* Returns a decoration appropriate for a 2d frame zoom.
*
* @param p1 drag start point
* @param p2 drag (current) end point
* @param xuse true if X zoom is in effect
* @param yuse true if Y zoom is in effect
* @param bounds plot region bounds
* @return frame decoration
*/
public static Decoration createBandDecoration( Point p1, Point p2,
boolean xuse, boolean yuse,
Rectangle bounds ) {
int dx = p2.x - p1.x;
int dy = p2.y - p1.y;
if ( xuse && yuse ) {
if ( dx >= 0 && dy >= 0 ) {
return new Decoration( new PlusBandZoomIcon2d( dx, dy ),
p1.x, p1.y );
}
else if ( dx < 0 && dy <= 0 ||
dx <= 0 && dy < 0 ) {
return center( new MinusBandZoomIcon2d( BAND_SIZE, -dx, -dy ),
p1 );
}
else {
return null;
}
}
else if ( xuse ) {
Icon icon = dx >= 0 ? new PlusBandZoomIcon1d( false, dx, bounds )
: new MinusBandZoomIcon1d( BAND_SIZE, false,
-dx, bounds );
return center1d( icon, false, p1, bounds );
}
else if ( yuse ) {
Icon icon = dy >= 0 ? new PlusBandZoomIcon1d( true, dy, bounds )
: new MinusBandZoomIcon1d( BAND_SIZE, true,
-dy, bounds );
return center1d( icon, true, p1, bounds );
}
else {
return null;
Expand All @@ -115,15 +162,34 @@ else if ( yuse ) {
* Utility function to center an symmetric icon at a point.
* The icon must correctly report its dimensions for this to work.
*
* @param p central point
* @param icon icon
* @param p central point
* @return centered decoration
*/
public static Decoration center( Point p, Icon icon ) {
public static Decoration center( Icon icon, Point p ) {
return new Decoration( icon, p.x - icon.getIconWidth() / 2,
p.y - icon.getIconHeight() / 2 );
}

/**
* Utility function to center one of the 1-dimensional zoom icons
* about a given point on its axis.
* The icon must correctly report its dimensions for this to work.
*
* @param icon icon
* @param isY false for X axis annotation, true for Y axis annotation
* @param p reference point
* @param bounds plot bounds
* @return centered decoration
*/
public static Decoration center1d( Icon icon, boolean isY, Point p,
Rectangle bounds ) {
Point cp = isY
? new Point( bounds.x, p.y - icon.getIconHeight() / 2 )
: new Point( p.x - icon.getIconWidth() / 2, bounds.y );
return new Decoration( icon, cp.x, cp.y );
}

/**
* Draws a line with an arrow head at one end.
*
Expand Down Expand Up @@ -216,22 +282,38 @@ private static abstract class ZoomIcon1d implements Icon {
10, new float[] { 5, 5 }, 2 );

/**
* Constructor.
* Constructs an icon for a destination value given in pixels.
*
* @param baseSize radial size
* @param baseSize radial size of fixed part of marker
* @param isY true for Y zoom, false for X
* @param factor zoom factor
* @param cTo destination value of zoom coordinate
* @param bounds maximum bounds over which the icon should extend
*/
public ZoomIcon1d( int baseSize, boolean isY, double factor,
public ZoomIcon1d( int baseSize, boolean isY, int cTo,
Rectangle bounds ) {
baseSize_ = baseSize;
isY_ = isY;
cTo_ = (int) Math.round( baseSize_ * factor );
cTo_ = cTo;
blo_ = isY ? bounds.x : bounds.y;
bhi_ = isY ? bounds.x + bounds.width : bounds.y + bounds.height;
}

/**
* Constructs an icon for a given zoom factor.
* The zoom factor is supplied as an array purely to avoid
* confusion with the other constructor.
*
* @param baseSize radial size of fixed part of marker
* @param isY true for Y zoom, false for X
* @param cfactor 1-element array giving zoom factor
* @param bounds maximum bounds over which the icon should extend
*/
public ZoomIcon1d( int baseSize, boolean isY, double[] cfactor,
Rectangle bounds ) {
this( baseSize, isY, (int) Math.round( baseSize * cfactor[ 0 ] ),
bounds );
}

public int getIconWidth() {
return isY_ ? bhi_ - blo_
: 2 * Math.max( baseSize_, cTo_ );
Expand Down Expand Up @@ -334,7 +416,8 @@ private static class WheelZoomIcon1d extends ZoomIcon1d {
* arrows that are too small to see easily. This means that the
* visual representation shows the result of WHEEL_MAG wheel
* clicks not one. */
super( baseSize, isY, Math.pow( factor, WHEEL_MAG ), bounds );
super( baseSize, isY,
new double[] { Math.pow( factor, WHEEL_MAG ) }, bounds );
}

void doPainting( Graphics g, int c0 ) {
Expand Down Expand Up @@ -369,7 +452,7 @@ private static class DragZoomIcon1d extends ZoomIcon1d {
*/
DragZoomIcon1d( int baseSize, boolean isY, double factor,
Rectangle bounds ) {
super( baseSize, isY, factor, bounds );
super( baseSize, isY, new double[] { factor }, bounds );
}

void doPainting( Graphics g, int c0 ) {
Expand All @@ -381,6 +464,54 @@ void doPainting( Graphics g, int c0 ) {
}
}

/**
* Icon representing a frame-type positive zoom in one dimension.
*/
private static class PlusBandZoomIcon1d extends ZoomIcon1d {

/**
* Constructor.
*
* @param isY true for Y zoom, false for X
* @param dc drag extent in pixels
* @param bounds maximum bounds over which the icon should extend
*/
PlusBandZoomIcon1d( boolean isY, int dc, Rectangle bounds ) {
super( 0, isY, dc, bounds );
}

void doPainting( Graphics g, int c0 ) {
drawSpan( g, c0 );
drawSpan( g, c0 + cTo_ );
}
}

/**
* Icon representing a frame-type negative zoom in one dimension.
*/
private static class MinusBandZoomIcon1d extends ZoomIcon1d {

/**
* Constructor.
*
* @param baseSize radial size of fixed part of icon
* @param isY true for Y zoom, false for X
* @param dc drag extent in pixels
* @param bounds maximum bounds over which the icon should extend
*/
MinusBandZoomIcon1d( int baseSize, boolean isY, int dc,
Rectangle bounds ) {
super( baseSize, isY, baseSize + dc, bounds );
}

void doPainting( Graphics g, int c0 ) {
drawSpan( g, c0 - baseSize_ );
drawSpan( g, c0 + baseSize_ );
drawSpan( g, c0 - cTo_ );
drawSpan( g, c0 + cTo_ );
}
}

/**
* Abstract icon to represent a zoom action in 2 dimensions.
*/
Expand All @@ -392,16 +523,30 @@ private static abstract class ZoomIcon2d implements Icon {
final int yTo_;

/**
* Constructor.
* Constructs a zoom icon specifying destination position.
*
* @param baseSize radial size
* @param xFact zoom factor in X direction
* @param yFact zoom factor in Y direction
* @param baseSize radial size of fixed part of icon
* @param xTo X destination coordinate
* @param yTo Y destination coordinate
*/
ZoomIcon2d( int baseSize, double xFact, double yFact ) {
ZoomIcon2d( int baseSize, int xTo, int yTo ) {
baseSize_ = baseSize;
xTo_ = (int) Math.round( baseSize_ * xFact );
yTo_ = (int) Math.round( baseSize_ * yFact );
xTo_ = xTo;
yTo_ = yTo;
}

/**
* Constructs a zoom icon specifying zoom area by relative size.
* The <code>xyFactors</code> parameter is given as an array
* purely to avoid confusion with the other constructor.
*
* @param baseSize radial size of fixed part of icon
* @param xyFactors 2-element array giving X,Y zoom factors
*/
ZoomIcon2d( int baseSize, double[] xyFactors ) {
this( baseSize,
(int) Math.round( baseSize * xyFactors[ 0 ] ),
(int) Math.round( baseSize * xyFactors[ 1 ] ) );
}

public int getIconWidth() {
Expand All @@ -423,7 +568,7 @@ public void paintIcon( Component c, Graphics g, int x, int y ) {
*
* @param g graphics context
* @param cx central X coordinate
* @parma cy central Y coordinate
* @param cy central Y coordinate
*/
abstract void doPainting( Graphics g, int cx, int cy );

Expand Down Expand Up @@ -482,8 +627,9 @@ private static class WheelZoomIcon2d extends ZoomIcon2d {
* arrows that are too small to see easily. This means that the
* visual representation shows the result of WHEEL_MAG wheel
* clicks not one. */
super( baseSize, Math.pow( xFact, WHEEL_MAG ),
Math.pow( yFact, WHEEL_MAG ) );
super( baseSize,
new double[] { Math.pow( xFact, WHEEL_MAG ),
Math.pow( yFact, WHEEL_MAG ) } );
}

void doPainting( Graphics g, int xc, int yc ) {
Expand All @@ -510,7 +656,7 @@ private static class DragZoomIcon2d extends ZoomIcon2d {
* @param yFact zoom factor in Y direction
*/
DragZoomIcon2d( int baseSize, double xFact, double yFact ) {
super( baseSize, xFact, yFact );
super( baseSize, new double[] { xFact, yFact } );
}

void doPainting( Graphics g, int xc, int yc ) {
Expand All @@ -520,4 +666,47 @@ void doPainting( Graphics g, int xc, int yc ) {
drawCenterPoint( g, xc, yc );
}
}

/**
* Icon representing a frame-type positive zoom in two dimensions.
*/
private static class PlusBandZoomIcon2d extends ZoomIcon2d {

/**
* Constructor.
*
* @param dx drag extent in X direction
* @param dy drag extent in Y direction
*/
PlusBandZoomIcon2d( int dx, int dy ) {
super( 0, dx, dy );
}

void doPainting( Graphics g, int xc, int yc ) {
g.drawRect( xc - xTo_, yc - yTo_, xTo_, yTo_ );
}
}

/**
* Icon representing a frame-type negative zoom in two dimensions.
*/
private static class MinusBandZoomIcon2d extends ZoomIcon2d {

/**
* Constructor.
*
* @param baseSize radial size of fixed part of icon
* @param dx drag extent in X direction
* @param dy drag extent in Y direction
*/
MinusBandZoomIcon2d( int baseSize, int dx, int dy ) {
super( baseSize, baseSize + dx, baseSize + dy );
}

void doPainting( Graphics g, int xc, int yc ) {
g.drawRect( xc - baseSize_, yc - baseSize_,
2 * baseSize_, 2 * baseSize_ );
g.drawRect( xc - xTo_, yc - yTo_, 2 * xTo_, 2 * yTo_ );
}
}
}

0 comments on commit fd8fb56

Please sign in to comment.