ref: 855a60a7698acb993b68f8e64448bd2fc3ff86da
dir: /nate.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.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;
}
Nelem*
nassign(Nelem** dst, Nelem* src)
{
assert(dst && src);
*dst = src;
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;
}