## SwingOSC – Java-based GUI classes

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

different behaviour
threading | methods 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
bounds | for 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.
font | the default font is not Helvetica 12, but depends on the platform. On Mac OS X for example, the default font is Lucida Grande 11.
mouseOverAction | on Mac OS X mouse-over can only be tracked when the window is activated.
hasFocus | components report to be unfocussed when their window is not the active window
extended functionality
id method | returns the nodeID for the component.
mouseOverAction | key-modifer argument is passed
known issues / todo
findByID | not 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:

1 | 2 | 3
4 | 5 | 6
7 | 8 | 9

    (
    	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:

- `view` – The receiving instance of `JSCView`.
- `char` – The character pressed, possibly unprintable.
- modifiers – An Integer bit field indicating the modifier keys in effect. You can examine individual flag settings using the bitwise AND operator (`&`).
  - `65536` (`NSAlphaShiftKeyMask`) – Set if Caps Lock key is pressed.
  - `131072` (`NSShiftKeyMask`) – Set if Shift key is pressed.
  - `262144` (`NSControlKeyMask`) – Set if Control key is pressed.
  - `524288` (`NSAlternateKeyMask`) – Set if Option or Alternate key is pressed.
  - `1048576` (`NSCommandKeyMask`) – Set if Command key is pressed.
  - `2097152` (`NSNumericPadKeyMask`) – Set if any key in the numeric keypad is pressed. The numeric keypad is generally on the right side of the keyboard. Note: Not working in SwingOSC.
  - `4194304` (`NSHelpKeyMask`) – Set if the Help key is pressed. Note: Not working in SwingOSC.
  - `8388608` (`NSFunctionKeyMask`) – Set if any function key is pressed. The function keys include the F keys at the top of most keyboards (F1, F2, and so on) and the navigation keys in the center of most keyboards (Help, Forward Delete, Home, End, Page Up, Page Down, and the arrow keys). Note: Not working in SwingOSC.
  - arrow keys have an extra modifier value of `10485760`, so for a shift arrow key do a bitwise 'or' with the shift mask: `10485760 | 131072 = 10616832`. Note: Not working in SwingOSC.
- `unicode` – The unicode integer, identical to the char.
- `keycode` – The hardware dependent keycode indicating the physical key. This will vary from machine to machine, but is useful for building musical interfaces using the computer keyboard. In order to play little melodies, this code will identify which key you consider to be special.

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 = JSC2DSlider( 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;
    )