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.layoutcontrol;
10 
11 import dgui.core.interfaces.ilayoutcontrol;
12 public import dgui.core.controls.containercontrol;
13 
14 class ResizeManager: Handle!(HDWP), IDisposable
15 {
16 	public this(int c)
17 	{
18 		if(c > 1)
19 		{
20 			this._handle = BeginDeferWindowPos(c);
21 		}
22 	}
23 
24 	public ~this()
25 	{
26 		this.dispose();
27 	}
28 
29 	public void dispose()
30 	{
31 		if(this._handle)
32 		{
33 			EndDeferWindowPos(this._handle);
34 		}
35 	}
36 
37 	public void setPosition(Control ctrl, Point pt)
38 	{
39 		this.setPosition(ctrl, pt.x, pt.y);
40 	}
41 
42 	public void setPosition(Control ctrl, int x, int y)
43 	{
44 		this.resizeControl(ctrl, x, y, 0, 0, PositionSpecified.position);
45 	}
46 
47 	public void setSize(Control ctrl, Size sz)
48 	{
49 		this.setSize(ctrl, sz.width, sz.height);
50 	}
51 
52 	public void setSize(Control ctrl, int w, int h)
53 	{
54 		this.resizeControl(ctrl, 0, 0, w, h, PositionSpecified.size);
55 	}
56 
57 	public void resizeControl(Control ctrl, Rect r, PositionSpecified ps = PositionSpecified.all)
58 	{
59 		this.resizeControl(ctrl, r.x, r.y, r.width, r.height, ps);
60 	}
61 
62 	public void resizeControl(Control ctrl, int x, int y, int w, int h, PositionSpecified ps = PositionSpecified.all)
63 	{
64 		uint wpf = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE;
65 
66 		if(ps !is PositionSpecified.all)
67 		{
68 			if(ps is PositionSpecified.position)
69 			{
70 				wpf &= ~SWP_NOMOVE;
71 			}
72 			else //if(ps is PositionSpecified.size)
73 			{
74 				wpf &= ~SWP_NOSIZE;
75 			}
76 		}
77 		else
78 		{
79 			wpf &= ~(SWP_NOMOVE | SWP_NOSIZE);
80 		}
81 
82 		if(this._handle)
83 		{
84 			this._handle = DeferWindowPos(this._handle, ctrl.handle, null, x, y, w, h, wpf);
85 		}
86 		else
87 		{
88 			SetWindowPos(ctrl.handle, null, x, y, w, h, wpf); //Bounds updated in WM_WINDOWPOSCHANGED
89 		}
90 	}
91 }
92 
93 abstract class LayoutControl: ContainerControl, ILayoutControl
94 {
95 	public override void show()
96 	{
97 		super.show();
98 		this.updateLayout();
99 	}
100 
101 	public void updateLayout()
102 	{
103 	
104 		// MGW
105 		import std.stdio: writeln;
106 		
107 		
108 		if(this._childControls && this.created && this.visible)
109 		{
110 			scope ResizeManager rm = new ResizeManager(this._childControls.length);
111 			Rect da = Rect(nullPoint, this.clientSize);
112 			// writeln("---> da = ", da);
113 			// writeln("---> da.top = ", da.top);
114 			// Считаем высоту и ширину всех элементов
115 			int allH, allW; 
116 			foreach(Control c; this._childControls) {
117 				if(c.dock == DockStyle.top  ||  c.dock == DockStyle.bottom  ||  c.dock == DockStyle.height) allH += c.height;
118 				if(c.dock == DockStyle.left ||  c.dock == DockStyle.right   ||  c.dock == DockStyle.width)  allW += c.width;
119 			}
120 
121 			foreach(Control c; this._childControls)
122 			{
123 				if(da.empty)
124 				{
125 					rm.dispose();
126 					break;
127 				}
128 
129 				if(c.dock !is DockStyle.none && c.visible && c.created)
130 				{
131 					Rect da2 = Rect(nullPoint, this.clientSize);
132 					switch(c.dock)
133 					{
134 						// Добавлено два новых стиля height и width. В наборен элементов может быть
135 						// только один элемент этих стилей
136 						case DockStyle.height:
137 							allH -= c.height; c.height = da2.height - allH;
138 							rm.resizeControl(c, da.left, da.top, da.width, c.height);
139 							break;
140 
141 						case DockStyle.width:
142 							allW -= c.width; c.width = da2.width - allW;
143 							rm.resizeControl(c, da.left, da.top, c.width, da.height);
144 							break;
145 
146 						case DockStyle.left:
147 							//c.bounds = Rect(da.left, da.top, c.width, da.height);
148 							rm.resizeControl(c, da.left, da.top, c.width, da.height);
149 							da.left += c.width;
150 							break;
151 
152 						case DockStyle.top:
153 							//c.bounds = Rect(da.left, da.top, da.width, c.height);
154 							rm.resizeControl(c, da.left, da.top, da.width, c.height);
155 							da.top += c.height;
156 							break;
157 
158 						case DockStyle.right:
159 							//c.bounds = Rect(da.right - c.width, da.top, c.width, da.height);
160 							rm.resizeControl(c, da.right - c.width, da.top, c.width, da.height);
161 							da.right -= c.width;
162 							break;
163 
164 						case DockStyle.bottom:
165 							//c.bounds = Rect(c, da.left, da.bottom - c.height, da.width, c.height);
166 							rm.resizeControl(c, da.left, da.bottom - c.height, da.width, c.height);
167 							da.bottom -= c.height;
168 							break;
169 
170 						case DockStyle.fill:
171 							//c.bounds = da;
172 							rm.resizeControl(c, da);
173 							da.size = nullSize;
174 							break;
175 
176 						default:
177 							rm.dispose();
178 							assert(false, "Unknown DockStyle");
179 							//break;
180 					}
181 				}
182 			}
183 		}
184 	}
185 
186 	protected override void onDGuiMessage(ref Message m)
187 	{
188 		switch(m.msg)
189 		{
190 			case DGUI_DOLAYOUT:
191 				this.updateLayout();
192 				break;
193 
194 			case DGUI_CHILDCONTROLCREATED:
195 			{
196 				Control c = winCast!(Control)(m.wParam);
197 
198 				if(c.dock !is DockStyle.none && c.visible)
199 				{
200 					this.updateLayout();
201 				}
202 			}
203 			break;
204 
205 			default:
206 				break;
207 		}
208 
209 		super.onDGuiMessage(m);
210 	}
211 
212 	protected override void onHandleCreated(EventArgs e)
213 	{
214 		super.onHandleCreated(e);
215 
216 		this.updateLayout();
217 	}
218 
219 	protected override void onResize(EventArgs e)
220 	{
221 		this.updateLayout();
222 
223 		InvalidateRect(this._handle, null, true);
224 		UpdateWindow(this._handle);
225 		super.onResize(e);
226 	}
227 }