# HG changeset patch # User Diggory Hardy # Date 1226495931 0 # Node ID 49e7cfed4b34cad9f91a840884f56d6fb86b7967 # Parent 30470bc19ca4ceaf41881ce90da360bb7982a0cd All types of Option have been converted to use ValueContent classes, and their values can be displayed. diff -r 30470bc19ca4 -r 49e7cfed4b34 data/L10n/MiscOptions.mtt --- a/data/L10n/MiscOptions.mtt Mon Nov 10 16:44:44 2008 +0000 +++ b/data/L10n/MiscOptions.mtt Wed Nov 12 13:18:51 2008 +0000 @@ -1,7 +1,8 @@ {MT01} {en-GB} - + + diff -r 30470bc19ca4 -r 49e7cfed4b34 data/conf/gui.mtt --- a/data/conf/gui.mtt Mon Nov 10 16:44:44 2008 +0000 +++ b/data/conf/gui.mtt Wed Nov 12 13:18:51 2008 +0000 @@ -7,7 +7,7 @@ - + @@ -16,8 +16,8 @@ - - - + + + {Basic} diff -r 30470bc19ca4 -r 49e7cfed4b34 data/conf/options.mtt --- a/data/conf/options.mtt Mon Nov 10 16:44:44 2008 +0000 +++ b/data/conf/options.mtt Wed Nov 12 13:18:51 2008 +0000 @@ -3,7 +3,8 @@ - + + {FontOptions} diff -r 30470bc19ca4 -r 49e7cfed4b34 examples/guiDemo.d --- a/examples/guiDemo.d Mon Nov 10 16:44:44 2008 +0000 +++ b/examples/guiDemo.d Wed Nov 12 13:18:51 2008 +0000 @@ -57,10 +57,6 @@ scope Init init = new Init(args); // initialize mde - // Make sure pollInterval has a sane value. FIXME: get Options class to enforce range - if (miscOpts.pollInterval !<= 1.0 || miscOpts.pollInterval !>= 0.0) - miscOpts.set!(double) ("pollInterval", 0.01); - //BEGIN Main loop setup /* Note: the main loop is currently controlled by the scheduler. This is not really ideal, * since it provides no direct control of the order in which components are executed and does @@ -74,7 +70,7 @@ while (run) { mainSchedule.execute (Clock.now()); - Thread.sleep (miscOpts.pollInterval); // sleep this many seconds + Thread.sleep (miscOpts.pollInterval()); // sleep this many seconds } return 0; // cleanup handled by init's DTOR diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/font/FontTexture.d --- a/mde/font/FontTexture.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/font/FontTexture.d Wed Nov 12 13:18:51 2008 +0000 @@ -229,7 +229,7 @@ auto g = face.glyph; // Use renderMode from options, masking bits which are allowable: - if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | (fontOpts.renderMode & 0xF0000))) + if (FT_Load_Glyph (face, gi, FT_LOAD_RENDER | (fontOpts.renderMode() & 0xF0000))) throw new fontGlyphException ("Unable to render glyph"); auto b = g.bitmap; @@ -280,7 +280,7 @@ buffer[i*b.width + j + 2] = b.buffer[i*b.pitch + j + 2]; } - format = (fontOpts.renderMode & RENDER_LCD_BGR) ? GL_BGR : GL_RGB; + format = (fontOpts.renderMode() & RENDER_LCD_BGR) ? GL_BGR : GL_RGB; } else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V) { // NOTE: Notes above apply. But in this case converting the buffers seems essential. buffer = new ubyte[b.width*b.rows]; @@ -292,7 +292,7 @@ buffer[i/3*b.width*3 + 3*j + i%3] = b.buffer[i*b.pitch + j]; } - format = (fontOpts.renderMode & RENDER_LCD_BGR) ? GL_BGR : GL_RGB; + format = (fontOpts.renderMode() & RENDER_LCD_BGR) ? GL_BGR : GL_RGB; } else throw new fontGlyphException ("Unsupported freetype bitmap format"); diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/font/font.d --- a/mde/font/font.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/font/font.d Wed Nov 12 13:18:51 2008 +0000 @@ -71,19 +71,19 @@ // Set LCD filtering method if LCD rendering is enabled. const RMF = FT_LOAD_TARGET_LCD | FT_LOAD_TARGET_LCD_V; - if (fontOpts.renderMode & RMF && - FT_Library_SetLcdFilter(library, cast(FT_LcdFilter)fontOpts.lcdFilter)) { + if (fontOpts.renderMode() & RMF && + FT_Library_SetLcdFilter(library, cast(FT_LcdFilter)fontOpts.lcdFilter())) { /* An error occurred, presumably because LCD rendering support * is not compiled into the library. */ logger.warn ("Bad/unsupported LCD filter option; disabling LCD font rendering."); logger.warn ("Your FreeType 2 library may be compiled without support for LCD/sub-pixel rendering."); // Reset the default filter (in case an invalid value was set in config files). - fontOpts.set!(int) ("lcdFilter", FT_LcdFilter.FT_LCD_FILTER_DEFAULT); + fontOpts.lcdFilter = FT_LcdFilter.FT_LCD_FILTER_DEFAULT; /* If no support for LCD filtering, then LCD rendering only emulates NORMAL with 3 * times wider glyphs. So disable and save the extra work. */ - fontOpts.set!(int) ("renderMode", FT_LOAD_TARGET_NORMAL); + fontOpts.renderMode = FT_LOAD_TARGET_NORMAL; } /* Load font settings diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/gui/content/Content.d --- a/mde/gui/content/Content.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/gui/content/Content.d Wed Nov 12 13:18:51 2008 +0000 @@ -17,7 +17,9 @@ */ module mde.gui.content.Content; +//FIXME: efficient conversions? Need to dup result when formatting a string anyway? import Int = tango.text.convert.Integer; +import Float = tango.text.convert.Float; debug { import tango.util.log.Log : Log, Logger; @@ -92,6 +94,19 @@ char[] name_, desc_;// name and description, loaded by lookup.Translation } +template VContentN(T) { + static if (is(T == bool)) { + const char[] VContentN = "BoolContent"; + } else static if (is(T == int)) { + const char[] VContentN = "IntContent"; + } else static if (is(T == double)) { + const char[] VContentN = "DoubleContent"; + } else static if (is(T == char[])) { + const char[] VContentN = "TextContent"; + } else + static assert (false, "No ValueContent of type "~T.stringof); +} + class BoolContent : ValueContent { /** Create a content with _symbol name symbol. */ @@ -122,6 +137,7 @@ bool opCall () { return v; } + alias opCall opCast; bool v; //FIXME: should be protected but Options needs to set without calling callbacks protected: @@ -132,67 +148,115 @@ /** Text content. */ class TextContent : ValueContent { - this () {} - this (char[] text, char[] name = null) { - text_ = text; - name_ = name; - } - /+ - ContentText dup () { - return new ContentText (text_); + this (char[] symbol, char[] val = null) { + symb = symbol; + v = val; } - ContentText toText () { + /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ + TextContent addChangeCb (void delegate (char[] symbol,char[] value) cb) { + cngCb ~= cb; return this; } - ContentInt toInt () { - // FIXME: convert - return null; - } - +/ /// Get the text. char[] toString (uint i) { - debug logger.trace ("TextContent.toString"); - return (i == 0) ? text_ + return (i == 0) ? v : (i == 1) ? name_ : (i == 2) ? desc_ : null; } + void opAssign (char[] val) { + v = val; + foreach (cb; cngCb) + cb(symb, val); + } + char[] opCall () { + return v; + } + alias opCall opCast; + + char[] v; protected: - char[] text_; + char[] symb; + void delegate (char[],char[])[] cngCb; } -/+ + /** Integer content. */ -class ContentInt : IContent +class IntContent : ValueContent { - this () {} - this (int integer) { - int_ = integer; + /** Create a content with _symbol name symbol. */ + this (char[] symbol, int val = 0) { + symb = symbol; + v = val; } - ContentInt dup () { - return new ContentInt (int_); - } - - ContentText toText () { - return new ContentText(toString); - } - ContentInt toInt () { + /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ + IntContent addChangeCb (void delegate (char[] symbol,int value) cb) { + cngCb ~= cb; return this; } - /// Get the integer. - int integer () { - return int_; + /// Get the text. + char[] toString (uint i) { + return (i == 0) ? Int.toString (v) + : (i == 1) ? name_ + : (i == 2) ? desc_ + : null; } - char[] toString () { - return Int.toString (int_); + void opAssign (int val) { + v = val; + foreach (cb; cngCb) + cb(symb, val); + } + int opCall () { + return v; + } + alias opCall opCast; + + int v; +protected: + char[] symb; + void delegate (char[],int)[] cngCb; +} + +/** Double content. */ +class DoubleContent : ValueContent +{ + /** Create a content with _symbol name symbol. */ + this (char[] symbol, double val = 0) { + symb = symbol; + v = val; } + /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ + DoubleContent addChangeCb (void delegate (char[] symbol,double value) cb) { + cngCb ~= cb; + return this; + } + + /// Get the text. + char[] toString (uint i) { + return (i == 0) ? Float.toString (v) + : (i == 1) ? name_ + : (i == 2) ? desc_ + : null; + } + + void opAssign (double val) { + v = val; + foreach (cb; cngCb) + cb(symb, val); + } + double opCall () { + return v; + } + alias opCall opCast; + + double v; protected: - int int_; + char[] symb; + void delegate (char[],double)[] cngCb; } -+/ \ No newline at end of file diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/gui/widget/createWidget.d --- a/mde/gui/widget/createWidget.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/gui/widget/createWidget.d Wed Nov 12 13:18:51 2008 +0000 @@ -103,6 +103,7 @@ // content editables: 0x30 editContent = FUNCTION | TAKES_CONTENT | 0x30, + DisplayContent = TAKES_CONTENT | 0x30, BoolContent = TAKES_CONTENT | 0x31, GridLayout = TAKES_CONTENT | PARENT | 0x100, @@ -121,6 +122,7 @@ "Button", "TextLabel", "ContentLabel", + "DisplayContent", "BoolContent", "editContent", "TrialContentLayout", diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/lookup/Options.d --- a/mde/lookup/Options.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/lookup/Options.d Wed Nov 12 13:18:51 2008 +0000 @@ -81,8 +81,9 @@ // All supported types, for generic handling via templates. It should be possible to change // the supported types simply by changing this list now (untested). template store(A...) { alias A store; } - alias store!(bool, int, double, char[]) TYPES; - alias store!(int, double, char[]) TYPES2; + // NOTE: currently all types have transitioned to the new method, but the old method remains + alias store!(bool, int, double, char[]) TYPES; // all types + alias store!(bool, int, double, char[]) CTYPES; // types stored with a content //BEGIN Templates: internal private { // Get name of a type. Basically just stringof, but special handling for arrays. @@ -97,7 +98,7 @@ // Pointer lists template PLists(A...) { static if (A.length) { - static if (is (T == bool)) { + static if (TIsIn!(A[0], CTYPES)) { const char[] PLists = PLists!(A[1..$]); } else const char[] PLists = A[0].stringof~"*[ID] opts"~TName!(A[0])~";\n" ~ PLists!(A[1..$]); @@ -118,11 +119,11 @@ // For addTag template addTagMixin(T, A...) { - static if (is(T == bool)) { + static if (TIsIn!(T, CTYPES)) { const char[] ifBlock = `if (tp == "`~T.stringof~`") { auto p = id in opts; if (p) { - auto q = cast(BoolContent) (*p); + auto q = cast(`~VContentN!(T)~`) (*p); if (q) q.v = parseTo!(`~T.stringof~`) (dt); } }`; @@ -140,7 +141,10 @@ // For list template listMixin(A...) { static if (A.length) { - const char[] listMixin = `ret ~= opts`~TName!(A[0])~`.keys;` ~ listMixin!(A[1..$]); + static if (TIsIn!(A, CTYPES)) + const char[] listMixin = listMixin!(A[1..$]); + else + const char[] listMixin = `ret ~= opts`~TName!(A[0])~`.keys;` ~ listMixin!(A[1..$]); } else const char[] listMixin = ``; } @@ -248,7 +252,7 @@ * via hash-maps, which is a little slower than direct access but necessary since the option * must be changed in two separate places. */ void set(T) (char[] symbol, T val) { - static assert (TIsIn!(T,TYPES) && !is(T == bool), "Options does not support type "~T.stringof); + static assert (TIsIn!(T,TYPES) && !TIsIn!(T, CTYPES), "Options.set does not support type "~T.stringof); changed = true; // something got set (don't bother checking this isn't what it already was) @@ -280,7 +284,7 @@ /** List the names of all options of a specific type. */ char[][] list () { char[][] ret; - mixin (listMixin!(TYPES2)); + mixin (listMixin!(TYPES)); return ret; } @@ -297,7 +301,7 @@ OptionChanges optionChanges; // all changes to options (for saving) // The "pointer lists", e.g. char[]*[ID] optscharA; - mixin (PLists!(TYPES2)); //FIXME + mixin (PLists!(TYPES)); ValueContent[char[]] opts; // generic list of option values } @@ -315,16 +319,10 @@ private { // Replace, e.g., bool, with BoolContent template contentName(A) { - static if (is(A == bool)) { - const char[] contentName = "BoolContent"; - } else static if (is(A == int)) { - const char[] contentName = "int";// no IntContent yet - } else static if (is(A == double)) { - const char[] contentName = "double"; - } else static if (is(A == char[])) { - const char[] contentName = "char[]"; + static if (TIsIn!(A, CTYPES)) { + const char[] contentName = VContentN!(A); } else - static assert (false, "unsuppurted type: "~ A); + const char[] contentName = A.stringof; } // Return index of first comma, or halts if not found. template cIndex(char[] A) { @@ -370,14 +368,14 @@ aaVars!(A[cIndex!(A)+1..$]); } // May have a trailing comma. Assumes cIndex always returns less than A.$ . - template aaVarsBool(char[] A) {//FIXME + template aaVarsContent(char[] A) {//FIXME static if (A.length == 0) - const char[] aaVarsBool = ""; + const char[] aaVarsContent = ""; else static if (A[0] == ' ') - const char[] aaVarsBool = aaVarsBool!(A[1..$]); + const char[] aaVarsContent = aaVarsContent!(A[1..$]); else - const char[] aaVarsBool = "\""~A[0..cIndex!(A)]~"\"[]:"~A[0..cIndex!(A)] ~ "," ~ - aaVarsBool!(A[cIndex!(A)+1..$]); + const char[] aaVarsContent = "\""~A[0..cIndex!(A)]~"\"[]:cast(ValueContent)"~A[0..cIndex!(A)] ~ "," ~ + aaVarsContent!(A[cIndex!(A)+1..$]); } // strip Trailing Comma template sTC(char[] A) { @@ -403,21 +401,20 @@ const char[] catOrNothing = ``; } // foreach decl... - template createBCs(char[] A) { + template createContents(T, char[] A) { static if (A.length == 0) - const char[] createBCs = ""; + const char[] createContents = ""; else static if (A[0] == ' ') - const char[] createBCs = createBCs!(A[1..$]); + const char[] createContents = createContents!(T,A[1..$]); else - const char[] createBCs = A[0..cIndex!(A)]~ ` = (new BoolContent ("`~A[0..cIndex!(A)]~"\")).addChangeCb (&optionChanges.set);\n"~ - createBCs!(A[cIndex!(A)+1..$]); + const char[] createContents = "opts[\""~A[0..cIndex!(A)]~"\"] = " ~ A[0..cIndex!(A)]~ " = (new "~VContentN!(T)~" (\""~A[0..cIndex!(A)]~"\")).addChangeCb (&optionChanges.set);\n"~ + createContents!(T,A[cIndex!(A)+1..$]); } // for recursing on TYPES template optionsThisInternal(char[] A, B...) { static if (B.length) { - static if (is(B[0] == bool)) {//FIXME - const char[] optionsThisInternal = createBCs!(parseT!(B[0].stringof,A))~ - `opts = `~listOrNull!(sTC!(aaVarsBool!(parseT!(B[0].stringof,A))))~";\n" ~ + static if (TIsIn!(B[0], CTYPES)) { + const char[] optionsThisInternal = createContents!(B[0],parseT!(B[0].stringof,A))~ optionsThisInternal!(A,B[1..$]); } else const char[] optionsThisInternal = `opts`~TName!(B[0])~` = `~listOrNull!(sTC!(aaVars!(parseT!(B[0].stringof,A))))~";\n" ~ optionsThisInternal!(A,B[1..$]); @@ -557,18 +554,18 @@ /** A home for all miscellaneous options, at least for now. */ MiscOptions miscOpts; class MiscOptions : Options { - const A = "bool exitImmediately; int maxThreads, logOptions; double pollInterval; char[] L10n;"; + const A = "bool exitImmediately; int maxThreads, logLevel, logOutput; double pollInterval; char[] L10n;"; //pragma (msg, impl!(A)); mixin (impl!(A)); void validate() { // Try to enforce sensible values, whilst being reasonably flexible: - if (miscOpts.maxThreads < 1 || miscOpts.maxThreads > 64) { + if (maxThreads() < 1 || maxThreads() > 64) { logger.warn ("maxThreads must be in the range 1-64. Defaulting to 4."); - miscOpts.set!(int)("maxThreads", 4); + maxThreads = 4; } - if (pollInterval !<= 1.0 || pollInterval !>= 0.0) - set!(double) ("pollInterval", 0.01); + if (pollInterval() !<= 1.0 || pollInterval() !>= 0.0) + pollInterval = 0.01; } static this() { diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/lookup/Translation.d --- a/mde/lookup/Translation.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/lookup/Translation.d Wed Nov 12 13:18:51 2008 +0000 @@ -113,7 +113,7 @@ ID[] secsToLoad // locales/sections to load (dependancies may be added) = [cast(ID) miscOpts.L10n]; // start by loading the current locale - Translation transl = new Translation (name, miscOpts.L10n); + Translation transl = new Translation (name, miscOpts.L10n()); IReader reader; try { diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/mde.d --- a/mde/mde.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/mde.d Wed Nov 12 13:18:51 2008 +0000 @@ -36,6 +36,8 @@ } //BEGIN A simple drawable to print a message in the window. +/* This block of code is to draw the message you see on the screen. Most users of mde would be +better off using the gui drawable in gui.WidgetManager than this. */ import mde.font.font; class SimpleDrawable : Screen.IDrawable { this () { diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/setup/Init.d --- a/mde/setup/Init.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/setup/Init.d Wed Nov 12 13:18:51 2008 +0000 @@ -146,32 +146,21 @@ // Set up the logger: Logger root; try { - enum LOG { - LEVEL = 0xF, // mask for log level - CONSOLE = 0x1000, // log to console? - ROLLFILE= 0x2000 // use Rolling/Switching File Appender? - } - // Where logging is done to is determined at compile-time, currently just via static ifs. root = Log.root; root.clear; // we may no longer want to log to the console // Now re-set the logging level, using the value from the config file: - root.level (cast(Level) (miscOpts.logOptions & LOG.LEVEL), true); + root.level (miscOpts.logOutput() == 0 ? Level.None : cast(Level) miscOpts.logLevel(), true); - // Log to a file (first appender so root seperator messages don't show on console): - if (miscOpts.logOptions & LOG.ROLLFILE) { - // Use 2 log files with a maximum size of 1 MB: - root.add (new AppendFiles (paths.logDir~"/log-.txt", 2, 1024*1024)); - root.info (""); // some kind of separation between runs - root.info (""); - } else if (!(miscOpts.logOptions & LOG.CONSOLE)) { - // make sure at least one logger is enabled - miscOpts.set!(int) ("logOptions", miscOpts.logOptions | LOG.CONSOLE); + if (miscOpts.logOutput() & 2) { // first appender so root seperator messages don't show on console + // Use 2 log files with a maximum size of 16kiB: + root.add (new AppendFiles (paths.logDir~"/log-.txt", 2, 16*1024)); + root.append (Level.None, ""); // some kind of separation between runs + root.append (Level.None, ""); } - if (miscOpts.logOptions & LOG.CONSOLE) { // Log to the console + if (miscOpts.logOutput() & 1) root.add(new AppendConsole); - } logger.info ("Starting mde [no version] on " ~ TimeStamp.toString(WallClock.now)); } catch (Exception e) { // Presumably it was only adding a file appender which failed; set up a new console @@ -256,7 +245,7 @@ } } // Counts number of active threads, and before threads are started is number to use: - size_t numWorking = (toRun.size < miscOpts.maxThreads) ? toRun.size : miscOpts.maxThreads; + size_t numWorking = (toRun.size < miscOpts.maxThreads()) ? toRun.size : miscOpts.maxThreads(); enum STATE { WORKING = 0, DONE = 1, ABORT = 2 } STATE doneInit = STATE.WORKING; Mutex toRunM = new Mutex; // synchronization on toRun, numWorking @@ -381,7 +370,7 @@ } catch (ThreadException e) { logger.error ("Exception while using threads: "~e.msg); logger.error ("Disabling threads and attempting to continue."); - miscOpts.set!(int)("NumThreads", 1); // count includes current thread + miscOpts.maxThreads = 1; // count includes current thread auto x = new InitStageThread (0); x.initThreadFct(); // try with just this thread } // any other exception will be caught in main() and abort program diff -r 30470bc19ca4 -r 49e7cfed4b34 mde/setup/Screen.d --- a/mde/setup/Screen.d Mon Nov 10 16:44:44 2008 +0000 +++ b/mde/setup/Screen.d Wed Nov 12 13:18:51 2008 +0000 @@ -82,14 +82,14 @@ int w, h; if (videoOpts.fullscreen()) { flags |= SDL_FULLSCREEN; - w = videoOpts.screenW; - h = videoOpts.screenH; + w = videoOpts.screenW(); + h = videoOpts.screenH(); } else { if (videoOpts.resizable()) flags |= SDL_RESIZABLE; if (videoOpts.noFrame()) flags |= SDL_NOFRAME; - w = videoOpts.windowW; - h = videoOpts.windowH; + w = videoOpts.windowW(); + h = videoOpts.windowH(); } // OpenGL attributes @@ -157,11 +157,11 @@ void resizeEvent (int w, int h) { // Save new size to config if (videoOpts.fullscreen()) { // probably resizeEvent only called when not fullscreen - videoOpts.set!(int) ("screenW", w); - videoOpts.set!(int) ("screenH", h); + videoOpts.screenW = w; + videoOpts.screenH = h; } else { - videoOpts.set!(int) ("windowW", w); - videoOpts.set!(int) ("windowH", h); + videoOpts.windowW = w; + videoOpts.windowH = h; } if (setWindow (w,h))