diff mde/input/Config.d @ 32:316b0230a849

Lots more work on the GUI. Also renamed lots of files. Lots of changes to the GUI. Renderer is now used exclusively for rendering and WidgetDecoration is gone. Renamed lots of files to conform to case policies. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 30 Apr 2008 18:05:56 +0100
parents
children 66d555da083e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/input/Config.d	Wed Apr 30 18:05:56 2008 +0100
@@ -0,0 +1,200 @@
+/* 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 a class for holding configs and handles saving, loading and editing.
+module mde.input.Config;
+
+debug import tango.scrapple.text.convert.parseFrom : parseFrom;
+
+import mde.input.exception;
+
+import MT = mde.mergetag.Reader;
+import mde.resource.paths;
+import tango.scrapple.text.convert.parseTo : parseTo;
+
+import tango.util.log.Log : Log, Logger;
+import tango.util.collection.TreeBag : TreeBag;
+
+/** Class to hold the configuration for the input system. Thus loading and switching between
+ *  multiple configurations should be easy.
+ *
+ * Class extends DataSection so that it can be loaded by mergetag easily.
+ */
+class Config : MT.IDataSection
+{
+    alias uint[] outQueue;		// This is the type for the out queue config data.
+    /** Button event type bit-codes
+     *
+     *  These bitcodes are OR'd to the identifier code for the input device, to indicate which type
+     *  of input they are for. E.g. when a key event is recieved with code x, look up
+     *  $(_B _B.SDLKEY) | x in button. Keyboard events are SDL-specific since the codes may differ
+     *  for other libraries.
+     *
+     *  For joystick hat events, a motion is converted into up and down events on separate U,L,D,R
+     *  positions and up and down events sent to the appropriate outputs (effectively making four
+     *  buttons, some pairs of which can be pressed simultaneously). For output to axes, see
+     *  A.JOYHAT_* .
+     */
+    enum B : uint {
+        KEY		= 0x8000_0000u,		/// 0x8000_0000
+        SDLKEY		= 0x8800_0000u,		/// 0x8800_0000
+        MOUSE		= 0x4000_0000u,		/// 0x4000_0000
+        JOYBUTTON	= 0x2000_0000u,		/// 0x2000_0000
+        JOYHAT		= 0x1000_0000u,		/// 0x1000_0000
+        JOYHAT_U	= 0x1800_0000u,		/// 0x1800_0000
+        JOYHAT_D	= 0x1400_0000u,		/// 0x1400_0000
+        JOYHAT_L	= 0x1200_0000u,		/// 0x1200_0000
+        JOYHAT_R	= 0x1100_0000u,		/// 0x1100_0000
+    }
+    
+    /** Axis event type bit-codes
+     *
+     *  SDL only supports one type of axis now, but this could be extended in the future.
+     *
+     *  This can also be used to make joystick hats output to two axes (and can be used in
+     *  conjuction with B.JOYHAT_* to output as buttons as well).
+    */
+    enum A : uint {
+        JOYAXIS		= 0x8000_0000u,		/// 0x8000_0000
+        JOYHAT		= 0x1000_0000u,		/// 0x1000_0000
+        JOYHAT_LR	= 0x1300_0000u,		/// 0x1300_0000
+        JOYHAT_UD	= 0x1C00_0000u,		/// 0x1C00_0000
+    }
+    
+    /** Mouse & Joystick ball event type bit-codes
+     *
+     *  Currently, mouse input only comes from the window manager: the code is exactly M.WMMOUSE.
+     */
+    enum M : uint {
+        MOUSE		= 0x8000_0000u,		/// 0x8000_0000
+        WMMOUSE		= 0x8800_0000u,		/// 0x8800_0000
+        JOYBALL		= 0x4000_0000u,		/// 0x4000_0000
+    }
+    
+    /** Output queues: the core of the input configuration.
+    *
+    *  These are all mapped with a uint key; upon any event outQueues are looked for in the
+    *  appropriate associative array with a key as follows.
+    *
+    *  The index is split into two parts;
+    *  the first byte specifies the type of input (given by the above enums), and the last three
+    *  bytes define where the input comes from.
+    *
+    *  For type B.SDLKEY, the last three bytes are for the SDL keysym.
+    *  For B.MOUSE, B.JOY*, A.JOY* & M.JOY*, the last three bytes are split into two sets of 12
+    *  bits (with masks 0x00FF_F000 and 0x0000_0FFF), the higher of which specifies the device
+    *  (which mouse or joystick), and the lower of which specifies the button/axis/ball.
+    *
+    *  For all three types of output, the outQueues are used as follows. The first value in the queue is
+    *  read, and a function is called with the event details dependant on this; most of the time an
+    *  output function is called directly. Other functions may be used, however, to allow further
+    *  functionality such as modifier keys, timed keys, and key sequences.
+    *
+    *  The output functions all have code 0x100; these read a single item from the outQueue which
+    *  is the inputID the event outputs to (i.e. any callbacks at that ID called and status set for
+    *  that ID).
+    *
+    */
+    outQueue[][uint] button;
+    outQueue[][uint] axis;	/// ditto
+    outQueue[][uint] relMotion;	/// ditto
+    
+    // FIXME:
+    char[] name;		/// Name for user to save this under.
+    uint[] inheritants;		/// Other profiles to inherit.
+    
+    static Config[char[]] configs;	/// All configs loaded by load().
+    private static TreeBag!(char[]) loadedFiles;	// all filenames load tried to read
+    
+    private static Logger logger;
+    static this() {
+        logger = Log.getLogger ("mde.input.config.Config");
+    }
+    
+//BEGIN File loading/saving code
+    static this () {
+        loadedFiles = new TreeBag!(char[]);
+    }
+    
+    // Load all configs from a file.
+    static void load (char[] filename) {
+        if (loadedFiles.contains (filename)) return;	// forget it; already done that
+        loadedFiles.add (filename);
+        
+        MT.IReader file;
+        
+        try {
+            // open and read header:
+            file = confDir.makeMTReader (filename, PRIORITY.LOW_HIGH, null, true);
+            
+            file.dataSecCreator =
+            delegate MT.IDataSection (MT.ID) {	return new Config;	};
+            
+            // D2.0: enum MT.ID CONFIGS = "Configs";
+            const MT.ID CONFIGS = cast(MT.ID)"Configs";
+            // Restrict config sections if this tag exists:
+            auto file_configs_p = CONFIGS in file.dataset.header._charAA;
+            MT.ID[] file_configs = null;
+            if (file_configs_p) {
+                file_configs = cast(MT.ID[]) *file_configs_p;
+            }
+            
+            if (file_configs)	file.read(file_configs);	// restrict to this set IF a restriction was given
+            else		file.read();			// otherwise read all
+        }
+        catch (MT.MTException) {
+            logger.fatal ("Unable to load configs from: " ~ filename);
+            throw new ConfigLoadException;
+        }
+        
+        // Trying to directly cast dataset.sec to configs resulted in the Configs losing their data.
+        // Also this is safer since it checks types (and must be done if configs wasn't previously empty).
+        foreach (i, sec; file.dataset.sec) {
+            Config c = cast(Config) sec;
+            if (c) configs[i] = c;		// Check, because we don't want null entries in configs
+            else debug logger.error ("Ended up with DataSection of wrong type; this should never happen.");
+        }
+        
+        debug (MDE_CONFIG_DUMP) {
+            char tmp[128] = void;
+            logger.trace (logger.format (tmp, "Loaded {} config sections.", configs.length));
+            foreach (id, cfg; configs) {
+                logger.trace ("Section " ~ id ~
+                ":\n\tbutton:\t\t" ~ parseFrom!(uint[][][uint])(cfg.button) ~
+                "\n\taxis:\t\t" ~ parseFrom!(uint[][][uint])(cfg.axis) ~
+                "\n\trelMotion:\t" ~ parseFrom!(uint[][][uint])(cfg.relMotion) );
+            }
+        }
+    }
+    
+    // D2.0: private enum QUEUE : MT.ID { BUTTON = "B", AXIS = "A", MOUSE = "M" }
+    private struct QUEUE {
+        static const MT.ID BUTTON = cast(MT.ID)"B", AXIS = cast(MT.ID)"A", MOUSE = cast(MT.ID)"M";
+    }
+    private this() {}	// Private since this class should only be created from here.
+    
+    void addTag (char[] tp, MT.ID id, char[] dt) {
+        if (tp == "uint[][uint]") {
+            if (id == QUEUE.BUTTON) button = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt);
+            else if (id == QUEUE.AXIS) axis = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt);
+            else if (id == QUEUE.MOUSE) relMotion = cast(outQueue[][uint]) parseTo!(uint[][][uint]) (dt);
+            else logger.warn ("Unexpected tag encountered with ID " ~ cast(char[])id);
+        } // FIXME: add support for name and inheritants.
+    }
+    void writeAll (ItemDelg) {
+        // FIXME
+    }
+//END File loading/saving code
+}