Mercurial > projects > mde
view mde/gui/widget/createWidget.d @ 95:2a364c7d82c9
Boolean options can be adjusted from the gui now (using a very basic widget). Also some bug-fixes.
Fixed a minor bug where layouts with the same id but without shared alignments would be messed up.
Tracked down the "nothing trawn until a resize" bug (see jobs.txt).
If widgets throw during creation they're now replaced by debug widgets.
Function pointers are converted to delegates using a safer method.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 06 Nov 2008 11:07:18 +0000 |
parents | 4d5d53e4f881 |
children | 49e7cfed4b34 |
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/>. */ /** This module contains code to create a widget based on an enumeration value passed at runtime. * * It could be a part of the WidgetLoader.makeWidget function, but having it here makes things * tidier. */ module mde.gui.widget.createWidget; import mde.gui.widget.Ifaces; import mde.gui.exception : WidgetDataException; import mde.gui.content.Content; //NOTE - maybe move IContent to a separate module // Widgets to create: import mde.gui.widget.layout; import mde.gui.widget.miscWidgets; import mde.gui.widget.TextWidget; import mde.gui.widget.miscContent; import mde.gui.widget.Floating; import tango.util.log.Log : Log, Logger; private Logger logger; static this () { logger = Log.getLogger ("mde.gui.widget.createWidget"); } /** Create a widget. * * Usually called by the widget manager's makeWidget function. * * Widget created of type data.ints[0] (see enum WIDGET_TYPES), with one of the following CTORs: * --- * this (IWidgetManager mgr, WidgetData data); * // Called if (data.ints[0] & WIDGET_TYPES.TAKES_CONTENT): * this (IWidgetManager mgr, WidgetData data, IContent content); * --- *************************************************************************************************/ IChildWidget createWidget (IWidgetManager mgr, widgetID id, WidgetData data, IContent content) in { assert (mgr !is null, "createWidget: mgr is null"); } body { if (data.ints.length < 1) { logger.error ("No int data; creating a debug widget"); data.ints = [WIDGET_TYPE.Debug]; } int type = data.ints[0]; // type is first element of data try { //pragma (msg, binarySearch ("type", WIDGETS)); mixin (binarySearch ("type", WIDGETS)); // creates widget by type: new XWidget (mgr, data [, parent]); // Not returned a new widget or thrown: logger.error ("Bad widget type: {}; creating a debug widget instead",type); } catch (Exception e) { logger.error ("Error creating widget: {}; creating a debug widget instead.", e.msg); } return new DebugWidget (mgr, id, data); } /+ for converting to a char[] name (unused) static this() { WIDGET_NAMES = [ FixedBlank : "FixedBlank", SizableBlank : "SizableBlank", Button : "Button", GridLayout : "GridLayout" ]; }+/ private: /// Widget types. enum WIDGET_TYPE : int { FUNCTION = 0x2000, // Function called instead of widget created (no "Widget" appended to fct name) TAKES_CONTENT = 0x4000, // Flag indicates widget's this should be passed an IContent reference. PARENT = 0x8000, // widget can have children; not used by code (except in data files) // Use widget names rather than usual capitals convention Unnamed = 0x0, // Only for use by widgets not created with createWidget // blank: 0x1 FixedBlank = 0x1, SizableBlank = 0x2, Debug = 0xF, // buttons: 0x10 Button = 0x10, // labels: 0x20 ContentLabel = TAKES_CONTENT | 0x20, TextLabel = 0x21, // content editables: 0x30 editContent = FUNCTION | TAKES_CONTENT | 0x30, BoolContent = TAKES_CONTENT | 0x31, GridLayout = TAKES_CONTENT | PARENT | 0x100, TrialContentLayout = PARENT | 0x110, FloatingArea = PARENT | 0x200, } //const char[][int] WIDGET_NAMES; // Only used for binarySearch algorithm generation; must be ordered by numerical values. const char[][] WIDGETS = [ "FixedBlank", "SizableBlank", "Debug", "Button", "TextLabel", "ContentLabel", "BoolContent", "editContent", "TrialContentLayout", "FloatingArea", "GridLayout"]; /* Generates a binary search algorithm. */ char[] binarySearch (char[] var, char[][] consts) { if (consts.length > 3) { return "if (" ~ var ~ " <= WIDGET_TYPE." ~ consts[$/2 - 1] ~ ") {\n" ~ binarySearch (var, consts[0 .. $/2]) ~ "} else {\n" ~ binarySearch (var, consts[$/2 .. $]) ~ "}\n"; } else { char[] ret; foreach (c; consts) { ret ~= "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~ " debug (mdeWidgets) logger.trace (\"Creating new "~c~"Widget.\");\n" ~ " static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.FUNCTION)\n" ~ " return " ~ c ~ " (mgr, id, data, content);\n" ~ " else static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.TAKES_CONTENT)\n" ~ " return new " ~ c ~ "Widget (mgr, id, data, content);\n" ~ " else\n" ~ " return new " ~ c ~ "Widget (mgr, id, data);\n" ~ "} else "; } ret = ret[0..$-6] ~ '\n'; // remove last else return ret; } } debug { // check items in WIDGETS are listed in order char[] WIDGETS_check () { char[] ret; for (int i = WIDGETS.length-2; i > 0; --i) { ret ~= "WIDGET_TYPE."~WIDGETS[i] ~" >= WIDGET_TYPE."~ WIDGETS[i+1]; if (i>1) ret ~= " || "; } return ret; } mixin ("static if ("~WIDGETS_check~") static assert (false, \"WIDGETS is not in order!\");"); }