Mercurial > projects > mde
view mde/gui/widget/Window.d @ 36:57d000574d75
Enabled drawing on demand, and made the polling interval configurable.
Renamed mde.global to mde.imde.
Enabled drawing on demand.
Allowed options to take double values.
Made the main loop's polling interval (sleep duration) settable from config files.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Fri, 02 May 2008 17:38:43 +0100 |
parents | 928db3c75ed3 |
children | 052df9b2fe07 |
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 Window class. Hopefully eventually this will become a widget to make things a bit more * generic. */ module mde.gui.widget.Window; import mde.gui.widget.Ifaces; import mde.gui.widget.createWidget; import mde.gui.IGui; import mde.gui.exception; import mt = mde.mergetag.DataSet; import tango.scrapple.text.convert.parseTo : parseTo; // not yet implemented: //import tango.scrapple.text.convert.parseFrom : parseFrom; import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.widget.Window"); } /** 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 { //BEGIN Methods for GUI this (char[] id) { name = id; } /** Call after loading is finished to setup the window and confirm that it's valid. * * Throws: WindowLoadException. Do not use the instance in this case! */ void finalise (IGui gui) in { assert (gui !is null, "Window.finalise ("~name~"): gui is null"); } body { // Check data was loaded: if (widgetData is null) throw new WindowLoadException ("No widget data"); gui_ = gui; rend = gui.renderer; // Create the primary widget (and indirectly all sub-widgets), throwing on error: widget = makeWidget (0, this);// primary widget always has ID 0. widgetData = null; // data is no longer needed: allow GC to collect (cannot safely delete) widgetX = x + rend.windowBorder; // widget position widgetY = y + rend.windowBorder; // must be updated if the window is moved widget.setPosition (widgetX, widgetY); widget.getCurrentSize (w,h);// Find the initial size w += rend.windowBorder * 2; // Adjust for border h += rend.windowBorder * 2; xw = x+w; yh = y+h; } //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 //END Methods for GUI //BEGIN IWindow methods /** Get/create a widget by ID. * * Should $(I only) be called internally and by sub-widgets! */ IWidget makeWidget (widgetID i, IWidget parent) in { // widgetData is normally left to be garbage collected after widgets have been created: assert (widgetData !is null, "Window.makeWidget ("~name~"): widgetData is null"); } body { /* Each widget returned should be a unique object; if multiple widgets are requested with * the same ID, a new widget is created each time. */ int[]* d = i in widgetData; if (d is null) throw new WindowLoadException ("Window.makeWidget ("~name~"): Widget not found"); // Throws WidgetDataException (a WindowLoadException) if bad data: IWidget widg = createWidget (this, parent, *d); widgets ~= widg; return widg; } IGui gui () { return gui_; } /+void requestRedraw () { }+/ IRenderer renderer () { return rend; } //END IWindow methods //BEGIN IWidget methods void getMinimumSize (out int w, out int h) { widget.getMinimumSize (x,y); w += rend.windowBorder * 2; // Adjust for border h += rend.windowBorder * 2; } void getCurrentSize (out int cw, out int ch) { cw = w; ch = h; } void setPosition (int x, int y) { // Currently only used internally this.x = x; this.y = y; xw = x+w; yh = y+h; widgetX = x + rend.windowBorder; widgetY = y + rend.windowBorder; widget.setPosition (widgetX, widgetY); gui_.requestRedraw (); // obviously necessary whenever the window is moved } IWidget getWidget (int cx, int cy) { if (cx < x || cx >= xw || cy < y || cy >= yh) // not over window return null; if (cx >= widgetX && cx < xw-rend.windowBorder && cy >= widgetY && cy < yh-rend.windowBorder) // over the widget return widget.getWidget (cx, cy); else // over the window border return this; } void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { if (b == 1 && state == true) { xDrag = cx; yDrag = cy; gui_.addClickCallback (&dragEndCallback); // handle repositioning gui_.addMotionCallback (&dragCallback); // handle repositioning } } void draw () { // background rend.drawWindow (x,y, w,h); // Tell the widget to draw itself: widget.draw(); } //END IWidget methods private: /* For window dragging. */ void dragCallback (ushort cx, ushort cy) { setPosition (x+cx-xDrag, y+cy-yDrag); xDrag = cx; yDrag = cy; } void dragEndCallback (ushort cx, ushort cy, ubyte b, bool state) { if (b == 1 && state == false) { setPosition (x+cx-xDrag, y+cy-yDrag); gui_.removeCallbacks (cast(void*) this); } } int xDrag, yDrag; // locations where a drag starts (used by dragCallback). char[] name; // The window's name (id from config file) IGui gui_; // The gui managing this window int[][widgetID] widgetData; // Data for all widgets under this window (deleted after loading) IWidget[] widgets; // List of all widgets under this window (created on demand). Use for saving? IWidget widget; // The primary widget in this window. IRenderer rend; // The window's renderer // FIXME: revise which parameters are stored once Gui knows window position int x,y; // Window position int w,h; // Window size (calculated from Widgets) int xw, yh; // x+w, y+h (frequent use by clickEvent) int widgetX, widgetY; // Widget position (= window position plus BORDER_WIDTH) }