SuperCollider CLASSES

Pen

Draw custom graphics
Inherits from: Object
Subclasses: QPen

Description

A class which allows you to draw custom graphics on a UserView or Window.

The following methods must be called within a Window: -drawFunc or a UserView: -drawFunc function, and will only be visible once the window or the view is refreshed. Each call to Window: -refresh or UserView: -refresh will 'overwrite' all previous drawing by executing the currently defined function, unless UserView: -clearOnRefresh is set to false

Class Methods

Construct path

The following methods define paths. You will need to call *stroke or *fill to actually draw them.

*moveTo (point)

Move the Pen to point.

Arguments:

point

An instance of Point

*lineTo (point)

Draw a line (define a path) from the current position to point.

Arguments:

point

An instance of Point

*line (p1, p2)

Draw a line (define a path) from p1 to p2. Current position will be p2.

Arguments:

p1

An instance of Point

p2

An instance of Point

*curveTo (endPoint, cPoint1, cPoint2)

Draws a cubic bezier curve from the current position to point. cpoint1 and cpoint2 are control points determining the curve's curvature.

Arguments:

endPoint

An instance of Point

cPoint1

An instance of Point

cPoint2

An instance of Point

*quadCurveTo (endPoint, cPoint)

Draws a quad bezier curve from the current position to point. cpoint is a control point determining the curve's curvature.

Arguments:

endPoint

An instance of Point

cPoint

An instance of Point

*arcTo (point1, point2, radius)

Draws an arc of a circle using a radius and tangent points.

Arguments:

point1

The end point of the first tangent line. Its start point is the current position. An instance of Point

point2

The end point of the second tangent line. Its start point is point1. An instance of Point

radius

The radius of the arc.

Discussion:

example:

(
var w = Window("arcTo", Rect(100, 200, 300, 300)).front;
var r= 15;
w.drawFunc = { |v|
    Pen.fillColor = Color.blue;
    Pen.strokeColor = Color.red;
    Pen.moveTo(150@150);
    Pen.arcTo(200@150, 200@225, r);
    Pen.arcTo(200@225, 100@225, r);
    Pen.arcTo(100@225, 100@150, r);
    Pen.arcTo(100@150, 150@150, r);
    Pen.lineTo(150@150);
    Pen.fillStroke;
};
)

*addArc (center, radius, startAngle, arcAngle)

Draw an arc around the Point center, at radius number of pixels. startAngle and arcAngle refer to the starting angle and the extent of the arc, and are in radians [0..2pi].

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.translate(100, 100);
    10.do{
        // set the Color
        Pen.color = Color.red(rrand(0.0, 1), rrand(0.0, 0.5));
        Pen.addArc((100.rand)@(100.rand), rrand(10, 100), 2pi.rand, pi);
        Pen.perform([\stroke, \fill].choose);
    }
};
w.refresh;
)

*addWedge (center, radius, startAngle, sweepLength)

Draw a wedge around the Point center, at radius number of pixels. startAngle and sweepLength refer to the starting angle and the extent of the arc, and are in radians [0..2pi].

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.translate(100, 100);
    10.do{
        // set the Color
        Pen.color = Color.blue(rrand(0.0, 1), rrand(0.0, 0.5));
        Pen.addWedge((100.rand)@(100.rand), rrand(10, 100), 2pi.rand, 2pi.rand);
        Pen.perform([\stroke, \fill].choose);
    }
};
w.refresh;
)

*addAnnularWedge (center, innerRadius, outerRadius, startAngle, sweepLength)

Draw an annular wedge around the Point center, from innerRadius to outerRadius in pixels. startAngle and sweepLength refer to the starting angle and the extent of the arc, and are in radians [0..2pi].

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.translate(100, 100);
    1000.do{
        // set the Color
        Pen.color = Color.green(rrand(0.0, 1), rrand(0.0, 0.5));
        Pen.addAnnularWedge(
            (100.rand)@(100.rand),
            rrand(10, 50),
            rrand(51, 100),
            2pi.rand,
            2pi.rand
        );
        Pen.perform([\stroke, \fill].choose);
    }
};
w.refresh;
)

