15 static void sizeitem(Lay *, Item *);
19 sizetext(Lay *lay, Itext *i)
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);
29 sizerule(Lay *lay, Irule *i)
31 i->width = lay->width;
32 i->height = Space + i->size + Space;
37 sizeimage(Lay *, Iimage *i)
41 ci = (Cimage *)i->aux;
47 getimage(ci, i->altrep);
50 i->width = Dx(ci->i->r) + i->border + i->hspace;
51 i->height = Dy(ci->i->r) + i->border + i->vspace;
56 sizetextfield(Lay *, Iformfield *i)
63 if(ff->ftype == Ftextarea){
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);
78 sizecheck(Lay *, Iformfield *i)
80 i->width = Boxsize + Space;
86 sizebutton(Lay *, Iformfield *i)
91 x = Margin + Border + Space;
93 i->width = runestringwidth(f, i->formfield->value) + 2*x + Space;
94 i->height = f->height + 2*x;
99 sizefimage(Lay *lay, Iformfield *i)
103 ii = (Iimage *)i->formfield->image;
105 i->width = ii->width;
106 i->height = ii->height;
111 sizeselect(Lay *, Iformfield *i)
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;
123 i->height = f->height+2*x;
128 sizeformfield(Lay *lay, Iformfield *i)
132 type = i->formfield->ftype;
134 if(type==Ftext || type==Ftextarea || type==Fpassword)
135 sizetextfield(lay, i);
136 else if(type==Fcheckbox || type==Fradio)
138 else if(type==Fbutton || type==Freset || type==Fsubmit)
140 else if(type == Fimage)
142 else if(type == Fselect)
148 sizetable(Lay *lay, Itable *i)
150 tablesize(i->table, lay->width);
151 i->width = i->table->totw;
152 i->height = i->table->toth;
157 sizefloat(Lay *lay, Ifloat *i)
159 sizeitem(lay, i->item);
160 i->width = i->item->width;
161 i->height = i->item->height;
166 sizespacer(Lay *lay, Ispacer *i)
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;
177 sizeitem(Lay *lay, Item *i)
182 sizetext(lay, (Itext *)i);
185 sizerule(lay, (Irule *)i);
188 sizeimage(lay, (Iimage *)i);
191 sizeformfield(lay, (Iformfield *)i);
194 sizetable(lay, (Itable *)i);
197 sizefloat(lay, (Ifloat *)i);
200 sizespacer(lay, (Ispacer *)i);
203 error("can't happen");
209 drawtext(Box *b, Page *p, Image *im)
218 r = rectsubpt(b->r, p->pos);
221 if(istextsel(p, b->r, &q0, &q1, i->s, f)){
224 r1.min.x += runestringnwidth(f, i->s, q0);
226 r1.max.x = r1.min.x + runestringnwidth(f, i->s+q0, q1-q0);
227 draw(im, r1, textcols[HIGH], nil, ZP);
230 runestringbg(im, r.min, c, ZP, f, i->s, im, addpt(r.min, im->r.min));
236 r.min.y += f->height/2;
238 r.min.y +=f->height-1;
240 pt.x += runestringwidth(f, i->s);
241 line(im, r.min, pt, Enddisc, Enddisc, 0, c, ZP);
246 drawrule(Box *b, Page *p, Image *im)
252 r = rectsubpt(b->r, p->pos);
255 draw(im, r, getcolor(i->color), nil, ZP);
260 drawimage(Box *b, Page *p, Image *im)
267 if(b->i->tag==Iimagetag)
270 i = (Iimage *)((Iformfield *)b->i)->formfield->image;
272 ci = (Cimage *)i->aux;
273 if(ci==nil || ci->i==nil)
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;
282 draw(im, r, ci->i, nil, ci->i->r.min);
286 c = getcolor(p->doc->link);
290 border(im, r, i->border, c, ZP);
296 drawtextfield(Image *im, Rectangle r, Iformfield *i)
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);
310 t = emalloc(sizeof(Text));
311 if(ff->ftype == Ftextarea)
315 if(ff->ftype == Fpassword)
319 textinit(t, im, r, f, textcols);
321 textinsert(t, 0, ff->value, runestrlen(ff->value));
322 textsetselect(t, t->rs.nr, t->rs.nr);
324 if(t->what == Textarea)
328 textresize(i->aux, im, r);
332 drawcheck(Image *im, Rectangle r, Formfield *f)
338 if(f->flags & FFchecked)
339 colarray(c, getcolor(Dark), getcolor(Light), getcolor(Red), TRUE);
341 colarray(c, getcolor(Dark), getcolor(Light), getcolor(Back), FALSE);
343 if(f->ftype == Fradio){
345 pt = addpt(r.min, Pt(n,n));
346 ellipse3d(im, pt, n, Border, c, ZP);
348 rect3d(im, r, Border, c, ZP);
352 drawbutton(Image *im, Rectangle r, Formfield *f, int checked)
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);
365 drawselect(Image *im, Rectangle r, Iformfield *i)
371 if(f->options == nil)
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);
379 i->aux = f->options->display;
380 i->formfield->value = erunestrdup(f->options->value);
382 runestring(im, r.min, display->black, ZP, getfont(WFont), i->aux);
385 /* Formfields are a special case */
388 drawformfield(Box *b, Page *p, Image *im)
393 f = ((Iformfield *)b->i)->formfield;
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)
403 else if(type == Fselect)
404 drawselect(im, rectsubpt(b->r, p->pos), (Iformfield *)b->i);
409 drawnull(Box *, Page *, Image *)
415 whichtarget1(Page *p, Rune *r)
421 if(k && k->name && runestrcmp(k->name, r)==0)
423 for(c=p->child; c; c=c->next){
424 ret = whichtarget1(c, r);
433 whichtarget(Page *p, int t)
449 if(targetname(t) == L"?")
451 r = whichtarget1(&p->w->page, targetname(t));
454 return r ? r: &p->w->page;
459 mouselink(Box *b, Page *p, int but)
465 while(mousectl->buttons)
468 if(b->i->anchorid < 0)
471 /* binary search would be better */
472 for(a=p->doc->anchors; a!=nil; a=a->next)
473 if(a->index == b->i->anchorid)
476 if(a==nil || a->href==nil)
479 p = whichtarget(p, a->target);
480 rs.r = urlcombine(getbase(p), a->href);
483 rs.nr = runestrlen(rs.r);
486 pageget(p, &rs, nil, HGet, p==&p->w->page);
488 textset(&p->w->status, rs.r, rs.nr);
490 plumbrunestr(&rs, nil);
496 submit(Page *p, Formfield *formfield, int subfl)
501 Rune *x, *sep, *y, *z;
503 form = formfield->form;
504 x = erunestrdup(L"");
506 for(f=form->fields; f!=nil; f=f->next){
507 if(f->ftype == Freset)
509 if((f->ftype==Fradio || f->ftype==Fcheckbox) && !(f->flags&FFchecked))
511 if(f->ftype==Fsubmit && (f!=formfield || !subfl))
513 if(f->value==nil || f->name==nil || runestrcmp(f->name, L"_no_name_submit_")==0)
517 y = runesmprint("%S%S%S=%S", x, sep, f->name, z);
523 p = whichtarget(p, form->target);
524 y = urlcombine(getbase(p), form->action);
526 memset(&src, 0, sizeof(Runestr));
527 memset(&post, 0, sizeof(Runestr));
528 if(form->method == HGet){
529 if(y[runestrlen(y)-1] == L'?')
533 src.r = runesmprint("%S%S%S",y, sep, x);
539 post.nr = runestrlen(x);
545 src.nr = runestrlen(src.r);
546 pageget(p, &src, &post, form->method, p==&p->w->page);
553 setradios(Formfield *formfield)
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;
564 selectmouse(Box *b, Page *p, int but)
572 f = ((Iformfield *)b->i)->formfield;
575 for(o=f->options; o!=nil; o=o->next){
576 item = erealloc(item, ++n*sizeof(char *));
578 item[n-1] = smprint("%S", o->display);
580 item[n-1] = estrdup("--");
587 i = menuhit(but, mousectl, &m, nil);
589 for(o=f->options; o!=nil; o=o->next, i--){
593 ((Iformfield *)b->i)->aux = o->display;
594 drawselect(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
597 f->value = erunestrdup(o->value);
606 mouseform(Box *b, Page *p, int but)
612 f = ((Iformfield *)b->i)->formfield;
613 r = rectaddpt(rectsubpt(b->r, p->pos), p->r.min);
614 if(istextfield(b->i)){
616 replclipr(p->b, 0, p->r);
617 t = ((Iformfield *)b->i)->aux;
619 drawtextfield(p->b, r, (Iformfield *)b->i);
620 textmouse(t, mouse->xy, but);
623 f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
624 replclipr(p->b, 0, cr);
631 if(f->ftype==Fselect){
632 selectmouse(b, p, but);
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)
640 if(f->ftype == Fsubmit)
641 drawbutton(p->b, r, f, FALSE);
642 if(mouse->buttons==0 && ptinrect(mouse->xy, r))
646 if(f->ftype==Fradio || f->ftype==Fcheckbox){
647 if(f->flags&FFchecked){
648 if(f->ftype==Fcheckbox)
649 f->flags &=~FFchecked;
651 f->flags |= FFchecked;
653 if(f->ftype == Fradio)
661 keyform(Box *b, Page *p, Rune r)
667 f = ((Iformfield *)b->i)->formfield;
668 if(r==L'\n' && f->ftype==Ftext){
672 t = ((Iformfield *)b->i)->aux;
674 replclipr(p->b, 0, p->r);
676 drawtextfield(p->b, rectaddpt(rectsubpt(b->r, p->pos), p->r.min), (Iformfield *)b->i);
680 f->value = runesmprint("%.*S", t->rs.nr, t->rs.r);
681 replclipr(p->b, 0, cr);
688 b->mouse = mouselink;
689 /* override mouselink for forms */
690 if(b->i->tag == Iformfieldtag){
691 b->mouse = mouseform;
692 if(istextfield(b->i))
706 b->draw = drawformfield;
720 boxalloc(Line *l, Item *i, Rectangle r)
724 b = emalloc(sizeof(Box));
730 b->prev = l->lastbox;
731 l->lastbox->next = b;
734 setmalloctag(b, getcallerpc(&l));
739 pttobox(Line *l, Point xy)
743 for(b=l->boxes; b!=nil; b=b->next)
744 if(ptinrect(xy, b->r))
752 tbtoline(Itable *i, Point xy)
756 for(c=i->table->cells; c!=nil; c=c->next)
757 if(ptinrect(xy, c->lay->r))
758 return linewhich(c->lay, xy);
764 linewhich(Lay *lay, Point xy)
770 for(l=lay->lines; l!=nil; l=l->next)
771 if(ptinrect(xy, l->r))
774 if(l!=nil && l->hastable){
776 if(b!=nil && b->i->tag==Itabletag)
777 t = tbtoline((Itable *)b->i, xy);
783 boxwhich(Lay *lay, Point xy)
787 l = linewhich(lay, xy);
789 return pttobox(l, xy);
794 static void justline1(Line *, int);
798 justlay(Lay *lay, int x)
805 for(l=lay->lines; l!=nil; l=l->next)
811 justtable(Itable *i, int x)
815 for(c=i->table->cells; c!=nil; c=c->next)
821 justline1(Line *l, int x)
827 for(b=l->boxes; b!=nil; b=b->next){
828 if(b->i->tag == Itabletag)
829 justtable((Itable *)b->i, x);
837 justline(Lay *lay, Line *l)
843 if(w>0 && w<lay->width){
845 if(l->state & IFrjust)
847 else if(l->state & IFcjust)
848 x = lay->width/2 - w/2;
856 newline(Lay *lay, int state)
861 last = lay->lastline;
862 if(lay->laying == TRUE)
865 lay->r.max.x = max(lay->r.max.x, last->r.max.x);
866 lay->r.max.y = last->r.max.y;
868 indent = ((state&IFindentmask)>>IFindentshift) * Tabspace;
869 nl = (state & IFbrksp) ? 1 : 0;
871 l = emalloc(sizeof(Line));
875 l->r.min.x = lay->r.min.x + indent;
876 l->r.min.y = last->r.max.y + font->height*nl;
886 layitem(Lay *lay, Item *i)
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);
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;
903 if(i->tag == Ifloattag)
904 i = ((Ifloat *)i)->item;
905 if(i->tag == Itexttag)
907 else if(i->tag == Itabletag && lay->laying==TRUE){
908 laytable((Itable *)i, r);
911 b = boxalloc(l, i, r);
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;
929 layitems(Item *items, Rectangle r, int laying)
935 lay = emalloc(sizeof(Lay));
938 lay->xwall = r.max.x;
940 lay->laying = laying;
941 l = emalloc(sizeof(Line));
942 l->r.min = lay->r.min;
943 l->r.max = lay->r.min;
950 for(i=items; i; i=i->next){
967 p->lay = layitems(p->items, Rect(0,0,Dx(p->r),Dy(p->r)), TRUE);
968 p->lay->r.max.y = max(p->lay->r.max.y, Dy(p->r));
973 drawline(Page *p, Image *im, Line *l)
977 for(b=l->boxes; b!=nil; b=b->next)
982 laydraw(Page *p, Image *im, Lay *lay)
987 r = rectaddpt(p->lay->r, p->pos);
988 for(l=lay->lines; l!=nil; l=l->next){
989 if(rectXrect(r, l->r))
996 laytablefree(Table *t)
1000 for(c=t->cells; c!=nil; c=c->next){
1016 for(l=lay->lines; l!=nil; l=nextline){
1017 for(b=l->boxes; b!=nil; b=nextbox){
1019 if(lay->laying==TRUE){
1020 if(b->i->tag==Iformfieldtag && istextfield(b->i)){
1021 aux = &((Iformfield *)b->i)->aux;
1027 }else if(b->i->tag == Itabletag)
1028 laytablefree(((Itable *)b->i)->table);
1039 laysnarf(Page *p, Lay *lay, Runestr *rs)
1048 for(l=lay->lines; l!=nil; l=l->next) for(b=l->boxes; b!=nil; b=b->next){
1049 if(p->selecting && hasbrk(b->i->state)){
1050 rs->r = runerealloc(rs->r, rs->nr+2);
1051 rs->r[rs->nr++] = L'\n';
1052 rs->r[rs->nr] = L'\0';
1054 if(b->i->tag==Itexttag){
1056 f = getfont(i->fnt);
1057 if(istextsel(p, b->r, &q0, &q1, i->s, f)){
1059 q1 = runestrlen(i->s);
1062 n = runestrlen(i->s);
1063 rs->r = runerealloc(rs->r, rs->nr+n+2);
1064 runemove(rs->r+rs->nr, i->s+q0, n);
1066 rs->r[rs->nr++] = L' ';
1067 rs->r[rs->nr] = L'\0';
1069 }else if(b->i->tag == Itabletag)
1070 for(c=((Itable *)b->i)->table->cells; c!=nil; c=c->next)
1072 laysnarf(p, c->lay, rs);