twind.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #include "lib9.h"
  2. #include "draw.h"
  3. #include "tk.h"
  4. #include "textw.h"
  5. #define istring u.string
  6. #define iwin u.win
  7. #define imark u.mark
  8. #define iline u.line
  9. #define O(t, e) ((long)(&((t*)0)->e))
  10. static char* tktwincget(Tk*, char*, char**);
  11. static char* tktwinconfigure(Tk*, char*, char**);
  12. static char* tktwincreate(Tk*, char*, char**);
  13. static char* tktwinnames(Tk*, char*, char**);
  14. static int winowned(Tk *tk, Tk *sub);
  15. static
  16. TkStab tkalign[] =
  17. {
  18. "top", Tktop,
  19. "bottom", Tkbottom,
  20. "center", Tkcenter,
  21. "baseline", Tkbaseline,
  22. nil
  23. };
  24. static
  25. TkOption twinopts[] =
  26. {
  27. "align", OPTstab, O(TkTwind, align), tkalign,
  28. "create", OPTtext, O(TkTwind, create), nil,
  29. "padx", OPTnndist, O(TkTwind, padx), nil,
  30. "pady", OPTnndist, O(TkTwind, pady), nil,
  31. "stretch", OPTstab, O(TkTwind, stretch), tkbool,
  32. "window", OPTwinp, O(TkTwind, sub), nil,
  33. "ascent", OPTdist, O(TkTwind, ascent), nil,
  34. nil
  35. };
  36. TkCmdtab
  37. tktwincmd[] =
  38. {
  39. "cget", tktwincget,
  40. "configure", tktwinconfigure,
  41. "create", tktwincreate,
  42. "names", tktwinnames,
  43. nil
  44. };
  45. int
  46. tktfindsubitem(Tk *sub, TkTindex *ix)
  47. {
  48. Tk *tk, *isub;
  49. TkText *tkt;
  50. tk = sub->parent;
  51. if(tk != nil) {
  52. tkt = TKobj(TkText, tk);
  53. tktstartind(tkt, ix);
  54. do {
  55. if(ix->item->kind == TkTwin) {
  56. isub = ix->item->iwin->sub;
  57. if(isub != nil &&
  58. isub->name != nil &&
  59. strcmp(isub->name->name, sub->name->name) == 0)
  60. return 1;
  61. }
  62. } while(tktadjustind(tkt, TkTbyitem, ix));
  63. }
  64. return 0;
  65. }
  66. static void
  67. tktwindsize(Tk *tk, TkTindex *ix)
  68. {
  69. Tk *s;
  70. TkTitem *i;
  71. TkTwind *w;
  72. i = ix->item;
  73. /* assert(i->kind == TkTwin); */
  74. w = i->iwin;
  75. s = w->sub;
  76. if(s == nil)
  77. return;
  78. if(w->width != s->act.width || w->height != s->act.height) {
  79. s->act.width = w->width;
  80. s->act.height = w->height;
  81. if(s->slave) {
  82. tkpackqit(s);
  83. tkrunpack(tk->env->top);
  84. }
  85. }
  86. tktfixgeom(tk, tktprevwrapline(tk, ix->line), ix->line, 0);
  87. tktextsize(tk, 1);
  88. }
  89. void
  90. tktxtforgetsub(Tk *sub, Tk *tk)
  91. {
  92. TkTwind *w;
  93. TkTindex ix;
  94. if(!tktfindsubitem(sub, &ix))
  95. return;
  96. w = ix.item->iwin;
  97. if(w->focus == tk) {
  98. if(0)print("tktxtforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));
  99. w->focus = nil;
  100. }
  101. }
  102. static void
  103. tktwingeom(Tk *sub, int x, int y, int w, int h)
  104. {
  105. TkTindex ix;
  106. Tk *tk;
  107. TkTwind *win;
  108. USED(x);
  109. USED(y);
  110. tk = sub->parent;
  111. if(!tktfindsubitem(sub, &ix)) {
  112. print("tktwingeom: %s not found\n", sub->name->name);
  113. return;
  114. }
  115. win = ix.item->iwin;
  116. win->width = w;
  117. win->height = h;
  118. sub->req.width = w;
  119. sub->req.height = h;
  120. tktwindsize(tk, &ix);
  121. }
  122. static void
  123. tktdestroyed(Tk *sub)
  124. {
  125. TkTindex ix;
  126. Tk *tk;
  127. if(tktfindsubitem(sub, &ix)) {
  128. ix.item->iwin->sub = nil;
  129. ix.item->iwin->focus = nil;
  130. if((tk = sub->parent) != nil) {
  131. tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
  132. tktextsize(tk, 1);
  133. sub->parent = nil;
  134. }
  135. }
  136. }
  137. void
  138. tktdirty(Tk *sub)
  139. {
  140. Tk *tk, *parent, *isub;
  141. TkText *tkt;
  142. TkTindex ix;
  143. parent = nil;
  144. for(tk = sub; tk && parent == nil; tk = tk->master)
  145. parent = tk->parent;
  146. if(tk == nil)
  147. return;
  148. tkt = TKobj(TkText, parent);
  149. tktstartind(tkt, &ix);
  150. do {
  151. if(ix.item->kind == TkTwin) {
  152. isub = ix.item->iwin->sub;
  153. if(isub != nil) {
  154. tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0);
  155. if (sub->flag & Tktransparent)
  156. parent->flag |= Tkrefresh; /* XXX could be more efficient, by drawing the background locally? */
  157. return;
  158. }
  159. }
  160. } while(tktadjustind(tkt, TkTbyitem, &ix));
  161. tktextsize(parent, 1);
  162. }
  163. static char*
  164. tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub)
  165. {
  166. Tk *sub;
  167. sub = w->sub;
  168. if (sub != oldsub) {
  169. w->sub = oldsub;
  170. if(sub == nil)
  171. return nil;
  172. if(sub->flag & Tkwindow)
  173. return TkIstop;
  174. if(sub->master != nil || sub->parent != nil)
  175. return TkWpack;
  176. if (oldsub != nil) {
  177. oldsub->parent = nil;
  178. oldsub->geom = nil;
  179. oldsub->destroyed = nil;
  180. }
  181. w->sub = sub;
  182. w->focus = nil;
  183. sub->parent = tk;
  184. tksetbits(sub, Tksubsub);
  185. sub->geom = tktwingeom;
  186. sub->destroyed = tktdestroyed;
  187. w->width = sub->req.width;
  188. w->height = sub->req.height;
  189. w->owned = winowned(tk, sub);
  190. }
  191. return nil;
  192. }
  193. /* Text Window Command (+ means implemented)
  194. +cget
  195. +configure
  196. +create
  197. +names
  198. */
  199. static char*
  200. tktwincget(Tk *tk, char *arg, char **val)
  201. {
  202. char *e;
  203. TkTindex ix;
  204. TkOptab tko[2];
  205. e = tktindparse(tk, &arg, &ix);
  206. if(e != nil)
  207. return e;
  208. if(ix.item->kind != TkTwin)
  209. return TkBadwp;
  210. tko[0].ptr = ix.item->iwin;
  211. tko[0].optab = twinopts;
  212. tko[1].ptr = nil;
  213. return tkgencget(tko, arg, val, tk->env->top);
  214. }
  215. static char*
  216. tktwinconfigure(Tk *tk, char *arg, char **val)
  217. {
  218. char *e;
  219. TkTindex ix;
  220. TkOptab tko[2];
  221. Tk *oldsub;
  222. USED(val);
  223. e = tktindparse(tk, &arg, &ix);
  224. if(e != nil)
  225. return e;
  226. if(ix.item->kind != TkTwin)
  227. return TkBadwp;
  228. oldsub = ix.item->iwin->sub;
  229. tko[0].ptr = ix.item->iwin;
  230. tko[0].optab = twinopts;
  231. tko[1].ptr = nil;
  232. e = tkparse(tk->env->top, arg, tko, nil);
  233. if(e != nil)
  234. return e;
  235. e = tktwinchk(tk, ix.item->iwin, oldsub);
  236. if(e != nil)
  237. return e;
  238. tktwindsize(tk, &ix);
  239. return nil;
  240. }
  241. /*
  242. * return true if tk is an ancestor of sub
  243. */
  244. static int
  245. winowned(Tk *tk, Tk *sub)
  246. {
  247. int len;
  248. if (tk->name == nil || sub->name == nil)
  249. return 0;
  250. len = strlen(tk->name->name);
  251. if (strncmp(tk->name->name, sub->name->name, len) == 0 &&
  252. sub->name->name[len] == '.')
  253. return 1;
  254. return 0;
  255. }
  256. static char*
  257. tktwincreate(Tk *tk, char *arg, char **val)
  258. {
  259. char *e;
  260. TkTindex ix;
  261. TkTitem *i;
  262. TkText *tkt;
  263. TkOptab tko[2];
  264. USED(val);
  265. tkt = TKobj(TkText, tk);
  266. e = tktindparse(tk, &arg, &ix);
  267. if(e != nil)
  268. return e;
  269. e = tktnewitem(TkTwin, 0, &i);
  270. if(e != nil)
  271. return e;
  272. i->iwin = malloc(sizeof(TkTwind));
  273. if(i->iwin == nil) {
  274. tktfreeitems(tkt, i, 1);
  275. return TkNomem;
  276. }
  277. memset(i->iwin, 0, sizeof(TkTwind));
  278. i->iwin->align = Tkcenter;
  279. i->iwin->ascent = -1;
  280. tko[0].ptr = i->iwin;
  281. tko[0].optab = twinopts;
  282. tko[1].ptr = nil;
  283. e = tkparse(tk->env->top, arg, tko, nil);
  284. if(e != nil) {
  285. err1:
  286. tktfreeitems(tkt, i, 1);
  287. return e;
  288. }
  289. e = tktwinchk(tk, i->iwin, nil);
  290. if(e != nil)
  291. goto err1;
  292. e = tktsplititem(&ix);
  293. if(e != nil)
  294. goto err1;
  295. tktiteminsert(tkt, &ix, i);
  296. if(e != nil)
  297. goto err1;
  298. tktadjustind(tkt, TkTbyitemback, &ix);
  299. tktwindsize(tk, &ix);
  300. return nil;
  301. }
  302. static char*
  303. tktwinnames(Tk *tk, char *arg, char **val)
  304. {
  305. char *e, *fmt;
  306. TkTindex ix;
  307. TkText *tkt = TKobj(TkText, tk);
  308. USED(arg);
  309. tktstartind(tkt, &ix);
  310. fmt = "%s";
  311. do {
  312. if(ix.item->kind == TkTwin &&
  313. ix.item->iwin->sub != nil &&
  314. ix.item->iwin->sub->name != nil) {
  315. e = tkvalue(val, fmt, ix.item->iwin->sub->name->name);
  316. if(e != nil)
  317. return e;
  318. fmt = " %s";
  319. }
  320. } while(tktadjustind(tkt, TkTbyitem, &ix));
  321. return nil;
  322. }