## SwingOSC – Java-based GUI classes

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

no-op / not working
alpha | only working on mac os x
alwaysOnTop | requires java 1.5+
different behaviour
endFullScreen | window bounds are restored to previous state
threading | methods needn't be called in the app thread
extended functionality
unminimize | restores an iconified window to normal state
visible method | hides / shows the window
known issues / todo
screenBounds | on multi-display systems, this returns the bounds of the main screen (cocoa GUI reports the bounds of the screen containing the window that was most recently focused). screenBounds and vertical positioning is only correct when the SwingOSC class is initialized after the server was booted. otherwise call SwingOSC.retrieveScreenBounds !
findByID | not yet implemented

# JSCWindow

Note: please use the abstraction layer Window if possible!

A class representing a user interface window. See also JSCView to learn about the gadgets that can populate a window.

## Instantiation

    	JSCWindow.new( <name>, <bounds>, <resizable>, <border>, <server>, <scroll> )

Creates a new `JSCWindow` instance. You will need to call `front` (see below) on it before it will be visible.

- `name` – the name that will be displayed in the title bar. An instance of String or Symbol. The default is `"panel"`.
- `bounds` – a Rect specifying the location and size of the window. The size does not include the title bar. Note: Location is measured from the bottom left of the screen. This is different from view location, which is measured from the upper left of the window (not including the title bar). The default is `Rect( 128, 64, 400, 400 )`.
- `resizable` – a Boolean indicating whether this window can be resized by the user. The default is `true`. Use `resizable_` to change this behaviour after the window has been created.
- `border` – a Boolean indicating whether this window has a border. Borderless windows have no title bar and thus can only be closed in code. The default is `true`.
- `server` – use this argument to specify the SwingOSC server to use (if `nil`, the default server will be used).

Examples:

        w = JSCWindow.new;
        w.front; // draw it and bring it to the front

    // how to add views
    (
        w = JSCWindow( "my name is... panel", Rect( 128, 64, 340, 360 ));
        32.do({ arg i;
            b = JSCButton( w, Rect( rrand( 20, 300 ), rrand( 20, 300 ), 75, 24 ));
            b.states = [[ "Start " ++ i, Color.black, Color.rand ],
                        [ "Stop "  ++ i, Color.white, Color.red ]];
        });
        w.front;
    )

        // a window without border decoration
        JSCWindow.new( border: false ).front; // can't be closed, as it has no buttons, but cmd-w works!
        JSCWindow.closeAll;

## Accessing all open windows

To return an Array of all open `JSCWindow`s:

        JSCWindow.allWindows

To close all all open `JSCWindow`s:

        JSCWindow.closeAll

To register a function that gets called every time a window is opened:

        JSCWindow.initAction = { arg win; "Opened '%'!\n".postf( win.name )};
        JSCWindow( "Huhu" ).front;

## Determining the screen bounds

        JSCWindow.screenBounds

Returns a Rect indicating the bounds of the current main screen (i.e. monitor resolution).

Example:

        JSCWindow.new( "Centered", Rect.aboutPoint( JSCWindow.screenBounds.center, 160, 80 )).front;

## Class method: viewPalette

        JSCWindow.viewPalette

Opens a window with a selection of different kind of gadgets. Eventually will be coupled with a WYSIWYG GUI-Editor.

## Opening and closing, showing and hiding a window

The instantiation of a window does create the window, but the window needs to be made visible explictly, by calling the `front` method. The window can hidden temporarily by calling the `visible` method which takes a Boolean argument (`false` to hide the window, `true` to show the window). Eventually the window can be closed and destroyed by calling the `close` method:

        w = JSCWindow.new;
        w.front;
        w.visible = false;
        w.visible = true;
        w.close;

Note: GUI-building performance is better if front is called after the window has been populated with gadgets!

To determine when a window is closed, you can assign a Function using the `onClose_` setter method. The function gets executed when the window closes. In the following example, a synth is released when the window is closed:

    (
    s.waitForBoot({
    	w = JSCWindow.new;
    	x = Synth( \default, [ \amp, 0.1 ]);
    	JSCSlider( w, w.view.bounds.insetBy( 10, 10 )).value_( 0.322 ).action_({ arg b;
    		x.set( \freq, b.value.linexp( 0, 1, 100, 10000 ));
    	});
    	w.onClose = { x.release };
    	w.front;
    });
    )

Alternatively, you can call `isClosed` anytime to query whether the window is still open:

    (
        w = JSCWindow.new.front;
        fork { while({ w.isClosed.not }, { w.view.background = Color.rand; 0.2.wait }); "Done.".postln };
    )

Sometimes you will want to prevent the user (or yourself) from accidentally closing a window. Using the `userCanClose_` setter method with a `false` value prevents the window from closing when clicking on its close gadget:

    (
    	w = JSCWindow.new.userCanClose_( false );
    	JSCButton( w, Rect.aboutPoint( w.view.bounds.center, 160, 30 ))
    		.states_([[ "Need to click here to close" ]])
    		.action_({ w.close });
    	w.front;
    )

Further notifications include a window becoming active (being brought to the front) or inactive (focus is transferred to another window):

        w.toFrontAction = { arg win; "Activated '%'!\n".postf( win.name )};
        w.endFrontAction = { arg win; "Deactivated '%'!\n".postf( win.name )};

## Customizing the window look

