1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "canvs.h" 5 6 #define O(t, e) ((long)(&((t*)0)->e)) 7 typedef void (*Drawfn)(Image*, Point, int, int, Image*, int); 8 9 /* Oval Options (+ means implemented) 10 +fill 11 +outline 12 +stipple 13 +tags 14 +width 15 */ 16 17 typedef struct TkCoval TkCoval; 18 struct TkCoval 19 { 20 int width; 21 Image* stipple; 22 Image* pen; 23 TkCanvas* canv; 24 }; 25 26 static 27 TkOption ovalopts[] = 28 { 29 "width", OPTnnfrac, O(TkCoval, width), nil, /* XXX should be nnfrac */ 30 "stipple", OPTbmap, O(TkCoval, stipple), nil, 31 nil 32 }; 33 34 static 35 TkOption itemopts[] = 36 { 37 "tags", OPTctag, O(TkCitem, tags), nil, 38 "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill), 39 "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd), 40 nil 41 }; 42 43 void 44 tkcvsovalsize(TkCitem *i) 45 { 46 int w; 47 TkCoval *o; 48 49 o = TKobj(TkCoval, i); 50 w = TKF2I(o->width)*2; 51 52 i->p.bb = bbnil; 53 tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); 54 i->p.bb = insetrect(i->p.bb, -w); 55 } 56 57 char* 58 tkcvsovalcreat(Tk* tk, char *arg, char **val) 59 { 60 char *e; 61 TkCoval *o; 62 TkCitem *i; 63 TkCanvas *c; 64 TkOptab tko[3]; 65 66 c = TKobj(TkCanvas, tk); 67 68 i = tkcnewitem(tk, TkCVoval, sizeof(TkCitem)+sizeof(TkCoval)); 69 if(i == nil) 70 return TkNomem; 71 72 o = TKobj(TkCoval, i); 73 o->width = TKI2F(1); 74 o->canv = c; 75 e = tkparsepts(tk->env->top, &i->p, &arg, 0); 76 if(e != nil) { 77 tkcvsfreeitem(i); 78 return e; 79 } 80 if(i->p.npoint != 2) { 81 tkcvsfreeitem(i); 82 return TkFewpt; 83 } 84 85 tko[0].ptr = o; 86 tko[0].optab = ovalopts; 87 tko[1].ptr = i; 88 tko[1].optab = itemopts; 89 tko[2].ptr = nil; 90 e = tkparse(tk->env->top, arg, tko, nil); 91 if(e != nil) { 92 tkcvsfreeitem(i); 93 return e; 94 } 95 e = tkcaddtag(tk, i, 1); 96 if(e != nil) { 97 tkcvsfreeitem(i); 98 return e; 99 } 100 101 tkcvsovalsize(i); 102 103 e = tkvalue(val, "%d", i->id); 104 if(e != nil) { 105 tkcvsfreeitem(i); 106 return e; 107 } 108 109 tkcvsappend(c, i); 110 tkbbmax(&c->update, &i->p.bb); 111 tkmkpen(&o->pen, i->env, o->stipple); 112 tkcvssetdirty(tk); 113 return nil; 114 } 115 116 char* 117 tkcvsovalcget(TkCitem *i, char *arg, char **val) 118 { 119 TkOptab tko[3]; 120 TkCoval *o = TKobj(TkCoval, i); 121 122 tko[0].ptr = o; 123 tko[0].optab = ovalopts; 124 tko[1].ptr = i; 125 tko[1].optab = itemopts; 126 tko[2].ptr = nil; 127 128 return tkgencget(tko, arg, val, i->env->top); 129 } 130 131 char* 132 tkcvsovalconf(Tk *tk, TkCitem *i, char *arg) 133 { 134 char *e; 135 TkOptab tko[3]; 136 TkCoval *o = TKobj(TkCoval, i); 137 138 tko[0].ptr = o; 139 tko[0].optab = ovalopts; 140 tko[1].ptr = i; 141 tko[1].optab = itemopts; 142 tko[2].ptr = nil; 143 144 e = tkparse(tk->env->top, arg, tko, nil); 145 tkcvsovalsize(i); 146 tkmkpen(&o->pen, i->env, o->stipple); 147 148 return e; 149 } 150 151 void 152 tkcvsovalfree(TkCitem *i) 153 { 154 TkCoval *o; 155 156 o = TKobj(TkCoval, i); 157 if(o->stipple) 158 freeimage(o->stipple); 159 if(o->pen) 160 freeimage(o->pen); 161 } 162 163 void 164 tkcvsovaldraw(Image *img, TkCitem *i, TkEnv *pe) 165 { 166 Point c; 167 TkEnv *e; 168 Image *pen; 169 TkCoval *o; 170 Rectangle d; 171 int w, dx, dy; 172 173 USED(pe); 174 175 d.min = i->p.drawpt[0]; 176 d.max = i->p.drawpt[1]; 177 178 e = i->env; 179 o = TKobj(TkCoval, i); 180 181 pen = o->pen; 182 if(pen == nil && (e->set & (1<<TkCfill))) 183 pen = tkgc(e, TkCfill); 184 185 w = TKF2I(o->width)/2; 186 if(w < 0) 187 return; 188 189 d = canonrect(d); 190 dx = Dx(d)/2; 191 dy = Dy(d)/2; 192 c.x = d.min.x + dx; 193 c.y = d.min.y + dy; 194 if(pen != nil) 195 fillellipse(img, c, dx, dy, pen, c); 196 ellipse(img, c, dx, dy, w, tkgc(e, TkCforegnd), c); 197 } 198 199 char* 200 tkcvsovalcoord(TkCitem *i, char *arg, int x, int y) 201 { 202 char *e; 203 TkCpoints p; 204 205 if(arg == nil) { 206 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 207 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 208 i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y))); 209 } 210 else { 211 e = tkparsepts(i->env->top, &p, &arg, 0); 212 if(e != nil) 213 return e; 214 if(p.npoint != 2) { 215 tkfreepoint(&p); 216 return TkFewpt; 217 } 218 tkfreepoint(&i->p); 219 i->p = p; 220 tkcvsovalsize(i); 221 } 222 return nil; 223 } 224 225 int 226 tkcvsovalhit(TkCitem *i, Point p) 227 { 228 TkCoval *o; 229 int w, dx, dy; 230 Rectangle d; 231 232 o = TKobj(TkCoval, i); 233 w = TKF2I(o->width)/2; 234 d = canonrect(Rpt(i->p.drawpt[0], i->p.drawpt[1])); 235 d = insetrect(d, -(w/2 + 1)); 236 237 dx = Dx(d)/2; 238 dy = Dy(d)/2; 239 240 p.x -= d.min.x + dx; 241 p.y -= d.min.y + dy; 242 243 dx *= dx; 244 dy *= dy; 245 246 /* XXX can we do this nicely without overflow and without vlongs? */ 247 return (vlong)(p.x*p.x)*dy + (vlong)(p.y*p.y)*dx < (vlong)dx*dy; 248 } 249