# HG changeset patch # User Diggory Hardy # Date 1217347882 -3600 # Node ID 3dfd934100f722eb8b5a92c1de0087be12d86cd8 # Parent 65780e0e48e6f4b3acf722364b078db5c22778ff Continuing widget data changes started in last commit: all previous widgets work again now (but lacking saving). diff -r 65780e0e48e6 -r 3dfd934100f7 data/conf/gui.mtt --- a/data/conf/gui.mtt Mon Jul 28 18:49:18 2008 +0100 +++ b/data/conf/gui.mtt Tue Jul 29 17:11:22 2008 +0100 @@ -1,8 +1,15 @@ {MT01} - + +{Working} + + + + + + {Basic} - + !{ {W1} diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/WidgetData.d --- a/mde/gui/WidgetData.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/WidgetData.d Tue Jul 29 17:11:22 2008 +0100 @@ -289,7 +289,7 @@ if (strs.length != 2) throw new ParseException ("Not two components"); ints = parseTo!(int[]) (strs[0]); - str = parseTo!(char[]) (strs[1]); + strings = parseTo!(char[][]) (strs[1]); } widgetData[id] = data; } @@ -329,7 +329,7 @@ // Note: is a very simple form of struct serialization with(data) { dlg ("WidgetData", id, - parseFrom!(int[]) (ints) ~ ',' ~ parseFrom!(char[]) (str) ); + parseFrom!(int[]) (ints) ~ ',' ~ parseFrom!(char[][]) (strings) ); } } } diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/Ifaces.d --- a/mde/gui/widget/Ifaces.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/Ifaces.d Tue Jul 29 17:11:22 2008 +0100 @@ -268,6 +268,6 @@ *************************************************************************************************/ struct WidgetData { - int[] ints; // An array of integer data - char[] str; // One string + int[] ints; + char[][] strings; } diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/TextWidget.d --- a/mde/gui/widget/TextWidget.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/TextWidget.d Tue Jul 29 17:11:22 2008 +0100 @@ -60,6 +60,7 @@ } /// Basic text widget +// FIXME (content, creation for different types) class ContentWidget(ContentT : IContent) : Widget { /** Constructor for a widget containing [fixed] content. @@ -69,8 +70,8 @@ * where contentID is an ID for the string ID of the contained content * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */ this (IWidgetManager mgr, WidgetData data) { - if (data.length != 2) throw new WidgetDataException; - text.set (data.str, data[1]); + WDCheck (data, 2, 1); + text.set (data.strings[0], data.ints[1]); text.getDimensions (mw, mh); super (mgr,data); } @@ -118,11 +119,11 @@ /// Basic text widget class ContentOptionWidget : Widget { - this (IWindow wind, int[] data, IContent c) { - if (data.length != 2) throw new WidgetDataException; - content.set (c, data[1]); + this (IWidgetManager mgr, WidgetData data, IContent c) { + WDCheck (data, 2, 0); + content.set (c, data.ints[1]); content.getDimensions (mw, mh); - super (wind,data); + super (mgr,data); } void draw () { diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/Widget.d --- a/mde/gui/widget/Widget.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/Widget.d Tue Jul 29 17:11:22 2008 +0100 @@ -13,21 +13,43 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** GUI Widget module. +/************************************************************************************************* + * GUI Widget module. * * This module contains some base widget classes suitable for widget classes to inherit. However, - * inheriting one of them is by no means necessary for a widget so long as the IWidget interface is - * implemented. */ + * inheriting one of them is by no means necessary for a widget so long as the IWidget interface + * is implemented. + *************************************************************************************************/ module mde.gui.widget.Widget; public import mde.gui.widget.Ifaces; import mde.gui.renderer.IRenderer; +import mde.gui.exception; -/** An abstract base widget class. -* -* This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a -* useful basic implementation for widgets. Widgets need not inherit these (they only need implement -* IWidget); they are simply provided for convenience and to promote code reuse. */ + +/************************************************************************************************* + * Widgets may use WDCheck as a utility to check what data holds. Its use is encouraged, so that + * the checks can easily be updated should WidgetData be changed. + * + * Params: + * data = the WidgetData to check lengths of + * n_ints = number of integers wanted + * n_strings= number of strings (default 0 since not all widgets use strings) + *************************************************************************************************/ +void WDCheck (WidgetData data, size_t n_ints, size_t n_strings = 0) { + if (data.ints.length != n_ints || + data.strings.length != n_strings) + throw new WidgetDataException; +} + + +/************************************************************************************************* + * An abstract base widget class. + * + * This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a + * useful basic implementation for widgets. Widgets need not inherit these (they only need + * implement IWidget); they are simply provided for convenience and to promote code reuse. + *************************************************************************************************/ abstract class Widget : IChildWidget { //BEGIN Load and save diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/createWidget.d --- a/mde/gui/widget/createWidget.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/createWidget.d Tue Jul 29 17:11:22 2008 +0100 @@ -20,9 +20,9 @@ import mde.gui.exception : WidgetDataException; // Widgets to create: -//import mde.gui.widget.layout; +import mde.gui.widget.layout; import mde.gui.widget.miscWidgets; -//import mde.gui.widget.TextWidget; +import mde.gui.widget.TextWidget; /** Create a widget of type data[0] (see enum WIDGET_TYPES) under manager mgr, with initialisation * data [1..$]. */ @@ -56,6 +56,7 @@ LAYOUT = 0x8000, // is a layout widget (i.e. has sub-widgets)? // Use widget names rather than usual capitals convention + Unnamed = 0x0, // Only for use by widgets not created with createWidget // blank: 0x1 FixedBlank = 0x1, @@ -77,12 +78,12 @@ // Only used for binarySearch algorithm generation; must be ordered by numerical values. const char[][] WIDGETS = [ "FixedBlank", - //"Text", - //"Int", + "Text", + "Int", "SizableBlank", "Button", - //"GridLayout", - /+"TrialContentLayout"+/]; + "GridLayout", + "TrialContentLayout"]; /* Generates a binary search algorithm. */ char[] binarySearch (char[] var, char[][] consts) { diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/layout.d --- a/mde/gui/widget/layout.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/layout.d Tue Jul 29 17:11:22 2008 +0100 @@ -48,27 +48,38 @@ * [widgetID, r, c, w11, w12, ..., w1c, ..., wr1, ..., wrc] * where r and c are the number of rows and columns, and wij is the ID (from parent Window's * list) for the widget in row i and column j. The number of parameters must be r*c + 3. */ - this (IWindow wind, int[] data) { + this (IWidgetManager mgr, WidgetData data) { // Get grid size and check data - // Check sufficient data for rows, cols, and at least one widget: - if (data.length < 4) throw new WidgetDataException; + // Check sufficient data for rows, cols, and possibly row/col widths. + if (data.ints.length < 3) throw new WidgetDataException; - rows = data[1]; - cols = data[2]; - if (data.length != 3 + rows * cols) throw new WidgetDataException; - /* data.length >= 4 so besides checking the length is correct, this tells us: - * rows * cols >= 4 - 3 = 1 a free check! - * The only thing not checked is whether both rows and cols are negative, which would - * cause an exception when dynamic arrays are allocated by genCachedConstructionData, which - * is an acceptible method of failure (and is unlikely anyway). */ + rows = data.ints[1]; + cols = data.ints[2]; + // Check: at least one sub-widget, ints length == 3 or also contains row & col widths, + // strings' length is correct: + if (rows < 1 || cols < 1 || + (data.ints.length != 3 && data.ints.length != 3 + rows + cols) || + data.strings.length != rows * cols) + throw new WidgetDataException; // Get all sub-widgets subWidgets.length = rows*cols; foreach (i, ref subWidget; subWidgets) { - subWidget = wind.makeWidget (data[i+3]); + subWidget = mgr.makeWidget (data.strings[i]); } - super (wind, data); + + super (mgr, data); + + if (data.ints.length == 3 + rows + cols) { + col.setCheck (cast(wdim[]) data.ints[3..cols+3]); + row.setCheck (cast(wdim[]) data.ints[cols+3..$]); + } else { + col.dupMin; + row.dupMin; + } + adjustCache; } + /+FIXME /** Return construction data to recreate this GridLayoutWidget. */ int[] getCreationData () { int[] ret; @@ -80,7 +91,7 @@ ret[i+3] = window.addCreationData (widget); return ret; - } + }+/ } @@ -89,10 +100,10 @@ *************************************************************************************************/ class TrialContentLayoutWidget : GridWidget { - this (IWindow wind, int[] data) { + this (IWidgetManager mgr, WidgetData data) { debug scope (failure) logger.warn ("TrialContentLayoutWidget: failure"); - if (data.length != 3) throw new WidgetDataException; + WDCheck (data, 2); OptionList optsList = OptionList.trial(); rows = optsList.list.length; @@ -100,15 +111,23 @@ // Get all sub-widgets subWidgets.length = rows*cols; + WidgetData COWData; + COWData.ints = [0, data.ints[1]]; foreach (i, c; optsList.list) { - subWidgets[i] = new ContentOptionWidget (wind, data[1..3], c); + subWidgets[i] = new ContentOptionWidget (mgr, COWData, c); } - super (wind, data); + super (mgr, data); + + // Set col/row widths to minimals. + col.dupMin; + row.dupMin; + adjustCache; } + /+FIXME int[] getCreationData () { return [widgetType]; - } + }+/ private: OptionList optsList; @@ -130,11 +149,14 @@ //BEGIN Creation & saving /** Partial constructor for a grid layout widget. * - * Deriving classes should check data length, and set rows, cols, and the subWidgets array, + * Deriving classes should check data lengths, and set rows, cols, and the subWidgets array, * before calling this super constructor. (If it's necessary to call super(...) first, - * the call to genCachedConstructionData can be moved to the derived this() methods.) */ - protected this (IWindow wind, int[] data) { - super (wind, data); + * the call to genCachedConstructionData can be moved to the derived this() methods.) + * + * Derived constructors should call either dupMin or setCheck on col and row, and then call + * adjustCache, after calling this. */ + protected this (IWidgetManager mgr, WidgetData data) { + super (mgr, data); // Needn't be set before genCachedConstructionData is called: col.setColWidth = &setColWidth; @@ -144,34 +166,6 @@ genCachedConstructionData; } - /** This implementation of adjust() does two things: - * 1. Pass adjust data on to sub-widgets - * 2. Set the size, from the adjust data if possible - * - * Can be overridden (probably along with getMutableData()) if a different implementation is - * wanted. adjustCache() may still be useful. */ - int[] adjust (int[] data) { - // Give all sub-widgets their data: - foreach (widget; subWidgets) - data = widget.adjust (data); - - /** We basically short-cut setSize by loading previous col/row sizes and doing the final - * calculations. - * Note: if setSize gets called afterwards, it should have same dimensions and so not do - * anything. */ - int lenUsed = 0; - if (data.length < rows + cols) { // data error; use defaults - col.dupMin; - row.dupMin; - } else { // sufficient data - lenUsed = rows+cols; - col.setCheck (cast(wdim[])data[0..cols]); - row.setCheck (cast(wdim[])data[cols..lenUsed]); - } - - adjustCache(); - return data[lenUsed..$]; - } /** Generates cached mutable data. * * Should be called by adjust() after setting col and row widths (currently via dupMin or @@ -189,6 +183,7 @@ widget.setHeight (row.width[i / cols], -1); } } + /+ FIXME - saving /** Returns sub-widget mutable data along with column widths and row heights, as used by * adjust(). */ int[] getMutableData () { @@ -197,7 +192,7 @@ ret ~= widget.getMutableData; return ret ~ cast(int[])col.width ~ cast(int[])row.width; - } + }+/ //END Creation & saving //BEGIN Size & position @@ -234,7 +229,7 @@ // Find the relevant widget. - IWidget getWidget (wdim cx, wdim cy) { + IChildWidget getWidget (wdim cx, wdim cy) { debug scope (failure) logger.warn ("getWidget: failure"); // Find row/column: @@ -263,8 +258,8 @@ dragX = cx; dragY = cy; - window.gui.addClickCallback (&endCallback); - window.gui.addMotionCallback (&resizeCallback); + mgr.addClickCallback (&endCallback); + mgr.addMotionCallback (&resizeCallback); } } @@ -284,7 +279,7 @@ * rows, cols and subWidgets must be set before calling. */ void genCachedConstructionData () { // Will only change if renderer changes: - col.spacing = row.spacing = window.renderer.layoutSpacing; + col.spacing = row.spacing = mgr.renderer.layoutSpacing; // Calculate the minimal column and row sizes: // set length, making sure the arrays are initialised to zero: @@ -302,7 +297,7 @@ // Calculate the overall minimal size, starting with the spacing: - mh = window.renderer.layoutSpacing; // use mh temporarily + mh = mgr.renderer.layoutSpacing; // use mh temporarily mw = mh * cast(wdim)(cols - 1); mh *= cast(wdim)(rows - 1); @@ -370,11 +365,11 @@ foreach (i,widget; subWidgets) widget.setPosition (x + col.pos[i % cols], y + row.pos[i / cols]); - window.requestRedraw; + mgr.requestRedraw; } bool endCallback (wdabs cx, wdabs cy, ubyte b, bool state) { if (b == 1 && state == false) { - window.gui.removeCallbacks (cast(void*) this); + mgr.removeCallbacks (cast(void*) this); return true; // we've handled the up-click } return false; // we haven't handled it @@ -390,7 +385,7 @@ /* All widgets in the grid, by row. Order: [ 0 1 ] * [ 2 3 ] */ - IWidget[] subWidgets; + IChildWidget[] subWidgets; /* Widths, positions, etc., either of columns or of rows * @@ -491,7 +486,7 @@ */ wdim adjustCellSizes (wdim diff, myDiff start, int incr) in { - // Could occur if adjust isn't called first, but this would be a code error: + // Could occur if constructor doesn't call dupMin/setCheck (code error): assert (width !is null, "adjustCellSizes: width is null"); // Most likely if passed negative when sizing is disabled: assert (start >= 0 && start < minWidth.length, "adjustCellSizes: invalid start"); diff -r 65780e0e48e6 -r 3dfd934100f7 mde/gui/widget/miscWidgets.d --- a/mde/gui/widget/miscWidgets.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/gui/widget/miscWidgets.d Tue Jul 29 17:11:22 2008 +0100 @@ -27,7 +27,7 @@ class FixedBlankWidget : FixedWidget { this (IWidgetManager mgr, WidgetData data) { - if (data.ints.length != 3) throw new WidgetDataException; + WDCheck (data, 3); super (mgr, data); } @@ -42,7 +42,7 @@ class SizableBlankWidget : SizableWidget { this (IWidgetManager mgr, WidgetData data) { - if (data.ints.length != 1) throw new WidgetDataException; + WDCheck (data, 1); super (mgr, data); } @@ -61,7 +61,7 @@ // it is whether the mouse is over the button after being clicked. this (IWidgetManager mgr, WidgetData data) { - if (data.ints.length != 3) throw new WidgetDataException; + WDCheck (data, 3); super (mgr, data); } diff -r 65780e0e48e6 -r 3dfd934100f7 mde/setup/Init.d --- a/mde/setup/Init.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/setup/Init.d Tue Jul 29 17:11:22 2008 +0100 @@ -262,7 +262,7 @@ const LOG_F_START = " - running"; const LOG_F_END = " - completed"; const LOG_F_BAD = " - failed"; - const LOG_F_FAIL = " - failed: "; + const LOG_F_FAIL = " - exception: "; /* Runs all functions consecutively, first-to-last. * If any function fails, halts immediately. */ void runStageForward (InitStage s) { diff -r 65780e0e48e6 -r 3dfd934100f7 mde/setup/sdl.d --- a/mde/setup/sdl.d Mon Jul 28 18:49:18 2008 +0100 +++ b/mde/setup/sdl.d Tue Jul 29 17:11:22 2008 +0100 @@ -178,6 +178,7 @@ void cleanupSDL () { // cleanup func closeJoysticks(); + logger.trace ("cleanupSDL - middle"); SDL_Quit(); }