shithub: libnate

ref: aab184987c79fc7a8e5467200f9ac448700b797f
dir: /n_vbox.c/

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

#define N_TYPE NVBox_Type
char* NVBox_Type = "NVBox";

typedef struct csizep csizep;
struct csizep {
	Rectangle crect;
	Image *screen;
	int autoheight;
	int fillwidth;
};

static void
childsize(Nelem* nelem, int, void *aux)
{
	Point pt;
	Rectangle r;
	csizep *p = (csizep*)aux;
	
	if (!nelem->slot.fill&FILLX || !nelem->slot.fill&FILLY)
		pt = ncalldesiredsize(nelem, p->screen);
	
	if (nelem->slot.fill&FILLX)
		pt.x = p->fillwidth;
	if (nelem->slot.fill&FILLY)
		pt.y = p->autoheight;
	
	r = p->crect;
	r.max = addpt(r.min, pt);
	ncallcalcrect(nelem, p->screen, r);
	p->crect.min.y = r.max.y;
}

typedef struct dprepassp dprepassp;
struct dprepassp {
	Image *screen;
	int numfill;
	int fixedheight;
};

static void
sizeprepass(Nelem *nelem, int, void *aux)
{
	Point pt;
	dprepassp *p = (dprepassp*)aux;
	if (nelem->slot.fill&FILLY) {
		p->numfill++;
		return;
	}
	pt = ncalldesiredsize(nelem, p->screen);
	p->fixedheight += pt.y;
}

static Rectangle
vbox_calcrect(Nelem* nelem, Image* img, Rectangle r)
{
	csizep cp;
	dprepassp pp;
	NVBox* b = (NVBox*)nelem;
	GUARD(b);
	
	b->slot.r = r;
	
	pp.screen = screen;
	pp.numfill = 0;
	pp.fixedheight = 0;
	
	lforeach(&b->children, sizeprepass, &pp);
	
	cp.crect = r;
	cp.screen = img;
	cp.fillwidth = Dx(r);
	cp.autoheight = Dy(r) - pp.fixedheight;
	if (pp.numfill)
		cp.autoheight /= pp.numfill;
	
	// TODO: check if numfill is correct!
	
	lforeach(&b->children, childsize, &cp);
	
	return b->slot.r;
}

typedef struct cdsizep cdsizep;
struct cdsizep {
	Image *screen;
	Point size;
};

static void
dsizechild(Nelem *el, int, void *aux)
{
	Point pt;
	cdsizep *p = (cdsizep*)aux;
	pt = ncalldesiredsize(el, p->screen);
	if (pt.x > p->size.x)
		p->size.x = pt.x;
	p->size.y += pt.y;
}

static Point
vbox_desiredsize(Nelem *nelem, Image *screen)
{
	cdsizep p;
	NVBox *b = (NVBox*)nelem;
	GUARD(b);
	
	p.screen = screen;
	p.size = ZP;
	lforeach(&b->children, dsizechild, &p);
	return p.size;
}

static void
vbox_childdraw(Nelem* elem, int, void *aux)
{
	ncalldraw(elem, (Image*)aux);
}

static void
vbox_draw(Nelem* nelem, Image* img)
{
	NVBox* b = (NVBox*)nelem;
	GUARD(b);
	
	lforeach(&b->children, vbox_childdraw, img);
}

static Nelemfunctions Nvboxfunctions = {
	.calcrect = vbox_calcrect,
	.desiredsize = vbox_desiredsize,
	.draw = vbox_draw,
};

#define NTYPE NVBox
#define NACCS NVBoxAccessors

DEF_SLOTFUNC(vbox_slot);
DEF_ACCESSOR_OneParam(vbox_autowidth, int, autowidth);

static NACCS accs = {
	.Slot = vbox_slot,
	.AutoWidth = vbox_autowidth,
};

NACCS*
New_VBox(char *name)
{
	NVBox *b = MakeNelem(NVBox, NVBox_Type, &Nvboxfunctions, &accs, name, -1);
	
	linit(&b->children);
	b->autowidth = 0;
	nc_push(b);
	return &accs;
}