ref: aab184987c79fc7a8e5467200f9ac448700b797f
dir: /nate.c/
#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; }