diff options
Diffstat (limited to 'src/mgui/scrollview.c')
-rw-r--r-- | src/mgui/scrollview.c | 159 |
1 files changed, 103 insertions, 56 deletions
diff --git a/src/mgui/scrollview.c b/src/mgui/scrollview.c index a11862f..5cb4773 100644 --- a/src/mgui/scrollview.c +++ b/src/mgui/scrollview.c @@ -1,12 +1,14 @@ #include "../../include/mgui/scrollview.h" #include "../../include/mgui/mgui.h" #include "../../include/alloc.h" +#include "../../include/common.h" #include <mgl/mgl.h> #include <mgl/window/window.h> #include <mgl/window/event.h> #include <mgl/graphics/rectangle.h> #include <limits.h> #include <assert.h> +#include <stdio.h> #define SCROLL_ACCEL 20.0f #define SCROLL_DEACCEL 10.0f @@ -29,13 +31,17 @@ static float abs_float(float value) { return value >= 0.0f ? value : -value; } -mgui_scrollview* mgui_scrollview_create() { +mgui_scrollview* mgui_scrollview_create(void) { mgui_scrollview *scrollview = mgui_alloc(sizeof(mgui_scrollview)); mgui_widget_init(&scrollview->widget, MGUI_WIDGET_SCROLLVIEW); scrollview->child = NULL; scrollview->position = (mgl_vec2i){ 0, 0 }; scrollview->scroll = (mgl_vec2i){ 0, 0 }; scrollview->mouse_scroll = (mgl_vec2f){ 0.0f, 0.0f }; + scrollview->scrollbar_pos = (mgl_vec2f){ 0.0f, 0.0f }; + scrollview->scrollbar_size = (mgl_vec2f){ 0.0f, 0.0f }; + scrollview->scrollbar_move_prev_pos = (mgl_vec2f){ 0.0f, 0.0f }; + scrollview->moving_scrollbar = false; return scrollview; } @@ -84,33 +90,77 @@ void mgui_scrollview_on_event(mgui_scrollview *self, mgl_window *window, mgl_eve /* 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(event->type == MGL_EVENT_MOUSE_BUTTON_PRESSED + && event->mouse_button.button == MGL_BUTTON_LEFT + && mgui_rectangle_contains(self->scrollbar_pos, self->scrollbar_size, (mgl_vec2f){ event->mouse_button.x, event->mouse_button.y })) + { + self->moving_scrollbar = true; + self->scrollbar_move_prev_pos = (mgl_vec2f){ event->mouse_button.x, event->mouse_button.y }; + } else if(event->type == MGL_EVENT_MOUSE_BUTTON_RELEASED && event->mouse_button.button == MGL_BUTTON_LEFT) { + self->moving_scrollbar = false; + } if(self->child) mgui_widget_on_event(self->child, window, event); } -/* TODO: Check if visible in scissor */ +static void mgui_scrollview_handle_scrollbar_move(mgui_scrollview *self, mgl_window *window, double scrollbar_height_ratio) { + if(mgl_window_is_mouse_button_pressed(window, MGL_BUTTON_LEFT) && self->moving_scrollbar) { + mgl_vec2f mouse_move_diff = (mgl_vec2f){ + window->cursor_position.x - self->scrollbar_move_prev_pos.x, + window->cursor_position.y - self->scrollbar_move_prev_pos.y + }; + self->scrollbar_move_prev_pos.x = window->cursor_position.x; + self->scrollbar_move_prev_pos.y = window->cursor_position.y; -void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { - const double frame_time = mgui_get_frame_time_seconds(); - 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)); + /* TODO: Handle vertical scrollbar once its added */ + /* TODO: Not perfect, improve */ + if(scrollbar_height_ratio != 0.0) + self->scroll.y -= (mouse_move_diff.y * (1.0/scrollbar_height_ratio)); + } +} - if(abs_float(self->mouse_scroll.x) < 0.0001f) - self->mouse_scroll.x = 0.0f; +static void mgui_scrollview_draw_child(mgui_scrollview *self, mgl_window *window, double margin_width, double margin_height, double height, double scrollbar_height, mgl_vec2i child_size) { + if(!self->child) + return; - if(abs_float(self->mouse_scroll.y) < 0.0001f) - self->mouse_scroll.y = 0.0f; + mgl_scissor prev_scissor; + mgl_window_get_scissor(window, &prev_scissor); - self->scroll.x += (int)self->mouse_scroll.x; - self->scroll.y += (int)self->mouse_scroll.y; + mgl_scissor new_scissor = { + .position = self->position, + .size = (mgl_vec2i){ self->widget.size.x - margin_width, self->widget.size.y - margin_height } + }; + mgl_window_set_scissor(window, &new_scissor); - mgl_vec2i child_size; - if(self->child) - child_size = self->child->size; - else - child_size = (mgl_vec2i){ 0, 0 }; + mgui_widget_set_position(self->child, + (mgl_vec2i){ self->position.x + self->scroll.x + self->child->margin.left, self->position.y + self->scroll.y + self->child->margin.top }); + mgui_widget_draw(self->child, window); + + mgl_window_set_scissor(window, &prev_scissor); + + { + const double scroll_ratio = child_size.y == 0 ? 0.0 : (double)-self->scroll.y / (double)child_size.y; + const int scrollbar_offset_y = height * scroll_ratio; + + const int scrollbar_width = 10; + const int right = self->widget.size.x - self->widget.margin.left - self->widget.margin.right; + + self->scrollbar_pos = (mgl_vec2f){ self->position.x + right - scrollbar_width, self->position.y + scrollbar_offset_y }; + self->scrollbar_size = (mgl_vec2f){ scrollbar_width, scrollbar_height }; + + mgl_rectangle rect = { + .position = self->scrollbar_pos, + .size = self->scrollbar_size, + .color = { 55, 60, 68, 255 } + }; + + mgl_rectangle_draw(mgl_get_context(), &rect); + } +} +static void mgui_scrollview_limit_scroll_to_child_size(mgui_scrollview *self, mgl_vec2i child_size) { if(child_size.x > self->widget.size.x) { self->scroll.x = min_int(self->scroll.x, 0); self->scroll.x = max_int(self->scroll.x, -child_size.x + self->widget.size.x); @@ -124,46 +174,43 @@ void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { } else { self->scroll.y = 0; } +} - if(self->child) { - mgl_scissor prev_scissor; - mgl_window_get_scissor(window, &prev_scissor); +static void mgui_scrollview_update_mouse_scroll(mgui_scrollview *self, double frame_time) { + 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; - /* TODO: Fix all this margin crap, it should be invisible */ - const int margin_width = self->widget.margin.top + self->widget.margin.bottom; - const int margin_height = self->widget.margin.top + self->widget.margin.bottom; + if(abs_float(self->mouse_scroll.y) < 0.0001f) + self->mouse_scroll.y = 0.0f; - mgl_scissor new_scissor = { - .position = self->position, - .size = (mgl_vec2i){ self->widget.size.x - margin_width, self->widget.size.y - margin_height } - }; - mgl_window_set_scissor(window, &new_scissor); - - mgui_widget_set_position(self->child, - (mgl_vec2i){ self->position.x + self->scroll.x + self->child->margin.left, self->position.y + self->scroll.y + self->child->margin.top }); - mgui_widget_draw(self->child, window); - - mgl_window_set_scissor(window, &prev_scissor); - - { - /* TODO: Fix all this margin crap, it should be invisible */ - const int margin_height = self->widget.margin.top + self->widget.margin.bottom; - const int height = self->widget.size.y - margin_height; - const double scrollbar_height_ratio = child_size.y == 0 ? 0.0 : (double)height / (double)child_size.y; - const int scrollbar_height = scrollbar_height_ratio * height; - - const double scroll_ratio = child_size.y == 0 ? 0.0 : (double)-self->scroll.y / (double)child_size.y; - const int scrollbar_offset_y = height * scroll_ratio; - - const int scrollbar_width = 5; - const int right = self->widget.size.x - self->widget.margin.left - self->widget.margin.right; - mgl_rectangle rect = { - .position = { self->position.x + right - scrollbar_width, self->position.y + scrollbar_offset_y }, - .size = { scrollbar_width, scrollbar_height }, - .color = { 55, 60, 68, 255 } - }; - - mgl_rectangle_draw(mgl_get_context(), &rect); - } - } + self->scroll.x += (int)self->mouse_scroll.x; + self->scroll.y += (int)self->mouse_scroll.y; +} + +/* TODO: Check if visible in scissor */ +void mgui_scrollview_draw(mgui_scrollview *self, mgl_window *window) { + const double frame_time = mgui_get_frame_time_seconds(); + mgui_scrollview_update_mouse_scroll(self, frame_time); + + mgl_vec2i child_size; + if(self->child) + child_size = self->child->size; + else + child_size = (mgl_vec2i){ 0, 0 }; + + /* TODO: Fix all this margin crap, it should be invisible */ + const int margin_width = self->widget.margin.top + self->widget.margin.bottom; + const int margin_height = self->widget.margin.top + self->widget.margin.bottom; + + /* TODO: Fix all this margin crap, it should be invisible */ + const int height = self->widget.size.y - margin_height; + const double scrollbar_height_ratio = child_size.y == 0 ? 0.0 : (double)height / (double)child_size.y; + const int scrollbar_height = scrollbar_height_ratio * height; + + mgui_scrollview_handle_scrollbar_move(self, window, scrollbar_height_ratio); + mgui_scrollview_limit_scroll_to_child_size(self, child_size); + mgui_scrollview_draw_child(self, window, margin_width, margin_height, height, scrollbar_height, child_size); } |