ref: 69e287559e1faed50092d64659c5bc02f9bf395c
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_calcrect(Nelem* nelem, Image* screen, Rectangle r)
{
Rectangle cr;
NBox* b = (NBox*)nelem;
GUARD(b);
if (!b->autosize && b->size.x >= 0 && b->size.y >= 0)
r.max = addpt(r.min, b->size);
Nelem *child = lgetfirst(&b->children);
if (child) {
if (b->autosize)
r.max = addpt(r.min, ncalldesiredsize(child, screen));
/* tell child its size (important!) */
cr = insetrect(r, b->borderwidth);
ncallcalcrect(child, screen, cr);
}
b->slot.r = r;
return b->slot.r;
}
static Point
box_desiredsize(Nelem *nelem, Image *screen)
{
Point pt;
NBox *b = (NBox*)nelem;
GUARD(b);
if (b->autosize) {
Nelem *child = lgetfirst(&b->children);
if (child)
pt = ncalldesiredsize(child, screen);
pt.x += 2*b->borderwidth;
pt.y += 2*b->borderwidth;
return pt;
}
if (b->size.x < 0 || b->size.y < 0)
sysfatal("error: box size < 0: %s %s", b->type, b->name);
return b->size;
}
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->slot.r;
if (b->borderwidth > 0)
border(img, r, b->borderwidth, b->bordercolor, ZP);
ncalldraw(f, img);
}
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->slot.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 = {
.calcrect = box_calcrect,
.desiredsize = box_desiredsize,
.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 = Pt(-1, -1);
b->hitfunc = nil;
b->hitaux = nil;
b->borderwidth = 0;
b->bordercolor = display->black;
nc_push(b);
return b;
}