*addRect (aRect)

Adds a Rect to the drawing.

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    80.do{
        // set the Color
        Pen.color = Color.green(rrand(0.0, 1), rrand(0.0, 0.5));
        Pen.addRect(
            Rect(20, 20, (w.bounds.width-40).rand, (w.bounds.height-40).rand)
        );
        Pen.perform([\stroke, \fill].choose);
    }
};
w.refresh;
)

*addOval (rect)

Adds an Oval shape that fits inside the Rect to the current path.

Draw the path

*stroke

Outline the previous defined path.

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    // set the Color
    Pen.strokeColor = Color.red;
    Pen.moveTo(200@100);

    Pen.lineTo(250@200);
    Pen.lineTo(300@200);
    Pen.lineTo(200@250);
    Pen.lineTo(100@200);
    Pen.lineTo(150@200);
    Pen.lineTo(200@100);

    Pen.stroke
};
w.refresh;
)

*fill

Fill the previous defined path.

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    // set the Color
    Pen.fillColor = Color.red;
    Pen.moveTo(200@100);

    Pen.lineTo(250@200);
    Pen.lineTo(300@200);
    Pen.lineTo(200@250);
    Pen.lineTo(100@200);
    Pen.lineTo(150@200);
    Pen.lineTo(200@100);

    Pen.fill
};
w.refresh;
)

*draw (style)

Draw the previous defined path using any of the following options:

Arguments:

style
0fill
1fill using even-odd rule
2stroke
3fill and stroke the current path
4fill and stroke using even-odd rule

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    // set the Color
    Pen.fillColor = Color.red;
    Pen.moveTo(200@100);

    Pen.lineTo(250@200);
    Pen.lineTo(300@200);
    Pen.lineTo(200@250);
    Pen.lineTo(100@200);
    Pen.lineTo(150@200);
    Pen.lineTo(200@100);

    Pen.draw(4); // fill and then stroke
};
w.refresh;
)

*fillStroke

Fill and stroke the current path. Shortcut to the draw(3) method.

Construct and draw

These methods do not require separate calls to *stroke or *fill.

*strokeRect (rect)

Strokes a Rect into the window.

*fillRect (rect)

Draws a filled Rect into the window.

*strokeOval (rect)

Strokes an oval into the window.

*fillOval (rect)

Draws a filled oval into the window.

Gradients

*fillAxialGradient (startPoint, endPoint, startColor, endColor)

Fills an Axial gradient.

Discussion:

example:

(
w = Window.new.front;
w.drawFunc = {
    // fill the gradient
    Pen.addRect(w.view.bounds.insetBy(30));
    Pen.fillAxialGradient(w.view.bounds.leftTop, w.view.bounds.rightBottom, Color.rand, Color.rand);
};
w.refresh;
)

*fillRadialGradient (innerCircleCenter, outerCircleCenter, startRadius, endRadius, startColor, endColor)

Fills a Radial gradient.

Discussion:

example:

(
w = Window.new.front;
w.drawFunc = {
    // fill the gradient
    Pen.addOval(w.view.bounds.insetBy(30));
    Pen.fillRadialGradient(w.view.bounds.center,
        w.view.bounds.center, 0, w.bounds.width, Color.rand, Color.rand);
};
w.refresh;
)

Graphics State Methods

The following commands transform the graphics state, i.e. they effect all subsequent drawing commands. These transformations are cumulative, i.e. each command applies to the previous graphics state, not the original one.

*translate (x: 0, y: 0)

Translate the coordinate system to have its origin moved by x,y

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.strokeColor = Color.blue;
    Pen.translate(200,100); // 0@0 is now 200@100
    Pen.moveTo(0@0);
    Pen.lineTo(50@100);
    Pen.lineTo(100@100);
    Pen.lineTo(0@150);
    Pen.lineTo(-100@100);
    Pen.lineTo(-50@100);
    Pen.lineTo(0@0);
    Pen.stroke
};
w.refresh;
)

