diff mde/content/AStringContent.d @ 137:9f035cd139c6

BIG commit. Major change: old Options class is gone, all content values are loaded and saved automatically. All options updated to reflect this, some changed. Content restrutured a lot: New IContent module, Content module includes more functionality. New ContentLoader module to manage content loading/saving/translation. Translation module moved to content dir and cut down to reflect current usage. File format unchanged except renames: FontOptions -> Font, VideoOptions -> Screen. Font render mode and LCD filter options are now enums. GUI loading needs to create content (and set type for enums), but doesn't save/load value. Some setup of mainSchedule moved to mde.mainLoop. Content callbacks are called on content change now. ContentLists are set up implicitly from content symbols. Not as fast but much easier! Bug-fix in the new MTTagReader. Renamed MT *Reader maker functions to avoid confusion in paths.d. New mde.setup.logger module to allow logger setup before any other module's static this().
author Diggory Hardy <diggory.hardy@gmail.com>
date Sat, 07 Feb 2009 12:46:03 +0000
parents 41582439a42b
children 2476790223b8
line wrap: on
line diff
--- a/mde/content/AStringContent.d	Sun Feb 01 12:36:21 2009 +0000
+++ b/mde/content/AStringContent.d	Sat Feb 07 12:46:03 2009 +0000
@@ -29,32 +29,14 @@
     logger = Log.getLogger ("mde.content.AStringContent");
 }
 
