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 }