Mercurial > projects > mde
view mde/gui/widget/Window.d @ 34:6b4116e6355c
Work on the Gui: some of the framework for drag & drop. Also made Window an IWidget.
Implemented getWidget(x,y) to find the widget under this location for IWidgets (but not Gui).
Made Window an IWidget and made it work a little more similarly to widgets.
Implemented callbacks on the Gui for mouse events (enabling drag & drop, etc.).
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Fri, 02 May 2008 16:03:52 +0100 |
parents | 316b0230a849 |
children | 928db3c75ed3 |
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 { // See if it's already been created: IWidget* p = i in widgets; if (p !is null) { // yes char[128] tmp; logger.warn (logger.format (tmp, "Window.makeWidget ("~name~"): widget {} has multiple uses!", i)); return *p; } else { // no 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[i] = 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) { /+ Note: this is currently unused. Maybe only use it internally? this.x = x; this.y = y; widgetX = x + rend.windowBorder; widgetY = y + rend.windowBorder; widget.setPosition (widgetX, widgetY); +/ } 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 (cx >= x && cx < xw && cy >= y && cy < yh) { // click on window? // FIXME: repositioning? } void draw () { // background rend.drawWindow (x,y, w,h); // Tell the widget to draw itself: widget.draw(); } //END IWidget methods private: 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[widgetID] widgets; // List of all widgets under this window (created on demand). 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) }