From ca58769a917af43a89d6fb0f6c1c7b716c705fdf Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 24 Mar 2015 20:47:54 +0300 Subject: [PATCH 1/3] issue #64 - draw points --- src/dlangui/graphics/drawbuf.d | 38 ++++++++++++++++++++++++++++++-- src/dlangui/graphics/gldrawbuf.d | 12 +++++++++- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index 3fd046e2..2dbb349d 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -260,6 +260,8 @@ class DrawBuf : RefCountedObject { abstract void fill(uint color); /// fill rectangle with solid color (clipping is applied) abstract void fillRect(Rect rc, uint color); + /// draw pixel at (x, y) with specified color + abstract void drawPixel(int x, int y, uint color); /// draw 8bit alpha image - usually font glyph using specified color (clipping is applied) abstract void drawGlyph(int x, int y, Glyph * glyph, uint color); /// draw source buffer rectangle contents to destination buffer @@ -646,6 +648,22 @@ class ColorDrawBufBase : DrawBuf { } } } + + /// draw pixel at (x, y) with specified color + override void drawPixel(int x, int y, uint color) { + if (!_clipRect.isPointInside(x, y)) + return; + color = applyAlpha(color); + uint * row = scanLine(y); + uint alpha = color >> 24; + if (!alpha) { + row[x] = color; + } else if (alpha < 254) { + // apply blending + row[x] = blendARGB(row[x], color, alpha); + } + } + } class GrayDrawBuf : DrawBuf { @@ -828,11 +846,11 @@ class GrayDrawBuf : DrawBuf { } } override void fillRect(Rect rc, uint color) { - ubyte cl = rgbToGray(color); if (applyClipping(rc)) { + uint alpha = color >> 24; + ubyte cl = rgbToGray(color); for (int y = rc.top; y < rc.bottom; y++) { ubyte * row = scanLine(y); - uint alpha = color >> 24; for (int x = rc.left; x < rc.right; x++) { if (!alpha) row[x] = cl; @@ -844,6 +862,22 @@ class GrayDrawBuf : DrawBuf { } } } + + /// draw pixel at (x, y) with specified color + override void drawPixel(int x, int y, uint color) { + if (!_clipRect.isPointInside(x, y)) + return; + color = applyAlpha(color); + ubyte cl = rgbToGray(color); + ubyte * row = scanLine(y); + uint alpha = color >> 24; + if (!alpha) { + row[x] = cl; + } else if (alpha < 254) { + // apply blending + row[x] = blendGray(row[x], cl, alpha); + } + } } class ColorDrawBuf : ColorDrawBufBase { diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index ec294935..ee613c12 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -100,7 +100,17 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { if (!isFullyTransparentColor(color) && applyClipping(rc)) _scene.add(new SolidRectSceneItem(rc, color)); } - /// draw 8bit alpha image - usually font glyph using specified color (clipping is applied) + /// draw pixel at (x, y) with specified color + override void drawPixel(int x, int y, uint color) { + assert(_scene !is null); + if (!_clipRect.isPointInside(x, y)) + return; + color = applyAlpha(color); + if (isFullyTransparentColor(color)) + return; + _scene.add(new SolidRectSceneItem(Rect(x, y, x + 1, y + 1), color)); + } + /// draw 8bit alpha image - usually font glyph using specified color (clipping is applied) override void drawGlyph(int x, int y, Glyph * glyph, uint color) { assert(_scene !is null); Rect dstrect = Rect(x,y, x + glyph.correctedBlackBoxX, y + glyph.blackBoxY); From 0c2b25d558e1162869b8002be6c6366b8dc13c36 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 24 Mar 2015 21:20:47 +0300 Subject: [PATCH 2/3] CanvasWidget, with example --- examples/example1/src/example1.d | 13 +++++++++ examples/example1/views/res/i18n/en.ini | 1 + src/dlangui/widgets/controls.d | 35 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index 37e6cae2..3db6f55d 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -840,6 +840,19 @@ void main() tabs.addTab((new SampleAnimationWidget("tab6")).layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT), "TAB_ANIMATION"c); + CanvasWidget canvas = new CanvasWidget("canvas"); + canvas.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) { + int x = rc.left; + int y = rc.top; + buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80); + buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF); + canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0); + canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080); + for (int i = 0; i < 80; i++) + buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2); + }; + tabs.addTab(canvas, "TAB_CANVAS"c); //========================================================================== diff --git a/examples/example1/views/res/i18n/en.ini b/examples/example1/views/res/i18n/en.ini index 5016474a..f71127d3 100644 --- a/examples/example1/views/res/i18n/en.ini +++ b/examples/example1/views/res/i18n/en.ini @@ -32,4 +32,5 @@ TAB_BUTTONS=Buttons TAB_ANIMATION=Animation TAB_TABLE_LAYOUT=Table layout TAB_EDITORS=Editors +TAB_CANVAS=Canvas diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 82968d80..b9a36186 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -994,3 +994,38 @@ class ScrollBar : AbstractSlider, OnClickHandler { } } +/// interface - slot for onClick +interface OnDrawHandler { + void doDraw(CanvasWidget canvas, DrawBuf buf, Rect rc); +} + +/// canvas widget - draw on it either by overriding of doDraw() or by assigning of onDrawListener +class CanvasWidget : Widget { + + Listener!OnDrawHandler onDrawListener; + + this(string ID = null) { + super(ID); + } + + override void measure(int parentWidth, int parentHeight) { + measuredContent(parentWidth, parentHeight, 0, 0); + } + + void doDraw(DrawBuf buf, Rect rc) { + if (onDrawListener.assigned) + onDrawListener(this, buf, rc); + } + + override void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + super.onDraw(buf); + Rect rc = _pos; + applyMargins(rc); + auto saver = ClipRectSaver(buf, rc, alpha); + applyPadding(rc); + doDraw(buf, rc); + } +} + From a9d1a31f6bad2cac50e9bbe71e61f316fa5654a2 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 24 Mar 2015 21:56:54 +0300 Subject: [PATCH 3/3] added DrawBuf,drawLine() - issue #64 - based on code from Ted Bullen; OpenGL version of drawLine still needs optimization to avoid drawing by-pixel --- examples/example1/src/example1.d | 6 +++++ src/dlangui/graphics/drawbuf.d | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index 3db6f55d..57950a49 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -843,14 +843,20 @@ void main() CanvasWidget canvas = new CanvasWidget("canvas"); canvas.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) { + buf.fill(0xFFFFFF); int x = rc.left; int y = rc.top; buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80); buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF); canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0); + buf.drawFrame(Rect(x + 400, y + 30, x + 550, y + 150), 0x204060, Rect(2,3,4,5), 0x80704020); + canvas.font.drawText(buf, x + 400, y + 5, "drawFrame()"d, 0x208020); canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080); for (int i = 0; i < 80; i++) buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2); + canvas.font.drawText(buf, x + 200, y + 250, "drawLine()"d, 0x800020); + for (int i = 0; i < 40; i+=3) + buf.drawLine(Point(x+200 + i * 4, y+290), Point(x+150 + i * 7, y+420 + i * 2), 0x008000 + i * 5); }; tabs.addTab(canvas, "TAB_CANVAS"c); diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index 2dbb349d..2b6ce4cc 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -338,6 +338,50 @@ class DrawBuf : RefCountedObject { } } + /// draw line from point p1 to p2 with specified color + void drawLine(Point p1, Point p2, uint colour) { + if (p1.x < _clipRect.left && p2.x < _clipRect.left) + return; + if (p1.y < _clipRect.top && p2.y < _clipRect.top) + return; + if (p1.x >= _clipRect.right && p2.x >= _clipRect.right) + return; + if (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom) + return; + // from rosettacode.org + import std.math: abs; + immutable int dx = p2.x - p1.x; + immutable int ix = (dx > 0) - (dx < 0); + immutable int dx2 = abs(dx) * 2; + int dy = p2.y - p1.y; + immutable int iy = (dy > 0) - (dy < 0); + immutable int dy2 = abs(dy) * 2; + drawPixel(p1.x, p1.y, colour); + if (dx2 >= dy2) { + int error = dy2 - (dx2 / 2); + while (p1.x != p2.x) { + if (error >= 0 && (error || (ix > 0))) { + error -= dx2; + p1.y += iy; + } + error += dy2; + p1.x += ix; + drawPixel(p1.x, p1.y, colour); + } + } else { + int error = dx2 - (dy2 / 2); + while (p1.y != p2.y) { + if (error >= 0 && (error || (iy > 0))) { + error -= dy2; + p1.x += ix; + } + error += dx2; + p1.y += iy; + drawPixel(p1.x, p1.y, colour); + } + } + } + /// create drawbuf with copy of current buffer with changed colors (returns this if not supported) DrawBuf transformColors(ref ColorTransform transform) { return this;