Mercurial > projects > mde
view mde/gui/widget/AParentWidget.d @ 171:7f7b2011b759
Partially complete commit: code runs but context menus don't work.
Moved WMScreen.createRootWidget to WidgetManager.createWidgets.
Put childContext under a popupHandler widget.
TODO: implement IChildWidget.setContent(Content) (see AParentWidget.d:237).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sun, 26 Jul 2009 11:04:17 +0200 |
parents | c67d074a7111 |
children | 0dd49f333189 |
line wrap: on
line source
/* LICENSE BLOCK Part of mde: a Modular D game-oriented Engine Copyright © 2007-2008 Diggory Hardy This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /****************************************************************************** * This module contains base widget classes for parent widgets. * * Abstract widget classes have an 'A' prepended to the name, similar to the * 'I' convention for interfaces. *****************************************************************************/ module mde.gui.widget.AParentWidget; public import mde.gui.widget.AChildWidget; import mde.gui.exception; import mde.content.IContent; debug { import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.widget.AParentWidget"); } } /****************************************************************************** * Abstract base widget classes to facilitate parent widgets. * * To improve code sharing, there's no separate version for parents taking a * single subwidget. * * Parent widgets probably need to overload these functions (from AChildWidget): * setup, saveChanges, setPosition, getWidget, draw, setWidth and setHeight. *****************************************************************************/ abstract class AParentWidget : AChildWidget, IParentWidget { protected this (IWidgetManager mgr, IParentWidget parent, widgetID id) { super (mgr, parent, id); } override bool setup (uint n, uint flags) { debug (mdeWidgets) logger.trace ("AParentWidget.setup"); bool c = false; foreach (w; subWidgets) { debug assert (w, "AParentWidget: w is null"); c |= w.setup (n,flags); } return c; } override bool saveChanges () { bool c = false; foreach (w; subWidgets) c |= w.saveChanges; return c; } size_t getWidgetIndex (IChildWidget widg) { foreach (i,w; subWidgets) if (w is widg) return i; throw new GuiException ("getWidgetIndex: widget not found (code error)"); } // Parents taking a content should override, only throwing if both the // widget id and the content are the same (as its it and content). override void recursionCheck (widgetID wID, IContent c) { debug assert (id !is null && parent !is null, "recursionCheck called before parent and id set"); if (wID == id) throw new WidgetRecursionException (wID); parent.recursionCheck (wID, c); } IPopupParentWidget getParentIPPW () { return parent.getParentIPPW; } // Most parent widgets need to implement these, although not all void minWChange (IChildWidget widget, wdim mw) {} void minHChange (IChildWidget widget, wdim mh) {} debug override void logWidgetSize () { super.logWidgetSize; foreach (widg; subWidgets) widg.logWidgetSize; } protected: IChildWidget[] subWidgets; } /****************************************************************************** * Base code for implementing IPopupParentWidget. * * The current intention is that an IPPW (excluding the widget manager) may * only have one popup; this class follows this intention. *****************************************************************************/ abstract class APopupParentWidget : AParentWidget, IPopupParentWidget { protected this (IWidgetManager mgr, IParentWidget parent, widgetID id) { super (mgr, parent, id); parentIPPW = parent.getParentIPPW; } override IPopupParentWidget getParentIPPW () { return this; } override void addChildIPPW (IPopupParentWidget ippw) { if (childIPPW) childIPPW.removedIPPW; childIPPW = ippw; mgr.requestRedraw; } override bool removeChildIPPW (IPopupParentWidget ippw) { if (childIPPW !is ippw) return false; childIPPW.removedIPPW; childIPPW = null; mgr.requestRedraw; mAIPPW = MenuPosition.INACTIVE; return true; } // If this function is overriden, you MUST still call it (super.removedIPPW)! // Or invariant will throw assert errors. override void removedIPPW () { if (childIPPW) { childIPPW.removedIPPW; childIPPW = null; } mAIPPW = MenuPosition.INACTIVE; } override void menuActive (MenuPosition mA) { mAIPPW = mA; if (childIPPW) childIPPW.menuActive = mA; } override MenuPosition menuActive () { return mAIPPW; } override MenuPosition parentMenuActive () { return parentIPPW.menuActive; } override void menuDone () { // default actions, for popup menus: parentIPPW.removeChildIPPW (this); // remove self parentIPPW.menuDone; // and propegate } override IChildWidget getPopupWidget (wdabs cx, wdabs cy, bool closePopup) { IChildWidget ret; if (childIPPW) { ret = childIPPW.getPopupWidget (cx, cy, closePopup); if (closePopup && ret is null) { removeChildIPPW (childIPPW); } } if (ret is null) { if (popup.onSelf (cx, cy)) ret = popup.getWidget (cx, cy); else if (onSelf (cx, cy)) ret = getWidget (cx, cy); } return ret; } override void drawPopup () { popup.draw; if (childIPPW) childIPPW.drawPopup; } debug invariant () { // True as long as removedIPPW gets called: if (!parentIPPW.isChild (this)) { assert (childIPPW is null, "APPW: childIPPW"); assert (mAIPPW is false, "APPW: mAIPPW"); } } protected: // How to activate a popup: /+void activatePopup (IChildWidget widget) { parentIPPW.addChildIPPW (this); popup = widget; mgr.positionPopup (this, popup); }+/ debug override bool isChild (IPopupParentWidget ippw) { return ippw is childIPPW; } IPopupParentWidget parentIPPW; IPopupParentWidget childIPPW; IChildWidget popup; MenuPosition mAIPPW; } import mde.content.Content; /****************************************************************************** * Not "really" a widget (zero size, no direct interaction), but a handler for * popup widgets. * * Intended to manage a context menu for WidgetManager, and not to work quite * like a regular IPPW. *****************************************************************************/ class PopupHandlerWidget : APopupParentWidget { this (IWidgetManager mgr, IParentWidget parent, widgetID id, char[] subWidg, IContent c) { super (mgr, parent, id); popup = mgr.makeWidget (this, subWidg, c); subWidgets = [popup]; w = mw = 0; h = mh = 0; } /// Open a context menu void openMenu (IChildWidget underMouse, Content contextContent) { if (mAIPPW != MenuPosition.INACTIVE) return; // already in use //TODO: //subWidgets[0].setContent (contextContent); parentIPPW.addChildIPPW (this); // For context menus, don't set parentIPPW.menuActive like for clicked menus: menuActive = mgr.positionPopup (underMouse, popup); mgr.requestRedraw; } }