Cumulative translations:

(
w = Window.new.front;
w.view.background_(Color.clear);
w.drawFunc = {
    Pen.strokeColor = Color.black;
    35.do { // draw 35 lines
        Pen.moveTo(0@0);
        Pen.lineTo(50@350);
        Pen.translate(10, 0); // shift 10 to the right every time
        Pen.stroke
    }
};
w.refresh;
)

*scale (x: 0, y: 0)

Scales subsequent drawing. x and y are scaling factors (i.e. 1 is normal, 2 is double size, etc.).

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.strokeColor = Color.green;
    Pen.translate(200,100);
    Pen.scale(0.5, 2);
    Pen.moveTo(0@0); // you have to set a starting point...
    Pen.lineTo(50@100);
    Pen.lineTo(100@100);
    Pen.lineTo(0@150);
    Pen.lineTo(-100@100);
    Pen.lineTo(-50@100);
    Pen.lineTo(0@0);
    Pen.stroke
};
w.refresh;
)

*skew (x: 0, y: 0)

Skews subsequent drawing. x and y are skewing factors (i.e. 1 is normal).

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    Pen.fillColor = Color.green(0.5, 0.8);
    Pen.translate(200,100);
    Pen.skew(0.5, 0.2);
    Pen.moveTo(0@0); // you have to set a starting point...
    Pen.lineTo(50@100);
    Pen.lineTo(100@100);
    Pen.lineTo(0@150);
    Pen.lineTo(-100@100);
    Pen.lineTo(-50@100);
    Pen.lineTo(0@0);
    Pen.fill
};
w.refresh;
)

*rotate (angle: 0, x: 0, y: 0)

Rotates subsequent drawing around the Point x@y by the amount angle in radians [0..2pi].

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
c = 0;
w.drawFunc = {
    Pen.translate(220, 200);
    10.do({
        Pen.translate(0,10);
        Pen.fillColor = Color.hsv(c.fold(0, 1), 1, 1, 0.5);
        Pen.moveTo(0@0); // you have to set a starting point...
        Pen.lineTo(50@100);
        Pen.lineTo(100@100);
        Pen.lineTo(0@150);
        Pen.lineTo(-100@100);
        Pen.lineTo(-50@100);
        Pen.lineTo(0@0);
        Pen.fill;
        Pen.rotate(0.2pi);
        c = c + 0.1;
    });
};
w.refresh;
)

*matrix

*matrix = matrixArray

Gets or sets the coordinate system transformation matrix.

See Matrix%20example for an example.

Arguments:

matrixArray

An array of the form [ zoomX, shearingY, shearingX, zoomY, translateX, translateY ]

*width = width

Sets the width of the Pen for the whole stroke

*use (aFunction)

Draw function, and then revert to the previous graphics state. This allows you to make complex transformations of the graphics state without having to explicitly revert to get back to 'normal'.

Discussion:

example:

(
// modified by an example of Stefan Wittwer
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    //paint origin
    Pen.fillColor = Color.gray(0, 0.5);
    Pen.addArc(0@0, 20, 0, 2pi);
    Pen.fill;
    Pen.width = 10;

    Pen.use { // draw something complex...
        Pen.width = 0.5;
        Pen.translate(100,100);
        Pen.fillColor = Color.blue;
        Pen.addArc(0@0, 10, 0, 2pi);
        Pen.fill;
        20.do{
            Pen.moveTo(0@0);
            Pen.lineTo(100@0);
            Pen.strokeColor = Color.red(0.8, rrand(0.7, 1));
            Pen.stroke;
            Pen.skew(0, 0.1);
        };
    };

    // now go on with all params as before
    // translation, skewing, width, and color modifications do not apply
    Pen.line(10@120, 300@120);
    Pen.stroke;
};
w.refresh
)

