ref: e74727d7e806863494a92d4b5cdcefdeee7495e9
dir: /libwidget/grid.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <String.h>
#include <widget.h>
#include "w-internal.h"
static char *gridentrykind = "Gridentry";
int
isgridentry(Widget *w)
{
return strcmp(w->kind, gridentrykind) == 0;
}
static Gridentry*
entrycoerce(Widget *w)
{
if(!isgridentry(w))
werror("coerce: not a grid entry");
return (Gridentry*)w;
}
Point
gridentryredraw(Widget *w, Image *dst, Rectangle r)
{
Gridentry *entry;
entry = entrycoerce(w);
return redrawwidget(entry->content, dst, r);
}
int
gridentrykbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
{
Gridentry *entry;
entry = entrycoerce(w);
return kbdevent(entry->content, dst, rect, r, chan);
}
int
gridentrymouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
{
Gridentry *entry;
entry = entrycoerce(w);
return mouseevent(entry->content, dst, rect, m, chan);
}
void
gridentryfree(Widget *w)
{
Gridentry *entry;
entry = entrycoerce(w);
freewidget(entry->content);
free(entry);
}
Gridentry*
newgridentry(Point position, Point size, Widget *w)
{
Gridentry *entry;
entry = emallocz(sizeof(*entry), 1);
wdefaults(entry);
entry->kind = gridentrykind;
entry->redraw = gridentryredraw;
entry->kbdevent = gridentrykbd;
entry->mouseevent = gridentrymouse;
entry->cleanup = gridentryfree;
entry->position = position;
entry->size = size;
entry->content = newcenterbox(w);
return entry;
}
/**/
Point GRID_DYNAMIC_SIZE = {-1, -1};
static char *gridkind = "Grid";
int
isgrid(Widget *w)
{
return strcmp(w->kind, gridkind) == 0;
}
static Grid*
gridcoerce(Widget *w)
{
if(!isgrid(w))
werror("coerce: not a grid");
return (Grid*)w;
}
Point
gridsize(Widget *w)
{
Grid *grid;
Point size;
grid = gridcoerce(w);
size = grid->size;
/* negative grid size means "as much space as the widgets inside take" */
if(size.x < 0 || size.y < 0)
for(Gridentry *e = grid->widgets; e != nil; e = e->next)
{
Point max = addpt(e->position, e->size);
if(grid->size.x < 0 && max.x > size.x)
size.x = max.x;
if(grid->size.y < 0 && max.y > size.y)
size.y = max.y;
}
return size;
}
Gridentry*
gridat(Widget *w, Point p)
{
Grid *grid;
grid = gridcoerce(w);
for(Gridentry *e = grid->widgets; e != nil; e = e->next)
if(ptinrect(p, Rpt(e->position, addpt(e->position, e->size))))
return e;
return nil;
}
Point
gridredraw(Widget *w, Image *dst, Rectangle r)
{
Grid *grid;
Point size, wsize, maxdraw;
grid = gridcoerce(w);
size = gridsize(grid);
wsize = subpt(r.max, r.min);
wsize.x /= size.x;
wsize.y /= size.y;
print("drawing grid into %R, wsize = %P\n", r, wsize);
for(Gridentry *e = grid->widgets; e != nil; e = e->next)
{
Rectangle bounds;
Point drew;
bounds.min = e->position;
bounds.min.x *= wsize.x;
bounds.min.y *= wsize.y;
bounds.max = bounds.min;
bounds.max.x += wsize.x * e->size.x;
bounds.max.y += wsize.y * e->size.y;
bounds = rectaddpt(bounds, r.min);
print("%P %P → %R\n", e->position, e->size, bounds);
drew = redrawwidget(e->content, dst, bounds);
if(drew.x > maxdraw.x)
maxdraw.x = drew.x;
if(drew.y > maxdraw.y)
maxdraw.y = drew.y;
}
return maxdraw;
}
/* TODO need focus system
int
gridkbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
{
Grid *grid;
grid = gridcoerce(w);
return kbdevent(entry->content, dst, rect, r, chan);
}
*/
int
gridmouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
{
Grid *grid;
Gridentry *hit;
Point size, wsize, pos;
grid = gridcoerce(w);
size = gridsize(grid);
wsize = subpt(rect.max, rect.min);
wsize.x /= size.x;
wsize.y /= size.y;
pos = subpt(m.xy, rect.min);
pos.x /= wsize.x;
pos.y /= wsize.y;
if((hit = gridat(grid, pos)) != nil)
return mouseevent(hit, dst, rect, m, chan);
return 0;
}
void
gridfree(Widget *w)
{
Grid *grid;
grid = gridcoerce(w);
for(Gridentry *e = grid->widgets; e != nil;)
{
Gridentry *next = e->next;
freewidget(e);
e = next;
}
free(grid);
}
/* TODO gridadd and gridremove */
Grid*
newgrid(Point size, Gridentry **ws)
{
Grid *grid;
for(int c = 0; ws[c] != nil; c++)
{
print("c = %d\n", c);
ws[c]->next = ws[c+1];
}
grid = emallocz(sizeof(*grid), 1);
wdefaults(grid);
grid->kind = gridkind;
grid->redraw = gridredraw;
// grid->kbdevent = gridkbd;
grid->mouseevent = gridmouse;
grid->cleanup = gridfree;
grid->size = size;
grid->widgets = *ws;
return grid;
}
/* TODO variadic constructor */