SwingOSC – Java-based GUI classes

This class is meant as an emulation of SCView. last mod: 17-jul-09 sciss

different behaviour
threadingmethods needn't be called in the app thread ; however all actions performed from OSCresponders are deferred to the app thread for compatibility with cocoa GUI
boundsfor some gadgets the actual bounds are bigger than specified because in Swing, the focus decoration needs to be painted inside the gadget's bounds. generally you shouldn't recognize a difference. however, for gadgets that are part of the standard look-and-feel, no addtional insets are used at the moment, as example the JSCPopUpMenu on Mac OS X (Aqua look-and-feel) is actually smaller than with cocoa GUI because the focus border is not accounted for. I'll try to fix this some day.
fontthe default font is not Helvetica 12, but depends on the platform. On Mac OS X for example, the default font is Lucida Grande 11.
mouseOverActionon Mac OS X mouse-over can only be tracked when the window is activated.
hasFocuscomponents report to be unfocussed when their window is not the active window
extended functionality
id methodreturns the nodeID for the component.
mouseOverActionkey-modifer argument is passed
known issues / todo
findByIDnot yet implemented
focusColor_not implemented (will not be implemented)
id_not implemented (will not be implemented)

 

JSCView

Note: please use the abstraction layer View if possible!

JSCView is the abstract superclass for all SC GUI widgets, using a SwingOSC java server. Several key methods and variables are defined in JSCView and inherited in its subclasses. For a list of subclasses, refer to the CocoaVsJava help document.

Instance methods : resize_

	aView.resize_( <resize> )
	

This Integer setting controls how the widget will behave when it's window or enclosing view is resized. This is illustrated graphically below:

123
456
789

 

(
	w = JSCWindow( "Resize", Rect( 40, 40, 300, 330 ));
	JSCPopUpMenu( w, Rect( 3, 3, 270, 26 ))
		.items_([	"1 - fixed to left, fixed to top",
				"2 - horizontally elastic, fixed to top",
				"3 - fixed to right, fixed to top",
				
				"4 - fixed to left, vertically elastic",
				"5 - horizontally elastic, vertically elastic",
				"6 - fixed to right, vertically elastic",
				
				"7 - fixed to left, fixed to bottom",
				"8 - horizontally elastic, fixed to bottom",
				"9 - fixed to right, fixed to bottom" ])
		.action_({ arg b;
			x.resize = b.value + 1;
		});
	c = JSCCompositeView( w, w.view.bounds.insetAll( 0, 30, 0, 0 ))
		.background_( Color.yellow )
		.resize_( 5 );
	x = JSCStaticText( c, Rect( 100, 100, 100, 100 ))
		.string_( "Resize" )
		.background_( Color.red );
	w.front;
)

// additionally constrain the minimum and maximum dimensions
x.setProperty( \minWidth, 20 );
x.setProperty( \maxWidth, 200 );
x.setProperty( \minHeight, 10 );
x.setProperty( \maxHeight, 150 );

Instance methods : resize

Returns an Integer corresponding to the current resize behaviour (see above).

Instance methods : keyDownAction_

	aView.keyDownAction_( <val> )
	

Registers a Function to be evaluated when a keystroke is received and this view is in focus.

// select the slider, type something and watch the post window
(
	w = JSCWindow.new;
	c = JSCSlider( w, Rect( 0, 0, 100, 30 ));
	c.keyDownAction = { arg view,char,modifiers,unicode,keycode;
		[ char, modifiers, unicode, keycode ].postln;
	};
	w.front;
)

// use the following on Mac OS X to find out about the different codes returned
// from cocoa and java:
(
	w = JSCWindow( "j", Rect( 400, 500, 120, 80 ));
	c = JSCButton( w, Rect( 10, 10, 90, 30 ));
	c.states = [[ "Hit any Key" ]];
	c.keyDownAction = { arg view,char,modifiers,unicode,keycode;
		[ "j ", modifiers, unicode, keycode ].postln;
	};
	w.front;
	c.focus;

	w = SCWindow( "c", Rect( 540, 500, 120, 80 ));
	c = SCButton( w, Rect( 10, 10, 90, 30 ));
	c.states = [[ "Hit any Key" ]];
	c.keyDownAction = { arg view,char,modifiers,unicode,keycode;
		[ "c ", modifiers, unicode, keycode ].postln;
	};
	w.front;
	c.focus;
)

If you return nil from your function, or you have no function registered, the event will bubble up to the parent view which may then respond. It will continue to bubble up unless something responds or it hits the topView of the window. You may register a function in the window's topView to respond to all unhandled events for the window.

There are default keyDownActions for some views, which will be overridden when you set a keydown action.

When called, the function will be passed the following arguments:

 

Note: Function key modifier may change the keycode.

Note: The virtual java key codes are not translated into actual hardware key codes, thus the codes received through Cocoa GUI are different from those received through SwingOSC. For example, pressing '#' reports keycode 92 using SwingOSC or keycode 42 using Cocoa. Since java virtual codes are layout independant, there is no unique way to map them to Cocoa keycodes which are layout dependant (e.g. the 'Y' key will have different Cocoa keycodes on a QWERTZ and a QWERTY keyboard, while java will always attribute the value 89 to it). That's why an attempt to map values has not been made !!!

Note: tab, shift tab, ctrl tab are consumed by swing's default focus traversal handler.

Instance methods : keyDownAction

Returns the current keyDownAction Function for this view if there is one, otherwise return nil.

Class methods : *globalKeyDownAction_

	JSCView.globalKeyDownAction_( <val> )
	