*path

Make a path, consisting of the drawing made in function.

NOTE: Unfortunately not working for now... (there's no Pen.endPath which currently is used in this method)

*beginPath

Discard any previous path.

*beginTransparencyLayer

Begins a new transparency layer. Transparency layers are useful when you want to apply an effect to a group of objects or create a composite graphic. See Transparency%20layer%20example.

*endTransparencyLayer

Ends the current transparency layer.

*clip

Use the previously defined path as a clipping path.

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
w.drawFunc = {
    // outline the clipping path
    Pen.moveTo(110@110);
    Pen.lineTo(290@110);
    Pen.lineTo(290@240);
    Pen.lineTo(110@240);
    Pen.lineTo(110@110);
    // now clip
    Pen.clip;

    // everything else we draw is now clipped
    Pen.fillColor = Color.yellow;
    Pen.fillRect(Rect(0,0,400,400));
    Pen.fillColor = Color.red;
    Pen.moveTo(200@100);

    Pen.lineTo(250@200);
    Pen.lineTo(300@200);
    Pen.lineTo(200@250);
    Pen.lineTo(100@200);
    Pen.lineTo(150@200);

    Pen.fill;
};
w.refresh;
)

*smoothing = flag

Turns on/off anti-aliasing.

Discussion:

example:

(
var w = Window("smoothing", Rect(100, 200, 500, 300)).front;
w.view.background_(Color.white);
w.drawFunc = { |v|
    Pen.strokeColor = Color.grey(0.25);
    Pen.smoothing_(false); //no anti-aliasing
    50.do{|i|
        Pen.moveTo(50@50.rrand(250));
        Pen.lineTo(250@50.rrand(250));
    };
    Pen.stroke;
    Pen.smoothing_(true); //anti-aliasing (default)
    50.do{|i|
        Pen.moveTo(250@50.rrand(250));
        Pen.lineTo(450@50.rrand(250));
    };
    Pen.stroke;
};
)

*setShadow (offsetPoint, blur, color)

Will fill the current path with a shadow. You should use this option between Pen.push / Pen.pop (or Pen.use)

*joinStyle = style

Set the lines joining style according to the defined options:
0miter
1round
2bevel

*capStyle = style

Set the lines joining style according to the defined options:
0butt
1round
2square

Discussion:

example:

(
w = Window.new.front;
w.view.background_(Color.white);
StaticText(w, Rect(0,0,180,20))
    .string_(" Change Line Cap & Join Styles: ");
y = PopUpMenu(w, Rect(180,0,130,20))
    .items_(["Butt - Miter", "Round - Round", "Square - Bevel"])
    .action_({w.refresh});
w.drawFunc = {
    Pen.strokeColor = Color.red;
    Pen.width_(8.0);
    Pen.capStyle_(y.value);
    Pen.joinStyle_(y.value);
    Pen.moveTo(200@100);
    Pen.lineTo(250@200);
    Pen.lineTo(300@200);
    Pen.lineTo(200@250);
    Pen.lineTo(100@200);
    Pen.lineTo(150@200);
    Pen.lineTo(200@100);
    Pen.stroke;
};
w.refresh;
)

*alpha = value

Set the opacity level.

*blendMode = mode

Set the blending mode to use. See Blending%20modes for more information.

*lineDash = pattern

Set the line dash pattern. pattern should be a FloatArray of values that specify the lengths of the painted segments and not painted segments.

*drawImage (target, image, source, operation: 'sourceOver', opacity: 1)

Draw a bitmap image using the Image class.

Discussion:

example:

w = Window.new.front;
w.view.background = Color.red;
i = Image.open(SCDoc.helpSourceDir +/+ "images/Swamp.png");
w.drawFunc_({
    Pen.drawImage( Point(140, 140), i, operation: 'sourceOver', opacity:1);
});

