shithub: widget

Download patch

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	\