diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index cf3960b6..93447554 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -41,8 +41,13 @@ public struct Rect { public class RefCountedObject { protected int _refCount; public @property int refCount() { return _refCount; } - public void addRef() { _refCount++; } - public void releaseRef() { if (--_refCount == 0) destroy(this); } + public void addRef() { + _refCount++; + } + public void releaseRef() { + if (--_refCount == 0) + destroy(this); + } public ~this() {} } @@ -56,23 +61,39 @@ public struct Ref(T) { // if (T is RefCountedObject) if (_data !is null) _data.addRef(); } - public void opAssign(Ref!T data) { + public this(this) { + if (_data !is null) + _data.addRef(); + } + public ref Ref opAssign(ref Ref data) { if (data._data == _data) - return; + return this; if (_data !is null) _data.releaseRef(); _data = data._data; if (_data !is null) _data.addRef(); + return this; } - public void opAssign(T data) { + public ref Ref opAssign(Ref data) { + if (data._data == _data) + return this; + if (_data !is null) + _data.releaseRef(); + _data = data._data; + if (_data !is null) + _data.addRef(); + return this; + } + public ref Ref opAssign(T data) { if (data == _data) - return; + return this; if (_data !is null) _data.releaseRef(); _data = data; if (_data !is null) _data.addRef(); + return this; } public void clear() { if (_data !is null) { diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index ac538b50..55d19764 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -47,6 +47,7 @@ class DrawBuf : RefCountedObject { fillRect(Rect(left, top, right, bottom), color); } abstract public void fillRect(Rect rc, uint color); + abstract public void drawGlyph(int x, int y, ubyte[] src, int srcdx, int srcdy, uint color); public void clear() {} public ~this() { clear(); } } @@ -59,6 +60,35 @@ class ColorDrawBufBase : DrawBuf { public override void fillRect(int left, int top, int right, int bottom, uint color) { fillRect(Rect(left, top, right, bottom), color); } + public override void drawGlyph(int x, int y, ubyte[] src, int srcdx, int srcdy, uint color) { + bool clipping = !_clipRect.empty(); + for (int yy = 0; yy < srcdy; yy++) { + int liney = y + yy; + if (clipping && (liney < _clipRect.top || liney >= _clipRect.bottom)) + continue; + if (liney < 0 || liney >= _dy) + continue; + uint * row = scanLine(liney); + ubyte * srcrow = src.ptr + yy * srcdx; + for (int xx = 0; xx < srcdx; xx++) { + int colx = xx + x; + if (clipping && (colx < _clipRect.left || colx >= _clipRect.right)) + continue; + if (colx < 0 || colx >= _dx) + continue; + uint alpha1 = srcrow[xx] ^ 255; + uint alpha2 = (color >> 24); + uint alpha = ((((alpha1 ^ 255) * (alpha2 ^ 255)) >> 8) ^ 255) & 255; + uint pixel = row[colx]; + if (!alpha) + row[colx] = pixel; + else if (alpha < 255) { + // apply blending + row[colx] = blendARGB(pixel, color, alpha); + } + } + } + } public override void fillRect(Rect rc, uint color) { if (applyClipping(rc)) { for (int y = rc.top; y < rc.bottom; y++) { diff --git a/src/dlangui/graphics/fonts.d b/src/dlangui/graphics/fonts.d index 784139b0..36ed525a 100644 --- a/src/dlangui/graphics/fonts.d +++ b/src/dlangui/graphics/fonts.d @@ -1,5 +1,8 @@ module dlangui.graphics.fonts; -import dlangui.core.types; +public import dlangui.graphics.drawbuf; +public import dlangui.core.types; +public import dlangui.core.logger; +import std.algorithm; public enum FontFamily : int { SansSerif, @@ -91,12 +94,53 @@ public class Font : RefCountedObject { abstract public @property bool isNull(); // measure text string, return accumulated widths[] (distance to end of n-th character), returns number of measured chars. abstract public int measureText(const dchar[] text, ref int[] widths, int maxWidth); + // draw text string to buffer + abstract public void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color); abstract public Glyph * getCharGlyph(dchar ch); public void clear() {} public ~this() { clear(); } } alias FontRef = Ref!Font; +public struct FontList { + FontRef[] _list; + uint _len; + public ~this() { + for (uint i = 0; i < _len; i++) { + _list[i].clear(); + } + } + // returns item by index + public ref FontRef get(int index) { + return _list[index]; + } + // returns index of found item, -1 if not found + public int find(int size, int weight, bool italic, FontFamily family, string face) { + for (int i = 0; i < _list.length; i++) { + Font item = _list[i].get; + if (item.family != family) + continue; + if (item.size != size) + continue; + if (item.italic != italic || item.weight != weight) + continue; + if (!equal(item.face, face)) + continue; + return i; + } + return -1; + } + public ref FontRef add(Font item) { + Log.d("FontList.add() enter"); + if (_len >= _list.length) { + _list.length = _len < 16 ? 16 : _list.length * 2; + } + _list[_len++] = item; + Log.d("FontList.add() exit"); + return _list[_len - 1]; + } +} + public class FontManager { static __gshared FontManager _instance; public static @property void instance(FontManager manager) { @@ -105,6 +149,6 @@ public class FontManager { public static @property FontManager instance() { return _instance; } - abstract public FontRef getFont(int size, int weight, bool italic, FontFamily family, string face); + abstract public ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face); public ~this() {} } diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index c5cc49ec..768c6daa 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -46,6 +46,10 @@ class Win32Font : Font { public this() { } + public ~this() { + Log.d("Deleting font"); + clear(); + } public override void clear() { if (_hfont !is null) { @@ -174,6 +178,26 @@ class Win32Font : Font { return _glyphCache.put(cast(ushort)glyphIndex, &g); } + // draw text string to buffer + public override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) { + int[] widths; + int charsMeasured = measureText(text, widths, 3000); + for (int i = 0; i < charsMeasured; i++) { + int xx = (i > 0) ? widths[i - 1] : 0; + Glyph * glyph = getCharGlyph(text[i]); + if (glyph is null) + continue; + if ( glyph.blackBoxX && glyph.blackBoxY ) { + buf.drawGlyph( x + xx + glyph.originX, + y + _baseline - glyph.originY, + glyph.glyph, + glyph.blackBoxX, + glyph.blackBoxY, + color); + } + } + } + public override int measureText(const dchar[] text, ref int[] widths, int maxWidth) { if (_hfont is null || _drawbuf is null || text.length == 0) return 0; @@ -251,7 +275,7 @@ class Win32Font : Font { class Win32FontManager : FontManager { - FontRef[] _activeFonts; + FontList _activeFonts; FontDef[] _fontFaces; FontDef*[string] _faceByName; public this() { @@ -277,32 +301,23 @@ class Win32FontManager : FontManager { Log.i("Found ", _fontFaces.length, " font faces"); return res!=0; } - public override FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) { - FontRef res; + FontRef _emptyFontRef; + public override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) { + Log.i("getFont()"); FontDef * def = findFace(family, face); if (def !is null) { - for (int i = 0; i < _activeFonts.length; i++) { - Font item = _activeFonts[i].get; - if (item.family != def.family) - continue; - if (item.size != size) - continue; - if (item.italic != italic || item.weight != weight) - continue; - if (!equal(item.face, def.face)) - continue; - res = _activeFonts[i]; - break; - } - if (res.isNull) { - Win32Font item = new Win32Font(); - if (!item.create(def, size, weight, italic)) - return res; - res = item; - _activeFonts ~= res; - } + int index = _activeFonts.find(size, weight, italic, def.family, def.face); + if (index >= 0) + return _activeFonts.get(index); + Log.d("Creating new font"); + Win32Font item = new Win32Font(); + if (!item.create(def, size, weight, italic)) + return _emptyFontRef; + Log.d("Adding to list of active fonts"); + return _activeFonts.add(item); + } else { + return _emptyFontRef; } - return res; } FontDef * findFace(FontFamily family) { FontDef * res = null; diff --git a/winmain.d b/winmain.d index 923930d3..3781d444 100644 --- a/winmain.d +++ b/winmain.d @@ -6,19 +6,42 @@ import dlangui.core.logger; import dlangui.graphics.fonts; import std.stdio; +class TestWidget : Widget { + public override void onDraw(DrawBuf buf) { + super.onDraw(buf); + FontRef font1; + FontRef font2; + Log.d("Testing opAssign"); + font1 = font2; + Log.d("Testing copy constructor"); + FontRef font3 = font2; + Log.d("On draw: getting font"); + FontRef font = FontManager.instance.getFont(32, 400, false, FontFamily.SansSerif, "Arial"); + Log.d("Got font, drawing text"); + font.drawText(buf, _pos.left + 5, _pos.top + 5, "Text"d, 0x0000FF); + Log.d("Text is drawn successfully"); + } +} + extern (C) int UIAppMain() { Log.d("Some debug message"); Log.e("Sample error #", 22); Window window = Platform.instance().createWindow("My Window", null); - Widget myWidget = new Widget(); + Widget myWidget = new TestWidget(); window.mainWidget = myWidget; window.show(); window.windowCaption = "New Window Caption"; + + + + Log.d("Before getFont"); FontRef font = FontManager.instance.getFont(32, 400, false, FontFamily.SansSerif, "Arial"); + Log.d("After getFont"); assert(!font.isNull); int[] widths; dchar[] text = cast(dchar[])"Test string"d; + Log.d("Calling measureText"); int charsMeasured = font.measureText(text, widths, 1000); assert(charsMeasured > 0); int w = widths[charsMeasured - 1];