# HG changeset patch # User Diggory Hardy # Date 1231964654 0 # Node ID 41582439a42bc19acdf29e0f7fe2839df58fae8f # Parent 3328c6fb77cae00ef78c2f7ab5ab37681cee3a0a Added support for dynamic EnumContent loading and saving, with translation loading. WMScreen.init removed; code moved to this() since class is now created by main() instead of a static this(). Fix for SwitchWidget not passing events. Still some resizing bugs evident in SwitchWidget :-( diff -r 3328c6fb77ca -r 41582439a42b data/L10n/en-GB.mtt --- a/data/L10n/en-GB.mtt Thu Jan 08 20:09:46 2009 +0000 +++ b/data/L10n/en-GB.mtt Wed Jan 14 20:24:14 2009 +0000 @@ -9,6 +9,8 @@ + + {MiscOptions} @@ -33,3 +35,8 @@ +{dynamic} + + + + diff -r 3328c6fb77ca -r 41582439a42b data/conf/guiDemo.mtt --- a/data/conf/guiDemo.mtt Thu Jan 08 20:09:46 2009 +0000 +++ b/data/conf/guiDemo.mtt Wed Jan 14 20:24:14 2009 +0000 @@ -3,20 +3,28 @@ {Working} - + + + - - - - - + + + + + + + + + + + !{use optBox for no description, optDBox for descriptions under entries} - + @@ -24,10 +32,5 @@ - - - - {Basic} diff -r 3328c6fb77ca -r 41582439a42b examples/guiDemo.d --- a/examples/guiDemo.d Thu Jan 08 20:09:46 2009 +0000 +++ b/examples/guiDemo.d Wed Jan 14 20:24:14 2009 +0000 @@ -45,7 +45,6 @@ // Set up the gui scope WMScreen gui = new WMScreen ("guiDemo"); StageState guiLoad () { // init func - gui.init; gui.loadDesign(); return StageState.ACTIVE; } diff -r 3328c6fb77ca -r 41582439a42b mde/content/AStringContent.d --- a/mde/content/AStringContent.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/content/AStringContent.d Wed Jan 14 20:24:14 2009 +0000 @@ -302,6 +302,7 @@ * val = which value is active; must be in [0,length-1] */ this (char[] symbol, char[][] enumSymbols, int val = 0) { + this.enumSymbols = enumSymbols; enums.length = enumSymbols.length; char[] symPeriod = symbol~'.'; foreach (i, ref e; enums) { @@ -310,6 +311,20 @@ super (symbol, val); // calls assignNoCb } + /** Create from a EnumCStruct. */ + this (char[] symbol, EnumCStruct data) { + this (symbol, data.symbols, data.value); + } + + /** 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; + } + override void assignNoCb (int val) { // called by children (via opAssign) if (val >= enums.length || val < 0) { logger.error ("EnumContent "~name_~" assigned invalid value; keeping value: "~sv); @@ -351,8 +366,14 @@ return enums; } + struct EnumCStruct { + char[][] symbols; + int value; + } + protected: EnumValueContent[] enums; + char[][] enumSymbols; // saved for getStructOf /** Special version of BoolContent for each enumeration to update the parent Enum. */ private class EnumValueContent : BoolContent { diff -r 3328c6fb77ca -r 41582439a42b mde/content/Items.d --- a/mde/content/Items.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/content/Items.d Wed Jan 14 20:24:14 2009 +0000 @@ -41,7 +41,8 @@ * Items.get ("Options.MiscOptions") returns a ContentList of all misc options. */ Content get (char[] item) { assert (currentL10n is miscOpts.L10n(), "must call loadTranslation (code error)"); - + char[] orig = item; // item is modified by head() + char[] h = head (item); if (h == "Options") { if (item is null) @@ -63,11 +64,12 @@ return imde.menu; else if (h == "quit" && item is null) return imde.quit; - else if (h == "sw" && item is null) - return imde.sw; - } - logger.warn ("Bad content specifier: {}",h); - return new ErrorContent ("Error: bad content specifier",h); + } else if (h == "dynamic") { + auto i = head (item) in items; + if (i) return *i; + } + + return new ErrorContent ("Error: bad content specifier", orig); } /** Creates some content on first run (required by get()). @@ -88,14 +90,15 @@ Options.allContentList = new ContentList ("Options", list); } + Translation trl; + Translation.Entry trle; + // Translate Options: - Translation.Entry trle; with (Options.allContentList) { trle = Translation.get (symbol).getStruct (symbol); name (trle.name, trle.desc); } foreach (n,opts; Options.optionsClasses) { - Translation trl; trl = Translation.get (n); trle = trl.getStruct (n); opts.contentList.name (trle.name, trle.desc); @@ -113,15 +116,42 @@ } // Translate imde: - trle = Translation.get ("imde").getStruct ("menu"); + trl = Translation.get ("imde"); + trle = trl.getStruct ("menu"); imde.menu.name (trle.name, trle.desc); - trle = Translation.get ("imde").getStruct ("quit"); + trle = trl.getStruct ("quit"); imde.quit.name (trle.name, trle.desc); + + // Translate dynamic content: + if (items.length) { + trl = Translation.get ("dynamic"); + foreach (n,item; items) { + trle = trl.getStruct (n); + item.name (trle.name, trle.desc); + IContentList cl = cast(IContentList) item; + if (cl) { + foreach (i,c; cl.list) { + trle = trl.getStruct (c.symbol); + c.name (trle.name, trle.desc); + } + } + } + } currentL10n = miscOpts.L10n(); } + /** Add content c with name c.symbol, so that translations are loaded for it and it can be + * returned by get ("dynamic."~c.symbol). */ + Content addContent (Content c) { + items[c.symbol] = c; + return c; + } + private: + // NOTE: possibly add all content to this list. Lookups would be faster. + Content[char[]] items; // dynamically added content + /** Takes the string "head.tail" where tail may contain '.' but head does not, returns "head", * with str set to "tail". */ char[] head (ref char[] str) { diff -r 3328c6fb77ca -r 41582439a42b mde/content/miscContent.d --- a/mde/content/miscContent.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/content/miscContent.d Wed Jan 14 20:24:14 2009 +0000 @@ -57,6 +57,7 @@ this (char[] name, char[] msg) { super (name); this.msg = msg; + logger.error (name ~ ": " ~ msg); } override char[] toString (uint i) { diff -r 3328c6fb77ca -r 41582439a42b mde/gui/WMScreen.d --- a/mde/gui/WMScreen.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/gui/WMScreen.d Wed Jan 14 20:24:14 2009 +0000 @@ -26,8 +26,6 @@ import mde.gui.renderer.createRenderer; import mde.setup.Screen; -import Items = mde.content.Items; // loadTranslation -import mde.lookup.Options; // miscOpts.L10n callback import tango.util.log.Log : Log, Logger; @@ -50,29 +48,21 @@ scope class WMScreen : AWidgetManager, Screen.IDrawable { /** Construct a new widget manager. * + * Must be run after static this. + * * params: * fileName = Name of file specifying the gui, excluding path and extension. */ this (char[] file) { + // Doesn't need a lock - cannot conflict with other class functions. super(file); Screen.addDrawable (this); - clickCallbacks = new typeof(clickCallbacks); - motionCallbacks = new typeof(motionCallbacks); - } - - // this() runs during static this(), when imde.input doesn't exist. init() runs later. - void init () { - // Doesn't need a lock - cannot conflict with other class functions. // Events we want to know about: imde.input.addMouseClickCallback(&clickEvent); imde.input.addMouseMotionCallback(&motionEvent); - - Items.loadTranslation (); - miscOpts.L10n.addCallback (&reloadStrings); } - /** Draw the gui. */ void draw() { synchronized(mutex) { diff -r 3328c6fb77ca -r 41582439a42b mde/gui/WidgetDataSet.d --- a/mde/gui/WidgetDataSet.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/gui/WidgetDataSet.d Wed Jan 14 20:24:14 2009 +0000 @@ -28,11 +28,14 @@ module mde.gui.WidgetDataSet; public import mde.gui.types; +import mde.content.AStringContent; +import Items = mde.content.Items; // For loading from file: import mt = mde.file.mergetag.DataSet; import mt = mde.file.mergetag.DefaultData; import mde.file.serialize; + import tango.util.log.Log : Log, Logger; private Logger logger; @@ -52,6 +55,11 @@ widgetData[id] = deserialize!(WidgetData) (dt); } else if (tp == "WDims" && (id in dimData) is null) { dimData[id] = cast(wdims) deserialize!(int[]) (dt); + } else if (tp == "EnumContent" && (id in enumContent) is null) { + // Add dynamic content. NOTE: could confict with content from another design/section. + EnumContent a = new EnumContent (id, deserialize!(EnumContent.EnumCStruct) (dt)); + enumContent[id] = a; + Items.addContent (a); } } // Only WidgetDataChanges is used for writing. @@ -77,6 +85,7 @@ protected: WidgetData[widgetID] widgetData; // Per-widget data wdims[widgetID] dimData; // Per-widget sizes + EnumContent[char[]] enumContent; } /************************************************************************************************* @@ -88,7 +97,9 @@ { /** * Params: - * wds = The base WidgetDataSet these changes are applied against. */ + * wds = The base WidgetDataSet these changes are applied against. + * + * Base's enumContent is used directly; this.enumContent is null. */ this (WidgetDataSet wds) { base = wds; } @@ -101,6 +112,8 @@ dlg ("WidgetData", id, serialize!(WidgetData) (data)); foreach (id,dim; dimData) dlg ("WDims", id, serialize!(int[]) (cast(int[]) dim)); + foreach (id,c; base.enumContent) + dlg ("EnumContent", id, serialize (c.structOf)); } //END Mergetag code @@ -118,8 +131,8 @@ } /** Do any changes exist? True if no changes have been stored. */ - bool none () { - return widgetData.length == 0; + bool noChanges () { + return widgetData.length == 0 && dimData.length == 0 && enumContent.length == 0; } protected WidgetDataSet base; diff -r 3328c6fb77ca -r 41582439a42b mde/gui/WidgetManager.d --- a/mde/gui/WidgetManager.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/gui/WidgetManager.d Wed Jan 14 20:24:14 2009 +0000 @@ -24,9 +24,12 @@ import mde.gui.WidgetDataSet; import mde.gui.widget.Ifaces; import mde.gui.exception; -import mde.content.Content; import imde = mde.imde; +import mde.lookup.Options; // miscOpts.L10n callback +import mde.content.Content; +import Items = mde.content.Items; // loadTranslation + import mde.file.mergetag.Reader; import mde.file.mergetag.Writer; import mde.setup.paths; @@ -64,6 +67,10 @@ protected this (char[] file) { mutex = new Mutex; // Used on functions intended to be called from outside the gui package. fileName = file; + miscOpts.L10n.addCallback (&reloadStrings); + + clickCallbacks = new typeof(clickCallbacks); + motionCallbacks = new typeof(motionCallbacks); } /* Load the widgets' data from the file specified to the CTOR. @@ -123,6 +130,8 @@ logger.error (e.msg); throw new GuiException ("Failure parsing config file"); } + + Items.loadTranslation (); } /** Load the gui from some design. @@ -180,8 +189,10 @@ mutex.lock; scope(exit) mutex.unlock; - // Make all widgets save any changed data; return if no changes: - if (!child.saveChanges) + // Make all widgets save any changed data: + child.saveChanges; + + if (changes.noChanges) return; if (loadUserFile) { // merge entries from user file into current changes diff -r 3328c6fb77ca -r 41582439a42b mde/gui/widget/miscContent.d --- a/mde/gui/widget/miscContent.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/gui/widget/miscContent.d Wed Jan 14 20:24:14 2009 +0000 @@ -198,6 +198,10 @@ currentW.setPosition (nx,ny); } + override IChildWidget getWidget (wdim cx, wdim cy) { + return currentW.getWidget (cx, cy); + } + override void draw () { currentW.draw; } diff -r 3328c6fb77ca -r 41582439a42b mde/imde.d --- a/mde/imde.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/imde.d Wed Jan 14 20:24:14 2009 +0000 @@ -20,7 +20,6 @@ import mde.input.Input; import mde.scheduler.Scheduler; import mde.content.miscContent; -import mde.content.AStringContent; //FIXME: for sw static this () { // Make these available to all importing modules' static CTORs, as well as during init. @@ -37,15 +36,11 @@ new EventContent("b"), new EventContent("c")]) ]); - - sw = new EnumContent ("switch", ["one", "two"]); } ContentList menu; /// Root menu for imde EventContent quit; /// A content triggering mde to halt -EnumContent sw; - Scheduler mainSchedule; /// The schedule used by the main loop. /** Some enums used by per request scheduled functions. */ diff -r 3328c6fb77ca -r 41582439a42b mde/lookup/Translation.d --- a/mde/lookup/Translation.d Thu Jan 08 20:09:46 2009 +0000 +++ b/mde/lookup/Translation.d Wed Jan 14 20:24:14 2009 +0000 @@ -156,6 +156,7 @@ if (p) { return *p; } else { + logger.warn ("Unable to find translation for {} in {}", id, section); Entry ret; ret.name = id; return ret;