shithub: widget

Download patch

ref: 1d84452255fa2d3c41ac2596f39d61d7e3b27b12
parent: ec1aec49349dab76af4e3063eb11e8a030c87de0
author: Tevo <[email protected]>
date: Sun Jan 10 22:09:39 EST 2021

Box is (hopefully) not a piece of shit anymore

--- a/CONVENTIONS
+++ b/CONVENTIONS
@@ -1,7 +1,6 @@
 • widgets that encapsulate other widgets:
 	- take ownership (responsible for freeing, etc)
-	- are responsible for ensuring their subwidgets don't stomp
-all over the screen
+	- are responsible for ensuring their subwidgets don't stomp all over the screen
 • widgets should make sure global state is consistent with how it was when their functions were invoked (i.e. if you touch screen->clipr, restore it before returning, etc)
 • Widget->draw returns size of widget
-• event handling functions return 1 for when they handled the event themselves and 0 when they didn't
+• event handling functions return 1 for when they (or one of their children) handled the event and 0 when they didn't
--- a/TODO
+++ b/TODO
@@ -1,3 +1,2 @@
-• figure out a way to reduce boilerplate for each widget
+• figure out a way to reduce boilerplate for each widget(?)
 • not sure if pulling every base widget dependency along the library is a great idea, maybe split the headers (<widget.h>, then <widget/textbox.h>, <widget/button.h>, etc)?
-• figure out widget-generated event handling
--- a/cmd/factory/factory.c
+++ b/cmd/factory/factory.c
@@ -19,7 +19,7 @@
 {
 	Widgetctl *wctl;
 	Widgetmsg *msg;
-	Button *root;
+	Box *root;
 	Rune rune;
 
 	ARGBEGIN {
@@ -30,8 +30,12 @@
 	if(initdraw(nil, nil, "widget factory") < 0)
 		sysfatal("initdraw: %r");
 
-	root = newtextbutton(nil, "hello, world!");
+	root = newbox(
+		newtextbutton(nil, "hello, world!"), 0
+	);
 
+	root->maxsize = Pt(256, 128);
+
 	if((wctl = initwidget(screen, nil, nil, root, FORWARD_KBD)) == nil)
 		sysfatal("initwidget: %r");
 
@@ -56,10 +60,10 @@
 			switch(msg->what)
 			{
 			case M_BUTTON_PRESSED:
-				print("button %d was pressed!\n", msg->sender->id);
+			//	print("button %d was pressed!\n", msg->sender->id);
 				break;
 			case M_BUTTON_RELEASED:
-				print("button %d was released!\n", msg->sender->id);
+			//	print("button %d was released!\n", msg->sender->id);
 				break;
 			}
 			free(msg);
--- a/libwidget/base.h
+++ b/libwidget/base.h
@@ -34,6 +34,9 @@
 	Keyboardctl *kbd;
 	Mousectl *mouse;
 
+	/* if non-nil, shown when widgets don't handle the respective mouse events */
+	Menu *left, *middle, *right;
+
 	Image *image;
 
 	int flags;
@@ -47,6 +50,14 @@
 {
 	FORWARD_KBD		= 1<<0,
 	FORWARD_MOUSE	= 1<<1
+};
+
+enum /* mouse buttons */
+{
+	M_LEFT		= 1<<0,
+	M_MIDDLE	= 1<<1,
+	M_RIGHT		= 1<<2
+	/* TODO add scroll up/down */
 };
 
 struct Widgetmsg
--- a/libwidget/box.c
+++ b/libwidget/box.c
@@ -26,43 +26,72 @@
 	return (Box*)w;
 }
 
+/* centers a inside b */
+static Rectangle
+centerrect(Rectangle a, Rectangle b)
+{
+	Rectangle a’, b’;
+	Point ps;
+
+	a’ = rectsubpt(a, a.min);
+	b’ = rectsubpt(b, b.min);
+
+	ps = divpt(b’.max, 2);
+	ps = subpt(ps, divpt(a’.max, 2));
+
+	return Rpt(addpt(b.min, ps), subpt(b.max, ps));
+}
+
 Point
 boxredraw(Widget *w, Image *dst, Rectangle r)
 {
-	Image *tmp;
 	Box *box;
-	Point boxsz, pos, sz;
+	/* wrect = where widget is allowed to draw, arect = where widget actually drew */
+	Rectangle wrect, arect;
+	Image *tmp;
+	Point sz;
 
 	box = coerce(w);
+	if(memcmp(&box->maxsize, &ZP, sizeof(Point)) != 0) /* box->maxsize != ZP */
+	{
+		wrect = Rpt(r.min, addpt(r.min, box->maxsize));
+		rectclip(&wrect, r);
+	}
+	else
+		wrect = r;
 
-	tmp = allocimage(dst->display, r, RGBA32, 0, DTransparent);
-	sz  = redrawwidget(box->content, tmp, r);
+	if(box->flags & B_CENTER_CONTENT)
+		wrect = centerrect(wrect, r);
 
-	pos = boxsz = subpt(r.max, r.min);
-	pos = divpt(pos, 2);
-	pos = subpt(pos, divpt(sz, 2));
+	tmp = allocimage(dst->display, wrect, RGBA32, 0, DTransparent);
+	sz  = redrawwidget(box->content, tmp, wrect);
 
-	box->conrect = Rpt(pos, subpt(r.max, pos));
+	if(box->flags & B_CENTER_CONTENT)
+		arect = centerrect(Rpt(ZP, sz), r);
+	else
+		arect = Rpt(r.min, addpt(r.min, sz));
 
 	draw(dst, r, box->bg, nil, ZP);
-	draw(dst, box->conrect, tmp, nil, ZP);
+	draw(dst, arect, tmp, nil, wrect.min);
 
 	freeimage(tmp);
 
-	return boxsz;
+	box->bounds = wrect;
+
+	return subpt(r.max, r.min);
 }
 
 int
-boxmouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
+boxmouse(Widget *w, Image *dst, Rectangle, Mouse m, Channel *chan)
 {
 	Box *box;
 
 	box = coerce(w);
 
-	if(ptinrect(m.xy, box->conrect))
+	if(ptinrect(m.xy, box->bounds))
 	{
 		box->focused = 1;
-		return mouseevent(box->content, dst, rect, m, chan);
+		return mouseevent(box->content, dst, box->bounds, m, chan);
 	}
 	else
 		box->focused = 0;
@@ -71,7 +100,7 @@
 }
 
 int
-boxkbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
+boxkbd(Widget *w, Image *dst, Rectangle, Rune r, Channel *chan)
 {
 	Box *box;
 
@@ -78,7 +107,7 @@
 	box = coerce(w);
 
 	if(box->focused)
-		return kbdevent(box->content, dst, rect, r, chan);
+		return kbdevent(box->content, dst, box->bounds, r, chan);
 
 	return 0;
 }
@@ -103,6 +132,7 @@
 	box->kind	= boxkind;
 	box->redraw	= boxredraw;
 	box->flags	= flags;
+	box->maxsize	= ZP;
 	box->kbdevent	= boxkbd;
 	box->mouseevent	= boxmouse;
 	box->cleanup	= boxfree;
--- a/libwidget/box.h
+++ b/libwidget/box.h
@@ -9,9 +9,11 @@
 	Widget *content;
 	int flags;
 
+	Point maxsize;
+
 	/* don't touch */
-	Rectangle conrect;
 	int focused;
+	Rectangle bounds;
 };
 
 enum /* flags */