examples::
Simple rotating and scaling:
code::
(
    w = Window("Pen Rotation and Scaling", Rect(128, 64, 360, 360));
    w.drawFunc = {
        Pen.use {
            // use the same rect for everything, just scale and rotate
            var r = Rect(0,0,200,80);
            Pen.fillColor = Color.black;
            // offset all subsequent co-ordinates
            Pen.translate(80,20);
            Pen.fillRect(r);
            Pen.fillColor = Color.red;
            // scale all subsequent co-ordinates
            Pen.scale(0.8, 0.8);
            Pen.translate(8,10);
            // rotate all subsequent co-ordinates
            Pen.rotate(0.1pi);
            Pen.fillRect(r);
            Pen.strokeColor = Color.blue;
            // lather, rinse, repeat
            Pen.scale(0.8, 0.8);
            Pen.rotate(0.1pi);
            Pen.width = 3;
            Pen.strokeRect(r);
            Pen.fillColor = Color.yellow(1,0.5);
            Pen.scale(0.8, 0.8);
            Pen.rotate(0.1pi);
            Pen.translate(20,-20);
            Pen.fillOval(r);
        }
    };

    w.front;
)

Redraw at random interval, different every time:

(
var w, run = true;
w = Window("my name is... panel", Rect(128, 64, 800, 800));
w.view.background = Color.white;
w.onClose = { run = false; };
w.front;
w.drawFunc = {
    Pen.use {
        Pen.width = 0.2;
        400.do {
            Pen.beginPath;
            Pen.moveTo(Point(10.rand * 80 + 40, 10.rand * 80 + 40));
            Pen.lineTo(Point(10.rand * 80 + 40, 10.rand * 80 + 40));
            Pen.stroke;
        };
    };
};

{ while { run } { w.refresh; 1.0.rand.wait } }.fork(AppClock)

)

(
var w, run = true;
w = Window("my name is... panel", Rect(128, 64, 800, 500));
w.view.background = Color.white;
w.onClose = { run = false; };
w.front;
w.drawFunc = {
    Pen.use {
        Pen.width = 2;
        80.do {
            Pen.width = rrand(0,4) + 0.5;
            Pen.beginPath;
            Pen.moveTo(Point(800.rand, 500.rand));
            Pen.lineTo(Point(800.rand, 500.rand));
            Pen.stroke;
        };
    };
};

{ while { run } { w.refresh; 1.0.rand.wait } }.fork(AppClock)

)

Animation

Uses random seed to 'store' data By reseting the seed each time the same random values and shapes are generated for each 'frame' These can then be subjected to cumulative rotation, etc., by simply incrementing the phase var.

(
// By James McCartney
var w, h = 700, v = 700, seed, run = true, phase = 0;
w = Window("wedge", Rect(40, 40, h, v), false);
w.view.background = Color.rand(0,0.3);
w.onClose = { run = false }; // stop the thread on close
w.front;
// store an initial seed value for the random generator
seed = Date.seed;
w.drawFunc = {
    Pen.width = 2;
    Pen.use {
        // reset this thread's seed for a moment
        thisThread.randSeed = Date.seed;
        // now a slight chance of a new seed or background color
        if (0.006.coin) { seed = Date.seed; };
        if (0.02.coin) { w.view.background = Color.rand(0,0.3); };
        // either revert to the stored seed or set the new one
        thisThread.randSeed = seed;
        // the random values below will be the same each time if the seed has not changed
        // only the phase value has advanced
        Pen.translate(h/2, v/2);
        // rotate the whole image
        // negative random values rotate one direction, positive the other
        Pen.rotate(phase * 1.0.rand2);
        // scale the rotated y axis in a sine pattern
        Pen.scale(1, 0.3 * sin(phase * 1.0.rand2 + 2pi.rand) + 0.5 );
        // create a random number of annular wedges
        rrand(6,24).do {
            Pen.color = Color.rand(0.0,1.0).alpha_(rrand(0.1,0.7));
            Pen.beginPath;
            Pen.addAnnularWedge(Point(0,0), a = rrand(60,300), a + 50.rand2, 2pi.rand
                + (phase * 2.0.rand2), 2pi.rand);
            if (0.5.coin) {Pen.stroke}{Pen.fill};
        };
    };
};

// fork a thread to update 20 times a second, and advance the phase each time
{ while { run } { w.refresh; 0.05.wait; phase = phase + 0.01pi;} }.fork(AppClock)

)

