Mercurial > projects > mde
view mde/options.d @ 16:9cb7b9310168
Improvements to Options and Init.
Revamped Options with sections and auto saving/loading.
Moved some of init's functions outside the module.
committer: Diggory Hardy <diggory.hardy@gmail.com>
author | Diggory Hardy <diggory.hardy@gmail.com> |
---|---|
date | Sat, 15 Mar 2008 11:56:13 +0000 |
parents | 4608be19ebe2 |
children | 5f90774ea1ef |
line wrap: on
line source
/** This module handles stored options, currently all except input maps. * * The purpose of having all options centrally controlled is to allow generic handling by the GUI * and ease saving and loading of values. The Options class is only really designed around handling * small numbers of variables for now. */ module mde.options; import mde.exception; import mde.mergetag.Reader; import mde.mergetag.Writer; import mde.mergetag.DataSet; import mde.mergetag.exception; import mde.resource.paths; import tango.scrapple.text.convert.parseTo : parseTo; import tango.scrapple.text.convert.parseFrom : parseFrom; import tango.util.log.Log : Log, Logger; /** Base class for handling options. This class itself will handle no options and should not be * instantiated, but sub-classes handle options. * * Each sub-class provides named variables for maximal-speed reading & writing. Sub-class references * are stored by name, and will be available after pre-init has run (DO NOT access before this). * * The static class keeps track of all Options class instances for global loading and saving. * * Details: Options sub-classes hold associative arrays of pointers to all option variables, with a * char[] id. This list is used for saving, loading and to provide generic GUI options screens. The * built-in support in Options is only for bool, int and char[] types (a float type may get added). */ class Options : IDataSection { // No actual options are stored by this class. However, much of the infrastructure is // present since it need not be redefined in sub-classes. // The "pointer lists": protected bool* [ID] optsBool; protected char[]*[ID] optsCharA; protected int* [ID] optsInt; //BEGIN Mergtag loading/saving code void addTag (char[] tp, ID id, char[] dt) { if (tp == "bool") { bool** p = id in optsBool; if (p !is null) **p = parseTo!(bool) (dt); } else if (tp == "char[]") { char[]** p = id in optsCharA; if (p !is null) **p = parseTo!(char[]) (dt); } else if (tp == "int") { int** p = id in optsInt; if (p !is null) **p = parseTo!(int) (dt); } } void writeAll (ItemDelg dlg) { foreach (ID id, bool* val; optsBool) dlg ("bool" , id, parseFrom!(bool ) (*val)); foreach (ID id, char[]* val; optsCharA) dlg ("char[]", id, parseFrom!(char[]) (*val)); foreach (ID id, int* val; optsInt) dlg ("int" , id, parseFrom!(int ) (*val)); } //END Mergtag loading/saving code //BEGIN Static // Each individual section static OptionsMisc misc; /* Load/save options from file. * * If the file doesn't exist, no reading is attempted (options are left at default values). */ private static const fileName = "options"; static void load () { // Create all uncreated sections now, so that if we return early they are still created. if (misc is null) misc = new OptionsMisc; // Check it exists (if not it should still be created on exit). // Don't bother checking it's not a folder, because it could still be a block or something. if (!confDir.exists (fileName)) return; IReader reader; try { reader = confDir.makeMTReader (fileName, PRIORITY.LOW_HIGH); reader.dataSecCreator = delegate IDataSection(ID id) { /* Recognise each defined section, and return null for unrecognised sections. */ if (id == cast(ID) "misc") return misc; else return null; }; reader.read; } catch (MTException e) { logger.error ("Mergetag exception occurred:"); logger.error (e.msg); throw new optionsLoadException ("Loading aborted: mergetag exception"); } if (misc is null) throw new optionsLoadException ("Loading failed: section \"misc\" not found"); } static void save () { DataSet ds = new DataSet(); ds.sec[cast(ID) "misc"] = misc; IWriter writer; try { writer = confDir.makeMTWriter (fileName, ds); writer.write(); } catch (MTException e) { logger.error ("Mergetag exception occurred; saving aborted:"); logger.error (e.msg); //FIXME: currently nothing done besides logging the error } } private static Logger logger; static this() { logger = Log.getLogger ("mde.options"); } //END Static } /** A home for all miscellaneous options, at least for now. */ class OptionsMisc : Options { bool useThreads; // set 0 to disable threading char[] L10n; // locale, e.g. en-GB int logLevel; // tango logger level this () { optsBool = ["useThreads":&useThreads]; optsCharA = ["L10n":&L10n]; optsInt = ["logLevel":&logLevel]; } }