diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-12-07 20:20:27 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-12-07 20:20:27 +0100 |
commit | 864ee5f167d1e2dda9bfce24ef617d71ce49bfd8 (patch) | |
tree | 14c3bfe2d9b28dce43be9efae8e18156de7787fc /src/mgui/scrollview.c | |
parent | d3a5b3d579e30ce02afd5e270dfdd511af195c31 (diff) |
scrollview
Diffstat (limited to 'src/mgui/scrollview.c')
-rw-r--r-- | src/mgui/scrollview.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/mgui/scrollview.c b/src/mgui/scrollview.c new file mode 100644 index 0000000..ae9ad97 --- /dev/null +++ b/src/mgui/scrollview.c @@ -0,0 +1,128 @@ +#include "../../include/mgui/scrollview.h" +#include "../../include/mgui/mgui.h" +#include "../../include/alloc.h" +#include <mgl/mgl.h> +#include <mgl/window/window.h> +#include <mgl/window/event.h> +#include <assert.h> + +#define SCROLL_ACCEL 20.0f +#define SCROLL_DEACCEL 10.0f + +/* TODO: free child */ + +mgui_scrollview* mgui_scrollview_create() { + mgui_scrollview *scrollview = mgui_alloc(sizeof(mgui_scrollview)); + mgui_widget_init(&scrollview->widget, MGUI_WIDGET_SCROLLVIEW); + scrollview->child = NULL; + scrollview->child_size = (mgl_vec2i){ 0, 0 }; + scrollview->position = (mgl_vec2i){ 0, 0 }; + scrollview->size = (mgl_vec2i){ 0, 0 }; + scrollview->scroll = (mgl_vec2i){ 0, 0 }; + scrollview->mouse_scroll = (mgl_vec2f){ 0.0f, 0.0f }; + return scrollview; +} + +mgui_widget* mgui_scrollview_to_widget(mgui_scrollview *list) { + return &list->widget; +} + +mgui_scrollview* mgui_widget_to_scrollview(mgui_widget *widget) { + assert(widget->type == MGUI_WIDGET_SCROLLVIEW); + return (mgui_scrollview*)widget; +} + +void mgui_scrollview_set_child(mgui_scrollview *self, mgui_widget *child) { + assert(child != mgui_scrollview_to_widget(self)); + self->child = child; +} + +void mgui_scrollview_set_position(mgui_scrollview *self, mgl_vec2i position) { + self->position = position; +} + +void mgui_scrollview_set_size(mgui_scrollview *self, mgl_vec2i size) { + self->size = size; +} + +void mgui_scrollview_set_width(mgui_scrollview *self, int width) { + /* TODO: Call for child so text can wordwrap? but only if wordwrap is enabled in this scrollview */ + (void)self; + (void)width; +} + +void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_event *event) { + /* TODO: Allow keyboard navigation if scrollview has focus */ + if(event->type == MGL_EVENT_MOUSE_WHEEL_SCROLLED) + self->mouse_scroll.y += (event->mouse_wheel_scroll.delta * SCROLL_ACCEL); + + if(self->child) + mgui_widget_on_event(self->child, window, event); +} + +static float max_float(float a, float b) { + return a >= b ? a : b; +} + +static int max_int(int a, int b) { + return a >= b ? a : b; +} + +static int min_int(int a, int b) { + return a <= b ? a : b; +} + +static float abs_float(float value) { + return value >= 0.0f ? value : -value; +} + +/* TODO: Check if visible in scissor */ + +mgl_vec2i mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { + const double frame_time = mgui_get_seconds_since_last_update(); + self->mouse_scroll.x *= max_float(0.0f, (1.0f - frame_time * SCROLL_DEACCEL)); + self->mouse_scroll.y *= max_float(0.0f, (1.0f - frame_time * SCROLL_DEACCEL)); + + if(abs_float(self->mouse_scroll.x) < 0.0001f) + self->mouse_scroll.x = 0.0f; + + if(abs_float(self->mouse_scroll.y) < 0.0001f) + self->mouse_scroll.y = 0.0f; + + self->scroll.x += (int)self->mouse_scroll.x; + self->scroll.y += (int)self->mouse_scroll.y; + + if(self->child_size.x > self->size.x) { + self->scroll.x = min_int(self->scroll.x, 0); + self->scroll.x = max_int(self->scroll.x, -self->child_size.x + self->size.x); + } else { + self->scroll.x = 0; + } + + if(self->child_size.y > self->size.y) { + self->scroll.y = min_int(self->scroll.y, 0); + self->scroll.y = max_int(self->scroll.y, -self->child_size.y + self->size.y); + } else { + self->scroll.y = 0; + } + + if(self->child) { + mgl_scissor prev_scissor; + mgl_window_get_scissor(window, &prev_scissor); + + mgl_scissor new_scissor = { + .position = self->position, + .size = self->size + }; + mgl_window_set_scissor(window, &new_scissor); + + mgui_widget_set_position(self->child, (mgl_vec2i){ self->position.x + self->scroll.x, self->position.y + self->scroll.y }); + self->child_size = mgui_widget_draw(self->child, window); + + mgl_window_set_scissor(window, &prev_scissor); + } else { + self->child_size = (mgl_vec2i){ 0, 0 }; + } + + return self->child_size; +} |