Mercurial > projects > dynamin
annotate dynamin/gui/container.d @ 8:b621b528823d
whenXX methods have to come before the event if switched to template mixins.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Wed, 15 Jul 2009 14:04:55 -0500 |
parents | 4029d5af7542 |
children | ccc108b25a0a |
rev | line source |
---|---|
0 | 1 // Written in the D programming language |
2 // www.digitalmars.com/d/ | |
3 | |
4 /* | |
5 * The contents of this file are subject to the Mozilla Public License Version | |
6 * 1.1 (the "License"); you may not use this file except in compliance with | |
7 * the License. You may obtain a copy of the License at | |
8 * http://www.mozilla.org/MPL/ | |
9 * | |
10 * Software distributed under the License is distributed on an "AS IS" basis, | |
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 * for the specific language governing rights and limitations under the | |
13 * License. | |
14 * | |
15 * The Original Code is the Dynamin library. | |
16 * | |
17 * The Initial Developer of the Original Code is Jordan Miner. | |
18 * Portions created by the Initial Developer are Copyright (C) 2006-2009 | |
19 * the Initial Developer. All Rights Reserved. | |
20 * | |
21 * Contributor(s): | |
22 * Jordan Miner <jminer7@gmail.com> | |
23 * | |
24 */ | |
25 | |
26 module dynamin.gui.container; | |
27 | |
28 import dynamin.all_core; | |
29 import dynamin.all_painting; | |
30 import dynamin.all_gui; | |
31 import dynamin.gui.control; | |
32 import dynamin.gui.events; | |
33 import tango.io.Stdout; | |
34 | |
35 alias List!(Control) ControlList; | |
36 | |
37 /// | |
38 class Container : Control { | |
39 protected: | |
40 ControlList _children; | |
41 Size _minSize; | |
42 Size _maxSize; | |
43 | |
44 override void whenResized(EventArgs e) { | |
45 layout(); | |
46 } | |
47 public: | |
48 /// Override this method in a subclass to handle the minSizeChanged event. | |
49 protected void whenMinSizeChanged(EventArgs e) { } | |
8
b621b528823d
whenXX methods have to come before the event if switched to template mixins.
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
50 /// This event occurs after the control's minimum size has been changed. |
b621b528823d
whenXX methods have to come before the event if switched to template mixins.
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
51 Event!() minSizeChanged; |
0 | 52 |
8
b621b528823d
whenXX methods have to come before the event if switched to template mixins.
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
53 /// Override this method in a subclass to handle the maxSizeChanged event. |
b621b528823d
whenXX methods have to come before the event if switched to template mixins.
Jordan Miner <jminer7@gmail.com>
parents:
5
diff
changeset
|
54 protected void whenMaxSizeChanged(EventArgs e) { } |
0 | 55 /// This event occurs after the control's maximum size has been changed. |
56 Event!() maxSizeChanged; | |
57 | |
58 this() { | |
59 minSizeChanged = new Event!()(&whenMinSizeChanged); | |
60 maxSizeChanged = new Event!()(&whenMaxSizeChanged); | |
61 _children = new ControlList(); | |
62 | |
63 elasticX = true; | |
64 elasticY = true; | |
65 } | |
66 override void dispatchPainting(PaintingEventArgs e) { | |
67 super.dispatchPainting(e); | |
68 foreach(c; _children) { | |
69 e.graphics.save(); | |
70 e.graphics.translate(c.x, c.y); | |
71 c.setupGraphics(e.graphics); | |
72 c.painting(e); | |
73 e.graphics.restore(); | |
74 } | |
75 } | |
76 // TODO: make these use common code...get rid of copy and paste | |
77 override void dispatchMouseDown(MouseEventArgs e) { | |
78 auto c = getChildAtPoint(e.location); | |
79 if(c && getCaptorControl() !is this) { | |
80 e.location = e.location - c.location; | |
81 c.mouseDown(e); | |
82 e.location = e.location + c.location; | |
83 } else { | |
84 super.dispatchMouseDown(e); | |
85 } | |
86 } | |
87 override void dispatchMouseUp(MouseEventArgs e) { | |
88 auto c = getChildAtPoint(e.location); | |
89 if(c && getCaptorControl() !is this) { | |
90 e.location = e.location - c.location; | |
91 c.mouseUp(e); | |
92 e.location = e.location + c.location; | |
93 } else { | |
94 super.dispatchMouseUp(e); | |
95 } | |
96 } | |
97 override void dispatchMouseMoved(MouseEventArgs e) { | |
98 auto c = getChildAtPoint(e.location); | |
99 if(c && getCaptorControl() !is this) { | |
100 e.location = e.location - c.location; | |
101 c.mouseMoved(e); | |
102 e.location = e.location + c.location; | |
103 } else { | |
104 super.dispatchMouseMoved(e); | |
105 } | |
106 } | |
107 override void dispatchMouseDragged(MouseEventArgs e) { | |
108 auto c = getChildAtPoint(e.location); | |
109 if(c && getCaptorControl() !is this) { | |
110 e.location = e.location - c.location; | |
111 c.mouseDragged(e); | |
112 e.location = e.location + c.location; | |
113 } else { | |
114 super.dispatchMouseDragged(e); | |
115 } | |
116 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
117 |
0 | 118 /** |
119 * Gets the child control at the specified point. If there are | |
120 * multiple child controls at the point, the topmost control is returned. | |
121 * If there is no child control at the point, null is returned. The returned | |
122 * control, if any, is a direct child of this container. | |
123 */ | |
124 Control getChildAtPoint(real[] pt) { | |
125 assert(pt.length == 2, "pt must be just an x and y"); | |
126 return getChildAtPoint(Point(pt[0], pt[1])); | |
127 } | |
128 /// ditto | |
129 Control getChildAtPoint(real x, real y) { | |
130 return getChildAtPoint(Point(x, y)); | |
131 } | |
132 /// ditto | |
133 Control getChildAtPoint(Point pt) { | |
134 for(int i = _children.count-1; i >= 0; --i) { | |
135 pt = pt - _children[i].location; | |
136 scope(exit) pt = pt + _children[i].location; | |
137 if(_children[i].contains(pt)) | |
138 return _children[i]; | |
139 } | |
140 return null; | |
141 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
142 |
0 | 143 /** |
144 * Never returns null. If there is no descendant at the specified point, | |
145 * this container will be returned. | |
146 */ | |
147 Control getDescendantAtPoint(real[] pt) { | |
148 assert(pt.length == 2, "pt must be just an x and y"); | |
149 return getDescendantAtPoint(Point(pt[0], pt[1])); | |
150 } | |
151 /// ditto | |
152 Control getDescendantAtPoint(real x, real y) { | |
153 return getDescendantAtPoint(Point(x, y)); | |
154 } | |
155 /// ditto | |
156 Control getDescendantAtPoint(Point pt) { | |
157 Container des = this; | |
158 while(true) { | |
159 auto child = des.getChildAtPoint(pt); | |
160 if(!child) | |
161 return des; | |
162 auto isContainer = cast(Container)child; | |
163 if(isContainer) { | |
164 des = isContainer; | |
165 pt = pt - des.location; | |
166 // loop around with this container | |
167 } else { | |
168 return child; | |
169 } | |
170 } | |
171 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
172 |
0 | 173 /** |
174 * Gets or sets the minimum size of this window. A minimum width or | |
175 * height of 0 means that there is no minimum width or height. | |
176 * The default is Size(0, 0). | |
177 */ | |
178 Size minSize() { return _minSize; } | |
179 /// ditto | |
180 void minSize(Size size) { | |
181 _minSize = size; | |
182 minSizeChanged(new EventArgs); | |
183 } | |
184 /// ditto | |
185 void minSize(real[] size) { | |
186 assert(size.length == 2, "size must be just a width and height"); | |
187 minSize = Size(size[0], size[1]); | |
188 } | |
189 /// | |
190 real minWidth() { return _minSize.width; } | |
191 /// | |
192 real minHeight() { return _minSize.height; } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
193 |
0 | 194 /** |
195 * Gets or sets the maximum size of this window. A maximum width or | |
196 * height of 0 means that there is no maximum width or height. | |
197 * The default is Size(0, 0). | |
198 */ | |
199 Size maxSize() { return _maxSize; } | |
200 /// ditto | |
201 void maxSize(Size size) { | |
202 _maxSize = size; | |
203 minSizeChanged(new EventArgs); | |
204 } | |
205 /// ditto | |
206 void maxSize(real[] size) { | |
207 assert(size.length == 2, "size must be just a width and height"); | |
208 maxSize = Size(size[0], size[1]); | |
209 } | |
210 /// | |
211 real maxWidth() { return _maxSize.width; } | |
212 /// | |
213 real maxHeight() { return _maxSize.height; } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
214 |
0 | 215 /** |
216 * Causes this container to position its child controls. Called on every | |
217 * resize. Usually, this function will get each child's best size, and | |
218 * then set each child's location and height. The definition in Container | |
219 * is empty, as it is intended for subclasses to override. | |
220 */ | |
221 void layout() { | |
222 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
223 |
0 | 224 protected void add(Control child) { |
225 if(child.parent) | |
226 child.parent.remove(child); | |
227 _children.add(child); | |
228 child.parent = this; | |
229 repaint(); | |
230 //ControlAdded(EventArgs e); // TODO: add event | |
231 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
232 |
0 | 233 protected void remove(Control child) { |
234 _children.remove(child); | |
235 child.parent = null; | |
236 repaint(); | |
237 //ControlRemoved(EventArgs e); // TODO: add event | |
238 } | |
5
4029d5af7542
Add blank lines and rewrap some comments.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
239 |
0 | 240 protected int opApply(int delegate(inout Control item) dg) { |
241 for(uint i = 0; i < _children.count; ++i) { | |
242 auto tmp = _children[i]; | |
243 if(int result = dg(tmp)) | |
244 return result; | |
245 } | |
246 return 0; | |
247 } | |
248 protected int opApply(int delegate(inout uint index, inout Control item) dg) { | |
249 for(uint i = 0; i < _children.count; ++i) { | |
250 auto tmp = _children[i]; | |
251 if(int result = dg(i, tmp)) | |
252 return result; | |
253 } | |
254 return 0; | |
255 } | |
256 } | |
257 | |
258 // TODO: calling panel.children.add(button) will cause a crash | |
259 // because the button's parent is not set to the panel | |
260 // need to add a change handler on children? | |
261 class Panel : Container { | |
262 ControlList children() { return _children; } | |
263 void add(Control child) { super.add(child); }; | |
264 void remove(Control child) { super.remove(child); }; | |
265 int opApply(int delegate(inout Control item) dg) { | |
266 return super.opApply(dg); | |
267 } | |
268 int opApply(int delegate(inout uint index, inout Control item) dg) { | |
269 return super.opApply(dg); | |
270 } | |
271 // override protected void whenPainting() { | |
272 // } | |
273 } | |
274 |