cpoly.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #include "lib9.h"
  2. #include "draw.h"
  3. #include "tk.h"
  4. #include "canvs.h"
  5. #define O(t, e) ((long)(&((t*)0)->e))
  6. typedef struct TkCpoly TkCpoly;
  7. struct TkCpoly
  8. {
  9. int width;
  10. Image* stipple;
  11. Image* pen;
  12. TkCanvas* canv;
  13. int smooth;
  14. int steps;
  15. int winding;
  16. };
  17. static
  18. TkStab tkwinding[] =
  19. {
  20. "nonzero", ~0,
  21. "odd", 1,
  22. nil
  23. };
  24. /* Polygon Options (+ means implemented)
  25. +fill
  26. +smooth
  27. +splinesteps
  28. +stipple
  29. +tags
  30. +width
  31. +outline
  32. */
  33. static
  34. TkOption polyopts[] =
  35. {
  36. "width", OPTnnfrac, O(TkCpoly, width), nil,
  37. "stipple", OPTbmap, O(TkCpoly, stipple), nil,
  38. "smooth", OPTstab, O(TkCpoly, smooth), tkbool,
  39. "splinesteps", OPTdist, O(TkCpoly, steps), nil,
  40. "winding", OPTstab, O(TkCpoly, winding), tkwinding,
  41. nil
  42. };
  43. static
  44. TkOption itemopts[] =
  45. {
  46. "tags", OPTctag, O(TkCitem, tags), nil,
  47. "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
  48. "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
  49. nil
  50. };
  51. void
  52. tkcvspolysize(TkCitem *i)
  53. {
  54. int w;
  55. TkCpoly *p;
  56. p = TKobj(TkCpoly, i);
  57. w = TKF2I(p->width);
  58. i->p.bb = bbnil;
  59. tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
  60. i->p.bb = insetrect(i->p.bb, -w);
  61. }
  62. char*
  63. tkcvspolycreat(Tk* tk, char *arg, char **val)
  64. {
  65. char *e;
  66. TkCpoly *p;
  67. TkCitem *i;
  68. TkCanvas *c;
  69. TkOptab tko[3];
  70. c = TKobj(TkCanvas, tk);
  71. i = tkcnewitem(tk, TkCVpoly, sizeof(TkCitem)+sizeof(TkCpoly));
  72. if(i == nil)
  73. return TkNomem;
  74. p = TKobj(TkCpoly, i);
  75. p->width = TKI2F(1);
  76. p->winding = ~0;
  77. e = tkparsepts(tk->env->top, &i->p, &arg, 1);
  78. if(e == nil && i->p.npoint < 3)
  79. e = TkBadvl;
  80. if(e != nil) {
  81. tkcvsfreeitem(i);
  82. return e;
  83. }
  84. tko[0].ptr = p;
  85. tko[0].optab = polyopts;
  86. tko[1].ptr = i;
  87. tko[1].optab = itemopts;
  88. tko[2].ptr = nil;
  89. e = tkparse(tk->env->top, arg, tko, nil);
  90. if(e != nil) {
  91. tkcvsfreeitem(i);
  92. return e;
  93. }
  94. p->canv = c;
  95. e = tkcaddtag(tk, i, 1);
  96. if(e != nil) {
  97. tkcvsfreeitem(i);
  98. return e;
  99. }
  100. tkcvspolysize(i);
  101. tkmkpen(&p->pen, i->env, p->stipple);
  102. e = tkvalue(val, "%d", i->id);
  103. if(e != nil) {
  104. tkcvsfreeitem(i);
  105. return e;
  106. }
  107. tkcvsappend(c, i);
  108. tkbbmax(&c->update, &i->p.bb);
  109. tkcvssetdirty(tk);
  110. return nil;
  111. }
  112. char*
  113. tkcvspolycget(TkCitem *i, char *arg, char **val)
  114. {
  115. TkOptab tko[3];
  116. TkCpoly *p = TKobj(TkCpoly, i);
  117. tko[0].ptr = p;
  118. tko[0].optab = polyopts;
  119. tko[1].ptr = i;
  120. tko[1].optab = itemopts;
  121. tko[2].ptr = nil;
  122. return tkgencget(tko, arg, val, i->env->top);
  123. }
  124. char*
  125. tkcvspolyconf(Tk *tk, TkCitem *i, char *arg)
  126. {
  127. char *e;
  128. TkOptab tko[3];
  129. TkCpoly *p = TKobj(TkCpoly, i);
  130. tko[0].ptr = p;
  131. tko[0].optab = polyopts;
  132. tko[1].ptr = i;
  133. tko[1].optab = itemopts;
  134. tko[2].ptr = nil;
  135. e = tkparse(tk->env->top, arg, tko, nil);
  136. tkcvspolysize(i);
  137. tkmkpen(&p->pen, i->env, p->stipple);
  138. return e;
  139. }
  140. void
  141. tkcvspolyfree(TkCitem *i)
  142. {
  143. TkCpoly *p;
  144. p = TKobj(TkCpoly, i);
  145. if(p->stipple)
  146. freeimage(p->stipple);
  147. if(p->pen)
  148. freeimage(p->pen);
  149. }
  150. void
  151. tkcvspolydraw(Image *img, TkCitem *i, TkEnv *pe)
  152. {
  153. int w;
  154. TkEnv *e;
  155. TkCpoly *p;
  156. Image *pen;
  157. Point *pts;
  158. USED(pe);
  159. p = TKobj(TkCpoly, i);
  160. e = i->env;
  161. pen = p->pen;
  162. if(pen == nil && (e->set & (1<<TkCfill)))
  163. pen = tkgc(e, TkCfill);
  164. pts = i->p.drawpt;
  165. if(i->p.npoint > 0 && pen != nil) {
  166. if (p->smooth == BoolT)
  167. fillbezspline(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
  168. else
  169. fillpoly(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
  170. }
  171. w = TKF2I(p->width) - 1;
  172. if(w >= 0 && (e->set & (1<<TkCforegnd))) {
  173. pen = tkgc(i->env, TkCforegnd);
  174. if (p->smooth == BoolT)
  175. bezspline(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
  176. else
  177. poly(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
  178. }
  179. }
  180. char*
  181. tkcvspolycoord(TkCitem *i, char *arg, int x, int y)
  182. {
  183. char *e;
  184. TkCpoints p;
  185. if(arg == nil) {
  186. tkxlatepts(i->p.parampt, i->p.npoint, x, y);
  187. tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
  188. i->p.drawpt[i->p.npoint] = i->p.drawpt[0];
  189. i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
  190. }
  191. else {
  192. e = tkparsepts(i->env->top, &p, &arg, 1);
  193. if(e != nil)
  194. return e;
  195. if(p.npoint < 2) {
  196. tkfreepoint(&p);
  197. return TkFewpt;
  198. }
  199. tkfreepoint(&i->p);
  200. i->p = p;
  201. tkcvspolysize(i);
  202. }
  203. return nil;
  204. }
  205. int
  206. tkcvspolyhit(TkCitem *item, Point p)
  207. {
  208. Point *poly;
  209. int r, np, fill, w;
  210. TkCpoly *l;
  211. TkEnv *e;
  212. l = TKobj(TkCpoly, item);
  213. w = TKF2I(l->width) + 2; /* include some slop */
  214. e = item->env;
  215. fill = e->set & (1<<TkCfill);
  216. if (l->smooth == BoolT) {
  217. /* this works but it's slow if used intensively... */
  218. np = getbezsplinepts(item->p.drawpt, item->p.npoint + 1, &poly);
  219. if (fill)
  220. r = tkinsidepoly(poly, np, l->winding, p);
  221. else
  222. r = tklinehit(poly, np, w, p);
  223. free(poly);
  224. } else {
  225. if (fill)
  226. r = tkinsidepoly(item->p.drawpt, item->p.npoint, l->winding, p);
  227. else
  228. r = tklinehit(item->p.drawpt, item->p.npoint + 1, w, p);
  229. }
  230. return r;
  231. }