Mercurial > projects > dynamin
comparison dynamin/gui/container.d @ 0:aa4efef0f0b1
Initial commit of code.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Mon, 15 Jun 2009 22:10:48 -0500 |
parents | |
children | 4029d5af7542 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:aa4efef0f0b1 |
---|---|
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 /// This event occurs after the control's minimum size has been changed. | |
49 Event!() minSizeChanged; | |
50 /// Override this method in a subclass to handle the minSizeChanged event. | |
51 protected void whenMinSizeChanged(EventArgs e) { } | |
52 | |
53 /// This event occurs after the control's maximum size has been changed. | |
54 Event!() maxSizeChanged; | |
55 /// Override this method in a subclass to handle the maxSizeChanged event. | |
56 protected void whenMaxSizeChanged(EventArgs e) { } | |
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 } | |
117 /** | |
118 * Gets the child control at the specified point. If there are | |
119 * multiple child controls at the point, the topmost control is returned. | |
120 * If there is no child control at the point, null is returned. The returned | |
121 * control, if any, is a direct child of this container. | |
122 */ | |
123 Control getChildAtPoint(real[] pt) { | |
124 assert(pt.length == 2, "pt must be just an x and y"); | |
125 return getChildAtPoint(Point(pt[0], pt[1])); | |
126 } | |
127 /// ditto | |
128 Control getChildAtPoint(real x, real y) { | |
129 return getChildAtPoint(Point(x, y)); | |
130 } | |
131 /// ditto | |
132 Control getChildAtPoint(Point pt) { | |
133 for(int i = _children.count-1; i >= 0; --i) { | |
134 pt = pt - _children[i].location; | |
135 scope(exit) pt = pt + _children[i].location; | |
136 if(_children[i].contains(pt)) | |
137 return _children[i]; | |
138 } | |
139 return null; | |
140 } | |
141 /** | |
142 * Never returns null. If there is no descendant at the specified point, | |
143 * this container will be returned. | |
144 */ | |
145 Control getDescendantAtPoint(real[] pt) { | |
146 assert(pt.length == 2, "pt must be just an x and y"); | |
147 return getDescendantAtPoint(Point(pt[0], pt[1])); | |
148 } | |
149 /// ditto | |
150 Control getDescendantAtPoint(real x, real y) { | |
151 return getDescendantAtPoint(Point(x, y)); | |
152 } | |
153 /// ditto | |
154 Control getDescendantAtPoint(Point pt) { | |
155 Container des = this; | |
156 while(true) { | |
157 auto child = des.getChildAtPoint(pt); | |
158 if(!child) | |
159 return des; | |
160 auto isContainer = cast(Container)child; | |
161 if(isContainer) { | |
162 des = isContainer; | |
163 pt = pt - des.location; | |
164 // loop around with this container | |
165 } else { | |
166 return child; | |
167 } | |
168 } | |
169 } | |
170 /** | |
171 * Gets or sets the minimum size of this window. A minimum width or | |
172 * height of 0 means that there is no minimum width or height. | |
173 * The default is Size(0, 0). | |
174 */ | |
175 Size minSize() { return _minSize; } | |
176 /// ditto | |
177 void minSize(Size size) { | |
178 _minSize = size; | |
179 minSizeChanged(new EventArgs); | |
180 } | |
181 /// ditto | |
182 void minSize(real[] size) { | |
183 assert(size.length == 2, "size must be just a width and height"); | |
184 minSize = Size(size[0], size[1]); | |
185 } | |
186 /// | |
187 real minWidth() { return _minSize.width; } | |
188 /// | |
189 real minHeight() { return _minSize.height; } | |
190 /** | |
191 * Gets or sets the maximum size of this window. A maximum width or | |
192 * height of 0 means that there is no maximum width or height. | |
193 * The default is Size(0, 0). | |
194 */ | |
195 Size maxSize() { return _maxSize; } | |
196 /// ditto | |
197 void maxSize(Size size) { | |
198 _maxSize = size; | |
199 minSizeChanged(new EventArgs); | |
200 } | |
201 /// ditto | |
202 void maxSize(real[] size) { | |
203 assert(size.length == 2, "size must be just a width and height"); | |
204 maxSize = Size(size[0], size[1]); | |
205 } | |
206 /// | |
207 real maxWidth() { return _maxSize.width; } | |
208 /// | |
209 real maxHeight() { return _maxSize.height; } | |
210 /** | |
211 * Causes this container to position its child controls. Called on every | |
212 * resize. Usually, this function will get each child's best size, and | |
213 * then set each child's location and height. The definition in Container | |
214 * is empty, as it is intended for subclasses to override. | |
215 */ | |
216 void layout() { | |
217 } | |
218 protected void add(Control child) { | |
219 if(child.parent) | |
220 child.parent.remove(child); | |
221 _children.add(child); | |
222 child.parent = this; | |
223 repaint(); | |
224 //ControlAdded(EventArgs e); // TODO: add event | |
225 } | |
226 protected void remove(Control child) { | |
227 _children.remove(child); | |
228 child.parent = null; | |
229 repaint(); | |
230 //ControlRemoved(EventArgs e); // TODO: add event | |
231 } | |
232 protected int opApply(int delegate(inout Control item) dg) { | |
233 for(uint i = 0; i < _children.count; ++i) { | |
234 auto tmp = _children[i]; | |
235 if(int result = dg(tmp)) | |
236 return result; | |
237 } | |
238 return 0; | |
239 } | |
240 protected int opApply(int delegate(inout uint index, inout Control item) dg) { | |
241 for(uint i = 0; i < _children.count; ++i) { | |
242 auto tmp = _children[i]; | |
243 if(int result = dg(i, tmp)) | |
244 return result; | |
245 } | |
246 return 0; | |
247 } | |
248 } | |
249 | |
250 // TODO: calling panel.children.add(button) will cause a crash | |
251 // because the button's parent is not set to the panel | |
252 // need to add a change handler on children? | |
253 class Panel : Container { | |
254 ControlList children() { return _children; } | |
255 void add(Control child) { super.add(child); }; | |
256 void remove(Control child) { super.remove(child); }; | |
257 int opApply(int delegate(inout Control item) dg) { | |
258 return super.opApply(dg); | |
259 } | |
260 int opApply(int delegate(inout uint index, inout Control item) dg) { | |
261 return super.opApply(dg); | |
262 } | |
263 // override protected void whenPainting() { | |
264 // } | |
265 } | |
266 |