diff options
Diffstat (limited to 'src/gui/ScrollablePage.cpp')
-rw-r--r-- | src/gui/ScrollablePage.cpp | 90 |
1 files changed, 82 insertions, 8 deletions
diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp index 41ede41..a791d75 100644 --- a/src/gui/ScrollablePage.cpp +++ b/src/gui/ScrollablePage.cpp @@ -1,16 +1,21 @@ #include "../../include/gui/ScrollablePage.hpp" +#include "../../include/gui/Utils.hpp" #include <mglpp/window/Window.hpp> +#include <mglpp/window/Event.hpp> +//#include <mglpp/graphics/Rectangle.hpp> namespace gsr { + static const int scroll_speed = 80; + static const double scroll_update_speed = 10.0; + ScrollablePage::ScrollablePage(mgl::vec2f size) : size(size) {} bool ScrollablePage::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) { if(!visible) return true; - const mgl::vec2f draw_pos = position + offset; - offset = draw_pos; + offset = position + offset + mgl::vec2f(0.0f, scroll_y); Widget *selected_widget = selected_child_widget; if(selected_widget) { @@ -19,21 +24,34 @@ namespace gsr { } // Process widgets by visibility (backwards) - return widgets.for_each_reverse([selected_widget, &window, &event, offset](std::unique_ptr<Widget> &widget) { + const bool continue_events = widgets.for_each_reverse([selected_widget, &window, &event, offset](std::unique_ptr<Widget> &widget) { if(widget.get() != selected_widget) { if(!widget->on_event(event, window, offset)) return false; } return true; }); + + if(!continue_events) + return false; + + if(event.type == mgl::Event::MouseWheelScrolled) { + const double scroll = event.mouse_wheel_scroll.delta * scroll_speed; + scroll_target_y += scroll; + return false; + } + + return true; } void ScrollablePage::draw(mgl::Window &window, mgl::vec2f offset) { - if(!visible) + if(!visible || widgets.empty()) { + reset_scroll(); return; + } - const mgl::vec2f draw_pos = position + offset; - offset = draw_pos; + offset = position + offset; + const mgl::vec2f page_scroll_start = offset; mgl_scissor prev_scissor; mgl_window_get_scissor(window.internal_window(), &prev_scissor); @@ -46,16 +64,67 @@ namespace gsr { mgl_window_set_scissor(window.internal_window(), &new_scissor); Widget *selected_widget = selected_child_widget; + offset.y += scroll_y; + double child_top = 999999.0; + double child_bottom = 0.0; for(size_t i = 0; i < widgets.size(); ++i) { auto &widget = widgets[i]; - if(widget.get() != selected_widget) + if(widget.get() != selected_widget) { widget->draw(window, offset); + + // TODO: Create a widget function to get the render area instead, which each widget should set (position + offset as start, and position + offset + size as end), this has to be done in the widgets to ensure that recursive rendering has correct position. + // TODO: Do these calls before drawing, so that scroll limits can be set before drawing to prevent scrolling from overflowing for 1 frame. + // To make that possible move inner_size calculation in FileChooserBody to the get_inner_size function. + // That calculation can be done without looping folders. + const mgl::vec2f widget_pos = widget->get_position() + offset; + const mgl::vec2f widget_inner_size = widget->get_inner_size(); + + child_top = std::min(child_top, (double)widget_pos.y); + child_bottom = std::max(child_bottom, (double)widget_pos.y + (double)widget_inner_size.y); + } } - if(selected_widget) + if(selected_widget) { selected_widget->draw(window, offset); + const mgl::vec2f widget_pos = selected_widget->get_position() + offset; + const mgl::vec2f widget_inner_size = selected_widget->get_inner_size(); + + child_top = std::min(child_top, (double)widget_pos.y); + child_bottom = std::max(child_bottom, (double)widget_pos.y + (double)widget_inner_size.y); + } + + const double child_height = child_bottom - child_top; + + // Debug output + // mgl::Rectangle bottom(mgl::vec2f(size.x, 5.0f)); + // bottom.set_color(mgl::Color(255, 0, 0, 255)); + // bottom.set_position(mgl::vec2f(offset.x, child_bottom)); + // window.draw(bottom); + + // mgl::Rectangle bottom_d(mgl::vec2f(size.x, 5.0f)); + // bottom_d.set_color(mgl::Color(0, 255, 0, 255)); + // bottom_d.set_position(mgl::vec2f(offset.x, page_scroll_start.y + size.y - 5)); + // window.draw(bottom_d); + + // Scroll animation + const double scroll_diff = scroll_target_y - scroll_y; + if(std::abs(scroll_diff) < 0.1) { + scroll_y = scroll_target_y; + } else { + const double frame_scroll_speed = std::min(1.0, get_frame_delta_seconds() * scroll_update_speed); + scroll_y += (scroll_diff * frame_scroll_speed); + } + + // Top and bottom limit + const double child_draw_overflow = (page_scroll_start.y + size.y) - child_bottom; + if(scroll_y > 0.001 || child_height < size.y) { + scroll_target_y = 0; + } else if(child_draw_overflow > 0.001) { + scroll_target_y = scroll_y + child_draw_overflow; + } + mgl_window_set_scissor(window.internal_window(), &prev_scissor); } @@ -73,4 +142,9 @@ namespace gsr { void ScrollablePage::add_widget(std::unique_ptr<Widget> widget) { widgets.push_back(std::move(widget)); } + + void ScrollablePage::reset_scroll() { + scroll_y = 0; + scroll_target_y = 0; + } }
\ No newline at end of file |