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 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 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 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 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 78 sizecheck(Lay *, Iformfield *i) 79 { 80 i->width = Boxsize + Space; 81 i->height = Boxsize; 82 } 83 84 static 85 void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 409 drawnull(Box *, Page *, Image *) 410 { 411 } 412 413 static 414 Page * 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 * 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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