(
var w, phase = 0, seed = Date.seed, run = true;
w = Window("my name is... panel", Rect(128, 64, 800, 800));
w.view.background = Color.blue(0.4);
w.onClose = { run = false; };
w.front;
w.drawFunc = {
    Pen.use {
        if (0.02.coin) { seed = Date.seed; };
        thisThread.randSeed = seed;
        Pen.strokeColor = Color.white;
        200.do {
            var a = 4.rand;
            var b = 24.rand;
            var r1 = 230 + (50 * a);
            var a1 = 2pi / 24 * b + phase;
            var r2 = 230 + (50 * (a + 1.rand2).fold(0,3));
            var a2 = 2pi / 24 * (b + (3.rand2)).wrap(0,23) + phase;
            Pen.width = 0.2 + 1.0.linrand;
            Pen.beginPath;
            Pen.moveTo(Polar(r1, a1).asPoint + Point(400,400));
            Pen.lineTo(Polar(r2, a2).asPoint + Point(400,400));
            Pen.stroke;
        };
        thisThread.randSeed = Date.seed;
        40.do {
            var a = 4.rand;
            var b = 24.rand;
            var r1 = 230 + (50 * a);
            var a1 = 2pi / 24 * b + phase;
            var r2 = 230 + (50 * (a + 1.rand2).fold(0,3));
            var a2 = 2pi / 24 * (b + (3.rand2)).wrap(0,23) + phase;
            Pen.width = 0.2 + 1.5.linrand;
            Pen.beginPath;
            Pen.moveTo(Polar(r1, a1).asPoint + Point(400,400));
            Pen.lineTo(Polar(r2, a2).asPoint + Point(400,400));
            Pen.stroke;
        };
    };
};

{ while { run } { w.refresh; 0.1.wait; phase = phase + (2pi/(20*24)) } }.fork(AppClock)

)
(
var w, h = 800, v = 600, seed = Date.seed, phase = 0, zoom = 0.7, zoomf = 1, run = true;
w = Window("affines", Rect(40, 40, h, v));
w.view.background = Color.blue(0.4);
w.onClose = { run = false };
w.front;
w.drawFunc = {
    thisThread.randSeed = Date.seed;
    if (0.0125.coin) { seed = Date.seed; phase = 0; zoom = 0.7; zoomf = exprand(1/1.01, 1.01); }
    { phase = phase + (2pi/80); zoom = zoom * zoomf; };
    thisThread.randSeed = seed;
    Pen.use {
        var p1 = Point(20.rand2 + (h/2), 20.rand2 + (v/2));
        var p2 = Point(20.rand2 + (h/2), 20.rand2 + (v/2));
        var xscales = { exprand(2** -0.1, 2**0.1) } ! 2;
        var yscales = { exprand(2** -0.1, 2**0.1) } ! 2;
        var xlates = { 8.rand2 } ! 2;
        var ylates = { 8.rand2 } ! 2;
        var rots = { 2pi.rand + phase } ! 2;
        var xform;
        xscales = (xscales ++ (1/xscales)) * 1;
        yscales = (yscales ++ (1/yscales)) * 1;
        xlates = xlates ++ xlates.neg;
        ylates = ylates ++ xlates.neg;
        rots = rots ++ rots.neg;
        xform = {|i| [xlates[i], ylates[i], rots[i], xscales[i], yscales[i]] } ! 4;
        Pen.strokeColor = Color.grey(1,0.5);
        Pen.width = 8.linrand + 1;
        Pen.translate(400, 400);
        Pen.scale(zoom, zoom);
        Pen.translate(-400, -400);
        1200.do {
            var p, rot, xlate, ylate, xscale, yscale;
            Pen.width = 8.linrand + 1;
            Pen.beginPath;
            #rot, xlate, ylate, xscale, yscale = xform.choose;
            Pen.translate(xlate, ylate);
            Pen.rotate(rot, h/2, v/2);
            Pen.scale(xscale, yscale);
                Pen.moveTo(p1);
                Pen.lineTo(p2);
            Pen.stroke;
        };
    };
};

{ while { run } { w.refresh; 0.05.wait; } }.fork(AppClock)

)

