ref: 1890aeca379976e46deabb0ce844aefc8be1a2c5
dir: /n_box.c/
#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";
static Rectangle
box_calcsize(Nelem* nelem, Image* screen, Rectangle r)
{
NBox* b = (NBox*)nelem;
GUARD(b);
Nelem *child = lgetfirst(&b->children);
if (!b->autosize) {
r.max = addpt(r.min, b->size);
/* tell child its size (important!) */
ncallcalcsize(child, screen, r);
b->r = r;
return r;
}
if (!child) {
/* greedy */
b->r = r;
return r;
}
Rectangle csize = ncallcalcsize(child, screen, r);
b->r = insetrect(csize, b->borderwidth);
return b->r;
}
static void
box_draw(Nelem* nelem, Image* img)
{
Nelem* f;
Rectangle r;
NBox* b = (NBox*)nelem;
GUARD(b);
f = lgetfirst(&b->children);
if (!f)
return;
r = b->r;
if (b->autosize) {
r = b->r;
} else {
r = b->r;
r.max = addpt(r.min, b->size);
}
border(img, r, b->borderwidth, b->bordercolor, ZP);
ncalldraw(f, img);
if (nateborders) {
border(img, r, 1, ncolor.red, ZP);
}
}
static Nelem*
box_checkhit(Nelem *nelem, Image *screen, Mouse m)
{
NBox *b = (NBox*)nelem;
GUARD(b);
if (!b->hitfunc)
return nd_checkhit(nelem, screen, m);
if (ptinrect(m.xy, b->r))
return b;
return nil;
}
static int
box_hit(Nelem* nelem, Mouse m)
{
NBox* b = (NBox*)nelem;
GUARD(b);
int b1 = m.buttons&1;
// TODO: behaviour when pressed down and releasing on another box?
// TODO: drag-and-drop?
if (b->ishit == b1) {
/* no state change */
return 0;
}
if (b->ishit && !b1) {
/* released */
b->ishit = 0;
return 0;
}
if (!b->ishit && b1) {
/* pressed */
b->ishit = 1;
if (b->hitfunc)
return b->hitfunc(m, b, b->hitaux);
return 0;
}
/* cannot happen */
assert(0);
return 1;
}
static char*
box_getname(Nelem *nelem)
{
Nelem *ch;
NBox *b = (NBox*)nelem;
GUARD(b);
ch = lgetfirst(&b->children);
if (!(ch && ch->funcs && ch->funcs->getname))
return b->name;
return ch->funcs->getname(ch);
}
static Nelemfunctions Nboxfunctions = {
.calcsize = box_calcsize,
.draw = box_draw,
.checkhit = box_checkhit,
.hit = box_hit,
.getname = box_getname,
};
DEF_SLOTFUNC(NBox, box_slot);
DEF_ACCESSOR_TwoParams(NBox, box_border, int, borderwidth, Image*, bordercolor);
DEF_ACCESSOR_OneParam(NBox, box_autosize, int, autosize);
DEF_ACCESSOR_OneParam(NBox, box_size, Point, size);
DEF_ACCESSOR_OneParam(NBox, box_padding, Nmargin, padding);
DEF_ACCESSOR_TwoParams(NBox, box_onclick, OnclickHandler, hitfunc, void*, hitaux);
NBox*
New_Box(char *name)
{
NBox *b = MakeNelem(NBox, NBox_Type, &Nboxfunctions, name, 1);
b->Slot = box_slot;
b->Border = box_border;
b->AutoSize = box_autosize;
b->Size = box_size;
b->OnClick = box_onclick;
b->Padding = box_padding;
b->autosize = 0;
b->size = ZP;
b->hitfunc = nil;
b->hitaux = nil;
b->borderwidth = 0;
b->bordercolor = display->black;
nc_push(b);
return b;
}