ref: a578dcbab74f736509dbe3e8fc1cefaa9919132c
dir: /n_box.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include "nate.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;
Point childsize;
NBox* b = (NBox*)nelem;
GUARD(b);
Nelem *child = lgetfirst(&b->children);
cr.min = r.min;
if (b->slot.fill&FILLX && b->slot.fill&FILLY) {
b->slot.r = cr = r;
if (child) {
cr = insetmargin(insetrect(cr, b->borderwidth), b->padding);
ncallcalcrect(child, screen, cr);
}
return b->slot.r;
}
if (b->slot.fill&FILLX)
cr.max.x = r.max.x;
if (b->slot.fill&FILLY)
cr.max.y = r.max.y;
if (child)
childsize = ncalldesiredsize(child, screen);
if (!(b->slot.fill&FILLX)) {
if (b->size.x >= 0) {
cr.max.x = cr.min.x + b->size.x;
} else if (child) {
cr.max.x = cr.min.x + childsize.x;
} else {
cr.max.x = cr.min.x;
}
cr.max.x += 2*b->borderwidth + b->padding.left + b->padding.right;
}
if (!(b->slot.fill&FILLY)) {
if (b->size.y >= 0) {
cr.max.y = cr.min.y + b->size.y;
} else if (child) {
cr.max.y = cr.min.y + childsize.y;
} else {
cr.max.y = cr.min.y;
}
cr.max.y += 2*b->borderwidth + b->padding.top + b->padding.bottom;
}
b->slot.r = cr;
/* tell child its size (important!) */
if (child) {
cr = insetmargin(insetrect(cr, b->borderwidth), b->padding);
ncallcalcrect(child, screen, cr);
}
return b->slot.r;
}
static Point
box_desiredsize(Nelem *nelem, Image *screen)
{
Point pt;
Nelem *child;
NBox *b = (NBox*)nelem;
GUARD(b);
if (b->size.x >= 0 && b->size.y >= 0) {
pt = b->size;
pt.x += 2*b->borderwidth + b->padding.left + b->padding.right;
pt.y += 2*b->borderwidth + b->padding.top + b->padding.bottom;
return pt;
}
child = lgetfirst(&b->children);
if (child)
pt = ncalldesiredsize(child, screen);
pt.x += 2*b->borderwidth + b->padding.left + b->padding.right;
pt.y += 2*b->borderwidth + b->padding.top + b->padding.bottom;
return pt;
}
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,
};
#define NTYPE NBox
#define NACCS NBoxAccessors
DEF_SLOTFUNC(box_slot);
DEF_ACCESSOR_TwoParams(box_border, int, borderwidth, Image*, bordercolor);
DEF_ACCESSOR_OneParam(box_autosize, int, autosize);
DEF_ACCESSOR_OneParam(box_size, Point, size);
DEF_ACCESSOR_TwoParams(box_onclick, OnclickHandler, hitfunc, void*, hitaux);
DEF_ACCESSOR_OneParam(box_padding, Nmargin, padding);
static NBoxAccessors accs = {
.Slot = box_slot,
.Border = box_border,
.AutoSize = box_autosize,
.Size = box_size,
.OnClick = box_onclick,
.Padding = box_padding,
};
NBoxAccessors*
New_Box(char *name)
{
NBox *b = MakeNelem(NBox, NBox_Type, &Nboxfunctions, &accs, name, 1);
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 &accs;
}