#include #include #include "interp.h" #include "isa.h" #include "runt.h" #include "prefabmod.h" #include "image.h" #include "drawif.h" #include "prefab.h" #include "raise.h" uchar elementmap[] = Prefab_Element_map; uchar compoundmap[] = Prefab_Compound_map; uchar layoutmap[] = Prefab_Layout_map; void freeprefabcompound(Heap*, int); Type* TCompound; Type* TElement; Type* TLayout; /* Infrared remote buttons known to Compound_select */ enum { IRFF = 14, IRRew = 15, IRUp = 16, IRDn = 17, IRSelect = 18, IREnter = 20, }; void prefabmodinit(void) { TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap)); TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap)); TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap)); builtinmod("$Prefab", Prefabmodtab); } PElement* checkelement(Prefab_Element *de) { PElement *pe; pe = lookupelement(de); if(pe == H) error(exType); return pe; } PCompound* checkcompound(Prefab_Compound *de) { PCompound *pe; pe = lookupcompound(de); if(pe == H) error(exType); return pe; } PElement* lookupelement(Prefab_Element *de) { PElement *pe; if(de == H) return H; if(D2H(de)->t != TElement) return H; pe = (PElement*)de; if(de->kind!=pe->pkind || de->kids!=pe->first) return H; return pe; } PCompound* lookupcompound(Prefab_Compound *dc) { if(dc == H) return H; if(D2H(dc)->t != TCompound) return H; return (PCompound*)dc; } void freeprefabcompound(Heap *h, int swept) { Image *i; Prefab_Compound *d; PCompound *pc; d = H2D(Prefab_Compound*, h); pc = lookupcompound(d); /* disconnect compound from image refresh daemon */ i = lookupimage(pc->c.image); if(i != nil) delrefresh(i); if(!swept && TCompound->np) freeptrs(d, TCompound); /* header will be freed by caller */ } static PElement* findtag(PElement *pelem, char *tag) { PElement *pe, *t; List *l; if(pelem==H || tag[0]==0) return pelem; for(l=pelem->first; l!=H; l=l->tail){ pe = *(PElement**)l->data; if(strcmp(tag, string2c(pe->e.tag)) == 0) return pe; else if(pe->pkind==EHorizontal || pe->pkind==EVertical){ t = findtag(pe, tag); if(t != H) return t; } } return H; } int badenviron(Prefab_Environ *env, int err) { Prefab_Style *s; if(env == H) goto bad; s = env->style; if(s == H) goto bad; if(s->titlefont==H || s->textfont==H) goto bad; if(s->elemcolor==H || s->edgecolor==H) goto bad; if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H) goto bad; return 0; bad: if(err) error(exType); return 1; } void Element_iconseparator(void *fp, int kind) { F_Element_icon *f; PElement *e; Image *icon; int locked; f = fp; badenviron(f->env, 1); checkimage(f->mask); icon = checkimage(f->icon); locked = lockdisplay(icon->display, 0); destroy(*f->ret); *f->ret = H; if(kind == ESeparator) e = separatorelement(f->env, f->r, f->icon, f->mask); else e = iconelement(f->env, f->r, f->icon, f->mask); *f->ret = (Prefab_Element*)e; if(locked) unlockdisplay(icon->display); } void Element_icon(void *fp) { Element_iconseparator(fp, EIcon); } void Element_separator(void *fp) { Element_iconseparator(fp, ESeparator); } void Element_text(void *fp) { F_Element_text *f; PElement *pelem; Display *disp; int locked; f = fp; badenviron(f->env, 1); if(f->kind!=EText && f->kind!=ETitle) return; disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pelem = textelement(f->env, f->text, f->r, f->kind); *f->ret = (Prefab_Element*)pelem; if(locked) unlockdisplay(disp); } void Element_layout(void *fp) { F_Element_layout *f; PElement *pelem; Display *disp; int locked; f = fp; badenviron(f->env, 1); if(f->kind!=EText && f->kind!=ETitle) return; disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pelem = layoutelement(f->env, f->lay, f->r, f->kind); *f->ret = (Prefab_Element*)pelem; if(locked) unlockdisplay(disp); } void Element_elist(void *fp) { F_Element_elist *f; PElement *pelist; Display *disp; int locked; f = fp; if(f->elem != H) checkelement(f->elem); badenviron(f->env, 1); if(f->kind!=EHorizontal && f->kind!=EVertical) return; disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pelist = elistelement(f->env, f->elem, f->kind); *f->ret = (Prefab_Element*)pelist; if(locked) unlockdisplay(disp); } void Element_append(void *fp) { F_Element_append *f; f = fp; *f->ret = 0; if(f->elist==H || f->elem==H) return; badenviron(f->elist->environ, 1); checkelement(f->elist); checkelement(f->elem); if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical) return; if(appendelist(f->elist, f->elem) != H) *f->ret = 1; } void Element_adjust(void *fp) { F_Element_adjust *f; Display *disp; int locked; f = fp; checkelement(f->elem); badenviron(f->elem->environ, 1); disp = checkscreen(f->elem->environ->screen)->display; locked = lockdisplay(disp, 0); adjustelement(f->elem, f->equal, f->dir); if(locked) unlockdisplay(disp); } void Element_show(void *fp) { F_Element_show *f; Display *disp; int locked; f = fp; checkelement(f->elem); checkelement(f->elist); badenviron(f->elem->environ, 1); disp = checkscreen(f->elem->environ->screen)->display; locked = lockdisplay(disp, 0); *f->ret = showelement(f->elist, f->elem); if(locked) unlockdisplay(disp); } void Element_clip(void *fp) { F_Element_clip *f; Rectangle r; Display *disp; int locked; f = fp; checkelement(f->elem); badenviron(f->elem->environ, 1); R2R(r, f->r); disp = checkscreen(f->elem->environ->screen)->display; locked = lockdisplay(disp, 0); clipelement(f->elem, r); if(locked) unlockdisplay(disp); } void Element_translatescroll(void *fp, int trans) { F_Element_scroll *f; Point d; Display *disp; int locked, moved; f = fp; checkelement(f->elem); badenviron(f->elem->environ, 1); P2P(d, f->d); disp = checkscreen(f->elem->environ->screen)->display; locked = lockdisplay(disp, 0); if(trans) translateelement(f->elem, d); else{ moved = 0; scrollelement(f->elem, d, &moved); } if(locked) unlockdisplay(disp); } void Element_scroll(void *fp) { Element_translatescroll(fp, 0); } void Element_translate(void *fp) { Element_translatescroll(fp, 1); } void Compound_iconbox(void *fp) { F_Compound_iconbox *f; Image *icon; int locked; PCompound *pc; f = fp; badenviron(f->env, 1); checkimage(f->mask); icon = checkimage(f->icon); locked = lockdisplay(icon->display, 0); destroy(*f->ret); *f->ret = H; pc = iconbox(f->env, f->p, f->title, f->icon, f->mask); *f->ret = &pc->c; if(locked) unlockdisplay(icon->display); } void Compound_textbox(void *fp) { F_Compound_textbox *f; Display *disp; int locked; PCompound *pc; f = fp; badenviron(f->env, 1); disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pc = textbox(f->env, f->r, f->title, f->text); *f->ret = &pc->c; if(locked) unlockdisplay(disp); } void Compound_layoutbox(void *fp) { F_Compound_layoutbox *f; Display *disp; int locked; PCompound *pc; f = fp; badenviron(f->env, 1); disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pc = layoutbox(f->env, f->r, f->title, f->lay); *f->ret = &pc->c; if(locked) unlockdisplay(disp); } void Compound_box(void *fp) { F_Compound_box *f; Display *disp; int locked; PCompound *pc; f = fp; badenviron(f->env, 1); if(f->title != H) checkelement(f->title); checkelement(f->elist); disp = checkscreen(f->env->screen)->display; locked = lockdisplay(disp, 0); destroy(*f->ret); *f->ret = H; pc = box(f->env, f->p, f->title, f->elist); *f->ret = &pc->c; if(locked) unlockdisplay(disp); } void Compound_draw(void *fp) { F_Compound_draw *f; PCompound *pc; int locked; f = fp; if(f->comp == H) return; pc = checkcompound(f->comp); badenviron(pc->c.environ, 1); locked = lockdisplay(pc->display, 0); drawcompound(&pc->c); flushimage(pc->display, 1); if(locked) unlockdisplay(pc->display); } void Compound_redraw(void *fp) { F_Compound_redraw *f; PCompound *pc; Image *i; int locked; f = fp; if(f->comp == H) return; pc = checkcompound(f->comp); badenviron(pc->c.environ, 1); i = checkimage(pc->c.image); locked = lockdisplay(pc->display, 0); redrawcompound(i, IRECT(f->r), &pc->c); flushimage(pc->display, 1); if(locked) unlockdisplay(pc->display); } static PElement* pelement(Prefab_Compound *comp, Prefab_Element *elem) { PElement *pe; if(comp == H) return H; checkcompound(comp); badenviron(comp->environ, 1); pe = lookupelement(elem); return pe; } void Compound_highlight(void *fp) { F_Compound_highlight *f; PCompound *pc; PElement *pe; Image *i; int locked; f = fp; pe = pelement(f->comp, f->elem); if(pe == H) return; pc = (PCompound*)f->comp; i = checkimage(pc->c.image); locked = lockdisplay(pc->display, 0); highlightelement(&pe->e, i, &pc->c, f->on); flushimage(pc->display, 1); if(locked) unlockdisplay(pc->display); } void Compound_scroll(void *fp) { F_Compound_scroll *f; PCompound *pc; PElement *pe; int locked; Image *i; int moved; f = fp; pe = pelement(f->comp, f->elem); if(pe == H) return; pc = (PCompound*)f->comp; i = checkimage(pc->c.image); locked = lockdisplay(pc->display, 0); moved = 0; scrollelement(&pe->e, IPOINT(f->d), &moved); if(moved){ drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0); flushimage(pc->display, 1); } if(locked) unlockdisplay(pc->display); } void Compound_show(void *fp) { F_Compound_show *f; PCompound *pc; PElement *pe; int locked; f = fp; pe = pelement(f->comp, f->elem); if(pe == H) return; pc = (PCompound*)f->comp; locked = lockdisplay(pc->display, 0); *f->ret = showelement(pc->c.contents, &pe->e); flushimage(pc->display, 1); if(locked) unlockdisplay(pc->display); } static PElement* element(PElement *plist, int index, int *ip) { int i; PElement *pe; List *l; i = 0; pe = H; for(l=plist->first; l!=H; l=l->tail){ pe = *(PElement**)l->data; if(pe->pkind == ESeparator) continue; if(i == index) break; i++; } if(ip) *ip = i; if(l == H) return H; return pe; } static int wrapelement(PElement *plist, int index, int ntag) { int i, wrap; if(ntag > 0){ if(index < 0) return ntag-1; if(index >= ntag) return 0; return index; } wrap = 1; if(index < 0){ index = 1000000; /* will seek to end */ wrap = 0; } if(element(plist, index, &i)==H && index!=0){ if(wrap) /* went off end; wrap to beginning */ return wrapelement(plist, 0, 0); if(i > 0) --i; } return i; } void dohighlight(PCompound *pc, PElement *list, PElement *pe, int on) { Image *i; /* see if we need to scroll */ i = lookupimage(pc->c.image); if(i == nil) return; if(on && showelement(&list->e, &pe->e)) redrawcompound(i, IRECT(pc->c.contents->r), &pc->c); highlightelement(&pe->e, i, &pc->c, on); } void highlight(PCompound *pc, PElement *list, int index, int on) { dohighlight(pc, list, element(list, index, nil), on); } static PElement** tags(PElement *pelem, int *ntag) { int n, nalloc, nn; List *l; PElement *pe, **tagged, **ntagged; n = 0; nalloc = 0; tagged = nil; *ntag = 0; for(l=pelem->first; l!=H; l=l->tail){ pe = *(PElement**)l->data; if(pe->e.tag != H){ if(nalloc == n){ nalloc += 10; tagged = realloc(tagged, nalloc*sizeof(PElement*)); if(tagged == nil) return nil; } tagged[n++] = pe; }else if(pe->pkind==EHorizontal || pe->pkind==EVertical){ ntagged = tags(pe, &nn); if(nn > 0){ if(nalloc < n+nn){ nalloc = n+nn+10; tagged = realloc(tagged, nalloc*sizeof(PElement*)); if(tagged == nil){ free(ntagged); return nil; } } memmove(tagged+n, ntagged, nn*sizeof(PElement*)); free(ntagged); n += nn; } } } *ntag = n; return tagged; } void doselect(void *fp, int dotags) { F_Compound_select *f; PCompound *pc; PElement *pe; WORD *val; List *l; Prefab_Element *t; int i, lasti, ntag; PElement **tagged; int locked; f = fp; pc = checkcompound(f->comp); pe = lookupelement(f->elem); if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){ Bad: destroy(f->ret->t2); f->ret->t0 = 9999; f->ret->t1 = 0; f->ret->t2 = H; return; } ntag = 0; tagged = 0; /* check at least one selectable item */ if(dotags){ tagged = tags(pe, &ntag); if(ntag > 0) goto OK; }else for(l=pe->first; l!=H; l=l->tail){ t = *(Prefab_Element**)l->data; if(t->kind != ESeparator) goto OK; } goto Bad; OK: i = f->i; i = wrapelement(pe, i, ntag); lasti = i; locked = lockdisplay(pc->display, 0); if(dotags) dohighlight(pc, pe, tagged[i], 1); else highlight(pc, pe, i, 1); /* val must be in shared memory, but stacks not shared */ val = malloc(sizeof(WORD)); if(val == nil) goto Bad; for(;;){ if(lasti != i){ if(dotags){ dohighlight(pc, pe, tagged[lasti], 0); dohighlight(pc, pe, tagged[i], 1); }else{ highlight(pc, pe, lasti, 0); highlight(pc, pe, i, 1); } lasti = i; } flushimage(pc->display, 1); if(locked) unlockdisplay(pc->display); crecv(f->c, val); locked = lockdisplay(pc->display, 0); switch(*val){ case IRUp: if(pe->pkind != EVertical) goto Default; goto Up; case IRRew: if(pe->pkind != EHorizontal) goto Default; Up: i = wrapelement(pe, i-1, ntag); break; case IRSelect: if(dotags) dohighlight(pc, pe, tagged[i], 0); else highlight(pc, pe, i, 0); f->ret->t0 = *val; f->ret->t1 = i; Return: flushimage(pc->display, 1); if(dotags) pe = tagged[i]; else pe = element(pe, i, nil); destroy(f->ret->t2); D2H(pe)->ref++; f->ret->t2 = &pe->e; if(locked) unlockdisplay(pc->display); free(val); free(tagged); return; case IRDn: if(pe->pkind != EVertical) goto Default; goto Down; case IRFF: if(pe->pkind != EHorizontal) goto Default; Down: i = wrapelement(pe, i+1, ntag); break; default: Default: if(dotags) dohighlight(pc, pe, tagged[lasti], 0); else highlight(pc, pe, lasti, 0); f->ret->t0 = *val; f->ret->t1 = i; goto Return; } } } void Compound_tagselect(void *fp) { doselect(fp, 1); } void Compound_select(void *fp) { doselect(fp, 0); }