view mde/gui/widget/AParentWidget.d @ 131:9cff74f68b84

Major revisions to popup handling. Buttons can close menus now, plus some smaller impovements. Removed Widget module. Moved Widget.AWidget to AChildWidget.AChildWidget and Widget.AParentWidget to AParentWidget.AParentWidget. Removed ASingleParentWidget to improve code sharing. AChildWidget doesn't implement IParentWidget like AWidget did. New IPopupParentWidget extending IParentWidget for the WM and some widgets to handle popups. Cut old popup management code. New underMouse() function replacing highlight(); called on all widgets. Separate menu-popup and button widgets aren't needed for menus now. Functions returning content widgets have been moved to their own module. Cleaned up jobs.txt. Switched to 80 line length for Ddoc.
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 21 Jan 2009 13:01:40 +0000
parents
children 9fd705793568
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;

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)");
    }
    
    // Don't override; use the WIDGET_TYPE.SAFE_RECURSION flag for safe widgets.
    //NOTE: should be override (compiler bug)
    final void recursionCheck (widgetID a) {
        debug assert (id !is null && parent !is null, "recursionCheck called before parent and id set");
        if (a is id)
            throw new GuiException ("Infite recursion of "~a);
        parent.recursionCheck (a);
    }
    
    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 = false;
        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 = false;
    }
    
    override void menuActive (bool mA) {
        mAIPPW = mA;
        if (childIPPW)
            childIPPW.menuActive = mA;
    }
    override bool menuActive () {
        return mAIPPW;
    }
    
    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) {
                menuActive = false;
                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;
    bool mAIPPW;
}