flayer.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
flayer.c (9842B) | |
--- | |
1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */ | |
2 #include <u.h> | |
3 #include <libg.h> | |
4 #include <frame.h> | |
5 #include "flayer.h" | |
6 #include "samterm.h" | |
7 | |
8 #define DELTA 10 | |
9 | |
10 static Flayer **llist; /* front to back */ | |
11 static int nllist; | |
12 static int nlalloc; | |
13 static Rectangle lDrect; | |
14 | |
15 extern Bitmap screen; | |
16 extern Mouse mouse; | |
17 | |
18 extern uint64_t _bgpixel; | |
19 | |
20 Vis visibility(Flayer *); | |
21 void newvisibilities(int); | |
22 void llinsert(Flayer*); | |
23 void lldelete(Flayer*); | |
24 | |
25 void | |
26 flstart(Rectangle r) | |
27 { | |
28 lDrect = r; | |
29 } | |
30 | |
31 void | |
32 flnew(Flayer *l, wchar_t *(*fn)(Flayer*, int64_t, uint64_t*), int u0, vo… | |
33 { | |
34 if(nllist == nlalloc){ | |
35 nlalloc += DELTA; | |
36 llist = realloc(llist, nlalloc*sizeof(Flayer**)); | |
37 if(llist == 0) | |
38 panic("flnew"); | |
39 } | |
40 l->textfn = fn; | |
41 l->user0 = u0; | |
42 l->user1 = u1; | |
43 l->bg = _bgpixel; | |
44 llinsert(l); | |
45 } | |
46 | |
47 Rectangle | |
48 flrect(Flayer *l, Rectangle r) | |
49 { | |
50 rectclip(&r, lDrect); | |
51 l->entire = r; | |
52 l->scroll = inset(r, FLMARGIN); | |
53 r.min.x = | |
54 l->scroll.max.x = r.min.x+FLMARGIN+FLSCROLLWID+(FLGAP-FLMARGIN); | |
55 return r; | |
56 } | |
57 | |
58 void | |
59 flinit(Flayer *l, Rectangle r, XftFont *ft, uint64_t bg) | |
60 { | |
61 lldelete(l); | |
62 llinsert(l); | |
63 l->visible = All; | |
64 l->origin = l->p0 = l->p1 = 0; | |
65 frinit(&l->f, inset(flrect(l, r), FLMARGIN), ft, &screen, bg); | |
66 l->bg = bg; | |
67 newvisibilities(1); | |
68 bitblt2(&screen, l->entire.min, &screen, l->entire, 0, 0, l->bg); | |
69 scrdraw(l, 0L); | |
70 flborder(l, 0); | |
71 } | |
72 | |
73 void | |
74 flclose(Flayer *l) | |
75 { | |
76 if(l->visible == All) | |
77 bitblt2(&screen, l->entire.min, &screen, l->entire, 0, _bgpixel,… | |
78 else if(l->visible == Some){ | |
79 if(l->f.b == 0) | |
80 l->f.b = balloc(l->entire, screen.ldepth); | |
81 if(l->f.b){ | |
82 bitblt2(l->f.b, l->entire.min, l->f.b, l->entire, 0, _bgpixe… | |
83 flrefresh(l, l->entire, 0); | |
84 } | |
85 } | |
86 frclear(&l->f); | |
87 lldelete(l); | |
88 if(l->f.b && l->visible!=All) | |
89 bfree(l->f.b); | |
90 l->textfn = 0; | |
91 newvisibilities(1); | |
92 } | |
93 | |
94 void | |
95 flborder(Flayer *l, bool wide) | |
96 { | |
97 if(flprepare(l)){ | |
98 border(l->f.b, l->entire, FLMARGIN, 0, l->bg); | |
99 border(l->f.b, l->entire, wide? FLMARGIN : 1, F&~D, l->bg); | |
100 if(l->visible==Some) | |
101 flrefresh(l, l->entire, 0); | |
102 } | |
103 } | |
104 | |
105 Flayer * | |
106 flwhich(Point p) | |
107 { | |
108 int i; | |
109 | |
110 if(p.x==0 && p.y==0) | |
111 return nllist? llist[0] : 0; | |
112 for(i=0; i<nllist; i++) | |
113 if(ptinrect(p, llist[i]->entire)) | |
114 return llist[i]; | |
115 return 0; | |
116 } | |
117 | |
118 void | |
119 flupfront(Flayer *l) | |
120 { | |
121 int v = l->visible; | |
122 | |
123 lldelete(l); | |
124 llinsert(l); | |
125 if(v!=All) | |
126 newvisibilities(0); | |
127 } | |
128 | |
129 void | |
130 newvisibilities(int redraw) | |
131 /* if redraw false, we know it's a flupfront, and needn't | |
132 * redraw anyone becoming partially covered */ | |
133 { | |
134 int i; | |
135 Vis ov; | |
136 Flayer *l; | |
137 | |
138 for(i = 0; i<nllist; i++){ | |
139 l = llist[i]; | |
140 ov = l->visible; | |
141 l->visible = visibility(l); | |
142 #define V(a, b) (((a)<<2)|((b))) | |
143 switch(V(ov, l->visible)){ | |
144 case V(Some, None): | |
145 if(l->f.b) | |
146 bfree(l->f.b); | |
147 case V(All, None): | |
148 case V(All, Some): | |
149 l->f.b = 0; | |
150 frclear(&l->f); | |
151 break; | |
152 | |
153 case V(Some, Some): | |
154 if(l->f.b==0 && redraw) | |
155 case V(None, Some): | |
156 flprepare(l); | |
157 if(l->f.b && redraw){ | |
158 flrefresh(l, l->entire, 0); | |
159 bfree(l->f.b); | |
160 l->f.b = 0; | |
161 frclear(&l->f); | |
162 } | |
163 case V(None, None): | |
164 case V(All, All): | |
165 break; | |
166 | |
167 case V(Some, All): | |
168 if(l->f.b){ | |
169 bitblt2(&screen, l->entire.min, l->f.b, l->entire, S, 0,… | |
170 bfree(l->f.b); | |
171 l->f.b = &screen; | |
172 break; | |
173 } | |
174 case V(None, All): | |
175 flprepare(l); | |
176 break; | |
177 } | |
178 if(ov==None && l->visible!=None) | |
179 flnewlyvisible(l); | |
180 } | |
181 } | |
182 | |
183 void | |
184 llinsert(Flayer *l) | |
185 { | |
186 int i; | |
187 for(i=nllist; i>0; --i) | |
188 llist[i]=llist[i-1]; | |
189 llist[0]=l; | |
190 nllist++; | |
191 } | |
192 | |
193 void | |
194 lldelete(Flayer *l) | |
195 { | |
196 int i; | |
197 | |
198 for(i=0; i<nllist; i++) | |
199 if(llist[i]==l){ | |
200 --nllist; | |
201 for(; i<nllist; i++) | |
202 llist[i] = llist[i+1]; | |
203 return; | |
204 } | |
205 panic("lldelete"); | |
206 } | |
207 | |
208 void | |
209 flinsert(Flayer *l, wchar_t *sp, wchar_t *ep, int64_t p0) | |
210 { | |
211 if(flprepare(l)){ | |
212 frinsert(&l->f, sp, ep, p0-l->origin); | |
213 scrdraw(l, scrtotal(l)); | |
214 if(l->visible==Some) | |
215 flrefresh(l, l->entire, 0); | |
216 } | |
217 } | |
218 | |
219 void | |
220 fldelete(Flayer *l, int64_t p0, int64_t p1) | |
221 { | |
222 if(flprepare(l)){ | |
223 p0 -= l->origin; | |
224 if(p0 < 0) | |
225 p0 = 0; | |
226 p1 -= l->origin; | |
227 if(p1<0) | |
228 p1 = 0; | |
229 frdelete(&l->f, p0, p1); | |
230 scrdraw(l, scrtotal(l)); | |
231 if(l->visible==Some) | |
232 flrefresh(l, l->entire, 0); | |
233 } | |
234 } | |
235 | |
236 bool | |
237 flselect(Flayer *l) | |
238 { | |
239 if(l->visible!=All) | |
240 flupfront(l); | |
241 if(mouse.msec-l->click<Clicktime && (l->f.p0 == l->f.p1 && l->f.p0 =… | |
242 l->click = 0; | |
243 return true; | |
244 } | |
245 frselect(&l->f, &mouse); | |
246 if(l->f.p0==l->f.p1) | |
247 l->click = mouse.msec; | |
248 else | |
249 l->click = 0; | |
250 l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin; | |
251 return false; | |
252 } | |
253 | |
254 void | |
255 flsetselect(Flayer *l, int64_t p0, int64_t p1) | |
256 { | |
257 uint64_t fp0, fp1; | |
258 | |
259 l->click = 0; | |
260 if(l->visible==None || !flprepare(l)){ | |
261 l->p0 = p0, l->p1 = p1; | |
262 return; | |
263 } | |
264 l->p0 = p0, l->p1 = p1; | |
265 flfp0p1(l, &fp0, &fp1); | |
266 if(fp0==l->f.p0 && fp1==l->f.p1) | |
267 return; | |
268 frselectp(&l->f, F&~D); | |
269 l->f.p0 = fp0, l->f.p1 = fp1; | |
270 frselectp(&l->f, F&~D); | |
271 if(l->visible==Some) | |
272 flrefresh(l, l->entire, 0); | |
273 } | |
274 | |
275 void | |
276 flfp0p1(Flayer *l, uint64_t *pp0, uint64_t *pp1) | |
277 { | |
278 int64_t p0 = l->p0-l->origin, p1 = l->p1-l->origin; | |
279 | |
280 if(p0 < 0) | |
281 p0 = 0; | |
282 if(p1 < 0) | |
283 p1 = 0; | |
284 if(p0 > l->f.nchars) | |
285 p0 = l->f.nchars; | |
286 if(p1 > l->f.nchars) | |
287 p1 = l->f.nchars; | |
288 *pp0 = p0; | |
289 *pp1 = p1; | |
290 } | |
291 | |
292 Rectangle | |
293 rscale(Rectangle r, Point old, Point new) | |
294 { | |
295 r.min.x = r.min.x*new.x/old.x; | |
296 r.min.y = r.min.y*new.y/old.y; | |
297 r.max.x = r.max.x*new.x/old.x; | |
298 r.max.y = r.max.y*new.y/old.y; | |
299 return r; | |
300 } | |
301 | |
302 void | |
303 flreshape(Rectangle dr) | |
304 { | |
305 int i; | |
306 Flayer *l; | |
307 Frame *f; | |
308 Rectangle r, olDrect; | |
309 int move; | |
310 | |
311 olDrect = lDrect; | |
312 lDrect = dr; | |
313 move = 0; | |
314 bitblt2(&screen, lDrect.min, &screen, lDrect, 0, 0, _bgpixel); | |
315 | |
316 for(i=0; i<nllist; i++){ | |
317 l = llist[i]; | |
318 f = &l->f; | |
319 if(move) | |
320 r = raddp(rsubp(l->entire, olDrect.min), dr.min); | |
321 else{ | |
322 r = raddp(rscale(rsubp(l->entire, olDrect.min), | |
323 sub(olDrect.max, olDrect.min), | |
324 sub(dr.max, dr.min)), dr.min); | |
325 if(l->visible==Some && f->b){ | |
326 bfree(f->b); | |
327 frclear(f); | |
328 } | |
329 f->b = 0; | |
330 if(l->visible!=None) | |
331 frclear(f); | |
332 } | |
333 if(!rectclip(&r, dr)) | |
334 panic("flreshape"); | |
335 if(r.max.x-r.min.x<100) | |
336 r.min.x = dr.min.x; | |
337 if(r.max.x-r.min.x<100) | |
338 r.max.x = dr.max.x; | |
339 if(r.max.y-r.min.y<2*FLMARGIN+f->fheight) | |
340 r.min.y = dr.min.y; | |
341 if(r.max.y-r.min.y<2*FLMARGIN+f->fheight) | |
342 r.max.y = dr.max.y; | |
343 if(!move) | |
344 l->visible = None; | |
345 frsetrects(f, inset(flrect(l, r), FLMARGIN), f->b); | |
346 if(!move && f->b) | |
347 scrdraw(l, scrtotal(l)); | |
348 } | |
349 newvisibilities(1); | |
350 } | |
351 | |
352 int | |
353 flprepare(Flayer *l) | |
354 { | |
355 Frame *f; | |
356 uint64_t n; | |
357 wchar_t *r; | |
358 | |
359 if(l->visible == None) | |
360 return 0; | |
361 f = &l->f; | |
362 if(f->b == 0){ | |
363 if(l->visible == All) | |
364 f->b = &screen; | |
365 else if((f->b = balloc(l->entire, screen.ldepth))==0) | |
366 return 0; | |
367 bitblt2(f->b, l->entire.min, f->b, l->entire, 0, 0, l->bg); | |
368 border(f->b, l->entire, l==llist[0]? FLMARGIN : 1, F&~D, l->bg); | |
369 n = f->nchars; | |
370 frinit(f, f->entire, f->font, f->b, l->bg); | |
371 r = (*l->textfn)(l, n, &n); | |
372 frinsert(f, r, r+n, (uint64_t)0); | |
373 frselectp(f, F&~D); | |
374 flfp0p1(l, &l->f.p0, &l->f.p1); | |
375 frselectp(f, F&~D); | |
376 scrdraw(l, scrtotal(l)); | |
377 } | |
378 return 1; | |
379 } | |
380 | |
381 static bool somevis, someinvis, justvis; | |
382 | |
383 Vis | |
384 visibility(Flayer *l) | |
385 { | |
386 somevis = someinvis = false; | |
387 justvis = true; | |
388 flrefresh(l, l->entire, 0); | |
389 justvis = false; | |
390 if(!somevis) | |
391 return None; | |
392 if(!someinvis) | |
393 return All; | |
394 return Some; | |
395 } | |
396 | |
397 void | |
398 flrefresh(Flayer *l, Rectangle r, int i) | |
399 { | |
400 Flayer *t; | |
401 Rectangle s; | |
402 | |
403 Top: | |
404 if((t=llist[i++]) == l){ | |
405 if(!justvis) | |
406 bitblt2(&screen, r.min, l->f.b, r, S, 0, l->bg); | |
407 somevis = true; | |
408 }else{ | |
409 if(!rectXrect(t->entire, r)) | |
410 goto Top; /* avoid stacking unnecessarily */ | |
411 if(t->entire.min.x>r.min.x){ | |
412 s = r; | |
413 s.max.x = t->entire.min.x; | |
414 flrefresh(l, s, i); | |
415 r.min.x = t->entire.min.x; | |
416 } | |
417 if(t->entire.min.y>r.min.y){ | |
418 s = r; | |
419 s.max.y = t->entire.min.y; | |
420 flrefresh(l, s, i); | |
421 r.min.y = t->entire.min.y; | |
422 } | |
423 if(t->entire.max.x<r.max.x){ | |
424 s = r; | |
425 s.min.x = t->entire.max.x; | |
426 flrefresh(l, s, i); | |
427 r.max.x = t->entire.max.x; | |
428 } | |
429 if(t->entire.max.y<r.max.y){ | |
430 s = r; | |
431 s.min.y = t->entire.max.y; | |
432 flrefresh(l, s, i); | |
433 r.max.y = t->entire.max.y; | |
434 } | |
435 /* remaining piece of r is blocked by t; forget about it */ | |
436 someinvis = true; | |
437 } | |
438 } |