Changeset 92:085f2ca31914
- Timestamp:
- 10/21/08 04:57:19
(3 months ago)
- Author:
- Diggory Hardy <diggory.hardy@gmail.com>
- branch:
- default
- Message:
Shared alignments supported in more complex cases.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r91 |
r92 |
|
| 8 | 8 | <WidgetData|button={0:[0x10,50,50]}> |
|---|
| 9 | 9 | <WidgetData|blank={0:[0x2]}> |
|---|
| 10 | | <WidgetData|opts={0:[0x8110,0],1:["optBox"]}> |
|---|
| | 10 | <WidgetData|opts={0:[0x8110,0],1:["optDBox"]}> |
|---|
| | 11 | <WidgetData|optDBox={0:[0xC100,0,2,1],1:["optBox","optDesc"]}> |
|---|
| 11 | 12 | <WidgetData|optBox={0:[0xC100,1,1,3],1:["optName","optSep","optVal"]}> |
|---|
| 12 | 13 | <WidgetData|optName={0:[0x4020, 1, 0xfe8c00]}> |
|---|
| | 14 | <WidgetData|optDesc={0:[0x4020, 2, 0xaf6000]}> |
|---|
| 13 | 15 | <WidgetData|optVal={0:[0x4020, 0, 0xBF00]}> |
|---|
| 14 | 16 | <WidgetData|optSep={0:[0x21, 0xff],1:["="]}> |
|---|
| r91 |
r92 |
|
| 6 | 6 | <int|logOptions=0x3000> |
|---|
| 7 | 7 | <double|pollInterval=0.01> |
|---|
| 8 | | <char[]|a="tildb\naeouc\ngpqyg"> |
|---|
| 9 | | <char[]|b="tildb"> |
|---|
| 10 | | <char[]|c="aeouc"> |
|---|
| 11 | | <char[]|g="gpqy"> |
|---|
| 12 | | <char[]|z="fghijklpq"> |
|---|
| 13 | 8 | |
|---|
| 14 | 9 | {font} |
|---|
| r91 |
r92 |
|
| 63 | 63 | } |
|---|
| 64 | 64 | |
|---|
| 65 | | // NOTE - temporarily here to allow CTOR to run safely during static this |
|---|
| 66 | | // called during init |
|---|
| | 65 | // this() runs during static this(), when imde.input doesn't exist. init() runs later. |
|---|
| 67 | 66 | void init () { |
|---|
| 68 | 67 | // Doesn't need a lock - cannot conflict with other class functions. |
|---|
| … | … | |
| 171 | 170 | |
|---|
| 172 | 171 | child = makeWidget ("root"); |
|---|
| | 172 | finalize; |
|---|
| 173 | 173 | |
|---|
| 174 | 174 | mw = child.minWidth; |
|---|
| … | … | |
| 385 | 385 | * |
|---|
| 386 | 386 | * A widget instance is created from data found under ID. Multiple instances may be created. |
|---|
| 387 | | * FIXME - data conflicts when saving? |
|---|
| | 387 | * NOTE - data conflicts when saving? |
|---|
| 388 | 388 | * |
|---|
| 389 | 389 | * An IContent may be passed. This could contain many things, e.g. some basic data, a widget, |
|---|
| … | … | |
| 395 | 395 | } |
|---|
| 396 | 396 | |
|---|
| | 397 | /** Runs finalize for all descendants, in a deepest first order. */ |
|---|
| | 398 | /* NOTE: The way this function works may seem a little odd, but it's designed to allow |
|---|
| | 399 | * shared alignments to be initialized properly: |
|---|
| | 400 | * 1. all sharing members need to know their children's min size |
|---|
| | 401 | * 2. all sharing members need to add their children's min size to the alignment |
|---|
| | 402 | * 3. all sharing members can only then get their min size |
|---|
| | 403 | * This method will fail if alignment members are not all of the same generation. An alternate |
|---|
| | 404 | * method without this drawback would be to have shared alignments created with a list of |
|---|
| | 405 | * pointers to their members, and once all members have been created the alignment could |
|---|
| | 406 | * initialize itself, first making sure each members' children have been initialized. */ |
|---|
| | 407 | void finalize () { |
|---|
| | 408 | IChildWidget[][] descendants; // first index: depth; is a list of widgets at each depth |
|---|
| | 409 | |
|---|
| | 410 | void recurseChildren (size_t depth, IChildWidget widget) { |
|---|
| | 411 | foreach (child; widget.children) |
|---|
| | 412 | recurseChildren (depth+1, child); |
|---|
| | 413 | |
|---|
| | 414 | if (descendants.length <= depth) |
|---|
| | 415 | descendants.length = depth * 2 + 1; |
|---|
| | 416 | descendants[depth] ~= widget; |
|---|
| | 417 | } |
|---|
| | 418 | |
|---|
| | 419 | recurseChildren (0, child); |
|---|
| | 420 | foreach_reverse (generation; descendants) { |
|---|
| | 421 | foreach (widget; generation) |
|---|
| | 422 | widget.prefinalize; |
|---|
| | 423 | foreach (widget; generation) |
|---|
| | 424 | widget.finalize; |
|---|
| | 425 | } |
|---|
| | 426 | } |
|---|
| | 427 | |
|---|
| 397 | 428 | /** For making changes. */ |
|---|
| 398 | 429 | void setData (widgetID id, WidgetData d) { |
|---|
| … | … | |
| 406 | 437 | * // 1. Create the root widget: |
|---|
| 407 | 438 | * child = makeWidget ("root"); |
|---|
| | 439 | * finalize; |
|---|
| 408 | 440 | * // 2. Set the setSize, e.g.: |
|---|
| 409 | 441 | * child.setWidth (child.minWidth, 1); |
|---|
| r91 |
r92 |
|
| 54 | 54 | * additionally an (x,y) coordinate for each subwidget (all x coords first, then all y coords). |
|---|
| 55 | 55 | */ |
|---|
| 56 | | class FloatingAreaWidget : SizableWidget |
|---|
| | 56 | class FloatingAreaWidget : ParentWidget |
|---|
| 57 | 57 | { |
|---|
| 58 | 58 | this (IWidgetManager mgr, widgetID id, WidgetData data) { |
|---|
| … | … | |
| 60 | 60 | foreach (i,s; data.strings) |
|---|
| 61 | 61 | subWidgets[i] = mgr.makeWidget (s); |
|---|
| | 62 | foreach (w; subWidgets) |
|---|
| | 63 | w.finalize; |
|---|
| 62 | 64 | sWCoords.length = subWidgets.length; |
|---|
| 63 | 65 | |
|---|
| … | … | |
| 81 | 83 | } |
|---|
| 82 | 84 | |
|---|
| | 85 | bool isWSizable () { return true; } |
|---|
| | 86 | bool isHSizable () { return true; } |
|---|
| | 87 | |
|---|
| 83 | 88 | void setPosition (wdim x, wdim y) { |
|---|
| 84 | 89 | super.setPosition (x,y); |
|---|
| … | … | |
| 98 | 103 | |
|---|
| 99 | 104 | protected: |
|---|
| 100 | | IChildWidget[] subWidgets; // all subwidgets, framed or not |
|---|
| 101 | 105 | wdimPair[] sWCoords; // coords for subwidgets, relative to this widget |
|---|
| 102 | 106 | |
|---|
| r91 |
r92 |
|
| 136 | 136 | * satisfy their minimal sizes as available from minWidth() and minHeight(). setWidth() and |
|---|
| 137 | 137 | * setHeight() are called on all widgets after creation. |
|---|
| | 138 | * |
|---|
| | 139 | * Also see finalize(). |
|---|
| 138 | 140 | *************************************************************************************************/ |
|---|
| 139 | 141 | //NOTE: add another this() without the data for default initialization, for the GUI editor? |
|---|
| … | … | |
| 141 | 143 | { |
|---|
| 142 | 144 | //BEGIN Load and save |
|---|
| | 145 | // NOTE - change? |
|---|
| | 146 | /** Called on all widgets after all widgets have been created in a deepest first order. |
|---|
| | 147 | * |
|---|
| | 148 | * Must be called before any other methods on the widget, which means this cannot call sub- |
|---|
| | 149 | * widgets' methods, but finalize can. */ |
|---|
| | 150 | void prefinalize (); |
|---|
| | 151 | void finalize (); /// ditto |
|---|
| | 152 | |
|---|
| | 153 | /** Widget should return a list of all its children. */ |
|---|
| | 154 | IChildWidget[] children (); |
|---|
| | 155 | |
|---|
| 143 | 156 | /** When this is called, if the widget has any changed data to save it should call |
|---|
| 144 | 157 | * IWidgetManager.setData (id, data) to set it and return true. Otherwise it should return |
|---|
| … | … | |
| 178 | 191 | /** The minimal size the widget could be shrunk to (or its fixed size). |
|---|
| 179 | 192 | * |
|---|
| 180 | | * Takes into account child-widgets and any other contents. |
|---|
| 181 | | * |
|---|
| 182 | | * Note: layout uses these calls to initialize it's alignment device. So, after creating a |
|---|
| 183 | | * (layout) widget, minWidth should be the first function called on it! */ |
|---|
| | 193 | * Takes into account child-widgets and any other contents. */ |
|---|
| 184 | 194 | wdim minWidth (); |
|---|
| 185 | 195 | wdim minHeight (); /// ditto |
|---|
| r91 |
r92 |
|
| 50 | 50 | } |
|---|
| 51 | 51 | |
|---|
| | 52 | // Most widgets don't need this; all initialization os usually done in this() |
|---|
| | 53 | void prefinalize () {} |
|---|
| | 54 | void finalize () {} |
|---|
| | 55 | |
|---|
| | 56 | // ParentWidget is inteded for parent widgets to derive |
|---|
| | 57 | IChildWidget[] children () { |
|---|
| | 58 | return null; |
|---|
| | 59 | } |
|---|
| | 60 | |
|---|
| 52 | 61 | // Don't save any data: fine for many widgets. |
|---|
| | 62 | // FIXME: implementation could be added to ParentWidget |
|---|
| 53 | 63 | bool saveChanges (widgetID) { |
|---|
| 54 | 64 | return false; |
|---|
| … | … | |
| 142 | 152 | } |
|---|
| 143 | 153 | |
|---|
| | 154 | /************************************************************************************************* |
|---|
| | 155 | * An abstract base widget class for parent widgets. |
|---|
| | 156 | *************************************************************************************************/ |
|---|
| | 157 | abstract class ParentWidget : Widget |
|---|
| | 158 | { |
|---|
| | 159 | this (IWidgetManager mgr, widgetID id, WidgetData data) { |
|---|
| | 160 | super (mgr, id, data); |
|---|
| | 161 | } |
|---|
| | 162 | |
|---|
| | 163 | IChildWidget[] children () { |
|---|
| | 164 | return subWidgets; |
|---|
| | 165 | } |
|---|
| | 166 | |
|---|
| | 167 | protected: |
|---|
| | 168 | IChildWidget[] subWidgets; |
|---|
| | 169 | } |
|---|
| | 170 | |
|---|
| 144 | 171 | /** A base for fixed-size widgets taking their size from the creation data. */ |
|---|
| 145 | 172 | class FixedWidget : Widget { |
|---|
| r91 |
r92 |
|
| 115 | 115 | rows = optsList.list.length; |
|---|
| 116 | 116 | cols = 1; |
|---|
| | 117 | sWId = data.strings[0]; |
|---|
| 117 | 118 | |
|---|
| 118 | 119 | // Get all sub-widgets |
|---|
| 119 | 120 | subWidgets.length = rows*cols; |
|---|
| 120 | 121 | foreach (i, c; optsList.list) { |
|---|
| 121 | | subWidgets[i] = mgr.makeWidget (data.strings[0], c); |
|---|
| | 122 | subWidgets[i] = mgr.makeWidget (sWId, c); |
|---|
| 122 | 123 | } |
|---|
| 123 | 124 | super (mgr, id, data); |
|---|
| | 125 | } |
|---|
| | 126 | |
|---|
| | 127 | bool saveChanges (widgetID id) { |
|---|
| | 128 | // Since all sub-widgets have the same id, it only makes sense to call on one |
|---|
| | 129 | if (subWidgets is null) |
|---|
| | 130 | return false; |
|---|
| | 131 | return subWidgets[0].saveChanges (sWId); |
|---|
| 124 | 132 | } |
|---|
| 125 | 133 | |
|---|
| 126 | 134 | private: |
|---|
| 127 | 135 | OptionList optsList; |
|---|
| | 136 | widgetID sWId; // sub-widget's ID, for calling saveChanges FIXME no longer pass? |
|---|
| 128 | 137 | } |
|---|
| 129 | 138 | |
|---|
| … | … | |
| 139 | 148 | * The grid has no border but has spacing between widgets. |
|---|
| 140 | 149 | *************************************************************************************************/ |
|---|
| 141 | | abstract class GridWidget : Widget |
|---|
| | 150 | abstract class GridWidget : ParentWidget |
|---|
| 142 | 151 | { |
|---|
| 143 | 152 | //BEGIN Creation & saving |
|---|
| … | … | |
| 149 | 158 | * |
|---|
| 150 | 159 | * Derived constructors may also set initWidths to the array of column widths followed by |
|---|
| 151 | | * row heights used to initially set the row/column dimensions. */ |
|---|
| | 160 | * row heights used to initially set the row/column dimensions. |
|---|
| | 161 | * |
|---|
| | 162 | * Sub-widgets are finalized here, so no methods should be called on sub-widgets before calling |
|---|
| | 163 | * this super. */ |
|---|
| 152 | 164 | protected this (IWidgetManager mgr, widgetID id, WidgetData data) { |
|---|
| 153 | 165 | super (mgr, id, data); |
|---|
| … | … | |
| 164 | 176 | row = (new AlignColumns (rows)); |
|---|
| 165 | 177 | row.addSetCallback (&setRowHeight); |
|---|
| 166 | | |
|---|
| 167 | | // Calculate cached construction data |
|---|
| 168 | | genCachedConstructionData; |
|---|
| | 178 | } |
|---|
| | 179 | |
|---|
| | 180 | /** Prior to finalizing but after sub-widgets are finalized, some information needs to be |
|---|
| | 181 | * passed to the AlignColumns. */ |
|---|
| | 182 | void prefinalize () { |
|---|
| | 183 | genCachedConstructionData; // min widths, sizableness |
|---|
| 169 | 184 | } |
|---|
| 170 | 185 | |
|---|
| … | … | |
| 172 | 187 | * |
|---|
| 173 | 188 | * As such, this must be the first function called after this(). */ |
|---|
| 174 | | wdim minWidth () { |
|---|
| 175 | | if (!alignInit) { // assumes col & row.width are initialized simultaneously |
|---|
| 176 | | alignInit = true; |
|---|
| 177 | | if (initWidths) { |
|---|
| 178 | | debug assert (initWidths.length == cols + rows, "initWidths provided but has bad length"); |
|---|
| 179 | | col.setWidths (initWidths[0..cols]); |
|---|
| 180 | | row.setWidths (initWidths[cols..$]); |
|---|
| 181 | | initWidths = null; // free |
|---|
| 182 | | } else { |
|---|
| 183 | | col.setWidths; |
|---|
| 184 | | row.setWidths; |
|---|
| 185 | | } |
|---|
| 186 | | |
|---|
| 187 | | mw = col.mw; |
|---|
| 188 | | mh = row.mw; |
|---|
| 189 | | w = col.w; |
|---|
| 190 | | h = row.w; |
|---|
| 191 | | |
|---|
| 192 | | // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. |
|---|
| 193 | | foreach (i,widget; subWidgets) { |
|---|
| 194 | | // Resizing direction is arbitrarily set to negative: |
|---|
| 195 | | widget.setWidth (col.width[i % cols], -1); |
|---|
| 196 | | widget.setHeight (row.width[i / cols], -1); |
|---|
| 197 | | } |
|---|
| 198 | | } |
|---|
| 199 | | return mw; |
|---|
| | 189 | void finalize () { |
|---|
| | 190 | if (initWidths) { |
|---|
| | 191 | debug assert (initWidths.length == cols + rows, "initWidths provided but has bad length"); |
|---|
| | 192 | col.setWidths (initWidths[0..cols]); |
|---|
| | 193 | row.setWidths (initWidths[cols..$]); |
|---|
| | 194 | initWidths = null; // free |
|---|
| | 195 | } else { |
|---|
| | 196 | col.setWidths; |
|---|
| | 197 | row.setWidths; |
|---|
| | 198 | } |
|---|
| | 199 | |
|---|
| | 200 | mw = col.mw; |
|---|
| | 201 | mh = row.mw; |
|---|
| | 202 | w = col.w; |
|---|
| | 203 | h = row.w; |
|---|
| | 204 | |
|---|
| | 205 | // Tell subwidgets their new sizes. Positions are given by a later call to setPosition. |
|---|
| | 206 | foreach (i,widget; subWidgets) { |
|---|
| | 207 | // Resizing direction is arbitrarily set to negative: |
|---|
| | 208 | widget.setWidth (col.width[i % cols], -1); |
|---|
| | 209 | widget.setHeight (row.width[i / cols], -1); |
|---|
| | 210 | } |
|---|
| 200 | 211 | } |
|---|
| 201 | 212 | //END Creation & saving |
|---|
| … | … | |
| 280 | 291 | * |
|---|
| 281 | 292 | * rows, cols and subWidgets must be set before calling. Part of the set-up for AlignColumns |
|---|
| 282 | | * (col and row). */ |
|---|
| | 293 | * (col and row). subWidgets need to know their minimal size and resizability. */ |
|---|
| 283 | 294 | void genCachedConstructionData () { |
|---|
| 284 | 295 | // Will only change if renderer changes: |
|---|
| | 296 | // NOTE shared AlignColumns get this set by all sharing GridWidgets |
|---|
| 285 | 297 | col.spacing = row.spacing = mgr.renderer.layoutSpacing; |
|---|
| 286 | 298 | |
|---|
| … | … | |
| 362 | 374 | myIt cols, rows; // number of cells in grid |
|---|
| 363 | 375 | wdim[] initWidths; // see this / setInitialSize |
|---|
| 364 | | bool alignInit; // have AlignColumns instances been initialized? |
|---|
| 365 | 376 | |
|---|
| 366 | 377 | /* All widgets in the grid, by row. Order: [ 0 1 ] |
|---|
| 367 | 378 | * [ 2 3 ] */ |
|---|
| 368 | | IChildWidget[] subWidgets; |
|---|
| | 379 | //IChildWidget[] subWidgets; |
|---|
| 369 | 380 | |
|---|
| 370 | 381 | AlignColumns col, row; |
|---|