1 EZGui{ // an abstract class
2 var <>labelView, <widget, <view, gap, popUp=false, innerBounds,
3 <>action, <layout, <value, labelSize, <alwaysOnTop=false, margin;
4 var scaler=1; //for swing compatibility
5 // general stuff for all EZ classes. override as needed
6 visible { ^view.getProperty(\visible) }
7 visible_ { |bool| view.setProperty(\visible,bool) }
9 enabled { ^view.enabled }
10 enabled_ { |bool| view.enabled_(bool) }
14 alwaysOnTop_{arg bool;
16 popUp.if{this.window.alwaysOnTop=alwaysOnTop};
20 labelView.notNil.if{labelView.font=font};
24 window{^ popUp.if{view.parent.findWindow};}
26 onClose{^ popUp.if{this.window.onClose}{view.onClose};}
28 onClose_{|func| popUp.if{this.window.onClose_(func)}{view.onClose_(func)};}
31 //// value stuff. override as needed
34 value_{|val| value=val; widget.value_(val)}
36 valueAction_{|val| this.value_(val); this.doAction}
38 doAction {this.action.value(this)}
41 ///////// private methods. You can still override these in subclasses
43 prSubViewBounds{arg rect, hasLabel;
44 var widgetBounds,labelBounds,tmp;
45 hasLabel.not.if{gap=0@0; labelSize=0@0};
48 { widgetBounds= Rect( // fit to full width
52 rect.height-labelSize.y-gap.y
54 labelBounds=Rect(0,0,widgetBounds.width,labelSize.y);//fit to full width
56 widgetBounds= Rect( // fit to full remaining
59 rect.width-labelSize.x-gap.x,
62 labelBounds=Rect(0,0, labelSize.x ,widgetBounds.height )}; // to left
64 ^[labelBounds, widgetBounds].collect{arg v; v.moveBy(margin.x,margin.y)}
68 prMakeView{arg parentView,bounds; // return a container, or a popUpWindow with a container
69 var w, winBounds, view, extraHeight=24;
70 (GUI.id==\swing).if{extraHeight=36};
73 // if bounds is a point the place the window on screen
74 if (bounds.class==Point)
75 { bounds = bounds.x@max(bounds.y,bounds.y+extraHeight);// window minimum height;
76 winBounds=Rect(200, Window.screenBounds.height-bounds.y-100,
78 }{// window minimum height;
79 winBounds = bounds.height_(max(bounds.height,bounds.height+extraHeight))
81 w = GUI.window.new("",winBounds).alwaysOnTop_(alwaysOnTop);
85 // inset the bounds to make a nice margin
86 bounds=Rect(4,4,bounds.width-8,bounds.height-extraHeight);
87 view=GUI.compositeView.new(parentView,bounds).resize_(2);
88 w.bounds=w.bounds; // swing needs this for some reason, or bounds are too high
90 }{// normal parent view
92 view=GUI.compositeView.new(parentView,bounds);
95 innerBounds=view.bounds.insetBy(margin.x,margin.y);
99 prMakeMarginGap{arg parentView, argMargin, argGap;
100 //try to use the parent decorator gap
101 var decorator = parentView.asView.tryPerform(\decorator);
103 gap = gap ? decorator.tryPerform(\gap).copy; // use copy to protect the parent gap
107 argMargin.isNil.if{margin=0@0}{margin=argMargin};
113 EZLists : EZGui{ // an abstract class
115 var <items, <>globalAction;
117 *new { arg parentView, bounds, label,items, globalAction, initVal=0,
118 initAction=false, labelWidth,labelHeight=20, layout, gap, margin;
120 ^super.new.init(parentView, bounds, label, items, globalAction, initVal,
121 initAction, labelWidth,labelHeight,layout, gap, margin);
124 init { arg parentView, bounds, label, argItems, argGlobalAction, initVal,
125 initAction, labelWidth, labelHeight, layout, argGap, argMargin;
127 // try to use the parent decorator gap
128 this.prMakeMarginGap(parentView, argMargin, argGap);
130 // init the views (handled by subclasses)
131 this.initViews( parentView, bounds, label, labelWidth,labelHeight,layout );
133 this.items=argItems ? [];
135 globalAction=argGlobalAction;
137 widget.action={arg obj;
138 items.at(obj.value).value.value(this);
139 globalAction.value(this);
142 this.value_(initVal);
146 items.at(initVal).value.value(this); // You must do this like this
147 globalAction.value(this); // since listView's array is not accessible yet
149 this.value_(initVal);
154 initViews{} // override this for your subclass views
156 value{ ^widget.value}
157 value_{|val| widget.value=val}
159 valueAction_{|val| widget.value_(val); this.doAction}
161 doAction {widget.doAction;}
163 items_{ arg assocArray;
164 assocArray = assocArray.collect({ |it| if (it.isKindOf(Association), { it }, { it -> nil }) });
166 widget.items=assocArray.collect({|item| item.key});
169 item {^items.at(this.value).key}
170 itemFunc {^items.at(this.value).value}
172 addItem{arg name, action;
173 this.insertItem(nil, name, action);
176 insertItem{ arg index, name, action;
178 index = index ? items.size;
179 this.items=items.insert(index, name.asSymbol -> action);
182 removeItemAt{ arg index;
184 items.removeAt(index);
189 replaceItemAt{ arg index, name, action;
191 name = name ? items.at(index).key;
192 action = action ? items.at(index).value;
193 this.removeItemAt(index);
194 this.insertItem(index, name, action);