# HG changeset patch # User Diggory Hardy # Date 1226855027 0 # Node ID 71f0f1f836202a8c1e6fd1ca208b7def87662835 # Parent 0ea4a3e651ae8d06e5f08531462729946f16800b Some path adjustments for windows (untested) and fonts. All types of option can be edited. paths: support for getting the full path for a font when just the file name is entered, in order to unify usage on windows and linux. paths: Used getSpecialPath for some windows paths; needs testing. Content: Moved line-editing code to abstract ValueContent class and added some conversion functions, so that any type of ValueContent can be edited as text. diff -r 0ea4a3e651ae -r 71f0f1f83620 data/conf/gui.mtt --- a/data/conf/gui.mtt Sat Nov 15 17:39:14 2008 +0000 +++ b/data/conf/gui.mtt Sun Nov 16 17:03:47 2008 +0000 @@ -14,7 +14,6 @@ - + {Basic} diff -r 0ea4a3e651ae -r 71f0f1f83620 data/conf/options.mtt --- a/data/conf/options.mtt Sat Nov 15 17:39:14 2008 +0000 +++ b/data/conf/options.mtt Sun Nov 16 17:03:47 2008 +0000 @@ -10,8 +10,8 @@ {FontOptions} - -! +! + {VideoOptions} diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/font/font.d --- a/mde/font/font.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/font/font.d Sun Nov 16 17:03:47 2008 +0000 @@ -22,6 +22,7 @@ import mde.font.exception; import mde.setup.exception; // InitStage stuff +import mde.setup.paths; import derelict.freetype.ft; @@ -125,16 +126,16 @@ * Even if the same font is used at multiple sizes, multiple copies of FT_Face are used. * Sharing an FT_Face would require calling FT_Set_Pixel_Sizes each time a glyph is rendered or * swapping the size information (face.size)? */ - this (char[] path, int size) + this (char[] file, int size) in { assert (library !is null, "font: library is null"); } body { - if (FT_New_Face (library, toStringz(path), 0, &face)) - throw new fontLoadException ("Unable to read font: "~path); + if (FT_New_Face (library, getFontPath (file).ptr, 0, &face)) + throw new fontLoadException ("Unable to read font: "~file[0..$-1]); if (!FT_IS_SCALABLE (face)) throw new fontLoadException ("Currently no support for non-scalable fonts (which " ~ - path ~ " is). Please report if you want to see support."); + file[0..$-1] ~ " is). Please report if you want to see support."); /* The following will need to be addressed when adding support for non-scalables: * Use of face.size.metrics.height property. */ diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/gui/content/Content.d --- a/mde/gui/content/Content.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/gui/content/Content.d Sun Nov 16 17:03:47 2008 +0000 @@ -91,7 +91,75 @@ name_ = n; desc_ = d; } + + /// Get the text. + char[] toString (uint i) { + return (i == 0) ? sv + : (i == 1) ? name_ + : (i == 2) ? desc_ + : null; + } + + /** Acts on a keystroke and returns the new value. + * + * Supports one-line editing: left/right, home/end, backspace/delete. */ + char[] keyStroke (ushort sym, char[] i) { + debug assert (i.length, "TextContent.keyStroke: no value (??)"); // impossible? + char k = *i; + if (k > 0x20) { + if (k == 0x7f) { // delete + size_t p = pos; + if (p < sv.length) ++p; + while (p < sv.length && (sv[p] & 0x80) && !(sv[p] & 0x40)) + ++p; + sv = sv[0..pos] ~ sv[p..$]; + } else { // insert character + char[] tail = sv[pos..$]; + sv.length = sv.length + i.length; + size_t npos = pos+i.length; + if (tail) sv[npos..$] = tail.dup; // cannot assign with overlapping ranges + sv[pos..npos] = i; + pos = npos; + } + } else { // use sym; many keys output 0 + if (sym == SDLK_BACKSPACE) { // backspace; k == 0x8 + char[] tail = sv[pos..$]; + if (pos) --pos; + while (pos && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) + --pos; + sv = sv[0..pos] ~ tail; + } else if (sym == SDLK_LEFT) { + if (pos) --pos; + while (pos && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) + --pos; + } else if (sym == SDLK_RIGHT) { + if (pos < sv.length) ++pos; + while (pos < sv.length && (sv[pos] & 0x80) && !(sv[pos] & 0x40)) + ++pos; + } else if (sym == SDLK_HOME || sym == SDLK_UP) { + pos = 0; + } else if (sym == SDLK_END || sym == SDLK_DOWN) { + pos = sv.length; + } else + debug logger.trace ("Symbol: {}", sym); + } + return sv; + } + + size_t getEditIndex () { + size_t i = 0; + for (size_t p = 0; p < pos; ++p) + if (!(sv[p] & 0x80) || sv[p] & 0x40) + ++i; + return i; + } + + /// Call at the end of an edit to convert sv to v and call callbacks + void endEdit (); protected: + char[] sv; // string of value; updated on assignment for displaying and editing + size_t pos; // editing position; used by keyStroke + char[] symb; char[] name_, desc_;// name and description, loaded by lookup.Translation } @@ -113,7 +181,7 @@ /** Create a content with _symbol name symbol. */ this (char[] symbol, bool val = false) { symb = symbol; - v = val; + assignNoCB (val); } /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ @@ -122,17 +190,13 @@ return this; } - /// Get the text. - char[] toString (uint i) { - return (i == 0) ? v ? "true" : "false" - : (i == 1) ? name_ - : (i == 2) ? desc_ - : null; + void assignNoCB (bool val) { + v = val; + sv = v ? "true" : "false"; } - void opAssign (bool val) { - v = val; - foreach (cb; cngCb) + assignNoCB (val); + foreach (cb; cngCb) cb(symb, val); } bool opCall () { @@ -140,9 +204,14 @@ } alias opCall opCast; - bool v; //FIXME: should be protected but Options needs to set without calling callbacks + void endEdit () { + v = sv && (sv[0] == 't' || sv[0] == 'T' || sv[0] == '1'); + foreach (cb; cngCb) + cb(symb, v); + } + protected: - char[] symb; + bool v; void delegate (char[],bool)[] cngCb; // change callbacks } @@ -152,7 +221,6 @@ this (char[] symbol, char[] val = null) { symb = symbol; v = val; - pos = v.length; } /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ @@ -161,14 +229,9 @@ return this; } - /// Get the text. - char[] toString (uint i) { - return (i == 0) ? v - : (i == 1) ? name_ - : (i == 2) ? desc_ - : null; + void assignNoCB (char[] val) { + v = val; } - void opAssign (char[] val) { v = val; foreach (cb; cngCb) @@ -179,70 +242,13 @@ } alias opCall opCast; - /** Acts on a keystroke and returns the new value. - * - * Supports one-line editing: left/right, home/end, backspace/delete. */ - char[] keyStroke (ushort sym, char[] i) { - debug assert (i.length, "TextContent.keyStroke: no value (??)"); // impossible? - char k = *i; - if (k > 0x20) { - if (k == 0x7f) { // delete - size_t p = pos; - if (p < v.length) ++p; - while (p < v.length && (v[p] & 0x80) && !(v[p] & 0x40)) - ++p; - v = v[0..pos] ~ v[p..$]; - } else { // insert character - char[] tail = v[pos..$]; - v.length = v.length + i.length; - size_t npos = pos+i.length; - if (tail) v[npos..$] = tail.dup; // cannot assign with overlapping ranges - v[pos..npos] = i; - pos = npos; - } - } else { // use sym; many keys output 0 - if (sym == SDLK_BACKSPACE) { // backspace; k == 0x8 - char[] tail = v[pos..$]; - if (pos) --pos; - while (pos && (v[pos] & 0x80) && !(v[pos] & 0x40)) - --pos; - v = v[0..pos] ~ tail; - } else if (sym == SDLK_LEFT) { - if (pos) --pos; - while (pos && (v[pos] & 0x80) && !(v[pos] & 0x40)) - --pos; - } else if (sym == SDLK_RIGHT) { - if (pos < v.length) ++pos; - while (pos < v.length && (v[pos] & 0x80) && !(v[pos] & 0x40)) - ++pos; - } else if (sym == SDLK_HOME || sym == SDLK_UP) { - pos = 0; - } else if (sym == SDLK_END || sym == SDLK_DOWN) { - pos = v.length; - } else - debug logger.trace ("Symbol: {}", sym); - } - return v; - } - - size_t getEditIndex () { - size_t i = 0; - for (size_t p = 0; p < pos; ++p) - if (!(v[p] & 0x80) || v[p] & 0x40) - ++i; - return i; - } - - /// Gives all callbacks the modified value void endEdit () { foreach (cb; cngCb) cb(symb, v); } - char[] v; protected: - char[] symb; - size_t pos; // editing position; used by keyStroke + alias sv v; // don't need separate v and sv in this case void delegate (char[],char[])[] cngCb; } @@ -252,7 +258,7 @@ /** Create a content with _symbol name symbol. */ this (char[] symbol, int val = 0) { symb = symbol; - v = val; + assignNoCB (val); } /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ @@ -261,17 +267,13 @@ return this; } - /// Get the text. - char[] toString (uint i) { - return (i == 0) ? Int.toString (v) - : (i == 1) ? name_ - : (i == 2) ? desc_ - : null; + void assignNoCB (int val) { + v = val; + sv = Int.toString (v); } - void opAssign (int val) { - v = val; - foreach (cb; cngCb) + assignNoCB (val); + foreach (cb; cngCb) cb(symb, val); } int opCall () { @@ -279,9 +281,14 @@ } alias opCall opCast; - int v; + void endEdit () { + v = Int.toInt (sv); + foreach (cb; cngCb) + cb(symb, v); + } + protected: - char[] symb; + int v; void delegate (char[],int)[] cngCb; } @@ -291,7 +298,7 @@ /** Create a content with _symbol name symbol. */ this (char[] symbol, double val = 0) { symb = symbol; - v = val; + assignNoCB (val); } /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ @@ -300,17 +307,13 @@ return this; } - /// Get the text. - char[] toString (uint i) { - return (i == 0) ? Float.toString (v) - : (i == 1) ? name_ - : (i == 2) ? desc_ - : null; + void assignNoCB (double val) { + v = val; + sv = Float.toString (v); } - void opAssign (double val) { - v = val; - foreach (cb; cngCb) + assignNoCB (val); + foreach (cb; cngCb) cb(symb, val); } double opCall () { @@ -318,8 +321,13 @@ } alias opCall opCast; - double v; + void endEdit () { + v = Float.toFloat (sv); + foreach (cb; cngCb) + cb(symb, v); + } + protected: - char[] symb; + double v; void delegate (char[],double)[] cngCb; } diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/gui/widget/createWidget.d --- a/mde/gui/widget/createWidget.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/gui/widget/createWidget.d Sun Nov 16 17:03:47 2008 +0000 @@ -106,7 +106,7 @@ editContent = FUNCTION | TAKES_CONTENT | 0x30, DisplayContent = TAKES_CONTENT | 0x30, BoolContent = TAKES_CONTENT | 0x31, - TextContent = TAKES_CONTENT | 0x32, + ValueContent = TAKES_CONTENT | 0x32, GridLayout = TAKES_CONTENT | PARENT | 0x100, TrialContentLayout = PARENT | 0x110, @@ -126,7 +126,7 @@ "ContentLabel", "DisplayContent", "BoolContent", - "TextContent", + "ValueContent", "editContent", "TrialContentLayout", "FloatingArea", diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/gui/widget/miscContent.d --- a/mde/gui/widget/miscContent.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/gui/widget/miscContent.d Sun Nov 16 17:03:47 2008 +0000 @@ -28,8 +28,8 @@ IChildWidget editContent (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { if (cast(BoolContent) c) return new BoolContentWidget(mgr,id,data,c); - else if (cast(TextContent) c) - return new TextContentWidget(mgr,id,data,c); + else if (cast(ValueContent) c) + return new ValueContentWidget(mgr,id,data,c); else // generic uneditable option return new DisplayContentWidget(mgr,id,data,c); } diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/gui/widget/textContent.d --- a/mde/gui/widget/textContent.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/gui/widget/textContent.d Sun Nov 16 17:03:47 2008 +0000 @@ -31,14 +31,14 @@ } } - -class TextContentWidget : ATextWidget +/// Capable of editing any ValueContent class +class ValueContentWidget : ATextWidget { this (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { WDCheck(data, 1); - content = cast(TextContent) c; - if (!content) content = new TextContent (null, null); - //throw new ContentException (); + content = cast(ValueContent) c; + if (!content) //content = new TextContent (null, null); + throw new ContentException (); adapter = mgr.renderer.getAdapter (content.toString(0)); super (mgr, id, data); } @@ -63,5 +63,5 @@ } protected: - TextContent content; + ValueContent content; } diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/lookup/Options.d --- a/mde/lookup/Options.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/lookup/Options.d Sun Nov 16 17:03:47 2008 +0000 @@ -124,7 +124,7 @@ auto p = id in opts; if (p) { auto q = cast(`~VContentN!(T)~`) (*p); - if (q) q.v = parseTo!(`~T.stringof~`) (dt); + if (q) q.assignNoCB = parseTo!(`~T.stringof~`) (dt); } }`; } else diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/scheduler/Scheduler.d --- a/mde/scheduler/Scheduler.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/scheduler/Scheduler.d Sun Nov 16 17:03:47 2008 +0000 @@ -25,9 +25,9 @@ debug { import tango.util.log.Log : Log, Logger; private Logger logger; -} -static this() { - debug logger = Log.getLogger ("mde.scheduler.Scheduler"); + static this() { + logger = Log.getLogger ("mde.scheduler.Scheduler"); + } } /// This class can run scheduled functions per frame, per time interval and per request. diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/setup/Init.d --- a/mde/setup/Init.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/setup/Init.d Sun Nov 16 17:03:47 2008 +0000 @@ -119,6 +119,7 @@ paths.extraDataPath = args["data-path"]; if (args.contains("conf-path")) paths.extraConfPath = args["conf-path"]; + if (args.contains("base-path")) paths.resolvePaths (args["base-path"]); else diff -r 0ea4a3e651ae -r 71f0f1f83620 mde/setup/paths.d --- a/mde/setup/paths.d Sat Nov 15 17:39:14 2008 +0000 +++ b/mde/setup/paths.d Sun Nov 16 17:03:47 2008 +0000 @@ -39,8 +39,20 @@ import tango.io.Console; import tango.io.FilePath; -import tango.sys.Environment; -//import tango.scrapple.sys.win32.Registry; // Trouble getting this to work +version (linux) { + import tango.io.FileScan; + import tango.util.container.SortedMap; + import tango.sys.Environment; +} else version (Windows) + import tango.sys.win32.SpecialPath; + +debug { + import tango.util.log.Log : Log, Logger; + private Logger logger; + static this() { + logger = Log.getLogger ("mde.setup.paths"); + } +} /** Order to read files in. * @@ -111,7 +123,15 @@ dataDir.coutPaths; Cout ("\nConf paths found:"); confDir.coutPaths; - Cout ("\nLog file directory:\n\t")(logDir).newline; + Cout ("\nLog file directory:\n\t")(logDir); + version (Windows) { + Cout ("\nFont directory:\n\t")(fontDir).newline; + } else version (linux) { + Cout ("\nFont filse found:"); + foreach (f,p; fontFiles) + Cout ("\n\t")(f)("\t")(p[0..$-1]); + Cout.newline; + } } private: @@ -190,7 +210,7 @@ /** These are the actual instances, one for each of the data and conf "directories". */ mdeDirectory dataDir, confDir; -char[] logDir; +char[] logDir; /// Directory for log files //BEGIN Path resolution // These are used several times: @@ -202,15 +222,26 @@ * Note: the logger cannot be used yet, so only output is exception messages. */ // FIXME: use tango/sys/Environment.d version (linux) { + SortedMap!(char[],char[]) fontFiles; // key is file name, value is CString path + /** Get the actual path of a font file, or throw NoFileException if not found. + * + * Returns a C string (null terminated). */ + char[] getFontPath (char[] file) { + char[] ret; + if (fontFiles.get (file, ret)) + return ret; + throw new NoFileException ("Unable to find font file: "~file); + } + // base-path not used on posix - void resolvePaths (char[] = null) { + void resolvePaths (char[] base = "data") { // Home directory: char[] HOME = Environment.get("HOME", "."); // Base paths: // Static data (must exist): FilePath staticPath = - findPath (false, "/usr/share/games/mde", "/usr/local/share/games/mde", "data"); + findPath (false, "/usr/share/games/mde", "/usr/local/share/games/mde", base); // Config (can just use defaults if necessary, so long as we can save afterwards): FilePath userPath = findPath (true, HOME~"/.config/mde", HOME~"/.mde"); @@ -229,17 +260,37 @@ // Logging path: logDir = userPath.toString; + + // Font paths: + auto fs = new FileScan; + // Scan for directories containing truetype and type1 fonts: + fs.sweep ("/usr/share/fonts", (FilePath fp, bool isDir) + { return isDir || fp.suffix == ".ttf" || fp.suffix == ".pfb"; }, + true); + fontFiles = new SortedMap!(char[],char[]); + foreach (fp; fs.files) + fontFiles.add (fp.file, fp.cString); // both strings should be slices of same memory + logger.trace ("found {} font files, {} dirs", fs.files.length, fs.folders.length); } } else version (Windows) { + char[] fontDir; + /** Get the actual path of a font file, or throw NoFileException if not found. + * + * Returns a C string (null terminated). */ + char[] getFontPath (char[] file) { + FilePath path = new FilePath (fontDir~file); + if (path.exists && !path.isFolder) + return path.CString; + throw new NoFileException ("Unable to find font file: "~file); + } + void resolvePaths (char[] base = "./") { - //FIXME: Get path from registry - //FIXME: Get user path (Docs&Settings/USER/Local Settings/Application data/mde) - //http://www.dsource.org/projects/tango/forums/topic/187 + //FIXME: Get base path from registry // Base paths: FilePath installPath = findPath (false, base); - FilePath staticPath = findPath (false, installPath.append("data").toString); - FilePath userPath = findPath (true, installPath.append("user").toString); // FIXME: see above + FilePath staticPath = findPath (false, installPath.toString); + FilePath userPath = findPath (true, getSpecialPath(CSIDL_LOCAL_APPDATA) ~ "/mde"); // Static data paths: dataDir.addPath (staticPath.toString); // we know this is valid anyway @@ -256,6 +307,9 @@ // Logging path: logDir = userPath.toString; + + // Font path: + fontDir = getSpecialPath (CSIDL_FONTS) ~ "/"; // append separator } } else { static assert (false, "Platform is not linux or Windows: no support for paths on this platform yet!");