Mercurial > projects > dynamin
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dynamin/gui/container.d Mon Jun 15 22:10:48 2009 -0500 @@ -0,0 +1,266 @@ +// Written in the D programming language +// www.digitalmars.com/d/ + +/* + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Dynamin library. + * + * The Initial Developer of the Original Code is Jordan Miner. + * Portions created by the Initial Developer are Copyright (C) 2006-2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jordan Miner <jminer7@gmail.com> + * + */ + +module dynamin.gui.container; + +import dynamin.all_core; +import dynamin.all_painting; +import dynamin.all_gui; +import dynamin.gui.control; +import dynamin.gui.events; +import tango.io.Stdout; + +alias List!(Control) ControlList; + +/// +class Container : Control { +protected: + ControlList _children; + Size _minSize; + Size _maxSize; + + override void whenResized(EventArgs e) { + layout(); + } +public: + /// This event occurs after the control's minimum size has been changed. + Event!() minSizeChanged; + /// Override this method in a subclass to handle the minSizeChanged event. + protected void whenMinSizeChanged(EventArgs e) { } + + /// This event occurs after the control's maximum size has been changed. + Event!() maxSizeChanged; + /// Override this method in a subclass to handle the maxSizeChanged event. + protected void whenMaxSizeChanged(EventArgs e) { } + + this() { + minSizeChanged = new Event!()(&whenMinSizeChanged); + maxSizeChanged = new Event!()(&whenMaxSizeChanged); + _children = new ControlList(); + + elasticX = true; + elasticY = true; + } + override void dispatchPainting(PaintingEventArgs e) { + super.dispatchPainting(e); + foreach(c; _children) { + e.graphics.save(); + e.graphics.translate(c.x, c.y); + c.setupGraphics(e.graphics); + c.painting(e); + e.graphics.restore(); + } + } + // TODO: make these use common code...get rid of copy and paste + override void dispatchMouseDown(MouseEventArgs e) { + auto c = getChildAtPoint(e.location); + if(c && getCaptorControl() !is this) { + e.location = e.location - c.location; + c.mouseDown(e); + e.location = e.location + c.location; + } else { + super.dispatchMouseDown(e); + } + } + override void dispatchMouseUp(MouseEventArgs e) { + auto c = getChildAtPoint(e.location); + if(c && getCaptorControl() !is this) { + e.location = e.location - c.location; + c.mouseUp(e); + e.location = e.location + c.location; + } else { + super.dispatchMouseUp(e); + } + } + override void dispatchMouseMoved(MouseEventArgs e) { + auto c = getChildAtPoint(e.location); + if(c && getCaptorControl() !is this) { + e.location = e.location - c.location; + c.mouseMoved(e); + e.location = e.location + c.location; + } else { + super.dispatchMouseMoved(e); + } + } + override void dispatchMouseDragged(MouseEventArgs e) { + auto c = getChildAtPoint(e.location); + if(c && getCaptorControl() !is this) { + e.location = e.location - c.location; + c.mouseDragged(e); + e.location = e.location + c.location; + } else { + super.dispatchMouseDragged(e); + } + } + /** + * Gets the child control at the specified point. If there are + * multiple child controls at the point, the topmost control is returned. + * If there is no child control at the point, null is returned. The returned + * control, if any, is a direct child of this container. + */ + Control getChildAtPoint(real[] pt) { + assert(pt.length == 2, "pt must be just an x and y"); + return getChildAtPoint(Point(pt[0], pt[1])); + } + /// ditto + Control getChildAtPoint(real x, real y) { + return getChildAtPoint(Point(x, y)); + } + /// ditto + Control getChildAtPoint(Point pt) { + for(int i = _children.count-1; i >= 0; --i) { + pt = pt - _children[i].location; + scope(exit) pt = pt + _children[i].location; + if(_children[i].contains(pt)) + return _children[i]; + } + return null; + } + /** + * Never returns null. If there is no descendant at the specified point, + * this container will be returned. + */ + Control getDescendantAtPoint(real[] pt) { + assert(pt.length == 2, "pt must be just an x and y"); + return getDescendantAtPoint(Point(pt[0], pt[1])); + } + /// ditto + Control getDescendantAtPoint(real x, real y) { + return getDescendantAtPoint(Point(x, y)); + } + /// ditto + Control getDescendantAtPoint(Point pt) { + Container des = this; + while(true) { + auto child = des.getChildAtPoint(pt); + if(!child) + return des; + auto isContainer = cast(Container)child; + if(isContainer) { + des = isContainer; + pt = pt - des.location; + // loop around with this container + } else { + return child; + } + } + } + /** + * Gets or sets the minimum size of this window. A minimum width or + * height of 0 means that there is no minimum width or height. + * The default is Size(0, 0). + */ + Size minSize() { return _minSize; } + /// ditto + void minSize(Size size) { + _minSize = size; + minSizeChanged(new EventArgs); + } + /// ditto + void minSize(real[] size) { + assert(size.length == 2, "size must be just a width and height"); + minSize = Size(size[0], size[1]); + } + /// + real minWidth() { return _minSize.width; } + /// + real minHeight() { return _minSize.height; } + /** + * Gets or sets the maximum size of this window. A maximum width or + * height of 0 means that there is no maximum width or height. + * The default is Size(0, 0). + */ + Size maxSize() { return _maxSize; } + /// ditto + void maxSize(Size size) { + _maxSize = size; + minSizeChanged(new EventArgs); + } + /// ditto + void maxSize(real[] size) { + assert(size.length == 2, "size must be just a width and height"); + maxSize = Size(size[0], size[1]); + } + /// + real maxWidth() { return _maxSize.width; } + /// + real maxHeight() { return _maxSize.height; } + /** + * Causes this container to position its child controls. Called on every + * resize. Usually, this function will get each child's best size, and + * then set each child's location and height. The definition in Container + * is empty, as it is intended for subclasses to override. + */ + void layout() { + } + 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 + } + protected int opApply(int delegate(inout Control item) dg) { + for(uint i = 0; i < _children.count; ++i) { + auto tmp = _children[i]; + if(int result = dg(tmp)) + return result; + } + return 0; + } + protected int opApply(int delegate(inout uint index, inout Control item) dg) { + for(uint i = 0; i < _children.count; ++i) { + auto tmp = _children[i]; + if(int result = dg(i, tmp)) + return result; + } + return 0; + } +} + +// TODO: calling panel.children.add(button) will cause a crash +// because the button's parent is not set to the panel +// need to add a change handler on children? +class Panel : Container { + ControlList children() { return _children; } + void add(Control child) { super.add(child); }; + void remove(Control child) { super.remove(child); }; + int opApply(int delegate(inout Control item) dg) { + return super.opApply(dg); + } + int opApply(int delegate(inout uint index, inout Control item) dg) { + return super.opApply(dg); + } +// override protected void whenPainting() { +// } +} +