Changeset 39:5132301e9ed7
- Timestamp:
- 05/07/08 08:07:03 (8 months ago)
- Files:
-
- mde/gui/Gui.d (modified) (6 diffs)
- mde/gui/exception.d (modified) (2 diffs)
- mde/gui/renderer/SimpleRenderer.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (5 diffs)
- mde/gui/widget/Widget.d (modified) (7 diffs)
- mde/gui/widget/Window.d (modified) (10 diffs)
- mde/gui/widget/createWidget.d (modified) (2 diffs)
- mde/gui/widget/layout.d (modified) (5 diffs)
- mde/scheduler/Scheduler.d (modified) (1 diff)
- mde/scheduler/init2.d (modified) (2 diffs)
- mde/scheduler/initFunctions.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
mde/gui/Gui.d
r36 r39 38 38 import mt = mde.mergetag.exception; 39 39 import mde.mergetag.Reader; 40 import mde.mergetag.Writer; 40 41 import mde.resource.paths; 41 42 … … 57 58 //BEGIN Loading code 58 59 /** Load all windows from the file gui. */ 59 void load (char[] fileName) {60 void load (char[] fileName) { 60 61 if (!confDir.exists (fileName)) { 61 62 logger.error ("Unable to load GUI: no config file!"); … … 65 66 IReader reader; 66 67 try { 67 reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_ ONLY, null, true);68 reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_LOW, null, true); 68 69 reader.dataSecCreator = delegate mt.IDataSection(mt.ID id) { 69 70 return new Window (id); … … 78 79 79 80 // Get the renderer 80 char[]* p = "Renderer"in reader.dataset.header.Arg!(char[]).Arg;81 char[]* p = RENDERER in reader.dataset.header.Arg!(char[]).Arg; 81 82 if (p is null || *p is null) { 82 83 logger.error ("Loading GUI aborted: no renderer specified"); 83 84 return; 84 85 } 85 rend = createRenderer (*p); 86 rendName = *p; 87 rend = createRenderer (rendName); 86 88 87 89 // get list … … 105 107 imde.input.addMouseMotionCallback(&motionEvent); 106 108 } 109 110 void save (char[] fileName) { 111 mt.DataSet ds = new mt.DataSet; 112 113 // Add header: 114 ds.header = new mt.DefaultData; 115 ds.header.Arg!(char[]).Arg[RENDERER] = rendName; 116 117 // Add windows to be saved: 118 foreach (window; windows) 119 ds.sec [window.name] = window; 120 121 try { // Save 122 IWriter writer; 123 writer = confDir.makeMTWriter (fileName, ds); 124 writer.write; 125 } catch (mt.MTException e) { 126 logger.error ("Saving GUI failed:"); 127 logger.error (e.msg); 128 129 return; 130 } 131 } 132 private static const { 133 auto RENDERER = "Renderer"; 134 } 107 135 //END Loading code 108 136 … … 172 200 private: 173 201 Window[] windows; // Windows. First window is "on top", others may be obscured. 174 IRenderer rend; 202 203 IRenderer rend; // Renderer (synonymous with theme) 204 char[] rendName; // Name of renderer; for saving 205 175 206 // callbacks indexed by their frame pointers: 176 207 void delegate(ushort cx, ushort cy, ubyte b, bool state) [void*] clickCallbacks; mde/gui/exception.d
r27 r39 38 38 } 39 39 40 /// Thrown when or createWidgeta Widget class's this() is called with invalid data.40 /// Thrown when createWidget or a Widget class's this() is called with invalid data. 41 41 class WidgetDataException : WindowLoadException 42 42 { … … 48 48 } 49 49 } 50 51 /// Thrown when a Widget class's adjust() is called with invalid data. 52 class MutableDataException : WindowLoadException 53 { 54 this () { // Default, by Widget class's this 55 super ("Bad widget mutable data"); 56 } 57 this (char[] msg) { // From createWidget 58 super (msg); 59 } 60 } mde/gui/renderer/SimpleRenderer.d
r38 r39 30 30 class SimpleRenderer : IRenderer 31 31 { 32 33 34 32 BorderDimensions getBorder (BORDER_TYPES type) { 35 33 BorderDimensions dims; mde/gui/widget/Ifaces.d
r37 r39 21 21 22 22 /** Interface for Window, allowing widgets to call some of Window's methods. 23 *24 * Contains the methods in Window available for widgets to call on their root. */23 * 24 * Contains the methods in Window available for widgets to call on their root. */ 25 25 interface IWindow : IWidget 26 26 { 27 27 /** Widget ID type. Each ID is unique under this window. 28 *29 * Type is int since this is the widget data type. */28 * 29 * Type is int since this is the widget data type. */ 30 30 alias int widgetID; 31 31 32 32 /** Get a widget by ID. 33 * 34 * Returns the widget with the given ID from the Window's widget list. If the widget hasn't yet 35 * been created, creates it using the Window's widget creation data. 36 * 37 * Widgets should never be used more than once (must have a unique parent and position!), and 38 * this function is only intended for widgets to get child-widgets, hence a warning is logged 39 * if a widget is asked for more than once. */ 40 //NOTE: possibly revise: parent isn't actually used any more 41 IWidget makeWidget (widgetID i, IWidget parent); 33 * 34 * Returns the widget with the given ID from the Window's widget list. If the widget hasn't yet 35 * been created, creates it using the Window's widget creation data. */ 36 IWidget makeWidget (widgetID i); 37 38 /** Add widget's saveData to the data to be saved, returning it's widgetID. */ 39 widgetID addCreationData (IWidget widget); 42 40 43 41 /** Get the managing Gui. */ 42 //FIXME: remove and add requestRedraw to allow for only redrawing the window 44 43 IGui gui (); 45 44 … … 52 51 53 52 /** Interface for widgets. 54 * 55 * Note that Window also implements this interface so that widgets can interact with their parent in 56 * a uniform way. 57 * 58 * A widget is a region of a GUI window which handles rendering and user-interaction for itself 59 * and is able to communicate with it's window and parent/child widgets as necessary. 60 * 61 * A widget's constructor should have this prototype: 62 * ---------------------------------- 63 * this (IWindow window, IWidget parent, int[] data); 64 * ---------------------------------- 65 * Where window is the root window (the window to which the widget belongs), parent is the parent 66 * widget, and data is an array of initialisation data. The method should throw a 67 * WidgetDataException (created without parameters) if the data has wrong length or is otherwise 68 * invalid. 69 * 70 * The widget's size should be set either by it's this() method or by the first call to 71 * setSize(). setSize() is called on all widgets immediately after their creation, and throwing an 72 * exception at this point (but not on later calls to setSize) is an acceptible method of failure. 73 */ 53 * 54 * Note that Window also implements this interface so that widgets can interact with their parent 55 * in a uniform way. 56 * 57 * A widget is a region of a GUI window which handles rendering and user-interaction for itself 58 * and is able to communicate with it's window and parent/child widgets as necessary. 59 * 60 * A widget's constructor should have this prototype: 61 * ---------------------------------- 62 * this (IWindow window, int[] data); 63 * ---------------------------------- 64 * Where window is the root window (the window to which the widget belongs) and data is an array of 65 * initialisation data. The method should throw a WidgetDataException (created without parameters) 66 * if the data has wrong length or is otherwise invalid. 67 * 68 * The widget's size should be set either by it's this() method or by the first call to 69 * setSize(). setSize() is called on all widgets immediately after their creation, and throwing an 70 * exception at this point (but not on later calls to setSize) is an acceptible method of failure. 71 */ 74 72 //NOTE: add another this() without the data for default initialization, for the GUI editor? 75 73 interface IWidget 76 74 { 75 //BEGIN Load and save 76 /** Called after creating widgets to adjust size & other mutable attributes from saved data. 77 * 78 * Each widget should call adjust on each of its sub-widgets in turn with data, each time 79 * replacing data by the return value of the call. It should then take its own mutable data 80 * from the beginning of the array and return the remainder of the array. 81 * 82 * Throws: on error, throw a MutableDataException. */ 83 int[] adjust (int[] data); 84 85 /** Output data suitible for recreating the widget (data to be passed to this()). */ 86 int[] getCreationData (); 87 88 /** Output data containing the widget's current adjustments (data to be passed to adjust()). 89 * Should be a concatenation of each sub-widget's mutable data and the widget's own. */ 90 int[] getMutableData (); 91 //END Load and save 92 93 //BEGIN Size and position 77 94 /** is the width / height resizable? 78 95 * … … 90 107 /** Used to adjust the size. 91 108 * 109 * setPosition should always be called after setSize (for layout widgets). Adding this 110 * restriction appears to be the most efficient approach without a lot more tests. 111 * 112 * Implementation: 92 113 * The size should be clamped to the widget's minimal size, i.e. the size set may be larger 93 114 * than that given by the parameters. Conversely, the size should not be reduced to the … … 99 120 /** Set the current position (i.e. called on init and move). */ 100 121 void setPosition (int x, int y); 122 //END Size and position 101 123 102 124 //BEGIN Events 103 125 /** Recursively scan the widget tree to find the widget under (x,y). 104 126 * … … 119 141 * Widget may assume coordinates are on the widget (caller must check). */ 120 142 void clickEvent (ushort cx, ushort cy, ubyte b, bool state); 121 143 //END Events 122 144 123 145 /** Draw, using the stored values of x and y. mde/gui/widget/Widget.d
r37 r39 30 30 abstract class Widget : IWidget 31 31 { 32 // Base this(); all widgets must at least check data.length is correct. 33 this (IWindow wind, int[] data) { 34 window = wind; 35 widgetType = data[0]; 36 } 37 38 // Most widgets don't need to do adjustments based on mutable data, however they usually do 39 // still need to set their size. 40 int[] adjust (int[] data) { 41 setSize (0,0); 42 return data; 43 } 44 45 // Widget type should always be the first value. 46 int[] getCreationData () { 47 return [widgetType]; 48 } 49 // Most widgets don't use mutable data. 50 int[] getMutableData () { 51 return []; 52 } 53 32 54 void getCurrentSize (out int cw, out int ch) { 33 55 cw = w; … … 55 77 56 78 protected: 79 final int widgetType; // the type (stored for saving) 57 80 IWindow window; // the enclosing window 58 81 int x, y; // position … … 61 84 /** A base for fixed-size widgets. */ 62 85 class FixedWidget : Widget { 86 this (IWindow wind, int[] data) { 87 super (wind, data); 88 w = wF = data[1]; 89 h = hF = data[2]; 90 } 91 92 int[] getCreationData () { 93 return [widgetType, wF, hF]; 94 } 95 63 96 bool isWSizable () { return false; } 64 97 bool isHSizable () { return false; } … … 81 114 /** A base for resizable widgets. */ 82 115 class SizableWidget : Widget { 116 this (IWindow wind, int[] data) { 117 super (wind, data); 118 } 119 83 120 bool isWSizable () { return true; } 84 121 bool isHSizable () { return true; } … … 98 135 class FixedBlankWidget : FixedWidget 99 136 { 100 this (IWindow wind, IWidget, int[] data) { 101 if (data.length != 2) throw new WidgetDataException; 102 103 window = wind; 104 105 w = wF = data[0]; 106 h = hF = data[1]; 137 this (IWindow wind, int[] data) { 138 if (data.length != 3) throw new WidgetDataException; 139 super (wind, data); 107 140 } 108 141 } … … 111 144 class SizableBlankWidget : SizableWidget 112 145 { 113 this (IWindow wind, IWidget, int[] data) { 114 if (data.length != 0) throw new WidgetDataException; 115 116 window = wind; 146 this (IWindow wind, int[] data) { 147 if (data.length != 1) throw new WidgetDataException; 148 super (wind, data); 117 149 } 118 150 } … … 125 157 // it is whether the mouse is over the button after being clicked. 126 158 127 this (IWindow wind, IWidget, int[] data) { 128 if (data.length != 2) throw new WidgetDataException; 129 130 window = wind; 131 132 w = wF = data[0]; 133 h = hF = data[1]; 159 this (IWindow wind, int[] data) { 160 if (data.length != 3) throw new WidgetDataException; 161 super (wind, data); 134 162 } 135 163 mde/gui/widget/Window.d
r38 r39 26 26 import mt = mde.mergetag.DataSet; 27 27 import tango.scrapple.text.convert.parseTo : parseTo; 28 // not yet implemented: 29 //import tango.scrapple.text.convert.parseFrom : parseFrom; 28 import tango.scrapple.text.convert.parseFrom : parseFrom; 30 29 31 30 import tango.util.log.Log : Log, Logger; … … 60 59 } body { 61 60 // Check data was loaded: 62 if (widgetData is null) throw new WindowLoadException ("No widget data"); 61 if (widgetData is null || mutableData is null) 62 throw new WindowLoadException ("No widget/mutable data"); 63 63 64 64 gui_ = gui; 65 65 rend = gui.renderer; 66 67 // Create the primary widget (and indirectly all sub-widgets), throwing on error:68 widget = makeWidget (0, this); // primary widget always has ID 0.69 widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete)70 66 71 67 // Get border sizes … … 73 69 resize = rend.getBorder (BORDER_TYPES.WINDOW_RESIZE); 74 70 75 widget.setSize (0,0); // set the minimal size 71 // Create the primary widget (and indirectly all sub-widgets), throwing on error: 72 widget = makeWidget (0); // primary widget always has ID 0. 73 widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete) 74 75 widget.adjust (mutableData); // adjust/set size, etc. 76 mutableData = null; // no longer needed 77 76 78 widget.getCurrentSize (w,h); // and get this size 77 79 w += border.l + border.r; // Adjust for border … … 87 89 //BEGIN Mergetag code 88 90 void addTag (char[] tp, mt.ID id, char[] dt) { 89 if (tp == "int[][int]") { 90 if (id == "widgetData") { 91 // Priority is HIGH_LOW, so don't overwrite data which has already been loaded. 92 if (tp == INTAA) { 93 if (id == WDGD && widgetData == null) { 91 94 widgetData = cast(int[][widgetID]) parseTo!(int[][int]) (dt); 92 95 } 93 } else if (tp == "int") { 94 if (id == "x") { 96 } else if (tp == INTA) { 97 if (id == MD && mutableData == null) { 98 mutableData = parseTo!(int[]) (dt); 99 } 100 } else if (tp == INT) { 101 if (id == X && x == -1) { 95 102 x = parseTo!(int) (dt); 96 } else if (id == "y") {103 } else if (id == Y && y == -1) { 97 104 y = parseTo!(int) (dt); 98 105 } 99 106 } 100 107 } 101 void writeAll (ItemDelg dlg) { 108 void writeAll (ItemDelg dlg) 109 in { 110 assert (widgetData is null, "Window.writeAll: widgetData !is null"); 111 } body { 112 /+ NOTE: currently editing is impossible... 113 if (edited) { // only save the widget creation data if it's been adjusted: 114 addSaveData (widget); // generate widget save data 115 dlg (INTAA, WDGD, parseFrom!(int[][int]) (widgetData)); 116 }+/ 117 // Save mutable data: 118 dlg (INTA, MD, parseFrom!(int[]) (widget.getMutableData)); 119 // Save the window position: 120 dlg (INT, X, parseFrom!(int) (x)); 121 dlg (INT, Y, parseFrom!(int) (y)); 122 } 123 private static const { 124 auto INTAA = "int[][int]"; 125 auto INTA = "int[]"; 126 auto INT = "int"; 127 auto WDGD = "widgetData"; 128 auto MD = "mutableData"; 129 auto X = "x"; 130 auto Y = "y"; 102 131 } 103 132 //END Mergetag code … … 108 137 * 109 138 * Should $(I only) be called internally and by sub-widgets! */ 110 IWidget makeWidget (widgetID i , IWidget parent)139 IWidget makeWidget (widgetID i) 111 140 in { 112 141 // widgetData is normally left to be garbage collected after widgets have been created: … … 121 150 122 151 // Throws WidgetDataException (a WindowLoadException) if bad data: 123 IWidget widg = createWidget (this, parent, *d); 124 widgets ~= widg; 125 return widg; 126 } 127 152 return createWidget (this, *d); 153 } 154 155 /** Add this widget's data to that to be saved, returning it's widgetID. */ 156 widgetID addCreationData (IWidget widget) 157 { 158 widgetID i; 159 if (widgetData is null) 160 i = 0; 161 else 162 i = widgetData.keys[$-1] + 1; 163 164 widgetData[i] = null; // Make sure the same ID doesn't get used by a recursive call 165 widgetData[i] = widget.getCreationData; 166 167 return i; 168 } 169 128 170 IGui gui () { 129 171 return gui_; … … 136 178 137 179 //BEGIN IWidget methods 180 //FIXME: how many of these methods are actually needed/used? 181 int[] adjust (int[]) { // simply not relevant (never used) 182 return []; 183 } 184 int[] getCreationData () { // simply not relevant (never used) 185 return []; 186 } 187 int[] getMutableData () { // simply not relevant (never used) 188 return []; 189 } 190 138 191 bool isWSizable () { 139 192 return widget.isWSizable; … … 201 254 * diagonal resizes). */ 202 255 resizeType = RESIZE.NONE; 203 if (cx < x + border.l) { 204 xDrag = w + cx; 205 resizeType = RESIZE.L; 256 257 if (isWSizable) { 258 if (cx < x + border.l) { 259 xDrag = w + cx; 260 resizeType = RESIZE.L; 261 } 262 else if (cx >= xw - border.r) { 263 xDrag = w - cx; 264 resizeType = RESIZE.R; 265 } 206 266 } 207 else if (cx >= xw - border.r) { 208 xDrag = w - cx; 209 resizeType = RESIZE.R; 210 } 211 if (cy < y + border.t) { 212 yDrag = h + cy; 213 resizeType |= RESIZE.T; 214 } 215 else if (cy >= yh - border.b) { 216 yDrag = h - cy; 217 resizeType |= RESIZE.B; 267 if (isHSizable) { 268 if (cy < y + border.t) { 269 yDrag = h + cy; 270 resizeType |= RESIZE.T; 271 } 272 else if (cy >= yh - border.b) { 273 yDrag = h - cy; 274 resizeType |= RESIZE.B; 275 } 218 276 } 219 277 220 gui_.addClickCallback (&endCallback); 221 gui_.addMotionCallback (&resizeCallback); 278 if (resizeType != RESIZE.NONE) { // only if some valid size is being done 279 gui_.addClickCallback (&endCallback); 280 gui_.addMotionCallback (&resizeCallback); 281 } 222 282 } else { // window is being moved 223 283 xDrag = cx - x; … … 253 313 nw = xDrag - cx; 254 314 if (nw < mw) nw = mw; // clamp 255 setPosition (x + w - nw, y);315 mw = x + w - nw; // reuse 256 316 setSize (nw, h); 317 setPosition (mw, y); 257 318 } 258 319 else if (resizeType & RESIZE.R) { 259 320 setSize (xDrag + cx, h); 321 setPosition (x, y); 260 322 } 261 323 if (resizeType & RESIZE.T) { 262 324 int mh, nh; 263 getMinimalSize (nh, mh); // (only want mh)325 getMinimalSize (nh, mh); 264 326 nh = yDrag - cy; 265 if (nh < mh) nh = mh; // clamp266 setPosition (x, y + h - nh);327 if (nh < mh) nh = mh; 328 mh = y + h - nh; 267 329 setSize (w, nh); 330 setPosition (x, mh); 268 331 } 269 332 else if (resizeType & RESIZE.B) { 270 333 setSize (w, yDrag + cy); 334 setPosition (x, y); 271 335 } 272 336 } … … 285 349 //END Window moving and resizing 286 350 287 char[] name; // The window's name (id from config file) 351 // Load/save data: 352 public char[] name; // The window's name (id from config file) 353 //bool edited = false; // True if any widgets have been edited (excluding scaling) 354 // Data used for saving and loading (null in between): 355 int[][widgetID] widgetData = null;// Data for all widgets under this window 356 int[] mutableData = null; // Widget's mutable data (adjusted sizes, etc.) 357 288 358 IGui gui_; // The gui managing this window 289 290 int[][widgetID] widgetData; // Data for all widgets under this window (deleted after loading) 291 IWidget[] widgets; // List of all widgets under this window (created on demand). Use for saving? 359 IRenderer rend; // The window's renderer 360 292 361 IWidget widget; // The primary widget in this window. 293 362 294 IRenderer rend; // The window's renderer 295 // FIXME: revise which parameters are stored once Gui knows window position 296 int x,y; // Window position 363 int x = -1, y = -1; // Window position 297 364 int w,h; // Window size (calculated from Widgets) 298 365 int xw, yh; // x+w, y+h (frequent use by clickEvent) mde/gui/widget/createWidget.d
r37 r39 25 25 /** Create a widget of type data[0] (see enum WIDGET_TYPES) for _window window, with initialisation 26 26 * data [1..$]. */ 27 IWidget createWidget (IWindow window, IWidget parent,int[] data)27 IWidget createWidget (IWindow window, int[] data) 28 28 in { 29 29 assert (window !is null, "createWidget: window is null"); 30 assert (parent !is null, "createWidget: parent is null");31 30 } body { 32 31 if (data.length < 1) throw new WidgetDataException ("No widget data"); 33 32 int type = data[0]; // type is first element of data 34 data = data[1..$]; // the restis passed to the Widget33 // the whole of data is passed to the Widget 35 34 36 35 mixin (binarySearch ("type", WIDGETS)); … … 101 100 foreach (c; consts) { 102 101 ret ~= "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~ 103 indent(indents+1) ~ "return new " ~ c ~ "Widget (window, parent,data);\n" ~102 indent(indents+1) ~ "return new " ~ c ~ "Widget (window, data);\n" ~ 104 103 indent(indents) ~ "} else "; 105 104 } mde/gui/widget/layout.d
r38 r39 18 18 19 19 import mde.gui.widget.Widget; 20 import mde.gui.exception : WidgetDataException;20 import mde.gui.exception; 21 21 22 22 /** Encapsulates a grid of Widgets. … … 25 25 class GridLayoutWidget : Widget 26 26 { 27 this (IWindow wind, IWidget,int[] data) {27 this (IWindow wind, int[] data) { 28 28 // Get grid size and check data 29 29 // Check sufficient data for rows, cols, and at least one widget: 30 if (data.length < 3) throw new WidgetDataException; 31 rows = data[0]; 32 cols = data[1]; 33 if (data.length != 2 + rows * cols) throw new WidgetDataException; 30 if (data.length < 4) throw new WidgetDataException; 31 super (wind, data); 32 33 rows = data[1]; 34 cols = data[2]; 35 if (data.length != 3 + rows * cols) throw new WidgetDataException; 34 36 /* data.length >= 3 so besides checking the length is correct, this tells us: 35 * rows * cols >= 3 - 2= 1 a free check!37 * rows * cols >= 4 - 3 = 1 a free check! 36 38 * The only thing not checked is whether both rows and cols are negative, which would 37 39 * cause an exception when dynamic arrays are allocated later (and is unlikely). */ 38 39 window = wind;40 40 41 41 // Get all sub-widgets 42 42 subWidgets.length = rows*cols; 43 43 foreach (i, inout subWidget; subWidgets) { 44 subWidget = window.makeWidget (data[i+2], this); 45 } 44 subWidget = window.makeWidget (data[i+3]); 45 } 46 } 47 48 int[] adjust (int[] data) { 49 // Give all sub-widgets their data: 50 foreach (widget; subWidgets) 51 data = widget.adjust (data); 52 if (data.length < rows + cols) throw new MutableDataException; 53 54 /* We basically short-cut setSize by loading previous col/row sizes and doing the final 55 * calculations. There isn't checks that the data is valid/up-to-date... worst case is too 56 * small overlapping widgets or huge ones? 57 * Note: if setSize gets called afterwards, it should have same dimensions and so not do 58 * anything. */ 59 colW = data[0..cols]; 60 rowH = data[cols..rows+cols]; 61 setColRowSizes; 62 w = colW[$-1] + colX[$-1]; 63 h = rowY[$-1] + rowH[$-1]; 64 65 return data[rows+cols..$]; 66 } 67 68 int[] getCreationData () { 69 int[] ret; 70 ret.length = 3 + subWidgets.length; 71 72 ret [0..3] = [widgetType, rows, cols]; // first data 73 74 foreach (i,widget; subWidgets) // sub widgets 75 ret[i+3] = window.addCreationData (widget); 76 77 return ret; 78 } 79 int[] getMutableData () { 80 int[] ret; 81 foreach (widget; subWidgets) 82 ret ~= widget.getMutableData; 83 84 ret ~= colW ~ rowH; 85 return ret; 46 86 } 47 87 … … 109 149 110 150 void setSize (int nw, int nh) { 151 /* For each of width and height, there are several cases: 152 * [new value is] more than old value 153 * -> enlarge any row/column 154 * same as old value 155 * -> do nothing 156 * more than min but less than current value 157 * -> find an enlarged row/col and reduce size 158 * -> repeat if necessary 159 * minimal value or less 160 * -> clamp to min and use min col/row sizes 161 */ 162 // FIXME: implement! 163 111 164 // Step 1: calculate the minimal row/column sizes. 112 165 alias w mw; // no need for extra vars, just use these … … 133 186 } 134 187 135 // Step 3: set each sub-widget's size.136 foreach (i,widget; subWidgets)137 widget.setSize (colW[i % cols], rowH[i / cols]);138 139 188 w = nw; 140 189 h = nh; 141 190 191 // Step 3: set each sub-widget's size. 142 192 // Step 4: calculate the column and row positions 143 colX.length = cols; 144 rowY.length = rows; 145 int spacing = window.renderer.layoutSpacing; 146 147 int cum = 0; 148 foreach (i, x; rowH) { 149 rowY[i] = cum; 150 cum += x + spacing; 151 } 152 153 cum = 0; 154 foreach (i, x; colW) { 155 colX[i] = cum; 156 cum += x + spacing; 157 } 193 setColRowSizes; 158 194 159 195 // Step 5: position needs resetting 160 // FIXME: find a more efficient method of doing this? 161 // maybe setPosition should ALWAYS be called after setSize? 162 setPosition (x,y); 196 // Currently this happens by specifying that setPosition should be run after setSize. 163 197 } 164 198 … … 229 263 } 230 264 265 void setColRowSizes () { 266 // Calculate column and row locations: 267 colX.length = cols; 268 rowY.length = rows; 269 int spacing = window.renderer.layoutSpacing; 270 271 int cum = 0; 272 foreach (i, x; rowH) { 273 rowY[i] = cum; 274 cum += x + spacing; 275 } 276 277 cum = 0; 278 foreach (i, x; colW) { 279 colX[i] = cum; 280 cum += x + spacing; 281 } 282 283 // Tell subwidgets their new sizes: 284 foreach (i,widget; subWidgets) 285 widget.setSize (colW[i % cols], rowH[i / cols]); 286 } 287 231 288 protected: 232 289 int cols, rows; // number of cells in grid mde/scheduler/Scheduler.d
r30 r39 120 120 * IDs. */ 121 121 ID getNewID () { 122 // For now use a very simple method to find a vacant ID: iterate 123 for (ID i = 0xF000_0000; i < ID.max; ++i) 124 if ((i in funcs) is null) 125 return i; 122 if (funcs.length == 0) return 0xF000_0000; // otherwise would get an out-of-bounds error 123 // Take the last used ID and add one, making sure it's at least 0xF000_0000. 124 // Don't bother checking if it's out of bounds since there's 2^28 available IDs. 125 ID i = funcs.keys[$-1] + 1; 126 if (i < 0xF000_0000) i = 0xF000_0000; 127 return i; 126 128 } 127 129 mde/scheduler/init2.d
r36 r39 51 51 void guiLoad () { // init func 52 52 try { 53 gui.load ("gui"); 53 gui.load (GUI); 54 cleanup.addFunc (&guiSave, "guiSave"); 54 55 } catch (Exception e) { 55 56 logger.fatal ("guiLoad failed: " ~ e.msg); … … 57 58 } 58 59 } 60 void guiSave () { // cleanup func 61 try { 62 gui.save (GUI); 63 } catch (Exception e) { 64 logger.fatal ("guiSave failed: " ~ e.msg); 65 setInitFailure; 66 } 67 } 68 private const GUI = "gui"; 59 69 60 70 void initInput () { // init func mde/scheduler/initFunctions.d
r32 r39 66 66 67 67 InitStage init; // all functions called during init (all should be thread-safe) 68 //FIXME: implement: 69 InitStage save; // all functions to be called to save data (possible to run more than once) 68 70 InitStage cleanup; // all functions called during cleanup (all should be thread-safe) 69 71
