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 */