Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/sys/src/cmd/omero/util.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#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 <nel; i++)
		l += strlen(el[i]) + 1;
	s = sp = emalloc9p(l);
	*sp++ = '/';
	*sp = 0;
	for (i = nel - 1; 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);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].