ref: e74727d7e806863494a92d4b5cdcefdeee7495e9
parent: 5549503afffbd360061e5a36d3488e3fb101f504
author: Tevo <estevan.cps@gmail.com>
date: Sat Jul 3 17:04:52 EDT 2021
Grid WIP
--- a/cmd/factory/factory.c
+++ b/cmd/factory/factory.c
@@ -20,7 +20,7 @@
Widgetctl *wctl;
Widgetmsg *msg;
Menumsg mmsg;
- Box *root;
+ Widget *root;
Rune rune;
ARGBEGIN {
@@ -48,11 +48,27 @@
.lasthit = -1
};
- root = newcenterbox(
- newtextbutton(nil, "hello, world!")
+ Gridentry *entries[] =
+ {
+ newgridentry(
+ Pt(0, 0),
+ Pt(1, 1),
+ newtextbutton(nil, "hello, world!")
+ ),
+ newgridentry(
+ Pt(0, 1),
+ Pt(2, 1),
+ newtextbutton(nil, "haha")
+ ),
+ nil
+ };
+
+ root = newgrid(
+ GRID_DYNAMIC_SIZE,
+ entries
);
- root->maxsize = Pt(256, 128);
+ // root->content->maxsize = Pt(256, 128);
if((wctl = initwidget(screen, nil, nil, root, FORWARD_KBD)) == nil)
sysfatal("initwidget: %r");
--- /dev/null
+++ b/libwidget/grid.c
@@ -1,0 +1,274 @@
+#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 */
--- /dev/null
+++ b/libwidget/grid.h
@@ -1,0 +1,41 @@
+/*** Grid ***/
+
+typedef struct Gridentry Gridentry;
+
+struct Gridentry
+{
+ Widget;
+
+ Box *content;
+
+ Point position, size;
+
+ /**/
+ Gridentry *next;
+};
+
+int isgridentry(Widget*);
+
+Gridentry* newgridentry(Point position, Point size, Widget*);
+
+/**/
+
+typedef struct Grid Grid;
+
+struct Grid
+{
+ Widget;
+
+ Point size;
+ Gridentry *widgets;
+};
+
+int isgrid(Widget*);
+
+Point gridsize(Widget*);
+Gridentry* gridat(Widget*, Point);
+
+extern Point GRID_DYNAMIC_SIZE;
+
+Grid* newgrid(Point size, Gridentry**);
+
--- a/libwidget/mkfile
+++ b/libwidget/mkfile
@@ -6,7 +6,8 @@
base.$O \
textbox.$O \
button.$O \
- box.$O
+ box.$O \
+ grid.$O
HDR=widget.h
@@ -14,7 +15,8 @@
base.h \
textbox.h \
box.h \
- button.h
+ button.h \
+ grid.h
HFILES=\
/sys/include/$HDR \