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);
}