shithub: widget

Download patch

ref: ec1aec49349dab76af4e3063eb11e8a030c87de0
parent: 86177eda0338c6773955897d9b5105fe89c980a0
author: Tevo <[email protected]>
date: Sun Jan 10 13:43:04 EST 2021

Simple box

--- a/libwidget/base.c
+++ b/libwidget/base.c
@@ -158,7 +158,8 @@
 void
 freewidget(Widget *w)
 {
-	w->cleanup(w);
+	if(w != nil)	/* freeing nil widgets should be a no-op */
+		w->cleanup(w);
 }
 
 void
--- /dev/null
+++ b/libwidget/box.c
@@ -1,0 +1,118 @@
+#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 *boxkind = "Box";
+
+int
+isbox(Widget *w)
+{
+	return strcmp(w->kind, boxkind) == 0;
+}
+
+static Box*
+coerce(Widget *w)
+{
+	if(!isbox(w))
+		werror("coerce: not a box");
+
+	return (Box*)w;
+}
+
+Point
+boxredraw(Widget *w, Image *dst, Rectangle r)
+{
+	Image *tmp;
+	Box *box;
+	Point boxsz, pos, sz;
+
+	box = coerce(w);
+
+	tmp = allocimage(dst->display, r, RGBA32, 0, DTransparent);
+	sz  = redrawwidget(box->content, tmp, r);
+
+	pos = boxsz = subpt(r.max, r.min);
+	pos = divpt(pos, 2);
+	pos = subpt(pos, divpt(sz, 2));
+
+	box->conrect = Rpt(pos, subpt(r.max, pos));
+
+	draw(dst, r, box->bg, nil, ZP);
+	draw(dst, box->conrect, tmp, nil, ZP);
+
+	freeimage(tmp);
+
+	return boxsz;
+}
+
+int
+boxmouse(Widget *w, Image *dst, Rectangle rect, Mouse m, Channel *chan)
+{
+	Box *box;
+
+	box = coerce(w);
+
+	if(ptinrect(m.xy, box->conrect))
+	{
+		box->focused = 1;
+		return mouseevent(box->content, dst, rect, m, chan);
+	}
+	else
+		box->focused = 0;
+
+	return 0;
+}
+
+int
+boxkbd(Widget *w, Image *dst, Rectangle rect, Rune r, Channel *chan)
+{
+	Box *box;
+
+	box = coerce(w);
+
+	if(box->focused)
+		return kbdevent(box->content, dst, rect, r, chan);
+
+	return 0;
+}
+
+void
+boxfree(Widget *w)
+{
+	Box *box;
+
+	box = coerce(w);
+	freewidget(box->content);
+	free(box);
+}
+
+Box*
+newbox(Widget *w, int flags)
+{
+	Box *box;
+
+	box = emallocz(sizeof(*box), 1);
+	wdefaults(box);
+	box->kind	= boxkind;
+	box->redraw	= boxredraw;
+	box->flags	= flags;
+	box->kbdevent	= boxkbd;
+	box->mouseevent	= boxmouse;
+	box->cleanup	= boxfree;
+	box->content	= w;
+
+	return box;
+}
+
+Box*
+newcenterbox(Widget *w)
+{
+	return newbox(w, B_CENTER_CONTENT);
+}
--- /dev/null
+++ b/libwidget/box.h
@@ -1,0 +1,26 @@
+/*** Box ***/
+
+typedef struct Box Box;
+
+struct Box
+{
+	Widget;
+
+	Widget *content;
+	int flags;
+
+	/* don't touch */
+	Rectangle conrect;
+	int focused;
+};
+
+enum /* flags */
+{
+	B_CENTER_CONTENT	= 1<<0
+};
+
+int isbox(Widget*);
+
+Box* newbox(Widget*, int flags);
+Box* newcenterbox(Widget*);
+
--- a/libwidget/button.c
+++ b/libwidget/button.c
@@ -18,33 +18,26 @@
 	return strcmp(w->kind, btnkind) == 0;
 }
 
+static Button*
+coerce(Widget *w)
+{
+	if(!isbutton(w))
+		werror("coerce: not a button");
+
+	return (Button*)w;
+}
+
 Point
 btnredraw(Widget *w, Image *dst, Rectangle r)
 {
-	Image *tmp;
 	Button *btn;
-	Point btsz, pos, sz;
-	Rectangle conrect;
 
-	if(!isbutton(w))
-		werror("btnredraw: not a button");
+	btn = coerce(w);
 
-	btn = (Button*)w;
-	tmp = allocimage(dst->display, r, RGBA32, 0, DTransparent);
-	sz  = redrawwidget(btn->content, tmp, r);
+	btn->box->content = btn->content;
+	btn->box->bg = btn->pressed ? btn->fg : btn->bg;
 
-	pos = btsz = subpt(r.max, r.min);
-	pos = divpt(pos, 2);
-	pos = subpt(pos, divpt(sz, 2));
-
-	conrect = Rpt(pos, subpt(r.max, pos));
-
-	draw(dst, r, btn->pressed ? btn->fg : btn->bg, nil, ZP);
-	draw(dst, conrect, tmp, nil, ZP);
-
-	freeimage(tmp);
-
-	return btsz;
+	return redrawwidget(btn->box, dst, r);
 }
 
 int
@@ -54,10 +47,7 @@
 	int pressed;
 	Widgetmsg *msg;
 
-	if(!isbutton(w))
-		werror("btndraw: not a button");
-
-	btn = (Button*)w;
+	btn = coerce(w);
 	if((pressed = m.buttons & 1) != btn->pressed)
 	{
 		msg = newmsg(btn, pressed ? M_BUTTON_PRESSED : M_BUTTON_RELEASED);
@@ -75,11 +65,10 @@
 {
 	Button *btn;
 
-	if(!isbutton(w))
-		werror("btnfree: not a button");
-
-	btn = (Button*)w;
+	btn = coerce(w);
+	btn->box->content = nil;	/* to avoid double-free */
 	freewidget(btn->content);
+	freewidget(btn->box);
 	free(btn);
 }
 
@@ -98,6 +87,7 @@
 	wdefaults(btn);
 	btn->bg			= lightblue;
 	btn->fg			= darkblue;
+	btn->box		= newcenterbox(w);
 	btn->kind		= btnkind;
 	btn->redraw		= btnredraw;
 	btn->cleanup	= btnfree;
--- a/libwidget/button.h
+++ b/libwidget/button.h
@@ -8,6 +8,9 @@
 
 	Widget *content;
 	int pressed;
+
+	/* don't touch */
+	Box *box;
 };
 
 int isbutton(Widget*);
--- a/libwidget/mkfile
+++ b/libwidget/mkfile
@@ -5,7 +5,8 @@
 OFILES=\
 	base.$O		\
 	textbox.$O	\
-	button.$O
+	button.$O	\
+	box.$O
 
 HDR=widget.h
 
@@ -12,6 +13,7 @@
 HCOMP=\
 	base.h		\
 	textbox.h	\
+	box.h		\
 	button.h
 
 HFILES=\