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=\