ref: 1d84452255fa2d3c41ac2596f39d61d7e3b27b12
parent: ec1aec49349dab76af4e3063eb11e8a030c87de0
author: Tevo <estevan.cps@gmail.com>
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 */