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; }