1 /// 2 module plot2d.backend.dlangui; 3 4 import std.exception : enforce; 5 import plot2d.backend.base; 6 7 version (dlangui): 8 9 import dlangui; 10 11 alias PPoint = plot2d.Point; 12 alias PColor = plot2d.Color; 13 14 alias UIPoint = dlangui.PointF; 15 alias UIPointI = dlangui.Point; 16 alias UIColor = dlangui.Color; 17 18 import std.math : floor, ceil; 19 20 int floori(double v) { return cast(int)floor(v); } 21 22 UIPoint toUI()(auto ref const PPoint p) 23 { return UIPoint(p.x, p.y); } 24 25 UIPointI toUII()(auto ref const PPoint p) 26 { return UIPointI(floori(p.x), floori(p.y)); } 27 28 uint toUI()(auto ref const PColor c) 29 { 30 return (cast(uint)(c.r*255))<<16 | 31 (cast(uint)(c.g*255))<<8 | 32 (cast(uint)(c.b*255)); 33 } 34 35 import std.array; 36 import std.typecons : Tuple; 37 38 /// 39 class DlangUICtx : Ctx 40 { 41 protected: 42 alias Line = Tuple!(PPoint, PPoint); 43 44 static struct State 45 { 46 PPoint position; 47 Appender!(Line[]) lines; 48 float lineWidth = 1.0; 49 PColor color = PColor.red; 50 Rect clip; 51 string fontface; 52 double fontsize; 53 } 54 55 State[] stateStack; 56 57 ref State state() @property { return stateStack.back; } 58 59 void setCurrentState() 60 { 61 buf.resetClipping(); 62 buf.clipRect = state.clip; 63 buf.alpha = cast(uint)(state.color.a * 255); 64 } 65 66 void reset() 67 { 68 stateStack.length = 1; 69 setCurrentState(); 70 } 71 72 struct StackReseter 73 { 74 DlangUICtx ctx; 75 this(DlangUICtx c) { ctx = c; } 76 ~this() { ctx.reset(); } 77 } 78 79 DrawBuf buf; 80 81 void drawLineSoft(PPoint a, PPoint b, int c) 82 { buf.drawLine(a.toUII, b.toUII, c); } 83 84 void fillTriangleSoft(PPoint p0, PPoint p1, PPoint p2, int clr) 85 { 86 import std.algorithm : sort; 87 auto p = [p0, p1, p2].sort!"a.x < b.x"; 88 89 auto d1 = floori(p[1].x) - floori(p[0].x); 90 auto d2 = floori(p[2].x) - floori(p[1].x); 91 auto d3 = p[2].x - p[0].x; 92 93 foreach (i; 0 .. d1+1) 94 { 95 auto fa = i/cast(float)d1; 96 auto a = (p[0] * (1-fa) + p[1] * fa); 97 auto fb = (a.x - p[0].x) / d3; 98 auto b = (p[0] * (1-fb) + p[2] * fb); 99 auto x = p[0].x + i; 100 drawLineSoft(PPoint(x, a.y), PPoint(x, b.y), clr); 101 } 102 103 foreach (i; 0 .. d2+1) 104 { 105 auto fa = i/cast(float)d2; 106 auto a = (p[1] * (1-fa) + p[2] * fa); 107 auto fb = (a.x - p[0].x) / d3; 108 auto b = (p[0] * (1-fb) + p[2] * fb); 109 auto x = p[1].x + i; 110 drawLineSoft(PPoint(x, a.y), PPoint(x, b.y), clr); 111 } 112 } 113 114 public: 115 116 StackReseter set(DrawBuf buf) 117 { 118 this.buf = buf; 119 state.clip = buf.clipRect; 120 return StackReseter(this); 121 } 122 123 this() 124 { 125 stateStack.length = 1; 126 } 127 128 override: 129 void save() { stateStack ~= stateStack[$-1]; } 130 131 void restore() 132 { 133 enforce(stateStack.length > 1, "no saved state"); 134 stateStack.popBack(); 135 setCurrentState(); 136 } 137 138 void stroke() 139 { 140 setCurrentState(); 141 auto clr = state.color.toUI; 142 foreach (ln; state.lines.data) 143 //drawLineSoft(ln[0], ln[1], clr); 144 buf.drawLineF(ln[0].toUI, ln[1].toUI, 145 state.lineWidth, 146 state.color.toUI); 147 state.lines.clear(); 148 } 149 150 void fill() 151 { 152 if (state.lines.data.length == 0) return; 153 setCurrentState(); 154 auto p0 = state.lines.data[0][0]; 155 auto clr = state.color.toUI; 156 foreach (ln; state.lines.data[1..$]) 157 //fillTriangleSoft(p0, ln[0], ln[1], clr); 158 buf.fillTriangleF(p0.toUI, ln[0].toUI, 159 ln[1].toUI, clr); 160 state.lines.clear(); 161 } 162 163 void moveTo(double x, double y) 164 { state.position = PPoint(x,y); } 165 166 void lineTo(double x, double y) 167 { 168 state.lines.put(Line(state.position, PPoint(x,y))); 169 moveTo(x, y); 170 } 171 172 void setLineWidth(double lw) { state.lineWidth = lw; } 173 174 void showText(string str) 175 { 176 // TODO 177 auto p = state.position; 178 Glyph g; 179 g.blackBoxX = 10; 180 g.blackBoxY = 15; 181 g.originX = 0; 182 g.originY = 0; 183 g.width = 10; 184 auto hh = 15; 185 g.glyph.length = g.width * hh; 186 foreach (i; 0..hh) foreach (j; 0..g.width) 187 { 188 if (i == j || g.width - i == j) 189 g.glyph[i*g.width + j] = 1; 190 } 191 foreach (c; str) 192 buf.drawGlyph(cast(int)p.x, cast(int)p.y, &g, 193 UIColor.red); 194 } 195 196 void setDash(double[] dash, double offset) 197 { 198 // TODO 199 } 200 201 void setColor(double r, double g, double b, double a=1) 202 { state.color = PColor(r,g,b,a); } 203 204 void getTextSize(string str, out double w, out double h) 205 { 206 // TODO 207 w = str.length * 0.7 * 15; 208 h = 15; 209 } 210 211 void setFont(string name, double size) 212 { 213 state.fontface = name; 214 state.fontsize = size; 215 } 216 217 void clipViewport(Viewport vp) 218 { 219 state.clip = Rect(cast(int)vp.w.min, 220 cast(int)vp.h.min, 221 cast(int)vp.w.max, 222 cast(int)vp.h.max); 223 buf.clipRect = state.clip; 224 state.clip = buf.clipRect; 225 } 226 }