This class is meant as an emulation of SCUserView. last mod: 29-jan-09 sciss
Also refer to JSCView for different behaviour affecting all widgets
different behaviour | |
refresh | see the introductory paragraph for SwingOSC's refresh policy |
view bounds | here is no way to paint outside the logical bounds of a swing view, all draw operations are automatically clipped to the view's bounds. |
extended functionality | |
focusVisible_ | allows you to switch off the default focus border painting |
refreshOnFocus_ | allows you to switch off refreshing as result of focus change |
Note: please use the abstraction layer GUI.userView if possible! (see GUI)
JSCUserView
is a user-definable view intended mainly for use with JPen and drawHooks.
See also: JSCWindow, JPen, JSCTabletView.
Sets the function which should be evaluated if the view is refreshed. Note: A refresh happens if either of the following conditions meet:
refresh
on the view.refresh
on the window that contains the view.drawFunc_
on the viewrefreshOnFocus
is true
and the view gains or looses focus.
Example:
( var func; func = { arg me; JPen.use { // clipping into the boundingbox JPen.addRect( me.bounds.moveTo( 0, 0 )); JPen.clip; // draw background // (alternatively use addRect) JPen.fillColor = Color.gray( 0.5 ); JPen.moveTo( 0 @ 0 ); JPen.lineTo( me.bounds.width @ 0 ); JPen.lineTo( me.bounds.width @ me.bounds.height ); JPen.lineTo( 0 @ me.bounds.height ); JPen.lineTo( 0 @ 0 ); JPen.fill; 10.do { JPen.color = Color.red( rrand( 0.0, 1 ), rrand( 0.0, 0.5 )); JPen.addArc( 400.exprand( 2 ) @ 100.rand, rrand( 10, 100 ), 2pi.rand, pi ); JPen.perform([ \stroke, \fill ].choose ); } } }; w = JSCWindow.new( "DrawFunc Examples" ).front; w.view.background_( Color.white ); 3.do { arg i; v = JSCUserView( w, Rect( 20 + (i * 120), 100, 100, 100 )); v.drawFunc = func; }; ) v.refresh; // updates the last created (third) view w.refresh; // updates all user views in the window
// these only work in SwingOSC: v.refreshOnFocus = false; // do not re-evaluate drawFunc when focus is gained or lost (can be more efficient) v.focusVisible = false; // don't paint focus border. you can do yourself in the drawFunc, checking for me.hasFocus!
Sets the coordinate origin of JPen in the view's drawFunc
to be relative to the view's top left corner (when true
, which is the default) or to be relative to the window's top left corner (when false
).
( w = JSCWindow.new( "relativeOrigin = true" ); w.view.background_( Color.white ); 3.do { arg i; v = JSCUserView(w, Rect( 20 + (i * 120), 100, 100, 100 )) // this code not needed since it's the default // .relativeOrigin_( true ) .drawFunc_({ JPen.strokeRect( Rect( 0, 0, 100, 100 )); JPen.line( 0 @ 0, 100 @ 100 ); JPen.line( 100 @ 0, 0 @ 100 ); JPen.stroke; }); }; w.front; )
You can achieve a similar result with relativeOrigin
being false
, by translating the coordinate system at the beginning of the drawFunc
:
( w = JSCWindow.new( "relativeOrigin = false" ); w.view.background_( Color.white ); 3.do { arg i; v = JSCUserView(w, Rect( 20 + (i * 120), 100, 100, 100 )) .relativeOrigin_( false ) .drawFunc_({ arg view; var bounds; bounds = view.bounds; JPen.translate( bounds.left, bounds.top ); JPen.strokeRect( Rect( 0, 0, 100, 100 )); JPen.line( 0 @ 0, 100 @ 100 ); JPen.line( 100 @ 0, 0 @ 100 ); JPen.stroke; }) }; w.front; )
Sets the function which should be evaluated if the view is in focus and a key is pressed. This function will be passed four arguments: the view itself, the key pressed as a Char, the modifier keys Integer (shift, alt, etc.), and the unicode value Integer. See JSCView for more details.
( // select the window, type something and watch the post window w = JSCWindow.new( "select this window and type something" ); c = JSCUserView( w, w.view.bounds ); c.keyDownAction = { arg view, char, modifiers, unicode, keycode; [char, modifiers, unicode, keycode].postln; c.drawFunc = { JPen.font = JFont( "Helvetica", 70 ); JPen.fillColor = Color.blue( 0.3, 0.5 ); JPen.stringAtPoint( char.asString, 180 @ 150 ); }; }; w.front; c.focus; )
Sets the function which should be evaluated if the mouse is at the beginning of tracking (mouse-down). This function will be passed four arguments: theView, x coordinate, y coordinate, and keyboard modifiers.
Sets the function which should be evaluated if the mouse is tracked. This function will be passed four arguments: theView, x coordinate, y coordinate, and keyboard modifiers.
Sets the function which should be evaluated if the mouse is at the end of tracking (mouse-up). This function will be passed four arguments: theView, x coordinate, y coordinate, and keyboard modifiers.
Example:
( var drawFunc, beginTrackFunc, endTrackFunc, trackFunc, sat = 0, absX; drawFunc = { arg me; JPen.use { // clipping into the boundingbox JPen.addRect( me.bounds.moveTo( 0, 0 )); JPen.clip; // draw background JPen.fillColor = Color.gray( sat ); JPen.addRect( me.bounds.moveTo( 0, 0 )); JPen.fill; 10.do { JPen.color = Color.red( rrand( 0.0, 1 ), rrand( 0.0, 0.5 )); JPen.addArc( 400.exprand( 2 ) @ 100.rand, rrand( 10, 100 ), 2pi.rand, pi ); JPen.perform([ \stroke, \fill ].choose ); } } }; beginTrackFunc = { arg me, x, y, mod; absX = x; postf( "begin path: x=%\n", absX ); }; endTrackFunc = { arg me, x, y, mod; postf( "end path: (absX-x)=%\n", (absX - x)); }; trackFunc = { arg me, x, y, mod; sat = (absX - x) / 100; me.refresh; }; w = JSCWindow.new.front; w.view.background_(Color.white); 3.do { arg i; v = JSCUserView( w, Rect( 20 + (i * 120), 100, 100, 100 )); v.drawFunc = drawFunc; v.mouseDownAction = beginTrackFunc; v.mouseUpAction = endTrackFunc; v.mouseMoveAction = trackFunc; }; ) // draw on the view // NOTE: in swing, do not rely on correct painting // when components overlap. components should never overlap. // therefore, in this example, we use the drawFunc of the user view // and not the window to paint (see SCUserView help for comparison) // NOTE: after some drawing, the number of OSC packets sent // during each refresh increases which results in more sluggish // updates ( var w, txt, tmppoints, all; tmppoints = []; w = JSCWindow( "draw on me", Rect( 128, 64, 340, 360 )); v = JSCUserView( w, Rect( 0, 0, 340, 360 )) .canFocus_( false ) .mouseMoveAction_({ arg view,x,y; tmppoints = tmppoints.add( x @ y ); view.refresh; }) .mouseUpAction_({ arg view, x, y; all = all.add( tmppoints.copy ); tmppoints = []; view.refresh; }) .drawFunc_({ JPen.use { JPen.width = 1; JPen.beginPath; tmppoints.do { arg p, i; if( i == 0, { JPen.moveTo( p ); }, { JPen.lineTo( p ); }); }; all.do{ arg points; points.do { arg p, i; if( i == 0, { JPen.moveTo( p ); }, { JPen.lineTo( p ); }); }; }; JPen.stroke; }; }); w.front; )
Set the behaviour for refreshing the view. If this flag is true
(the default) the view will be cleared before each refresh call, otherwise It will draw in top of it. In the following example we utilize the GUI
factory pattern (described in the GUI help file), so you can easily use it with CocoaGUI as well.
Example:
( var width = 640, height = 480, w, theta = 0, drawFunc, gui; gui = GUI.get( \swing ); w = gui.window.new( "clearOnRefresh = true", Rect( 128, 64, width, height ), false ); drawFunc = { arg view; var x = 20 * sin( theta ), y = 42 * cos( theta ); gui.pen.addRect( view.bounds.moveTo( 0, 0 )); gui.pen.clip; theta = theta + 0.01; gui.pen.fillColor_( Color.red( 0.2, 0.1 )); gui.pen.fillRect( Rect( 0, 0, width, height )); gui.pen.strokeColor_( Color.white ); gui.pen.translate( width * 0.5, height * 0.5 ); 6.do { arg i; gui.pen.rotate( theta * (1 - (i / 6)) ); gui.pen.scale( 0.7 + (i * 0.4), 0.4 + (i * 0.5) ); gui.pen.strokeOval( Rect.aboutPoint( Point( x, y ), 60, 40 )); }; }; x = gui.userView.new( w, Rect( 10, 10, width - 20, height - 20 )) .canFocus_( false ) .drawFunc_( drawFunc ) .clearOnRefresh_( false ); w.front; Routine({ while({ x.isClosed.not }, { x.refresh; (1/25).wait })}).play( AppClock ); )
To "freeze" a drawing, that is, to prevent it to be re-drawn, use either .canFocus_( false )
or .refreshOnFocus_( false )
:
( var func, views; func = { 10.do { JPen.color = Color.red( rrand(0.0, 1), rrand( 0.0, 0.5 )); JPen.addArc( 400.exprand( 2 ) @ 100.rand, rrand( 10, 100 ), 2pi.rand, pi ); JPen.perform([ \stroke, \fill ].choose ); }; }; w = JSCWindow.new( "Frozen drawing" ); w.view.background_( Color.white ); views = { arg i; v = JSCUserView( w, Rect( 20 + (i * 120), 100, 100, 100 )) .refreshOnFocus_( false ) .drawFunc_( func ); } ! 3; w.front; )