SwingOSC – Java-based GUI classes

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
refreshsee the introductory paragraph for SwingOSC's refresh policy
view boundshere 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

 

JSCUserView

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.

drawFunc_

Sets the function which should be evaluated if the view is refreshed. Note: A refresh happens if either of the following conditions meet:


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

 

Focus Behaviour

// 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!

 

relativeOrigin_

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;
)

 

keyDownAction_

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;
)

 

mouseDownAction_

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.

mouseMoveAction_

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.

mouseUpAction_

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;
)

 

clearOnRefresh_

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 );
)

 

refreshOnFocus_ (SwingOSC only!)

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;
)