# HG changeset patch # User Diggory Hardy # Date 1232722745 0 # Node ID 264028f4115aa2d5775219defd1c5f7337586ace # Parent 9cff74f68b84b749f55fdf5f459c0dce521310fa Cleaned up mde.imde and a couple of widget functions. New mde.menus module to add default menus. The input singleton is now created in mde.input.Input instead of mde.imde. diff -r 9cff74f68b84 -r 264028f4115a data/L10n/en-GB.mtt --- a/data/L10n/en-GB.mtt Wed Jan 21 13:01:40 2009 +0000 +++ b/data/L10n/en-GB.mtt Fri Jan 23 14:59:05 2009 +0000 @@ -1,8 +1,9 @@ {MT01} !{en-GB British English} {imde} - + + {Options} {FontOptions} diff -r 9cff74f68b84 -r 264028f4115a data/conf/guiDemo.mtt --- a/data/conf/guiDemo.mtt Wed Jan 21 13:01:40 2009 +0000 +++ b/data/conf/guiDemo.mtt Fri Jan 23 14:59:05 2009 +0000 @@ -2,16 +2,18 @@ {Working} - + - + - - - - - + + + +!{Could recurse to menuPopup if it wasn't for recursion protection:} + + + diff -r 9cff74f68b84 -r 264028f4115a examples/guiDemo.d --- a/examples/guiDemo.d Wed Jan 21 13:01:40 2009 +0000 +++ b/examples/guiDemo.d Fri Jan 23 14:59:05 2009 +0000 @@ -17,6 +17,7 @@ module examples.guiDemo; import mde.imde; // this module's interface for external modules +import mde.menus; // add default menus import mde.events; // pollEvents() // NOTE: Must be imported before Init, otherwise fonts don't display properly (why??) import mde.setup.Init; // initialization import mde.lookup.Options; // pollInterval option diff -r 9cff74f68b84 -r 264028f4115a mde/content/Items.d --- a/mde/content/Items.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/content/Items.d Fri Jan 23 14:59:05 2009 +0000 @@ -60,10 +60,8 @@ } } else if (h == "imde") { h = head (item); - if (h == "menu" && item is null) - return imde.menu; - else if (h == "quit" && item is null) - return imde.quit; + if (h == "menus" && item is null) + return imde.menus; } else if (h == "dynamic") { auto i = head (item) in items; if (i) return *i; @@ -117,10 +115,8 @@ // Translate imde: trl = Translation.get ("imde"); - trle = trl.getStruct ("menu"); - imde.menu.name (trle.name, trle.desc); - trle = trl.getStruct ("quit"); - imde.quit.name (trle.name, trle.desc); + trle = trl.getStruct ("menus"); + imde.menus.name (trle.name, trle.desc); // Translate dynamic content: if (items.length) { diff -r 9cff74f68b84 -r 264028f4115a mde/events.d --- a/mde/events.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/events.d Fri Jan 23 14:59:05 2009 +0000 @@ -28,8 +28,10 @@ import tango.util.log.Log : Log, Logger; private Logger logger; +private Input input; static this() { logger = Log.getLogger ("mde.events"); + input = Input.singleton; } void pollEvents (TimeSpan) { @@ -37,7 +39,7 @@ while (SDL_PollEvent (&event)) { switch (event.type) { case SDL_QUIT: - logger.info ("Quit requested"); + debug logger.trace ("Quit (from SDL_QUIT event)"); imde.run = false; break; case SDL_VIDEORESIZE: @@ -50,8 +52,8 @@ break; default: try { - if (!imde.input (event)) - logger.warn ("Unrecognised event with code {}", event.type); + if (!input.send (event)) + logger.info ("Unrecognised event with code {}", event.type); } catch (Exception e) { logger.error ("Caught input exception; event will be ignored. Exception was:"); logger.error (e.msg); diff -r 9cff74f68b84 -r 264028f4115a mde/gui/WMScreen.d --- a/mde/gui/WMScreen.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/gui/WMScreen.d Fri Jan 23 14:59:05 2009 +0000 @@ -26,6 +26,7 @@ import mde.gui.renderer.createRenderer; import mde.setup.Screen; +import mde.input.Input; import tango.util.log.Log : Log, Logger; @@ -61,8 +62,9 @@ Screen.addDrawable (this); // Events we want to know about: - imde.input.addMouseClickCallback(&clickEvent); - imde.input.addMouseMotionCallback(&motionEvent); + input = Input.singleton; + input.addMouseClickCallback(&clickEvent) + .addMouseMotionCallback(&motionEvent); } /** Draw the gui. */ @@ -98,13 +100,13 @@ if (keyFocus && keyFocus !is underMouse) { keyFocus.keyFocusLost; keyFocus = null; - imde.input.setLetterCallback (null); + input.setLetterCallback (null); } // Finally, post the actual event: if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { // keyboard input requested keyFocus = underMouse; - imde.input.setLetterCallback (&underMouse.keyEvent); + input.setLetterCallback (&underMouse.keyEvent); } } @@ -181,7 +183,9 @@ if (keyFocus) { keyFocus.keyFocusLost; keyFocus = null; - imde.input.setLetterCallback (null); + input.setLetterCallback (null); } } + + Input input; // input singleton } diff -r 9cff74f68b84 -r 264028f4115a mde/gui/WidgetManager.d --- a/mde/gui/WidgetManager.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/gui/WidgetManager.d Fri Jan 23 14:59:05 2009 +0000 @@ -34,6 +34,7 @@ import Items = mde.content.Items; // loadTranslation debug import mde.content.miscContent; // Debug menu +import mt = mde.file.mergetag.DataSet; import mde.file.mergetag.Reader; import mde.file.mergetag.Writer; import mde.setup.paths; @@ -80,7 +81,7 @@ debug { auto lWS = new EventContent ("logWidgetSize"); lWS.addCallback (&logWidgetSize); - imde.menu.append (lWS); + imde.menus.append (new ContentList ("debug", [cast(Content)lWS])); } } @@ -492,8 +493,7 @@ // 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, + popupListContent = FUNCTION | TAKES_CONTENT | 0x33, // content widgets: 0x40 DisplayContent = TAKES_CONTENT | 0x40, @@ -524,10 +524,9 @@ "GridLayout", "FloatingArea", "Switch", - "subMenuContent", + "popupListContent", "ContentList", - "editContent", - "flatMenuContent"]; + "editContent"]; /* Generates a binary search algorithm for makeWidget. */ char[] binarySearch (char[] var, char[][] consts) { diff -r 9cff74f68b84 -r 264028f4115a mde/gui/widget/contentFunctions.d --- a/mde/gui/widget/contentFunctions.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/gui/widget/contentFunctions.d Fri Jan 23 14:59:05 2009 +0000 @@ -65,27 +65,13 @@ } /****************************************************************************** - * A function which returns a ContentListWidget or MenuButtonContentWidget. + * PopupMenuContent will create a popup for any content. This function more + * conservatively only creates a popup for a ContentList, and otherwise returns + * the same as editContent. *****************************************************************************/ -IChildWidget flatMenuContent (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { - if (c is null) throw new ContentException; - if (cast(IContentList) c) - return new ContentListWidget(mgr,parent,id,data,c); - if (cast(EventContent) c) - return new ButtonContentWidget(mgr,parent,id,data,c); - // generic uneditable option - return new DisplayContentWidget(mgr,parent,id,data,c); -} - -/****************************************************************************** - * A function which returns a PopupMenuWidget or MenuButtonContentWidget. - *****************************************************************************/ -IChildWidget subMenuContent (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { +IChildWidget popupListContent (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data, IContent c) { if (c is null) throw new ContentException; if (cast(IContentList) c) return new PopupMenuWidget(mgr,parent,id,data,c); - if (cast(EventContent) c) - return new ButtonContentWidget(mgr,parent,id,data,c); - // generic uneditable option - return new DisplayContentWidget(mgr,parent,id,data,c); + else return editContent (mgr, parent, id, data, c); } diff -r 9cff74f68b84 -r 264028f4115a mde/imde.d --- a/mde/imde.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/imde.d Fri Jan 23 14:59:05 2009 +0000 @@ -13,33 +13,22 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** This module is for interfacing with the mde.mde module (or other module containing main()) and - * some global items. */ +/****************************************************************************** + * This module is for interfacing with the mde.mde module (or other module + * containing main()) and contains some global references. + *****************************************************************************/ module mde.imde; -import mde.input.Input; import mde.scheduler.Scheduler; import mde.content.miscContent; static this () { - // Make these available to all importing modules' static CTORs, as well as during init. - input = new Input(); + // Make available to all importing modules: mainSchedule = new Scheduler; - - quit = new EventContent("quit"); - quit.addCallback ((Content){ - run = false; - }); - menu = new ContentList ("menu",[cast(Content) quit, - new EventContent("a"), - new ContentList("subMenu",[ - new EventContent("b"), - new EventContent("c")]) - ]); + menus = new ContentList ("menu"); } -ContentList menu; /// Root menu for imde -EventContent quit; /// A content triggering mde to halt +ContentList menus; /// Root of all menus; import mde.menus to add entries Scheduler mainSchedule; /// The schedule used by the main loop. @@ -49,5 +38,3 @@ }; bool run = true; // main loop continues if this is true - -Input input; // Input instance. When multiple users are allowed instances will be per-user. diff -r 9cff74f68b84 -r 264028f4115a mde/input/Input.d --- a/mde/input/Input.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/input/Input.d Fri Jan 23 14:59:05 2009 +0000 @@ -143,15 +143,17 @@ /** Adds a callback delegate for key events (both DOWN and UP) with this ID. * * Delegate receives event status. */ - void addButtonCallback (inputID id, ButtonCallback dg) { + Input addButtonCallback (inputID id, ButtonCallback dg) { buttonCallbacks[id] ~= dg; + return this; } /** Adds a callback delegate for axis events with this ID. * * Delegate receives event status (as per what getAxis returns). */ - void addAxisCallback (inputID id, AxisCallback dg) { + Input addAxisCallback (inputID id, AxisCallback dg) { axisCallbacks[id] ~= dg; + return this; } /** Adds a callback delegate for mouse motion/joystick ball events with this ID. @@ -162,8 +164,9 @@ * (A separate callback for mouse screen position changes is not * necessary since this will be triggered by the same event - use mouseScreenPos from within the * function to get new screen coordinates.) */ - void addRelMotionCallback (inputID id, RelMotionCallback dg) { + Input addRelMotionCallback (inputID id, RelMotionCallback dg) { relMotionCallbacks[id] ~= dg; + return this; } /** Adds a callback delegate for all mouse clicks & releases. @@ -175,16 +178,18 @@ * The point of this over a standard button callback is firstly to avoid mouse configuration for * the GUI, and secondly to give the pointer position at the time of the event, not the time the * callback gets called. */ - void addMouseClickCallback (MouseClickCallback dg) { + Input addMouseClickCallback (MouseClickCallback dg) { mouseClickCallbacks ~= dg; + return this; } /** Adds a callback delegate for all mouse motion events. * * Really just for graphical user interfaces. Use addRelMotionCallback for relative motion (for * manipulating 3D views, etc.). */ - void addMouseMotionCallback (MouseMotionCallback dg) { + Input addMouseMotionCallback (MouseMotionCallback dg) { mouseMotionCallbacks ~= dg; + return this; } /** Sets a callback delegate to recieve key presses as a Utf-8 char[]. @@ -206,21 +211,22 @@ } /** Feed an SDL_Event struct (only uses if it's a key, mouse or joystick event). - * - * Other types of event functions may be added. Returns true if the event was used, false if not - * or no config was available. Hmm... doesn't seem very useful, but has practically no cost. - * (Due to lack of use of this feature, false is returned even for used events when no config is - * available). - * - * May throw InputClassExceptions (on configuration errors). Catching the exception and continuing should - * be fine. */ - bool opCall (ref SDL_Event event) { + * + * Other types of event functions may be added. Returns true if the event + * was used, false if not or no config was available. Hmm... doesn't seem + * very useful, but has practically no cost. + * + * May throw InputClassExceptions (on configuration errors). Catching the + * exception and continuing should be fine. */ + bool send (ref SDL_Event event) { /* Non-config events. * - * Handle these first so that if no config exists some functionality at least is retained. + * Handle these first so that if no config exists some functionality at + * least is retained. * * Coordinates don't need adjusting (they put the top-left most pixel at 0,0). - */ + * + * If no config, exit from this switch. */ switch (event.type) { case SDL_KEYDOWN: if (letterCallback) { @@ -252,12 +258,9 @@ break; default: + if (!config) return false; // event not used } - - /* No config available, so don't try to access it and segfault. - * Don't log a message because this function is called per-event (i.e. frequently). - * A message should already have been logged by loadConfig anyway. */ - if (!config) return false; + if (!config) return true; // event used switch (event.type) { // Keyboard events: @@ -388,11 +391,19 @@ Config* c_p = profile in Config.configs; if (c_p) config = *c_p; else { + logger.error ("Config profile \""~profile~"\" not found: input won't work unless a valid profile is loaded!"); throw new ConfigLoadException; - logger.error ("Config profile \""~profile~"\" not found: input won't work unless a valid profile is loaded!"); } } + /** For now, use as a singleton. (Could be changed later to allow multiple + * "players". */ + static Input singleton () { + if (instance is null) + instance = new Input(); + return instance; + } + private: // Static constructor for event stream (fills es_*_fcts tables). static this () { @@ -414,6 +425,7 @@ static const CB_EXC = "Callback exception: "; + static Input instance; static Logger logger; Config config; // Configuration diff -r 9cff74f68b84 -r 264028f4115a mde/menus.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mde/menus.d Fri Jan 23 14:59:05 2009 +0000 @@ -0,0 +1,40 @@ +/* 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 . */ + +/****************************************************************************** + * Import this module to add some standard menus to imde.menus. + * + * Note that the widget manager also adds menu items in debug mode. + *****************************************************************************/ +module mde.menus; + +import mde.content.miscContent; +import mde.imde; +debug { + import tango.util.log.Log : Log, Logger; + private Logger logger; + static this () { + logger = Log.getLogger ("mde.menus"); + } +} + +static this () { + auto quit = new EventContent("quit"); + quit.addCallback ((Content){ + debug logger.trace ("Quit (from menu)"); + run = false; + }); + menus.append (new ContentList ("main", [cast(Content)quit])); +} diff -r 9cff74f68b84 -r 264028f4115a mde/setup/Init.d --- a/mde/setup/Init.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/setup/Init.d Fri Jan 23 14:59:05 2009 +0000 @@ -329,19 +329,21 @@ try { static if (startup) { debug logger.trace ("({}) InitStage {}: starting init", threadNum, stage.name); - stage.state = (*stage).init(); // init is a property of a pointer (oh no!) + stage.state = (*stage).init(); // init is a property too :-( } else { debug logger.trace ("({}) InitStage {}: starting cleanup", threadNum, stage.name); stage.state = stage.cleanup(); } debug logger.trace ("({}) InitStage {}: completed; state: {}", threadNum, stage.name, stage.state); } catch (InitStageException e) { - debug logger.trace ("({}) InitStage {}: failed: "~e.msg, threadNum, stage.name); + debug logger.error ("({}) InitStage {}: failed: "~e.msg, threadNum, stage.name); + else logger.error ("InitStage {}: failed: "~e.msg, stage.name); stage.state = e.state; doneInit = STATE.ABORT; break threadLoop; } catch (Exception e) { - debug logger.trace ("({}) InitStage {}: failed: "~e.msg, threadNum, stage.name); + debug logger.error ("({}) InitStage {}: failed: "~e.msg, threadNum, stage.name); + else logger.error ("InitStage {}: failed: "~e.msg, stage.name); doneInit = STATE.ABORT; break threadLoop; } diff -r 9cff74f68b84 -r 264028f4115a mde/setup/InitStage.d --- a/mde/setup/InitStage.d Wed Jan 21 13:01:40 2009 +0000 +++ b/mde/setup/InitStage.d Fri Jan 23 14:59:05 2009 +0000 @@ -13,9 +13,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/************************************************************************************************** +/****************************************************************************** * The infrastructure for handling external startup/shutdown code. - *************************************************************************************************/ + *****************************************************************************/ module mde.setup.InitStage; public import mde.setup.exception; @@ -81,9 +81,9 @@ -/************************************************************************************************** +/****************************************************************************** * Initialization functions. - *************************************************************************************************/ + *****************************************************************************/ import imde = mde.imde; import mde.input.Input; import mde.setup.Screen; @@ -99,12 +99,12 @@ } StageState initInput () { - imde.input.loadConfig ("input"); + Input.singleton.loadConfig ("input"); - // Quit on escape. NOTE: quit via SDL_QUIT event is handled completely independently! - imde.input.addButtonCallback (cast(Input.inputID) 0x0u, delegate void(Input.inputID i, bool b) { + // Quit on escape. + Input.singleton.addButtonCallback (cast(Input.inputID) 0x0u, delegate void(Input.inputID i, bool b) { if (b) { - logger.info ("Quiting..."); + debug logger.trace ("Quit (from Esc)"); imde.run = false; } } );