1 #include <lib9.h> 2 #include <kernel.h> 3 #include "interp.h" 4 #include "isa.h" 5 #include "runt.h" 6 #include "prefabmod.h" 7 #include "draw.h" 8 #include "drawif.h" 9 #include "prefab.h" 10 #include "raise.h" 11 12 uchar elementmap[] = Prefab_Element_map; 13 uchar compoundmap[] = Prefab_Compound_map; 14 uchar layoutmap[] = Prefab_Layout_map; 15 16 void freeprefabcompound(Heap*, int); 17 18 Type* TCompound; 19 Type* TElement; 20 Type* TLayout; 21 22 /* Infrared remote buttons known to Compound_select */ 23 enum 24 { 25 IRFF = 14, 26 IRRew = 15, 27 IRUp = 16, 28 IRDn = 17, 29 IRSelect = 18, 30 IREnter = 20, 31 }; 32 33 void 34 prefabmodinit(void) 35 { 36 TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap)); 37 TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap)); 38 TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap)); 39 builtinmod("$Prefab", Prefabmodtab, Prefabmodlen); 40 } 41 42 PElement* 43 checkelement(Prefab_Element *de) 44 { 45 PElement *pe; 46 47 pe = lookupelement(de); 48 if(pe == H) 49 error(exType); 50 return pe; 51 } 52 53 PCompound* 54 checkcompound(Prefab_Compound *de) 55 { 56 PCompound *pe; 57 58 pe = lookupcompound(de); 59 if(pe == H) 60 error(exType); 61 return pe; 62 } 63 64 PElement* 65 lookupelement(Prefab_Element *de) 66 { 67 PElement *pe; 68 if(de == H) 69 return H; 70 if(D2H(de)->t != TElement) 71 return H; 72 pe = (PElement*)de; 73 if(de->kind!=pe->pkind || de->kids!=pe->first) 74 return H; 75 return pe; 76 } 77 78 PCompound* 79 lookupcompound(Prefab_Compound *dc) 80 { 81 if(dc == H) 82 return H; 83 if(D2H(dc)->t != TCompound) 84 return H; 85 return (PCompound*)dc; 86 } 87 88 void 89 freeprefabcompound(Heap *h, int swept) 90 { 91 Image *i; 92 Prefab_Compound *d; 93 PCompound *pc; 94 95 d = H2D(Prefab_Compound*, h); 96 pc = lookupcompound(d); 97 /* disconnect compound from image refresh daemon */ 98 i = lookupimage(pc->c.image); 99 if(i != nil) 100 delrefresh(i); 101 if(!swept && TCompound->np) 102 freeptrs(d, TCompound); 103 /* header will be freed by caller */ 104 } 105 106 static 107 PElement* 108 findtag(PElement *pelem, char *tag) 109 { 110 PElement *pe, *t; 111 List *l; 112 113 if(pelem==H || tag[0]==0) 114 return pelem; 115 for(l=pelem->first; l!=H; l=l->tail){ 116 pe = *(PElement**)l->data; 117 if(strcmp(tag, string2c(pe->e.tag)) == 0) 118 return pe; 119 else if(pe->pkind==EHorizontal || pe->pkind==EVertical){ 120 t = findtag(pe, tag); 121 if(t != H) 122 return t; 123 } 124 } 125 return H; 126 } 127 128 int 129 badenviron(Prefab_Environ *env, int err) 130 { 131 Prefab_Style *s; 132 133 if(env == H) 134 goto bad; 135 s = env->style; 136 if(s == H) 137 goto bad; 138 if(s->titlefont==H || s->textfont==H) 139 goto bad; 140 if(s->elemcolor==H || s->edgecolor==H) 141 goto bad; 142 if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H) 143 goto bad; 144 return 0; 145 bad: 146 if(err) 147 error(exType); 148 return 1; 149 } 150 151 void 152 Element_iconseparator(void *fp, int kind) 153 { 154 F_Element_icon *f; 155 PElement *e; 156 Image *icon; 157 int locked; 158 159 f = fp; 160 badenviron(f->env, 1); 161 checkimage(f->mask); 162 icon = checkimage(f->icon); 163 locked = lockdisplay(icon->display); 164 destroy(*f->ret); 165 *f->ret = H; 166 if(kind == ESeparator) 167 e = separatorelement(f->env, f->r, f->icon, f->mask); 168 else 169 e = iconelement(f->env, f->r, f->icon, f->mask); 170 *f->ret = (Prefab_Element*)e; 171 if(locked) 172 unlockdisplay(icon->display); 173 } 174 175 void 176 Element_icon(void *fp) 177 { 178 Element_iconseparator(fp, EIcon); 179 } 180 181 void 182 Element_separator(void *fp) 183 { 184 Element_iconseparator(fp, ESeparator); 185 } 186 187 void 188 Element_text(void *fp) 189 { 190 F_Element_text *f; 191 PElement *pelem; 192 Display *disp; 193 int locked; 194 195 f = fp; 196 badenviron(f->env, 1); 197 if(f->kind!=EText && f->kind!=ETitle) 198 return; 199 200 disp = checkscreen(f->env->screen)->display; 201 locked = lockdisplay(disp); 202 destroy(*f->ret); 203 *f->ret = H; 204 pelem = textelement(f->env, f->text, f->r, f->kind); 205 *f->ret = (Prefab_Element*)pelem; 206 if(locked) 207 unlockdisplay(disp); 208 } 209 210 void 211 Element_layout(void *fp) 212 { 213 F_Element_layout *f; 214 PElement *pelem; 215 Display *disp; 216 int locked; 217 218 f = fp; 219 badenviron(f->env, 1); 220 if(f->kind!=EText && f->kind!=ETitle) 221 return; 222 223 disp = checkscreen(f->env->screen)->display; 224 locked = lockdisplay(disp); 225 destroy(*f->ret); 226 *f->ret = H; 227 pelem = layoutelement(f->env, f->lay, f->r, f->kind); 228 *f->ret = (Prefab_Element*)pelem; 229 if(locked) 230 unlockdisplay(disp); 231 } 232 233 void 234 Element_elist(void *fp) 235 { 236 F_Element_elist *f; 237 PElement *pelist; 238 Display *disp; 239 int locked; 240 241 f = fp; 242 if(f->elem != H) 243 checkelement(f->elem); 244 badenviron(f->env, 1); 245 if(f->kind!=EHorizontal && f->kind!=EVertical) 246 return; 247 248 disp = checkscreen(f->env->screen)->display; 249 locked = lockdisplay(disp); 250 destroy(*f->ret); 251 *f->ret = H; 252 pelist = elistelement(f->env, f->elem, f->kind); 253 *f->ret = (Prefab_Element*)pelist; 254 if(locked) 255 unlockdisplay(disp); 256 } 257 258 void 259 Element_append(void *fp) 260 { 261 F_Element_append *f; 262 263 f = fp; 264 *f->ret = 0; 265 if(f->elist==H || f->elem==H) 266 return; 267 268 badenviron(f->elist->environ, 1); 269 checkelement(f->elist); 270 checkelement(f->elem); 271 272 if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical) 273 return; 274 275 if(appendelist(f->elist, f->elem) != H) 276 *f->ret = 1; 277 } 278 279 void 280 Element_adjust(void *fp) 281 { 282 F_Element_adjust *f; 283 Display *disp; 284 int locked; 285 286 f = fp; 287 checkelement(f->elem); 288 badenviron(f->elem->environ, 1); 289 disp = checkscreen(f->elem->environ->screen)->display; 290 locked = lockdisplay(disp); 291 adjustelement(f->elem, f->equal, f->dir); 292 if(locked) 293 unlockdisplay(disp); 294 } 295 296 void 297 Element_show(void *fp) 298 { 299 F_Element_show *f; 300 Display *disp; 301 int locked; 302 303 f = fp; 304 checkelement(f->elem); 305 checkelement(f->elist); 306 badenviron(f->elem->environ, 1); 307 disp = checkscreen(f->elem->environ->screen)->display; 308 locked = lockdisplay(disp); 309 *f->ret = showelement(f->elist, f->elem); 310 if(locked) 311 unlockdisplay(disp); 312 } 313 314 void 315 Element_clip(void *fp) 316 { 317 F_Element_clip *f; 318 Rectangle r; 319 Display *disp; 320 int locked; 321 322 f = fp; 323 checkelement(f->elem); 324 badenviron(f->elem->environ, 1); 325 R2R(r, f->r); 326 disp = checkscreen(f->elem->environ->screen)->display; 327 locked = lockdisplay(disp); 328 clipelement(f->elem, r); 329 if(locked) 330 unlockdisplay(disp); 331 } 332 333 void 334 Element_translatescroll(void *fp, int trans) 335 { 336 F_Element_scroll *f; 337 Point d; 338 Display *disp; 339 int locked, moved; 340 341 f = fp; 342 checkelement(f->elem); 343 badenviron(f->elem->environ, 1); 344 P2P(d, f->d); 345 disp = checkscreen(f->elem->environ->screen)->display; 346 locked = lockdisplay(disp); 347 if(trans) 348 translateelement(f->elem, d); 349 else{ 350 moved = 0; 351 scrollelement(f->elem, d, &moved); 352 } 353 if(locked) 354 unlockdisplay(disp); 355 } 356 357 void 358 Element_scroll(void *fp) 359 { 360 Element_translatescroll(fp, 0); 361 } 362 363 void 364 Element_translate(void *fp) 365 { 366 Element_translatescroll(fp, 1); 367 } 368 369 void 370 Compound_iconbox(void *fp) 371 { 372 F_Compound_iconbox *f; 373 Image *icon; 374 int locked; 375 PCompound *pc; 376 377 f = fp; 378 badenviron(f->env, 1); 379 checkimage(f->mask); 380 icon = checkimage(f->icon); 381 locked = lockdisplay(icon->display); 382 destroy(*f->ret); 383 *f->ret = H; 384 pc = iconbox(f->env, f->p, f->title, f->icon, f->mask); 385 *f->ret = &pc->c; 386 if(locked) 387 unlockdisplay(icon->display); 388 } 389 390 void 391 Compound_textbox(void *fp) 392 { 393 F_Compound_textbox *f; 394 Display *disp; 395 int locked; 396 PCompound *pc; 397 398 f = fp; 399 badenviron(f->env, 1); 400 disp = checkscreen(f->env->screen)->display; 401 locked = lockdisplay(disp); 402 destroy(*f->ret); 403 *f->ret = H; 404 pc = textbox(f->env, f->r, f->title, f->text); 405 *f->ret = &pc->c; 406 if(locked) 407 unlockdisplay(disp); 408 } 409 410 void 411 Compound_layoutbox(void *fp) 412 { 413 F_Compound_layoutbox *f; 414 Display *disp; 415 int locked; 416 PCompound *pc; 417 418 f = fp; 419 badenviron(f->env, 1); 420 disp = checkscreen(f->env->screen)->display; 421 locked = lockdisplay(disp); 422 destroy(*f->ret); 423 *f->ret = H; 424 pc = layoutbox(f->env, f->r, f->title, f->lay); 425 *f->ret = &pc->c; 426 if(locked) 427 unlockdisplay(disp); 428 } 429 430 void 431 Compound_box(void *fp) 432 { 433 F_Compound_box *f; 434 Display *disp; 435 int locked; 436 PCompound *pc; 437 438 f = fp; 439 badenviron(f->env, 1); 440 if(f->title != H) 441 checkelement(f->title); 442 checkelement(f->elist); 443 disp = checkscreen(f->env->screen)->display; 444 locked = lockdisplay(disp); 445 destroy(*f->ret); 446 *f->ret = H; 447 pc = box(f->env, f->p, f->title, f->elist); 448 *f->ret = &pc->c; 449 if(locked) 450 unlockdisplay(disp); 451 } 452 453 void 454 Compound_draw(void *fp) 455 { 456 F_Compound_draw *f; 457 PCompound *pc; 458 int locked; 459 460 f = fp; 461 if(f->comp == H) 462 return; 463 pc = checkcompound(f->comp); 464 badenviron(pc->c.environ, 1); 465 locked = lockdisplay(pc->display); 466 drawcompound(&pc->c); 467 flushimage(pc->display, 1); 468 if(locked) 469 unlockdisplay(pc->display); 470 } 471 472 void 473 Compound_redraw(void *fp) 474 { 475 F_Compound_redraw *f; 476 PCompound *pc; 477 Image *i; 478 int locked; 479 480 f = fp; 481 if(f->comp == H) 482 return; 483 pc = checkcompound(f->comp); 484 badenviron(pc->c.environ, 1); 485 i = checkimage(pc->c.image); 486 locked = lockdisplay(pc->display); 487 redrawcompound(i, IRECT(f->r), &pc->c); 488 flushimage(pc->display, 1); 489 if(locked) 490 unlockdisplay(pc->display); 491 } 492 493 static 494 PElement* 495 pelement(Prefab_Compound *comp, Prefab_Element *elem) 496 { 497 PElement *pe; 498 499 if(comp == H) 500 return H; 501 checkcompound(comp); 502 badenviron(comp->environ, 1); 503 pe = lookupelement(elem); 504 return pe; 505 } 506 507 void 508 Compound_highlight(void *fp) 509 { 510 F_Compound_highlight *f; 511 PCompound *pc; 512 PElement *pe; 513 Image *i; 514 int locked; 515 516 f = fp; 517 pe = pelement(f->comp, f->elem); 518 if(pe == H) 519 return; 520 pc = (PCompound*)f->comp; 521 i = checkimage(pc->c.image); 522 locked = lockdisplay(pc->display); 523 highlightelement(&pe->e, i, &pc->c, f->on); 524 flushimage(pc->display, 1); 525 if(locked) 526 unlockdisplay(pc->display); 527 } 528 529 void 530 Compound_scroll(void *fp) 531 { 532 F_Compound_scroll *f; 533 PCompound *pc; 534 PElement *pe; 535 int locked; 536 Image *i; 537 int moved; 538 539 f = fp; 540 pe = pelement(f->comp, f->elem); 541 if(pe == H) 542 return; 543 pc = (PCompound*)f->comp; 544 i = checkimage(pc->c.image); 545 locked = lockdisplay(pc->display); 546 moved = 0; 547 scrollelement(&pe->e, IPOINT(f->d), &moved); 548 if(moved){ 549 drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0); 550 flushimage(pc->display, 1); 551 } 552 if(locked) 553 unlockdisplay(pc->display); 554 } 555 556 void 557 Compound_show(void *fp) 558 { 559 F_Compound_show *f; 560 PCompound *pc; 561 PElement *pe; 562 int locked; 563 564 f = fp; 565 pe = pelement(f->comp, f->elem); 566 if(pe == H) 567 return; 568 pc = (PCompound*)f->comp; 569 locked = lockdisplay(pc->display); 570 *f->ret = showelement(pc->c.contents, &pe->e); 571 flushimage(pc->display, 1); 572 if(locked) 573 unlockdisplay(pc->display); 574 } 575 576 static 577 PElement* 578 element(PElement *plist, int index, int *ip) 579 { 580 int i; 581 PElement *pe; 582 List *l; 583 584 i = 0; 585 pe = H; 586 for(l=plist->first; l!=H; l=l->tail){ 587 pe = *(PElement**)l->data; 588 if(pe->pkind == ESeparator) 589 continue; 590 if(i == index) 591 break; 592 i++; 593 } 594 if(ip) 595 *ip = i; 596 if(l == H) 597 return H; 598 return pe; 599 } 600 601 static 602 int 603 wrapelement(PElement *plist, int index, int ntag) 604 { 605 int i, wrap; 606 607 if(ntag > 0){ 608 if(index < 0) 609 return ntag-1; 610 if(index >= ntag) 611 return 0; 612 return index; 613 } 614 wrap = 1; 615 if(index < 0){ 616 index = 1000000; /* will seek to end */ 617 wrap = 0; 618 } 619 if(element(plist, index, &i)==H && index!=0){ 620 if(wrap) /* went off end; wrap to beginning */ 621 return wrapelement(plist, 0, 0); 622 if(i > 0) 623 --i; 624 } 625 return i; 626 } 627 628 void 629 dohighlight(PCompound *pc, PElement *list, PElement *pe, int on) 630 { 631 Image *i; 632 633 /* see if we need to scroll */ 634 i = lookupimage(pc->c.image); 635 if(i == nil) 636 return; 637 if(on && showelement(&list->e, &pe->e)) 638 redrawcompound(i, IRECT(pc->c.contents->r), &pc->c); 639 highlightelement(&pe->e, i, &pc->c, on); 640 } 641 642 void 643 highlight(PCompound *pc, PElement *list, int index, int on) 644 { 645 dohighlight(pc, list, element(list, index, nil), on); 646 } 647 648 static 649 PElement** 650 tags(PElement *pelem, int *ntag) 651 { 652 int n, nalloc, nn; 653 List *l; 654 PElement *pe, **tagged, **ntagged; 655 656 n = 0; 657 nalloc = 0; 658 tagged = nil; 659 *ntag = 0; 660 for(l=pelem->first; l!=H; l=l->tail){ 661 pe = *(PElement**)l->data; 662 if(pe->e.tag != H){ 663 if(nalloc == n){ 664 nalloc += 10; 665 tagged = realloc(tagged, nalloc*sizeof(PElement*)); 666 if(tagged == nil) 667 return nil; 668 } 669 tagged[n++] = pe; 670 }else if(pe->pkind==EHorizontal || pe->pkind==EVertical){ 671 ntagged = tags(pe, &nn); 672 if(nn > 0){ 673 if(nalloc < n+nn){ 674 nalloc = n+nn+10; 675 tagged = realloc(tagged, nalloc*sizeof(PElement*)); 676 if(tagged == nil){ 677 free(ntagged); 678 return nil; 679 } 680 } 681 memmove(tagged+n, ntagged, nn*sizeof(PElement*)); 682 free(ntagged); 683 n += nn; 684 } 685 } 686 } 687 *ntag = n; 688 return tagged; 689 } 690 691 void 692 doselect(void *fp, int dotags) 693 { 694 F_Compound_select *f; 695 PCompound *pc; 696 PElement *pe; 697 WORD *val; 698 List *l; 699 Prefab_Element *t; 700 int i, lasti, ntag; 701 PElement **tagged; 702 int locked; 703 704 f = fp; 705 pc = checkcompound(f->comp); 706 pe = lookupelement(f->elem); 707 if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){ 708 Bad: 709 destroy(f->ret->t2); 710 f->ret->t0 = 9999; 711 f->ret->t1 = 0; 712 f->ret->t2 = H; 713 return; 714 } 715 ntag = 0; 716 tagged = 0; 717 /* check at least one selectable item */ 718 if(dotags){ 719 tagged = tags(pe, &ntag); 720 if(ntag > 0) 721 goto OK; 722 }else 723 for(l=pe->first; l!=H; l=l->tail){ 724 t = *(Prefab_Element**)l->data; 725 if(t->kind != ESeparator) 726 goto OK; 727 } 728 goto Bad; 729 730 OK: 731 i = f->i; 732 i = wrapelement(pe, i, ntag); 733 lasti = i; 734 locked = lockdisplay(pc->display); 735 if(dotags) 736 dohighlight(pc, pe, tagged[i], 1); 737 else 738 highlight(pc, pe, i, 1); 739 /* val must be in shared memory, but stacks not shared */ 740 val = malloc(sizeof(WORD)); 741 if(val == nil) 742 goto Bad; 743 for(;;){ 744 if(lasti != i){ 745 if(dotags){ 746 dohighlight(pc, pe, tagged[lasti], 0); 747 dohighlight(pc, pe, tagged[i], 1); 748 }else{ 749 highlight(pc, pe, lasti, 0); 750 highlight(pc, pe, i, 1); 751 } 752 lasti = i; 753 } 754 flushimage(pc->display, 1); 755 if(locked) 756 unlockdisplay(pc->display); 757 crecv(f->c, val); 758 locked = lockdisplay(pc->display); 759 switch(*val){ 760 case IRUp: 761 if(pe->pkind != EVertical) 762 goto Default; 763 goto Up; 764 case IRRew: 765 if(pe->pkind != EHorizontal) 766 goto Default; 767 Up: 768 i = wrapelement(pe, i-1, ntag); 769 break; 770 case IRSelect: 771 if(dotags) 772 dohighlight(pc, pe, tagged[i], 0); 773 else 774 highlight(pc, pe, i, 0); 775 f->ret->t0 = *val; 776 f->ret->t1 = i; 777 Return: 778 flushimage(pc->display, 1); 779 if(dotags) 780 pe = tagged[i]; 781 else 782 pe = element(pe, i, nil); 783 destroy(f->ret->t2); 784 D2H(pe)->ref++; 785 f->ret->t2 = &pe->e; 786 if(locked) 787 unlockdisplay(pc->display); 788 free(val); 789 free(tagged); 790 return; 791 case IRDn: 792 if(pe->pkind != EVertical) 793 goto Default; 794 goto Down; 795 case IRFF: 796 if(pe->pkind != EHorizontal) 797 goto Default; 798 Down: 799 i = wrapelement(pe, i+1, ntag); 800 break; 801 default: 802 Default: 803 if(dotags) 804 dohighlight(pc, pe, tagged[lasti], 0); 805 else 806 highlight(pc, pe, lasti, 0); 807 f->ret->t0 = *val; 808 f->ret->t1 = i; 809 goto Return; 810 } 811 } 812 } 813 814 void 815 Compound_tagselect(void *fp) 816 { 817 doselect(fp, 1); 818 } 819 820 void 821 Compound_select(void *fp) 822 { 823 doselect(fp, 0); 824 } 825