flayer.c - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) 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, void *u1)
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, _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, _bgpixel, _bgpixel);
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, l->bg);
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 == frcharofpt(&l->f, mouse.xy))) {
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 }