Matrix example

(
var controlWindow, w;
var r, a, b, c, d, matrix = [1, 0, 0, 1, 10, 10];
var sliders, spex, name;

w = Window.new.front;
w.view.background_(Color.white);

// create a controller-window
controlWindow = Window("matrix controls", Rect(400,200,350,120));
controlWindow.front;

// determine the rectangle to be drawn
r = Rect.fromPoints(a = 0 @ 0, c = 180 @ 180);
b = r.leftBottom;
d = r.rightTop;

// the drawFunc
w.drawFunc = {
    Pen.strokeColor = Color.red;
    Pen.matrix = matrix;
    Pen.width = 5;
    Pen.strokeRect(r);
    Pen.strokeOval(r);
    Pen.color = Color.blue;
    Pen.width = 0.1;
    Pen.line(a, c);
    Pen.line(b, d);
    Pen.stroke;

    Pen.font = Font( "Helvetica-Bold", 12 );
    Pen.stringAtPoint( "A", a - 6 );
    Pen.stringAtPoint( "B", b - 6 );
    Pen.stringAtPoint( "C", c - (0@6) );
    Pen.stringAtPoint( "D", d - (0@6) );

    Pen.font = Font( "Helvetica", 10 );
    Pen.stringInRect( "a matrix test", r.moveBy( 50, 50 ));
};

controlWindow.view.decorator = sliders = FlowLayout(controlWindow.view.bounds);
spex = [
    [0, 2.0].asSpec,
    [0, 2.0].asSpec,
    [0, 2.0].asSpec,
    [0, 2.0].asSpec,
    [0, 200.0].asSpec,
    [0, 200.0].asSpec
];
name = #[zoomX, shearingY, shearingX, zoomY, translateX, translateY];
6.do { |i|
    EZSlider(controlWindow, 300 @ 14, name[i], spex[i], { |ez| var val;
            val = ez.value;
            [i, val.round(10e-4)].postln;
            matrix.put(i, val);
            w.refresh; // reevaluate drawFunc function
    }, matrix[i]);
    sliders.nextLine;
};
w.refresh;
)

Transparency layer example

(
w = Window.new("Transparency Layer test", Rect(400,400,430,450)).front;
w.drawFunc = {
    Color.blue.setStroke;

    Pen.use {
    Pen.setShadow(2@2, 10, Color.black);
    Pen.beginTransparencyLayer;

    Color.red.setFill;
    Pen.addOval(Rect(20,40,100,100));
    Pen.fill;

    Color.green.setFill;
    Pen.addOval(Rect(30,70,100,100));
    Pen.fill;

    Color.blue.setFill;
    Pen.addOval(Rect(60,40,100,100));
    Pen.fill;

    "With Transparency Layer".drawCenteredIn(Rect(30, 40, 100, 100), Font.default, Color.white);
    Pen.endTransparencyLayer;
    };

    Pen.use {
    Pen.translate(200, 0);
    Pen.setShadow(2@2, 10, Color.black);


    Color.red.setFill;
    Pen.addOval(Rect(20,40,100,100));
    Pen.fill;

    Color.green.setFill;
    Pen.addOval(Rect(30,70,100,100));
    Pen.fill;

    Color.blue.setFill;
    Pen.addOval(Rect(60,40,100,100));
    Pen.fill;

    "Without Transparency Layer".drawCenteredIn(Rect(30, 40, 100, 100), Font.default, Color.white);
    };

    Pen.use {
        Pen.translate(0, 200);
        Pen.setShadow(2@2, 10, Color.black);
        Pen.beginTransparencyLayer;

        Pen.push;
        Pen.addOval(Rect(20,40,170,170));
        Pen.fillAxialGradient(w.view.bounds.leftTop, w.view.bounds.rightBottom, Color.rand, Color.rand);
        Pen.pop;

        "With Transparency Layer".drawCenteredIn(Rect(20,40,170,170), Font.default, Color.white);

        Pen.endTransparencyLayer;
    };

    Pen.use {
        Pen.translate(200, 200);
        Pen.setShadow(2@2, 10, Color.black);
        Pen.addOval(Rect(20,40,170,170));
        Pen.fillAxialGradient(w.view.bounds.leftTop, w.view.bounds.rightBottom, Color.rand, Color.rand);

        "Without Transparency Layer".drawCenteredIn(Rect(20,40,170,170), Font.default, Color.white);
    };
};
w.refresh;
)