-// Used by Options
-template ContentN(T) {
-    static if (is(T == bool)) {
-	const char[] ContentN = "BoolContent";
-    } else static if (is(T == int)) {
-	const char[] ContentN = "IntContent";
-    } else static if (is(T == double)) {
-	const char[] ContentN = "DoubleContent";
-    } else static if (is(T == char[])) {
-	const char[] ContentN = "StringContent";
-    } else
-	static assert (false, "No Content of type "~T.stringof);
-}
-
-/** Base class for content containing a simple value editable as text. All content types used by
- * Options extend this class.
+/** Base class for content containing a simple value editable as text.
  *
- * All derived classes should have the following functions:
- * ---
- *  char[] endEdit ();	// Should convert sv and assign to self, then call endEvent
- * // Used by Options:
- *  BoolContent changeCb (void delegate (char[] symbol,T value) cb);	// The callback used by Options
- *  void assignNoCb (T val);	// assign val, but without calling callbacks
- * ---
- * On any assignation (by this, assignNoCb, opAssign) the value should be converted to a string and
- * assigned to sv, and pos should be clamped to [0,sv.length] (i.e. enforce pos <= sv.length). */
+ * Derived classes should implement endEdit to convert sv and assign its value
+ * to self, then call endEvent.
+ *
+ * On assignation by this or opAssign the value should be converted to a string
+ * and assigned to sv, and pos should be clamped to [0,sv.length] (i.e. enforce
+ * pos <= sv.length). */
 abstract class AStringContent : Content
 {
     protected this (char[] symbol) {
@@ -150,23 +132,24 @@
 class BoolContent : AStringContent
 {
     /** Create a content with _symbol name symbol. */
-    this (char[] symbol, bool val = false) {
-	assignNoCb (val);
+    this (char[] symbol) {
+        auto valp = symbol in changed.boolData;
+        if (valp)
+            v = *valp;
+        sv = v ? "true" : "false";
 	super (symbol);
     }
-    // for use by EnumValueContent
-    protected this (char[] symbol, int dummy) {
-        super (symbol);
-    }
     
-    void assignNoCb (bool val) {
+    // Assign without adding change to save changeset
+    void assignNoCng (bool val) {
 	v = val;
 	sv = v ? "true" : "false";
 	if (pos > sv.length) pos = sv.length;
+        endEvent;
     }
     void opAssign (bool val) {
-	assignNoCb (val);
-	endEvent;
+	assignNoCng (val);
+        endCng;
     }
     bool opCall () {
         return v;
@@ -177,9 +160,15 @@
 	v = sv && (sv[0] == 't' || sv[0] == 'T' || sv[0] == '1');
         sv = v ? "true" : "false";
         endEvent;
+        endCng;
 	return sv;
     }
     
+    // Add change to changeset
+    void endCng () {
+        changed.boolData[symbol] = v;
+    }
+    
 protected:
     bool v;
 }
@@ -187,18 +176,21 @@
 /** Text content. */
 class StringContent : AStringContent
 {
-    this (char[] symbol, char[] val = null) {
-        v = val;
-	super (symbol);
+    this (char[] symbol) {
+        auto valp = symbol in changed.charAData;
+        if (valp)
+            v = *valp;
+        super (symbol);
     }
     
-    void assignNoCb (char[] val) {
+    void assignNoCng (char[] val) {
 	v = val;
 	if (pos > sv.length) pos = sv.length;
+        endEvent;
     }
     void opAssign (char[] val) {
-	assignNoCb (val);
-	endEvent;
+	assignNoCng (val);
+        endCng;
     }
     char[] opCall () {
         return v;
@@ -207,9 +199,14 @@
     
     override char[] endEdit () {
 	endEvent;
+        endCng;
 	return sv;
     }
     
+    void endCng () {
+        changed.charAData[symbol] = v;
+    }
+    
 protected:
     alias sv v;		// don't need separate v and sv in this case
 }
@@ -218,19 +215,23 @@
 class IntContent : AStringContent
 {
     /** Create a content with _symbol name symbol. */
-    this (char[] symbol, int val = 0) {
-        assignNoCb (val);
+    this (char[] symbol) {
+        auto valp = symbol in changed.intData;
+        if (valp)
+            v = *valp;
+        sv = Int.toString (v);
 	super (symbol);
     }
     
-    void assignNoCb (int val) {
+    void assignNoCng (int val) {
 	v = val;
 	sv = Int.toString (v);
 	if (pos > sv.length) pos = sv.length;
+        endEvent;
     }
     void opAssign (int val) {
-	assignNoCb (val);
-	endEvent;
+	assignNoCng (val);
+	endCng;
     }
     int opCall () {
         return v;
@@ -245,30 +246,39 @@
         }
         sv = Int.toString (v);
         endEvent;
+        endCng;
 	return sv;
     }
     
+    void endCng () {
+        changed.intData[symbol] = v;
+    }
+    
 protected:
-    int v = 0;	// must be a valid value for EnumContent (i.e. 0)
+    int v;
 }
 
 /** Double content. */
 class DoubleContent : AStringContent
 {
     /** Create a content with _symbol name symbol. */
-    this (char[] symbol, double val = 0) {
-        assignNoCb (val);
+    this (char[] symbol) {
+        auto valp = symbol in changed.doubleData;
+        if (valp)
+            v = *valp;
+        sv = Float.toString (v, 8, 4);
 	super (symbol);
     }
     
-    void assignNoCb (double val) {
+    void assignNoCng (double val) {
 	v = val;
 	sv = Float.toString (v, 8, 4);
 	if (pos > sv.length) pos = sv.length;
+        endEvent;
     }
     void opAssign (double val) {
-	assignNoCb (val);
-	endEvent;
+	assignNoCng (val);
+        endCng;
     }
     double opCall () {
         return v;
@@ -283,17 +293,20 @@
         }
         sv = Float.toString (v, 8, 4);
         endEvent;
+        endCng;
 	return sv;
     }
     
+    void endCng () {
+        changed.doubleData[symbol] = v;
+    }
+    
 protected:
     double v;
 }
 
-/** A content representing an enumeration.
- *
- * Extends IntContent for Options support. */
-class EnumContent : IntContent, IContentList
+/** A content representing an enumeration. */
+class EnumContent : AStringContent, IContentList
 {
     /** CTOR.
     *
@@ -301,32 +314,43 @@
     *	enumSymbols = Symbol names for each
     *	val = which value is active; must be in [0,length-1]
     */
-    this (char[] symbol, char[][] enumSymbols, int val = 0) {
+    this (char[] symbol, char[][] enumSymbols) {
+        super (symbol);
         this.enumSymbols = enumSymbols;
         enums.length = enumSymbols.length;
         char[] symPeriod = symbol~'.';
         foreach (i, ref e; enums) {
             e = new EnumValueContent (this, i, symPeriod~enumSymbols[i]);
         }
-        super (symbol, val);	// calls assignNoCb
-    }
-    
-    /** Create from a EnumCStruct. */
-    this (char[] symbol, EnumCStruct data) {
-        this (symbol, data.symbols, data.value);
+        enums[v].assignFromParent (true);
+        sv = enums[v].name_;
+        // Re-set the value if a saved value is found:
+        auto valp = symbol in changed.enumValData;
+        if (valp)
+            assignNoCng = *valp;
     }
     
-    /** Return an EnumCStruct, which could be used to recreate this Content. */
-    //NOTE: save EnumCStruct directly?
-    EnumCStruct structOf () {
-        EnumCStruct r;
-        r.symbols = enumSymbols;
-        r.value = v;
-        return r;
+    void opAssign (size_t val) {
+        assignNoCng (val);
+        endCng;
     }
-    
-    override void assignNoCb (int val) {	// called by children (via opAssign)
-        if (val >= enums.length || val < 0) {
+    // Assign by enum symbol name (for ContentLoader)
+    void assignNoCng (char[] enumSym) {
+        foreach (i,e; enumSymbols) {
+            if (e == enumSym) {
+                assignNoCng (i);
+                return;
+            }
+        }
+        logger.warn ("EnumContent {} assigned invalid enumeration: {}; valid: {}", symbol, enumSym, enumSymbols);
+    }
+    size_t opCall () {
+        //debug logger.trace ("EnumContent {} returning value: {} ({})",symbol, enumSymbols[v], v);
+        return v;
+    }
+    alias opCall opCast;
+    void assignNoCng (size_t val) {
+        if (val >= enums.length) {
 	    logger.error ("EnumContent "~name_~" assigned invalid value; keeping value: "~sv);
 	    return;
 	}
@@ -337,19 +361,11 @@
         if (pos > sv.length) pos = sv.length;
         endEvent;
     }
-    // Change if true, assert current value if false
-    void childAssign (int val) {
-        debug assert (0 <= val && val < enums.length, "cA out of bounds");
-        if (enums[val].v)
-            assignNoCb (val);
-        else
-            enums[val].assignFromParent (v == val);
-    }
     
     override char[] endEdit () {
 	foreach (i,e; enums)
 	    if (sv == e.name_) {
-		v = i;
+		assignNoCng (i);
 		goto break1;
 	    }
 	
@@ -358,40 +374,56 @@
 	if (pos > sv.length) pos = sv.length;
 	
 	break1:
-	endEvent;
+	endCng;
 	return sv;
     }
     
+    void endCng () {
+        changed.enumValData[symbol] = enumSymbols[v];
+    }
+
     override Content[] list () {
         return enums;
     }
     
-    struct EnumCStruct {
-        char[][] symbols;
-        int value;
+    // Interface functions that don't make sense for an emuneration:
+    override void append (Content) {}
+    
+protected:
+    // Called by child; change this if true, assert current value if false
+    void childAssign (size_t val) {
+        debug assert (val < enums.length, "cA out of bounds");
+        if (enums[val].v)
+            this = val;
+        else
+            enums[val].assignFromParent (v == val);
     }
     
-protected:
+    size_t v;			// value (i.e. enums[v] is value)
     EnumValueContent[] enums;
     char[][] enumSymbols;	// saved for getStructOf
     
-    /** Special version of BoolContent for each enumeration to update the parent Enum. */
+    /** Special version of BoolContent for each enumeration to update the
+     * parent Enum.
+     * 
+     * Also should not save its value, since the parent stores the value. */
     private class EnumValueContent : BoolContent {
         /** New enumeration of parent with index num. */
         this (EnumContent parent, size_t num, char[] symbol) {
             this.parent = parent;
             i = num;
-            super (symbol, 0);	// parent sets value (if true); we shouldn't
-            sv = "false";	// except for this
+            super (symbol);
         }
         
-        override void assignNoCb (bool val) {
+        override void assignNoCng (bool val) {
             v = val;
             parent.childAssign (i);
         }
+        override void opAssign (bool val) {
+            assignNoCng (val);
+        }
         void assignFromParent (bool val) {	// don't call back to parent
-            super.assignNoCb (val);
-            endEvent;
+            super.assignNoCng (val);
         }
         
         override char[] endEdit () {