shithub: libnate

ref: aab184987c79fc7a8e5467200f9ac448700b797f
dir: /nate.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include "nate.h"
#include "nate_construct.h"

int nateborders = 0;
int natetracehit = 0;
int natetracedraw = 0;
int natedebugfd = -1;

static Nlist rootchain = { nil };
static Nelem* rootelem = nil;

void
nregroot(Nelem* nelem)
{
	assert(nelem);

	// root must be inside rootchain
	nregister(nelem);

	if (rootelem)
		ncallfree(rootelem);

	rootelem = nelem;
}

void
nregister(Nelem* nelem)
{
	if (lhas(&rootchain, nelem))
		return;
		
	ladd(&rootchain, nelem);
}

void
nderegister(Nelem* nelem)
{
	ldel(&rootchain, nelem);
}

void
nforeachroot(void (*f)(Nelem*, int, void*), void *aux)
{
	lforeach(&rootchain, f, aux);
}

int
nisroot(Nelem* nelem)
{
	return lhas(&rootchain, nelem);
}

void
linit(Nlist* list)
{
	list->first = nil;
	list->num = 0;
}

int
lhas(Nlist* list, Nelem* item)
{
	Nlistelem* l = list->first;
	while (l) {
		if (l->item == item)
			return 1;
		l = l->next;
	}
	return 0;
}

void
ladd(Nlist* list, Nelem* item)
{
	Nlistelem* l;
	if (!list->first) {
		list->first = malloc(sizeof(Nlist));
		assert(list->first);
		list->first->item = item;
		list->first->next = nil;
		list->num++;
		return;
	}
	
	l = list->first;
	while (l->next)
		l = l->next;
	
	l->next = malloc(sizeof(Nlist));
	assert(l->next);
	l->next->item = item;
	l->next->next = nil;
	list->num++;
}

void
ldel(Nlist* list, Nelem* item)
{
	Nlistelem* l, *a;
	if (!list->first)
		return;
	
	l = list->first;
	while (l->next && l->next->item != item)
		l = l->next;
	
	a = l->next;
	l->next = a->next;
	free(a);
	list->num--;
}

void
linsert(Nlist* list, Nelem* before, Nelem* item)
{
	Nlistelem* l = list->first, *a;
	while (l->next && l->item != before)
		l = l->next;
	
	a = l->next;
	l->next = malloc(sizeof(Nlist));
	l->next->next = a;
	l->next->item = item;
	list->num++;
}

void
lforeach(Nlist* list, void (*f)(Nelem*, int, void*), void *aux)
{
	Nlistelem* l = list->first;
	for (int i = 0; l; i++) {
		f(l->item, i, aux);
		l = l->next;
	}
}

void
lfreelist(Nlist* list)
{
	Nlistelem* a;
	Nlistelem* l = list->first;
	while (l) {
		a = l->next;
		if (l->item)
			ncallfree(l->item);
		free(l);
		l = a;
	}
}

Nelem*
lgetfirst(Nlist* list)
{
	return list->first ? list->first->item : nil;
}

Nelem*
lsetfirst(Nlist* list, Nelem* item)
{
	Nelem* f = lgetfirst(list);
	if (list->first) {
		list->first->item = item;
		return f;
	}
	list->first = malloc(sizeof(Nlistelem));
	list->first->next = nil;
	list->first->item = item;
	return f;
}

void
ncallfree(Nelem* nelem)
{
	assert(nelem);
	
	if (nisroot(nelem))
		return;
	
	if (nelem->funcs && nelem->funcs->free)
		nelem->funcs->free(nelem);
}

Rectangle
ncallcalcrect(Nelem* nelem, Image* dst, Rectangle r)
{
	assert(nelem);
	
	if (nelem->funcs && nelem->funcs->calcrect) {
		r = nelem->funcs->calcrect(nelem, dst, r);
		ndebugprint(nelem, "calcrect %P ← %R\n", subpt(r.max, r.min), r);
		return r;
	}
	
	return r;
}

