1 /** DGui project file. 2 3 Copyright: Trogu Antonio Davide 2011-2013 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Trogu Antonio Davide 8 */ 9 module dguihub.layout.gridpanel; 10 11 import std.algorithm; 12 import dguihub.core.interfaces.idisposable; 13 import dguihub.layout.layoutcontrol; 14 15 class ColumnPart : IDisposable { 16 private Control _control; 17 private GridPanel _gridPanel; 18 private int _width = 0; 19 private int _marginLeft = 0; 20 private int _marginRight = 0; 21 22 package this(GridPanel gp, Control c) { 23 this._gridPanel = gp; 24 this._control = c; 25 } 26 27 public ~this() { 28 this.dispose(); 29 } 30 31 public void dispose() { 32 if (this._control) { 33 this._control.dispose(); 34 this._control = null; 35 } 36 } 37 38 @property public int marginLeft() { 39 return this._marginLeft; 40 } 41 42 @property public void marginLeft(int m) { 43 this._marginLeft = m; 44 } 45 46 @property public int marginRight() { 47 return this._marginRight; 48 } 49 50 @property public void marginRight(int m) { 51 this._marginRight = m; 52 } 53 54 @property public int width() { 55 return this._width; 56 } 57 58 @property public void width(int w) { 59 this._width = w; 60 61 if (this._gridPanel && this._gridPanel.created) { 62 this._gridPanel.updateLayout(); 63 } 64 } 65 66 @property public GridPanel gridPanel() { 67 return this._gridPanel; 68 } 69 70 @property public Control control() { 71 return this._control; 72 } 73 } 74 75 class RowPart : IDisposable { 76 private Collection!(ColumnPart) _columns; 77 private GridPanel _gridPanel; 78 private int _height = 0; 79 private int _marginTop = 0; 80 private int _marginBottom = 0; 81 82 package this(GridPanel gp) { 83 this._gridPanel = gp; 84 } 85 86 public ~this() { 87 this.dispose(); 88 } 89 90 public void dispose() { 91 if (this._columns) { 92 foreach (ColumnPart cp; this._columns) { 93 cp.dispose(); 94 } 95 96 this._columns.clear(); 97 } 98 } 99 100 @property public int marginTop() { 101 return this._marginTop; 102 } 103 104 @property public void marginTop(int m) { 105 this._marginTop = m; 106 } 107 108 @property public int marginBottom() { 109 return this._marginBottom; 110 } 111 112 @property public void marginBottom(int m) { 113 this._marginBottom = m; 114 } 115 116 @property public int height() { 117 return this._height; 118 } 119 120 @property public void height(int h) { 121 this._height = h; 122 123 if (this._gridPanel && this._gridPanel.created) { 124 this._gridPanel.updateLayout(); 125 } 126 } 127 128 @property public GridPanel gridPanel() { 129 return this._gridPanel; 130 } 131 132 public ColumnPart addColumn() { 133 return this.addColumn(null); 134 } 135 136 public ColumnPart addColumn(Control c) { 137 if (!this._columns) { 138 this._columns = new Collection!(ColumnPart)(); 139 } 140 141 if (c) { 142 this._gridPanel.canAddChild = true; // Unlock Add Child 143 c.parent = this._gridPanel; // Set the parent 144 this._gridPanel.canAddChild = false; // Lock Add Child 145 } 146 147 ColumnPart cp = new ColumnPart(this._gridPanel, c); 148 this._columns.add(cp); 149 150 if (c && this._gridPanel && this._gridPanel.created) { 151 c.show(); // Layout is done by LayoutControl 152 } 153 154 return cp; 155 } 156 157 public void removeColumn(int idx) { 158 ColumnPart c = this._columns[idx]; 159 160 this._columns.removeAt(idx); 161 c.dispose(); 162 163 this._gridPanel.updateLayout(); //Recalculate layout 164 } 165 166 @property public ColumnPart[] columns() { 167 if (this._columns) { 168 return this._columns.get(); 169 } 170 171 return null; 172 } 173 } 174 175 class GridPanel : LayoutControl { 176 private Collection!(RowPart) _rows; 177 private bool _canAddChild = false; 178 179 @property package void canAddChild(bool b) { 180 this._canAddChild = b; 181 } 182 183 public RowPart addRow() { 184 if (!this._rows) { 185 this._rows = new Collection!(RowPart)(); 186 } 187 188 RowPart rp = new RowPart(this); 189 this._rows.add(rp); 190 191 return rp; 192 } 193 194 public void removeRow(int idx) { 195 if (this._rows) { 196 RowPart c = this._rows[idx]; 197 198 this._rows.removeAt(idx); 199 c.dispose(); 200 } 201 } 202 203 @property public RowPart[] rows() { 204 if (this._rows) { 205 return this._rows.get(); 206 } 207 208 return null; 209 } 210 211 protected override void createControlParams(ref CreateControlParams ccp) { 212 ccp.className = WC_DGRIDPANEL; 213 ccp.defaultCursor = SystemCursors.arrow; 214 215 super.createControlParams(ccp); 216 } 217 218 protected override void onDGuiMessage(ref Message m) { 219 switch (m.msg) { 220 case DGUI_ADDCHILDCONTROL: { 221 if (this._canAddChild) { 222 super.onDGuiMessage(m); 223 } else { 224 throwException!(DGuiException)("GridPanel doesn't accept child controls"); 225 } 226 } 227 break; 228 229 default: 230 super.onDGuiMessage(m); 231 break; 232 } 233 } 234 235 public override void updateLayout() { 236 if (this._rows) { 237 int x = 0, y = 0, ctrlCount = 0; 238 239 foreach (RowPart rp; this._rows) { 240 if (rp.columns) { 241 ctrlCount += rp.columns.length; 242 } 243 } 244 245 scope ResizeManager rm = new ResizeManager(ctrlCount); 246 247 foreach (RowPart rp; this._rows) { 248 x = 0; // This is a new Row 249 int maxCtrlHeight = rp.height; 250 251 if (rp.columns) { 252 if (!maxCtrlHeight) { 253 // Find the max height of Controls 254 foreach (ColumnPart cp; rp.columns) { 255 if (cp.control) { 256 maxCtrlHeight = max(maxCtrlHeight, cp.control.height); 257 } 258 } 259 } 260 261 foreach (ColumnPart cp; rp.columns) { 262 int w = cp.width; 263 264 if (cp.control) { 265 if (!w) { 266 w = cp.control.width; 267 } 268 269 //cp.control.bounds = Rect(cp.marginLeft + x, rp.marginTop + y, w, maxCtrlHeight); 270 rm.resizeControl(cp.control, cp.marginLeft + x, 271 rp.marginTop + y, w, maxCtrlHeight); 272 } 273 274 x += cp.marginLeft + w + cp.marginRight; 275 } 276 } 277 278 y += rp.marginTop + maxCtrlHeight + rp.marginBottom; 279 } 280 } 281 } 282 }