A function that is evaluated for every keyDown event on every JSCView. See keyDownAction_ (above) for details.

Mouse Action Functions

Four functions can be assigned to track mouse events with a view. The methods to assign these functions are mouseDownAction_ (called when the mouse button is pressed over the view), mouseUpAction_ (called when the mouse button is released over the view), mouseMoveAction_ (called when the mouse button is kept pressed and the mouse is dragged over the view), and mouseOverAction_ (called when the mouse is moved over the view). Mouse tracking is enabled once one of these methods are called. Since you often don't need to track mouse movements without the button being pressed, using requires that you additionally call acceptsMouseOver_( true ) on the window that contains the view to make it actually work (not accepting mouse over events saves CPU power and OSC traffic).

All these functions are called with four arguments (the view, mouseX, mouseY, key-modifiers), where the mouse coordinates are relative to the top left corner of the view.

Example:

// use the 'mouse pad' to telepathically control the 2D slider on the right
(
    w = JSCWindow( "Mouse Actions", Rect( 200, 400, 350, 180 ), resizable: false );
    a = JSCStaticText( w, Rect( 10, 10, 160, 160 ))
        .string_( "Mouse Pad" )
        .stringColor_( Color.white )
        .align_( \center )
        .background_( Color.blue );
    b = JSCSlider2D( w, Rect( 180, 10, 160, 160 ))
        .canFocus_( false );
    f = { arg view, x, y, modif; var bounds = view.bounds;
        b.setXY( x / bounds.width, 1.0 - (y / bounds.height) );
    };
    a.mouseMoveAction = f;
    a.mouseDownAction = { arg ... args; b.knobColor = Color.red; f.value( *args )};
    a.mouseUpAction = { arg ... args; b.knobColor = Color.clear; f.value( *args )};
    w.front;
)

// Now additionally enable mouse-over actions:

a.mouseOverAction = f;
w.acceptsMouseOver = true;  // otherwise mouseOverAction won't be called
	
// Mouse events are only fired if the component is enabled.

a.enabled = false;
a.enabled = true;

Sometimes you just want to display a hint about the functionality of a view that pops up when the mouse is moved over the view. You can achieve this by setting a tool-tip string:

a.toolTip = "Press + move the mouse here";

Instance methods : focus

Brings the view into focus (it will receive keyboard events).

(
	w = JSCWindow.new;
	c = JSCSlider( w, Rect( 0, 0, 100, 30 ));
	d = JSCSlider( w, Rect( 0, 30, 100, 30 ));
	w.front;
)

c.focus;
d.focus;

You can switch of the ability of a view to get focussed. This you will want to do, if that view should not be controllable via keyboard or if you do not wish to see the focus border painted. To switch on / off focusability, call canFocus_( <(Boolean) onOff> ) . To check whether a view has focus, call hasFocus (it returns true or false).

c.focus;
c.hasFocus;	// --> true
c.canFocus_( false );	// cannot be focused anymore. as a side-effect, the gadget looses focus
c.hasFocus;	// --> false

Drag and Drop

Each view subclass has a default object that it exports when dragged from. For sliders its the value of the slider, for lists it is the currently selected numeric index etc.

By setting the beginDragAction handler you can return a different object based on the context and your application.

Note that the default drag-starting gesture is Control+Click+Move, since Command+Click+Move (as used with Cocoa GUIs) causes problems with some components, and besides the Command key is not available on PC keyboards.

aView.beginDragAction_( <func> ) – assigns a function that should return the object you wish your view to export by dragging. Example: aView.beginDragAction = { arg theView; someList[ theView.value ]}

The current dragged thing can be found in the classvar JSCView.currentDrag. Objects dragged from within SuperCollider are also in JSCView.currentDragString as a compile string. Text dragged from other applications is in JSCView.currentDragString and the results of attempting to compile that as sc code is in JSCView.currentDrag.

Each view subclass has a defaultCanReceiveDrag method that determines if the current object being dragged is possible for this view to accept, and a defaultReceiveDrag method for actually receiving the drag. Sliders accept numbers, simple text labels do not accept drags etc. After receiving the drag, the JSCView.currentDrag is set to nil.

By setting the canReceiveDragHandler and receiveDragHandler you can make any view accept and receive objects based on the context and your application. (Note: currently not possible for JSCStaticText (?)).

aView.canReceiveDrag_( <func> ) – assigns a function that should return true/false if you are willing to accept the current drag. (Example: aView.canReceiveDrag = false; // no, leave me alone ; Example: aView.canReceiveDrag = { JSCView.currentDrag.isString }; // ok if it's a string)

aView.receiveDrag_( <func> ) – assigns a function that gets called when drag should be accepted. Example: aView.receiveDrag = { JSCView.currentDrag.postln }

For example, the default drag object from a list view is the currently selected integer index. Here a list view is made to export a string:

// ctrl+press+move initiates the drag from the list view
(
    f = JSCWindow.new;
    a = JSCListView( f, Rect( 10, 10, 100, 120 ));
    a.items = [ "alpha", "beta", "gamma"];
    a.beginDragAction = { arg listView;
        listView.items[ listView.value ].debug( "begun dragging" );
    };
    
    c = nil;
    b = JSCButton( f, Rect( 10, 160, 100, 24 ));
    b.states = [[ "Drop stuff on me" ]];
    b.canReceiveDragHandler = { JSCView.currentDrag.isString };
    b.receiveDragHandler = { 
        b.states = [[ JSCView.currentDrag ]];
        c = JSCView.currentDrag;
    };
    b.action = { c.postln };
    f.front;
)