Blending modes

/*
different blend modes:
OS X 10.4 and > Only
--------------------
0 - Normal
1 - Multiply
2 - Screen
3 - Overlay
4 - Darken
5 - Lighten
6 - ColorDodge
7 - ColorBurn
8 - SoftLight
9 - HardLight
10 - Difference
11 - Exclusion
12 - Hue
13 - Saturation
14 - Color
15 - Luminosity

OS 10.5 and > Only
--------------------
16 - Clear
17 - Copy
18 - SourceIn
19 - SourceOut
20 - SourceATop
21 - DestinationOver
22 - DestinationIn
23 - DestinationATop
24 - XOR
25 - PlusDarker
26 - PlusLighter
*/

(
    var blendMode=0, blendString="Normal";
    w = Window.new.front;
    m = SCPopUpMenu(w, Rect(10, w.view.bounds.height - 30, 150, 20));
    m.items = [
        "0 - Normal",
        "1 - Multiply",
        "2 - Screen",
        "3 - Overlay",
        "4 - Darken",
        "5 - Lighten",
        "6 - ColorDodge",
        "7 - ColorBurn",
        "8 - SoftLight",
        "9 - HardLight",
        "10 - Difference",
        "11 - Exclusion",
        "12 - Hue",
        "13 - Saturation",
        "14 - Color",
        "15 - Luminosity"
    ];

    m.action_({|view|
        blendMode = view.value;
        blendString = view.items.at(blendMode);
        w.refresh;
    });
    w.drawFunc = {
        80.do{|i|
            Pen.use {
            Pen.blendMode_(blendMode);
            Pen.color = Color.green(0.6, 0.10);
            Pen.addRect(
                Rect(20, 20, 20 + (i*4), 20 + (i*4));
            );
            Pen.fill;
            };
        }
    };
    w.refresh;
)

Inherited class methods

Undocumented class methods

*addRoundedRect (aRect, radiusX, radiusY)

*addWedge_Deg (center, radius, startAngle, sweepLength)

*color = aColor

*fillColor = aColor

*font

*font = aFont

*nonimpl (methodName)

*pop

*prAddAnnularWedge (center, innerRadius, outerRadius, startAngle, sweepLength)

*prAddArc (center, radius, startAngle, arcAngle)

*prBegin (aView)

*prDrawImage (target, image, source, operation, opacity)

*prEnd

*prSetFont (aFont)

*prTileImage (target, image, source, operation, opacity)

*push

*rotateDeg (angle: 0, x: 0, y: 0)

*string (aString)

*stringAtPoint (string, point, font, color)

*stringCenteredIn (string, rect, font, color)

*stringInRect (string, rect, font, color, alignment)

*stringLeftJustIn (string, rect, font, color)

*stringRightJustIn (string, rect, font, color)

*strokeColor = aColor

*tileImage (target, image, source, operation: 'sourceOver', opacity: 1)

Instance Methods

Inherited instance methods