commit 33cf30d1cfde0826ff45ce7b876ca2c1d8dbc9b9
parent d1f0903f23c0887590329483d8993cbefb1b6189
Author: lumidify <nobody@lumidify.org>
Date: Sun, 8 May 2022 17:10:22 +0200
Make scrolling normal
Diffstat:
5 files changed, 100 insertions(+), 78 deletions(-)
diff --git a/src/box.c b/src/box.c
@@ -315,7 +315,7 @@ ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XE
return 0;
}
- /* FIXME: When scrolling is implemented properly, check only the currently visible items */
+ /* FIXME: 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)) {
@@ -329,7 +329,26 @@ ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XE
static int
ltk_box_mouse_press(ltk_widget *self, XEvent event) {
ltk_box *box = (ltk_box *)self;
- return ltk_box_mouse_event(box, event, <k_widget_mouse_press_event);
+ /* FIXME: combine multiple events into one for efficiency */
+ /* FIXME: fix this whole state handling */
+ if (event.xbutton.button == 4 || event.xbutton.button == 5) {
+ ltk_widget *widget;
+ int default_handler = 1;
+ 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)) {
+ if (widget->vtable->mouse_press)
+ default_handler = widget->vtable->mouse_press(widget, event);
+ }
+ }
+ if (default_handler) {
+ int delta = event.xbutton.button == 4 ? -15 : 15;
+ ltk_scrollbar_scroll((ltk_widget *)box->sc, delta, 0);
+ }
+ return 0;
+ } else {
+ return ltk_box_mouse_event(box, event, <k_widget_mouse_press_event);
+ }
}
static int
diff --git a/src/button.c b/src/button.c
@@ -189,12 +189,16 @@ ltk_button_change_state(ltk_widget *self) {
self->dirty = 1;
}
+/* FIXME: only when pressed button was actually this one */
static int
ltk_button_mouse_release(ltk_widget *self, XEvent event) {
(void)event;
ltk_button *button = (ltk_button *)self;
- ltk_queue_event(button->widget.window, LTK_EVENT_BUTTON, button->widget.id, "button_click");
- return 1;
+ if (event.xbutton.button == 1) {
+ ltk_queue_event(button->widget.window, LTK_EVENT_BUTTON, button->widget.id, "button_click");
+ return 1;
+ }
+ return 0;
}
static ltk_button *
diff --git a/src/scrollbar.c b/src/scrollbar.c
@@ -109,12 +109,35 @@ ltk_scrollbar_set_virtual_size(ltk_scrollbar *scrollbar, int virtual_size) {
scrollbar->virtual_size = virtual_size;
}
+static ltk_rect
+get_handle_rect(ltk_scrollbar *sc) {
+ ltk_rect r;
+ ltk_rect sc_rect = sc->widget.rect;
+ if (sc->orient == LTK_HORIZONTAL) {
+ r.y = 0;
+ r.h = sc_rect.h;
+ r.x = (int)((sc->cur_pos / (double)sc->virtual_size) * sc_rect.w);
+ if (sc->virtual_size > sc_rect.w)
+ r.w = (int)((sc_rect.w / (double)sc->virtual_size) * sc_rect.w);
+ else
+ r.w = sc_rect.w;
+ } else {
+ r.x = 0;
+ r.w = sc_rect.w;
+ r.y = (int)((sc->cur_pos / (double)sc->virtual_size) * sc_rect.h);
+ if (sc->virtual_size > sc_rect.h)
+ r.h = (int)((sc_rect.h / (double)sc->virtual_size) * sc_rect.h);
+ else
+ r.h = sc_rect.h;
+ }
+ return r;
+}
+
static void
ltk_scrollbar_draw(ltk_widget *self, ltk_rect clip) {
/* FIXME: dirty attribute */
ltk_scrollbar *scrollbar = (ltk_scrollbar *)self;
ltk_color *bg = NULL, *fg = NULL;
- int handle_x, handle_y, handle_w, handle_h;
ltk_rect rect = scrollbar->widget.rect;
switch (scrollbar->widget.state) {
case LTK_NORMAL:
@@ -141,24 +164,7 @@ ltk_scrollbar_draw(ltk_widget *self, ltk_rect clip) {
ltk_surface_fill_rect(s, bg, (ltk_rect){0, 0, rect.w, rect.h});
/* FIXME: maybe too much calculation in draw function - move to
resizing function? */
- if (scrollbar->orient == LTK_HORIZONTAL) {
- handle_y = 0;
- handle_h = rect.h;
- handle_x = (int)((scrollbar->cur_pos / (double)scrollbar->virtual_size) * rect.w);
- if (scrollbar->virtual_size > rect.w)
- handle_w = (int)((rect.w / (double)scrollbar->virtual_size) * rect.w);
- else
- handle_w = rect.w;
- } else {
- handle_x = 0;
- handle_w = rect.w;
- handle_y = (int)((scrollbar->cur_pos / (double)scrollbar->virtual_size) * rect.h);
- if (scrollbar->virtual_size > rect.h)
- handle_h = (int)((rect.h / (double)scrollbar->virtual_size) * rect.h);
- else
- handle_h = rect.h;
- }
- ltk_surface_fill_rect(s, fg, (ltk_rect){handle_x, handle_y, handle_w, handle_h});
+ ltk_surface_fill_rect(s, fg, get_handle_rect(scrollbar));
ltk_rect clip_final = ltk_rect_intersect(clip, rect);
ltk_surface_copy(s, self->window->surface, ltk_rect_relative(rect, clip_final), clip_final.x, clip_final.y);
}
@@ -167,64 +173,71 @@ static int
ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event) {
ltk_scrollbar *sc = (ltk_scrollbar *)self;
int max_pos;
- double rel_pos;
- if (event.xbutton.button != 1 && event.xbutton.button != 3)
+ if (event.xbutton.button != 1)
return 0;
+ int ex = event.xbutton.x, ey = event.xbutton.y;
+ ltk_rect handle_rect = get_handle_rect(sc);
if (sc->orient == LTK_HORIZONTAL) {
- rel_pos = (event.xbutton.x - sc->widget.rect.x) / (double)sc->widget.rect.w;
+ if (ex < handle_rect.x || ex > handle_rect.x + handle_rect.w) {
+ sc->cur_pos = (sc->virtual_size / (double)sc->widget.rect.w) * (ex - handle_rect.w / 2 - sc->widget.rect.x);
+ }
max_pos = sc->virtual_size > sc->widget.rect.w ? sc->virtual_size - sc->widget.rect.w : 0;
} else {
- rel_pos = (event.xbutton.y - sc->widget.rect.y) / (double)sc->widget.rect.h;
+ if (ey < handle_rect.y || ey > handle_rect.y + handle_rect.h) {
+ sc->cur_pos = (sc->virtual_size / (double)sc->widget.rect.h) * (ey - handle_rect.h / 2 - sc->widget.rect.y);
+ }
max_pos = sc->virtual_size > sc->widget.rect.h ? sc->virtual_size - sc->widget.rect.h : 0;
}
- /* On right click, move the scrollbar left/up by 30% of the total size times how far
- away the click is from the right/bottom.
- On left click, move the scrollbar right/down by 30% of the total size times how far
- away the click is from the left/top. */
- if (event.xbutton.button == 1) {
- sc->cur_pos += rel_pos * sc->virtual_size * 0.3;
- } else if (event.xbutton.button == 3) {
- sc->cur_pos -= (1 - rel_pos) * sc->virtual_size * 0.3;
- }
-
if (sc->cur_pos < 0)
sc->cur_pos = 0;
else if (sc->cur_pos > max_pos)
sc->cur_pos = max_pos;
sc->callback(sc->callback_data);
- return 0;
+ sc->last_mouse_x = event.xbutton.x;
+ sc->last_mouse_y = event.xbutton.y;
+ return 1;
}
-/* FIXME: Make this scrollbar more "traditional" */
-static int
-ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
- (void)self;
- (void)event;
+/* FIXME: also queue redraw */
+/* FIXME: improve interface (scaled is weird) */
+void
+ltk_scrollbar_scroll(ltk_widget *self, int delta, int scaled) {
ltk_scrollbar *sc = (ltk_scrollbar *)self;
+ int max_pos;
double scale;
- int delta, max_pos;
- if (self->state != LTK_PRESSED) {
- 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;
scale = sc->virtual_size / (double)sc->widget.rect.w;
} else {
- delta = event.xbutton.y - sc->last_mouse_y;
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;
}
- sc->cur_pos += scale * delta;
+ if (scaled)
+ sc->cur_pos += scale * delta;
+ else
+ sc->cur_pos += delta;
if (sc->cur_pos < 0)
sc->cur_pos = 0;
else if (sc->cur_pos > max_pos)
sc->cur_pos = max_pos;
+ sc->callback(sc->callback_data);
+}
+
+static int
+ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) {
+ ltk_scrollbar *sc = (ltk_scrollbar *)self;
+ int delta;
+ if (self->state != LTK_PRESSED) {
+ return 1;
+ }
+ if (sc->orient == LTK_HORIZONTAL)
+ delta = event.xbutton.x - sc->last_mouse_x;
+ else
+ delta = event.xbutton.y - sc->last_mouse_y;
+ ltk_scrollbar_scroll(self, delta, 1);
sc->last_mouse_x = event.xbutton.x;
sc->last_mouse_y = event.xbutton.y;
- if (delta > 0)
- sc->callback(sc->callback_data);
- return 1;
+ return 0;
}
ltk_scrollbar *
diff --git a/src/scrollbar.h b/src/scrollbar.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 lumidify <nobody@lumidify.org>
+ * Copyright (c) 2021, 2022 lumidify <nobody@lumidify.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,5 +34,6 @@ 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, void (*callback)(ltk_widget *), void *data);
+void ltk_scrollbar_scroll(ltk_widget *self, int delta, int scaled);
#endif /* _LTK_SCROLLBAR_H_ */
diff --git a/src/widget.c b/src/widget.c
@@ -130,39 +130,24 @@ void
ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) {
if (!widget || widget->state == LTK_DISABLED)
return;
- int default_handler = 1;
if (widget->vtable->mouse_release)
- default_handler = widget->vtable->mouse_release(widget, event);
- if (default_handler)
- ltk_window_set_pressed_widget(widget->window, NULL);
+ widget->vtable->mouse_release(widget, event);
+ 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 || 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) {
- widget->state = LTK_ACTIVE;
- if (widget->vtable->change_state)
- widget->vtable->change_state(widget);
- if (widget->vtable->mouse_enter)
- widget->vtable->mouse_enter(widget, event);
- ltk_window_remove_active_widget(widget->window);
- ltk_window_set_active_widget(widget);
+ int set_active = 1;
+ if (widget->window->pressed_widget && widget->window->pressed_widget->vtable->motion_notify) {
+ widget->window->pressed_widget->vtable->motion_notify(widget->window->pressed_widget, event);
+ set_active = 0;
+ } else if (widget->vtable->motion_notify) {
+ set_active = widget->vtable->motion_notify(widget, event);
}
- */
- int default_handler = 1;
- 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)
+ if (set_active)
ltk_window_set_active_widget(widget->window, widget);
}