deprecate SCViewHolder-layRight
[supercollider.git] / SCClassLibrary / Common / GUI / Inspector.sc
blob94313d9c3371f5f62ecc3473a4fc2e1ccb9ce7e1
1 Inspector {
2         classvar <allInspectors;
4         var <object, <window, vpos=0, gui;
6         *new { arg object;
7                 var inspector;
8                 inspector = this.inspectorFor(object) ?? {
9                         super.newCopyArgs(object).init;
10                 };
11                 inspector.window.front;
12                 ^inspector
13         }
14         *initClass { allInspectors = []; }
15         *inspectorFor { arg object;
16                 ^allInspectors.detect({ arg item;
17                                 item.object === object
18                 });
19         }
20         init {
21                 allInspectors = allInspectors.add(this);
22                 gui = GUI.current;
23                 this.makeWindow;
24                 vpos = 4;
25                 this.makeHead;
26                 this.makeBody;
27                 window.refresh;
28         }
30         didClose {
31                 allInspectors.remove(this);
32         }
33         lineHeight { ^20 }
34         buttonHeight { ^this.lineHeight - 4 }
35         makeWindow {
36                 var bounds;
37                 bounds = Rect(80, 80, 376, this.lineHeight * (this.numLines + 1) + 16);
39                 window = gui.window.new(object.class.name.asString ++ " inspector", bounds);
40                 window.onClose = Message(this, \didClose);
41         }
42         //numLines{^0}
43         //makeHead{}
44         //makeBody {}
48 ObjectInspector : Inspector {
50         var stringView, slotInspectors;
52         numLines {
53                 ^min(30, object.slotSize); // don't display too many lines
54         }
56         makeHead {
57                 var view;
58                 view = gui.button.new(window, Rect(8, vpos, 128, this.buttonHeight));
59                 view.states = [[object.class.name]];
60                 view.action = { GUI.use( gui, { object.class.inspect })};
62                 if (object.mutable, {
63                         view = gui.button.new(window, Rect(140, vpos, 50, this.buttonHeight));
64                         view.states = [["update"]];
65                         view.action = Message(this, \update);
66                 });
68                 view = gui.dragSource.new(window, Rect(194, vpos, 174, this.buttonHeight));
69                 view.object = object;
70                 view.resize = 2;
71                 stringView = view;
73                 vpos = vpos + this.lineHeight;
74         }
76         makeBody {
77                 this.numLines.do({ arg i;
78                         slotInspectors = slotInspectors.add(
79                                 SlotInspector(this, i, vpos)
80                         );
81                         vpos = vpos + this.lineHeight;
82                 });
83                 // ... link to rest, or scroll view
84         }
86         update {
87                 stringView.object = object;
88                 slotInspectors.do({ arg slotinsp;
89                         slotinsp.update;
90                 });
91         }
94 StringInspector : ObjectInspector {
95         // don't bother with the array of Chars.
96         numLines { ^0 }
99 ClassInspector : ObjectInspector {
100         makeHead {
101                 var view;
102                 view = gui.button.new(window, Rect(8, vpos, 128, this.buttonHeight));
103                 view.states = [[object.class.name]];
104                 view.action = { GUI.use( gui, { object.class.inspect })};
106                 view = gui.button.new(window, Rect(140, vpos, 50, this.buttonHeight));
107                 view.states = [["edit"]];
108                 view.action = Message(object, \openCodeFile);
110                 if (object.superclass.notNil, {
111                         view = gui.button.new(window, Rect(194, vpos, 70, this.buttonHeight));
112                         view.states = [["superclass"]];
113                         view.action = { GUI.use( gui, { object.superclass.inspect })};
114                 });
116                 view = gui.dragSource.new(window, Rect(268, vpos, 96, this.buttonHeight));
117                 view.object = object;
118                 view.resize = 2;
119                 stringView = view;
121                 vpos = vpos + this.lineHeight;
122         }
126 FunctionDefInspector : ObjectInspector {
127         openSuper {
128                 GUI.use( gui, { object.superclass.inspect });
129         }
130         makeHead {
131                 var view;
132                 view = gui.button.new(window, Rect(8, vpos, 128, this.buttonHeight));
133                 view.states = [[object.class.name]];
134                 view.action = { GUI.use( gui, { object.class.inspect })};
136                 if (object.code.notNil, {
137                         view = gui.button.new(window, Rect(194, vpos, 70, this.buttonHeight));
138                         view.states = [["dump code"]];
139                         view.action = Message(object, \dumpByteCodes);
140                 });
142                 view = gui.dragSource.new(window, Rect(268, vpos, 96, this.buttonHeight));
143                 view.object = object;
144                 view.resize = 2;
145                 stringView = view;
147                 vpos = vpos + this.lineHeight;
148         }
151 MethodInspector : ObjectInspector {
152         openSuper {
153                 GUI.use( gui, { object.superclass.inspect });
154         }
155         makeHead {
156                 var view;
157                 view = gui.button.new(window, Rect(8, vpos, 128, this.buttonHeight));
158                 view.states = [[object.class.name]];
159                 view.action = { GUI.use( gui, { object.class.inspect })};
161                 view = gui.button.new(window, Rect(140, vpos, 50, this.buttonHeight));
162                 view.states = [["edit"]];
163                 view.action = Message(object, \openCodeFile);
165                 if (object.code.notNil, {
166                         view = gui.button.new(window, Rect(194, vpos, 70, this.buttonHeight));
167                         view.states = [["dump code"]];
168                         view.action = Message(object, \dumpByteCodes);
169                 });
171                 view = gui.dragSource.new(window, Rect(268, vpos, 96, this.buttonHeight));
172                 view.object = object;
173                 view.resize = 2;
174                 stringView = view;
176                 vpos = vpos + this.lineHeight;
177         }
180 SlotInspector {
181         var <object, <>index, <key, <slotKeyView, <slotValueView, <inspectButton;
183         var gui;
185         *new { arg inspector, index, vpos;
186                 ^super.newCopyArgs(inspector.object, index).init(inspector, vpos)
187         }
188         init { arg inspector, vpos;
189                 var w, class, hasGetter, hasSetter, vbounds, value;
191                 gui     = GUI.current;
193                 w = inspector.window;
194                 key = object.slotKey(index);
195                 class = object.class;
197                 slotKeyView = gui.staticText.new(w, Rect(8, vpos, 110, this.buttonHeight));
198                 slotKeyView.align = \right;
199 //              slotKeyView.font = gui.font.default ?? { gui.font.new("Helvetica", 12) };
201                 if (key.isKindOf(Symbol), {
202                         hasGetter = class.findRespondingMethodFor(key).notNil;
203                         hasSetter = class.findRespondingMethodFor(key.asSetter).notNil && object.mutable;
204                 },{
205                         hasGetter = true;
206                         hasSetter = object.mutable;
207                 });
208                 //slotKeyView.background = Color.grey(if(hasGetter,0.95,0.85));
210                 vbounds = Rect(122, vpos, 218, this.buttonHeight);
211                 if (hasSetter, {
212                         if (hasGetter, {
213                                 slotValueView = gui.dragBoth.new(w, vbounds);
214                         },{
215                                 slotValueView =  gui.dragSink.new(w, vbounds);
216                         });
217                         slotValueView.action = Message(this, \setSlot);
218                 },{
219                         if (hasGetter, {
220                                 slotValueView = gui.dragSource.new(w, vbounds);
221                         },{
222                                 slotValueView = gui.staticText.new(w, vbounds);
223                         });
224                 });
225                 slotValueView.resize = 2;
226 //              slotValueView.font = gui.font.default ?? { gui.font.new("Helvetica", 12) };
227                 //slotValueView.background = Color.grey(if(hasSetter,0.95,0.85));
229                 inspectButton = gui.button.new(w, Rect(344, vpos, this.buttonHeight, this.buttonHeight));
230                 inspectButton.states = [["I"]];
231                 inspectButton.action = Message(this, \inspectSlot);
232                 inspectButton.resize = 3;
233                 //inspectButton.visible = true; //object.slotAt(index).canInspect;
234                 this.update;
235         }
236         update {
237                 key = object.slotKey(index);
238                 slotKeyView.string = key;
239                 slotValueView.object = object.slotAt(index);
240                 //inspectButton.visible = true; //object.slotAt(index).canInspect;
241         }
242         inspectSlot {
243                 GUI.use( gui, { object.slotAt(index).inspect });
244         }
245         setSlot {
246                 if (key.isKindOf(Symbol), {
247                         object.perform(key.asSetter, gui.view.currentDrag);
248                 },{
249                         object.put(key, gui.view.currentDrag);
250                 });
251                 this.update;
252         }
253         lineHeight { ^20 }
254         buttonHeight { ^this.lineHeight - 4 }
257 FrameInspector : Inspector {
259         numLines{^0}
260         makeHead {
261                 var view;
262                 view = gui.button.new(window, Rect(8, vpos, 128, this.buttonHeight));
263                 view.states = [[object.class.name]];
264                 view.action = { GUI.use( gui, { object.class.inspect })};
266                 vpos = vpos + this.lineHeight;
267         }
268         makeBody {}