From c37eb75ef93560d702f2159d31b0c209f41a96fb Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 12:56:30 -0700 Subject: [PATCH 01/10] ignore vim's .swp files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a8c992ea..770a7ee0 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ bin *.obj *.~* *.*~ +.*.sw* From 71fd3086bd45e5c9394f88fe441ff410d32cdf7b Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 14:47:32 -0700 Subject: [PATCH 02/10] dlangui.core.stdaction module now uses immutable and static module initializer --- src/dlangui/core/stdaction.d | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/dlangui/core/stdaction.d b/src/dlangui/core/stdaction.d index 0cc005a7..3163890c 100644 --- a/src/dlangui/core/stdaction.d +++ b/src/dlangui/core/stdaction.d @@ -32,15 +32,27 @@ enum StandardAction : int { Save, } -__gshared const Action ACTION_OK = new Action(StandardAction.Ok, "ACTION_OK"c); -__gshared const Action ACTION_CANCEL = new Action(StandardAction.Cancel, "ACTION_CANCEL"c); -__gshared const Action ACTION_YES = new Action(StandardAction.Yes, "ACTION_YES"c); -__gshared const Action ACTION_NO = new Action(StandardAction.No, "ACTION_NO"c); -__gshared const Action ACTION_CLOSE = new Action(StandardAction.Close, "ACTION_CLOSE"c); -__gshared const Action ACTION_ABORT = new Action(StandardAction.Abort, "ACTION_ABORT"c); -__gshared const Action ACTION_RETRY = new Action(StandardAction.Retry, "ACTION_RETRY"c); -__gshared const Action ACTION_IGNORE = new Action(StandardAction.Ignore, "ACTION_IGNORE"c); -__gshared const Action ACTION_OPEN = new Action(StandardAction.Open, "ACTION_OPEN"c); -__gshared const Action ACTION_SAVE = new Action(StandardAction.Save, "ACTION_SAVE"c); - +immutable Action ACTION_OK; +immutable Action ACTION_CANCEL; +immutable Action ACTION_YES; +immutable Action ACTION_NO; +immutable Action ACTION_CLOSE; +immutable Action ACTION_ABORT; +immutable Action ACTION_RETRY; +immutable Action ACTION_IGNORE; +immutable Action ACTION_OPEN; +immutable Action ACTION_SAVE; +static this() +{ + ACTION_OK = cast(immutable(Action)) new Action(StandardAction.Ok, "ACTION_OK"c); + ACTION_CANCEL = cast(immutable(Action)) new Action(StandardAction.Cancel, "ACTION_CANCEL"c); + ACTION_YES = cast(immutable(Action)) new Action(StandardAction.Yes, "ACTION_YES"c); + ACTION_NO = cast(immutable(Action)) new Action(StandardAction.No, "ACTION_NO"c); + ACTION_CLOSE = cast(immutable(Action)) new Action(StandardAction.Close, "ACTION_CLOSE"c); + ACTION_ABORT = cast(immutable(Action)) new Action(StandardAction.Abort, "ACTION_ABORT"c); + ACTION_RETRY = cast(immutable(Action)) new Action(StandardAction.Retry, "ACTION_RETRY"c); + ACTION_IGNORE = cast(immutable(Action)) new Action(StandardAction.Ignore, "ACTION_IGNORE"c); + ACTION_OPEN = cast(immutable(Action)) new Action(StandardAction.Open, "ACTION_OPEN"c); + ACTION_SAVE = cast(immutable(Action)) new Action(StandardAction.Save, "ACTION_SAVE"c); +} From dbe7671cf2d560f5667461d98ce499d975c52932 Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 16:24:47 -0700 Subject: [PATCH 03/10] synchronized dlangui.core.logger.Logger; also refactored it a little bit --- src/dlangui/core/logger.d | 122 +++++++++++++------------ src/dlangui/platforms/sdl/sdlapp.d | 6 +- src/dlangui/platforms/windows/winapp.d | 4 +- src/dlangui/platforms/x11/x11app.d | 2 +- 4 files changed, 68 insertions(+), 66 deletions(-) diff --git a/src/dlangui/core/logger.d b/src/dlangui/core/logger.d index 9cd91ea1..465ee95b 100644 --- a/src/dlangui/core/logger.d +++ b/src/dlangui/core/logger.d @@ -39,71 +39,73 @@ enum LogLevel : int { Trace } -__gshared LogLevel logLevel = LogLevel.Info; -__gshared std.stdio.File logFile; - -void setLogLevel(LogLevel level) { - logLevel = level; -} - long currentTimeMillis() { return std.datetime.Clock.currStdTime / 10000; } -void setStdoutLogger() { - logFile = stdout; -} +synchronized class Log { + static { + private LogLevel logLevel = LogLevel.Info; + private std.stdio.File logFile; + + void setStdoutLogger() { + logFile = stdout; + } -void setStderrLogger() { - logFile = stderr; -} + void setStderrLogger() { + logFile = stderr; + } -void setFileLogger(File file) { - logFile = file; -} + void setFileLogger(File file) { + logFile = file; + } -class Log { - static string logLevelName(LogLevel level) { - switch (level) { - case LogLevel.Fatal: return "F"; - case LogLevel.Error: return "E"; - case LogLevel.Warn: return "W"; - case LogLevel.Info: return "I"; - case LogLevel.Debug: return "D"; - case LogLevel.Trace: return "V"; - default: return "?"; - } - } - static void log(S...)(LogLevel level, S args) { - if (logLevel >= level && logFile.isOpen) { - SysTime ts = Clock.currTime(); - logFile.writef("%04d-%02d-%02d %02d:%02d:%02d.%03d %s ", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fracSec.msecs, logLevelName(level)); - logFile.writeln(args); - logFile.flush(); - } - } - static void v(S...)(S args) { - if (logLevel >= LogLevel.Trace && logFile.isOpen) - log(LogLevel.Trace, args); - } - static void d(S...)(S args) { - if (logLevel >= LogLevel.Debug && logFile.isOpen) - log(LogLevel.Debug, args); - } - static void i(S...)(S args) { - if (logLevel >= LogLevel.Info && logFile.isOpen) - log(LogLevel.Info, args); - } - static void w(S...)(S args) { - if (logLevel >= LogLevel.Warn && logFile.isOpen) - log(LogLevel.Warn, args); - } - static void e(S...)(S args) { - if (logLevel >= LogLevel.Error && logFile.isOpen) - log(LogLevel.Error, args); - } - static void f(S...)(S args) { - if (logLevel >= LogLevel.Fatal && logFile.isOpen) - log(LogLevel.Fatal, args); - } + void setLogLevel(LogLevel level) { + logLevel = level; + } + + string logLevelName(LogLevel level) { + switch (level) { + case LogLevel.Fatal: return "F"; + case LogLevel.Error: return "E"; + case LogLevel.Warn: return "W"; + case LogLevel.Info: return "I"; + case LogLevel.Debug: return "D"; + case LogLevel.Trace: return "V"; + default: return "?"; + } + } + void log(S...)(LogLevel level, S args) { + if (logLevel >= level && logFile.isOpen) { + SysTime ts = Clock.currTime(); + logFile.writef("%04d-%02d-%02d %02d:%02d:%02d.%03d %s ", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fracSec.msecs, logLevelName(level)); + logFile.writeln(args); + logFile.flush(); + } + } + void v(S...)(S args) { + if (logLevel >= LogLevel.Trace && logFile.isOpen) + log(LogLevel.Trace, args); + } + void d(S...)(S args) { + if (logLevel >= LogLevel.Debug && logFile.isOpen) + log(LogLevel.Debug, args); + } + void i(S...)(S args) { + if (logLevel >= LogLevel.Info && logFile.isOpen) + log(LogLevel.Info, args); + } + void w(S...)(S args) { + if (logLevel >= LogLevel.Warn && logFile.isOpen) + log(LogLevel.Warn, args); + } + void e(S...)(S args) { + if (logLevel >= LogLevel.Error && logFile.isOpen) + log(LogLevel.Error, args); + } + void f(S...)(S args) { + if (logLevel >= LogLevel.Fatal && logFile.isOpen) + log(LogLevel.Fatal, args); + } + } } diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index 729e13a0..1c8fe90e 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -984,7 +984,7 @@ version(USE_SDL) { int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { setFileLogger(std.stdio.File("ui.log", "w")); - setLogLevel(LogLevel.Trace); + Log.setLogLevel(LogLevel.Trace); Log.d("myWinMain()"); string basePath = exePath(); Log.i("Current executable: ", exePath()); @@ -1006,8 +1006,8 @@ version(USE_SDL) { int main(string[] args) { - setStderrLogger(); - setLogLevel(LogLevel.Trace); + Log.setStderrLogger(); + Log.setLogLevel(LogLevel.Warn); FreeTypeFontManager ft = new FreeTypeFontManager(); diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index 46e33eb6..42c931e0 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -721,9 +721,9 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int { setFileLogger(std.stdio.File("ui.log", "w")); debug { - setLogLevel(LogLevel.Trace); + Log.setLogLevel(LogLevel.Trace); } else { - setLogLevel(LogLevel.Info); + Log.setLogLevel(LogLevel.Info); } Log.d("myWinMain()"); string basePath = exePath(); diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d index 8946d80b..996f0910 100644 --- a/src/dlangui/platforms/x11/x11app.d +++ b/src/dlangui/platforms/x11/x11app.d @@ -1131,7 +1131,7 @@ version(USE_XCB) { { setStderrLogger(); - setLogLevel(LogLevel.Trace); + Log.setLogLevel(LogLevel.Trace); FreeTypeFontManager ft = new FreeTypeFontManager(); ft.registerFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FontFamily.SansSerif, "DejaVu", false, FontWeight.Normal); From 78a5e49d07df6ab50cfc9379bd44c1684404fcf9 Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 16:29:32 -0700 Subject: [PATCH 04/10] SDLPlatform now enables OpenGL context sharing (important for multi-window) --- src/dlangui/platforms/sdl/sdlapp.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index 1c8fe90e..721ac703 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -1054,6 +1054,8 @@ version(USE_SDL) { // Set OpenGL attributes SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + // Share textures between contexts + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); } SDLPlatform sdl = new SDLPlatform(); From 198f685665c9af47f8ef6e5d1d01ddb6b9c2905c Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 18:37:55 -0700 Subject: [PATCH 05/10] loadImage() errors are now logged --- src/dlangui/graphics/images.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dlangui/graphics/images.d b/src/dlangui/graphics/images.d index 3af09351..9f9b10dc 100644 --- a/src/dlangui/graphics/images.d +++ b/src/dlangui/graphics/images.d @@ -26,6 +26,7 @@ import dlangui.core.logger; import dlangui.core.types; import dlangui.graphics.drawbuf; import std.stream; +import std.conv : to; /// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed ColorDrawBuf loadImage(string filename) { @@ -36,6 +37,7 @@ ColorDrawBuf loadImage(string filename) { return loadImage(f); } catch (Exception e) { Log.e("exception while loading image from file ", filename); + Log.e(to!string(e)); return null; } } From 4fa76dc40eeab1933bfc774713cd5cfa73720b17 Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Wed, 13 Aug 2014 19:02:54 -0700 Subject: [PATCH 06/10] dlangui.graphics.glsupport module now draws with VBOs and VAOs --- src/dlangui/graphics/glsupport.d | 103 +++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 11 deletions(-) diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index 91d60043..4023aa51 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -39,12 +39,28 @@ private void LVGLFillColor(uint color, float * buf, int count) { } } -/// for OpenGL calls diagnostics. -private bool checkError(string context, string file = __FILE__, int line = __LINE__) { - int err = glGetError(); - if (err != GL_NO_ERROR) { - //string errorString = fromStringz(gluErrorString()); - Log.e("OpenGL error ", err, " at ", file, ":", line, " -- ", context); +/* For reporting OpenGL errors, it's nicer to get a human-readable symbolic name for the + * error instead of the numeric form. Derelict's GLenum is just an alias for uint, so we + * can't depend on D's nice toString() for enums. + */ +private immutable(string[int]) errors; +static this() { + errors = [ + 0x0500: "GL_INVALID_ENUM", + 0x0501: "GL_INVALID_VALUE", + 0x0502: "GL_INVALID_OPERATION", + 0x0505: "GL_OUT_OF_MEMORY" + ]; +} +/* Convenient wrapper around glGetError() + * TODO use one of the DEBUG extensions instead + */ +bool checkError(string context="", string file=__FILE__, int line=__LINE__) +{ + GLenum err = glGetError(); + if (err != GL_NO_ERROR) + { + Log.e("OpenGL error ", err in errors ? errors[err] : to!string(err), " at ", file, ":", line, " -- ", context); return true; } return false; @@ -526,14 +542,36 @@ class SolidFillProgram : GLProgram { return false; beforeExecute(); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof, + null, + GL_STREAM_DRAW); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + vertices.length * vertices[0].sizeof, + vertices.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof, + colors.length * colors[0].sizeof, colors.ptr); + glEnableVertexAttribArray(vertexLocation); checkError("glEnableVertexAttribArray"); - glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, float.sizeof * 3, vertices.ptr); + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0); checkError("glVertexAttribPointer"); glEnableVertexAttribArray(colAttrLocation); checkError("glEnableVertexAttribArray"); - glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, float.sizeof * 4, colors.ptr); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*6)); checkError("glVertexAttribPointer"); glDrawArrays(GL_TRIANGLES, 0, 6); @@ -545,6 +583,12 @@ class SolidFillProgram : GLProgram { checkError("glDisableVertexAttribArray"); afterExecute(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vbo); + + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); return true; } } @@ -600,13 +644,43 @@ class TextureProgram : SolidFillProgram { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR : GL_NEAREST); checkError("drawColorAndTextureRect - glTexParameteri"); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + + colors.length * colors[0].sizeof + + texcoords.length * texcoords[0].sizeof, + null, + GL_STREAM_DRAW); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + vertices.length * vertices[0].sizeof, + vertices.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof, + colors.length * colors[0].sizeof, + colors.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof, + texcoords.length * texcoords[0].sizeof, + texcoords.ptr); + glEnableVertexAttribArray(vertexLocation); glEnableVertexAttribArray(colAttrLocation); glEnableVertexAttribArray(texCoordLocation); - glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices.ptr); - glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, colors.ptr); - glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords.ptr); + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof)); + glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof)); glDrawArrays(GL_TRIANGLES, 0, 6); checkError("glDrawArrays"); @@ -616,6 +690,13 @@ class TextureProgram : SolidFillProgram { glDisableVertexAttribArray(texCoordLocation); afterExecute(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vbo); + + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); + glBindTexture(GL_TEXTURE_2D, 0); checkError("glBindTexture"); return true; From 09953b2057e6affe0f79b18f75fb91ab85fee26c Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Thu, 14 Aug 2014 05:13:37 -0700 Subject: [PATCH 07/10] dos2unix'd i18n module; the file had inconsistent line-endings! --- src/dlangui/core/i18n.d | 326 ++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 163 deletions(-) diff --git a/src/dlangui/core/i18n.d b/src/dlangui/core/i18n.d index 79fa11a6..7563f256 100644 --- a/src/dlangui/core/i18n.d +++ b/src/dlangui/core/i18n.d @@ -36,156 +36,156 @@ Copyright: Vadim Lopatin, 2014 License: Boost License 1.0 Authors: Vadim Lopatin, coolreader.org@gmail.com */ -module dlangui.core.i18n; - -import dlangui.core.types; -import dlangui.core.logger; -import std.utf; - -/// container for UI string - either raw value or string resource ID -struct UIString { - /// if not null, use it, otherwise lookup by id - private dstring _value; - /// id to find value in translator - private string _id; - - /// create string with i18n resource id - this(string id) { - _id = id; - } - /// create string with raw value - this(dstring value) { - _value = value; - } - - - - @property string id() const { return _id; } - @property void id(string ID) { - _id = ID; - _value = null; - } - /// get value (either raw or translated by id) - @property dstring value() const { - if (_value !is null) - return _value; - if (_id is null) - return null; - // translate ID to dstring - return i18n.get(_id); - } - /// set raw value - @property void value(dstring newValue) { - _value = newValue; - } - /// assign raw value - ref UIString opAssign(dstring rawValue) { - _value = rawValue; - _id = null; - return this; - } - /// assign ID - ref UIString opAssign(string ID) { - _id = ID; - _value = null; - return this; - } - /// default conversion to dstring - alias value this; -} - -public __gshared UIStringTranslator i18n = new UIStringTranslator(); -//static shared this() { -// i18n = new UIStringTranslator(); -//} - -class UIStringTranslator { - private UIStringList _main; - private UIStringList _fallback; - private string[] _resourceDirs; - /// get i18n resource directory - @property string[] resourceDirs() { return _resourceDirs; } - /// set i18n resource directory - @property void resourceDirs(string[] dirs) { _resourceDirs = dirs; } - /// looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from - string[] findTranslationsDir(string[] dirs ...) { - _resourceDirs.length = 0; - import std.file; - foreach(dir; dirs) { - string path = appendPath(dir, "i18n/"); +module dlangui.core.i18n; + +import dlangui.core.types; +import dlangui.core.logger; +import std.utf; + +/// container for UI string - either raw value or string resource ID +struct UIString { + /// if not null, use it, otherwise lookup by id + private dstring _value; + /// id to find value in translator + private string _id; + + /// create string with i18n resource id + this(string id) { + _id = id; + } + /// create string with raw value + this(dstring value) { + _value = value; + } + + + + @property string id() const { return _id; } + @property void id(string ID) { + _id = ID; + _value = null; + } + /// get value (either raw or translated by id) + @property dstring value() const { + if (_value !is null) + return _value; + if (_id is null) + return null; + // translate ID to dstring + return i18n.get(_id); + } + /// set raw value + @property void value(dstring newValue) { + _value = newValue; + } + /// assign raw value + ref UIString opAssign(dstring rawValue) { + _value = rawValue; + _id = null; + return this; + } + /// assign ID + ref UIString opAssign(string ID) { + _id = ID; + _value = null; + return this; + } + /// default conversion to dstring + alias value this; +} + +public __gshared UIStringTranslator i18n = new UIStringTranslator(); +//static shared this() { +// i18n = new UIStringTranslator(); +//} + +class UIStringTranslator { + private UIStringList _main; + private UIStringList _fallback; + private string[] _resourceDirs; + /// get i18n resource directory + @property string[] resourceDirs() { return _resourceDirs; } + /// set i18n resource directory + @property void resourceDirs(string[] dirs) { _resourceDirs = dirs; } + /// looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from + string[] findTranslationsDir(string[] dirs ...) { + _resourceDirs.length = 0; + import std.file; + foreach(dir; dirs) { + string path = appendPath(dir, "i18n/"); if (exists(path) && isDir(path)) { - Log.i("Adding i18n dir ", path); - _resourceDirs ~= path; - } - } - return _resourceDirs; - } - - /// convert resource path - append resource dir if necessary - string[] convertResourcePaths(string filename) { - if (filename is null) - return null; - bool hasPathDelimiters = false; - foreach(char ch; filename) - if (ch == '/' || ch == '\\') - hasPathDelimiters = true; - string[] res; - if (!hasPathDelimiters && _resourceDirs.length) { - foreach (dir; _resourceDirs) - res ~= dir ~ filename; - } else { - res ~= filename; - } - return res; - } - - this() { - _main = new UIStringList(); - _fallback = new UIStringList(); - } - /// load translation file(s) - bool load(string mainFilename, string fallbackFilename = null) { - _main.clear(); - _fallback.clear(); - bool res = _main.load(convertResourcePaths(mainFilename)); - if (fallbackFilename !is null) { - res = _fallback.load(convertResourcePaths(fallbackFilename)) || res; - } - return res; - } - /// translate string ID to string (returns "UNTRANSLATED: id" for missing values) - dstring get(string id) { - if (id is null) - return null; - dstring s = _main.get(id); - if (s !is null) - return s; - s = _fallback.get(id); - if (s !is null) - return s; - return "UNTRANSLATED: "d ~ toUTF32(id); - } -} - -/// UI string translator -class UIStringList { - private dstring[string] _map; - /// remove all items - void clear() { - _map.clear(); - } - /// set item value - void set(string id, dstring value) { - _map[id] = value; - } - /// get item value, null if translation is not found for id - dstring get(string id) const { - if (id in _map) - return _map[id]; - return null; - } - /// load strings from stream - bool load(std.stream.InputStream stream) { + Log.i("Adding i18n dir ", path); + _resourceDirs ~= path; + } + } + return _resourceDirs; + } + + /// convert resource path - append resource dir if necessary + string[] convertResourcePaths(string filename) { + if (filename is null) + return null; + bool hasPathDelimiters = false; + foreach(char ch; filename) + if (ch == '/' || ch == '\\') + hasPathDelimiters = true; + string[] res; + if (!hasPathDelimiters && _resourceDirs.length) { + foreach (dir; _resourceDirs) + res ~= dir ~ filename; + } else { + res ~= filename; + } + return res; + } + + this() { + _main = new UIStringList(); + _fallback = new UIStringList(); + } + /// load translation file(s) + bool load(string mainFilename, string fallbackFilename = null) { + _main.clear(); + _fallback.clear(); + bool res = _main.load(convertResourcePaths(mainFilename)); + if (fallbackFilename !is null) { + res = _fallback.load(convertResourcePaths(fallbackFilename)) || res; + } + return res; + } + /// translate string ID to string (returns "UNTRANSLATED: id" for missing values) + dstring get(string id) { + if (id is null) + return null; + dstring s = _main.get(id); + if (s !is null) + return s; + s = _fallback.get(id); + if (s !is null) + return s; + return "UNTRANSLATED: "d ~ toUTF32(id); + } +} + +/// UI string translator +class UIStringList { + private dstring[string] _map; + /// remove all items + void clear() { + _map.clear(); + } + /// set item value + void set(string id, dstring value) { + _map[id] = value; + } + /// get item value, null if translation is not found for id + dstring get(string id) const { + if (id in _map) + return _map[id]; + return null; + } + /// load strings from stream + bool load(std.stream.InputStream stream) { dlangui.core.linestream.LineStream lines = dlangui.core.linestream.LineStream.create(stream, ""); int count = 0; for (;;) { @@ -212,21 +212,21 @@ class UIStringList { } } return count > 0; - } - - /// load strings from file (utf8, id=value lines) - bool load(string[] filenames) { + } + + /// load strings from file (utf8, id=value lines) + bool load(string[] filenames) { clear(); - bool res = false; - foreach(filename; filenames) { - import std.stream; + bool res = false; + foreach(filename; filenames) { + import std.stream; import std.file; - try { - debug Log.d("Loading string resources from file ", filename); - if (!exists(filename) || !isFile(filename)) { + try { + debug Log.d("Loading string resources from file ", filename); + if (!exists(filename) || !isFile(filename)) { Log.e("File does not exist: ", filename); - continue; - } + continue; + } std.stream.File f = new std.stream.File(filename); scope(exit) { f.close(); } res = load(f) || res; @@ -235,5 +235,5 @@ class UIStringList { } } return res; - } -} + } +} From 9f4b8e47eb4d1097eebd29c7d9a4449fcbce2503 Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Thu, 14 Aug 2014 05:18:06 -0700 Subject: [PATCH 08/10] addressed some synchronization issues in i18n to fix a crash with GDC 4.9.0; removed some minor unused features --- src/dlangui/core/i18n.d | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/dlangui/core/i18n.d b/src/dlangui/core/i18n.d index 7563f256..809f9097 100644 --- a/src/dlangui/core/i18n.d +++ b/src/dlangui/core/i18n.d @@ -94,21 +94,17 @@ struct UIString { alias value this; } -public __gshared UIStringTranslator i18n = new UIStringTranslator(); -//static shared this() { -// i18n = new UIStringTranslator(); -//} +shared UIStringTranslator i18n; +shared static this() { + i18n = new shared UIStringTranslator(); +} -class UIStringTranslator { +synchronized class UIStringTranslator { private UIStringList _main; private UIStringList _fallback; private string[] _resourceDirs; - /// get i18n resource directory - @property string[] resourceDirs() { return _resourceDirs; } - /// set i18n resource directory - @property void resourceDirs(string[] dirs) { _resourceDirs = dirs; } /// looks for i18n directory inside one of passed dirs, and uses first found as directory to read i18n files from - string[] findTranslationsDir(string[] dirs ...) { + void findTranslationsDir(string[] dirs ...) { _resourceDirs.length = 0; import std.file; foreach(dir; dirs) { @@ -118,7 +114,6 @@ class UIStringTranslator { _resourceDirs ~= path; } } - return _resourceDirs; } /// convert resource path - append resource dir if necessary @@ -140,8 +135,8 @@ class UIStringTranslator { } this() { - _main = new UIStringList(); - _fallback = new UIStringList(); + _main = new shared UIStringList(); + _fallback = new shared UIStringList(); } /// load translation file(s) bool load(string mainFilename, string fallbackFilename = null) { @@ -168,7 +163,7 @@ class UIStringTranslator { } /// UI string translator -class UIStringList { +private shared class UIStringList { private dstring[string] _map; /// remove all items void clear() { From 1b11e24f051362e27aab09745b7004bc415a650f Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Sun, 17 Aug 2014 19:35:33 -0700 Subject: [PATCH 09/10] MenuWidgetBase: onMenuItem() now destroys popup *after* handleMenuItemClick() to help prevent MenuItem "item" from being invalidated prematurely --- src/dlangui/widgets/menu.d | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dlangui/widgets/menu.d b/src/dlangui/widgets/menu.d index 02526269..29def03b 100644 --- a/src/dlangui/widgets/menu.d +++ b/src/dlangui/widgets/menu.d @@ -527,13 +527,12 @@ class MenuWidgetBase : ListWidget { // copy item action listeners Signal!MenuItemActionHandler onMenuItemActionListenerCopy = onMenuItemActionListener; + handleMenuItemClick(item); + PopupWidget popup = cast(PopupWidget)parent; if (popup) popup.close(); - handleMenuItemClick(item); - - // this pointer now can be invalid - if popup removed if (onMenuItemClickListenerCopy.assigned) if (onMenuItemClickListenerCopy(item)) From 5ef2a719f3b231ffdaaa92fdfaff2f6199f53756 Mon Sep 17 00:00:00 2001 From: Donny Viszneki Date: Mon, 18 Aug 2014 23:20:00 -0700 Subject: [PATCH 10/10] StringGridWidget bugfix: cell backgrounds now clip inside the grid's client area --- src/dlangui/widgets/grid.d | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index 02eea97e..c0387fcc 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -946,14 +946,14 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler { bool isHeader = x < _headerCols || y < _headerRows; if (phase == 0) { if (isHeader) - drawHeaderCellBackground(buf, cellRect, x - _headerCols, y - _headerRows); + drawHeaderCellBackground(buf, buf.clipRect, x - _headerCols, y - _headerRows); else - drawCellBackground(buf, cellRect, x - _headerCols, y - _headerRows); + drawCellBackground(buf, buf.clipRect, x - _headerCols, y - _headerRows); } else { if (isHeader) - drawHeaderCell(buf, cellRect, x - _headerCols, y - _headerRows); + drawHeaderCell(buf, buf.clipRect, x - _headerCols, y - _headerRows); else - drawCell(buf, cellRect, x - _headerCols, y - _headerRows); + drawCell(buf, buf.clipRect, x - _headerCols, y - _headerRows); } } }