Mercurial > projects > mde
view mde/gui/WMScreen.d @ 146:783969f4665c
Simple, inefficient context menus (displaying content description).
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Wed, 11 Feb 2009 12:00:12 +0000 |
parents | 264028f4115a |
children | c67d074a7111 |
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.widget.Ifaces; import mde.gui.renderer.createRenderer; 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. *****************************************************************************/ scope class WMScreen : AWidgetManager, 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); } /** Draw the gui. */ void draw() { synchronized(mutex) { if (child) child.draw; if (childIPPW) childIPPW.drawPopup; drawPopup; } } /** For mouse click events. * * Sends the event on to the relevant windows and all click callbacks. */ void clickEvent (ushort usx, ushort usy, ubyte b, bool state) { try { mutex.lock; scope(exit) mutex.unlock; if (child is null) return; wdabs cx = cast(wdabs) usx, cy = cast(wdabs) usy; // Callbacks have the highest priority receiving events (e.g. a button release) foreach (dg; clickCallbacks) if (dg (cx, cy, b, state)) return; // Update underMouse to get the widget clicked on updateUnderMouse (cx, cy, state); // Disable keyboard input if on another widget: if (keyFocus && keyFocus !is underMouse) { keyFocus.keyFocusLost; keyFocus = null; input.setLetterCallback (null); } // Finally, post the actual event: if (b == 3 && state) { // right click - open context menu IContent contextContent = underMouse.content; if (contextContent is null) return; // NOTE: Creates new widgets every time; not optimal popupContext = makeWidget (this, "context", contextContent); popupContext.setup (0, 3); positionPopup (underMouse, popupContext, 0); requestRedraw; } else // post other button presses to clickEvent if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { // keyboard input requested keyFocus = underMouse; input.setLetterCallback (&underMouse.keyEvent); } } catch (Exception e) { logger.error ("clickEvent: exception processing event: {}", e.msg); } } /** For mouse motion events. * * Sends the event on to all motion callbacks. */ void motionEvent (ushort scx, ushort scy) { try { mutex.lock; scope(exit) mutex.unlock; wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; foreach (dg; motionCallbacks) dg (cx, cy); updateUnderMouse (cx, cy, false); } catch (Exception e) { logger.error ("motionEvent: exception processing event: {}", e.msg); } } void sizeEvent (int nw, int nh) { // IDrawable function mutex.lock; scope(exit) mutex.unlock; w = cast(wdim) nw; h = cast(wdim) nh; if (w < mw) { logger.warn ("Min width for gui, {}, not met: {}", mw, w); w = mw; } if (h < mh) { logger.warn ("Min height for gui, {}, not met: {}", mh, h); h = mh; } if (!child) return; // if not created yet. child.setWidth (w, -1); child.setHeight (h, -1); child.setPosition (0,0); } protected: /* Second stage of widget loading. * Note: sizeEvent should be called with window size before this. */ final override void createRootWidget () { // The renderer needs to be created on the first load, but not after this. if (rend is null) rend = createRenderer (rendName); debug (mdeWidgets) logger.trace ("Creating root widget..."); child = makeWidget (this, "root"); debug (mdeWidgets) logger.trace ("Setting up root widget..."); child.setup (0, 3); mw = child.minWidth; mh = child.minHeight; if (w < mw) { logger.warn ("Min width for gui, {}, not met: {}", mw, w); w = mw; } if (h < mh) { logger.warn ("Min height for gui, {}, not met: {}", mh, h); h = mh; } debug (mdeWidgets) logger.trace ("Setting size and position of root widget..."); child.setWidth (w, -1); child.setHeight (h, -1); child.setPosition (0,0); debug (mdeWidgets) logger.trace ("Done creating root widget."); } final override void preSave () { if (keyFocus) { keyFocus.keyFocusLost; keyFocus = null; input.setLetterCallback (null); } } Input input; // input singleton }