view mde/gui/gui.d @ 28:b5fadd8d930b

Small addition to GUI, paths work-around for Windows. New GUI widget containing a widget. Paths on windows now uses "." and "./user" as a temporary measure. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 08 Apr 2008 15:52:21 +0100
parents 0aa621b3e070
children f985c28c0ec9
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/>. */

/// Base GUI module.
module mde.gui.gui;

import mde.gui.IWindow;
import mde.gui.Widget;
import mde.gui.exception;

import mt = mde.mergetag.DataSet;
import mt = mde.mergetag.exception;
import mde.mergetag.Reader;

import mde.resource.paths;
import mde.scheduler.InitFunctions;

import tango.scrapple.text.convert.parseTo : parseTo;
import tango.scrapple.text.convert.parseFrom : parseFrom;

private Logger logger;
static this () {
    logger = Log.getLogger ("mde.gui.gui");
    
    init.addFunc (&GUI.load);
}

struct GUI {
static:
    private const fileName = "gui";
    void load() {
        if (!confDir.exists (fileName)) {
            logger.error ("Unable to load GUI: no config file!");
            return; // not a fatal error (so long as the game can run without a GUI!)
        }
        
        IReader reader;
        try {
            reader = confDir.makeMTReader (fileName, PRIORITY.HIGH_ONLY);
            reader.dataSecCreator = delegate mt.IDataSection(mt.ID) {
                return new Window;
            };
            reader.read;
        } catch (mt.MTException e) {
            logger.error ("Loading GUI aborted:");
            logger.error (e.msg);
            
            return;
        }
        
        // get list
        windows.length = reader.dataset.sec.length; // pre-allocate
        windows.length = 0;
        foreach (sec; reader.dataset.sec) {
            Window w = cast(Window) sec;
            if (w !is null) {                       // extra safety
                windows ~= w;
                try {
                    w.finalise();
                    
                    gl.addDrawCallback (&w.draw);
                } catch (WindowLoadException e) {
                    logger.error ("Window failed to load: " ~ e.msg);
                }
            }
        }
    }
    
private:
    Window[] windows;
}

package:    // Nothing else here is for external use.

/** GUI Window class
*
* A window class instance does two things: (1) specify a region of the screen upon which the window
* and its associated widgets are drawn, and (2) load, save, and generally manage all its widgets.
*
* Let the window load a table of widget data, of type int[][widgetID]. Each widget will, when
* created, be given its int[] of data, which this() must confirm is valid (or throw).
*/
class Window : mt.IDataSection, IWindow
{
    alias int widgetID;     // Widget ID type. Each ID is unique under this window. Type is int since this is the widget data type.
    private int[][widgetID] widgetData;     // Data for all widgets under this window.
    private Widget[widgetID] widgets;       // List of all widgets under this window (created on demand).
    
    Widget widget;                  // The primary widget in this window.
    int x,y;                        // Window position
    int w,h;                        // Window size (calculated from Widgets)
    
    const BORDER_WIDTH = 8;         // Temporary way to handle window decorations
    
    
    // Call after loading is finished to setup the window and confirm that it's valid.
    void finalise () {
        // Create the widget, throwing on error:
        widget = getWidget (0);     // primary widget always has ID 0.
        widget.getSize (w,h);       // Find the initial size
        w += BORDER_WIDTH * 2;      // Adjust for border
        h += BORDER_WIDTH * 2;
    }
    
    Widget getWidget (widgetID i) {
        // See if it's already been created:
        Widget* p = i in widgets;
        if (p !is null) return *p;  // yes
        else {                      // no
            int[]* d = i in widgetData;
            if (d is null) throw new WindowLoadException ("Widget not found");
            
            // Throws WidgetDataException (a WindowLoadException) if bad data:
            Widget w = createWidget (this, *d);
            widgets[i] = w;
            return w;
        }
    }
    
    void draw () {
        //BEGIN Window border/back
        gl.setColor (0.0f, 0.0f, 0.5f);
        gl.drawBox (x,x+w, y,y+h);
        //END Window border/back
        
        // Tell the widget to draw itself:
        widget.draw(x + BORDER_WIDTH, y + BORDER_WIDTH);
    }
    
    //BEGIN Mergetag code
    void addTag (char[] tp, mt.ID id, char[] dt) {
        if (tp == "int[][int]") {
            if (id == "widgetData") {
                widgetData = cast(int[][widgetID]) parseTo!(int[][int]) (dt);
            }
        } else if (tp == "int") {
            if (id == "x") {
                x = parseTo!(int) (dt);
            } else if (id == "y") {
                y = parseTo!(int) (dt);
            }
        }
    }
    void writeAll (ItemDelg dlg) {
    }
    //END Mergetag code
}