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