Changeset 77:3dfd934100f7
- Timestamp:
- 07/29/08 12:11:22
(5 months ago)
- Author:
- Diggory Hardy <diggory.hardy@gmail.com>
- branch:
- default
- Message:
Continuing widget data changes started in last commit: all previous widgets work again now (but lacking saving).
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r75 |
r77 |
|
| 1 | 1 | {MT01} |
|---|
| 2 | 2 | <char[]|Renderer="Simple"> |
|---|
| 3 | | <char[]|Design="Basic"> |
|---|
| | 3 | <char[]|Design="Working"> |
|---|
| | 4 | {Working} |
|---|
| | 5 | <WidgetData|root=[0xB004,3,3],["square","blank","square","blank","content","blank","square","blank","square"]> |
|---|
| | 6 | <WidgetData|square=[0x1,6,6],[]> |
|---|
| | 7 | <WidgetData|content=[0xB004,3,2],["blank","button","blank","blank","blank","opts"]> |
|---|
| | 8 | <WidgetData|button=[0x4010,200,200],[]> |
|---|
| | 9 | <WidgetData|blank=[0x3001],[]> |
|---|
| | 10 | <WidgetData|opts=[0xB005, 0xfe8c00],[]> |
|---|
| 4 | 11 | {Basic} |
|---|
| 5 | | <WidgetData|root=[0x4010,200,200],""> |
|---|
| | 12 | <WidgetData|root=[0x21,0x90D970],["A string!"]> |
|---|
| 6 | 13 | !{ |
|---|
| 7 | 14 | {W1} |
|---|
| r76 |
r77 |
|
| 290 | 290 | throw new ParseException ("Not two components"); |
|---|
| 291 | 291 | ints = parseTo!(int[]) (strs[0]); |
|---|
| 292 | | str = parseTo!(char[]) (strs[1]); |
|---|
| | 292 | strings = parseTo!(char[][]) (strs[1]); |
|---|
| 293 | 293 | } |
|---|
| 294 | 294 | widgetData[id] = data; |
|---|
| … | … | |
| 330 | 330 | with(data) { |
|---|
| 331 | 331 | dlg ("WidgetData", id, |
|---|
| 332 | | parseFrom!(int[]) (ints) ~ ',' ~ parseFrom!(char[]) (str) ); |
|---|
| | 332 | parseFrom!(int[]) (ints) ~ ',' ~ parseFrom!(char[][]) (strings) ); |
|---|
| 333 | 333 | } |
|---|
| 334 | 334 | } |
|---|
| r76 |
r77 |
|
| 269 | 269 | struct WidgetData |
|---|
| 270 | 270 | { |
|---|
| 271 | | int[] ints; // An array of integer data |
|---|
| 272 | | char[] str; // One string |
|---|
| 273 | | } |
|---|
| | 271 | int[] ints; |
|---|
| | 272 | char[][] strings; |
|---|
| | 273 | } |
|---|
| r75 |
r77 |
|
| 61 | 61 | |
|---|
| 62 | 62 | /// Basic text widget |
|---|
| | 63 | // FIXME (content, creation for different types) |
|---|
| 63 | 64 | class ContentWidget(ContentT : IContent) : Widget |
|---|
| 64 | 65 | { |
|---|
| … | … | |
| 70 | 71 | * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */ |
|---|
| 71 | 72 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 72 | | if (data.length != 2) throw new WidgetDataException; |
|---|
| 73 | | text.set (data.str, data[1]); |
|---|
| | 73 | WDCheck (data, 2, 1); |
|---|
| | 74 | text.set (data.strings[0], data.ints[1]); |
|---|
| 74 | 75 | text.getDimensions (mw, mh); |
|---|
| 75 | 76 | super (mgr,data); |
|---|
| … | … | |
| 119 | 120 | class ContentOptionWidget : Widget |
|---|
| 120 | 121 | { |
|---|
| 121 | | this (IWindow wind, int[] data, IContent c) { |
|---|
| 122 | | if (data.length != 2) throw new WidgetDataException; |
|---|
| 123 | | content.set (c, data[1]); |
|---|
| | 122 | this (IWidgetManager mgr, WidgetData data, IContent c) { |
|---|
| | 123 | WDCheck (data, 2, 0); |
|---|
| | 124 | content.set (c, data.ints[1]); |
|---|
| 124 | 125 | content.getDimensions (mw, mh); |
|---|
| 125 | | super (wind,data); |
|---|
| | 126 | super (mgr,data); |
|---|
| 126 | 127 | } |
|---|
| 127 | 128 | |
|---|
| r76 |
r77 |
|
| 14 | 14 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
|---|
| 15 | 15 | |
|---|
| 16 | | /** GUI Widget module. |
|---|
| | 16 | /************************************************************************************************* |
|---|
| | 17 | * GUI Widget module. |
|---|
| 17 | 18 | * |
|---|
| 18 | 19 | * This module contains some base widget classes suitable for widget classes to inherit. However, |
|---|
| 19 | | * inheriting one of them is by no means necessary for a widget so long as the IWidget interface is |
|---|
| 20 | | * implemented. */ |
|---|
| | 20 | * inheriting one of them is by no means necessary for a widget so long as the IWidget interface |
|---|
| | 21 | * is implemented. |
|---|
| | 22 | *************************************************************************************************/ |
|---|
| 21 | 23 | module mde.gui.widget.Widget; |
|---|
| 22 | 24 | |
|---|
| 23 | 25 | public import mde.gui.widget.Ifaces; |
|---|
| 24 | 26 | import mde.gui.renderer.IRenderer; |
|---|
| | 27 | import mde.gui.exception; |
|---|
| 25 | 28 | |
|---|
| 26 | | /** An abstract base widget class. |
|---|
| 27 | | * |
|---|
| 28 | | * This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a |
|---|
| 29 | | * useful basic implementation for widgets. Widgets need not inherit these (they only need implement |
|---|
| 30 | | * IWidget); they are simply provided for convenience and to promote code reuse. */ |
|---|
| | 29 | |
|---|
| | 30 | /************************************************************************************************* |
|---|
| | 31 | * Widgets may use WDCheck as a utility to check what data holds. Its use is encouraged, so that |
|---|
| | 32 | * the checks can easily be updated should WidgetData be changed. |
|---|
| | 33 | * |
|---|
| | 34 | * Params: |
|---|
| | 35 | * data = the WidgetData to check lengths of |
|---|
| | 36 | * n_ints = number of integers wanted |
|---|
| | 37 | * n_strings= number of strings (default 0 since not all widgets use strings) |
|---|
| | 38 | *************************************************************************************************/ |
|---|
| | 39 | void WDCheck (WidgetData data, size_t n_ints, size_t n_strings = 0) { |
|---|
| | 40 | if (data.ints.length != n_ints || |
|---|
| | 41 | data.strings.length != n_strings) |
|---|
| | 42 | throw new WidgetDataException; |
|---|
| | 43 | } |
|---|
| | 44 | |
|---|
| | 45 | |
|---|
| | 46 | /************************************************************************************************* |
|---|
| | 47 | * An abstract base widget class. |
|---|
| | 48 | * |
|---|
| | 49 | * This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a |
|---|
| | 50 | * useful basic implementation for widgets. Widgets need not inherit these (they only need |
|---|
| | 51 | * implement IWidget); they are simply provided for convenience and to promote code reuse. |
|---|
| | 52 | *************************************************************************************************/ |
|---|
| 31 | 53 | abstract class Widget : IChildWidget |
|---|
| 32 | 54 | { |
|---|
| r75 |
r77 |
|
| 21 | 21 | |
|---|
| 22 | 22 | // Widgets to create: |
|---|
| 23 | | //import mde.gui.widget.layout; |
|---|
| | 23 | import mde.gui.widget.layout; |
|---|
| 24 | 24 | import mde.gui.widget.miscWidgets; |
|---|
| 25 | | //import mde.gui.widget.TextWidget; |
|---|
| | 25 | import mde.gui.widget.TextWidget; |
|---|
| 26 | 26 | |
|---|
| 27 | 27 | /** Create a widget of type data[0] (see enum WIDGET_TYPES) under manager mgr, with initialisation |
|---|
| … | … | |
| 57 | 57 | |
|---|
| 58 | 58 | // Use widget names rather than usual capitals convention |
|---|
| | 59 | Unnamed = 0x0, // Only for use by widgets not created with createWidget |
|---|
| 59 | 60 | |
|---|
| 60 | 61 | // blank: 0x1 |
|---|
| … | … | |
| 78 | 79 | const char[][] WIDGETS = [ |
|---|
| 79 | 80 | "FixedBlank", |
|---|
| 80 | | //"Text", |
|---|
| 81 | | //"Int", |
|---|
| | 81 | "Text", |
|---|
| | 82 | "Int", |
|---|
| 82 | 83 | "SizableBlank", |
|---|
| 83 | 84 | "Button", |
|---|
| 84 | | //"GridLayout", |
|---|
| 85 | | /+"TrialContentLayout"+/]; |
|---|
| | 85 | "GridLayout", |
|---|
| | 86 | "TrialContentLayout"]; |
|---|
| 86 | 87 | |
|---|
| 87 | 88 | /* Generates a binary search algorithm. */ |
|---|
| r72 |
r77 |
|
| 49 | 49 | * where r and c are the number of rows and columns, and wij is the ID (from parent Window's |
|---|
| 50 | 50 | * list) for the widget in row i and column j. The number of parameters must be r*c + 3. */ |
|---|
| 51 | | this (IWindow wind, int[] data) { |
|---|
| | 51 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 52 | 52 | // Get grid size and check data |
|---|
| 53 | | // Check sufficient data for rows, cols, and at least one widget: |
|---|
| 54 | | if (data.length < 4) throw new WidgetDataException; |
|---|
| 55 | | |
|---|
| 56 | | rows = data[1]; |
|---|
| 57 | | cols = data[2]; |
|---|
| 58 | | if (data.length != 3 + rows * cols) throw new WidgetDataException; |
|---|
| 59 | | /* data.length >= 4 so besides checking the length is correct, this tells us: |
|---|
| 60 | | * rows * cols >= 4 - 3 = 1 a free check! |
|---|
| 61 | | * The only thing not checked is whether both rows and cols are negative, which would |
|---|
| 62 | | * cause an exception when dynamic arrays are allocated by genCachedConstructionData, which |
|---|
| 63 | | * is an acceptible method of failure (and is unlikely anyway). */ |
|---|
| | 53 | // Check sufficient data for rows, cols, and possibly row/col widths. |
|---|
| | 54 | if (data.ints.length < 3) throw new WidgetDataException; |
|---|
| | 55 | |
|---|
| | 56 | rows = data.ints[1]; |
|---|
| | 57 | cols = data.ints[2]; |
|---|
| | 58 | // Check: at least one sub-widget, ints length == 3 or also contains row & col widths, |
|---|
| | 59 | // strings' length is correct: |
|---|
| | 60 | if (rows < 1 || cols < 1 || |
|---|
| | 61 | (data.ints.length != 3 && data.ints.length != 3 + rows + cols) || |
|---|
| | 62 | data.strings.length != rows * cols) |
|---|
| | 63 | throw new WidgetDataException; |
|---|
| 64 | 64 | |
|---|
| 65 | 65 | // Get all sub-widgets |
|---|
| 66 | 66 | subWidgets.length = rows*cols; |
|---|
| 67 | 67 | foreach (i, ref subWidget; subWidgets) { |
|---|
| 68 | | subWidget = wind.makeWidget (data[i+3]); |
|---|
| 69 | | } |
|---|
| 70 | | super (wind, data); |
|---|
| 71 | | } |
|---|
| | 68 | subWidget = mgr.makeWidget (data.strings[i]); |
|---|
| | 69 | } |
|---|
| | 70 | |
|---|
| | 71 | super (mgr, data); |
|---|
| | 72 | |
|---|
| | 73 | if (data.ints.length == 3 + rows + cols) { |
|---|
| | 74 | col.setCheck (cast(wdim[]) data.ints[3..cols+3]); |
|---|
| | 75 | row.setCheck (cast(wdim[]) data.ints[cols+3..$]); |
|---|
| | 76 | } else { |
|---|
| | 77 | col.dupMin; |
|---|
| | 78 | row.dupMin; |
|---|
| | 79 | } |
|---|
| | 80 | adjustCache; |
|---|
| | 81 | } |
|---|
| | 82 | /+FIXME |
|---|
| 72 | 83 | /** Return construction data to recreate this GridLayoutWidget. */ |
|---|
| 73 | 84 | int[] getCreationData () { |
|---|
| … | … | |
| 81 | 92 | |
|---|
| 82 | 93 | return ret; |
|---|
| 83 | | } |
|---|
| | 94 | }+/ |
|---|
| 84 | 95 | } |
|---|
| 85 | 96 | |
|---|
| … | … | |
| 90 | 101 | class TrialContentLayoutWidget : GridWidget |
|---|
| 91 | 102 | { |
|---|
| 92 | | this (IWindow wind, int[] data) { |
|---|
| | 103 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 93 | 104 | debug scope (failure) |
|---|
| 94 | 105 | logger.warn ("TrialContentLayoutWidget: failure"); |
|---|
| 95 | | if (data.length != 3) throw new WidgetDataException; |
|---|
| | 106 | WDCheck (data, 2); |
|---|
| 96 | 107 | |
|---|
| 97 | 108 | OptionList optsList = OptionList.trial(); |
|---|
| … | … | |
| 101 | 112 | // Get all sub-widgets |
|---|
| 102 | 113 | subWidgets.length = rows*cols; |
|---|
| | 114 | WidgetData COWData; |
|---|
| | 115 | COWData.ints = [0, data.ints[1]]; |
|---|
| 103 | 116 | foreach (i, c; optsList.list) { |
|---|
| 104 | | subWidgets[i] = new ContentOptionWidget (wind, data[1..3], c); |
|---|
| 105 | | } |
|---|
| 106 | | super (wind, data); |
|---|
| 107 | | } |
|---|
| 108 | | |
|---|
| | 117 | subWidgets[i] = new ContentOptionWidget (mgr, COWData, c); |
|---|
| | 118 | } |
|---|
| | 119 | super (mgr, data); |
|---|
| | 120 | |
|---|
| | 121 | // Set col/row widths to minimals. |
|---|
| | 122 | col.dupMin; |
|---|
| | 123 | row.dupMin; |
|---|
| | 124 | adjustCache; |
|---|
| | 125 | } |
|---|
| | 126 | |
|---|
| | 127 | /+FIXME |
|---|
| 109 | 128 | int[] getCreationData () { |
|---|
| 110 | 129 | return [widgetType]; |
|---|
| 111 | | } |
|---|
| | 130 | }+/ |
|---|
| 112 | 131 | |
|---|
| 113 | 132 | private: |
|---|
| … | … | |
| 131 | 150 | /** Partial constructor for a grid layout widget. |
|---|
| 132 | 151 | * |
|---|
| 133 | | * Deriving classes should check data length, and set rows, cols, and the subWidgets array, |
|---|
| | 152 | * Deriving classes should check data lengths, and set rows, cols, and the subWidgets array, |
|---|
| 134 | 153 | * before calling this super constructor. (If it's necessary to call super(...) first, |
|---|
| 135 | | * the call to genCachedConstructionData can be moved to the derived this() methods.) */ |
|---|
| 136 | | protected this (IWindow wind, int[] data) { |
|---|
| 137 | | super (wind, data); |
|---|
| | 154 | * the call to genCachedConstructionData can be moved to the derived this() methods.) |
|---|
| | 155 | * |
|---|
| | 156 | * Derived constructors should call either dupMin or setCheck on col and row, and then call |
|---|
| | 157 | * adjustCache, after calling this. */ |
|---|
| | 158 | protected this (IWidgetManager mgr, WidgetData data) { |
|---|
| | 159 | super (mgr, data); |
|---|
| 138 | 160 | |
|---|
| 139 | 161 | // Needn't be set before genCachedConstructionData is called: |
|---|
| … | … | |
| 145 | 167 | } |
|---|
| 146 | 168 | |
|---|
| 147 | | /** This implementation of adjust() does two things: |
|---|
| 148 | | * 1. Pass adjust data on to sub-widgets |
|---|
| 149 | | * 2. Set the size, from the adjust data if possible |
|---|
| 150 | | * |
|---|
| 151 | | * Can be overridden (probably along with getMutableData()) if a different implementation is |
|---|
| 152 | | * wanted. adjustCache() may still be useful. */ |
|---|
| 153 | | int[] adjust (int[] data) { |
|---|
| 154 | | // Give all sub-widgets their data: |
|---|
| 155 | | foreach (widget; subWidgets) |
|---|
| 156 | | data = widget.adjust (data); |
|---|
| 157 | | |
|---|
| 158 | | /** We basically short-cut setSize by loading previous col/row sizes and doing the final |
|---|
| 159 | | * calculations. |
|---|
| 160 | | * Note: if setSize gets called afterwards, it should have same dimensions and so not do |
|---|
| 161 | | * anything. */ |
|---|
| 162 | | int lenUsed = 0; |
|---|
| 163 | | if (data.length < rows + cols) { // data error; use defaults |
|---|
| 164 | | col.dupMin; |
|---|
| 165 | | row.dupMin; |
|---|
| 166 | | } else { // sufficient data |
|---|
| 167 | | lenUsed = rows+cols; |
|---|
| 168 | | col.setCheck (cast(wdim[])data[0..cols]); |
|---|
| 169 | | row.setCheck (cast(wdim[])data[cols..lenUsed]); |
|---|
| 170 | | } |
|---|
| 171 | | |
|---|
| 172 | | adjustCache(); |
|---|
| 173 | | return data[lenUsed..$]; |
|---|
| 174 | | } |
|---|
| 175 | 169 | /** Generates cached mutable data. |
|---|
| 176 | 170 | * |
|---|
| … | … | |
| 190 | 184 | } |
|---|
| 191 | 185 | } |
|---|
| | 186 | /+ FIXME - saving |
|---|
| 192 | 187 | /** Returns sub-widget mutable data along with column widths and row heights, as used by |
|---|
| 193 | 188 | * adjust(). */ |
|---|
| … | … | |
| 198 | 193 | |
|---|
| 199 | 194 | return ret ~ cast(int[])col.width ~ cast(int[])row.width; |
|---|
| 200 | | } |
|---|
| | 195 | }+/ |
|---|
| 201 | 196 | //END Creation & saving |
|---|
| 202 | 197 | |
|---|
| … | … | |
| 235 | 230 | |
|---|
| 236 | 231 | // Find the relevant widget. |
|---|
| 237 | | IWidget getWidget (wdim cx, wdim cy) { |
|---|
| | 232 | IChildWidget getWidget (wdim cx, wdim cy) { |
|---|
| 238 | 233 | debug scope (failure) |
|---|
| 239 | 234 | logger.warn ("getWidget: failure"); |
|---|
| … | … | |
| 264 | 259 | dragY = cy; |
|---|
| 265 | 260 | |
|---|
| 266 | | window.gui.addClickCallback (&endCallback); |
|---|
| 267 | | window.gui.addMotionCallback (&resizeCallback); |
|---|
| | 261 | mgr.addClickCallback (&endCallback); |
|---|
| | 262 | mgr.addMotionCallback (&resizeCallback); |
|---|
| 268 | 263 | } |
|---|
| 269 | 264 | } |
|---|
| … | … | |
| 285 | 280 | void genCachedConstructionData () { |
|---|
| 286 | 281 | // Will only change if renderer changes: |
|---|
| 287 | | col.spacing = row.spacing = window.renderer.layoutSpacing; |
|---|
| | 282 | col.spacing = row.spacing = mgr.renderer.layoutSpacing; |
|---|
| 288 | 283 | |
|---|
| 289 | 284 | // Calculate the minimal column and row sizes: |
|---|
| … | … | |
| 303 | 298 | |
|---|
| 304 | 299 | // Calculate the overall minimal size, starting with the spacing: |
|---|
| 305 | | mh = window.renderer.layoutSpacing; // use mh temporarily |
|---|
| | 300 | mh = mgr.renderer.layoutSpacing; // use mh temporarily |
|---|
| 306 | 301 | mw = mh * cast(wdim)(cols - 1); |
|---|
| 307 | 302 | mh *= cast(wdim)(rows - 1); |
|---|
| … | … | |
| 371 | 366 | widget.setPosition (x + col.pos[i % cols], |
|---|
| 372 | 367 | y + row.pos[i / cols]); |
|---|
| 373 | | window.requestRedraw; |
|---|
| | 368 | mgr.requestRedraw; |
|---|
| 374 | 369 | } |
|---|
| 375 | 370 | bool endCallback (wdabs cx, wdabs cy, ubyte b, bool state) { |
|---|
| 376 | 371 | if (b == 1 && state == false) { |
|---|
| 377 | | window.gui.removeCallbacks (cast(void*) this); |
|---|
| | 372 | mgr.removeCallbacks (cast(void*) this); |
|---|
| 378 | 373 | return true; // we've handled the up-click |
|---|
| 379 | 374 | } |
|---|
| … | … | |
| 391 | 386 | /* All widgets in the grid, by row. Order: [ 0 1 ] |
|---|
| 392 | 387 | * [ 2 3 ] */ |
|---|
| 393 | | IWidget[] subWidgets; |
|---|
| | 388 | IChildWidget[] subWidgets; |
|---|
| 394 | 389 | |
|---|
| 395 | 390 | /* Widths, positions, etc., either of columns or of rows |
|---|
| … | … | |
| 492 | 487 | wdim adjustCellSizes (wdim diff, myDiff start, int incr) |
|---|
| 493 | 488 | in { |
|---|
| 494 | | // Could occur if adjust isn't called first, but this would be a code error: |
|---|
| | 489 | // Could occur if constructor doesn't call dupMin/setCheck (code error): |
|---|
| 495 | 490 | assert (width !is null, "adjustCellSizes: width is null"); |
|---|
| 496 | 491 | // Most likely if passed negative when sizing is disabled: |
|---|
| r76 |
r77 |
|
| 28 | 28 | { |
|---|
| 29 | 29 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 30 | | if (data.ints.length != 3) throw new WidgetDataException; |
|---|
| | 30 | WDCheck (data, 3); |
|---|
| 31 | 31 | super (mgr, data); |
|---|
| 32 | 32 | } |
|---|
| … | … | |
| 43 | 43 | { |
|---|
| 44 | 44 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 45 | | if (data.ints.length != 1) throw new WidgetDataException; |
|---|
| | 45 | WDCheck (data, 1); |
|---|
| 46 | 46 | super (mgr, data); |
|---|
| 47 | 47 | } |
|---|
| … | … | |
| 62 | 62 | |
|---|
| 63 | 63 | this (IWidgetManager mgr, WidgetData data) { |
|---|
| 64 | | if (data.ints.length != 3) throw new WidgetDataException; |
|---|
| | 64 | WDCheck (data, 3); |
|---|
| 65 | 65 | super (mgr, data); |
|---|
| 66 | 66 | } |
|---|
| r67 |
r77 |
|
| 263 | 263 | const LOG_F_END = " - completed"; |
|---|
| 264 | 264 | const LOG_F_BAD = " - failed"; |
|---|
| 265 | | const LOG_F_FAIL = " - failed: "; |
|---|
| | 265 | const LOG_F_FAIL = " - exception: "; |
|---|
| 266 | 266 | /* Runs all functions consecutively, first-to-last. |
|---|
| 267 | 267 | * If any function fails, halts immediately. */ |
|---|
| r75 |
r77 |
|
| 179 | 179 | void cleanupSDL () { // cleanup func |
|---|
| 180 | 180 | closeJoysticks(); |
|---|
| | 181 | logger.trace ("cleanupSDL - middle"); |
|---|
| 181 | 182 | SDL_Quit(); |
|---|
| 182 | 183 | } |
|---|