Mercurial > projects > mde
comparison mde/gui/gui.d @ 30:467c74d4804d
Major changes to the scheduler, previously only used by the main loop.
Revamped Scheduler. Functions can be removed, have multiple schedules, have their scheduling changed, etc.
Scheduler has a unittest. Checked all pass.
Main loop scheduler moved to mde. Draw-on-demand currently disabled, simplifying this.
Made mtunitest.d remove the temporary file it uses afterwards.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Mon, 28 Apr 2008 10:59:47 +0100 |
parents | f985c28c0ec9 |
children | baa87e68d7dc |
comparison
equal
deleted
inserted
replaced
29:f985c28c0ec9 | 30:467c74d4804d |
---|---|
28 import mde.scheduler.InitFunctions; | 28 import mde.scheduler.InitFunctions; |
29 | 29 |
30 import tango.scrapple.text.convert.parseTo : parseTo; | 30 import tango.scrapple.text.convert.parseTo : parseTo; |
31 import tango.scrapple.text.convert.parseFrom : parseFrom; | 31 import tango.scrapple.text.convert.parseFrom : parseFrom; |
32 | 32 |
33 import tango.util.log.Log : Log, Logger; | |
34 | |
33 private Logger logger; | 35 private Logger logger; |
34 static this () { | 36 static this () { |
35 logger = Log.getLogger ("mde.gui.gui"); | 37 logger = Log.getLogger ("mde.gui.gui"); |
36 | 38 |
37 init.addFunc (&GUI.load, "GUI.load"); | 39 init.addFunc (&loadGUI, "loadGUI"); |
38 } | 40 } |
39 | 41 |
42 GUI gui; // Currently just one instance; handle differently later. | |
43 // Wrap gui.load, since init doesn't handle delegates | |
44 // (do it this way since GUI handling will eventually be changed) | |
45 void loadGUI () { | |
46 gui.load(); | |
47 } | |
48 | |
49 /** A GUI handles a bunch of windows, all to be drawn to the same device. */ | |
40 struct GUI { | 50 struct GUI { |
41 static: | 51 /** Load all windows from the file gui. */ |
42 private const fileName = "gui"; | |
43 void load() { | 52 void load() { |
53 static const fileName = "gui"; | |
44 if (!confDir.exists (fileName)) { | 54 if (!confDir.exists (fileName)) { |
45 logger.error ("Unable to load GUI: no config file!"); | 55 logger.error ("Unable to load GUI: no config file!"); |
46 return; // not a fatal error (so long as the game can run without a GUI!) | 56 return; // not a fatal error (so long as the game can run without a GUI!) |
47 } | 57 } |
48 | 58 |
63 // get list | 73 // get list |
64 windows.length = reader.dataset.sec.length; // pre-allocate | 74 windows.length = reader.dataset.sec.length; // pre-allocate |
65 windows.length = 0; | 75 windows.length = 0; |
66 foreach (sec; reader.dataset.sec) { | 76 foreach (sec; reader.dataset.sec) { |
67 Window w = cast(Window) sec; | 77 Window w = cast(Window) sec; |
68 if (w !is null) { // extra safety | 78 debug if (w is null) { |
69 windows ~= w; | 79 logger.error (__FILE__ ~ "(GUI.load): code error (w is null)"); |
70 try { | 80 continue; |
71 w.finalise(); | 81 } |
72 | 82 try { |
73 gl.addDrawCallback (&w.draw); | 83 //logger.trace ("1"); |
74 } catch (WindowLoadException e) { | 84 int x; |
75 logger.error ("Window failed to load: " ~ e.msg); | 85 w.finalise(); |
76 } | 86 x = 6; |
77 } | 87 windows ~= w; // only add if load successful |
78 } | 88 } catch (WindowLoadException e) { |
79 } | 89 logger.error ("Window failed to load: " ~ e.msg); |
80 | 90 } |
81 private: | 91 } |
92 } | |
93 | |
94 /** Draw each window. | |
95 * | |
96 * Currently no concept of how to draw overlapping windows, or how to not bother drawing windows | |
97 * which don't need redrawing. */ | |
98 void draw() { | |
99 foreach (w; windows) | |
100 w.draw(); | |
101 } | |
102 | |
103 private: | |
82 Window[] windows; | 104 Window[] windows; |
83 } | 105 } |
84 | 106 |
85 package: // Nothing else here is for external use. | 107 package: // Nothing else here is for external use. |
86 | 108 |
93 * created, be given its int[] of data, which this() must confirm is valid (or throw). | 115 * created, be given its int[] of data, which this() must confirm is valid (or throw). |
94 */ | 116 */ |
95 class Window : mt.IDataSection, IWindow | 117 class Window : mt.IDataSection, IWindow |
96 { | 118 { |
97 alias int widgetID; // Widget ID type. Each ID is unique under this window. Type is int since this is the widget data type. | 119 alias int widgetID; // Widget ID type. Each ID is unique under this window. Type is int since this is the widget data type. |
98 private int[][widgetID] widgetData; // Data for all widgets under this window. | 120 |
99 private Widget[widgetID] widgets; // List of all widgets under this window (created on demand). | 121 /** Call after loading is finished to setup the window and confirm that it's valid. |
100 | 122 * |
101 Widget widget; // The primary widget in this window. | 123 * Throws: WindowLoadException. Do not use the instance in this case! */ |
102 int x,y; // Window position | |
103 int w,h; // Window size (calculated from Widgets) | |
104 | |
105 const BORDER_WIDTH = 8; // Temporary way to handle window decorations | |
106 | |
107 | |
108 // Call after loading is finished to setup the window and confirm that it's valid. | |
109 void finalise () { | 124 void finalise () { |
110 // Create the widget, throwing on error: | 125 // Check data was loaded: |
126 if (widgetData is null) throw new WindowLoadException ("No widget data"); | |
127 | |
128 // Create the primary widget (and indirectly all sub-widgets), throwing on error: | |
111 widget = getWidget (0); // primary widget always has ID 0. | 129 widget = getWidget (0); // primary widget always has ID 0. |
112 widget.getSize (w,h); // Find the initial size | 130 |
131 widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete) | |
132 | |
133 widget.getCurrentSize (w,h);// Find the initial size | |
113 w += BORDER_WIDTH * 2; // Adjust for border | 134 w += BORDER_WIDTH * 2; // Adjust for border |
114 h += BORDER_WIDTH * 2; | 135 h += BORDER_WIDTH * 2; |
115 } | 136 } |
116 | 137 |
117 Widget getWidget (widgetID i) { | 138 /** Get/create a widget by ID. |
139 * | |
140 * Should $(I only) be called internally and by sub-widgets! */ | |
141 IWidget getWidget (widgetID i) | |
142 in { | |
143 // widgetData is normally left to be garbage collected after widgets have been created: | |
144 assert (widgetData !is null, "getWidget: widgetData is null"); | |
145 } body { | |
118 // See if it's already been created: | 146 // See if it's already been created: |
119 Widget* p = i in widgets; | 147 IWidget* p = i in widgets; |
120 if (p !is null) return *p; // yes | 148 if (p !is null) return *p; // yes |
121 else { // no | 149 else { // no |
122 int[]* d = i in widgetData; | 150 int[]* d = i in widgetData; |
123 if (d is null) throw new WindowLoadException ("Widget not found"); | 151 if (d is null) throw new WindowLoadException ("Widget not found"); |
124 | 152 |
125 // Throws WidgetDataException (a WindowLoadException) if bad data: | 153 // Throws WidgetDataException (a WindowLoadException) if bad data: |
126 Widget w = createWidget (this, *d); | 154 IWidget w = createWidget (this, *d); |
127 widgets[i] = w; | 155 widgets[i] = w; |
128 return w; | 156 return w; |
129 } | 157 } |
158 } | |
159 | |
160 void requestRedraw () { | |
161 //FIXME | |
130 } | 162 } |
131 | 163 |
132 void draw () { | 164 void draw () { |
133 //BEGIN Window border/back | 165 //BEGIN Window border/back |
134 gl.setColor (0.0f, 0.0f, 0.5f); | 166 gl.setColor (0.0f, 0.0f, 0.5f); |
154 } | 186 } |
155 } | 187 } |
156 void writeAll (ItemDelg dlg) { | 188 void writeAll (ItemDelg dlg) { |
157 } | 189 } |
158 //END Mergetag code | 190 //END Mergetag code |
159 } | 191 |
192 private: | |
193 int[][widgetID] widgetData; // Data for all widgets under this window (deleted after loading) | |
194 IWidget[widgetID] widgets; // List of all widgets under this window (created on demand). | |
195 | |
196 IWidget widget; // The primary widget in this window. | |
197 int x,y; // Window position | |
198 int w,h; // Window size (calculated from Widgets) | |
199 | |
200 const BORDER_WIDTH = 8; // Temporary way to handle window decorations | |
201 | |
202 } |