From b8e6949dfb8a88c832e82f8b7e853fe0ed462da0 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 24 Aug 2024 14:08:25 +0200 Subject: Remove scrollable page from gsr page, fix crash when navigating back --- depends/mglpp | 2 +- include/SafeVector.hpp | 2 +- include/Theme.hpp | 2 +- include/gui/FileChooser.hpp | 11 ++++-- include/gui/GsrPage.hpp | 8 ++--- include/gui/Page.hpp | 4 +-- include/gui/ScrollablePage.hpp | 4 +-- src/gui/Button.cpp | 4 ++- src/gui/FileChooser.cpp | 77 +++++++++++++++++++++------------------- src/gui/GsrPage.cpp | 80 ++++++++++++++++++++++++++++++------------ src/gui/ScrollablePage.cpp | 14 ++++---- src/gui/SettingsPage.cpp | 2 +- src/gui/StaticPage.cpp | 16 ++++----- 13 files changed, 137 insertions(+), 89 deletions(-) diff --git a/depends/mglpp b/depends/mglpp index 17254ca..61b2725 160000 --- a/depends/mglpp +++ b/depends/mglpp @@ -1 +1 @@ -Subproject commit 17254ca13ce7985e87a413df1d8546779734f05e +Subproject commit 61b2725ef174e4cec734e29bce4f69d6fcd2a813 diff --git a/include/SafeVector.hpp b/include/SafeVector.hpp index cea9cb9..916b547 100644 --- a/include/SafeVector.hpp +++ b/include/SafeVector.hpp @@ -21,7 +21,7 @@ public: } // Might not remove the data immediately if inside for_each loop. - // In that case the item is remove at the end of the loop. + // In that case the item is removed at the end of the loop. void remove(PointerType item_to_remove) { if(for_each_depth == 0) remove_item(item_to_remove); diff --git a/include/Theme.hpp b/include/Theme.hpp index 5f228af..7406c67 100644 --- a/include/Theme.hpp +++ b/include/Theme.hpp @@ -19,7 +19,7 @@ namespace gsr { float window_height = 0.0f; mgl::Color tint_color = mgl::Color(118, 185, 0); - mgl::Color scrollable_page_bg_color = mgl::Color(38, 43, 47); + mgl::Color page_bg_color = mgl::Color(38, 43, 47); mgl::Color text_color = mgl::Color(255, 255, 255); mgl::MemoryMappedFile body_font_file; diff --git a/include/gui/FileChooser.hpp b/include/gui/FileChooser.hpp index b8ea23e..309ff56 100644 --- a/include/gui/FileChooser.hpp +++ b/include/gui/FileChooser.hpp @@ -13,7 +13,7 @@ namespace gsr { class FileChooser : public Widget { public: - FileChooser(const char *start_directory, mgl::vec2f content_size); + FileChooser(const char *start_directory, mgl::vec2f size); FileChooser(const FileChooser&) = delete; FileChooser& operator=(const FileChooser&) = delete; @@ -24,11 +24,16 @@ namespace gsr { void set_current_directory(const char *directory); private: - mgl::vec2f content_size; + struct Folder { + mgl::Text text; + time_t last_modified_seconds = 0; + }; + + mgl::vec2f size; mgl::Text current_directory_text; int mouse_over_item = -1; int selected_item = -1; - std::vector folders; + std::vector folders; mgl::Clock double_click_timer; int times_clicked_within_timer = 0; }; diff --git a/include/gui/GsrPage.hpp b/include/gui/GsrPage.hpp index 9f38382..916055a 100644 --- a/include/gui/GsrPage.hpp +++ b/include/gui/GsrPage.hpp @@ -1,7 +1,6 @@ #pragma once #include "Page.hpp" -#include "ScrollablePage.hpp" #include "Button.hpp" #include @@ -19,20 +18,21 @@ namespace gsr { mgl::vec2f get_size() override; mgl::vec2f get_inner_size() override; - void add_widget(std::unique_ptr widget) override; - void set_margins(float top, float bottom, float left, float right); void set_on_back_button_click(std::function on_click_handler); private: void draw_page_label(mgl::Window &window, mgl::vec2f body_pos); + void draw_children(mgl::Window &window, mgl::vec2f position); + float get_border_size() const; float get_horizontal_spacing() const; + mgl::vec2f get_content_position(); + mgl::vec2f get_content_position_with_margin(); private: float margin_top_scale = 0.0f; float margin_bottom_scale = 0.0f; float margin_left_scale = 0.0f; float margin_right_scale = 0.0f; - ScrollablePage scrollable_body; Button back_button; mgl::Text label_text; }; diff --git a/include/gui/Page.hpp b/include/gui/Page.hpp index a8fa515..0d8536a 100644 --- a/include/gui/Page.hpp +++ b/include/gui/Page.hpp @@ -1,7 +1,7 @@ #pragma once #include "Widget.hpp" -#include +#include "../SafeVector.hpp" #include namespace gsr { @@ -19,6 +19,6 @@ namespace gsr { virtual void add_widget(std::unique_ptr widget); protected: - std::vector> widgets; + SafeVector> widgets; }; } \ No newline at end of file diff --git a/include/gui/ScrollablePage.hpp b/include/gui/ScrollablePage.hpp index 5048627..09c618f 100644 --- a/include/gui/ScrollablePage.hpp +++ b/include/gui/ScrollablePage.hpp @@ -1,8 +1,8 @@ #pragma once #include "Widget.hpp" +#include "../SafeVector.hpp" #include -#include namespace gsr { class ScrollablePage : public Widget { @@ -20,6 +20,6 @@ namespace gsr { void add_widget(std::unique_ptr widget); private: mgl::vec2f size; - std::vector> widgets; + SafeVector> widgets; }; } \ No newline at end of file diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp index 20a771e..6c475bd 100644 --- a/src/gui/Button.cpp +++ b/src/gui/Button.cpp @@ -23,8 +23,10 @@ namespace gsr { const mgl::vec2f item_size = get_size().floor(); if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) { const bool clicked_inside = mgl::FloatRect(position + offset, item_size).contains({ (float)event.mouse_button.x, (float)event.mouse_button.y }); - if(clicked_inside && on_click) + if(clicked_inside && on_click) { on_click(); + return false; + } } return true; } diff --git a/src/gui/FileChooser.cpp b/src/gui/FileChooser.cpp index 8cc5d74..b63af24 100644 --- a/src/gui/FileChooser.cpp +++ b/src/gui/FileChooser.cpp @@ -1,15 +1,18 @@ #include "../../include/gui/FileChooser.hpp" #include "../../include/gui/Utils.hpp" #include "../../include/Theme.hpp" + #include #include #include #include #include + #include #include #include #include +#include namespace gsr { static const float current_directory_padding_top_scale = 0.004629f; @@ -17,14 +20,14 @@ namespace gsr { static const float current_directory_padding_left_scale = 0.004629f; static const float current_directory_padding_right_scale = 0.004629f; static const float spacing_between_current_directory_and_content = 0.015f; - static const int num_columns = 6; - static const float content_padding_top_scale = 0.015f; - static const float content_padding_bottom_scale = 0.015f; - static const float content_padding_left_scale = 0.015f; - static const float content_padding_right_scale = 0.015f; - - FileChooser::FileChooser(const char *start_directory, mgl::vec2f content_size) : - content_size(content_size), current_directory_text(start_directory, get_theme().body_font) + static const int num_columns = 5; + static const float content_padding_top_scale = 0.03f; + static const float content_padding_bottom_scale = 0.03f; + static const float content_padding_left_scale = 0.03f; + static const float content_padding_right_scale = 0.03f; + + FileChooser::FileChooser(const char *start_directory, mgl::vec2f size) : + size(size), current_directory_text(start_directory, get_theme().body_font) { set_current_directory(start_directory); } @@ -45,7 +48,7 @@ namespace gsr { if(selected_item != -1 && times_clicked_within_timer > 0 && times_clicked_within_timer % 2 == 0) { char new_directory[PATH_MAX]; - snprintf(new_directory, sizeof(new_directory), "%s/%s", current_directory_text.get_string().c_str(), folders[selected_item].get_string().c_str()); + snprintf(new_directory, sizeof(new_directory), "%s/%s", current_directory_text.get_string().c_str(), folders[selected_item].text.get_string().c_str()); set_current_directory(new_directory); } } @@ -58,13 +61,14 @@ namespace gsr { if(!visible) return; - const mgl::vec2f draw_pos = position + offset; + const mgl::vec2f draw_pos_start = position + offset; + mgl::vec2f draw_pos = draw_pos_start; const mgl::vec2f current_directory_padding( current_directory_padding_left_scale * get_theme().window_height + current_directory_padding_right_scale * get_theme().window_height, current_directory_padding_top_scale * get_theme().window_height + current_directory_padding_bottom_scale * get_theme().window_height ); - mgl::Rectangle current_directory_background(mgl::vec2f(content_size.x, current_directory_text.get_bounds().size.y + current_directory_padding.y).floor()); + mgl::Rectangle current_directory_background(mgl::vec2f(size.x, current_directory_text.get_bounds().size.y + current_directory_padding.y).floor()); current_directory_background.set_color(mgl::Color(0, 0, 0, 120)); current_directory_background.set_position(draw_pos.floor()); window.draw(current_directory_background); @@ -73,9 +77,10 @@ namespace gsr { current_directory_text.set_position((draw_pos + mgl::vec2f(current_directory_padding.x, current_directory_background.get_size().y * 0.5f - current_directory_text.get_bounds().size.y * 0.5f)).floor()); window.draw(current_directory_text); - mgl::Rectangle content_background(content_size.floor()); + draw_pos += mgl::vec2f(0.0f, current_directory_background.get_size().y + spacing_between_current_directory_and_content * get_theme().window_height); + mgl::Rectangle content_background(mgl::vec2f(size.x, size.y - (draw_pos.y - draw_pos_start.y)).floor()); content_background.set_color(mgl::Color(0, 0, 0, 120)); - content_background.set_position((draw_pos + mgl::vec2f(0.0f, current_directory_background.get_size().y + spacing_between_current_directory_and_content * get_theme().window_height)).floor()); + content_background.set_position(draw_pos.floor()); window.draw(content_background); const mgl::vec2f mouse_pos = window.get_mouse_position().to_vec2f(); @@ -85,11 +90,11 @@ namespace gsr { const int content_padding_left = content_padding_left_scale * get_theme().window_height; const int content_padding_right = content_padding_right_scale * get_theme().window_height; - const float folder_width = (int)((content_size.x - (content_padding_left + content_padding_right) * num_columns) / num_columns); + const float folder_width = (int)((content_background.get_size().x - (content_padding_left + content_padding_right) * num_columns) / num_columns); const float width_per_item_after = content_padding_right + folder_width + content_padding_left; mgl::vec2f folder_pos = content_background.get_position() + mgl::vec2f(content_padding_left, content_padding_top); for(int i = 0; i < (int)folders.size(); ++i) { - auto &folder_text = folders[i]; + auto &folder = folders[i]; mgl::Sprite folder_sprite(&get_theme().folder_texture); folder_sprite.set_position(folder_pos.floor()); @@ -116,11 +121,11 @@ namespace gsr { window.draw(folder_sprite); // TODO: Dont allow text to go further left/right than item_pos (on the left side) and item_pos + item_size (on the right side). - folder_text.set_position(folder_sprite.get_position() + mgl::vec2f(folder_sprite.get_size().x * 0.5f - folder_text.get_bounds().size.x * 0.5f, folder_sprite.get_size().y)); - window.draw(folder_text); + folder.text.set_position(folder_sprite.get_position() + mgl::vec2f(folder_sprite.get_size().x * 0.5f - folder.text.get_bounds().size.x * 0.5f, folder_sprite.get_size().y)); + window.draw(folder.text); folder_pos.x += width_per_item_after; - if(folder_pos.x + folder_width > content_background.get_position().x + content_size.x) { + if(folder_pos.x + folder_width > content_background.get_position().x + content_background.get_size().x) { folder_pos.x = content_background.get_position().x + content_padding_left; folder_pos.y += content_padding_bottom + folder_sprite.get_size().y + content_padding_top; } @@ -131,22 +136,7 @@ namespace gsr { if(!visible) return {0.0f, 0.0f}; - const mgl::vec2f current_directory_padding( - current_directory_padding_left_scale * get_theme().window_height + current_directory_padding_right_scale * get_theme().window_height, - current_directory_padding_top_scale * get_theme().window_height + current_directory_padding_bottom_scale * get_theme().window_height - ); - return {content_size.x, current_directory_text.get_bounds().size.y + current_directory_padding.y + spacing_between_current_directory_and_content * get_theme().window_height + content_size.y}; - } - - static bool is_dir(struct dirent *dir, const char *parent_directory) { - if(dir->d_type == DT_DIR) - return true; - - char filepath[PATH_MAX]; - snprintf(filepath, sizeof(filepath), "%s/%s", parent_directory, dir->d_name); - - struct stat st; - return stat(filepath, &st) != -1 && S_ISDIR(st.st_mode); + return size; } void FileChooser::set_current_directory(const char *directory) { @@ -162,13 +152,28 @@ namespace gsr { } struct dirent *dir = NULL; + char filepath[PATH_MAX]; while((dir = readdir(d)) != NULL) { /* Ignore hidden files */ - if(dir->d_name[0] == '.' || !is_dir(dir, directory)) + if(dir->d_name[0] == '.') + continue; + + snprintf(filepath, sizeof(filepath), "%s/%s", directory, dir->d_name); + + struct stat st; + if(stat(filepath, &st) == -1) + continue; + + if(!S_ISDIR(st.st_mode)) continue; - folders.push_back(mgl::Text(dir->d_name, get_theme().body_font)); + + folders.push_back({mgl::Text(dir->d_name, get_theme().body_font), st.st_mtim.tv_sec}); } closedir(d); + + std::sort(folders.begin(), folders.end(), [](const Folder &folder_a, const Folder &folder_b) { + return folder_a.last_modified_seconds > folder_b.last_modified_seconds; + }); } } \ No newline at end of file diff --git a/src/gui/GsrPage.cpp b/src/gui/GsrPage.cpp index db49ced..df997e9 100644 --- a/src/gui/GsrPage.cpp +++ b/src/gui/GsrPage.cpp @@ -7,9 +7,8 @@ namespace gsr { GsrPage::GsrPage() : - scrollable_body(mgl::vec2f(0.0f, 0.0f)), back_button(&get_theme().title_font, "Back", - mgl::vec2f(get_theme().window_width / 10, get_theme().window_height / 15).floor(), get_theme().scrollable_page_bg_color), + mgl::vec2f(get_theme().window_width / 10, get_theme().window_height / 15).floor(), get_theme().page_bg_color), label_text("Settings", get_theme().title_font) { //set_position(content_page_position); @@ -22,30 +21,40 @@ namespace gsr { if(!visible) return true; - if(!scrollable_body.on_event(event, window, mgl::vec2f(0.0f, 0.0f))) - return false; - if(!back_button.on_event(event, window, mgl::vec2f(0.0f, 0.0f))) return false; - return true; + const int margin_top = margin_top_scale * get_theme().window_height; + const int margin_left = margin_left_scale * get_theme().window_height; + const mgl::vec2f content_page_position = get_content_position() + mgl::vec2f(margin_left, get_border_size() + margin_top).floor(); + + Widget *selected_widget = selected_child_widget; + + if(selected_widget) { + if(!selected_widget->on_event(event, window, content_page_position)) + return false; + } + + // Process widgets by visibility (backwards) + return widgets.for_each_reverse([selected_widget, &window, &event, content_page_position](std::unique_ptr &widget) { + if(widget.get() != selected_widget) { + if(!widget->on_event(event, window, content_page_position)) + return false; + } + return true; + }); } - void GsrPage::draw(mgl::Window &window, mgl::vec2f offset) { + void GsrPage::draw(mgl::Window &window, mgl::vec2f) { if(!visible) return; - const int margin_top = margin_top_scale * get_theme().window_height; - const int margin_left = margin_left_scale * get_theme().window_height; - - const mgl::vec2f window_size = mgl::vec2f(get_theme().window_width, get_theme().window_height).floor(); const mgl::vec2f content_page_size = get_size(); - const mgl::vec2f content_page_position = mgl::vec2f(window_size * 0.5f - content_page_size * 0.5f).floor(); - offset = content_page_position + mgl::vec2f(margin_left, get_border_size() + margin_top).floor(); + const mgl::vec2f content_page_position = get_content_position(); mgl::Rectangle background(content_page_size); background.set_position(content_page_position); - background.set_color(get_theme().scrollable_page_bg_color); + background.set_color(get_theme().page_bg_color); window.draw(background); mgl::Rectangle border(mgl::vec2f(content_page_size.x, get_border_size()).floor()); @@ -53,13 +62,14 @@ namespace gsr { border.set_color(get_theme().tint_color); window.draw(border); - scrollable_body.set_position(offset); - scrollable_body.draw(window, mgl::vec2f(0.0f, 0.0f)); - draw_page_label(window, content_page_position); back_button.set_position(content_page_position + mgl::vec2f(content_page_size.x + get_horizontal_spacing(), 0.0f).floor()); back_button.draw(window, mgl::vec2f(0.0f, 0.0f)); + + const int margin_top = margin_top_scale * get_theme().window_height; + const int margin_left = margin_left_scale * get_theme().window_height; + draw_children(window, content_page_position + mgl::vec2f(margin_left, get_border_size() + margin_top).floor()); } void GsrPage::draw_page_label(mgl::Window &window, mgl::vec2f body_pos) { @@ -80,6 +90,31 @@ namespace gsr { window.draw(icon); } + void GsrPage::draw_children(mgl::Window &window, mgl::vec2f position) { + Widget *selected_widget = selected_child_widget; + + mgl_scissor prev_scissor; + mgl_window_get_scissor(window.internal_window(), &prev_scissor); + + const mgl::vec2f inner_size = get_inner_size(); + mgl_scissor new_scissor = { + mgl_vec2i{(int)position.x, (int)position.y}, + mgl_vec2i{(int)inner_size.x, (int)inner_size.y} + }; + mgl_window_set_scissor(window.internal_window(), &new_scissor); + + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; + if(widget.get() != selected_widget) + widget->draw(window, position); + } + + if(selected_widget) + selected_widget->draw(window, position); + + mgl_window_set_scissor(window.internal_window(), &prev_scissor); + } + mgl::vec2f GsrPage::get_size() { if(!visible) return {0.0f, 0.0f}; @@ -100,16 +135,11 @@ namespace gsr { return get_size() - mgl::vec2f(margin_left + margin_right, margin_top + margin_bottom + get_border_size()); } - void GsrPage::add_widget(std::unique_ptr widget) { - scrollable_body.add_widget(std::move(widget)); - } - void GsrPage::set_margins(float top, float bottom, float left, float right) { margin_top_scale = top; margin_bottom_scale = bottom; margin_left_scale = left; margin_right_scale = right; - scrollable_body.set_size(get_inner_size()); } void GsrPage::set_on_back_button_click(std::function on_click_handler) { @@ -123,4 +153,10 @@ namespace gsr { float GsrPage::get_horizontal_spacing() const { return get_theme().window_width / 50; } + + mgl::vec2f GsrPage::get_content_position() { + const mgl::vec2f window_size = mgl::vec2f(get_theme().window_width, get_theme().window_height).floor(); + const mgl::vec2f content_page_size = get_size(); + return mgl::vec2f(window_size * 0.5f - content_page_size * 0.5f).floor(); + } } \ No newline at end of file diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp index a2b6c8f..41ede41 100644 --- a/src/gui/ScrollablePage.cpp +++ b/src/gui/ScrollablePage.cpp @@ -19,14 +19,13 @@ namespace gsr { } // Process widgets by visibility (backwards) - for(auto it = widgets.rbegin(), end = widgets.rend(); it != end; ++it) { - if(it->get() != selected_widget) { - if(!(*it)->on_event(event, window, offset)) + return widgets.for_each_reverse([selected_widget, &window, &event, offset](std::unique_ptr &widget) { + if(widget.get() != selected_widget) { + if(!widget->on_event(event, window, offset)) return false; } - } - - return true; + return true; + }); } void ScrollablePage::draw(mgl::Window &window, mgl::vec2f offset) { @@ -48,7 +47,8 @@ namespace gsr { Widget *selected_widget = selected_child_widget; - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(widget.get() != selected_widget) widget->draw(window, offset); } diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index d6022ab..94e51a2 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -370,7 +370,7 @@ namespace gsr { page_stack->pop(); }); - auto file_chooser = std::make_unique("/home/dec05eba", select_directory_page->get_size()); + auto file_chooser = std::make_unique("/home/dec05eba", select_directory_page->get_inner_size()); select_directory_page->add_widget(std::move(file_chooser)); page_stack->push(std::move(select_directory_page)); diff --git a/src/gui/StaticPage.cpp b/src/gui/StaticPage.cpp index 73adfa0..a89fc42 100644 --- a/src/gui/StaticPage.cpp +++ b/src/gui/StaticPage.cpp @@ -19,14 +19,13 @@ namespace gsr { } // Process widgets by visibility (backwards) - for(auto it = widgets.rbegin(), end = widgets.rend(); it != end; ++it) { - if(it->get() != selected_widget) { - if(!(*it)->on_event(event, window, offset)) + return widgets.for_each_reverse([selected_widget, &window, &event, offset](std::unique_ptr &widget) { + if(widget.get() != selected_widget) { + if(!widget->on_event(event, window, offset)) return false; } - } - - return true; + return true; + }); } void StaticPage::draw(mgl::Window &window, mgl::vec2f offset) { @@ -46,9 +45,10 @@ namespace gsr { }; mgl_window_set_scissor(window.internal_window(), &new_scissor); - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(widget.get() != selected_widget) - widget->draw(window, offset); + widget->draw(window, position); } if(selected_widget) -- cgit v1.2.3