Mercurial > projects > mde
comparison mde/gui/widget/layout.d @ 71:77c7d3235114
Separated the grid layout widget's implementation into a base and a derived class, to allow other uses of layout.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 05 Jul 2008 15:36:39 +0100 |
parents | f54ae4fc2b2f |
children | 159775502bb4 |
comparison
equal
deleted
inserted
replaced
70:7fc0a8295c83 | 71:77c7d3235114 |
---|---|
25 static this () { | 25 static this () { |
26 logger = Log.getLogger ("mde.gui.widget.layout"); | 26 logger = Log.getLogger ("mde.gui.widget.layout"); |
27 } | 27 } |
28 } | 28 } |
29 | 29 |
30 /** Encapsulates a grid of Widgets. | 30 /************************************************************************************************* |
31 * | 31 * Encapsulates a grid of Widgets. |
32 * Currently there is no support for changing number of cells, sub-widgets or sub-widget properties | 32 * |
33 * (namely isW/HSizable and minimal size) after this() has run. | 33 * Currently there is no support for changing number of cells, sub-widgets or sub-widget properties |
34 * | 34 * (namely isW/HSizable and minimal size) after this() has run. |
35 * Since a grid with either dimension zero is not useful, there must be at least one sub-widget. | 35 * |
36 * | 36 * Since a grid with either dimension zero is not useful, there must be at least one sub-widget. |
37 * The grid has no border but has spacing between widgets. */ | 37 * |
38 /* TODO: | 38 * The grid has no border but has spacing between widgets. |
39 separate positioning & sub-widget handling from creation/saving | 39 *************************************************************************************************/ |
40 other types of layouts (e.g. lists from content) | 40 class GridLayoutWidget : GridWidget |
41 */ | |
42 class GridLayoutWidget : Widget | |
43 { | 41 { |
44 //BEGIN Creation & saving | |
45 /** Constructor for a grid layout widget. | 42 /** Constructor for a grid layout widget. |
46 * | 43 * |
47 * Widget uses the initialisation data: | 44 * Widget uses the initialisation data: |
48 * [widgetID, r, c, w11, w12, ..., w1c, ..., wr1, ..., wrc] | 45 * [widgetID, r, c, w11, w12, ..., w1c, ..., wr1, ..., wrc] |
49 * where r and c are the number of rows and columns, and wij is the ID (from parent Window's | 46 * where r and c are the number of rows and columns, and wij is the ID (from parent Window's |
50 * list) for the widget in row i and column j. The number of parameters must be r*c + 3. */ | 47 * 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) { | 48 this (IWindow wind, int[] data) { |
52 // Get grid size and check data | 49 // Get grid size and check data |
53 // Check sufficient data for rows, cols, and at least one widget: | 50 // Check sufficient data for rows, cols, and at least one widget: |
54 if (data.length < 4) throw new WidgetDataException; | 51 if (data.length < 4) throw new WidgetDataException; |
55 super (wind, data); | |
56 | 52 |
57 rows = data[1]; | 53 rows = data[1]; |
58 cols = data[2]; | 54 cols = data[2]; |
59 if (data.length != 3 + rows * cols) throw new WidgetDataException; | 55 if (data.length != 3 + rows * cols) throw new WidgetDataException; |
60 /* data.length >= 4 so besides checking the length is correct, this tells us: | 56 /* data.length >= 4 so besides checking the length is correct, this tells us: |
64 * is an acceptible method of failure (and is unlikely anyway). */ | 60 * is an acceptible method of failure (and is unlikely anyway). */ |
65 | 61 |
66 // Get all sub-widgets | 62 // Get all sub-widgets |
67 subWidgets.length = rows*cols; | 63 subWidgets.length = rows*cols; |
68 foreach (i, ref subWidget; subWidgets) { | 64 foreach (i, ref subWidget; subWidgets) { |
69 subWidget = window.makeWidget (data[i+3]); | 65 subWidget = wind.makeWidget (data[i+3]); |
70 } | 66 } |
67 super (wind, data); | |
68 } | |
69 /** Return construction data to recreate this GridLayoutWidget. */ | |
70 int[] getCreationData () { | |
71 int[] ret; | |
72 ret.length = 3 + subWidgets.length; | |
73 | |
74 ret [0..3] = [widgetType, rows, cols]; // first data | |
75 | |
76 foreach (i,widget; subWidgets) // sub widgets | |
77 ret[i+3] = window.addCreationData (widget); | |
78 | |
79 return ret; | |
80 } | |
81 } | |
82 | |
83 | |
84 /************************************************************************************************* | |
85 * Trial layout of sub-widgets of one type only. | |
86 *************************************************************************************************/ | |
87 class TrialLayout : GridWidget | |
88 { | |
89 this (IWindow wind, int[] data) { | |
90 assert (false, "Not ready"); | |
91 if (data.length != 6) throw new WidgetDataException; | |
92 super (wind, data); | |
93 | |
94 rows = data[1]; | |
95 cols = data[2]; | |
96 | |
97 // Get all sub-widgets | |
98 subWidgets.length = rows*cols; | |
99 foreach (i, ref subWidget; subWidgets) { | |
100 //subWidget = new ContentWidget (data[3..6]); | |
101 } | |
102 } | |
103 | |
104 | |
105 } | |
106 | |
107 | |
108 /************************************************************************************************* | |
109 * Backend for grid-based (includes column/row) layout widgets. | |
110 * | |
111 * A deriving class must at least do some work in it's constructor (see Ddoc for this() below) | |
112 * and provide an implementation of getCreationData() (unless Widget's version is sufficient). | |
113 * | |
114 * Since a grid with either dimension zero is not useful, there must be at least one sub-widget. | |
115 * | |
116 * The grid has no border but has spacing between widgets. | |
117 *************************************************************************************************/ | |
118 class GridWidget : Widget | |
119 { | |
120 //BEGIN Creation & saving | |
121 /** Partial constructor for a grid layout widget. | |
122 * | |
123 * Deriving classes should check data length, and set rows, cols, and the subWidgets array, | |
124 * before calling this super constructor. (If it's necessary to call super(...) first, | |
125 * the call to genCachedConstructionData can be moved to the derived this() methods.) */ | |
126 protected this (IWindow wind, int[] data) { | |
127 super (wind, data); | |
128 | |
129 // Needn't be set before genCachedConstructionData is called: | |
130 col.setColWidth = &setColWidth; | |
131 row.setColWidth = &setRowHeight; | |
71 | 132 |
72 // Calculate cached construction data | 133 // Calculate cached construction data |
73 genCachedConstructionData; | 134 genCachedConstructionData; |
74 } | 135 } |
75 | 136 |
76 /* This does two things: | 137 /** This implementation of adjust() does two things: |
77 * 1. Pass adjust data on to sub-widgets | 138 * 1. Pass adjust data on to sub-widgets |
78 * 2. Set the size, from the adjust data if possible | 139 * 2. Set the size, from the adjust data if possible |
79 */ | 140 * |
141 * Can be overridden (probably along with getMutableData()) if a different implementation is | |
142 * wanted. adjustCache() may still be useful. */ | |
80 int[] adjust (int[] data) { | 143 int[] adjust (int[] data) { |
81 // Give all sub-widgets their data: | 144 // Give all sub-widgets their data: |
82 foreach (widget; subWidgets) | 145 foreach (widget; subWidgets) |
83 data = widget.adjust (data); | 146 data = widget.adjust (data); |
84 | 147 |
85 /* We basically short-cut setSize by loading previous col/row sizes and doing the final | 148 /** We basically short-cut setSize by loading previous col/row sizes and doing the final |
86 * calculations. | 149 * calculations. |
87 * Note: if setSize gets called afterwards, it should have same dimensions and so not do | 150 * Note: if setSize gets called afterwards, it should have same dimensions and so not do |
88 * anything. */ | 151 * anything. */ |
89 | |
90 int lenUsed = 0; | 152 int lenUsed = 0; |
91 if (data.length < rows + cols) { // data error; use defaults | 153 if (data.length < rows + cols) { // data error; use defaults |
92 col.dupMin; | 154 col.dupMin; |
93 row.dupMin; | 155 row.dupMin; |
94 } else { // sufficient data | 156 } else { // sufficient data |
95 lenUsed = rows+cols; | 157 lenUsed = rows+cols; |
96 col.setCheck (cast(wdim[])data[0..cols]); | 158 col.setCheck (cast(wdim[])data[0..cols]); |
97 row.setCheck (cast(wdim[])data[cols..lenUsed]); | 159 row.setCheck (cast(wdim[])data[cols..lenUsed]); |
98 } | 160 } |
99 | 161 |
100 | 162 adjustCache(); |
163 return data[lenUsed..$]; | |
164 } | |
165 /** Generates cached mutable data. | |
166 * | |
167 * Should be called by adjust() after setting col and row widths (currently via dupMin or | |
168 * setCheck). */ | |
169 void adjustCache () { | |
101 // Generate cached mutable data | 170 // Generate cached mutable data |
102 // Calculate column and row locations: | 171 // Calculate column and row locations: |
103 w = col.genPositions; | 172 w = col.genPositions; |
104 h = row.genPositions; | 173 h = row.genPositions; |
105 | 174 |
107 foreach (i,widget; subWidgets) { | 176 foreach (i,widget; subWidgets) { |
108 // Resizing direction is arbitrarily set to negative: | 177 // Resizing direction is arbitrarily set to negative: |
109 widget.setWidth (col.width[i % cols], -1); | 178 widget.setWidth (col.width[i % cols], -1); |
110 widget.setHeight (row.width[i / cols], -1); | 179 widget.setHeight (row.width[i / cols], -1); |
111 } | 180 } |
112 | 181 } |
113 return data[lenUsed..$]; | 182 /** Returns sub-widget mutable data along with column widths and row heights, as used by |
114 } | 183 * adjust(). */ |
115 | |
116 int[] getCreationData () { | |
117 int[] ret; | |
118 ret.length = 3 + subWidgets.length; | |
119 | |
120 ret [0..3] = [widgetType, rows, cols]; // first data | |
121 | |
122 foreach (i,widget; subWidgets) // sub widgets | |
123 ret[i+3] = window.addCreationData (widget); | |
124 | |
125 return ret; | |
126 } | |
127 int[] getMutableData () { | 184 int[] getMutableData () { |
128 int[] ret; | 185 int[] ret; |
129 foreach (widget; subWidgets) | 186 foreach (widget; subWidgets) |
130 ret ~= widget.getMutableData; | 187 ret ~= widget.getMutableData; |
131 | 188 |
209 } | 266 } |
210 | 267 |
211 private: | 268 private: |
212 //BEGIN Cache calculation functions | 269 //BEGIN Cache calculation functions |
213 /* Calculations which need to be run whenever a new sub-widget structure is set | 270 /* Calculations which need to be run whenever a new sub-widget structure is set |
214 * (i.e. to produce cached data calculated from construction data). */ | 271 * (i.e. to produce cached data calculated from construction data). |
272 * Also need to be re-run if the renderer changes. | |
273 * | |
274 * rows, cols and subWidgets must be set before calling. */ | |
215 void genCachedConstructionData () { | 275 void genCachedConstructionData () { |
276 // Will only change if renderer changes: | |
216 col.spacing = row.spacing = window.renderer.layoutSpacing; | 277 col.spacing = row.spacing = window.renderer.layoutSpacing; |
217 col.setColWidth = &setColWidth; | |
218 row.setColWidth = &setRowHeight; | |
219 | 278 |
220 // Calculate the minimal column and row sizes: | 279 // Calculate the minimal column and row sizes: |
221 // set length, making sure the arrays are initialised to zero: | 280 // set length, making sure the arrays are initialised to zero: |
222 col.minWidth = new wdim[cols]; | 281 col.minWidth = new wdim[cols]; |
223 row.minWidth = new wdim[rows]; | 282 row.minWidth = new wdim[rows]; |