Mercurial > projects > mde
view mde/gui/WidgetManager.d @ 76:65780e0e48e6
Re-enabled click event passing in the gui to make ButtonWidget work.
Bugfix (pass void* not class reference).
Change to allow compilation with dmd 1.027 (don't use DefaultData's Arg!() template).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Mon, 28 Jul 2008 18:49:18 +0100 |
parents | 25cb7420dc91 |
children | ea58f277f487 |
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/>. */ /************************************************************************************************* * The gui manager class. * * This is the module to use externally to create a graphical user interface (likely also with * content modules). *************************************************************************************************/ module mde.gui.WidgetManager; public import mde.gui.WidgetData; import mde.gui.widget.Ifaces; import mde.gui.renderer.createRenderer; // For adding the input event callbacks and requesting redraws: import imde = mde.imde; import mde.input.Input; import mde.scheduler.Scheduler; import tango.core.sync.Mutex; import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.WidgetManager"); gui = new WidgetManager ("gui"); } WidgetManager gui; /************************************************************************************************* * The widget manager. * * This is responsible for loading and saving an entire gui (although more than one may exist), * controlling the rendering device (e.g. the screen or a texture), and providing user input. * * 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. * * Aside from the IWidgetManager methods, this class should be thread-safe. *************************************************************************************************/ class WidgetManager : WidgetLoader { /** Construct a new widget manager. * * params: * fileName = Name of file specifying the gui, excluding path and extension. */ this (char[] file) { super(file); // Events we want to know about: imde.input.addMouseClickCallback(&clickEvent); imde.input.addMouseMotionCallback(&motionEvent); } /** Draw the gui. */ void draw() { synchronized(mutex) child.draw; } /** For mouse click events. * * Sends the event on to the relevant windows and all click callbacks. */ void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { debug scope (failure) logger.warn ("clickEvent: failed!"); mutex.lock; scope(exit) mutex.unlock; // NOTE: buttons receive the up-event even when drag-callbacks are in place. foreach (dg; clickCallbacks) // See IWidgetManager.addClickCallback's documentation: if (dg (cast(wdabs)cx, cast(wdabs)cy, b, state)) return; // NOTE: do we need to test if the click was on the gui (and thus child)? IChildWidget widg = child.getWidget (cast(wdabs)cx,cast(wdabs)cy); if (widg !is null) widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state); /+ FIXME: remove foreach (i,w; windows) { IWidget widg = w.getWidget (cast(wdabs)cx,cast(wdabs)cy); if (widg !is null) { // Bring to front windows = w ~ windows[0..i] ~ windows[i+1..$]; widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state); requestRedraw; // in case we've only moved to front return; // only pass to first window } }+/ } /** For mouse motion events. * * Sends the event on to all motion callbacks. */ void motionEvent (ushort cx, ushort cy) { debug scope (failure) logger.warn ("motionEvent: failed!"); mutex.lock; scope(exit) mutex.unlock; foreach (dg; motionCallbacks) dg (cast(wdabs)cx, cast(wdabs)cy); } void setSize (int x, int y) { mutex.lock; scope(exit) mutex.unlock; w = cast(wdim) x; h = cast(wdim) y; if (child is null) return; // May not have been created before this is first run. child.setWidth (w, -1); child.setHeight (h, -1); child.setPosition (0,0); } //BEGIN IWidgetManager methods // These methods are only intended for use within the gui package. They are not necessarily // thread-safe. IRenderer renderer () { assert (rend !is null, "WidgetManager.renderer: rend is null"); return rend; } void requestRedraw () { imde.mainSchedule.request(imde.SCHEDULE.DRAW); } void addClickCallback (bool delegate(wdabs, wdabs, ubyte, bool) dg) { clickCallbacks[dg.ptr] = dg; } void addMotionCallback (void delegate(wdabs, wdabs) dg) { motionCallbacks[dg.ptr] = dg; } void removeCallbacks (void* frame) { clickCallbacks.remove(frame); motionCallbacks.remove(frame); } //END IWidgetManager methods protected: /* Second stage of widget loading. */ void createRootWidget () { // The renderer needs to be created on the first load, but not after this. if (rend is null) rend = createRenderer (rendName); child = makeWidget ("root"); child.setWidth (w, -1); child.setHeight (h, -1); child.setPosition (0,0); } private: // callbacks indexed by their frame pointers: bool delegate(wdabs cx, wdabs cy, ubyte b, bool state) [void*] clickCallbacks; void delegate(wdabs cx, wdabs cy) [void*] motionCallbacks; IRenderer rend; wdim w,h; // area available to the widgets }