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
10
11 module dgui.layout.splitpanel;
12
13 import dgui.core.events.event;
14 import dgui.core.events.eventargs;
15 import dgui.layout.layoutcontrol;
16 import dgui.layout.panel;
17
18 enum SplitOrientation
19 {
20 vertical = 1,
21 horizontal = 2,
22 }
23
24 class SplitPanel: LayoutControl
25 {
26 private enum int splitterSize = 8;
27
28 private SplitOrientation _splitOrientation = SplitOrientation.vertical;
29 private bool _downing = false;
30 private int _splitPos = 0;
31 private Panel _panel1;
32 private Panel _panel2;
33
34 public this()
35 {
36 this._panel1 = new Panel();
37 this._panel1.parent = this;
38
39 this._panel2 = new Panel();
40 this._panel2.parent = this;
41 }
42
43 @property public void splitPosition(int sp)
44 {
45 this._splitPos = sp;
46
47 if(this.created)
48 {
49 this.updateLayout();
50 }
51 }
52
53 @property public Panel panel1()
54 {
55 return this._panel1;
56 }
57
58 @property public Panel panel2()
59 {
60 return this._panel2;
61 }
62
63 @property SplitOrientation splitOrientation()
64 {
65 return this._splitOrientation;
66 }
67
68 @property void splitOrientation(SplitOrientation so)
69 {
70 this._splitOrientation = so;
71 }
72
73 public override void updateLayout()
74 {
75 scope ResizeManager rm = new ResizeManager(2); //Fixed Panel
76
77 bool changed = false;
78
79 switch(this._splitOrientation)
80 {
81 case SplitOrientation.vertical:
82 {
83 if(this._splitPos >= 0 && (this._splitPos + splitterSize) < this.width)
84 {
85 rm.setSize(this._panel1, this._splitPos, this.height);
86 rm.resizeControl(this._panel2, this._splitPos + splitterSize, 0, this.width - (this._splitPos + splitterSize), this.height);
87 changed = true;
88 }
89 }
90 break;
91
92 default: // SplitOrientation.horizontal
93 {
94 if(this._splitPos >= 0 && (this._splitPos + splitterSize) < this.height)
95 {
96 rm.setSize(this._panel1, this.width, this._splitPos);
97 rm.resizeControl(this._panel2, 0, this._splitPos + splitterSize, this.width, this.height - (this._splitPos + splitterSize));
98 changed = true;
99 }
100 }
101 break;
102 }
103
104 if(changed)
105 {
106 this.invalidate();
107 }
108 }
109
110 protected override void onMouseKeyDown(MouseEventArgs e)
111 {
112 if(e.keys == MouseKeys.left)
113 {
114 this._downing = true;
115 SetCapture(this._handle);
116 }
117
118 super.onMouseKeyDown(e);
119 }
120
121 protected override void onMouseKeyUp(MouseEventArgs e)
122 {
123 if(this._downing)
124 {
125 this._downing = false;
126 ReleaseCapture();
127 }
128
129 super.onMouseKeyUp(e);
130 }
131
132 protected override void onMouseMove(MouseEventArgs e)
133 {
134 if(this._downing)
135 {
136 Point pt = Cursor.position;
137 convertPoint(pt, null, this);
138
139 switch(this._splitOrientation)
140 {
141 case SplitOrientation.vertical:
142 this._splitPos = pt.x;
143 break;
144
145 default: // SplitOrientation.horizontal
146 this._splitPos = pt.y;
147 break;
148 }
149
150 this.updateLayout();
151 }
152
153 super.onMouseMove(e);
154 }
155
156 protected override void createControlParams(ref CreateControlParams ccp)
157 {
158 ccp.className = WC_DSPLITPANEL;
159
160 switch(this._splitOrientation)
161 {
162 case SplitOrientation.vertical:
163 ccp.defaultCursor = SystemCursors.sizeWE;
164 break;
165
166 default: // SplitOrientation.horizontal
167 ccp.defaultCursor = SystemCursors.sizeNS;
168 break;
169 }
170
171 if(!this._splitPos)
172 {
173 switch(this._splitOrientation)
174 {
175 case SplitOrientation.vertical:
176 this._splitPos = this.width / 3;
177 break;
178
179 default: // SplitOrientation.horizontal
180 this._splitPos = this.height - (this.height / 3);
181 break;
182 }
183 }
184
185 super.createControlParams(ccp);
186 }
187
188 protected override void onDGuiMessage(ref Message m)
189 {
190 switch(m.msg)
191 {
192 case DGUI_ADDCHILDCONTROL:
193 {
194 Control c = winCast!(Control)(m.wParam);
195
196 if(c is this._panel1 || c is this._panel2)
197 {
198 super.onDGuiMessage(m);
199 }
200 else
201 {
202 throwException!(DGuiException)("SplitPanel doesn't accept child controls");
203 }
204 }
205 break;
206
207 default:
208 super.onDGuiMessage(m);
209 break;
210 }
211 }
212
213 protected override void onHandleCreated(EventArgs e)
214 {
215 switch(this._splitOrientation)
216 {
217 case SplitOrientation.vertical:
218 this.cursor = SystemCursors.sizeWE;
219 break;
220
221 default: // SplitOrientation.horizontal
222 this.cursor = SystemCursors.sizeNS;
223 break;
224 }
225
226 super.onHandleCreated(e);
227 }
228
229 protected override void onPaint(PaintEventArgs e)
230 {
231 Canvas c = e.canvas;
232 Rect cr = e.clipRectangle;
233 int mid = this._splitPos + (splitterSize / 2);
234 scope Pen dp = new Pen(SystemColors.color3DDarkShadow, 2, PenStyle.dot);
235 scope Pen lp = new Pen(SystemColors.colorButtonFace, 2, PenStyle.dot);
236
237 switch(this._splitOrientation)
238 {
239 case SplitOrientation.vertical:
240 {
241 c.drawEdge(Rect(this._splitPos, cr.top, splitterSize, cr.bottom), EdgeType.raised, EdgeMode.left | EdgeMode.right);
242
243 for(int p = (this.height / 2) - 15, i = 0; i < 8; i++, p += 5)
244 {
245 c.drawLine(dp, mid, p, mid, p + 1);
246 c.drawLine(lp, mid - 1, p - 1, mid - 1, p);
247 }
248 }
249 break;
250
251 default: // SplitOrientation.horizontal
252 {
253 c.drawEdge(Rect(cr.left, this._splitPos, cr.right, splitterSize), EdgeType.raised, EdgeMode.top | EdgeMode.bottom);
254
255 for(int p = (this.width / 2) - 15, i = 0; i < 8; i++, p += 5)
256 {
257 c.drawLine(dp, p, mid, p + 1, mid);
258 c.drawLine(lp, p - 1, mid + 1, p - 1, mid);
259 }
260 }
261 break;
262 }
263
264 super.onPaint(e);
265 }
266
267 protected override void wndProc(ref Message m)
268 {
269 if(m.msg == WM_WINDOWPOSCHANGING)
270 {
271 WINDOWPOS* pWndPos = cast(WINDOWPOS*)m.lParam;
272
273 if(!(pWndPos.flags & SWP_NOSIZE))
274 {
275 switch(this._splitOrientation)
276 {
277 case SplitOrientation.vertical:
278 {
279 if(this.width) // Avoid division by 0
280 this._splitPos = MulDiv(pWndPos.cx, this._splitPos, this.width);
281 }
282 break;
283
284 default: // SplitOrientation.horizontal
285 {
286 if(this.height) // Avoid division by 0
287 this._splitPos = MulDiv(pWndPos.cy, this._splitPos, this.height);
288 }
289 break;
290 }
291 }
292 }
293
294 super.wndProc(m);
295 }
296 }