#include #include #include #include #include #include #include #include #include <9p.h> #include "gui.h" /* * BUG: This touches the private parts of lib9p. * * I don't know how else to do it without * clobbering lib9p with stuff that does not belong there * The main reason for needing this is that omero uses the * File hierarchy to represent the widget hierarchy, and it's * just TOO dependent on the list of children. The main problems * are shifting left/right a set of panels and moving a panel * from one point in the tree to another. Any other stuff should * be using newfilewalk/endfilewalk without touching f->filelist. */ #include "/sys/src/lib9p/file.h" File** newfilewalk(File* f) { File** sons; File** s; Filelist* l; wlock(f); s = sons = emalloc9p(sizeof(File*)*(f->nchild+1)); sons[f->nchild] = nil; for (l = f->filelist; l != nil; l = l->link){ if (l->f){ incref(l->f); *s++ = l->f; } } wunlock(f); return sons; } void endfilewalk(File** sons) { File** s; for (s = sons; *s != nil; s++) closefile(*s); free(sons); } void shiftsonsright(File* f) { Filelist**fl; Filelist*fle; int max; File* ff; Panel* ffp; wlock(f); max = 0; again: for(fl=&f->filelist; (*fl) && (*fl)->link ; fl= &(*fl)->link) ; if (fl && *fl && *fl != f->filelist){ fle = *fl; *fl = nil; fle->link = f->filelist; f->filelist = fle; } ff = nil; ffp= nil; if (f->filelist){ ff = f->filelist->f; if (ff) ffp = ff->aux; } if (max++ < 20) if (!ff || !(ff->qid.type&QTDIR) || (ffp->flags&Phide)) goto again; wunlock(f); } void shiftsonsleft(File* f) { Filelist**fl; Filelist*fle; int max; File* ff; Panel* ffp; wlock(f); max = 0; again: for(fl=&f->filelist; (*fl) && (*fl)->link ; fl= &(*fl)->link) ; if (fl && *fl && *fl != f->filelist){ fle = *fl; fle->link = f->filelist; f->filelist = f->filelist->link; fle->link->link = nil; } ff = nil; ffp= nil; if (f->filelist){ ff = f->filelist->f; if (ff) ffp = ff->aux; } if (max++ < 20) if (!ff || !(ff->qid.type&QTDIR) || (ffp->flags&Phide)) goto again; wunlock(f); } void drawtag(Panel* p, int setdirty) { int fl; Rectangle r, rr; fl = (p->flags&(Pmore|Pdirty)); if (setdirty) fl |= Pdirty; r.min = p->rect.min; r.max = r.min; r.max.x += Tagwid; r.max.y += Taght; rr = r; rr.max.y += Taght; switch(fl){ case 0: draw(screen, r, bord[Btag], nil, ZP); break; case Pmore: draw(screen, rr, bord[Bmtag], nil, ZP); break; case Pdirty: draw(screen, r, bord[Bdtag], nil, ZP); break; case Pmore|Pdirty: draw(screen, rr, bord[Bdmtag], nil, ZP); break; } } static void drawspacetag(Panel* p) { Rectangle r; int space; space = p->space; if (space != 0){ r.min.x = p->rect.min.x + Tagwid; r.max.x = p->rect.max.x - Inset; r.min.y = p->rect.min.y; r.max.y = p->rect.min.y + Inset; space--; space %= 3; draw(screen, r, bord[Bws1 + space], nil, ZP); } } void borders(File* f) { Panel* p; Panel* np; File** w; File** l; File* fp; Rectangle r; Rectangle nr; Rectangle npr; int has; int last; int dirty; Point max; p = f->aux; if (p == nil || (p->flags&Pdead) || hidden(f)) return; assert(p->type == Qcol || p->type == Qrow); has = (p->flags&Ptag); dirty = (p->flags&Pdirty); if (Dx(p->rect) <= Inset || Dy(p->rect) <= Inset) return; r = insetrect(p->rect, Inset); if (has) r.min.x += Tagwid; max = ZP; last = 0; w = newfilewalk(f); for (l = w; fp = *l; l++){ if (!ispanel(fp)) continue; np = fp->aux; npr = np->rect; dirty |= (np->flags&Pdirty); if (!(np->flags&Phide)){ // clear space unused by component. max = npr.max; if (p->type == Qcol){ nr.min.x = npr.max.x; nr.max.x = r.max.x; nr.min.y = npr.min.y; nr.max.y = npr.max.y; } else { nr.min.y = npr.max.y; nr.max.y = r.max.y; nr.min.x = npr.min.x; nr.max.x = npr.max.x; } draw(screen, nr, cols[BACK], nil, ZP); } if (!(np->flags&Phide) && last != 0){ // clear separator from previous component nr = r; if (p->type == Qcol){ nr.min.y = last; nr.max.y = nr.min.y + Inset; } else { nr.min.x = last; nr.max.x = nr.min.x + Inset; } draw(screen, nr, cols[BACK], nil, ZP); last = 0; } if (!(np->flags&Phide)) if (p->type == Qcol) last = np->rect.max.y; else last = np->rect.max.x; } endfilewalk(w); // Clear unused space at end of components if (max.x || max.y){ nr = r; if (p->type == Qcol) nr.min.y = max.y; else nr.min.x = max.x; draw(screen, nr, cols[BACK], nil, ZP); } else { // no inner component. clear all space. draw(screen, r, cols[BACK], nil, ZP); } r = p->rect; r.max.x = r.min.x + Inset; if (has) r.max.x += Tagwid; r.min.y += Inset; r.max.y -= Inset; if (has) draw(screen, r, bord[Bw], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); r = p->rect; r.max.y = r.min.y + Inset; if (has) r.min.x += Tagwid; else r.min.x += Inset; r.max.x -= Inset; if (has) draw(screen, r, bord[Bn], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); r = p->rect; r.min.y = r.max.y - Inset; r.min.x += Inset; if (has) r.min.x += Tagwid; r.max.x -= Inset; if (has) draw(screen, r, bord[Bs], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); r = p->rect; r.min.x = r.max.x - Inset; r.min.y += Inset; r.max.y -= Inset; if (has) draw(screen, r, bord[Be], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); if (has) drawtag(p, dirty); r = p->rect; r.min.x = r.max.x - Inset; r.max.y = r.min.y + Inset; if (has) draw(screen, r, bord[Bne], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); r = p->rect; r.min.y = r.max.y - Inset; r.min.x = r.max.x - Inset; if (has) draw(screen, r, bord[Bse], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); r = p->rect; r.min.y = r.max.y - Inset; r.max.x = r.min.x + Inset; if (has) r.max.x += Tagwid; if (has) draw(screen, r, bord[Bsw], nil, ZP); else draw(screen, r, bord[Bback], nil, ZP); if (has) drawspacetag(p); } void pstring(Point pt, Image* color, Font* font, char* s, Rectangle clipr) { _string(screen, pt, color, ZP, font, s, nil, strlen(s), clipr, nil, ZP, SoverD); } int flagsons(File* f, int set, int clr, int first, int last) { File** l; File** w; File* fp; Panel* p; int some; some = 0; w = newfilewalk(f); for (l = w; fp = *l; l++){ if (ispanel(fp)) if (--first < 0 && --last >= 0){ p = fp->aux; p->flags |= set; p->flags &= ~clr; some++; } } endfilewalk(w); return some; } int flagothersons(File* f, int set, int clr, File* excl) { File** l; File** w; File* fp; Panel* p; int some; some = 0; w = newfilewalk(f); for (l = w; fp = *l; l++){ if (ispanel(fp)) if (fp != excl){ p = fp->aux; p->flags |= set; p->flags &= ~clr; some++; } } endfilewalk(w); return some; } int hassons(File* f, int flag) { File** l; File** w; File* fp; Panel* p; int some; some = 0; w = newfilewalk(f); for (l = w; fp = *l; l++) if (ispanel(fp)){ p = fp->aux; if (p->flags&flag) some++; } endfilewalk(w); return some; } void detachfile(File* f) { File *fp; Filelist *fl, **flp; fp = f->parent; assert(fp != nil && fp != f); wlock(f); wlock(fp); assert(f->parent == fp); //parent changed underfoot? for(flp=&fp->filelist; fl=*flp; flp=&(*flp)->link) if(fl->f == f){ *flp = fl->link; break; } assert(fl != nil && fl->f == f); fl->f = nil; free(fl); fp->nchild--; f->parent = nil; wunlock(fp); wunlock(f); closefile(fp); /* reference from child */ closefile(f); /* reference from tree */ return; } void insertfile(File* from, File* dir, File* after) { Filelist *fl, *ne, *fle; wlock(from); wlock(dir); ne = emalloc9p(sizeof(*ne)); ne->f = from; incref(from); ne->link = nil; from->parent = dir; incref(dir); dir->nchild++; if (dir->filelist == nil || after == nil){ ne->link = dir->filelist; dir->filelist = ne; goto done; } fle = nil; for(fl=dir->filelist; fl; fl=fl->link){ if(fl->f == after){ ne->link = fl->link; fl->link = ne; goto done; } fle = fl; } assert(fle && !fle->link); fle->link = ne; done: wunlock(dir); wunlock(from); } char* filepath(File* f) { int i, l; char* el[40]; int nel; char* s; char* sp; for (nel = 0; f && f != f->parent && nel < nelem(el); nel++){ el[nel] = f->name; f = f->parent; } l = 2; for (i = 0; i = 0; i--){ sp = strecpy(sp, s+l, el[i]); if (i > 0) *sp++ = '/'; } return s; } void event(Panel* p, char* fmt, ...) { char* ev; va_list arg; if (p->con == nil || p->path == nil) return; va_start(arg, fmt); ev = vsmprint(fmt, arg); va_end(arg); conprint(p->con, "%s %s\001", p->path, ev); free(ev); }