Mercurial > projects > mde
view mde/gui/widget/createWidget.d @ 119:d28aea50c6da
Basic edit cursor placement using the mouse.
Moved textContent.d's contents into TextWidget.d.
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Thu, 01 Jan 2009 14:52:09 +0000 |
parents | aba2dd815a1f |
children |
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; import mde.content.Content; import Items = mde.content.Items; // 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 mde.gui.widget.PopupMenu; 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); } /************************************************************************************************* * A function which uses Items.get (data.strings[0]) to get a content and creates a widget from * data.ints[1]. The first item in each ints and strings is removed before passing data to the new * widget. * * The function only takes an IContent parameter to satisfy createWidget; it's value is ignored. * * Circularly depends on createWidget, so should be in this module. *************************************************************************************************/ IChildWidget addContent (IWidgetManager mgr, widgetID id, WidgetData data, IContent) { if (data.ints.length < 2 || data.strings.length < 1) throw new WidgetDataException; char[] cItem = data.strings[0]; data.strings = data.strings[1..$]; data.ints = data.ints [1..$]; return createWidget (mgr, id, data, Items.get (cItem)); } 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. SAFE_RECURSION = 0x8000, // Safe to instantiate recursively without infinite looping. // 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, // popup widgets: 0x10 PopupMenu = TAKES_CONTENT | 0x11, SubMenu = TAKES_CONTENT | 0x12, // labels: 0x20 ContentLabel = TAKES_CONTENT | 0x20, TextLabel = 0x21, // content functions: 0x30 editContent = FUNCTION | TAKES_CONTENT | SAFE_RECURSION | 0x30, addContent = FUNCTION | 0x31, flatMenuContent = FUNCTION | TAKES_CONTENT | SAFE_RECURSION | 0x32, subMenuContent = FUNCTION | TAKES_CONTENT | 0x33, // content widgets: 0x40 DisplayContent = TAKES_CONTENT | 0x40, BoolContent = TAKES_CONTENT | 0x41, AStringContent = TAKES_CONTENT | 0x42, ButtonContent = TAKES_CONTENT | 0x43, MenuButtonContent = TAKES_CONTENT | 0x44, GridLayout = TAKES_CONTENT | 0x100, ContentList = TAKES_CONTENT | SAFE_RECURSION | 0x110, FloatingArea = 0x200, } //const char[][int] WIDGET_NAMES; // Only used for binarySearch algorithm generation; must be ordered by numerical values. const char[][] WIDGETS = [ "FixedBlank", "SizableBlank", "Debug", "TextLabel", "FloatingArea", "addContent", "PopupMenu", "SubMenu", "ContentLabel", "DisplayContent", "BoolContent", "AStringContent", "ButtonContent", "MenuButtonContent", "GridLayout", "subMenuContent", "ContentList", "editContent", "flatMenuContent"]; /* 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"~ /+if ((WIDGET_TYPE."~c~" & WIDGET_TYPE.SAFE_RECURSION) || "not being recursed (no parent with same id)") {\n For recursion detection; would probably work with above check and some modification to widgets. +/ "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 throw new GuiException (\"Widget not safe to be recursed: "~c~"\");+/ "} 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!\");"); }