1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <thread.h>
6 #include <cursor.h>
7 #include <mouse.h>
8 #include <keyboard.h>
9 #include <frame.h>
10 #include <plumb.h>
11 #include <html.h>
12 #include "dat.h"
13 #include "fns.h"
14
15 static void sizeitem(Lay *, Item *);
16
17 static
18 void
sizetext(Lay * lay,Itext * i)19 sizetext(Lay *lay, Itext *i)
20 {
21 lay->font = getfont(i->fnt);
22 i->height = lay->font->height + 2*Space;
23 i->width = runestringwidth(lay->font, i->s);
24 i->width += runestringnwidth(lay->font, L" ", 1);
25 }
26
27 static
28 void
sizerule(Lay * lay,Irule * i)29 sizerule(Lay *lay, Irule *i)
30 {
31 i->width = lay->width;
32 i->height = Space + i->size + Space;
33 }
34
35 static
36 void
sizeimage(Lay *,Iimage * i)37 sizeimage(Lay *, Iimage *i)
38 {
39 Cimage *ci;
40
41 ci = (Cimage *)i->aux;
42
43 if(ci==nil)
44 return;
45
46 if(ci->i == nil)
47 getimage(ci, i->altrep);
48 if(ci->i == nil)
49 return;
50 i->width = Dx(ci->i->r) + i->border + i->hspace;
51 i->height = Dy(ci->i->r) + i->border + i->vspace;
52 }
53
54 static
55 void
sizetextfield(Lay *,Iformfield * i)56 sizetextfield(Lay *, Iformfield *i)
57 {
58 Formfield *ff;
59 Font *f;
60 int w, h;
61
62 ff = i->formfield;
63 if(ff->ftype == Ftextarea){
64 w = ff->cols;
65 h = ff->rows;
66 }else{
67 w = ff->size;
68 h = 1;
69 }
70 f = getfont(WFont);
71 i->width = runestringnwidth(f, L"0", 1)*w + 2*(Space+Border+Margin);
72 i->width += Scrollsize+Scrollgap;
73 i->height = f->height*h + 2*(Space+Border+Margin);
74 }
75
76 static
77 void
sizecheck(Lay *,Iformfield * i)78 sizecheck(Lay *, Iformfield *i)
79 {
80 i->width = Boxsize + Space;
81 i->height = Boxsize;
82 }
83
84 static
85 void
sizebutton(Lay *,Iformfield * i)86 sizebutton(Lay *, Iformfield *i)
87 {
88 Font *f;
89 int x;
90
91 x = Margin + Border + Space;
92 f = getfont(WFont);
93 i->width = runestringwidth(f, i->formfield->value) + 2*x + Space;
94 i->height = f->height + 2*x;
95 }
96
97 static
98 void
sizefimage(Lay * lay,Iformfield * i)99 sizefimage(Lay *lay, Iformfield *i)
100 {
101 Iimage *ii;
102
103 ii = (Iimage *)i->formfield->image;
104 sizeimage(lay, ii);
105 i->width = ii->width;
106 i->height = ii->height;
107 }
108
109 static
110 void
sizeselect(Lay *,Iformfield * i)111 sizeselect(Lay *, Iformfield *i)
112 {
113 Option *o;
114 Font *f;
115 int x;
116
117 f = getfont(WFont);
118 i->width = 0;
119 for(o=i->formfield->options; o!=nil; o=o->next)
120 i->width = max(i->width, runestringwidth(f, o->display));
121 x = Margin + Border + Space;
122 i->width += 2*x;
123 i->height = f->height+2*x;
124 }
125
126 static
127 void
sizeformfield(Lay * lay,Iformfield * i)128 sizeformfield(Lay *lay, Iformfield *i)
129 {
130 int type;
131
132 type = i->formfield->ftype;
133
134 if(type==Ftext || type==Ftextarea || type==Fpassword)
135 sizetextfield(lay, i);
136 else if(type==Fcheckbox || type==Fradio)
137 sizecheck(lay, i);
138 else if(type==Fbutton || type==Freset || type==Fsubmit)
139 sizebutton(lay, i);
140 else if(type == Fimage)
141 sizefimage(lay, i);
142 else if(type == Fselect)
143 sizeselect(lay, i);
144 }
145
146 static
147 void
sizetable(Lay * lay,Itable * i)148 sizetable(Lay *lay, Itable *i)
149 {
150 tablesize(i->table, lay->width);
151 i->width = i->table->totw;
152 i->height = i->table->toth;
153 }
154
155 static
156 void
sizefloat(Lay * lay,Ifloat * i)157 sizefloat(Lay *lay, Ifloat *i)
158 {
159 sizeitem(lay, i->item);
160 i->width = i->item->width;
161 i->height = i->item->height;
162 }
163
164 static
165 void
sizespacer(Lay * lay,Ispacer * i)166 sizespacer(Lay *lay, Ispacer *i)
167 {
168 if(i->spkind != ISPnull){
169 if(i->spkind == ISPhspace)
170 i->width = stringnwidth(lay->font, " ", 1);
171 i->height = lay->font->height + 2*Space;
172 }
173 }
174
175 static
176 void
sizeitem(Lay * lay,Item * i)177 sizeitem(Lay *lay, Item *i)
178 {
179
180 switch(i->tag){
181 case Itexttag:
182 sizetext(lay, (Itext *)i);
183 break;
184 case Iruletag:
185 sizerule(lay, (Irule *)i);
186 break;
187 case Iimagetag:
188 sizeimage(lay, (Iimage *)i);
189 break;
190 case Iformfieldtag:
191 sizeformfield(lay, (Iformfield *)i);
192 break;
193 case Itabletag:
194 sizetable(lay, (Itable *)i);
195 break;
196 case Ifloattag:
197 sizefloat(lay, (Ifloat *)i);
198 break;
199 case Ispacertag:
200 sizespacer(lay, (Ispacer *)i);
201 break;
202 default:
203 error("can't happen");
204 }
205 }
206
207 static
208 void
drawtext(Box * b,Page * p,Image * im)209 drawtext(Box *b, Page *p, Image *im)
210 {
211 Rectangle r, r1;
212 Image *c;
213 Point pt;
214 Font *f;
215 Itext *i;
216 int q0, q1;
217
218 r = rectsubpt(b->r, p->pos);
219 i = (Itext *)b->i;
220 f = getfont(i->fnt);
221 if(istextsel(p, b->r, &q0, &q1, i->s, f)){
222 r1 = r;
223 if(q0 > 0)
224 r1.min.x += runestringnwidth(f, i->s, q0);
225 if(q1 > 0)
226 r1.max.x = r1.min.x + runestringnwidth(f, i->s+q0, q1-q0);
227 draw(im, r1, textcols[HIGH], nil, ZP);
228 }
229 c = getcolor(i->fg);
230 runestringbg(im, r.min, c, ZP, f, i->s, im, addpt(r.min, im->r.min));
231
232 if(i->ul == ULnone)
233 return;
234
235 if(i->ul == ULmid)
236 r.min.y += f->height/2;
237 else
238 r.min.y +=f->height-1;
239 pt = r.min;
240 pt.x += runestringwidth(f, i->s);
241 line(im, r.min, pt, Enddisc, Enddisc, 0, c, ZP);
242 }
243
244 static
245 void
drawrule(Box * b,Page * p,Image * im)246 drawrule(Box *b, Page *p, Image *im)
247 {
248 Rectangle r;
249 Irule *i;
250
251 i = ((Irule *)b->i);
252 r = rectsubpt(b->r, p->pos);
253 r.min.y += Space;
254 r.max.y -=Space;
255 draw(im, r, getcolor(i->color), nil, ZP);
256 }
257
258 static
259 void
drawimage(Box * b,Page * p,Image * im)260 drawimage(Box *b, Page *p, Image *im)
261 {
262 Rectangle r;
263 Cimage *ci;
264 Iimage *i;
265 Image *c;
266
267 if(b->i->tag==Iimagetag)
268 i = (Iimage *)b->i;
269 else
270 i = (Iimage *)((Iformfield *)b->i)->formfield->image;
271
272 ci = (Cimage *)i->aux;
273 if(ci==nil || ci->i==nil)
274 return;
275
276 r = rectsubpt(b->r, p->pos);
277 r.min.x += i->border + i->hspace;
278 r.min.y += i->border + i->vspace;
279 r.max.x -= i->border + i->hspace;
280 r.max.y -= i->border + i->vspace;
281
282 draw(im, r, ci->i, nil, ci->i->r.min);
283
284 if(i->border){
285 if(i->anchorid >= 0)
286 c = getcolor(p->doc->link);
287 else
288 c = display->black;
289
290 border(im, r, i->border, c, ZP);
291 }
292 }
293
294 static
295 void
drawtextfield(Image * im,Rectangle r,Iformfield * i)296 drawtextfield(Image *im, Rectangle r, Iformfield *i)
297 {
298 Formfield *ff;
299 Image *c[3];
300 Text *t;
301 Font *f;
302
303 r = insetrect(r, Space);
304 colarray(c, getcolor(Dark), getcolor(Light), display->white, 1);
305 rect3d(im, r, Border, c, ZP);
306 r = insetrect(r, Border+Margin);
307
308 if(i->aux == nil){
309 ff = i->formfield;
310 t = emalloc(sizeof(Text));
311 if(ff->ftype == Ftextarea)
312 t->what = Textarea;
313 else
314 t->what = Entry;
315 if(ff->ftype == Fpassword)
316 f = passfont;
317 else
318 f = getfont(WFont);
319 textinit(t, im, r, f, textcols);
320 if(ff->value!=nil){
321 textinsert(t, 0, ff->value, runestrlen(ff->value));
322 textsetselect(t, t->rs.nr, t->rs.nr);
323 }
324 if(t->what == Textarea)
325 textscrdraw(t);
326 i->aux = t;
327 }else
328 textresize(i->aux, im, r);
329 }
330
331 void
drawcheck(Image * im,Rectangle r,Formfield * f)332 drawcheck(Image *im, Rectangle r, Formfield *f)
333 {
334 Image *c[3];
335 Point pt;
336 int n;
337
338 if(f->flags & FFchecked)
339 colarray(c, getcolor(Dark), getcolor(Light), getcolor(Red), TRUE);
340 else
341 colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), FALSE);
342
343 if(f->ftype == Fradio){
344 n = Boxsize/2-1;
345 pt = addpt(r.min, Pt(n,n));
346 ellipse3d(im, pt, n, Border, c, ZP);
347 }else
348 rect3d(im, r, Border, c, ZP);
349 }
350
351 void
drawbutton(Image * im,Rectangle r,Formfield * f,int checked)352 drawbutton(Image *im, Rectangle r, Formfield *f, int checked)
353 {
354 Image *c[3];
355
356 r = insetrect(r, Space);
357 colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), checked);
358 rect3d(im, r, Border, c, ZP);
359 r.min.x += Border + Margin;
360 r.min.y += Border + Margin;
361 runestringbg(im, r.min, display->black, ZP, getfont(WFont), f->value, c[2], ZP);
362 }
363
364 void
drawselect(Image * im,Rectangle r,Iformfield * i)365 drawselect(Image *im, Rectangle r, Iformfield *i)
366 {
367 Formfield *f;
368 Image *c[3];
369
370 f = i->formfield;
371 if(f->options == nil)
372 return;
373 r = insetrect(r, Space);
374 colarray(c, getcolor(Dark), getcolor(Light), display->white, 1);
375 rect3d(im, r, Border, c, ZP);
376 r = insetrect(r, Border+Margin);
377 draw(im, r, textcols[HIGH], nil, ZP);
378 if(i->aux==nil){
379 i->aux = f->options->display;
380 i->formfield->value = erunestrdup(f->options->value);
381 }
382 runestring(im, r.min, display->black, ZP, getfont(WFont), i->aux);
383 }
384
385 /* Formfields are a special case */
386 static
387 void
drawformfield(Box * b,Page * p,Image * im)388 drawformfield(Box *b, Page *p, Image *im)
389 {
390 Formfield *f;
391 int type;
392
393 f = ((Iformfield *)b->i)->formfield;
394 type =f->ftype;
395 if(istextfield(b->i))
396 drawtextfield(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i);
397 else if(type==Fcheckbox || type==Fradio)
398 drawcheck(im, rectsubpt(b->r, p->pos), f);
399 else if(type==Fbutton || type==Freset || type==Fsubmit)
400 drawbutton(im, rectsubpt(b->r, p->pos), f, FALSE);
401 else if(type == Fimage)
402 drawimage(b, p, im);
403 else if(type == Fselect)
404 drawselect(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i);
405 }
406
407 static
408 void
drawnull(Box *,Page *,Image *)409 drawnull(Box *, Page *, Image *)
410 {
411 }
412
413 static
414 Page *
whichtarget1(Page * p,Rune * r)415 whichtarget1(Page *p, Rune *r)
416 {
417 Kidinfo *k;
418 Page *c, *ret;
419
420 k = p->kidinfo;
421 if(k && k->name && runestrcmp(k->name, r)==0)
422 return p;
423 for(c=p->child; c; c=c->next){
424 ret = whichtarget1(c, r);
425 if(ret)
426 return ret;
427 }
428 return nil;
429 }
430
431 static
432 Page *
whichtarget(Page * p,int t)433 whichtarget(Page *p, int t)
434 {
435 Page *r;
436
437 switch(t){
438 case FTblank:
439 case FTtop:
440 r = &p->w->page;
441 break;
442 case FTself:
443 r = p;
444 break;
445 case FTparent:
446 r = p->parent;
447 break;
448 default:
449 if(targetname(t) == L"?")
450 error("targetname");
451 r = whichtarget1(&p->w->page, targetname(t));
452 }
453
454 return r ? r: &p->w->page;
455 }
456
457 static
458 void
mouselink(Box * b,Page * p,int but)459 mouselink(Box *b, Page *p, int but)
460 {
461 Runestr rs;
462 Anchor *a;
463
464 /* eat mouse */
465 while(mousectl->buttons)
466 readmouse(mousectl);
467
468 if(b->i->anchorid < 0)
469 return;
470
471 /* binary search would be better */
472 for(a=p->doc->anchors; a!=nil; a=a->next)
473 if(a->index == b->i->anchorid)
474 break;
475
476 if(a==nil || a->href==nil)
477 return;
478
479 p = whichtarget(p, a->target);
480 rs.r = urlcombine(getbase(p), a->href);
481 if(rs.r == nil)
482 return;
483 rs.nr = runestrlen(rs.r);
484
485 if(but == 1)
486 pageget(p, &rs, nil, HGet, p==&p->w->page);
487 else if(but == 2)
488 textset(&p->w->status, rs.r, rs.nr);
489 else if(but == 3)
490 plumbrunestr(&rs, nil);
491 closerunestr(&rs);
492 }
493
494 static
495 void
submit(Page * p,Formfield * formfield,int subfl)496 submit(Page *p, Formfield *formfield, int subfl)
497 {
498 Formfield *f;
499 Form *form;
500 Runestr src, post;
501 Rune *x, *sep, *y, *z;
502
503 form = formfield->form;
504 x = erunestrdup(L"");
505 sep = L"";
506 for(f=form->fields; f!=nil; f=f->next){
507 if(f->ftype == Freset)
508 continue;
509 if((f->ftype==Fradio || f->ftype==Fcheckbox) && !(f->flags&FFchecked))
510 continue;
511 if(f->ftype==Fsubmit && (f!=formfield || !subfl))
512 continue;
513 if(f->value==nil || f->name==nil || runestrcmp(f->name, L"_no_name_submit_")==0)
514 continue;
515
516 z = ucvt(f->value);
517 y = runesmprint("%S%S%S=%S", x, sep, f->name, z);
518 free(z);
519 sep = L"&";
520 free(x);
521 x = y;
522 }
523 p = whichtarget(p, form->target);
524 y = urlcombine(getbase(p), form->action);
525
526 memset(&src, 0, sizeof(Runestr));
527 memset(&post, 0, sizeof(Runestr));
528 if(form->method == HGet){
529 if(y[runestrlen(y)-1] == L'?')
530 sep = L"";
531 else
532 sep = L"?";
533 src.r = runesmprint("%S%S%S",y, sep, x);
534 free(x);
535 free(y);
536 }else{
537 src.r = y;
538 post.r = x;
539 post.nr = runestrlen(x);
540 if(post.nr == 0){
541 free(post.r);
542 post.r = nil;
543 }
544 }
545 src.nr = runestrlen(src.r);
546 pageget(p, &src, &post, form->method, p==&p->w->page);
547 closerunestr(&src);
548 closerunestr(&post);
549 }
550
551 static
552 void
setradios(Formfield * formfield)553 setradios(Formfield *formfield)
554 {
555 Formfield *f;
556
557 for(f=formfield->form->fields; f!=nil; f=f->next)
558 if(f->ftype==Fradio && f!=formfield && runestrcmp(f->name, formfield->name)==0)
559 f->flags &=~FFchecked;
560 }
561
562 static
563 void
selectmouse(Box * b,Page * p,int but)564 selectmouse(Box *b, Page *p, int but)
565 {
566 Formfield *f;
567 Option *o;
568 Menu m;
569 char **item;
570 int i, n;
571
572 f = ((Iformfield *)b->i)->formfield;
573 n = 0;
574 item = nil;
575 for(o=f->options; o!=nil; o=o->next){
576 item = erealloc(item, ++n*sizeof(char *));
577 if(o->display)
578 item[n-1] = smprint("%S", o->display);
579 else
580 item[n-1] = estrdup("--");
581 }
582 if(item == nil)
583 return;
584
585 item[n] = 0;
586 m.item = item;
587 i = menuhit(but, mousectl, &m, nil);
588 if(i >= 0){
589 for(o=f->options; o!=nil; o=o->next, i--){
590 if(i == 0)
591 break;
592 }
593 ((Iformfield *)b->i)->aux = o->display;
594 drawselect(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
595 if(f->value != nil)
596 free(f->value);
597 f->value = erunestrdup(o->value);
598 }
599 for(i=0; i< n; i++)
600 free(item[i]);
601 // free(item);
602 }
603
604 static
605 void
mouseform(Box * b,Page * p,int but)606 mouseform(Box *b, Page *p, int but)
607 {
608 Rectangle r, cr;
609 Formfield *f;
610 Text *t;
611
612 f = ((Iformfield *)b->i)->formfield;
613 r = rectaddpt(rectsubpt(b->r, p->pos), p->r.min);
614 if(istextfield(b->i)){
615 cr = p->b->clipr;
616 replclipr(p->b, 0, p->r);
617 t = ((Iformfield *)b->i)->aux;
618 if(p->b != t->b)
619 drawtextfield(p->b, r, (Iformfield *)b->i);
620 textmouse(t, mouse->xy, but);
621 if(f->value)
622 free(f->value);
623 f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
624 replclipr(p->b, 0, cr);
625 return;
626 }
627
628 if(but != 1)
629 return;
630
631 if(f->ftype==Fselect){
632 selectmouse(b, p, but);
633 return;
634 }
635 if(f->ftype==Fsubmit || f->ftype==Fimage){
636 if(f->ftype == Fsubmit)
637 drawbutton(p->b, r, f, TRUE);
638 while(mouse->buttons == but)
639 readmouse(mousectl);
640 if(f->ftype == Fsubmit)
641 drawbutton(p->b, r, f, FALSE);
642 if(mouse->buttons==0 && ptinrect(mouse->xy, r))
643 submit(p, f, TRUE);
644 return;
645 }
646 if(f->ftype==Fradio || f->ftype==Fcheckbox){
647 if(f->flags&FFchecked){
648 if(f->ftype==Fcheckbox)
649 f->flags &=~FFchecked;
650 }else{
651 f->flags |= FFchecked;
652 }
653 if(f->ftype == Fradio)
654 setradios(f);
655 pageredraw(p);
656 }
657 }
658
659 static
660 void
keyform(Box * b,Page * p,Rune r)661 keyform(Box *b, Page *p, Rune r)
662 {
663 Rectangle cr;
664 Formfield *f;
665 Text *t;
666
667 f = ((Iformfield *)b->i)->formfield;
668 if(r==L'\n' && f->ftype==Ftext){
669 submit(p, f, FALSE);
670 return;
671 }
672 t = ((Iformfield *)b->i)->aux;
673 cr = p->b->clipr;
674 replclipr(p->b, 0, p->r);
675 if(t->b != p->b)
676 drawtextfield(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
677 texttype(t, r);
678 if(f->value)
679 free(f->value);
680 f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
681 replclipr(p->b, 0, cr);
682 }
683
684 void
boxinit(Box * b)685 boxinit(Box *b)
686 {
687 if(b->i->anchorid)
688 b->mouse = mouselink;
689 /* override mouselink for forms */
690 if(b->i->tag == Iformfieldtag){
691 b->mouse = mouseform;
692 if(istextfield(b->i))
693 b->key = keyform;
694 }
695 switch(b->i->tag){
696 case Itexttag:
697 b->draw = drawtext;
698 break;
699 case Iruletag:
700 b->draw = drawrule;
701 break;
702 case Iimagetag:
703 b->draw = drawimage;
704 break;
705 case Iformfieldtag:
706 b->draw = drawformfield;
707 break;
708 case Itabletag:
709 b->draw = drawtable;
710 break;
711 case Ifloattag:
712 b->draw = drawnull;
713 break;
714 case Ispacertag:
715 b->draw = drawnull;
716 }
717 }
718
719 Box *
boxalloc(Line * l,Item * i,Rectangle r)720 boxalloc(Line *l, Item *i, Rectangle r)
721 {
722 Box *b;
723
724 b = emalloc(sizeof(Box));
725 b->i = i;
726 b->r = r;
727 if(l->boxes == nil)
728 l->boxes = b;
729 else{
730 b->prev = l->lastbox;
731 l->lastbox->next = b;
732 }
733 l->lastbox = b;
734
735 return b;
736 }
737
738 Box *
pttobox(Line * l,Point xy)739 pttobox(Line *l, Point xy)
740 {
741 Box *b;
742
743 for(b=l->boxes; b!=nil; b=b->next)
744 if(ptinrect(xy, b->r))
745 return b;
746
747 return nil;
748 }
749
750 static
751 Line *
tbtoline(Itable * i,Point xy)752 tbtoline(Itable *i, Point xy)
753 {
754 Tablecell *c;
755
756 for(c=i->table->cells; c!=nil; c=c->next)
757 if(ptinrect(xy, c->lay->r))
758 return linewhich(c->lay, xy);
759
760 return nil;
761 }
762
763 Line *
linewhich(Lay * lay,Point xy)764 linewhich(Lay *lay, Point xy)
765 {
766 Line *l, *t;
767 Box *b;
768
769 t = nil;
770 for(l=lay->lines; l!=nil; l=l->next)
771 if(ptinrect(xy, l->r))
772 break;
773
774 if(l!=nil && l->hastable){
775 b = pttobox(l, xy);
776 if(b!=nil && b->i->tag==Itabletag)
777 t = tbtoline((Itable *)b->i, xy);
778 }
779 return t? t: l;
780 }
781
782 Box *
boxwhich(Lay * lay,Point xy)783 boxwhich(Lay *lay, Point xy)
784 {
785 Line *l;
786
787 l = linewhich(lay, xy);
788 if(l)
789 return pttobox(l, xy);
790
791 return nil;
792 }
793
794 static void justline1(Line *, int);
795
796 static
797 void
justlay(Lay * lay,int x)798 justlay(Lay *lay, int x)
799 {
800 Line *l;
801
802 lay->r.min.x += x;
803 lay->r.max.x += x;
804
805 for(l=lay->lines; l!=nil; l=l->next)
806 justline1(l, x);
807 }
808
809 static
810 void
justtable(Itable * i,int x)811 justtable(Itable *i, int x)
812 {
813 Tablecell *c;
814
815 for(c=i->table->cells; c!=nil; c=c->next)
816 justlay(c->lay, x);
817 }
818
819 static
820 void
justline1(Line * l,int x)821 justline1(Line *l, int x)
822 {
823 Box *b;
824
825 l->r.min.x += x;
826 l->r.max.x += x;
827 for(b=l->boxes; b!=nil; b=b->next){
828 if(b->i->tag == Itabletag)
829 justtable((Itable *)b->i, x);
830 b->r.min.x += x;
831 b->r.max.x += x;
832 }
833 }
834
835 static
836 void
justline(Lay * lay,Line * l)837 justline(Lay *lay, Line *l)
838 {
839
840 int w, x;
841
842 w = Dx(l->r);
843 if(w>0 && w<lay->width){
844 x = 0;
845 if(l->state & IFrjust)
846 x = lay->width - w;
847 else if(l->state & IFcjust)
848 x = lay->width/2 - w/2;
849 if(x > 0)
850 justline1(l, x);
851 }
852 }
853
854 static
855 void
newline(Lay * lay,int state)856 newline(Lay *lay, int state)
857 {
858 Line *l, *last;
859 int indent, nl;
860
861 last = lay->lastline;
862 if(lay->laying == TRUE)
863 justline(lay, last);
864
865 lay->r.max.x = max(lay->r.max.x, last->r.max.x);
866 lay->r.max.y = last->r.max.y;
867
868 indent = ((state&IFindentmask)>>IFindentshift) * Tabspace;
869 nl = (state & IFbrksp) ? 1 : 0;
870
871 l = emalloc(sizeof(Line));
872 l->state = state;
873 l->hastext = FALSE;
874 l->hastable = FALSE;
875 l->r.min.x = lay->r.min.x + indent;
876 l->r.min.y = last->r.max.y + font->height*nl;
877 l->r.max = l->r.min;
878 l->prev = last;
879 last->next = l;
880 lay->lastline = l;
881 }
882
883
884 static
885 void
layitem(Lay * lay,Item * i)886 layitem(Lay *lay, Item *i)
887 {
888 Rectangle r;
889 Line *l;
890 Box *b;
891
892 if(i->state&IFbrk || i->state&IFbrksp)
893 newline(lay, i->state);
894 else if(lay->lastline->r.max.x+i->width>lay->xwall && forceitem(i)==FALSE)
895 newline(lay, i->state);
896
897 l = lay->lastline;
898 r = Rect(l->r.max.x, l->r.min.y, l->r.max.x+i->width, l->r.min.y+i->height);
899 l->r.max.x = r.max.x;
900 if(l->r.max.y < r.max.y)
901 l->r.max.y = r.max.y;
902
903 if(i->tag == Ifloattag)
904 i = ((Ifloat *)i)->item;
905 if(i->tag == Itexttag)
906 l->hastext = TRUE;
907 else if(i->tag == Itabletag && lay->laying==TRUE){
908 laytable((Itable *)i, r);
909 l->hastable = TRUE;
910 }
911 b = boxalloc(l, i, r);
912 if(lay->laying)
913 boxinit(b);
914 }
915
916 static
917 void
linefix(Lay * lay)918 linefix(Lay *lay)
919 {
920 Line *l;
921
922 for(l=lay->lines; l!=nil; l=l->next){
923 l->r.min.x = lay->r.min.x;
924 l->r.max.x = lay->r.max.x;
925 }
926 }
927
928 Lay *
layitems(Item * items,Rectangle r,int laying)929 layitems(Item *items, Rectangle r, int laying)
930 {
931 Lay *lay;
932 Line *l;
933 Item *i;
934
935 lay = emalloc(sizeof(Lay));
936 lay->r.min = r.min;
937 lay->r.max = r.min;
938 lay->xwall = r.max.x;
939 lay->width = Dx(r);
940 lay->laying = laying;
941 l = emalloc(sizeof(Line));
942 l->r.min = lay->r.min;
943 l->r.max = lay->r.min;
944 l->state = IFbrk;
945 l->boxes = nil;
946 lay->lines = l;
947 lay->lastline = l;
948 lay->font = font;
949
950 for(i=items; i; i=i->next){
951 sizeitem(lay, i);
952 layitem(lay, i);
953 }
954 newline(lay, IFbrk);
955 if(laying)
956 linefix(lay);
957
958 return lay;
959 }
960
961 void
laypage(Page * p)962 laypage(Page *p)
963 {
964 settables(p);
965 layfree(p->lay);
966 p->lay = layitems(p->items, Rect(0,0,Dx(p->r),Dy(p->r)), TRUE);
967 p->lay->r.max.y = max(p->lay->r.max.y, Dy(p->r));
968 }
969
970 static
971 void
drawline(Page * p,Image * im,Line * l)972 drawline(Page *p, Image *im, Line *l)
973 {
974 Box *b;
975
976 for(b=l->boxes; b!=nil; b=b->next)
977 b->draw(b, p, im);
978 }
979
980 void
laydraw(Page * p,Image * im,Lay * lay)981 laydraw(Page *p, Image *im, Lay *lay)
982 {
983 Rectangle r;
984 Line *l;
985
986 r = rectaddpt(p->lay->r, p->pos);
987 for(l=lay->lines; l!=nil; l=l->next){
988 if(rectXrect(r, l->r))
989 drawline(p, im, l);
990 }
991 }
992
993 static
994 void
laytablefree(Table * t)995 laytablefree(Table *t)
996 {
997 Tablecell *c;
998
999 for(c=t->cells; c!=nil; c=c->next){
1000 layfree(c->lay);
1001 c->lay = nil;
1002 }
1003 }
1004
1005 void
layfree(Lay * lay)1006 layfree(Lay *lay)
1007 {
1008 Line *l, *nextline;
1009 Box *b, *nextbox;
1010 void **aux;
1011
1012 if(lay == nil)
1013 return;
1014
1015 for(l=lay->lines; l!=nil; l=nextline){
1016 for(b=l->boxes; b!=nil; b=nextbox){
1017 nextbox = b->next;
1018 if(b->i->tag==Iformfieldtag && istextfield(b->i)){
1019 aux = &((Iformfield *)b->i)->aux;
1020 if(*aux){
1021 textclose(*aux);
1022 free(*aux);
1023 }
1024 *aux = nil;
1025 }else if(b->i->tag == Itabletag)
1026 laytablefree(((Itable *)b->i)->table);
1027
1028 free(b);
1029 }
1030 nextline = l->next;
1031 free(l);
1032 }
1033 free(lay);
1034 }
1035
1036 void
laysnarf(Page * p,Lay * lay,Runestr * rs)1037 laysnarf(Page *p, Lay *lay, Runestr *rs)
1038 {
1039 Tablecell *c;
1040 Itext *i;
1041 Font *f;
1042 Line *l;
1043 Box *b;
1044 int q0, q1, n;
1045
1046 for(l=lay->lines; l!=nil; l=l->next) for(b=l->boxes; b!=nil; b=b->next){
1047 if(p->selecting && hasbrk(b->i->state)){
1048 rs->r = runerealloc(rs->r, rs->nr+2);
1049 rs->r[rs->nr++] = L'\n';
1050 rs->r[rs->nr] = L'\0';
1051 }
1052 if(b->i->tag==Itexttag){
1053 i = (Itext *)b->i;
1054 f = getfont(i->fnt);
1055 if(istextsel(p, b->r, &q0, &q1, i->s, f)){
1056 if(q1 == 0)
1057 q1 = runestrlen(i->s);
1058 n = q1-q0;
1059 if(n == 0)
1060 n = runestrlen(i->s);
1061 rs->r = runerealloc(rs->r, rs->nr+n+2);
1062 runemove(rs->r+rs->nr, i->s+q0, n);
1063 rs->nr += n;
1064 rs->r[rs->nr++] = L' ';
1065 rs->r[rs->nr] = L'\0';
1066 }
1067 }else if(b->i->tag == Itabletag)
1068 for(c=((Itable *)b->i)->table->cells; c!=nil; c=c->next)
1069 if(c->lay)
1070 laysnarf(p, c->lay, rs);
1071 }
1072 }
1073