comparison mde/gui/WidgetManager.d @ 85:56c0ddd90193

Intermediate commit (not stable). Changes to init system.
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 11 Sep 2008 11:33:51 +0100
parents e0f1ec7fe73a
children 79d816b3e2d2
comparison
equal deleted inserted replaced
84:e0f1ec7fe73a 85:56c0ddd90193
27 27
28 // For adding the input event callbacks and requesting redraws: 28 // For adding the input event callbacks and requesting redraws:
29 import imde = mde.imde; 29 import imde = mde.imde;
30 import mde.input.Input; 30 import mde.input.Input;
31 import mde.scheduler.Scheduler; 31 import mde.scheduler.Scheduler;
32 import mde.setup.Screen;
32 33
33 import tango.core.sync.Mutex; 34 import tango.core.sync.Mutex;
34 import tango.util.log.Log : Log, Logger; 35 import tango.util.log.Log : Log, Logger;
35 36
36 private Logger logger; 37 private Logger logger;
37 static this () { 38 static this () {
38 logger = Log.getLogger ("mde.gui.WidgetManager"); 39 logger = Log.getLogger ("mde.gui.WidgetManager");
39
40 gui = new WidgetManager ("gui");
41 } 40 }
42
43 WidgetManager gui;
44
45 41
46 /************************************************************************************************* 42 /*************************************************************************************************
47 * The widget manager. 43 * The widget manager.
48 * 44 *
49 * This is responsible for loading and saving an entire gui (although more than one may exist), 45 * This is responsible for loading and saving an entire gui (although more than one may exist),
52 * Currently mouse coordinates are passed to widgets untranslated. It may make sense to translate 48 * Currently mouse coordinates are passed to widgets untranslated. It may make sense to translate
53 * them and possibly drop events for some uses, such as if the gui is drawn to a texture. 49 * them and possibly drop events for some uses, such as if the gui is drawn to a texture.
54 * 50 *
55 * Aside from the IWidgetManager methods, this class should be thread-safe. 51 * Aside from the IWidgetManager methods, this class should be thread-safe.
56 *************************************************************************************************/ 52 *************************************************************************************************/
57 class WidgetManager : WidgetLoader { 53 class WidgetManager : WidgetLoader, Screen.Drawable {
58 /** Construct a new widget manager. 54 /** Construct a new widget manager.
59 * 55 *
60 * params: 56 * params:
61 * fileName = Name of file specifying the gui, excluding path and extension. 57 * fileName = Name of file specifying the gui, excluding path and extension.
62 */ 58 */
63 this (char[] file) { 59 this (char[] file) {
64 super(file); 60 super(file);
61
62 Screen.addDrawable (this);
65 } 63 }
66 64
67 // NOTE - temporarily here to allow CTOR to run safely during static this 65 // NOTE - temporarily here to allow CTOR to run safely during static this
68 // called during init 66 // called during init
69 void init () { 67 void init () {
68 // Doesn't need a lock - cannot conflict with other class functions.
70 // Events we want to know about: 69 // Events we want to know about:
71 imde.input.addMouseClickCallback(&clickEvent); 70 imde.input.addMouseClickCallback(&clickEvent);
72 imde.input.addMouseMotionCallback(&motionEvent); 71 imde.input.addMouseMotionCallback(&motionEvent);
73 } 72 }
74 73
75 74
76 /** Draw the gui. */ 75 /** Draw the gui. */
77 void draw() { 76 void draw() {
77 debug logger.trace ("drawing; w,h = {},{}",w,h);
78 synchronized(mutex) 78 synchronized(mutex)
79 child.draw; 79 if (child)
80 child.draw;
80 } 81 }
81 82
82 83
83 /** For mouse click events. 84 /** For mouse click events.
84 * 85 *
86 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 87 void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {
87 debug scope (failure) 88 debug scope (failure)
88 logger.warn ("clickEvent: failed!"); 89 logger.warn ("clickEvent: failed!");
89 mutex.lock; 90 mutex.lock;
90 scope(exit) mutex.unlock; 91 scope(exit) mutex.unlock;
92 if (child is null) return;
91 93
92 // NOTE: buttons receive the up-event even when drag-callbacks are in place. 94 // NOTE: buttons receive the up-event even when drag-callbacks are in place.
93 foreach (dg; clickCallbacks) 95 foreach (dg; clickCallbacks)
94 // See IWidgetManager.addClickCallback's documentation: 96 // See IWidgetManager.addClickCallback's documentation:
95 if (dg (cast(wdabs)cx, cast(wdabs)cy, b, state)) return; 97 if (dg (cast(wdabs)cx, cast(wdabs)cy, b, state)) return;
96 98
97 // NOTE: do we need to test if the click was on the gui (and thus child)? 99 // NOTE: do we need to test if the click was on the gui (and thus child)?
100 // FIXME: yes, unless we can guarantee this!
98 IChildWidget widg = child.getWidget (cast(wdabs)cx,cast(wdabs)cy); 101 IChildWidget widg = child.getWidget (cast(wdabs)cx,cast(wdabs)cy);
99 if (widg !is null) 102 if (widg !is null)
100 widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state); 103 widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state);
101 /+ FIXME: remove
102 foreach (i,w; windows) {
103 IWidget widg = w.getWidget (cast(wdabs)cx,cast(wdabs)cy);
104 if (widg !is null) {
105 // Bring to front
106 windows = w ~ windows[0..i] ~ windows[i+1..$];
107
108 widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state);
109 requestRedraw; // in case we've only moved to front
110 return; // only pass to first window
111 }
112 }+/
113 } 104 }
114 105
115 /** For mouse motion events. 106 /** For mouse motion events.
116 * 107 *
117 * Sends the event on to all motion callbacks. */ 108 * Sends the event on to all motion callbacks. */
124 foreach (dg; motionCallbacks) 115 foreach (dg; motionCallbacks)
125 dg (cast(wdabs)cx, cast(wdabs)cy); 116 dg (cast(wdabs)cx, cast(wdabs)cy);
126 } 117 }
127 118
128 119
129 void setSize (int x, int y) { 120 void sizeEvent (int nw, int nh) { // Drawable function
130 mutex.lock; 121 mutex.lock;
131 scope(exit) mutex.unlock; 122 scope(exit) mutex.unlock;
132 123
133 w = cast(wdim) x; 124 w = cast(wdim) nw;
134 h = cast(wdim) y; 125 h = cast(wdim) nh;
135 126
136 if (child is null) 127 debug logger.trace ("Resize to: {},{}", nw, nh);
137 return; // May not have been created before this is first run. 128 if (w < mw || h < mh)
129 logger.warn ("Minimal dimensions ({},{}) not met: ({},{}), but I cannot resize myself!",mw,mh,w,h);
130
131 if (!child) return; // if not created yet.
138 child.setWidth (w, -1); 132 child.setWidth (w, -1);
139 child.setHeight (h, -1); 133 child.setHeight (h, -1);
140 child.setPosition (0,0); 134 child.setPosition (0,0);
141 } 135 }
142 136
163 motionCallbacks.remove(frame); 157 motionCallbacks.remove(frame);
164 } 158 }
165 //END IWidgetManager methods 159 //END IWidgetManager methods
166 160
167 protected: 161 protected:
168 /* Second stage of widget loading. */ 162 /* Second stage of widget loading.
163 * Note: sizeEvent should be called with window size before this. */
169 void createRootWidget () { 164 void createRootWidget () {
170 // The renderer needs to be created on the first load, but not after this. 165 // The renderer needs to be created on the first load, but not after this.
171 if (rend is null) 166 if (rend is null)
172 rend = createRenderer (rendName); 167 rend = createRenderer (rendName);
173 168
174 child = makeWidget ("root"); 169 child = makeWidget ("root");
170
171 mw = child.minWidth;
172 mh = child.minHeight;
173
174 if (w < mw || h < mh)
175 logger.warn ("Minimal dimensions ({},{}) not met: ({},{}), but I cannot resize myself!",mw,mh,w,h);
175 176
176 child.setWidth (w, -1); 177 child.setWidth (w, -1);
177 child.setHeight (h, -1); 178 child.setHeight (h, -1);
178 child.setPosition (0,0); 179 child.setPosition (0,0);
179 } 180 }
182 // callbacks indexed by their frame pointers: 183 // callbacks indexed by their frame pointers:
183 bool delegate(wdabs cx, wdabs cy, ubyte b, bool state) [void*] clickCallbacks; 184 bool delegate(wdabs cx, wdabs cy, ubyte b, bool state) [void*] clickCallbacks;
184 void delegate(wdabs cx, wdabs cy) [void*] motionCallbacks; 185 void delegate(wdabs cx, wdabs cy) [void*] motionCallbacks;
185 IRenderer rend; 186 IRenderer rend;
186 wdim w,h; // area available to the widgets 187 wdim w,h; // area available to the widgets
188 wdim mw,mh; // minimal area available to the widgets
187 } 189 }
188 190
189 191
190 import mde.gui.exception; 192 import mde.gui.exception;
191 import mde.gui.widget.Ifaces; 193 import mde.gui.widget.Ifaces;
209 * fileName = Name of file specifying the gui, excluding path and extension. 211 * fileName = Name of file specifying the gui, excluding path and extension.
210 */ 212 */
211 protected this (char[] file) { 213 protected this (char[] file) {
212 mutex = new Mutex; // Used on functions intended to be called from outside the gui package. 214 mutex = new Mutex; // Used on functions intended to be called from outside the gui package.
213 fileName = file; 215 fileName = file;
214 }
215 ~this () {
216 save;
217 } 216 }
218 217
219 /* Load the widgets' data from the file specified to the CTOR. 218 /* Load the widgets' data from the file specified to the CTOR.
220 * 219 *
221 * params: 220 * params:
378 } 377 }
379 378
380 379
381 /** Create a widget by ID. */ 380 /** Create a widget by ID. */
382 IChildWidget makeWidget (widgetID id, IParentWidget parent = null) { 381 IChildWidget makeWidget (widgetID id, IParentWidget parent = null) {
383 debug logger.trace ("Creating widget \""~id~'"'); 382 debug (mdeWidgets) logger.trace ("Creating widget \""~id~'"');
384 return createWidget (this, curData[id], parent); 383 return createWidget (this, curData[id], parent);
385 } 384 }
386 385
387 /** For making changes. */ 386 /** For making changes. */
388 void setData (widgetID id, WidgetData d) { 387 void setData (widgetID id, WidgetData d) {