`name` and `name_` are getter and setter methods for the window's title. The value should be a String or Symbol. Example:

    (
        var win, rout;
        win = JSCWindow( "", Rect( 200, 200, 160, 12 )).front;
        rout = fork { inf.do({ win.name = Date.getDate.format( "%T" ); 1.wait })};
        win.onClose = { rout.stop };
        w = win;
    )

`resizable` and `resizable_` are getter and setter methods for making the window resizable by the user (SwingOSC only). The value is a Boolean. Note that regardless of its setting, the window can always be programmtically resized with the `bounds_` method. Example:

        w.resizable = false;

`alwaysOnTop` and `alwaysOnTop_` are getter and setter methods for making the window float above all other windows (requires Java 1.5+). The value is a Boolean. Example:

        x = JSCWindow( "I'm always below" ).front;
        w.alwaysOnTop = true;

`alpha` and `alpha_` are getter and setter methods for the window's alpha transparency. This currently only works on Mac OS X. The value is a Float between `0.0` (fully transparent) and `1.0` (fully opaque). Example:

        w.alpha = 0.5;
        w.view.background = Color.red;
        x.view.background = Color.blue;

## Resizing a window

A window can be resized any time by calling the `bounds_` method with a Rect argument. See the note in the instantiation section about the vertical coordinate orientation. A getter method `bounds` is provided to read the current window's bounds (this is not to be confused with the window's topview bounds, accessed using `aWindow.view.bounds`!). Example:

    (
    	// difficult to catch (;-) try Cmd+W to close the window
    	w = JSCWindow.new( "test" ).front;
    	w.view.background = Color.red;
    	fork { var b = JSCWindow.screenBounds;
    		while({ w.isClosed.not }, {
    			w.bounds_( Rect( (b.width - 50).rand, (b.height - 50).rand, 50, 50 ));
    			1.wait;
    		});
    	};
    )

Sometimes it is more convenient to use the `setInnerExtent` method for resizing, which takes two Number arguments for the content pane's width and height:

    (
    	w = JSCWindow.new;
    	w.drawHook = { arg win;
    		var b = win.view.bounds;
    		JPen.width = 6;
    		JPen.font = JFont( JFont.defaultSansFace, 32 ).boldVariant;
    		JPen.stringCenteredIn( "%, %".format( b.width, b.height ), b );
    		4.do({ arg i;
    			JPen.use({
    				JPen.translate( b.width / 2, b.height / 2 );
    				JPen.scale( (i & 1) * -2 + 1, i.div( 2 ) * -2 + 1 );
    				JPen.translate( b.width / -2, b.height / -2 );
    				JPen.line( 3 @ 40, 3 @ 3 );
    				JPen.lineTo( 40 @ 3 );
    				JPen.line( 3 @ 3, 80 @ 80 );
    				JPen.stroke;
    			});
    		});
    	};
    	w.front;
    )
    w.setInnerExtent( 333, 222 );

Finally, to save screen space, you may want to temporarily minimize (or "iconify") irrelevant windows. When a window is minimized, it is hidden, but an icon representation is shown in the Dock (Mac OS X) or a button appears in the task bar (Windows). You can programmatically `minimize` and `unminimize` a window:

    (
        w = JSCWindow.new.front;
        AppClock.sched( 1, { w.minimize });
        AppClock.sched( 3, { w.unminimize });
    )

## Using fullscreen mode

For performance situations or video projections you can bring a window into fullscreen display, using the `fullScreen` method. To return to normal display, call `endFullScreen`. To hide the windows title bar, see the `border` argument in the instantiation. To determine the screen bounds, look for the paragraph "Determining the screen bounds" above. Example:

    (
        w = JSCWindow( border: true ); // try border: false!
        w.view.background = Color.yellow;
        w.front;
        w.fullScreen;
        AppClock.sched( 2, { w.endFullScreen });
        AppClock.sched( 3, { w.close });
    )

## Customizing mouse behaviour

Using the getter and setter methods `acceptsMouseOver` and `acceptsMouseOver_`, you can determine whether mouse motion events (the mouse being moved without the button held pressed) are delivered to gadgets or not. See the paragraph "Mouse Action Functions" in the JSCView help file for more information.

## Adding a custom background graphic

You can add your own background graphic to a window by setting up a Function with `drawHook_`. See JPen for various examples of custom graphics.

## Accessing the top view, using a layout decorator

In the instantiation section example "how to add views" you have seen that the window can be passed in as the "parent" argument to the constructor of any gadget. This is because the gadget will determine its parent view by calling `asView` on the parent-argument. Both the field `view` and the method `asView` return a window's `JSCTopView` (when a scroll is used, this points to a JSCScrollTopView.

You will want to access the top view explictly in order to set its background colour or the layout decorator (see also JSCCompositeView for more info on decorators):

    // Set the decorator and background colour of the view
    (
        w = JSCWindow( "my name is... nepal", Rect( 128, 64, 340, 260 ));
        w.view.decorator = FlowLayout( w.view.bounds );
        w.view.background = Color( 0.6, 0.8, 0.8 );
        32.do({ arg i;
            b = JSCButton( w, Rect( rrand( 20, 300 ), rrand( 20, 300 ), 75, 24 ));
            b.states = [[ "Start " ++ i, Color.black, Color.rand ],
                        [ "Stop "  ++ i, Color.white, Color.red ]];
        });
        w.front;
    )

### keyboard shortcuts

`Meta+W` | closes window
`Meta+M` | minimizes window

...where `Meta` corresponds to the `Command`-key (Mac OS X) or `Control`-key (Linux and Windows)