Point
ncalldesiredsize(Nelem *nelem, Image *dst)
{
	Point p;
	assert(nelem);
	if (nelem->funcs && nelem->funcs->desiredsize) {
		p = nelem->funcs->desiredsize(nelem, dst);
		ndebugprint(nelem, "desired: %P\n", p);
		return p;
	}
	return ZP;
}

void
ncalldraw(Nelem* nelem, Image* dst)
{
	Rectangle or;
	assert(nelem);
	
	if (nelem->funcs && nelem->funcs->draw) {
		if (natetracedraw && natedebugfd >= 0)
			ndebugprint(nelem, "draw: %R\n", nelem->slot.r);
		or = dst->clipr;
		replclipr(dst, 0, nelem->slot.r);
		nelem->funcs->draw(nelem, dst);
		replclipr(dst, 0, or);
		if (nateborders)
			border(dst, nelem->slot.r, 1, ncolor.red, ZP);
	}
}

Nelem*
ncallcheckhit(Nelem* nelem, Image* screen, Mouse m)
{
	assert(nelem);
	
	if (natetracehit) {
		nctracehit(nelem, !nelem->funcs->hit);
		nctracehitlevel++;
	}
	if (nelem->funcs && nelem->funcs->checkhit) {
		return nelem->funcs->checkhit(nelem, screen, m);
	}
	return nd_checkhit(nelem, screen, m);
}

int
ncallhit(Nelem* nelem, Mouse m)
{
	assert(nelem);
	
	if (nelem->funcs && nelem->funcs->hit)
		return nelem->funcs->hit(nelem, m);
	return 0;
}

Nlist*
ncallgetchildren(Nelem* nelem)
{
	assert(nelem);
	
	if (nelem->funcs && nelem->funcs->getchildren)
		return nelem->funcs->getchildren(nelem);
	if (nelem->children.num)
		return &nelem->children;
	return nil;
}

Nelemaccessors*
nassign(Nelem** dst, Nelemaccessors* src)
{
	Nelem *nel = nc_get();
	assert(dst && src && nel);
	assert(nel->type == src->type);
	*dst = nel;
	return src;
}

void
nateinit()
{
	nc_init();
#define A(col) allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, col)
	ncolor.red = A(DRed);
	ncolor.green = A(DGreen);
	ncolor.blue = A(DBlue);
#undef A
}

void
nateredraw(int all)
{
	if (!rootelem)
		return;
	
	if (all)
		ncallcalcrect(rootelem, screen, screen->r);
	ncalldraw(rootelem, screen);
}

void
ndebugprint(Nelem *el, char *fmt, ...)
{
	if (natedebugfd < 0)
		return;
	fprint(natedebugfd, "%15s %10s  ", el->name, el->type);
	
	va_list args;
	va_start(args, fmt);
	vfprint(natedebugfd, fmt, args);
	va_end(args);
}

int
natemouseevent(Mouse m)
{
	Nelem* el;
	Rectangle r;
	
	if (!rootelem)
		return 0;
	
	if (!ptinrect(m.xy, rootelem->slot.r))
		return 0;
	
	nctracehitlevel = natetracehit - 1;
	el = ncallcheckhit(rootelem, screen, m);
	if (!el)
		return 0;
	
	return ncallhit(el, m);
}

Nslot
NSlot()
{
	Nslot s;
	s.fill = FILLX|FILLY;
	return s;
}

Nslot
NSlotx(Nalign a, int f)
{
	Nslot s;
	s.align = a;
	s.fill = f;
	return s;
}

Rectangle
insetmargin(Rectangle r, Nmargin i)
{
	r.min.x += i.left;
	r.min.y += i.top;
	r.max.x -= i.right;
	r.max.y -= i.bottom;
	return r;
}

Rectangle
extendmargin(Rectangle r, Nmargin i)
{
	r.max.x += i.right + i.left;
	r.max.y += i.bottom + i.top;
	return r;
}