jwidget: add a per-widget clipping setting

This commit is contained in:
Lephenixnoir 2022-11-19 23:42:38 +01:00
parent 67219834be
commit 950c5b7152
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
3 changed files with 61 additions and 2 deletions

View File

@ -89,8 +89,10 @@ typedef struct jwidget {
uint visible :1;
/* Widget is floating outside the layout (and positioned manually) */
uint floating :1;
/* Widget is clipped during rendering */
uint clipped :1;
uint :23;
uint :22;
} jwidget;
@ -358,6 +360,23 @@ bool jwidget_visible(void *w);
/* jwidget_set_visible(): Hide or show a widget */
void jwidget_set_visible(void *w, bool visible);
/* jwidget_clipped(): Whether widget is clipped
If a widget is clipped then its rendering function cannot draw pixels
outside of its bounding box. There is no performance cost to this feature
because it relies on underlying gint rendering functions already supporting
clipping.
This is disabled by default because it is convenient to have widgets draw
outside their bounding box. For instance it is easier to align a single-
line label by setting the font's bearing as its height, and then drawing
glyphs' tails outside the bouding box. It is also harder to spot layout
issues if the widgets are clipped away. */
bool jwidget_clipped(void *w);
/* jwidget_set_clipped(): Set a widget's rendering clipping preference */
void jwidget_set_clipped(void *w, bool clipped);
/* jwidget_needs_update(): Check whether the tree needs to be re-rendered
If this function returns true, you should re-render the tree. Aditionally,

View File

@ -109,6 +109,7 @@ void jwidget_init(jwidget *w, int type, void *parent)
w->dirty = 1;
w->visible = 1;
w->floating = 0;
w->clipped = 0;
w->type = type;
w->geometry = NULL;
@ -597,6 +598,21 @@ void jwidget_set_floating(void *w0, bool floating)
if(w->parent) w->parent->dirty = 1;
}
bool jwidget_clipped(void *w0)
{
J_CAST(w)
return w->clipped;
}
void jwidget_set_clipped(void *w0, bool clipped)
{
J_CAST(w)
if(w->clipped == clipped) return;
w->clipped = (clipped != 0);
w->update = 1;
}
//---
// Rendering
//---
@ -643,7 +659,18 @@ void jwidget_render(void *w0, int x, int y)
y += g->margin.top + b.top + g->padding.top;
jwidget_poly const *poly = widget_types[w->type];
if(poly->render) poly->render(w, x, y);
if(poly->render) {
if(w->clipped) {
struct dwindow win = { x, y, x+cw, y+ch };
win = intersect_dwindow(win, dwindow);
struct dwindow old_window = dwindow_set(win);
poly->render(w, x, y);
dwindow_set(old_window);
}
else {
poly->render(w, x, y);
}
}
w->update = 0;
}

View File

@ -6,6 +6,7 @@
#define _J_UTIL
#include <justui/defs.h>
#include <gint/display.h>
/* Clamp a value between two ends. */
__attribute__((always_inline))
@ -20,4 +21,16 @@ static inline int clamp(int value, int min, int max)
/* Code point for a character input */
uint32_t keymap_translate(int key, bool shift, bool alpha);
/* Intersect two dwindow settings. */
static inline struct dwindow intersect_dwindow(
struct dwindow d1, struct dwindow d2)
{
struct dwindow win;
win.left = max(d1.left, d2.left);
win.top = max(d1.top, d2.top);
win.right = max(min(d1.right, d2.right), win.left);
win.bottom = max(min(d1.bottom, d2.bottom), win.top);
return win;
}
#endif /* _J_UTIL */