## SwingGUI – Java-based GUI classes

last mod: 17-Jan-08 sciss

# Collapse

The `Collapse` class is useful for deferring actions to a certain clock or scheduling them while reducing system load to a minimum. The `Collapse` constructor takes a function to be deferred, a delta time span and a clock to defer to:

        Collapse.new( <(Function) func>, <(Number) delta = 0.0>, <(Clock) clock = AppClock> )

## defer

An action is deferred by calling the `defer` method with arbitrary arguments. The function's `value` method is called with these arguments after the scheduled delay. When `defer` is called before the function was executed, the function is deferred again by the schedule delay and the pending call is cancelled. The new arguments overwrite the previous (pending) arguments. An example for the usage of `defer` is to allow a MIDI controller dial to be turned until the target position has been found, so that an action is executed only after the dial has been released for a given amount of time (e.g. 100ms).

In the following example, a ring is drawn around the mouse position if the mousebutton is hold down and the mouse dragged over the userview. A new ring is only drawn if the mouse is hold still for 500 milliseconds:

    (
        var ring;
        c = Collapse({ arg x, y; ring = x @ y }, 0.5 );
        w = JSCWindow( "Drag the mouse and hold...", resizable: false ).front;
        f = { arg view, x, y; c.defer( x, y )};
        u = JSCUserView( w, w.view.bounds )
            .focusVisible_( false )
            .refreshOnFocus_( false )
            .clearOnRefresh_( false )
            .background_( Color.blue( alpha: 0.05 ))
            .mouseDownAction_( f )
            .mouseMoveAction_( f )
            .drawFunc_({ if( ring.notNil, {
    			JPen.width = 20;
    			JPen.strokeOval( Rect.aboutPoint( ring, 100, 100 ));
    			ring = nil;
    		})});
        fork { while({ u.notClosed }, { u.refresh; 0.02.wait })};
    )

## instantaneous

On the contrary, the `instantaneous` method schedules the function, but will not re-schedule the execution when called successively (just the arguments get replaced). An example usage of `instantaneous` is to filter out the amount of actions executed per time unit, so as to save processing power. Imagine a custom JSCUserView consisting of several hundred objects all of which can be configured (e.g. in size and colour). If each configuration call will refresh the view, a heavy OSC load will result. Wrapping `refresh` inside a function and executing that using `instananeous`, all the necessary refreshes will collapse into a single final refresh.

The following example modifies the initial example to use `instantaneos` instead of `defer`. Note how new rings are created at a regular interval of 500 milliseconds, while the mouse is being dragged:

    (
        w.name = "Keep the mouse dragging...";
        f = { arg view, x, y; c.instantaneous( x, y )};
        u.mouseDownAction_( f ).mouseMoveAction_( f );
    )

## cancel and reschedule

Sometimes a condition occurs that makes it necessary to cancel an already scheduled action. This can be done by calling the `cancel` method. After cancellation, the `Collapse` will not respond to `defer` or `instantaneous` any more, unless `reschedule` is called which "revives" the object.

The following example again modifies the initial example. Releasing the mouse button will call `cancel` so no ring is created after the button is released. Inversely, when pressing the button `reschedule` is called to revive the process:

    (
        w.name = "Release mouse to cancel...";
        u.mouseDownAction = { c.reschedule };
        u.mouseMoveAction = { arg view, x, y; c.defer( x, y )};
        u.mouseUpAction = { c.cancel; "Cancel!".postln };
    )