shithub: libnate

ref: c04fd4ce67a03c04b342c38185523bb834f4e0b7
dir: /n_box.c/

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

#define N_TYPE NBox_Type
char* NBox_Type = "NBox";

Point
box_calcsize(Nelem* nelem, Image* screen)
{
	NBox* b = (NBox*)nelem;
	GUARD(b);
	if (!lgetfirst(&b->child)) {
		return Pt(0, 0);
	}
	Point csize = ncallcalcsize(lgetfirst(&b->child), screen);
	Point ssize = Pt(b->borderwidth, b->borderwidth);
	csize = addpt(csize, addpt(ssize, ssize));
	return csize;
}

void
box_draw(Nelem* nelem, Image* img, Rectangle r)
{
	Nelem* f;
	NBox* b = (NBox*)nelem;
	GUARD(b);
	f = lgetfirst(&b->child);
	if (!f)
		return;

	if (b->sizetocontent) {
		r.max = addpt(r.min, ncallcalcsize(nelem, img));
	}

	border(img, r, b->borderwidth, b->bordercolor, ZP);
	ncalldraw(f, img, insetrect(r, b->borderwidth));
}

Nelem*
box_checkhit(Nelem* nelem, Image* screen, Rectangle rect, Mouse m)
{
	NBox* b = (NBox*)nelem;
	Nelem* r;
	Nelem* ch;
	Point size;
	Rectangle cr;
	GUARD(b);
	
	if (!(ch = lgetfirst(&b->child))) {
		if (m.buttons&1 && b->hitfunc) {
			return b;
		}
		return nil;
	}
	
	size = ncallcalcsize(ch, screen);
	cr.min = rect.min;
	cr.max = addpt(cr.min, size);
	
	if (ptinrect(m.xy, cr)) {
		r = ncallcheckhit(ch, screen, cr, m);
		if (r)
			return r;
	}
	
	if (m.buttons&1 && b->hitfunc) {
		return b;
	}
	return nil;
}

int
box_hit(Nelem* nelem, Mouse m)
{
	NBox* b = (NBox*)nelem;
	GUARD(b);
	
	if (b->hitfunc)
		return b->hitfunc(m, b, b->hitaux);
	return 0;
}

void
box_free(Nelem* nelem)
{
	Nelem* ch;
	NBox* b = (NBox*)nelem;
	if (nisroot(b))
		return;
	
	if ((ch = lgetfirst(&b->child)))
		ncallfree(ch);
	free(b);
}

Nlist*
box_getchildren(Nelem* nelem)
{
	NBox* b = (NBox*)nelem;
	GUARD(b);
	return &b->child;
}

static Nelemfunctions Nboxfunctions = {
	.calcsize = box_calcsize,
	.draw = box_draw,
	.checkhit = box_checkhit,
	.hit = box_hit,
	.free = box_free,
	.getchildren = box_getchildren,
};

NBox*
box_slot(Nelem* child)
{
	if (child == nc_get()) {
		nc_pop();
	}
	NBox* b = (NBox*)nc_get();
	GUARD(b);
	// TODO: potential leak!
	lsetfirst(&b->child, child);
	return b;
}

NBox*
box_border(int bwidth, Image* col)
{
	NBox* b = (NBox*)nc_get();
	GUARD(b);
	b->borderwidth = bwidth;
	if (col)
		b->bordercolor = col;
	return b;
}
NBox*
box_sizetocontent(int stc)
{
	NBox* b = (NBox*)nc_get();
	GUARD(b);
	b->sizetocontent = stc;
	return b;
}

NBox*
box_onclick(int (*f)(Mouse, Nelem*, void*), void* aux)
{
	NBox* b = (NBox*)nc_get();
	GUARD(b);
	b->hitfunc = f;
	b->hitaux = aux;
	return b;
}

NBox*
New_Box(void)
{
	NBox* b = malloc(sizeof(NBox));
	assert(b);
	
	b->type = NBox_Type;
	b->funcs = &Nboxfunctions;
	
	b->Slot = box_slot;
	b->Border = box_border;
	b->SizeToContent = box_sizetocontent;
	b->OnClick = box_onclick;
	
	linit(&b->child);
	b->sizetocontent = 0;
	b->hitfunc = nil;
	b->hitaux = nil;
	b->borderwidth = 0;
	b->bordercolor = display->black;
	nc_push(b);
	return b;
}