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