Changeset 105:08651e8a8c51
- Timestamp:
- 11/29/08 07:36:39 (1 month ago)
- Files:
-
- codeDoc/todo.txt (modified) (1 diff)
- data/conf/gui.mtt (modified) (2 diffs)
- mde/content/AStringContent.d (added)
- mde/content/Content.d (moved) (moved from mde/gui/content/Content.d) (6 diffs)
- mde/content/Items.d (moved) (moved from mde/gui/content/Items.d) (3 diffs)
- mde/content/Services.d (moved) (moved from mde/gui/content/Services.d) (1 diff)
- mde/gui/WidgetManager.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (1 diff)
- mde/gui/widget/TextWidget.d (modified) (2 diffs)
- mde/gui/widget/createWidget.d (modified) (5 diffs)
- mde/gui/widget/layout.d (modified) (1 diff)
- mde/gui/widget/miscContent.d (modified) (3 diffs)
- mde/gui/widget/textContent.d (modified) (3 diffs)
- mde/imde.d (modified) (2 diffs)
- mde/lookup/Options.d (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
codeDoc/todo.txt
r91 r105 1 1 Copyright © 2007-2008 Diggory Hardy 2 2 License: GNU General Public License version 2 or later (see COPYING) 3 4 5 Content:6 Need a way for a single content to contain multiple "sub-contents", and a way for widgets to be bound to a sub-content.7 -> how8 -> Use indecies; widget's use an integer value to choose index (or a string)?9 -> Protection: read-only and read-write contents?10 -> why11 -> Dynamic lists of name, value and possibly description fields.12 -> Done in a basic case, so is it needed?13 Generic Content creation:14 -> Created centrally, e.g. from options or translation strings.15 -> Creator keeps a hash-map of all created content, so that if the same content is asked for again the same content object will be returned, not a new object (besides efficiency, this keeps content synchronized).16 -> Generic ContentList type for instancing on at run-time.17 -> Items in ContentList may represent a cluster of items; e.g. an option plus it's name and description. These may be special classes, but should use a generic interface allowing getting sub-contents (e.g. value/name/desc.) via an index.18 3 19 4 data/conf/gui.mtt
r104 r105 4 4 {Working} 5 5 <WidgetData|root={0:[0xC100,0,3,3],1:["square","blank","square","blank","floating","blank","square","blank","square"]}> 6 <WidgetData|square={0:[0x1 0,10,10]}>6 <WidgetData|square={0:[0x1,6,6]}> 7 7 <WidgetData|blank={0:[0x2]}> 8 8 <WidgetData|opts={0:[0x2031,0x6030,0],1:["Options","optCls"]}> … … 18 18 <WidgetData|L10n={0:[0x2031,0xC100,0,2,1],1:["Options.MiscOptions.L10n","optBox2","apply"]}> 19 19 <WidgetData|optBox2={0:[0xC100,0,1,3],1:["optName","optSep","optVal"]}>!{cloned to avoid bug #4} 20 <WidgetData|apply={0:[0x 11],1:["Apply (unimplemented)"]}>20 <WidgetData|apply={0:[0x2031,0x4043],1:["quit"]}> 21 21 {Basic} 22 22 <WidgetData|root={0:[0x21,0x90D970],1:["A string!"]}> mde/content/Content.d
r104 r105 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** The content system â common types.16 /** The content system â common interface and a few classes without external dependencies. 17 17 */ 18 module mde.gui.content.Content; 19 20 //FIXME: efficient conversions? Need to dup result when formatting a string anyway? 21 import Int = tango.text.convert.Integer; 22 import Float = tango.text.convert.Float; 23 import derelict.sdl.keysym; 18 module mde.content.Content; 24 19 25 20 debug { … … 27 22 private Logger logger; 28 23 static this () { 29 logger = Log.getLogger ("mde. gui.content.Content");24 logger = Log.getLogger ("mde.content.Content"); 30 25 } 31 26 } … … 34 29 * 35 30 * Services like copy/paste could work on universal content. However, they would need to run a 36 * conversion to the appropriate type (or try next-oldest item on clipboard?). 37 * 38 * Currently Content instances can only have their data set on creation. 39 * Each Content class should provide a method to get it's content, e.g. the method text(). 40 * 41 * Extensions to content: 42 * 43 * These extensions require that a content can notify any dependants of changes. 44 * 45 * Use as a state switch (one option from an enumeration). E.g. a button/selection box could set a 46 * state, and a tabbed box could show a tab based on this. Or could represent an option. 47 */ 31 * conversion to the appropriate type (or try next-oldest item on clipboard?). */ 48 32 interface IContent 49 33 { … … 63 47 } 64 48 65 /** A generic way to handle a list of type IContent. */ 66 class ContentList : IContent 49 /** The base for $(I most) content classes. 50 * 51 * Includes generic callback support, toString implementation and symbol access. 52 * 53 * Derived classes should impement: 54 * --- 55 * this (char[] symbol, T val = /+ default value +/); 56 * void opAssign (T val); // assign val, calling callbacks 57 * T opCall (); // return value 58 * alias opCall opCast; 59 * --- */ 60 class AContent : IContent 67 61 { 68 this (IContent[] list = null, char[] n = null, char[] d = null) { 69 list_ = list; 62 this (char[] symbol) { 63 this.symbol = symbol; 64 } 65 66 void name (char[] n, char[] d = null) { 70 67 name_ = n; 71 68 desc_ = d; 72 69 } 73 this (ValueContent[char[]] l, char[] n = null, char[] d = null) { 70 71 /// Current implementation has 1 callback; can be changed to allow many. 72 EventContent addCallback (void delegate (AContent) cb) { 73 this.cb = cb; 74 return this; 75 } 76 77 char[] toString (uint i) { 78 return i == 0 ? "No value" 79 : i == 1 ? name_ 80 : i == 2 ? desc_ 81 : null; 82 } 83 84 /// End of an event, e.g. a button release or end of an edit (calls callbacks). 85 void endEvent () { 86 if (cb) 87 cb (this); 88 } 89 90 final char[] symbol; // Symbol name for this content 91 protected: 92 char[] name_, desc_; // name and description 93 void delegate (AContent) cb; 94 } 95 96 // FIXME: needs changes to allow updating translated strings. Move to Content and extend AContent? 97 /** A generic way to handle a list of type IContent. */ 98 class ContentList : AContent 99 { 100 this (char[] symbol, AContent[] list = null) { 101 list_.length = list.length; 102 foreach (i,c; list) 103 list_[i] = c; 104 super (symbol); 105 } 106 this (char[] symbol, AContent[char[]] l) { 74 107 list_.length = l.length; 75 108 size_t i; 76 109 foreach (c; l) 77 110 list_[i++] = c; 78 name_ = n; 79 desc_ = d; 80 } 81 82 char[] toString (uint i) { 83 return i == 0 ? Int.toString (list_.length) ~ " elements" 84 : i == 1 ? name_ 85 : i == 2 ? desc_ 86 : null; 111 super (symbol); 87 112 } 88 113 … … 90 115 return list_; 91 116 } 92 ContentList list (IContent[] list) {93 list_ = list;94 return this;95 }96 117 97 118 protected: 98 IContent[] list_; 99 char[] name_, desc_; // name and description 119 final IContent[] list_; 100 120 } 101 121 … … 117 137 } 118 138 119 /** Base class for content containing a simple value. 120 * 121 * All derived classes should have the following functions: 122 * --- 123 * this (char[] symbol, T val = /+ default value +/); 124 * BoolContent addChangeCb (void delegate (char[] symbol,T value) cb); // add a callback called on any change 125 * void assignNoCB (T val); // assign val, but without calling callbacks (for Options) 126 * void opAssign (T val); // assign val, calling callbacks 127 * T opCall (); // return value 128 * alias opCall opCast; 129 * void endEdit (); // Converts sv and assigns to self, calling callbacks 130 * --- 131 * On any assignation (by this, assignNoCB, opAssign) the value should be converted to a string and 132 * assigned to sv, and pos should be clamped to [0,sv.length] (i.e. enforce pos <= sv.length). */ 133 abstract class ValueContent : IContent 134 { 135 protected this () {} 136 137 void name (char[] n, char[] d = null) { 138 name_ = n; 139 desc_ = d; 140 } 141 142 /// Get the text. 143 char[] toString (uint i) { 144 return i == 0 ? sv 145 : i == 1 ? name_ 146 : i == 2 ? desc_ 147 : null; 148 } 149 150 /** Acts on a keystroke and returns the new value. 151 * 152 * Supports one-line editing: left/right, home/end, backspace/delete. */ 153 char[] keyStroke (ushort sym, char[] i) { 154 debug assert (i.length, "TextContent.keyStroke: no value (??)"); // impossible? 155 char k = *i; 156 if (k > 0x20) { 157 if (k == 0x7f) { // delete 158 size_t p = pos; 159 if (p < sv.length) ++p; 160 while (p < sv.length && (sv[p] & 0x80) && !(sv[p] & 0x40)) 161 ++p; 162 sv = sv[0..pos] ~ sv[p..$]; 163 } else { // insert character 164 char[] tail = sv[pos..$]; 165 sv.length = sv.length + i.length; 166 size_t npos = pos+i.length; 167 if (tail) sv[npos..$] = tail.dup; // cannot assign with overlapping ranges 168 sv[pos..npos] = i; 169 pos = npos; 170 } 171 } else { // use sym; many keys output 0 172 if (sym == SDLK_BACKSPACE) { // backspace; k == 0x8 173 char[] tail = sv[pos..$]; 174 if (pos) --pos; 175 while (pos && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) 176 --pos; 177 sv = sv[0..pos] ~ tail; 178 } else if (sym == SDLK_LEFT) { 179 if (pos) --pos; 180 while (pos && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) 181 --pos; 182 } else if (sym == SDLK_RIGHT) { 183 if (pos < sv.length) ++pos; 184 while (pos < sv.length && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) 185 ++pos; 186 } else if (sym == SDLK_HOME || sym == SDLK_UP) { 187 pos = 0; 188 } else if (sym == SDLK_END || sym == SDLK_DOWN) { 189 pos = sv.length; 190 } else 191 debug logger.trace ("Symbol: {}", sym); 192 } 193 return sv; 194 } 195 196 size_t editIndex () { 197 size_t i = 0; 198 for (size_t p = 0; p < pos; ++p) 199 if (!(sv[p] & 0x80) || sv[p] & 0x40) 200 ++i; 201 return i; 202 } 203 204 /// Call at the end of an edit to convert sv to v and call callbacks 205 void endEdit (); 206 protected: 207 char[] sv; // string of value; updated on assignment for displaying and editing 208 size_t pos; // editing position; used by keyStroke 209 char[] symb; 210 char[] name_, desc_;// name and description 211 } 212 213 template VContentN(T) { 214 static if (is(T == bool)) { 215 const char[] VContentN = "BoolContent"; 216 } else static if (is(T == int)) { 217 const char[] VContentN = "IntContent"; 218 } else static if (is(T == double)) { 219 const char[] VContentN = "DoubleContent"; 220 } else static if (is(T == char[])) { 221 const char[] VContentN = "TextContent"; 222 } else 223 static assert (false, "No ValueContent of type "~T.stringof); 224 } 225 226 class BoolContent : ValueContent 227 { 228 /** Create a content with _symbol name symbol. */ 229 this (char[] symbol, bool val = false) { 230 symb = symbol; 231 assignNoCB (val); 232 } 233 234 /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ 235 BoolContent addChangeCb (void delegate (char[] symbol,bool value) cb) { 236 cngCb ~= cb; 237 return this; 238 } 239 240 void assignNoCB (bool val) { 241 v = val; 242 sv = v ? "true" : "false"; 243 if (pos > sv.length) pos = sv.length; 244 } 245 void opAssign (bool val) { 246 assignNoCB (val); 247 foreach (cb; cngCb) 248 cb(symb, val); 249 } 250 bool opCall () { 251 return v; 252 } 253 alias opCall opCast; 254 255 override void endEdit () { 256 v = sv && (sv[0] == 't' || sv[0] == 'T' || sv[0] == '1'); 257 foreach (cb; cngCb) 258 cb(symb, v); 259 } 260 261 protected: 262 bool v; 263 void delegate (char[],bool)[] cngCb; // change callbacks 264 } 265 266 /** Text content. */ 267 class TextContent : ValueContent 268 { 269 this (char[] symbol, char[] val = null) { 270 symb = symbol; 271 v = val; 272 } 273 274 /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ 275 TextContent addChangeCb (void delegate (char[] symbol,char[] value) cb) { 276 cngCb ~= cb; 277 return this; 278 } 279 280 void assignNoCB (char[] val) { 281 v = val; 282 if (pos > sv.length) pos = sv.length; 283 } 284 void opAssign (char[] val) { 285 assignNoCB (val); 286 foreach (cb; cngCb) 287 cb(symb, val); 288 } 289 char[] opCall () { 290 return v; 291 } 292 alias opCall opCast; 293 294 override void endEdit () { 295 foreach (cb; cngCb) 296 cb(symb, v); 297 } 298 299 protected: 300 alias sv v; // don't need separate v and sv in this case 301 void delegate (char[],char[])[] cngCb; 302 } 303 304 /** Integer content. */ 305 class IntContent : ValueContent 306 { 307 /** Create a content with _symbol name symbol. */ 308 this (char[] symbol, int val = 0) { 309 symb = symbol; 310 assignNoCB (val); 311 } 312 313 /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ 314 IntContent addChangeCb (void delegate (char[] symbol,int value) cb) { 315 cngCb ~= cb; 316 return this; 317 } 318 319 void assignNoCB (int val) { 320 v = val; 321 sv = Int.toString (v); 322 if (pos > sv.length) pos = sv.length; 323 } 324 void opAssign (int val) { 325 assignNoCB (val); 326 foreach (cb; cngCb) 327 cb(symb, val); 328 } 329 int opCall () { 330 return v; 331 } 332 alias opCall opCast; 333 334 override void endEdit () { 335 v = Int.toInt (sv); 336 foreach (cb; cngCb) 337 cb(symb, v); 338 } 339 340 protected: 341 int v; 342 void delegate (char[],int)[] cngCb; 343 } 344 345 /** Double content. */ 346 class DoubleContent : ValueContent 347 { 348 /** Create a content with _symbol name symbol. */ 349 this (char[] symbol, double val = 0) { 350 symb = symbol; 351 assignNoCB (val); 352 } 353 354 /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ 355 DoubleContent addChangeCb (void delegate (char[] symbol,double value) cb) { 356 cngCb ~= cb; 357 return this; 358 } 359 360 void assignNoCB (double val) { 361 v = val; 362 sv = Float.toString (v); 363 if (pos > sv.length) pos = sv.length; 364 } 365 void opAssign (double val) { 366 assignNoCB (val); 367 foreach (cb; cngCb) 368 cb(symb, val); 369 } 370 double opCall () { 371 return v; 372 } 373 alias opCall opCast; 374 375 override void endEdit () { 376 v = Float.toFloat (sv); 377 foreach (cb; cngCb) 378 cb(symb, v); 379 } 380 381 protected: 382 double v; 383 void delegate (char[],double)[] cngCb; 384 } 139 /** A Content with no value but able to pass on an event. 140 * 141 * The point being that a button can be tied to one of these. */ 142 alias AContent EventContent; mde/content/Items.d
r104 r105 17 17 * A generic way to access content items. 18 18 *************************************************************************************************/ 19 module mde. gui.content.ContentItems;19 module mde.content.Items; 20 20 21 import mde. gui.content.Content;21 import mde.content.Content; 22 22 import mde.gui.exception; 23 23 24 import mde.imde; 24 25 import mde.lookup.Options; 25 26 import mde.lookup.Translation; … … 37 38 * E.g. get ("Options.MiscOptions.L10n") returns miscOpts.L10n, 38 39 * Items.get ("Options.MiscOptions") returns a ContentList of all misc options. */ 39 IContent get (char[] item) {40 AContent get (char[] item) { 40 41 char[] h = head (item); 41 if (h == "Options") 42 return getOptions (item); 43 throw new ContentItemException (h); 44 } 45 46 /** Same as calling get("Options."~item). */ 47 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); 42 if (h == "Options") { 43 if (item is null) { 44 if (Options.allContentList is null) { 45 AContent[] list; 46 list.length = Options.optionsClasses.length; 47 size_t i; 48 foreach (n,opts; Options.optionsClasses) { 49 if (opts.contentList is null) 50 loadTransl (opts, n); 51 list[i++] = opts.contentList; 52 } 53 Options.allContentList = new ContentList (h, list); 54 Options.allContentList.name ("Options"); //FIXME 55 } 56 return Options.allContentList; 55 57 } 58 h = head (item); 59 auto p = h in Options.optionsClasses; 60 if (p) { 61 if (p.contentList is null) 62 loadTransl (*p, h); 56 63 57 return new ContentList (list, "Options"); 58 } 59 char[] h = head (item); 60 auto p = h in Options.optionsClasses; 61 if (p) { 62 if (p.name is null) loadTransl (*p, h); 63 64 if (item == null) 65 return new ContentList (p.content, p.name, p.desc); 66 67 auto q = (h = head (item)) in p.content; 68 if (q && item is null) // enforce item is an exact match 69 return *q; 64 if (item == null) 65 return p.contentList; 66 67 auto q = (h = head (item)) in p.content; 68 if (q && item is null) // enforce item is an exact match 69 return *q; 70 } 71 } else if (h == "quit" && item is null) { 72 quit.name ("Quit"); //FIXME 73 return quit; 70 74 } 71 75 throw new ContentItemException (h); … … 91 95 Translation trans = Translation.load ("L10n/"~n); 92 96 Translation.Entry transled = trans.getStruct (n); 93 p. name = transled.name;94 p. desc = transled.desc;97 p.contentList = new ContentList (n, p.content); 98 p.contentList.name (transled.name, transled.desc); 95 99 foreach (s, v; p.content) { 96 100 transled = trans.getStruct (s); mde/content/Services.d
r61 r105 26 26 * to know whether caches need updating or not). 27 27 */ 28 module mde. gui.content.Services;28 module mde.content.Services; 29 29 30 30 bool copy (ref Content c) { mde/gui/WidgetManager.d
r103 r105 213 213 import mde.gui.exception; 214 214 import mde.gui.widget.Ifaces; 215 import mde. gui.content.Content; //NOTE - maybe move IContent to a separate module215 import mde.content.Content; 216 216 import mde.gui.widget.createWidget; 217 217 mde/gui/widget/Ifaces.d
r103 r105 26 26 public import mde.gui.types; 27 27 public import mde.gui.renderer.IRenderer; 28 import mde. gui.content.Content; //NOTE - maybe move IContent to a separate module28 import mde.content.Content; 29 29 30 30 mde/gui/widget/TextWidget.d
r103 r105 23 23 import mde.gui.exception; 24 24 import mde.gui.renderer.IRenderer; 25 import mde. gui.content.Content;25 import mde.content.Content; 26 26 27 27 import tango.util.log.Log : Log, Logger; … … 87 87 int index; 88 88 } 89 90 class TextButtonWidget : AButtonWidget91 {92 this (IWidgetManager mgr, widgetID id, WidgetData data) {93 WDCheck (data, 1, 1);94 adapter = mgr.renderer.getAdapter (data.strings[0]);95 adapter.getDimensions (mw, mh);96 w = mw;97 h = mh;98 super (mgr, id, data);99 }100 101 void draw () {102 super.draw();103 adapter.draw (x,y);104 }105 106 void activated () {107 logger.info ("Button \""~adapter.text~"\" pressed");108 }109 110 protected:111 IRenderer.TextAdapter adapter;112 IContent content;113 int index;114 }mde/gui/widget/createWidget.d
r103 r105 22 22 import mde.gui.widget.Ifaces; 23 23 import mde.gui.exception : WidgetDataException; 24 import mde. gui.content.Content; //NOTE - maybe move IContent to a separate module24 import mde.content.Content; 25 25 26 26 // Widgets to create: … … 98 98 // buttons: 0x10 99 99 Button = 0x10, 100 TextButton = 0x11,101 100 102 101 // labels: 0x20 … … 111 110 DisplayContent = TAKES_CONTENT | 0x40, 112 111 BoolContent = TAKES_CONTENT | 0x41, 113 ValueContent = TAKES_CONTENT | 0x42, 112 AStringContent = TAKES_CONTENT | 0x42, 113 ButtonContent = TAKES_CONTENT | 0x43, 114 114 115 115 GridLayout = TAKES_CONTENT | PARENT | 0x100, … … 127 127 "Debug", 128 128 "Button", 129 "TextButton",130 129 "TextLabel", 131 130 "addContent", … … 133 132 "DisplayContent", 134 133 "BoolContent", 135 "ValueContent", 134 "AStringContent", 135 "ButtonContent", 136 136 "editContent", 137 137 "FloatingArea", mde/gui/widget/layout.d
r103 r105 20 20 import mde.gui.exception; 21 21 22 import mde. gui.content.Content;22 import mde.content.Content; 23 23 24 24 import tango.util.container.HashMap; mde/gui/widget/miscContent.d
r103 r105 25 25 26 26 import mde.gui.renderer.IRenderer; 27 import mde. gui.content.Content;28 import Items = mde. gui.content.Items;27 import mde.content.AStringContent; 28 import Items = mde.content.Items; 29 29 30 30 /************************************************************************************************* … … 53 53 if (cast(BoolContent) c) 54 54 return new BoolContentWidget(mgr,id,data,c); 55 else if (cast( ValueContent) c)56 return new ValueContentWidget(mgr,id,data,c);55 else if (cast(AStringContent) c) 56 return new AStringContentWidget(mgr,id,data,c); 57 57 else if (cast(ContentList) c) 58 58 return new ContentListWidget(mgr,id,data,c); … … 86 86 } 87 87 88 /// A button connected to an EventContent 89 class ButtonContentWidget : AButtonWidget 90 { 91 this (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { 92 WDCheck (data, 1); 93 content = cast(EventContent) c; 94 if (!content) throw new ContentException (); 95 adapter = mgr.renderer.getAdapter (content.toString (1)); 96 adapter.getDimensions (mw, mh); 97 w = mw; 98 h = mh; 99 super (mgr, id, data); 100 } 101 102 void draw () { 103 super.draw(); 104 adapter.draw (x,y); 105 } 106 107 void activated () { 108 content.endEvent; 109 } 110 111 protected: 112 IRenderer.TextAdapter adapter; 113 EventContent content; 114 int index; 115 } 116 mde/gui/widget/textContent.d
r103 r105 22 22 import mde.gui.renderer.IRenderer; 23 23 24 import mde. gui.content.Content;24 import mde.content.AStringContent; 25 25 26 26 debug { … … 43 43 } 44 44 45 protected:46 IContent content;45 protected: 46 IContent content; 47 47 } 48 48 49 49 /// Capable of editing any ValueContent class 50 class ValueContentWidget : ATextWidget50 class AStringContentWidget : ATextWidget 51 51 { 52 52 this (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { 53 53 WDMinCheck(data, 1); 54 content = cast( ValueContent) c;54 content = cast(AStringContent) c; 55 55 if (!content) //content = new TextContent (null, null); 56 56 throw new ContentException (); … … 79 79 80 80 protected: 81 ValueContent content;81 AStringContent content; 82 82 } mde/imde.d
r95 r105 20 20 import mde.input.Input; 21 21 import mde.scheduler.Scheduler; 22 import mde.content.Content; 22 23 23 24 static this () { … … 25 26 input = new Input(); 26 27 mainSchedule = new Scheduler; 28 29 quit = (new EventContent("quit")).addCallback ((AContent){ 30 run = false; 31 }); 27 32 } 28 33 34 EventContent quit; /// A content triggering mde to halt 29 35 30 36 Scheduler mainSchedule; /// The schedule used by the main loop. mde/lookup/Options.d
r104 r105 21 21 import mde.exception; 22 22 23 public import mde. gui.content.Content;23 public import mde.content.AStringContent; 24 24 25 25 import mde.file.mergetag.Reader; … … 97 97 auto p = id in opts; 98 98 if (p) { 99 auto q = cast(`~ VContentN!(T)~`) (*p);100 if (q) q.assignNoC B= parseTo!(`~T.stringof~`) (dt);99 auto q = cast(`~ContentN!(T)~`) (*p); 100 if (q) q.assignNoCb = parseTo!(`~T.stringof~`) (dt); 101 101 } 102 102 }`; … … 120 120 private Options[ID] subClasses; 121 121 private bool changed = false; // any changes at all, i.e. do we need to save? 122 123 ContentList allContentList; /// Initially null; created by mde.content.Items on use. 122 124 123 125 /* Load/save options from file. … … 184 186 //BEGIN Non-static 185 187 /// Get all Options stored with a ValueContent. 186 ValueContent[char[]] content() {188 AContent[char[]] content() { 187 189 return opts; 188 190 } … … 193 195 protected void validate() {} 194 196 195 /** Translated name and description of the instance. mde.gui.content.Items loads these andthe196 * translation strings of all enclosed options simultaneously. */197 char[] name, desc;197 /** All content in a ContentList. Initially null; mde.content.Items creates this and loads the 198 * translation strings of all sub-content upon first request involving this Options instance. */ 199 ContentList contentList; 198 200 199 201 protected { 200 202 OptionChanges optionChanges; // all changes to options (for saving) 201 ValueContent[char[]] opts; // generic list of option values203 AContent[char[]] opts; // generic list of option values 202 204 } 203 205 … … 268 270 const char[] createContents = createContents!(T,A[1..$]); 269 271 else 270 const char[] createContents = "opts[\""~A[0..cIndex!(A)]~"\"] = " ~ A[0..cIndex!(A)]~ " = (new "~VContentN!(T)~" (\""~A[0..cIndex!(A)]~"\")).addChangeCb(&optionChanges.set);\n"~272 const char[] createContents = "opts[\""~A[0..cIndex!(A)]~"\"] = (" ~ A[0..cIndex!(A)]~ " = new "~ContentN!(T)~" (\""~A[0..cIndex!(A)]~"\")).addCallback (&optionChanges.set);\n"~ 271 273 createContents!(T,A[cIndex!(A)+1..$]); 272 274 } … … 281 283 template declValsInternal(char[] A, B...) { 282 284 static if (B.length) { 283 const char[] declValsInternal = catOrNothing!( VContentN!(B[0]),parseT!(B[0].stringof,A)) ~ declValsInternal!(A,B[1..$]);285 const char[] declValsInternal = catOrNothing!(ContentN!(B[0]),parseT!(B[0].stringof,A)) ~ declValsInternal!(A,B[1..$]); 284 286 } else 285 287 const char[] declValsInternal = ``; … … 354 356 const char[] Vars = ``; 355 357 } 356 // For set357 template Set(A...) {358 static if (A.length) {359 const char[] Set= `void set (char[] s,`~A[0].stringof~` v) {360 Options.changed = true;361 `~TName!(A[0])~`s[s] = v;362 }`~ Set!(A[1..$]);363 } else364 const char[] Set = ``;365 }366 367 358 // For addTag 368 359 template addTagMixin(T, A...) { … … 391 382 // optsX store pointers to each item added along with the ID and are used for access. 392 383 mixin(Vars!(TYPES)); 393 // set (char[] symbol, T value); (not templates but for each type T) 394 mixin(Set!(TYPES)); 395 384 385 void set (AContent c) { 386 union U { 387 BoolContent bc; 388 StringContent sc; 389 IntContent ic; 390 DoubleContent dc; 391 } 392 U u; 393 if ((u.bc = cast(BoolContent) c) !is null) 394 bools[u.bc.symbol] = u.bc(); 395 else if ((u.sc = cast(StringContent) c) !is null) 396 charAs[u.sc.symbol] = u.sc(); 397 else if ((u.ic = cast(IntContent) c) !is null) 398 ints[u.ic.symbol] = u.ic(); 399 else if ((u.dc = cast(DoubleContent) c) !is null) 400 doubles[u.dc.symbol] = u.dc(); 401 Options.changed = true; 402 } 403 396 404 this () {} 397 405
