diff --git a/examples/example1/example1.visualdproj b/examples/example1/example1.visualdproj index 6a6bd692..bfd6808a 100644 --- a/examples/example1/example1.visualdproj +++ b/examples/example1/example1.visualdproj @@ -47,7 +47,7 @@ 0 0 $(DMDInstallDir)windows\bin\dmd.exe - ../../src ../../3rdparty + $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/3rdparty/libpng/source $(ConfigurationName) $(OutDir) @@ -84,7 +84,7 @@ phobos.lib ole32.lib kernel32.lib user32.lib comctl32.lib comdlg32.lib dlangui.lib - ../../Debug ../../3rdparty/win32/lib + ../../Debug ../../3rdparty/libpng/lib $(OutDir)\$(ProjectName).exe diff --git a/examples/example1/res/exit.png b/examples/example1/res/exit.png new file mode 100644 index 00000000..74458879 Binary files /dev/null and b/examples/example1/res/exit.png differ diff --git a/examples/example1/res/fileclose.png b/examples/example1/res/fileclose.png new file mode 100644 index 00000000..8acc84d1 Binary files /dev/null and b/examples/example1/res/fileclose.png differ diff --git a/examples/example1/res/fileopen.png b/examples/example1/res/fileopen.png new file mode 100644 index 00000000..503a0045 Binary files /dev/null and b/examples/example1/res/fileopen.png differ diff --git a/examples/example1/winmain.d b/examples/example1/winmain.d index c9d8a504..498213ee 100644 --- a/examples/example1/winmain.d +++ b/examples/example1/winmain.d @@ -1,7 +1,7 @@ module winmain; -pragma(lib, "dlangui.lib"); import dlangui.platforms.common.platform; +import dlangui.graphics.images; import dlangui.widgets.widget; import dlangui.core.logger; import dlangui.graphics.fonts; @@ -20,6 +20,9 @@ version(Windows) { } } +ImageCache imageCache; +string resourceDir; + class TestWidget : Widget { public override void onDraw(DrawBuf buf) { super.onDraw(buf); @@ -34,10 +37,20 @@ class TestWidget : Widget { Log.d("Got font, drawing text"); font.drawText(buf, _pos.left + 5, _pos.top + 5, "Text"d, 0x0000FF); Log.d("Text is drawn successfully"); + DrawBufRef img = imageCache.get(resourceDir ~ "exit.png"); + if (!img.isNull) { + Log.d("loaded image ", img.width, "x", img.height); + buf.drawImage(200, 200, img); + buf.drawImage(250, 250, img); + } } } -extern (C) int UIAppMain() { +extern (C) int UIAppMain(string[] args) { + + imageCache = new ImageCache(); + resourceDir = exePath() ~ "..\\res\\"; + Log.d("Some debug message"); Log.e("Sample error #", 22); diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index 93447554..ce7d7808 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -10,22 +10,22 @@ public struct Point { } public struct Rect { - public int left; - public int top; - public int right; - public int bottom; - public @property int width() { return right - left; } - public @property int height() { return bottom - top; } - public this(int x0, int y0, int x1, int y1) { + int left; + int top; + int right; + int bottom; + @property int width() { return right - left; } + @property int height() { return bottom - top; } + this(int x0, int y0, int x1, int y1) { left = x0; top = y0; right = x1; bottom = y1; } - public bool empty() { + @property bool empty() { return right <= left || bottom <= top; } - public bool intersect(Rect rc) { + bool intersect(Rect rc) { if (left < rc.left) left = rc.left; if (top < rc.top) @@ -109,3 +109,27 @@ public struct Ref(T) { // if (T is RefCountedObject) _data.releaseRef(); } } + + +// some utility functions +string fromStringz(const(char[]) s) { + int i = 0; + while(s[i]) + i++; + return cast(string)(s[0..i].dup); +} + +string fromStringz(const(char*) s) { + int i = 0; + while(s[i]) + i++; + return cast(string)(s[0..i].dup); +} + +wstring fromWStringz(const(wchar[]) s) { + int i = 0; + while(s[i]) + i++; + return cast(wstring)(s[0..i].dup); +} + diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index cd70b355..6bb4a94f 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -29,7 +29,7 @@ class DrawBuf : RefCountedObject { _clipRect = rect; _clipRect.intersect(Rect(0, 0, width, height)); } - protected bool applyClipping(ref Rect rc) { + bool applyClipping(ref Rect rc) { if (!_clipRect.empty()) rc.intersect(_clipRect); if (rc.left < 0) @@ -42,6 +42,43 @@ class DrawBuf : RefCountedObject { rc.bottom = height; return !rc.empty(); } + bool applyClipping(ref Rect rc, ref Rect rc2) { + if (!_clipRect.empty()) { + if (rc.left < _clipRect.left) { + rc2.left += _clipRect.left - rc.left; + rc.left = _clipRect.left; + } + if (rc.top < _clipRect.top) { + rc2.top += _clipRect.top - rc.top; + rc.top = _clipRect.top; + } + if (rc.right > _clipRect.left) { + rc2.right -= rc.right - _clipRect.left; + rc.right = _clipRect.right; + } + if (rc.bottom > _clipRect.bottom) { + rc2.bottom -= rc.bottom - _clipRect.bottom; + rc.bottom = _clipRect.bottom; + } + } + if (rc.left < 0) { + rc2.left += -rc.left; + rc.left = 0; + } + if (rc.top < 0) { + rc2.top += -rc.top; + rc.top = 0; + } + if (rc.right > width) { + rc2.right -= rc.right - width; + rc.right = width; + } + if (rc.bottom > height) { + rc2.bottom -= rc.bottom - height; + rc.bottom = height; + } + return !rc.empty() && !rc2.empty(); + } void beforeDrawing() { } void afterDrawing() { } /// returns buffer bits per pixel @@ -55,6 +92,12 @@ class DrawBuf : RefCountedObject { } abstract void fillRect(Rect rc, uint color); abstract void drawGlyph(int x, int y, ubyte[] src, int srcdx, int srcdy, uint color); + /// draw source buffer rectangle contents to destination buffer + abstract void drawFragment(int x, int y, DrawBuf src, Rect srcrect); + /// draw whole unscaled image at specified coordinates + void drawImage(int x, int y, DrawBuf src) { + drawFragment(x, y, src, Rect(0, 0, src.width, src.height)); + } void clear() {} ~this() { clear(); } } @@ -68,6 +111,31 @@ class ColorDrawBufBase : DrawBuf { override @property int bpp() { return 32; } @property override int width() { return _dx; } @property override int height() { return _dy; } + /// draw source buffer rectangle contents to destination buffer + override void drawFragment(int x, int y, DrawBuf src, Rect srcrect) { + Rect dstrect = Rect(x, y, x + srcrect.width, y + srcrect.height); + if (applyClipping(dstrect, srcrect)) { + if (src.applyClipping(srcrect, dstrect)) { + int dx = srcrect.width; + int dy = srcrect.height; + for (int yy = 0; yy < dy; yy++) { + uint * srcrow = src.scanLine(srcrect.top + yy) + srcrect.left; + uint * dstrow = scanLine(dstrect.top + yy) + dstrect.left; + for (int i = 0; i < dx; i++) { + uint pixel = srcrow[i]; + uint alpha = pixel >> 24; + if (!alpha) + dstrow[i] = pixel; + else if (alpha < 255) { + // apply blending + dstrow[i] = blendARGB(dstrow[i], pixel, alpha); + } + } + + } + } + } + } override void fillRect(int left, int top, int right, int bottom, uint color) { fillRect(Rect(left, top, right, bottom), color); } diff --git a/src/dlangui/graphics/images.d b/src/dlangui/graphics/images.d index c4c2e6ca..9e745dae 100644 --- a/src/dlangui/graphics/images.d +++ b/src/dlangui/graphics/images.d @@ -1,5 +1,6 @@ module dlangui.graphics.images; +import dlangui.core.logger; import dlangui.graphics.drawbuf; import std.stream; import libpng.png; @@ -66,6 +67,7 @@ class ImageCache { /// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed ColorDrawBuf loadImage(string filename) { + Log.d("Loading image from file " ~ filename); try { std.stream.File f = new std.stream.File(filename); scope(exit) { f.close(); } @@ -89,13 +91,19 @@ class ImageDecodingException : Exception { } } -extern (C) void lvpng_error_func (png_structp png, png_const_charp) +extern (C) void lvpng_error_func (png_structp png, png_const_charp msg) { + string s = fromStringz(msg); + Log.d("Error while reading PNG image: ", s); + // todo: exceptions do not work inside C function throw new ImageDecodingException("Error while decoding PNG image"); } -extern (C) void lvpng_warning_func (png_structp png, png_const_charp) +extern (C) void lvpng_warning_func (png_structp png, png_const_charp msg) { + string s = fromStringz(msg); + Log.d("Warn while reading PNG image: ", s); + // todo: exceptions do not work inside C function throw new ImageDecodingException("Error while decoding PNG image"); } @@ -105,6 +113,8 @@ extern (C) void lvpng_read_func(png_structp png, png_bytep buf, png_size_t len) ubyte[] localbuf = new ubyte[len]; if (stream.read(localbuf) != len) throw new ImageDecodingException("Error while reading PNG image"); + for (uint i = 0; i < len; i++) + buf[i] = localbuf[i]; } /// load and decode PNG image diff --git a/src/dlangui/platforms/windows/win32fonts.d b/src/dlangui/platforms/windows/win32fonts.d index 944e7250..cbf68667 100644 --- a/src/dlangui/platforms/windows/win32fonts.d +++ b/src/dlangui/platforms/windows/win32fonts.d @@ -1,18 +1,18 @@ -module dlangui.platforms.windows.win32fonts; - +module dlangui.platforms.windows.win32fonts; + version (Windows) { - + import win32.windows; import dlangui.graphics.fonts; import dlangui.platforms.windows.win32drawbuf; import std.string; import std.utf; - + //auto toUTF16z(S)(S s) //{ //return toUTFz!(const(wchar)*)(s); //} - + struct FontDef { immutable FontFamily _family; immutable string _face; @@ -429,13 +429,6 @@ class Win32FontManager : FontManager { } } -string fromStringz(const(char[]) s) { - int i = 0; - while(s[i]) - i++; - return cast(string)(s[0..i].dup); -} - FontFamily pitchAndFamilyToFontFamily(ubyte flags) { if ((flags & FF_DECORATIVE) == FF_DECORATIVE) return FontFamily.Fantasy; diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index fc6dbc81..673cb2b4 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -8,6 +8,7 @@ import std.string; import std.utf; import std.stdio; import std.algorithm; +import std.file; import dlangui.platforms.common.platform; import dlangui.platforms.windows.win32fonts; import dlangui.platforms.windows.win32drawbuf; @@ -19,7 +20,7 @@ pragma(lib, "gdi32.lib"); pragma(lib, "user32.lib"); pragma(lib, "libpng15.lib"); -extern (C) int UIAppMain(); +extern (C) int UIAppMain(string[] args); immutable WIN_CLASS_NAME = "DLANGUI_APP"; @@ -112,20 +113,26 @@ class Win32Platform : Platform { } } +/// returns current executable path only, including last path delimiter +string exePath() { + string path = thisExePath(); + int lastSlash = 0; + for (int i = 0; i < path.length; i++) + if (path[i] == '\\') + lastSlash = i; + return path[0 .. lastSlash + 1]; +} + extern(Windows) int DLANGUIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int result; - void exceptionHandler(Throwable e) { - throw e; - } - try { - Runtime.initialize(&exceptionHandler); + Runtime.initialize(); result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - Runtime.terminate(&exceptionHandler); + Runtime.terminate(); } catch (Throwable e) // catch any uncaught exceptions { @@ -137,11 +144,45 @@ int DLANGUIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, return result; } +string[] splitCmdLine(string line) { + string[] res; + int start = 0; + bool insideQuotes = false; + for (int i = 0; i <= line.length; i++) { + char ch = i < line.length ? line[i] : 0; + if (ch == '\"') { + if (insideQuotes) { + if (i > start) + res ~= line[start .. i]; + start = i + 1; + insideQuotes = false; + } else { + insideQuotes = true; + start = i + 1; + } + } else if (!insideQuotes && (ch == ' ' || ch == '\t' || ch == 0)) { + if (i > start) { + res ~= line[start .. i]; + } + start = i + 1; + } + } + return res; +} + int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) { setFileLogger(std.stdio.File("ui.log", "w")); setLogLevel(LogLevel.Trace); + string basePath = exePath(); + Log.i("Current executable: ", exePath()); + + string cmdline = fromStringz(lpCmdLine); + Log.i("Command line: ", cmdline); + string[] args = splitCmdLine(cmdline); + Log.i("Command line params: ", args); + _cmdShow = iCmdShow; _hInstance = hInstance; Log.d("Inside myWinMain"); @@ -156,7 +197,7 @@ int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int Platform.setInstance(platform); Win32FontManager fontMan = new Win32FontManager(); FontManager.instance = fontMan; - return UIAppMain(); + return UIAppMain(args); }