Mercurial > projects > dynamin
diff dynamin/gui/container.d @ 55:c138461bf845
Add focusing and other changes that are related
like descendantAdded/Removed events, Window.activated event, and updating List.
Window.state was also added, even though focusing does not depend on it.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 08 Aug 2009 15:42:27 -0500 |
parents | ee9a564d2814 |
children | c2566ab82535 |
line wrap: on
line diff
--- a/dynamin/gui/container.d Sat Aug 08 15:31:24 2009 -0500 +++ b/dynamin/gui/container.d Sat Aug 08 15:42:27 2009 -0500 @@ -32,7 +32,7 @@ import dynamin.gui.events; import tango.io.Stdout; -alias List!(Control) ControlList; +alias List!(Control, true) ControlList; /// class Container : Control { @@ -44,6 +44,100 @@ override void whenResized(EventArgs e) { layout(); } + // If the specified array is large enough to hold the results, no heap + // allocation will be done. + Control[] getFocusableDescendants(Control[] des = null) { + uint cur = 0; + + void addDescendants(Container c) { + if(c._focusable) { // TODO: && c.enabled) { + if(cur == des.length) + des.length = des.length + 20; + des[cur++] = c; + } + foreach(ch; c._children) { + if(cast(Container)ch) + addDescendants(cast(Container)ch); + else if(ch.focusable) { // TODO: && ch.enabled) { + if(cur == des.length) + des.length = des.length + 20; + des[cur++] = ch; + } + } + } + addDescendants(this); + return des[0..cur]; + } + unittest { + class MyControl : Control { + this() { + _focusable = true; + } + } + auto container1 = new Container(); + auto container2 = new Container(); + auto container3 = new Container(); + auto container4 = new Container(); + container2._focusable = true; + container4._focusable = true; + auto ctrl1 = new MyControl(); + auto ctrl2 = new MyControl(); + auto ctrl3 = new MyControl(); + + container1.add(container2); + container1.add(container3); + container3.add(container4); + container2.add(ctrl1); + container4.add(ctrl2); + container4.add(ctrl3); + assert(container1.getFocusableDescendants() == + [cast(Control)container2, ctrl1, container4, ctrl2, ctrl3]); + Control[5] buf; + assert(container1.getFocusableDescendants(buf).ptr == buf.ptr); + } + + // not an event + void whenChildAdded(Control child, int) { + if(child.parent) + child.parent.remove(child); + child.parent = this; + repaint(); + + void callAdded(Control ctrl) { + scope e = new HierarchyEventArgs(ctrl); + descendantAdded(e); + + if(auto cntr = cast(Container)ctrl) { + foreach(c; cntr._children) + callAdded(c); + } + } + callAdded(child); + } + + // not an event + void whenChildRemoved(Control child, int) { + child.parent = null; + repaint(); + + scope e = new HierarchyEventArgs(child); + descendantRemoved(e); + } + + void dispatchDescendantAdded(HierarchyEventArgs e) { + descendantAdded.callHandlers(e); + descendantAdded.callMainHandler(e); + e.levels = e.levels + 1; + if(_parent) + _parent.descendantAdded(e); + } + void dispatchDescendantRemoved(HierarchyEventArgs e) { + descendantRemoved.callHandlers(e); + descendantRemoved.callMainHandler(e); + e.levels = e.levels + 1; + if(_parent) + _parent.descendantRemoved(e); + } public: /// Override this method in a subclass to handle the minSizeChanged event. protected void whenMinSizeChanged(EventArgs e) { } @@ -55,10 +149,25 @@ /// This event occurs after the control's maximum size has been changed. Event!(whenMaxSizeChanged) maxSizeChanged; + /// Override this method in a subclass to handle the descendantAdded event. + protected void whenDescendantAdded(HierarchyEventArgs e) { } + /// This event occurs after a control is added as a descendant of this container. + Event!(whenDescendantAdded) descendantAdded; + + /// Override this method in a subclass to handle the descendantRemoved event. + protected void whenDescendantRemoved(HierarchyEventArgs e) { } + /// This event occurs after a descendant of this container has been removed. + Event!(whenDescendantRemoved) descendantRemoved; + this() { minSizeChanged.mainHandler = &whenMinSizeChanged; maxSizeChanged.mainHandler = &whenMaxSizeChanged; - _children = new ControlList(); + descendantAdded.mainHandler = &whenDescendantAdded; + descendantAdded.dispatcher = &dispatchDescendantAdded; + descendantRemoved.mainHandler = &whenDescendantRemoved; + descendantRemoved.dispatcher = &dispatchDescendantRemoved; + + _children = new ControlList(&whenChildAdded, &whenChildRemoved); elasticX = true; elasticY = true; @@ -222,19 +331,11 @@ } protected void add(Control child) { - if(child.parent) - child.parent.remove(child); _children.add(child); - child.parent = this; - repaint(); - //ControlAdded(EventArgs e); // TODO: add event } protected void remove(Control child) { _children.remove(child); - child.parent = null; - repaint(); - //ControlRemoved(EventArgs e); // TODO: add event } int opApply(int delegate(inout Control item) dg) { @@ -254,6 +355,15 @@ return 0; } } +unittest { + auto i = 0; + auto container = new Panel; + container.descendantAdded += (HierarchyEventArgs e) { i++; }; + auto sub = new Panel; + sub.add(new Control); + container.add(sub); + assert(i == 2); +} // TODO: calling panel.children.add(button) will cause a crash // because the button's parent is not set to the panel