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 }