view mde/gui/WMScreen.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 b06b04c75e86
children a1ba9157510e
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 gui manager class using mde.setup.Screen and mde.input.Input.
 *
 * This is the module to use externally to create a graphical user interface
 * (likely also with content modules).
 *****************************************************************************/
module mde.gui.WMScreen;

import mde.gui.WidgetManager;
import mde.gui.WidgetLoader;
import mde.gui.widget.Ifaces;

import mde.setup.Screen;
import mde.input.Input;

import tango.util.log.Log : Log, Logger;

private Logger logger;
static this () {
    logger = Log.getLogger ("mde.gui.WMScreen");
}

/******************************************************************************
 * The widget manager.
 * 
 * This provides a layer on top of WidgetLoader, handling input and rendering.
 * Other functionality is contained in the super class, to simplify supporting
 * new input/graphics libraries.
 * 
 * Currently mouse coordinates are passed to widgets untranslated. It may make
 * sense to translate them and possibly drop events for some uses, such as if
 * the gui is drawn to a texture.
 * 
 * Public non IWidget* methods should be thread-safe, even to the same
 * instance (by locking on a mutex).
 *****************************************************************************/
scope class WMScreen : AWidgetLoader, Screen.IDrawable {
    /** Construct a new widget manager.
     * 
     * Must be run after static this.
     * 
     * params:
     *  fileName = Name of file specifying the gui, excluding path and extension.
     */
    this (char[] file) {
        // Doesn't need a lock - cannot conflict with other class functions.
        super(file);
        
        Screen.addDrawable (this);
        // Events we want to know about:
        input = Input.singleton;
        input.addMouseClickCallback(&clickEvent)
             .addMouseMotionCallback(&motionEvent);
    }
    ~this () {
	// Make sure the keyboard is not locked in text-entry mode.
	input.setLetterCallback (null);
    }
    
    /** Draw the gui. */
    void draw() {
        synchronized(mutex) {
	    debug (mdeDrawEvents)
		logger.trace ("drawing");
            wmDrawWidgets();
	}
    }
    
    /** For mouse click events. */
    void clickEvent (ushort usx, ushort usy, ubyte b, bool state) {
        try {
	    mutex.lock;
	    scope(exit) mutex.unlock;
	    wmMouseClick (cast(wdabs) usx, cast(wdabs) usy, b, state);
        } catch (Exception e) {
            logger.error ("clickEvent: exception processing event: {}", e.msg);
        }
    }
    
    /** For mouse motion events. */
    void motionEvent (ushort scx, ushort scy) {
        try {
            mutex.lock;
            scope(exit) mutex.unlock;
            wmMouseMotion (cast(wdabs) scx, cast(wdabs) scy);
        } catch (Exception e) {
            logger.error ("motionEvent: exception processing event: {}", e.msg);
        }
    }
    
    /** Notification of externally-caused screen resize.
     *
     * Should be called before createWidgets to prevent widgets being squashed
     * to min-dims on loading (losing saved dimensions of columns, etc). */
    void sizeEvent (int nw, int nh) {   // IDrawable function
        mutex.lock;
        scope(exit) mutex.unlock;
        
        w = cast(wdim) nw;
        h = cast(wdim) nh;
        matchMinimalSize;
        
        if (!childRoot) return;     // if not created yet.
        childRoot.setWidth  (w, -1);
        childRoot.setHeight (h, -1);
        childRoot.setPosition (0,0);
    }
    
protected:
    final override void setLetterCallback(void delegate(ushort, char[]) dlg) {
	input.setLetterCallback (dlg);
    }
    
    final override void preSave () {
	if (keyFocus) {
	    keyFocus.keyFocusLost;
	    keyFocus = null;
            input.setLetterCallback (null);
	}
    }
    
    Input input;	// input singleton
}