Changeset 40:b28d7adc786b
- Timestamp:
- 05/08/08 11:05:51 (8 months ago)
- Files:
-
- codeDoc/jobs.txt (modified) (1 diff)
- data/conf/gui.mtt (modified) (1 diff)
- mde/gui/exception.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (1 diff)
- mde/gui/widget/Window.d (modified) (3 diffs)
- mde/gui/widget/layout.d (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
codeDoc/jobs.txt
r37 r40 4 4 5 5 In progress: 6 Make a widget with multiple sizable rows/cols. 7 Implement row/col sizing. 6 8 7 9 data/conf/gui.mtt
r38 r40 8 8 <int|x=150> 9 9 <int|y=200> 10 <int[][int]|widgetData=[0:[0xB004, 1,3,3,1,5],3:[0x4010,160,160],5:[0xB004,3,1,6,1,6],6:[0x4010,60,60],1:[0x3001]]>10 <int[][int]|widgetData=[0:[0xB004,5,5,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2],1:[0x3001],2:[0x4010,75,75]]> mde/gui/exception.d
r39 r40 48 48 } 49 49 } 50 51 /// Thrown when a Widget class's adjust() is called with invalid data.52 class MutableDataException : WindowLoadException53 {54 this () { // Default, by Widget class's this55 super ("Bad widget mutable data");56 }57 this (char[] msg) { // From createWidget58 super (msg);59 }60 }mde/gui/widget/Ifaces.d
r39 r40 76 76 /** Called after creating widgets to adjust size & other mutable attributes from saved data. 77 77 * 78 * As for setSize, setPosition should be called afterwards. 79 * 78 80 * Each widget should call adjust on each of its sub-widgets in turn with data, each time 79 81 * replacing data by the return value of the call. It should then take its own mutable data 80 82 * from the beginning of the array and return the remainder of the array. 81 83 * 82 * Throws: on error, throw a MutableDataException. */ 84 * Adjust should handle errors gracefully by reverting to default values and not throwing. 85 * This is because the creation data and the user's mutable data may be stored separately and 86 * become out-of-sync during an update. */ 83 87 int[] adjust (int[] data); 84 88 85 /** Output data suitible for recreating the widget (data to be passed to this()). */ 89 /** Output data suitible for recreating the widget (data to be passed to this()). 90 * 91 * Creation data is data only changed when the gui is edited. */ 86 92 int[] getCreationData (); 87 93 88 94 /** Output data containing the widget's current adjustments (data to be passed to adjust()). 95 * 96 * Mutable data is data which can be changed during normal gui use, such as the size of 97 * resizible widgets or current tab of a tab widget. 98 * 89 99 * Should be a concatenation of each sub-widget's mutable data and the widget's own. */ 90 100 int[] getMutableData (); mde/gui/widget/Window.d
r39 r40 59 59 } body { 60 60 // Check data was loaded: 61 if (widgetData is null || mutableData is null)62 throw new WindowLoadException ("No widget /mutabledata");61 if (widgetData is null) 62 throw new WindowLoadException ("No widget creation data"); 63 63 64 64 gui_ = gui; … … 73 73 widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete) 74 74 75 // Note: this should return an empty array, but nothing much should happen if it's not empty: 75 76 widget.adjust (mutableData); // adjust/set size, etc. 76 77 mutableData = null; // no longer needed … … 112 113 /+ NOTE: currently editing is impossible... 113 114 if (edited) { // only save the widget creation data if it's been adjusted: 114 add SaveData (widget);// generate widget save data115 addCreationData (widget); // generate widget save data 115 116 dlg (INTAA, WDGD, parseFrom!(int[][int]) (widgetData)); 116 117 }+/ mde/gui/widget/layout.d
r39 r40 22 22 /** Encapsulates a grid of Widgets. 23 23 * 24 * Since a grid with either dimension zero is not useful, there must be at least one sub-widget. */ 24 * Currently there is no support for changing number of cells, sub-widgets or sub-widget properties 25 * (namely isW/HSizable and minimal size) after this() has run. 26 * 27 * Since a grid with either dimension zero is not useful, there must be at least one sub-widget. 28 * 29 * The grid has no border but has spacing between widgets. */ 25 30 class GridLayoutWidget : Widget 26 31 { … … 44 49 subWidget = window.makeWidget (data[i+3]); 45 50 } 51 52 // Calculate cached construction data 53 genCachedConstructionData; 46 54 } 47 55 … … 50 58 foreach (widget; subWidgets) 51 59 data = widget.adjust (data); 52 if (data.length < rows + cols) throw new MutableDataException;53 60 54 61 /* We basically short-cut setSize by loading previous col/row sizes and doing the final 55 * calculations. There isn't checks that the data is valid/up-to-date... worst case is too 56 * small overlapping widgets or huge ones? 62 * calculations. 57 63 * Note: if setSize gets called afterwards, it should have same dimensions and so not do 58 64 * anything. */ 59 colW = data[0..cols]; 60 rowH = data[cols..rows+cols]; 61 setColRowSizes; 65 66 int lenUsed = 0; 67 if (data.length < rows + cols) { // data error; use defaults 68 colW = colWMin.dup; 69 rowH = rowHMin.dup; 70 } else { // sufficient data 71 lenUsed = rows+cols; 72 colW = data[0..cols]; 73 rowH = data[cols..lenUsed]; 74 75 // Check row sizes are valid: 76 //NOTE: this could be made optional 77 foreach (i, inout w; colW) 78 if (w < colWMin[i]) w = colWMin[i]; 79 foreach (i, inout h; rowH) 80 if (h < rowHMin[i]) h = rowHMin[i]; 81 } 82 83 genCachedMutableData; 62 84 w = colW[$-1] + colX[$-1]; 63 85 h = rowY[$-1] + rowH[$-1]; 64 86 65 return data[ rows+cols..$];87 return data[lenUsed..$]; 66 88 } 67 89 … … 87 109 88 110 bool isWSizable () { 89 if (colSizable == -2) { // check whether any columns are resizable 90 for1: 91 for (uint i = 0; i < cols; ++i) { // for each column 92 for (uint j = 0; j < subWidgets.length; j += cols) // for each row 93 if (!subWidgets[i+j].isWSizable) // column not resizable 94 continue for1; // continue the outer for loop 95 96 // column is resizable if we get to here 97 colSizable = i; 98 goto break1; // use goto in lieu of for...else 99 } 100 101 // if we get here, no resizable column was found 102 colSizable = -1; 103 104 break1:; 105 } 106 107 if (colSizable >= 0) return true; 108 else return false; 111 return (sizableCols.length != 0); 109 112 } 110 113 111 114 bool isHSizable () { 112 if (rowSizable == -2) { // check whether any columns are resizable 113 for2: 114 for (uint i = 0; i < subWidgets.length; i += cols) { // for each row 115 for (uint j = 0; j < cols; ++j) // for each column 116 if (!subWidgets[i+j].isHSizable) 117 continue for2; 118 119 rowSizable = i / cols; // the current row 120 goto break2; 121 } 122 123 rowSizable = -1; 124 125 break2:; 126 } 127 128 if (rowSizable >= 0) return true; 129 else return false; 115 return (sizableRows.length != 0); 130 116 } 131 117 132 118 /* Calculates the minimal size from all rows and columns of widgets. */ 133 119 void getMinimalSize (out int mw, out int mh) { 134 // If rowHMin & colWMin are null, calculate them. They are set null whenever the contents 135 // or the contents' minimal size change, as well as when this widget is created. 136 if (rowHMin is null) 137 genMinRowColSizes; 138 139 // Calculate the size, starting with the spacing: 140 mh = window.renderer.layoutSpacing; // use temporarily 141 mw = mh * (cols - 1); 142 mh *= (rows - 1); 143 144 foreach (x; colWMin) // add the column/row's dimensions 145 mw += x; 146 foreach (x; rowHMin) 147 mh += x; 120 mw = this.mw; 121 mh = this.mh; 148 122 } 149 123 150 124 void setSize (int nw, int nh) { 151 /* For each of width and height, there are several cases: 152 * [new value is] more than old value 153 * -> enlarge any row/column 154 * same as old value 155 * -> do nothing 156 * more than min but less than current value 157 * -> find an enlarged row/col and reduce size 158 * -> repeat if necessary 159 * minimal value or less 160 * -> clamp to min and use min col/row sizes 161 */ 162 // FIXME: implement! 163 164 // Step 1: calculate the minimal row/column sizes. 165 alias w mw; // no need for extra vars, just use these 166 alias h mh; 167 getMinimalSize (mw, mh); 168 colW = colWMin.dup; // start with these dimensions, and increase if necessary 169 rowH = rowHMin.dup; // duplicate, because we may want to resize without recalculating *Min 170 171 // Step 2: clamp nw/nh or expand a column/row to achieve the required size 172 if (nw <= mw) nw = mw; // clamp to minimal size 173 else { 174 if (isWSizable) // calculates colSizable; true if any is resizable 175 colW[colSizable] += nw - mw; // new width 176 else // no resizable column; so force the last one 177 colW[$-1] += nw - mw; 178 } 179 180 if (nh <= mh) nh = mh; 181 else { 182 if (isHSizable) 183 rowH[rowSizable] += nh - mh; 184 else 185 rowH[$-1] += nh - mh; 186 } 187 188 w = nw; 189 h = nh; 190 191 // Step 3: set each sub-widget's size. 192 // Step 4: calculate the column and row positions 193 setColRowSizes; 194 195 // Step 5: position needs resetting 125 // Step 1: calculate the row/column sizes. 126 setSizeImpl!(true) (nw); 127 setSizeImpl!(false) (nh); 128 129 // Step 2: calculate the row/column offsets (positions) and set the sub-widgets sizes. 130 genCachedMutableData; 131 132 // Step 3: position needs to be set 196 133 // Currently this happens by specifying that setPosition should be run after setSize. 197 134 } … … 244 181 245 182 private: 246 void genMinRowColSizes () { 247 // Find the sizes of all subWidgets 248 int[] widgetW = new int[subWidgets.length]; // dimensions 249 int[] widgetH = new int[subWidgets.length]; 250 foreach (i,widget; subWidgets) 251 widget.getMinimalSize (widgetW[i],widgetH[i]); 183 /* Calculations which need to be run whenever a new sub-widget structure is set 184 * (i.e. to produce cached data calculated from construction data). */ 185 void genCachedConstructionData () { 186 // Calculate the minimal column and row sizes: 187 colWMin = new int[cols]; // set length, making sure the arrays are initialised to zero 188 rowHMin = new int[rows]; 189 int ww, wh; // sub-widget minimal sizes 190 foreach (i,widget; subWidgets) { 191 widget.getMinimalSize (ww, wh); 252 192 253 // Find the minimal row heights and column widths (non cumulative) 254 colWMin = new int[cols]; // set length 255 rowHMin = new int[rows]; 256 for (uint i = 0; i < subWidgets.length; ++i) { 257 uint n; 258 n = i % cols; // column 259 if (colWMin[n] < widgetW[i]) colWMin[n] = widgetW[i]; 193 // Increase dimensions if current minimal size is larger: 194 uint n = i % cols; // column 195 if (colWMin[n] < ww) colWMin[n] = ww; 260 196 n = i / cols; // row 261 if (rowHMin[n] < widgetH[i]) rowHMin[n] = widgetH[i]; 262 } 263 } 264 265 void setColRowSizes () { 197 if (rowHMin[n] < wh) rowHMin[n] = wh; 198 } 199 200 201 // Calculate the overall minimal size, starting with the spacing: 202 mh = window.renderer.layoutSpacing; // use temporarily 203 mw = mh * (cols - 1); 204 mh *= (rows - 1); 205 206 foreach (x; colWMin) // add the column/row's dimensions 207 mw += x; 208 foreach (x; rowHMin) 209 mh += x; 210 211 212 // Find which cols/rows are resizable: 213 sizableCols = null; // clear these because we append to them 214 sizableRows = null; 215 216 forCols: 217 for (uint i = 0; i < cols; ++i) { // for each column 218 for (uint j = 0; j < subWidgets.length; j += cols) // for each row 219 if (!subWidgets[i+j].isWSizable) // column not resizable 220 continue forCols; // continue the outer for loop 221 222 // column is resizable if we get to here 223 sizableCols ~= i; 224 } 225 226 forRows: 227 for (uint i = 0; i < subWidgets.length; i += cols) { // for each row 228 for (uint j = 0; j < cols; ++j) // for each column 229 if (!subWidgets[i+j].isHSizable) 230 continue forRows; 231 232 sizableRows ~= i / cols; // the current row 233 } 234 } 235 236 /* Calculations which need to be run whenever resizing occurs (or deeper alterations) 237 * (i.e. to produce cached data calculated from construction and mutable data). */ 238 void genCachedMutableData () { 266 239 // Calculate column and row locations: 267 240 colX.length = cols; … … 286 259 } 287 260 261 /* setSize generalised for either dimension; w/h is renamed d, col/row renamed cell. */ 262 void setSizeImpl(bool W) (int nd) { 263 static if (W) { 264 alias w d; 265 alias mw md; 266 alias colW cellD; 267 alias colWMin cellDMin; 268 alias sizableCols sizableCells; 269 } else { 270 alias h d; 271 alias mh md; 272 alias rowH cellD; 273 alias rowHMin cellDMin; 274 alias sizableRows sizableCells; 275 } 276 // Could occur if adjust isn't called first, but this would be a code error: 277 assert (cellD !is null, "setSizeImpl: cellD is null"); 278 279 /* For each of width and height, there are several cases: 280 * [new value is] more than old value 281 * -> enlarge any row/column 282 * same as old value 283 * -> do nothing 284 * more than min but less than current value 285 * -> find an enlarged row/col and reduce size 286 * -> repeat if necessary 287 * minimal value or less 288 * -> clamp to min and use min col/row sizes 289 */ 290 if (nd > d) { // expand (d < nd) 291 if (sizableCells.length) { // check there is a resizable col/row 292 cellD[sizableCells[$-1]] += nd - d; // new size 293 d = nd; 294 } 295 } else if (nd < d) { 296 if (nd > md) { // shrink (md < nd < d) 297 int toReduce = nd - d; // negative 298 foreach_reverse (cell; sizableCells) { 299 cellD[cell] += toReduce; 300 toReduce = cellD[cell] - cellDMin[cell]; 301 if (toReduce < 0) // reduced too far 302 cellD[cell] = cellDMin[cell]; 303 else // ok; cellD >= cellDMin 304 break; 305 } 306 d = nd; 307 } else { // clamp (nd <= md) 308 cellD = cellDMin.dup; // duplicate so future edits don't affect cellDMin 309 d = md; 310 } 311 } // third possibility: nd = d 312 } 313 288 314 protected: 315 // Construction data (saved): 289 316 int cols, rows; // number of cells in grid 290 291 int colSizable = -2;// 0..cols-1 means this column is resizable292 int rowSizable = -2;// -2 means not calculated yet, -1 means not resizable293 294 int[] colWMin; // minimal column width295 int[] rowHMin; // minimal row height296 int[] colW; // column width (widest widget)297 int[] rowH; // row height (highest widget in the row)298 299 int[] colX; // cumulative colW[i-1] + padding (add x to get column's left x-coord)300 int[] rowY; // cumulative rowH[i-1] + padding301 302 317 IWidget[] subWidgets; // all widgets in the grid (by row): 303 318 /* SubWidget order: [ 0 1 ] 304 319 * [ 2 3 ] */ 320 321 // Cached data calculated from construction data: 322 int[] colWMin; // minimal column width 323 int[] rowHMin; // minimal row height 324 int mw, mh; // minimal dimensions 325 326 int[] sizableCols; // all resizable columns / rows, empty if not resizable 327 int[] sizableRows; // resizing is done from last entry 328 329 // Mutable data (saved): 330 int[] colW; // column width (widest widget) 331 int[] rowH; // row height (highest widget in the row) 332 333 // Cached data calculated from construction and mutable data: 334 int[] colX; // cumulative colW[i-1] + padding (add x to get column's left x-coord) 335 int[] rowY; // cumulative rowH[i-1] + padding 305 336 }
