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 }