Changeset 104:ee209602770d

Show
Ignore:
Timestamp:
11/26/08 08:07:46 (1 month ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
Message:

Cleaned up Options.d removing old storage method. It's now possible to get a ContentList? of the whole of Options.

Tweaked translation strings (added name and desc to Options classes).
Replaced Options.addSubClass (class, "name") with Options.this("name").

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • data/L10n/FontOptions.mtt

    r95 r104  
    11{MT01} 
    22{en-GB} 
     3<entry|FontOptions={0:"Font options"}> 
    34<entry|lcdFilter={0:"LCD filtering",1:"Enable or disable sub-pixel rendering. Note that the FreeType library may be compiled without support due to patent issues."}> 
    45<entry|renderMode={0:"Font rendering mode",1:"Controls how fonts are rendered: in gray-scale, or for LCDs (with a horizontal (usual) or vertical layout, with an RGB (usual) or BGR sub-pixel mode."}> 
  • data/L10n/MiscOptions.mtt

    r98 r104  
    11{MT01} 
    22{en-GB} 
     3<entry|MiscOptions={0:"Miscellaneous options"}> 
    34<entry|maxThreads={0:"Max threads",1:"Maximum number of threads to use in mde (currently only applies to init stages run in parallel)."}> 
    45<entry|logLevel={0:"Logging level",1:"Lowest level to log messages; 0=trace, 1=info (default), 2=warn, 3=error, 4=fatal, 5=none."}> 
  • data/L10n/VideoOptions.mtt

    r95 r104  
    11{MT01} 
    22{en-GB} 
     3<entry|VideoOptions={0:"Video options"}> 
    34<entry|fullscreen={0:"Fullscreen",1:"If true use the whole screen, if false use a window."}> 
    45<entry|hardware={0:"Hardware",1:"Create the video surface in hardware or software memory."}> 
  • data/conf/gui.mtt

    r103 r104  
    66<WidgetData|square={0:[0x10,10,10]}> 
    77<WidgetData|blank={0:[0x2]}> 
    8 <WidgetData|opts={0:[0x2031,0x6030,0],1:["Options.VideoOptions","optDBox"]}> 
     8<WidgetData|opts={0:[0x2031,0x6030,0],1:["Options","optCls"]}> 
     9<WidgetData|optCls={0:[0xC100,0,2,1],1:["optName","optVars"]}> 
     10<WidgetData|optVars={0:[0x6030,0],1:["optDBox"]}> 
    911<WidgetData|optDBox={0:[0xC100,1,2,1],1:["optBox","optDesc"]}> 
    1012<WidgetData|optBox={0:[0xC100,1,1,3],1:["optName","optSep","optVal"]}> 
  • examples/guiDemo.d

    r98 r104  
    6868    //END Main loop setup 
    6969     
     70    double pollInterval = miscOpts.pollInterval(); 
    7071    while (run) { 
    71         mainSchedule.execute (Clock.now()); 
    72          
    73         Thread.sleep (miscOpts.pollInterval());   // sleep this many seconds 
     72   mainSchedule.execute (Clock.now()); 
     73     
     74   Thread.sleep (pollInterval);   // sleep this many seconds 
    7475    } 
    7576     
  • mde/font/FontTexture.d

    r100 r104  
    465465     
    466466    static this() { 
    467         fontOpts = new FontOptions; 
    468         Options.addOptionsClass (fontOpts, "FontOptions"); 
     467        fontOpts = new FontOptions ("FontOptions"); 
    469468    } 
    470469} 
  • mde/gui/content/Content.d

    r103 r104  
    6666class ContentList : IContent 
    6767{ 
    68     this (IContent[] list = null) { 
     68    this (IContent[] list = null, char[] n = null, char[] d = null) { 
    6969    list_ = list; 
    70     } 
    71     this (ValueContent[char[]] l) { 
     70    name_ = n; 
     71    desc_ = d; 
     72    } 
     73    this (ValueContent[char[]] l, char[] n = null, char[] d = null) { 
    7274    list_.length = l.length; 
    7375    size_t i; 
    7476    foreach (c; l) 
    7577        list_[i++] = c; 
     78    name_ = n; 
     79    desc_ = d; 
    7680    } 
    7781     
    7882    char[] toString (uint i) { 
    7983    return i == 0 ? Int.toString (list_.length) ~ " elements" 
    80     : i == 1 ? "ContentList" 
    81     : null; 
     84             : i == 1 ? name_ 
     85             : i == 2 ? desc_ 
     86             : null; 
    8287    } 
    8388     
     
    9297protected: 
    9398    IContent[] list_; 
     99    char[] name_, desc_;    // name and description 
    94100} 
    95101 
     
    136142    /// Get the text. 
    137143    char[] toString (uint i) { 
    138         return (i == 0) ? sv 
    139              : (i == 1) ? name_ 
    140              : (i == 2) ? desc_ 
     144        return i == 0 ? sv 
     145             : i == 1 ? name_ 
     146             : i == 2 ? desc_ 
    141147             : null; 
    142148    } 
     
    202208    size_t pos;     // editing position; used by keyStroke 
    203209    char[] symb; 
    204     char[] name_, desc_;// name and description, loaded by lookup.Translation 
     210    char[] name_, desc_;// name and description 
    205211} 
    206212 
  • mde/gui/content/Items.d

    r103 r104  
    2525import mde.lookup.Translation; 
    2626 
     27debug { 
     28    import tango.util.log.Log : Log, Logger; 
     29    private Logger logger; 
     30    static this () { 
     31    logger = Log.getLogger ("mde.gui.content.Items"); 
     32    } 
     33} 
     34 
    2735    /** Get a specific content item. 
    2836     * 
     
    3846    /** Same as calling get("Options."~item). */ 
    3947    IContent getOptions (char[] item) { 
     48    if (item is null) { 
     49        IContent[] list; 
     50        list.length = Options.optionsClasses.length; 
     51        size_t i; 
     52        foreach (n,opts; Options.optionsClasses) { 
     53        if (opts.name is null) loadTransl (opts, n); 
     54        list[i++] = new ContentList (opts.content, opts.name, opts.desc); 
     55        } 
     56         
     57        return new ContentList (list, "Options"); 
     58    } 
    4059    char[] h = head (item); 
    4160    auto p = h in Options.optionsClasses; 
    4261    if (p) { 
    43         if (!p.transLoaded) { 
    44         Translation trans = Translation.load ("L10n/"~h); 
    45         foreach (s, v; p.content) { 
    46             Translation.Entry transled = trans.getStruct (s); 
    47             v.name (transled.name, transled.desc); 
    48         } 
    49         p.transLoaded = true; 
    50         } 
     62        if (p.name is null) loadTransl (*p, h); 
    5163         
    5264        if (item == null) 
    53         return new ContentList (p.content); 
     65        return new ContentList (p.content, p.name, p.desc); 
    5466         
    5567        auto q = (h = head (item)) in p.content; 
     
    7486    return ret; 
    7587    } 
     88     
     89    void loadTransl (Options p, char[] n) { 
     90    debug logger.trace ("Loading translation strings for Options."~n); 
     91    Translation trans = Translation.load ("L10n/"~n); 
     92    Translation.Entry transled = trans.getStruct (n); 
     93    p.name = transled.name; 
     94    p.desc = transled.desc; 
     95    foreach (s, v; p.content) { 
     96        transled = trans.getStruct (s); 
     97        v.name (transled.name, transled.desc); 
     98    } 
     99    } 
  • mde/lookup/Options.d

    r103 r104  
    1414along with this program.  If not, see <http://www.gnu.org/licenses/>. */ 
    1515 
    16 //FIXME: Ddoc is outdated 
    17 /** This module handles stored options, currently all except input maps. 
    18  * 
    19  * The purpose of having all options centrally controlled is to allow generic handling by the GUI 
    20  * and ease saving and loading of values. The Options class is only really designed around handling 
    21  * small numbers of variables for now. 
    22  * 
    23  * Note: This module uses some non-spec functionality, which "works for me", but may need to be 
    24  * changed if it throws up problems. Specifically: templated virtual functions (Options.set, get 
    25  * and list), and accessing private templates from an unrelated class (Options.TName, TYPES). 
    26  * OptionChanges used to have a templated set member function (used by Options.set), which caused 
    27  * linker problems when the module wasn't compiled from scratch. 
    28  */ 
     16/** This module handles loading and saving of, and allows generic access to named option variables 
     17 * of a simple type (see Options.TYPES). */ 
    2918module mde.lookup.Options; 
    3019 
     
    4635} 
    4736 
    48 //FIXME: Ddoc is outdated 
    49 /** Base class for handling options. 
    50 
    51 * This class itself handles no options and should not be instantiated, but provides a sub-classable 
    52 * base for generic options handling. Also, the static portion of this class tracks sub-class 
    53 * instances and provides loading and saving methods. 
    54 
    55 * Each sub-class provides named variables for maximal-speed reading. Local sub-class references 
    56 * should be used for reading variables, and via the addOptionsClass() hook will be loaded from 
    57 * files during pre-init (init0 stage). Do not write changes directly to the subclasses or they will 
    58 * not be saved; instead use set(), for example, miscOpts.set!(char[])("L10n","en-GB"). Use an 
    59 * example like MiscOptions as a template for creating a new Options sub-class. 
    60 
    61 * Optionally, overload the validate() function. This is called after loading, allowing conditions 
    62 * to be enforced on variables. Use set!()() to change the variables. If an exception is thrown, 
    63 * init will abort and the executable won't start. 
    64 
    65 * Details: Options sub-classes hold associative arrays of pointers to all option variables, with a 
    66 * char[] id. This list is used for saving, loading and to provide generic GUI options screens. The 
    67 * built-in support in Options is only for bool, int and char[] types (a float type may get added). 
    68 * Further to this, a generic class is used to store all options which have been changed, and if any 
    69 * have been changed, is merged with options from the user conf dir and saved on exit. 
    70 */ 
    71 /* An idea for potentially extending Options, but which doesn't seem necessary now: 
    72 Move static code from Options to an OptionSet class, which may be sub-classed. These sub-classes 
    73 may be hooked in to the master OptionSet class to shadow all Options classes and be notified of 
    74 changes, and may or may not have values loaded from files during init. Change-sets could be 
    75 rewritten to use this. 
    76 However, only the changesets should need to be notified of each change (gui interfaces could simply 
    77 be notified that a change occured and redraw everything; users of options can just re-take their 
    78 values every time they use them). */ 
     37/************************************************************************************************* 
     38 * This class and the OptionChanges class contain all the functionality. 
     39 *  
     40 * Options are stored in derived class instances, tracked by the static portion of Options. Each 
     41 * value is stored in a ValueContent class, whose value can be accessed with opCall, opCast and 
     42 * opAssign. These class objects can be given callbacks called whenever their value is changed. 
     43 *  
     44 * Public static methods allow getting the list of tracked sub-class instances, and loading and saving 
     45 * option values. A public non-static method allows generic access to option variables. 
     46 *  
     47 * Generic access to Options is of most use to a gui, allowing Options to be edited generically. 
     48 *  
     49 * The easiest way to use Options is to use an existing sub-class as a template, e.g. MiscOptions. 
     50 *************************************************************************************************/ 
    7951class Options : IDataSection 
    8052{ 
    81     protected this() {}   /// Do not instantiate directly. 
    82      
    83     // All supported types, for generic handling via templates. It should be possible to change 
    84     // the supported types simply by changing this list now (untested). 
    85     template store(A...) { alias A store; } 
    86     // NOTE: currently all types have transitioned to the new method, but the old method remains 
    87     alias store!(bool, int, double, char[]) TYPES;    // all types 
    88     alias store!(bool, int, double, char[]) CTYPES;   // types stored with a content 
     53    /** Do not instantiate directly; use a sub-class. 
     54     * 
     55     * CTOR adds any created instance to the list of classes tracked statically for loading/saving 
     56     * and generic access. 
     57     *  
     58     * Normally instances are created by a static CTOR. */ 
     59    protected this(char[] name) 
     60    in { 
     61    assert (((cast(ID) name) in subClasses) is null);  // Don't allow a silent replacement 
     62    } body { 
     63    subClasses[cast(ID) name] = this; 
     64    } 
     65     
    8966    //BEGIN Templates: internal 
    90     private { 
    91         // Get name of a type. Basically just stringof, but special handling for arrays. 
     67    package { 
     68    // All supported types, for generic handling via templates. It should be possible to change 
     69    // the supported types simply by changing this list. 
     70    template store(A...) { alias A store; } 
     71    alias store!(bool, int, double, char[]) TYPES;   // types handled 
     72     
     73    // Get name of a type. Basically just stringof, but special handling for arrays. 
    9274        // Use TName!(T) for a valid symbol name, and T.stringof for a type. 
    9375        template TName(T : T[]) { 
     
    9779            const char[] TName = T.stringof; 
    9880        } 
    99          
    100         // Pointer lists 
    101         template PLists(A...) { 
    102             static if (A.length) { 
    103                 static if (TIsIn!(A[0], CTYPES)) { 
    104                     const char[] PLists = PLists!(A[1..$]); 
    105                 } else 
    106                     const char[] PLists = A[0].stringof~"*[ID] opts"~TName!(A[0])~";\n" ~ PLists!(A[1..$]); 
    107             } else 
    108                 const char[] PLists = ""; 
    109         } 
    110          
     81    } 
     82    private { 
    11183        // True if type is one of A 
    11284        template TIsIn(T, A...) { 
     
    12294        // For addTag 
    12395        template addTagMixin(T, A...) { 
    124             static if (TIsIn!(T, CTYPES)) { 
    125                 const char[] ifBlock = `if (tp == "`~T.stringof~`") { 
     96            const char[] ifBlock = `if (tp == "`~T.stringof~`") { 
    12697    auto p = id in opts; 
    12798    if (p) { 
     
    130101    } 
    131102}`; 
    132             } else 
    133                 const char[] ifBlock = `if (tp == "`~T.stringof~`") { 
    134     `~T.stringof~`** p = id in opts`~TName!(T)~`; 
    135     if (p !is null) **p = parseTo!(`~T.stringof~`) (dt); 
    136 }`; 
    137103            static if (A.length) 
    138104                const char[] addTagMixin = ifBlock~` else `~addTagMixin!(A).addTagMixin; 
     
    140106                const char[] addTagMixin = ifBlock; 
    141107        } 
    142          
    143         // For list 
    144         template listMixin(A...) { 
    145             static if (A.length) { 
    146                 static if (TIsIn!(A, CTYPES)) 
    147                     const char[] listMixin = listMixin!(A[1..$]); 
    148                 else 
    149                     const char[] listMixin = `ret ~= opts`~TName!(A[0])~`.keys;` ~ listMixin!(A[1..$]); 
    150             } else 
    151                 const char[] listMixin = ``; 
    152         } 
    153108    } 
    154109    //END Templates: internal 
     
    157112    //BEGIN Static 
    158113    static { 
    159         /** Add an options sub-class to the list for loading and saving. 
    160          * 
    161          * Call from static this() (before Init calls load()). */ 
    162         void addOptionsClass (Options c, char[] i) 
    163         in {    // Trap a couple of potential coding errors: 
    164             assert (c !is null);    // Instance must be created before calling addOptionsClass 
    165             assert (((cast(ID) i) in subClasses) is null);  // Don't allow a silent replacement 
    166         } body { 
    167             c.secName = i; 
    168             subClasses[cast(ID) i] = c; 
    169         } 
    170      
    171     /** Get the hash map of Options classes. */ 
     114    /** Get the hash map of Options classes. READ-ONLY. */ 
    172115    Options[ID] optionsClasses () { 
    173116        return subClasses; 
     
    240183     
    241184    //BEGIN Non-static 
    242     /+ NOTE: according to spec: "Templates cannot be used to add non-static members or virtual 
    243     functions to classes." However, this appears to work (but linking problems did occur). 
    244     Alternative: use mixins. From OptionsChanges: 
    245         // setT (used to be a template, but: 
    246         // Templates cannot be used to add non-static members or virtual functions to classes. ) 
    247         template setMixin(A...) { 
    248             static if (A.length) { 
    249                 const char[] setMixin = `void set`~TName!(A[0])~` (ID id, `~A[0].stringof~` x) { 
    250                     `~TName!(T)~`s[id] = x; 
    251                 } 
    252                 ` ~ setMixin!(A[1..$]); 
    253             } else 
    254                 const char[] setMixin = ``; 
    255         }+/ 
    256     /+ 
    257     /** Set option symbol of an Options sub-class to val. 
    258      * 
    259      * Due to the way options are handled generically, string IDs must be used to access the options 
    260      * via hash-maps, which is a little slower than direct access but necessary since the option 
    261      * must be changed in two separate places. */ 
    262     /+deprecated void set(T) (char[] symbol, T val) { 
    263         static assert (TIsIn!(T,TYPES) && !TIsIn!(T, CTYPES), "Options.set does not support type "~T.stringof); 
    264          
    265         changed = true;     // something got set (don't bother checking this isn't what it already was) 
    266          
    267         try { 
    268             mixin (`*(opts`~TName!(T)~`[cast(ID) symbol]) = val;`); 
    269             mixin (`optionChanges.`~TName!(T)~`s[symbol] = val;`); 
    270         } catch (ArrayBoundsException) { 
    271             // log and ignore: 
    272             logger.error ("Options.set: invalid symbol"); 
    273         } 
    274     }+/ 
    275     /** Get option symbol of an Options sub-class. 
    276      * 
    277      * Using this method to read an option is not necessary, but allows for generic use.  */ 
    278     deprecated T get(T) (char[] symbol) { 
    279         static assert (TIsIn!(T,TYPES), "Options does not support type "~T.stringof); 
    280          
    281         mixin (`alias opts`~TName!(T)~` optsVars;`); 
    282          
    283         try { 
    284             return *(optsVars[cast(ID) symbol]); 
    285         } catch (ArrayBoundsException) { 
    286             // log and ignore: 
    287             logger.error ("Options.get: invalid symbol"); 
    288         } 
    289     }+/ 
    290      
    291     /** List the names of all options of a specific type. */ 
    292     deprecated char[][] list () { 
    293         char[][] ret; 
    294         mixin (listMixin!(TYPES)); 
    295         return ret; 
    296     } 
    297      
    298185    /// Get all Options stored with a ValueContent. 
    299186    ValueContent[char[]] content() { 
     
    301188    } 
    302189     
    303     /** Variable validate function, called when options are loaded from file. This implementation 
    304      * does nothing. */ 
    305     void validate() {} 
    306      
    307     /** Boolean, telling whether translation strings have been loaded for the instance. */ 
    308     bool transLoaded; 
     190    /** Variable validate function, called when options are loaded from file. 
     191     * 
     192     * This can be overridden to enforce limits on option variables, etc. */ 
     193    protected void validate() {} 
     194     
     195    /** Translated name and description of the instance. mde.gui.content.Items loads these and the 
     196     * translation strings of all enclosed options simultaneously. */ 
     197    char[] name, desc; 
    309198     
    310199    protected { 
    311         char[] secName;         // name of this option setting; set null after translation is loaded 
    312200        OptionChanges optionChanges;    // all changes to options (for saving) 
    313          
    314         // The "pointer lists", e.g. char[]*[ID] optscharA; 
    315         mixin (PLists!(TYPES)); 
    316         ValueContent[char[]] opts;      // generic list of option values 
     201        ValueContent[char[]] opts;  // generic list of option values 
    317202    } 
    318203     
     
    329214    //BEGIN Templates: impl & optionsThis 
    330215    private { 
    331         // Replace, e.g., bool, with BoolContent 
    332         template contentName(A) { 
    333             static if (TIsIn!(A, CTYPES)) { 
    334                 const char[] contentName = VContentN!(A); 
    335             } else 
    336                 const char[] contentName = A.stringof; 
    337         } 
    338216        // Return index of first comma, or halts if not found. 
    339217        template cIndex(char[] A) { 
     
    369247                const char[] parseT = parseT!(type, A[scIndex!(A)+1 .. $]); 
    370248        } 
    371         // May have a trailing comma. Assumes cIndex always returns less than A.$ . 
    372         template aaVars(char[] A) { 
    373             static if (A.length == 0) 
    374                 const char[] aaVars = ""; 
    375             else static if (A[0] == ' ') 
    376                 const char[] aaVars = aaVars!(A[1..$]); 
    377             else 
    378                 const char[] aaVars = "\""~A[0..cIndex!(A)]~"\"[]:&"~A[0..cIndex!(A)] ~ "," ~ 
    379                         aaVars!(A[cIndex!(A)+1..$]); 
    380         } 
    381         // May have a trailing comma. Assumes cIndex always returns less than A.$ . 
    382         template aaVarsContent(char[] A) {//FIXME 
    383             static if (A.length == 0) 
    384             const char[] aaVarsContent = ""; 
    385             else static if (A[0] == ' ') 
    386                 const char[] aaVarsContent = aaVarsContent!(A[1..$]); 
    387             else 
    388                 const char[] aaVarsContent = "\""~A[0..cIndex!(A)]~"\"[]:cast(ValueContent)"~A[0..cIndex!(A)] ~ "," ~ 
    389                 aaVarsContent!(A[cIndex!(A)+1..$]); 
    390         } 
    391249        // strip Trailing Comma 
    392250        template sTC(char[] A) { 
     
    395253            else 
    396254                const char[] sTC = A; 
    397         } 
    398         // if string is empty (other than space) return null, otherwise enclose: [A] 
    399         template listOrNull(char[] A) { 
    400             static if (A.length == 0) 
    401                 const char[] listOrNull = "null"; 
    402             else static if (A[0] == ' ') 
    403                 const char[] listOrNull = listOrNull!(A[1..$]); 
    404             else 
    405                 const char[] listOrNull = "["~A~"]"; 
    406255        } 
    407256        // if B is empty return an empty string otherswise return what's below: 
     
    425274        template optionsThisInternal(char[] A, B...) { 
    426275            static if (B.length) { 
    427                 static if (TIsIn!(B[0], CTYPES)) { 
    428                     const char[] optionsThisInternal = createContents!(B[0],parseT!(B[0].stringof,A))~ 
    429                     optionsThisInternal!(A,B[1..$]); 
    430                 } else 
    431                 const char[] optionsThisInternal = `opts`~TName!(B[0])~` = `~listOrNull!(sTC!(aaVars!(parseT!(B[0].stringof,A))))~";\n" ~ optionsThisInternal!(A,B[1..$]); 
    432             } else 
     276                const char[] optionsThisInternal = createContents!(B[0],parseT!(B[0].stringof,A))~ 
     277            optionsThisInternal!(A,B[1..$]); 
     278        } else 
    433279                const char[] optionsThisInternal = ``; 
    434280        } 
    435281        template declValsInternal(char[] A, B...) { 
    436282            static if (B.length) { 
    437                 const char[] declValsInternal = catOrNothing!(contentName!(B[0]),parseT!(B[0].stringof,A)) ~ declValsInternal!(A,B[1..$]); 
     283                const char[] declValsInternal = catOrNothing!(VContentN!(B[0]),parseT!(B[0].stringof,A)) ~ declValsInternal!(A,B[1..$]); 
    438284            } else 
    439285                const char[] declValsInternal = ``; 
     
    451297            const char[] optionsThis = 
    452298                    "optionChanges = new OptionChanges;\n" ~ 
     299                    "super (name);\n" ~ 
    453300                    optionsThisInternal!(A,TYPES); 
    454301        } 
     
    468315         * --- 
    469316         * mixin (declVals!(A)~` 
    470         this () { 
    471       `~optionsThis!(A)~` 
     317   this (char[] name) { 
     318  `~optionsThis!(A)~` 
    472319    }`); 
    473320         * --- 
     
    481328         * class, but doing so would rather decrease readability of any implementation. */ 
    482329        template impl(char[] A /+, char[] symb+/) { 
    483             const char[] impl = declVals!(A)~"\nthis(){\n"~optionsThis!(A)~"}"; 
     330            const char[] impl = declVals!(A)~"\nthis(char[] name){\n"~optionsThis!(A)~"}"; 
    484331            // ~"\nstatic this(){\n"~optClassAdd!(symb)~"}" 
    485332        } 
     
    488335} 
    489336 
    490 /** Special class to store all locally changed options, whatever the section. */ 
     337/************************************************************************************************* 
     338 * Special class to store all locally changed options. 
     339 *  
     340 * This allows only changed options and those already stored in the user directory to be saved, so 
     341 * that other options can be merged in from a global directory, allowing any options not locally 
     342 * set to be changed globally. 
     343 *************************************************************************************************/ 
    491344class OptionChanges : IDataSection 
    492345{ 
     
    554407} 
    555408 
    556 /* NOTE: Options sub-classes are expected to use a template to ease inserting contents and 
    557 * hide some of the "backend" functionality. Use impl as below, or read the documentation for impl. 
    558 
    559 * Each entry should have a Translation entry with humanized names and descriptions in 
    560 * data/L10n/ClassName.mtt 
    561 
    562 * To create a new Options sub-class, just copy, paste and adjust. 
    563 */ 
    564  
    565 /** A home for all miscellaneous options, at least for now. */ 
     409/** A home for all miscellaneous options. 
     410 * 
     411 * Also a template for deriving Options; comments explain what does what. 
     412 *  
     413 * Translation strings for the options are looked for in data/L10n/SectionName.mtt where 
     414 * this ("SectionName") names the instance. */ 
    566415MiscOptions miscOpts; 
    567416class MiscOptions : Options { 
     417    /* The key step is to mixin impl. 
     418    The syntax is just as simple variables are declared, which is how these options used to be 
     419    stored. Now they're enclosed in ValueContent classes; e.g. "char[] L10n;" is replaced with 
     420    "TextContent L10n;". The pragma statement can be uncommented to see what code gets injected 
     421    (note: pragma () gets called each time the module is imported as well as when it's compiled). 
     422    impl creates a this() function; if you want to include your own CTOR see impl's ddoc. */ 
    568423    const A = "bool exitImmediately; int maxThreads, logLevel, logOutput; double pollInterval; char[] L10n;"; 
    569424    //pragma (msg, impl!(A)); 
    570425    mixin (impl!(A)); 
    571426     
    572     void validate() { 
     427    // Overriding validate allows limits to be enforced on variables at load time. Currently 
     428    // there's no infrastructure for enforcing limits when options are set at run-time. 
     429    override void validate() { 
    573430        // Try to enforce sensible values, whilst being reasonably flexible: 
    574431        if (maxThreads() < 1 || maxThreads() > 64) { 
     
    580437    } 
    581438     
     439    // A static CTOR is a good place to create the instance (it must be created before init runs). 
    582440    static this() { 
    583         miscOpts = new MiscOptions; 
    584         Options.addOptionsClass (miscOpts, "MiscOptions"); 
     441    // Adds instance to Options's tracking; the string is the section name in the config files. 
     442   miscOpts = new MiscOptions ("MiscOptions"); 
    585443    } 
    586444} 
  • mde/setup/Screen.d

    r98 r104  
    265265        logger = Log.getLogger ("mde.setup.Screen"); 
    266266         
    267         videoOpts = new VideoOptions; 
    268         Options.addOptionsClass (videoOpts, "VideoOptions"); 
     267        videoOpts = new VideoOptions ("VideoOptions"); 
    269268    } 
    270269