ScaledUserView

part of wslib


a SCUserView adaptation which supports scaling and translation of it's drawFunc


also see: ScaledUserViewWindow


Creation


ScaledUserView ( window, bounds, fromBounds )

the window and bounds work the same way as in every SCView.

fromBounds : (also an instance variable) the drawFunc of this userView is scaled and translated 

internally in such a way that the fromBounds rect fills the bounds. If no fromBounds are specified

ScaledUserView used the bounds for this instead, and thus doesn't scale anything.

(

// resize the window and see what happens

w = Window( "ScaledUserView" ).front;  

b = ScaledUserView( w,  w.view.bounds.insetBy( 10, 10 ), Rect(0,0,1,1) );

b.drawFunc = { Pen.line( 0.1@0.1, 0.9@0.9 ).stroke; };

b.view.resize = 5;

)


The Pen:width is set by ScaledUserView internally to correspond with 1 px in the view. To change this you can specify your own width:


b.drawFunc = { Pen.width = 0.05; Pen.line( 0.1@0.1, 0.9@0.9 ).stroke; };



Methods and variables


scaleH, scaleV

sets and gets the relative scaling of the drawFunc (default 1)


b.scaleH;

b.scaleH = 2;

b.scaleV = 0.5; 


moveH, moveV

sets and gets the relative moving of the drawFunc (default 0.5).

This depends on the scaling. If the scaling is 1, moveH and moveV are not visible. 

A moveH value of 0.5 means that the scaled func is centered in the view.

A moveH value of 1 means that the right side of the fromBounds is the same as the right side of the view

A moveH value of 0 means that the left side of the fromBounds is the same as that of the view

same goes for moveV


b.moveH;

b.scaleH = 2; b.moveH = 1;  // zoomed H x 2 and scrolled to the outer right side

b.moveH = 0;   // scrolled to the outer left side

b.moveH = 0.5; // scrolled to the center



scale, scale_ ( newScaleArray )

move, move_ ( newMoveArray )

the newScaleArray can be an Array, but also a number (for both H and V) or a Point


b.scale = [0.75, 0.5 ];

b.scale = 1.5@1;

b.scale = 1;  b.move = 0.5; // back to normal


reset

resets scale and move to defaults.


clip

sets and gets clipping boolean for he drawFunc (default true).

If clip is true the path will be clipped to inside the view. 

Depricated (all functions are clipped inside the view now)


b.scale = 2; b.clip = false;

b.clip = true;

b.reset;


autoRefresh

sets and gets the autoRefresh boolean (default true).

Auto refresh works for all the above methods and setters. 


b.autoRefresh = false; 

b.scale = 0.5;

b.refresh;


b.autoRefresh = true; 

b.scale = [-0.5, 0.5];  // yes, you can also use negative values for scale


You can bypass it for each setter individually with it's refreshFlag argument (always the last argument)


b.scale_( 1.1, refreshFlag: false ); 

b.refresh;


view

holds the SCUserView on which this class is based


background

gets and sets the background color


*window

Creates an ScaledUserViewWindow instead


ScaledUserView.window;


drawFuncs


Next to the drawFunc, as used in the above examples, there are several other drawing functions. They can be used simultaniously.


unscaledDrawFunc

this drawFunc is not scaled or moved, except from that it is translated in such a way that Point(0,0) inside this func resembles the topLeft corner of the view. The func is drawn on top of the scaled drawFunc.


b.unscaledDrawFunc = { Pen.width = 2; Color.blue(0.5).set; Pen.line( 300@10, 10@300 ).stroke; };

// resize the window to see the difference


unclippedUnscaledDrawFunc

Same as above, but also not clipped. This draws yet on top of the other two


b.unclippedUnscaledDrawFunc = { Color.red(0.5).set; Pen.line( 200@(-10), 200@500 ).stroke; };



all drawFuncs receive the ScaledUserView itself as firsst argument. From there you can also request the current move and scale settings. But there is a more convenient way of using scaled data inside the unscaled functions:


translateScale ( item )

returns a scaled and translated version of the item. The item can be a Point, a Rect, an array containing Points and Rects, or Pen.

Points and Rects will be scaled and translated according to the settings of the ScaledUserView.

Pen will perform the correct Pen.scale and Pen.translate methods.


(

b.unscaledDrawFunc = { |view|

var points, scaledPoints;

points = [ 0.1@0.1, 0.9@0.1, 0.2@0.5 ];

scaledPoints = view.translateScale( points );

Pen.width = 5; 

Color.blue.set; 

Pen.moveTo( scaledPoints[0] );

scaledPoints[1..].do({ |point| Pen.lineTo( point ) });

Pen.stroke; 

};

)


convertFwd ( x, y ), convertBwd ( x, y )

this converts unscaled x,y values to and back from scaled values


beforeDrawFunc

the beforeDrawFunc is called before any other of the drawFuncs are called at refresh. Use this if you need to calculate values before the other drawFuncs are called. 


clearDrawFuncs

removes all drawFuncs



mouseActions


the ScaledUserView uses the same mouseAction types as regular SCViews: 

mouseDownAction, mouseMoveAction and mouseUpAction 


The arguments they get are different though:

arg view, scaledX, scaledY, modifier, x, y, isInside

view : the ScaledUserView ( as in the drawFuncs )

scaledX, scaledY : the x/y coordinates, scaled according to the view's settings

modifier : binary code of the current modifier key

x, y : the unscaled x/y coordinates, relative to the view's leftTop corner

isInside : a boolean stating wether the mouse is still inside the bounds of the view

the view is automatically refreshed, unless autoRefreshMouseActions is set to false.

(

b.mouseMoveAction = { |v, sx, sy, m, x, y, inside|

[ sx@sy, x@y, inside ].postln;

};

)


/// move a point around

(

b.clearDrawFuncs;

p = 0.5@0.5;

b.drawFunc = { Color.green(0.5).alpha_(0.75).set; Pen.addArc( p, 0.05, 0, 2pi ).fill };

b.mouseMoveAction = { |v, sx, sy, m, x, y, inside| if( inside ) { p = sx@sy; }; };

b.mouseDownAction = b.mouseMoveAction;

)


b.scale = [2, 0.5]; b.move = [ 0.75, 0.25 ]; // still works

b.reset;



gridLines


ScaledUserView has built-in grid drawing. The code below explain how it works:


b.gridLines = 10;


b.gridLines = [ 10, 4 ];  // number of lines for H and V


b.gridMode = \lines; b.refresh; // doesn't refresh!!


b.gridMode = [\blocks, \lines]; b.refresh; 


b.scaleH = 1.5; b.moveH = 0.25;


b.reset;


ScaledUserView.gridColor = Color.red.alpha_(0.25); b.refresh; // gridColor is a global variable


b.gridMode = \blocks; b.refresh;  // default


ScaledUserView.gridColor = Color.gray.alpha_(0.25); b.refresh; // default


b.gridLines = 0;  // no grid (default) - inf does the same


b.gridSpacingH;  // the actual variables are gridSpacingH and gridSpacingV