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];