This class is meant as an emulation of SCView. last mod: 18-Jan-08 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 |
keyModifiersChangedAction_ | not yet implemented |
focusColor_ | not implemented (will not be implemented) |
id_ | not implemented (will not be implemented) |
Note: please use the abstraction layer GUI.view if possible! (see GUI)
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.
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 );
Returns an Integer corresponding to the current resize behaviour (see above).
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. &
).
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.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.
Returns the current keyDownAction Function for this view if there is one, otherwise return nil
.
JSCView.globalKeyDownAction_( <val> )
A function that is evaluated for every keyDown event on every JSCView
. See keyDownAction_ (above) for details.
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 global to the top view, not local to the child 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.left) / bounds.width, 1.0 - ((y - bounds.top) / 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;
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
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; )