view mde/gui/widget/miscContent.d @ 126:c9843fbaac88

Dynamic minimal size changing improved; works over layouts sharing alignment. EnumContent sub-contents use EnumValueContent instead of BoolContent; fixes a few small bugs. EnumContent substrings get translated (bug fixed). The widget manager no longer attempts to set widget sizes smaller than their minimals, even though some will not be shown. SwitchWidget: has fixed sizableness now.
author Diggory Hardy <diggory.hardy@gmail.com>
date Thu, 08 Jan 2009 13:05:44 +0000
parents 3e648bc53bde
children 41582439a42b
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/>. */

/*************************************************************************************************
 * A function to return content widgets and some miscellaneous content display/editing widgets.
 *************************************************************************************************/
module mde.gui.widget.miscContent;

import mde.gui.widget.Widget;
import mde.gui.exception;
import mde.gui.widget.TextWidget;
import mde.gui.widget.layout;
import mde.gui.widget.PopupMenu;

import mde.gui.renderer.IRenderer;
import mde.content.AStringContent;
import mde.content.miscContent;
import Items = mde.content.Items;

debug {
    import tango.util.log.Log : Log, Logger;
    private Logger logger;
    static this () {
	logger = Log.getLogger ("mde.gui.widget.miscContent");
    }
}

/*************************************************************************************************
 * A function which uses Items.get (data.strings[0]) to get a content and creates a widget from
 * data.ints[1]. The first item in each ints and strings is removed before passing data to the new
 * widget.
 * 
 * The function only takes an IContent parameter to satisfy createWidget; it's value is ignored.
 ************************************************************************************************/
IChildWidget addContent (IWidgetManager mgr, IParentWidget parent, widgetID, WidgetData data, IContent) {
    if (data.strings.length != 2) throw new WidgetDataException;
    return mgr.makeWidget (parent, data.strings[1], Items.get (data.strings[0]));
}

/*************************************************************************************************
 * A function which returns the most appropriate content editing widget.
 *
 * Widgets which can be returned: BoolContentWidget (toggle button), ValueContentWidget (generic
 * text-box editor), DisplayContentWidget (generic text label).
 *************************************************************************************************/
IChildWidget editContent (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) {
    // Note: SAFE_RECURSION enabled
    if (c is null) throw new ContentException;
    if (cast(AStringContent) c) {
        if (cast(EnumContent) c)	// can be PopupMenuWidget or ContentListWidget
            return new ContentListWidget(mgr,parent,id,data,c);
        if (cast(BoolContent) c)
            return new BoolContentWidget(mgr,parent,id,data,c);
        return new AStringContentWidget(mgr,parent,id,data,c);
    }
    if (cast(IContentList) c)
        return new ContentListWidget(mgr,parent,id,data,c);
    if (cast(EventContent) c)
        return new ButtonContentWidget(mgr,parent,id,data,c);
    // generic uneditable option
    return new DisplayContentWidget(mgr,parent,id,data,c);
}

/// Editable boolean widget
class BoolContentWidget : AButtonWidget
{
    this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) {
	content = cast(BoolContent) c;
        if (content is null) throw new ContentException (this);
        super (mgr, parent, id);
        wdimPair s = mgr.renderer.getToggleSize;
        w = mw = s.x;
        h = mh = s.y;
    }
    
    override void draw () {
        mgr.renderer.drawToggle (x,y, content(), pushed);
    }
    
    override void activated () {
        content = !content();
    }
    
protected:
    BoolContent content;
}

/// A button connected to an EventContent
class ButtonContentWidget : AButtonWidget
{
    this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData, IContent c) {
	content = cast(EventContent) c;
        if (content is null) throw new ContentException (this);
        adapter = mgr.renderer.getAdapter ();
        super (mgr, parent, id);
    }
    
    override bool setup (uint n, uint flags) {
	if (!(flags & 3)) return false;	// string or renderer (and possibly font) changed
	adapter.text = content.toString(1);
	adapter.getDimensions (mw, mh);
	if (mw != w || mh != h) {
	    w = mw;
	    h = mh;
	}
	return true;
    }
    
    override void draw () {
	super.draw();
	adapter.draw (x,y);
    }
    
    override void activated () {
	content.endEvent;
    }
    
protected:
    IRenderer.TextAdapter adapter;
    EventContent content;
    int index;
}

/** A "tab" widget: it doesn't display the tabs, but shows one of a number of widgets dependant on
 * an EnumContent. */
class SwitchWidget : AParentWidget
{
    this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) {
        super (mgr, parent, id);
        content = cast(EnumContent) c;
        if (content is null || (subWidgets.length = content.list.length) == 0)
            throw new ContentException (this);
        WDCheck (data, 1, subWidgets.length);
        
        foreach (i,sc; content.list) {
            subWidgets[i] = mgr.makeWidget (this, data.strings[i], sc);
            isWS |= subWidgets[i].isWSizable;
            isHS |= subWidgets[i].isHSizable;
        }
        currentW = subWidgets[content()];
        
        content.addCallback (&switchWidget);
    }
    
    override bool setup (uint n, uint flags) {
        bool r = super.setup (n, flags);
        if (r) {
            mw = currentW.minWidth;
            mh = currentW.minHeight;
            w = currentW.width;
            h = currentW.height;
        }
        return r;
    }
    
    override void minWChange (IChildWidget widget, wdim nmw) {
        if (widget !is currentW) return;
        mw = nmw;
        parent.minWChange (this, nmw);
    }
    override void minHChange (IChildWidget widget, wdim nmh) {
        if (widget !is currentW) return;
        mh = nmh;
        parent.minHChange (this, nmh);
    }
    
    override bool isWSizable () {
        return isWS;
    }
    override bool isHSizable () {
        return isHS;
    }
    
    override void setWidth (wdim nw, int dir) {
	w = (nw >= mw ? nw : mw);
        currentW.setWidth (w, dir);
    }
    override void setHeight (wdim nh, int dir) {
        h = (nh >= mh ? nh : mh);
        currentW.setHeight (h, dir);
    }
    
    override void setPosition (wdim nx, wdim ny) {
        x = nx;
        y = ny;
        currentW.setPosition (nx,ny);
    }
    
    override void draw () {
        currentW.draw;
    }
    
protected:
    // callback on content
    void switchWidget (Content) {
        currentW = subWidgets[content()];
        mw = currentW.minWidth;
        mh = currentW.minHeight;
        parent.minWChange (this, mw);
        parent.minHChange (this, mh);
        w = currentW.width;
        h = currentW.height;
        currentW.setPosition (x,y);
    }
    
    IChildWidget currentW;
    EnumContent content;
    
    bool isWS, isHS;	// no infrastructure for changing sizability, so need to fix it.
}