commit 75115e459d76c7f38fe5e743f90b2c4f0d21055a
parent 5d21899cd0709d59584964aed6e94c536f08c911
Author: lumidify <nobody@lumidify.org>
Date: Mon, 22 Feb 2021 19:54:14 +0100
Change ltk_widget to use a vtable
This avoids storing the functions pointers
separately for each instance of a widget.
Diffstat:
M | box.c | | | 48 | ++++++++++++++++++++++++++---------------------- |
M | button.c | | | 15 | +++++++++++---- |
M | draw.c | | | 11 | ++++++++--- |
M | grid.c | | | 32 | ++++++++++++++++++-------------- |
M | label.c | | | 8 | ++++++-- |
M | ltk.h | | | 33 | +++++++++++++++++++-------------- |
M | ltkd.c | | | 71 | ++++++++++++++++++++++++++++------------------------------------------- |
M | scrollbar.c | | | 12 | ++++++++---- |
8 files changed, 124 insertions(+), 106 deletions(-)
diff --git a/box.c b/box.c
@@ -52,6 +52,17 @@ static int ltk_box_mouse_press(ltk_widget *self, XEvent event);
static int ltk_box_mouse_release(ltk_widget *self, XEvent event);
static int ltk_box_motion_notify(ltk_widget *self, XEvent event);
+static struct ltk_widget_vtable vtable = {
+ .draw = <k_box_draw,
+ .destroy = <k_box_destroy,
+ .resize = <k_recalculate_box,
+ .child_size_change = <k_box_child_size_change,
+ .remove_child = <k_box_remove,
+ .mouse_press = <k_box_mouse_press,
+ .mouse_release = <k_box_mouse_release,
+ .motion_notify = <k_box_motion_notify
+};
+
static int ltk_box_cmd_add(
ltk_window *window,
char **tokens,
@@ -84,23 +95,16 @@ ltk_box_draw(ltk_widget *self, ltk_rect clip) {
ptr = box->widgets[i];
/* FIXME: Maybe continue immediately if widget is
obviously outside of clipping rect */
- ptr->draw(ptr, real_clip);
+ ptr->vtable->draw(ptr, real_clip);
}
- box->sc->widget.draw((ltk_widget *)box->sc, real_clip);
+ box->sc->widget.vtable->draw((ltk_widget *)box->sc, real_clip);
}
static ltk_box *
ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) {
ltk_box *box = ltk_malloc(sizeof(ltk_box));
- ltk_fill_widget_defaults(&box->widget, id, window, <k_box_draw,
- NULL, <k_box_destroy, 0, LTK_BOX);
- box->widget.mouse_press = <k_box_mouse_press;
- box->widget.mouse_release = <k_box_mouse_release;
- box->widget.motion_notify = <k_box_motion_notify;
- box->widget.resize = <k_recalculate_box;
- box->widget.child_size_change = <k_box_child_size_change;
- box->widget.remove_child = <k_box_remove;
+ ltk_fill_widget_defaults(&box->widget, id, window, &vtable, 0, LTK_BOX);
box->sc = ltk_scrollbar_create(window, orient, <k_box_scroll, box);
box->widgets = NULL;
@@ -118,13 +122,13 @@ ltk_box_destroy(ltk_widget *self, int shallow) {
if (!shallow) {
for (size_t i = 0; i < box->num_widgets; i++) {
ptr = box->widgets[i];
- ptr->destroy(ptr, shallow);
+ ptr->vtable->destroy(ptr, shallow);
}
}
ltk_free(box->widgets);
ltk_remove_widget(box->widget.id);
ltk_free(box->widget.id);
- box->sc->widget.destroy((ltk_widget *)box->sc, 0);
+ box->sc->widget.vtable->destroy((ltk_widget *)box->sc, 0);
ltk_free(box);
}
@@ -151,8 +155,8 @@ ltk_recalculate_box(ltk_widget *self) {
ptr->rect.y = box->widget.rect.y + box->widget.rect.h - ptr->rect.h - sc_rect->h;
else
ptr->rect.y = box->widget.rect.y + (box->widget.rect.h - ptr->rect.h) / 2;
- if (ptr->resize)
- ptr->resize(ptr);
+ if (ptr->vtable->resize)
+ ptr->vtable->resize(ptr);
cur_pos += ptr->rect.w;
} else {
ptr->rect.y = cur_pos - box->sc->cur_pos;
@@ -164,8 +168,8 @@ ltk_recalculate_box(ltk_widget *self) {
ptr->rect.x = box->widget.rect.x + box->widget.rect.w - ptr->rect.w - sc_rect->w;
else
ptr->rect.x = box->widget.rect.x + (box->widget.rect.w - ptr->rect.w) / 2;
- if (ptr->resize)
- ptr->resize(ptr);
+ if (ptr->vtable->resize)
+ ptr->vtable->resize(ptr);
cur_pos += ptr->rect.h;
}
}
@@ -214,8 +218,8 @@ ltk_box_child_size_change(ltk_widget *self, ltk_widget *widget) {
size_changed = 1;
}
- if (size_changed && box->widget.parent && box->widget.parent->child_size_change)
- box->widget.parent->child_size_change(box->widget.parent, (ltk_widget *)box);
+ if (size_changed && box->widget.parent && box->widget.parent->vtable->child_size_change)
+ box->widget.parent->vtable->child_size_change(box->widget.parent, (ltk_widget *)box);
else
ltk_recalculate_box((ltk_widget *)box);
}
@@ -279,16 +283,16 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_widget *self, char **
if (box->widgets[j]->ideal_h + sc_h > box->widget.ideal_h)
box->widget.ideal_h = box->widgets[j]->ideal_h + sc_h;
}
- if (box->widget.parent && box->widget.parent->resize)
- box->widget.parent->resize(box->widget.parent);
+ if (box->widget.parent && box->widget.parent->vtable->resize)
+ box->widget.parent->vtable->resize(box->widget.parent);
} else if (box->orient == LTK_VERTICAL && widget->ideal_w + sc_w == box->widget.ideal_w) {
box->widget.ideal_w = 0;
for (size_t j = 0; j < box->num_widgets; j++) {
if (box->widgets[j]->ideal_w + sc_w > box->widget.ideal_w)
box->widget.ideal_w = box->widgets[j]->ideal_w + sc_w;
}
- if (box->widget.parent && box->widget.parent->resize)
- box->widget.parent->resize(box->widget.parent);
+ if (box->widget.parent && box->widget.parent->vtable->resize)
+ box->widget.parent->vtable->resize(box->widget.parent);
}
return 0;
}
diff --git a/button.c b/button.c
@@ -42,6 +42,16 @@ static int ltk_button_mouse_release(ltk_widget *self, XEvent event);
static ltk_button *ltk_button_create(ltk_window *window,
const char *id, const char *text);
static void ltk_button_destroy(ltk_widget *self, int shallow);
+static void ltk_button_change_state(ltk_widget *self);
+static void ltk_button_resize(ltk_widget *self);
+
+static struct ltk_widget_vtable vtable = {
+ .mouse_release = <k_button_mouse_release,
+ .change_state = <k_button_change_state,
+ .draw = <k_button_draw,
+ .destroy = <k_button_destroy,
+ .resize = <k_button_resize
+};
static struct {
int border_width;
@@ -244,10 +254,7 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) {
char *text_copy;
ltk_button *button = ltk_malloc(sizeof(ltk_button));
- ltk_fill_widget_defaults(&button->widget, id, window,
- <k_button_draw, <k_button_change_state, <k_button_destroy, 1, LTK_BUTTON);
- button->widget.mouse_release = <k_button_mouse_release;
- button->widget.resize = <k_button_resize;
+ ltk_fill_widget_defaults(&button->widget, id, window, &vtable, 1, LTK_BUTTON);
uint16_t font_size = window->theme.font_size;
text_copy = ltk_strdup(text);
button->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
diff --git a/draw.c b/draw.c
@@ -45,6 +45,13 @@ static void ltk_draw_clear(ltk_window *window, ltk_draw *draw);
static void ltk_draw_set_color(ltk_window *window, ltk_draw *draw, const char *color);
static void ltk_draw_line(ltk_window *window, ltk_draw *draw, int x1, int y1, int x2, int y2);
static void ltk_draw_rect(ltk_window *window, ltk_draw *draw, int x, int y, int w, int h, int fill);
+
+static struct ltk_widget_vtable vtable = {
+ .draw = <k_draw_draw,
+ .resize = <k_draw_resize,
+ .destroy = <k_draw_destroy,
+};
+
static int ltk_draw_cmd_clear(
ltk_window *window,
char **tokens,
@@ -85,9 +92,7 @@ static ltk_draw *
ltk_draw_create(ltk_window *window, const char *id, int w, int h, const char *color) {
ltk_draw *draw = ltk_malloc(sizeof(ltk_draw));
- ltk_fill_widget_defaults(&draw->widget, id, window,
- <k_draw_draw, NULL, <k_draw_destroy, 1, LTK_DRAW);
- draw->widget.resize = <k_draw_resize;
+ ltk_fill_widget_defaults(&draw->widget, id, window, &vtable, 1, LTK_DRAW);
draw->widget.rect.w = w;
draw->widget.rect.h = h;
draw->pix = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth);
diff --git a/grid.c b/grid.c
@@ -60,6 +60,17 @@ static int ltk_grid_mouse_press(ltk_widget *self, XEvent event);
static int ltk_grid_mouse_release(ltk_widget *self, XEvent event);
static int ltk_grid_motion_notify(ltk_widget *self, XEvent event);
+static struct ltk_widget_vtable vtable = {
+ .draw = <k_grid_draw,
+ .destroy = <k_grid_destroy,
+ .resize = <k_recalculate_grid,
+ .child_size_change = <k_grid_child_size_change,
+ .remove_child = <k_grid_ungrid,
+ .mouse_press = <k_grid_mouse_press,
+ .mouse_release = <k_grid_mouse_release,
+ .motion_notify = <k_grid_motion_notify
+};
+
static int ltk_grid_cmd_add(
ltk_window *window,
char **tokens,
@@ -106,7 +117,7 @@ ltk_grid_draw(ltk_widget *self, ltk_rect clip) {
if (!grid->widget_grid[i])
continue;
ltk_widget *ptr = grid->widget_grid[i];
- ptr->draw(ptr, clip);
+ ptr->vtable->draw(ptr, clip);
}
}
@@ -114,14 +125,7 @@ static ltk_grid *
ltk_grid_create(ltk_window *window, const char *id, int rows, int columns) {
ltk_grid *grid = ltk_malloc(sizeof(ltk_grid));
- ltk_fill_widget_defaults(&grid->widget, id, window, <k_grid_draw,
- NULL, <k_grid_destroy, 0, LTK_GRID);
- grid->widget.mouse_press = <k_grid_mouse_press;
- grid->widget.mouse_release = <k_grid_mouse_release;
- grid->widget.motion_notify = <k_grid_motion_notify;
- grid->widget.resize = <k_recalculate_grid;
- grid->widget.child_size_change = <k_grid_child_size_change;
- grid->widget.remove_child = <k_grid_ungrid;
+ ltk_fill_widget_defaults(&grid->widget, id, window, &vtable, 0, LTK_GRID);
grid->rows = rows;
grid->columns = columns;
@@ -170,7 +174,7 @@ ltk_grid_destroy(ltk_widget *self, int shallow) {
grid->widget_grid[r * grid->columns + c] = NULL;
}
}
- ptr->destroy(ptr, shallow);
+ ptr->vtable->destroy(ptr, shallow);
}
}
}
@@ -248,8 +252,8 @@ ltk_recalculate_grid(ltk_widget *self) {
ptr->rect.h = grid->row_pos[end_row] - grid->row_pos[i];
}
if (orig_width != ptr->rect.w || orig_height != ptr->rect.h) {
- if (ptr->resize) {
- ptr->resize(ptr);
+ if (ptr->vtable->resize) {
+ ptr->vtable->resize(ptr);
}
}
@@ -291,8 +295,8 @@ ltk_grid_child_size_change(ltk_widget *self, ltk_widget *widget) {
grid->row_heights[widget->row] = widget->rect.h;
size_changed = 1;
}
- if (size_changed && grid->widget.parent && grid->widget.parent->child_size_change)
- grid->widget.parent->child_size_change(grid->widget.parent, (ltk_widget *)grid);
+ if (size_changed && grid->widget.parent && grid->widget.parent->vtable->child_size_change)
+ grid->widget.parent->vtable->child_size_change(grid->widget.parent, (ltk_widget *)grid);
else
ltk_recalculate_grid((ltk_widget *)grid);
}
diff --git a/label.c b/label.c
@@ -42,6 +42,11 @@ static ltk_label *ltk_label_create(ltk_window *window,
const char *id, const char *text);
static void ltk_label_destroy(ltk_widget *self, int shallow);
+static struct ltk_widget_vtable vtable = {
+ .draw = <k_label_draw,
+ .destroy = <k_label_destroy
+};
+
static struct {
LtkColor text_color;
LtkColor bg_color;
@@ -98,8 +103,7 @@ ltk_label_create(ltk_window *window, const char *id, const char *text) {
char *text_copy;
ltk_label *label = ltk_malloc(sizeof(ltk_label));
- ltk_fill_widget_defaults(&label->widget, id, window,
- <k_label_draw, NULL, <k_label_destroy, 1, LTK_LABEL);
+ ltk_fill_widget_defaults(&label->widget, id, window, &vtable, 1, LTK_LABEL);
uint16_t font_size = window->theme.font_size;
text_copy = ltk_strdup(text);
label->tl = ltk_text_line_create(window->xwindow, font_size, text_copy, -1);
diff --git a/ltk.h b/ltk.h
@@ -71,20 +71,36 @@ typedef enum {
struct ltk_window;
+struct ltk_widget_vtable;
+
typedef struct ltk_widget {
struct ltk_window *window;
struct ltk_widget *active_widget;
struct ltk_widget *parent;
char *id;
+ struct ltk_widget_vtable *vtable;
+
ltk_rect rect;
unsigned int ideal_w;
unsigned int ideal_h;
+ ltk_widget_type type;
+ ltk_widget_state state;
+ unsigned int sticky;
+ unsigned short row;
+ unsigned short column;
+ unsigned short row_span;
+ unsigned short column_span;
+ unsigned char needs_redraw;
+} ltk_widget;
+
+struct ltk_widget_vtable {
void (*key_press) (struct ltk_widget *, XEvent);
void (*key_release) (struct ltk_widget *, XEvent);
int (*mouse_press) (struct ltk_widget *, XEvent);
int (*mouse_release) (struct ltk_widget *, XEvent);
+ int (*mouse_wheel) (struct ltk_widget *, XEvent);
int (*motion_notify) (struct ltk_widget *, XEvent);
void (*mouse_leave) (struct ltk_widget *, XEvent);
void (*mouse_enter) (struct ltk_widget *, XEvent);
@@ -96,16 +112,7 @@ typedef struct ltk_widget {
void (*child_size_change) (struct ltk_widget *, struct ltk_widget *);
int (*remove_child) (struct ltk_window *, struct ltk_widget *, struct ltk_widget *, char **);
-
- ltk_widget_type type;
- ltk_widget_state state;
- unsigned int sticky;
- unsigned short row;
- unsigned short column;
- unsigned short row_span;
- unsigned short column_span;
- unsigned char needs_redraw;
-} ltk_widget;
+};
typedef struct {
int border_width;
@@ -159,10 +166,8 @@ void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, co
int ltk_collide_rect(ltk_rect rect, int x, int y);
void ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget);
void ltk_window_set_pressed_widget(ltk_window *window, ltk_widget *widget);
-void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window * window,
- void (*draw) (ltk_widget *, ltk_rect), void (*change_state) (ltk_widget *),
- void (*destroy) (ltk_widget *, int), unsigned int needs_redraw,
- ltk_widget_type type);
+void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
+ struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type);
void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event);
void ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event);
void ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event);
diff --git a/ltkd.c b/ltkd.c
@@ -432,8 +432,8 @@ ltk_set_root_widget_cmd(
ltk_window_invalidate_rect(window, widget->rect);
widget->rect.w = window->rect.w;
widget->rect.h = window->rect.h;
- if (widget->resize)
- widget->resize(widget);
+ if (widget->vtable->resize)
+ widget->vtable->resize(widget);
return 0;
}
@@ -516,7 +516,7 @@ ltk_redraw_window(ltk_window *window) {
if (!window->root_widget) return;
ptr = window->root_widget;
if (ptr)
- ptr->draw(ptr, window->dirty_rect);
+ ptr->vtable->draw(ptr, window->dirty_rect);
}
static void
@@ -532,10 +532,10 @@ ltk_window_other_event(ltk_window *window, XEvent event) {
window->rect.w = w;
window->rect.h = h;
ltk_window_invalidate_rect(window, window->rect);
- if (ptr && ptr->resize) {
+ if (ptr && ptr->vtable->resize) {
ptr->rect.w = w;
ptr->rect.h = h;
- ptr->resize(ptr);
+ ptr->vtable->resize(ptr);
}
}
} else if (event.type == Expose && event.xexpose.count == 0) {
@@ -617,7 +617,7 @@ ltk_destroy_widget_hash(void) {
for (k = kh_begin(widget_hash); k != kh_end(widget_hash); k++) {
if (kh_exist(widget_hash, k)) {
ptr = kh_value(widget_hash, k);
- ptr->destroy(ptr, 1);
+ ptr->vtable->destroy(ptr, 1);
}
}
kh_destroy(widget, widget_hash);
@@ -699,33 +699,18 @@ ltk_collide_rect(ltk_rect rect, int x, int y) {
void
ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
- void (*draw) (ltk_widget *, ltk_rect), void (*change_state) (ltk_widget *),
- void (*destroy) (ltk_widget *, int), unsigned int needs_redraw,
- ltk_widget_type type) {
- if (id) {
+ struct ltk_widget_vtable *vtable, unsigned int needs_redraw, ltk_widget_type type) {
+ if (id)
widget->id = ltk_strdup(id);
- } else {
+ else
widget->id = NULL;
- }
widget->window = window;
widget->active_widget = NULL;
widget->parent = NULL;
widget->type = type;
- widget->key_press = NULL;
- widget->key_release = NULL;
- widget->mouse_press = NULL;
- widget->mouse_release = NULL;
- widget->motion_notify = NULL;
- widget->mouse_enter = NULL;
- widget->mouse_leave = NULL;
-
- widget->resize = NULL;
- widget->draw = draw;
- widget->change_state = change_state;
- widget->destroy = destroy;
- widget->child_size_change = NULL;
- widget->remove_child = NULL;
+ /* FIXME: possibly check that draw and destroy aren't NULL */
+ widget->vtable = vtable;
widget->needs_redraw = needs_redraw;
widget->state = LTK_NORMAL;
@@ -746,8 +731,8 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
static void
ltk_widget_change_state(ltk_widget *widget) {
- if (widget->change_state)
- widget->change_state(widget);
+ if (widget->vtable->change_state)
+ widget->vtable->change_state(widget);
if (widget->needs_redraw)
ltk_window_invalidate_rect(widget->window, widget->rect);
}
@@ -792,8 +777,8 @@ ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) {
if (!widget || widget->state == LTK_DISABLED)
return;
int default_handler = 1;
- if (widget->mouse_press)
- default_handler = widget->mouse_press(widget, event);
+ if (widget->vtable->mouse_press)
+ default_handler = widget->vtable->mouse_press(widget, event);
if (default_handler) {
if (event.xbutton.button == 1)
ltk_window_set_pressed_widget(widget->window, widget);
@@ -805,8 +790,8 @@ ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
if (!widget || widget->state == LTK_DISABLED)
return;
int default_handler = 1;
- if (widget->mouse_release)
- default_handler = widget->mouse_release(widget, event);
+ if (widget->vtable->mouse_release)
+ default_handler = widget->vtable->mouse_release(widget, event);
if (default_handler)
ltk_window_set_pressed_widget(widget->window, NULL);
}
@@ -823,19 +808,19 @@ ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
(widget->state == LTK_ACTIVE && widget->window->active_widget != widget)) &&
!widget->window->pressed_widget) {
widget->state = LTK_ACTIVE;
- if (widget->change_state)
- widget->change_state(widget);
- if (widget->mouse_enter)
- widget->mouse_enter(widget, event);
+ if (widget->vtable->change_state)
+ widget->change_statevtable->(widget);
+ if (widget->vtable->mouse_enter)
+ widget->mouse_entervtable->(widget, event);
ltk_window_remove_active_widget(widget->window);
ltk_window_set_active_widget(widget);
}
*/
int default_handler = 1;
- if (widget->window->pressed_widget && widget->window->pressed_widget->motion_notify)
- default_handler = widget->window->pressed_widget->motion_notify(widget->window->pressed_widget, event);
- else if (widget->motion_notify)
- default_handler = widget->motion_notify(widget, event);
+ if (widget->window->pressed_widget && widget->window->pressed_widget->vtable->motion_notify)
+ default_handler = widget->window->pressed_widget->vtable->motion_notify(widget->window->pressed_widget, event);
+ else if (widget->vtable->motion_notify)
+ default_handler = widget->vtable->motion_notify(widget, event);
if (default_handler)
ltk_window_set_active_widget(widget->window, widget);
}
@@ -1223,12 +1208,12 @@ ltk_widget_destroy(
ltk_remove_widget(tokens[1]);
/* widget->parent->remove_child should never be NULL because of the fact that
the widget is set as parent, but let's just check anyways... */
- if (widget->parent && widget->parent->remove_child) {
- err = widget->parent->remove_child(
+ if (widget->parent && widget->parent->vtable->remove_child) {
+ err = widget->parent->vtable->remove_child(
window, widget, widget->parent, errstr
);
}
- widget->destroy(widget, shallow);
+ widget->vtable->destroy(widget, shallow);
return err;
}
diff --git a/scrollbar.c b/scrollbar.c
@@ -41,6 +41,13 @@ static int ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event);
static int ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event);
static void ltk_scrollbar_destroy(ltk_widget *self, int shallow);
+static struct ltk_widget_vtable vtable = {
+ .draw = <k_scrollbar_draw,
+ .mouse_press = <k_scrollbar_mouse_press,
+ .motion_notify = <k_scrollbar_motion_notify,
+ .destroy = <k_scrollbar_destroy
+};
+
static struct {
int size; /* width or height, depending on orientation */
LtkColor bg_normal;
@@ -228,11 +235,8 @@ ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
ltk_scrollbar *
ltk_scrollbar_create(ltk_window *window, ltk_orientation orient, void (*callback)(ltk_widget *), void *data) {
ltk_scrollbar *sc = ltk_malloc(sizeof(ltk_scrollbar));
- ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, <k_scrollbar_draw,
- NULL, <k_scrollbar_destroy, 1, LTK_UNKNOWN);
+ ltk_fill_widget_defaults((ltk_widget *)sc, NULL, window, &vtable, 1, LTK_UNKNOWN);
sc->last_mouse_x = sc->last_mouse_y = 0;
- sc->widget.motion_notify = <k_scrollbar_motion_notify;
- sc->widget.mouse_press = <k_scrollbar_mouse_press;
/* This cannot be 0 because that leads to divide-by-zero */
sc->virtual_size = 1;
sc->cur_pos = 0;