Removing an old, cherished, yet pointless caveat "This documentation is
[supercollider.git] / Help / GUI / Cocoa-GUI / SCUserViewSubclassing / SCUserViewTutorial.sc
blob20a0f6aa838e3751310b74a0535a795161270616
1 // How to subclass SCUserView to make custom GUI interfaces. Jost Muxfeldt, 2008.
2 // For many purposes you can use this as a template, and simply adjust the methods
4 MyWidget : SCUserView {
6         // (1) Setup instance vars appropriate to your widget. Make sure to define value.
7         var <>step, <value=0, <>leftColor, <>rightColor, <>thumbWidth=7;
9         // (2) Set the viewClass to SCUserView
10         *viewClass { ^SCUserView } // this ensures that SCUserView's primitive is called
13         // (3) Set up your view
14         init { |argParent, argBounds|
16                 super.init(argParent, argBounds);
18                 // set defaults of your instance variables
19                 rightColor=Color.grey(0.8);
20                 leftColor=Color.grey(0.2);
21                 step=this.pixelStep;
23                 // set the draw function of the SCUserView
24                 this.drawFunc={ this.draw};
25         }
28         // (4) define a drawing function for SCPen
29         draw{
30                 // Draw the fill
31                 SCPen.fillColor = Color.grey;
32                 Pen.addRect(Rect(0,0, this.bounds.width*value,this.bounds.height));
33                 Pen.fill;
34                 // Draw the triangle
35                 SCPen.fillColor = Color.red;
36                 Pen.moveTo(((this.bounds.width*value)-5) @ this.bounds.height);
37                 Pen.lineTo(((this.bounds.width*value)+5) @ this.bounds.height);
38                 Pen.lineTo(((this.bounds.width*value)) @ (this.bounds.height/2));
39                 Pen.lineTo(((this.bounds.width*value)-5) @ this.bounds.height);
40                 Pen.fill;
41                 // Draw the frame
42                 SCPen.strokeColor = Color.black;
43                 Pen.addRect(Rect(0,0, this.bounds.width,this.bounds.height));
44                 Pen.stroke;
45         }
48         // (5) define typical widget methods  (only those you need or adjust as needed)
49         valueAction_{ arg val; // most widgets have this
50                 this.value=val;
51                 this.doAction;
52         }
53         value_{ |val|    // in many widgets, you can change the
54                                          // value and refresh the view , but not do the action.
55                 value=val;
56                 this.refresh;
57         }
58                         // these are like in SCSlider
59         increment { |zoom=1| ^this.valueAction = this.value + (max(this.step, this.pixelStep) * zoom) }
60         decrement { |zoom=1| ^this.valueAction = this.value - (max(this.step, this.pixelStep) * zoom) }
62         pixelStep {  // like in SCSlider
63                 var bounds = this.bounds;
64                 ^(bounds.width-1).reciprocal
65         }
68         // (6) override mouseActions
69         mouseDown{ arg x, y, modifiers, buttonNumber, clickCount;
70                 var newVal;
71                 // this allows for user defined mouseDownAction
72                 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount);
74                 // set the value and do the action
75                 ([256, 0].includes(modifiers)).if{ // restrict to no modifier
77                         newVal= x.linlin(0,this.bounds.width,0,1);
78                         // translates the relative mouse position in pixels to a value between 0 and 1
80                         if (newVal != value) {this.valueAction_(newVal)}; // only do something if the value changed
81                 };
82         }
84         mouseMove{ arg x, y, modifiers, buttonNumber, clickCount;
85                 var newVal;
86                 // this allows for user defined mouseMoveAction
87                 mouseMoveAction.value(this, x, y, modifiers, buttonNumber, clickCount);
89                 // set the value and do the action
90                 ([256, 0].includes(modifiers)).if{ // restrict to no modifier
92                         newVal= x.linlin(0,this.bounds.width,0,1);
93                         // translates the  relative mouse position in pixels to a value between 0 and 1
95                         if (newVal != value) {this.valueAction_(newVal)}; // only do something if the value changed
96                 };
98         }
100         // (7) define default key actions
101         // make sure to return "this", if successful, and nil if not successful
102         defaultKeyDownAction { arg char, modifiers, unicode,keycode;
103                 if (unicode == 16rF700, { this.increment; ^this });
104                 if (unicode == 16rF703, { this.increment; ^this });
105                 if (unicode == 16rF701, { this.decrement; ^this });
106                 if (unicode == 16rF702, { this.decrement; ^this });
108                 ^nil            // bubble if it's an invalid key
109         }
111         // (8) define drag and drop
112         defaultGetDrag {^value} // what to drag
113         defaultCanReceiveDrag  {^currentDrag.isNumber} // when to receive
114         defaultReceiveDrag { this.valueAction = currentDrag;} // what to do on receiving