commit c25f7ed3099b6026f5e0c169e30a8a28719d5633
parent 2ed1efbf50d122e1120e32416b71c9838d9c3880
Author: lumidify <nobody@lumidify.org>
Date: Fri, 22 Jan 2021 19:42:03 +0100
Somewhat fix mouse event handling
Diffstat:
M | box.c | | | 47 | +++++++++++++++++++++++------------------------ |
M | button.c | | | 5 | +++-- |
M | grid.c | | | 36 | +++++++++++++++++++++++------------- |
M | ltk.h | | | 10 | +++++----- |
M | ltkd.c | | | 125 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
M | scrollbar.c | | | 25 | +++++++++++++++---------- |
M | scrollbar.h | | | 6 | ++++-- |
7 files changed, 128 insertions(+), 126 deletions(-)
diff --git a/box.c b/box.c
@@ -43,10 +43,11 @@ static void ltk_box_child_size_change(ltk_box *box, ltk_widget *widget);
static int ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, unsigned short sticky, char **errstr);
static int ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errstr);
/* static int ltk_box_clear(ltk_window *window, ltk_box *box, int shallow, char **errstr); */
-static void ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent));
-static void ltk_box_mouse_press(ltk_box *box, XEvent event);
-static void ltk_box_mouse_release(ltk_box *box, XEvent event);
-static void ltk_box_motion_notify(ltk_box *box, XEvent event);
+static void ltk_box_scroll(ltk_box *box);
+static int ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent));
+static int ltk_box_mouse_press(ltk_box *box, XEvent event);
+static int ltk_box_mouse_release(ltk_box *box, XEvent event);
+static int ltk_box_motion_notify(ltk_box *box, XEvent event);
static int ltk_box_cmd_add(
ltk_window *window,
@@ -99,7 +100,7 @@ ltk_box_create(ltk_window *window, const char *id, ltk_orientation orient) {
box->widget.child_size_change = <k_box_child_size_change;
box->widget.remove_child = <k_box_remove;
- box->sc = ltk_scrollbar_create(window, orient);
+ box->sc = ltk_scrollbar_create(window, orient, <k_box_scroll, box);
box->widgets = NULL;
box->num_alloc = 0;
box->num_widgets = 0;
@@ -291,48 +292,46 @@ ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_box *box, char **errs
}
static void
+ltk_box_scroll(ltk_box *box) {
+ ltk_recalculate_box(box);
+ ltk_window_invalidate_rect(box->widget.window, box->widget.rect);
+}
+
+static int
ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent)) {
int pos, start, size;
ltk_widget *widget;
int old_sc_pos = box->sc->cur_pos;
- /* FIXME: THIS IS A HACK! */
- if ((handler == <k_widget_motion_notify_event && box->sc->widget.state == LTK_PRESSED) ||
- (ltk_collide_rect(box->sc->widget.rect, event.xbutton.x, event.xbutton.y))) {
+ if (ltk_collide_rect(box->sc->widget.rect, event.xbutton.x, event.xbutton.y)) {
handler(box->sc, event);
- if (old_sc_pos != box->sc->cur_pos) {
- ltk_recalculate_box(box);
- ltk_window_invalidate_rect(box->widget.window, box->widget.rect);
- }
- return;
+ return 0;
}
- /* FIXME: When scrolling is implemented, check only the currently visible items */
+ /* FIXME: When scrolling is implemented properly, check only the currently visible items */
for (size_t i = 0; i < box->num_widgets; i++) {
widget = box->widgets[i];
if (ltk_collide_rect(widget->rect, event.xbutton.x, event.xbutton.y)) {
handler(widget, event);
- return;
+ return 0;
}
}
+ return 0;
}
-static void
+static int
ltk_box_mouse_press(ltk_box *box, XEvent event) {
- ltk_box_mouse_event(box, event, <k_widget_mouse_press_event);
+ return ltk_box_mouse_event(box, event, <k_widget_mouse_press_event);
}
-static void
+static int
ltk_box_mouse_release(ltk_box *box, XEvent event) {
- ltk_box_mouse_event(box, event, <k_widget_mouse_release_event);
+ return ltk_box_mouse_event(box, event, <k_widget_mouse_release_event);
}
-/* FIXME: Release events shouldn't happen if that widget wasn't actually
- pressed! Scrollbar still needs to receive motion notify while pressed
- even if not actually hovered over! */
-static void
+static int
ltk_box_motion_notify(ltk_box *box, XEvent event) {
- ltk_box_mouse_event(box, event, <k_widget_motion_notify_event);
+ return ltk_box_mouse_event(box, event, <k_widget_motion_notify_event);
}
/* box <box id> add <widget id> [sticky] */
diff --git a/button.c b/button.c
@@ -37,7 +37,7 @@
#include "button.h"
static void ltk_button_draw(ltk_button *button, ltk_rect clip);
-static void ltk_button_mouse_release(ltk_button *button, XEvent event);
+static int ltk_button_mouse_release(ltk_button *button, XEvent event);
static ltk_button *ltk_button_create(ltk_window *window,
const char *id, const char *text);
static void ltk_button_destroy(ltk_button *button, int shallow);
@@ -192,9 +192,10 @@ ltk_button_change_state(ltk_button *button) {
ltk_text_line_render(button->tl, fill, &theme.text_color);
}
-static void
+static int
ltk_button_mouse_release(ltk_button *button, XEvent event) {
ltk_queue_event(button->widget.window, LTK_EVENT_BUTTON, button->widget.id, "button_click");
+ return 1;
}
static ltk_button *
diff --git a/grid.c b/grid.c
@@ -53,9 +53,9 @@ static int ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid,
static int ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_grid *grid, char **errstr);
static int ltk_grid_find_nearest_column(ltk_grid *grid, int x);
static int ltk_grid_find_nearest_row(ltk_grid *grid, int y);
-static void ltk_grid_mouse_press(ltk_grid *grid, XEvent event);
-static void ltk_grid_mouse_release(ltk_grid *grid, XEvent event);
-static void ltk_grid_motion_notify(ltk_grid *grid, XEvent event);
+static int ltk_grid_mouse_press(ltk_grid *grid, XEvent event);
+static int ltk_grid_mouse_release(ltk_grid *grid, XEvent event);
+static int ltk_grid_motion_notify(ltk_grid *grid, XEvent event);
static int ltk_grid_cmd_add(
ltk_window *window,
@@ -356,46 +356,56 @@ ltk_grid_find_nearest_row(ltk_grid *grid, int y) {
return -1;
}
-static void
+static int
ltk_grid_mouse_press(ltk_grid *grid, XEvent event) {
int x = event.xbutton.x;
int y = event.xbutton.y;
int row = ltk_grid_find_nearest_row(grid, y);
int column = ltk_grid_find_nearest_column(grid, x);
if (row == -1 || column == -1)
- return;
+ return 0;
ltk_widget *ptr = grid->widget_grid[row * grid->columns + column];
- if (ptr && ltk_collide_rect(ptr->rect, x, y))
+ if (ptr && ltk_collide_rect(ptr->rect, x, y)) {
ltk_widget_mouse_press_event(ptr, event);
+ return 0;
+ }
+ return 0;
}
-static void
+static int
ltk_grid_mouse_release(ltk_grid *grid, XEvent event) {
int x = event.xbutton.x;
int y = event.xbutton.y;
int row = ltk_grid_find_nearest_row(grid, y);
int column = ltk_grid_find_nearest_column(grid, x);
if (row == -1 || column == -1)
- return;
+ return 0;
ltk_widget *ptr = grid->widget_grid[row * grid->columns + column];
- if (ptr && ltk_collide_rect(ptr->rect, x, y))
+ if (ptr && ltk_collide_rect(ptr->rect, x, y)) {
ltk_widget_mouse_release_event(ptr, event);
+ return 0;
+ }
+ return 0;
}
-static void
+static int
ltk_grid_motion_notify(ltk_grid *grid, XEvent event) {
+ /* FIXME: Why does it check this? */
short pressed = (event.xmotion.state & Button1Mask) == Button1Mask;
if (pressed)
- return;
+ return 0;
int x = event.xbutton.x;
int y = event.xbutton.y;
int row = ltk_grid_find_nearest_row(grid, y);
int column = ltk_grid_find_nearest_column(grid, x);
if (row == -1 || column == -1)
- return;
+ return 0;
ltk_widget *ptr = grid->widget_grid[row * grid->columns + column];
- if (ptr && ltk_collide_rect(ptr->rect, x, y))
+ if (ptr && ltk_collide_rect(ptr->rect, x, y)) {
ltk_widget_motion_notify_event(ptr, event);
+ return 0;
+ }
+ return 0;
}
/* grid <grid id> add <widget id> <row> <column> <row_span> <column_span> [sticky] */
diff --git a/ltk.h b/ltk.h
@@ -83,9 +83,9 @@ typedef struct ltk_widget {
void (*key_press) (void *, XEvent);
void (*key_release) (void *, XEvent);
- void (*mouse_press) (void *, XEvent);
- void (*mouse_release) (void *, XEvent);
- void (*motion_notify) (void *, XEvent);
+ int (*mouse_press) (void *, XEvent);
+ int (*mouse_release) (void *, XEvent);
+ int (*motion_notify) (void *, XEvent);
void (*mouse_leave) (void *, XEvent);
void (*mouse_enter) (void *, XEvent);
@@ -160,8 +160,8 @@ void ltk_fatal_errno(const char *format, ...);
int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col);
void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data);
int ltk_collide_rect(ltk_rect rect, int x, int y);
-void ltk_remove_active_widget(ltk_widget *widget);
-void ltk_set_active_widget(ltk_window *window, ltk_widget *widget);
+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) (void *), void (*change_state) (void *),
void (*destroy) (void *, int), unsigned int needs_redraw,
diff --git a/ltkd.c b/ltkd.c
@@ -725,42 +725,6 @@ ltk_collide_rect(ltk_rect rect, int x, int y) {
&& (rect.y + rect.h) >= y);
}
-static void
-ltk_widget_change_state(ltk_widget *widget) {
- if (widget->change_state)
- widget->change_state(widget);
- if (widget->needs_redraw)
- ltk_window_invalidate_rect(widget->window, widget->rect);
-}
-
-void
-ltk_window_remove_active_widget(ltk_window *window) {
- ltk_widget *widget = window->active_widget;
- if (!widget) return;
- while (widget) {
- widget->state = LTK_NORMAL;
- widget->active_widget = NULL;
- ltk_widget_change_state(widget);
- widget = widget->parent;
- }
- window->active_widget = NULL;
-}
-
-void
-ltk_window_set_active_widget(ltk_widget *widget) {
- widget->window->active_widget = widget;
- ltk_widget *parent = widget->parent;
- while (widget) {
- widget->state = LTK_ACTIVE;
- ltk_widget_change_state(widget);
- if (parent)
- parent->active_widget = widget;
- widget = parent;
- if (parent)
- parent = widget->parent;
- }
-}
-
void
ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
void (*draw) (void *), void (*change_state) (void *),
@@ -810,32 +774,46 @@ ltk_fill_widget_defaults(ltk_widget *widget, const char *id, ltk_window *window,
widget->sticky = 0;
}
+static void
+ltk_widget_change_state(ltk_widget *widget) {
+ if (widget->change_state)
+ widget->change_state(widget);
+ if (widget->needs_redraw)
+ ltk_window_invalidate_rect(widget->window, widget->rect);
+}
+
void
-ltk_widget_set_pressed(ltk_window *window, ltk_widget *widget) {
- ltk_widget *act = window->active_widget;
- ltk_widget *pre = window->pressed_widget;
- if (pre) {
- if (act) {
- act->state = LTK_NORMAL;
- if (act->needs_redraw)
- ltk_window_invalidate_rect(window, act->rect);
- if (act->change_state)
- act->change_state(act);
- }
- pre->state = LTK_ACTIVE;
- window->active_widget = pre;
- if (pre->needs_redraw)
- ltk_window_invalidate_rect(window, pre->rect);
- if (pre->change_state)
- pre->change_state(pre);
+ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget) {
+ if (window->active_widget == widget)
+ return;
+ if (window->active_widget) {
+ window->active_widget->state = LTK_NORMAL;
+ ltk_widget_change_state(window->active_widget);
+ }
+ window->active_widget = widget;
+ if (widget) {
+ widget->state = LTK_ACTIVE;
+ ltk_widget_change_state(widget);
+ }
+}
+
+/* FIXME: Should pressed widget also be set as active widget? */
+void
+ltk_window_set_pressed_widget(ltk_window *window, ltk_widget *widget) {
+ if (window->pressed_widget == widget)
+ return;
+ if (window->active_widget && window->active_widget != widget) {
+ window->active_widget->state = LTK_NORMAL;
+ ltk_widget_change_state(window->active_widget);
+ }
+ if (window->pressed_widget) {
+ window->pressed_widget->state = LTK_ACTIVE;
+ ltk_widget_change_state(window->pressed_widget);
}
window->pressed_widget = widget;
if (widget) {
widget->state = LTK_PRESSED;
- if (widget->needs_redraw)
- ltk_window_invalidate_rect(widget->window, widget->rect);
- if (widget->change_state)
- widget->change_state(widget);
+ ltk_widget_change_state(widget);
}
}
@@ -843,30 +821,34 @@ void
ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) {
if (!widget || widget->state == LTK_DISABLED)
return;
- if (event.xbutton.button == 1)
- ltk_widget_set_pressed(widget->window, widget);
+ int default_handler = 1;
if (widget->mouse_press)
- widget->mouse_press(widget, event);
+ default_handler = widget->mouse_press(widget, event);
+ if (default_handler) {
+ if (event.xbutton.button == 1)
+ ltk_window_set_pressed_widget(widget->window, widget);
+ }
}
void
ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
- if (!widget)
- return;
- /* FIXME: MAKE THIS WORK MORE CONSISTENTLY FOR OTHER MOUSE BUTTONS */
- ltk_widget_set_pressed(widget->window, NULL);
- if (widget->state == LTK_DISABLED)
+ if (!widget || widget->state == LTK_DISABLED)
return;
+ int default_handler = 1;
if (widget->mouse_release)
- widget->mouse_release(widget, event);
+ default_handler = widget->mouse_release(widget, event);
+ if (default_handler)
+ ltk_window_set_pressed_widget(widget->window, NULL);
}
/* FIXME: ONLY SET ACTIVE WIDGET AT BOTTOM OF HIERARCHY
-> Don't first set parent as active widget and then child */
void
ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
- if (!widget) return;
+ if (!widget || widget->state == LTK_DISABLED)
+ return;
/* FIXME: THIS WHOLE STATE HANDLING IS STILL PARTIALLY BROKEN */
+ /*
if (((widget->state == LTK_NORMAL) ||
(widget->state == LTK_ACTIVE && widget->window->active_widget != widget)) &&
!widget->window->pressed_widget) {
@@ -875,14 +857,17 @@ ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) {
widget->change_state(widget);
if (widget->mouse_enter)
widget->mouse_enter(widget, event);
- /* FIXME: do this properly */
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)
- widget->window->pressed_widget->motion_notify(widget->window->pressed_widget, event);
+ default_handler = widget->window->pressed_widget->motion_notify(widget->window->pressed_widget, event);
else if (widget->motion_notify)
- widget->motion_notify(widget, event);
+ default_handler = widget->motion_notify(widget, event);
+ if (default_handler)
+ ltk_window_set_active_widget(widget->window, widget);
}
static void
diff --git a/scrollbar.c b/scrollbar.c
@@ -36,8 +36,8 @@
#include "scrollbar.h"
static void ltk_scrollbar_draw(ltk_scrollbar *scrollbar, ltk_rect clip);
-static void ltk_scrollbar_mouse_press(ltk_scrollbar *scrollbar, XEvent event);
-static void ltk_scrollbar_motion_notify(ltk_scrollbar *scrollbar, XEvent event);
+static int ltk_scrollbar_mouse_press(ltk_scrollbar *scrollbar, XEvent event);
+static int ltk_scrollbar_motion_notify(ltk_scrollbar *scrollbar, XEvent event);
static void ltk_scrollbar_destroy(ltk_scrollbar *scrollbar, int shallow);
static struct {
@@ -99,7 +99,7 @@ ltk_scrollbar_set_virtual_size(ltk_scrollbar *scrollbar, int virtual_size) {
/* FIXME: some sort of error? */
if (virtual_size <= 0)
return;
- scrollbar->cur_pos = (int)(((double)scrollbar->cur_pos / scrollbar->virtual_size) * virtual_size);
+ scrollbar->cur_pos = ((double)scrollbar->cur_pos / scrollbar->virtual_size) * virtual_size;
scrollbar->virtual_size = virtual_size;
}
@@ -158,22 +158,23 @@ ltk_scrollbar_draw(ltk_scrollbar *scrollbar, ltk_rect clip) {
handle_x, handle_y, handle_w, handle_h);
}
-static void
+static int
ltk_scrollbar_mouse_press(ltk_scrollbar *scrollbar, XEvent event) {
if (event.xbutton.button != 1)
- return;
+ return 1;
scrollbar->last_mouse_x = scrollbar->widget.rect.x;
scrollbar->last_mouse_y = scrollbar->widget.rect.y;
scrollbar->cur_pos = 0;
ltk_scrollbar_motion_notify(scrollbar, event);
+ return 1;
}
-static void
+static int
ltk_scrollbar_motion_notify(ltk_scrollbar *sc, XEvent event) {
double scale;
int delta, max_pos;
if (sc->widget.state != LTK_PRESSED)
- return;
+ return 1;
if (sc->orient == LTK_HORIZONTAL) {
delta = event.xbutton.x - sc->last_mouse_x;
max_pos = sc->virtual_size > sc->widget.rect.w ? sc->virtual_size - sc->widget.rect.w : 0;
@@ -183,18 +184,20 @@ ltk_scrollbar_motion_notify(ltk_scrollbar *sc, XEvent event) {
max_pos = sc->virtual_size > sc->widget.rect.h ? sc->virtual_size - sc->widget.rect.h : 0;
scale = sc->virtual_size / (double)sc->widget.rect.h;
}
- /* FIXME: This doesn't work because delta is always only one pixel or so */
- sc->cur_pos += (int)(scale * delta);
+ sc->cur_pos += scale * delta;
if (sc->cur_pos < 0)
sc->cur_pos = 0;
else if (sc->cur_pos > max_pos)
sc->cur_pos = max_pos;
sc->last_mouse_x = event.xbutton.x;
sc->last_mouse_y = event.xbutton.y;
+ if (delta > 0)
+ sc->callback(sc->callback_data);
+ return 1;
}
ltk_scrollbar *
-ltk_scrollbar_create(ltk_window *window, ltk_orientation orient) {
+ltk_scrollbar_create(ltk_window *window, ltk_orientation orient, void (*callback)(void *), void *data) {
ltk_scrollbar *sc = malloc(sizeof(ltk_scrollbar));
if (!sc)
ltk_fatal_errno("Unable to allocate memory for scrollbar.\n");
@@ -211,6 +214,8 @@ ltk_scrollbar_create(ltk_window *window, ltk_orientation orient) {
sc->widget.rect.h = theme.size;
else
sc->widget.rect.w = theme.size;
+ sc->callback = callback;
+ sc->callback_data = data;
return sc;
}
diff --git a/scrollbar.h b/scrollbar.h
@@ -28,7 +28,9 @@
typedef struct {
ltk_widget widget;
- int cur_pos;
+ void (*callback)(void *);
+ void *callback_data;
+ double cur_pos;
int virtual_size;
int last_mouse_x;
int last_mouse_y;
@@ -38,6 +40,6 @@ typedef struct {
void ltk_scrollbar_set_virtual_size(ltk_scrollbar *scrollbar, int virtual_size);
void ltk_scrollbar_setup_theme_defaults(ltk_window *window);
void ltk_scrollbar_ini_handler(ltk_window *window, const char *prop, const char *value);
-ltk_scrollbar *ltk_scrollbar_create(ltk_window *window, ltk_orientation orient);
+ltk_scrollbar *ltk_scrollbar_create(ltk_window *window, ltk_orientation orient, void (*callback)(void *), void *data);
#endif /* _LTK_SCROLLBAR_H_ */