diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-08-22 21:44:06 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-08-23 18:53:19 +0200 |
commit | 54c60d9a18d103011a12939c5029dd35a8e9e200 (patch) | |
tree | fefba1d63a13df6c135a6b1f5e8640b12a9c0ff5 /src | |
parent | ba007c2b69dca6813c86115b2c1834de45c886be (diff) |
Start on file chooser, page stack
Diffstat (limited to 'src')
-rw-r--r-- | src/Config.cpp | 7 | ||||
-rw-r--r-- | src/GsrInfo.cpp | 14 | ||||
-rw-r--r-- | src/Theme.cpp | 13 | ||||
-rw-r--r-- | src/Utils.cpp | 7 | ||||
-rw-r--r-- | src/gui/Button.cpp | 4 | ||||
-rw-r--r-- | src/gui/ComboBox.cpp | 4 | ||||
-rw-r--r-- | src/gui/FileChooser.cpp | 174 | ||||
-rw-r--r-- | src/gui/GsrPage.cpp | 126 | ||||
-rw-r--r-- | src/gui/List.cpp | 63 | ||||
-rw-r--r-- | src/gui/PageStack.cpp | 58 | ||||
-rw-r--r-- | src/gui/RadioButton.cpp | 4 | ||||
-rw-r--r-- | src/gui/ScrollablePage.cpp | 44 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 82 | ||||
-rw-r--r-- | src/main.cpp | 68 |
14 files changed, 453 insertions, 215 deletions
diff --git a/src/Config.cpp b/src/Config.cpp index b4825a3..8f28c89 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -12,6 +12,13 @@ #define CONFIG_FILE_VERSION 1 namespace gsr { + static std::optional<KeyValue> parse_key_value(std::string_view line) { + const size_t space_index = line.find(' '); + if(space_index == std::string_view::npos) + return std::nullopt; + return KeyValue{line.substr(0, space_index), line.substr(space_index + 1)}; + } + using ConfigValue = std::variant<bool*, std::string*, int32_t*, ConfigHotkey*, std::vector<std::string>*>; static std::map<std::string_view, ConfigValue> get_config_options(Config &config) { diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index dfd18af..5d9773d 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -4,6 +4,13 @@ #include <string.h> namespace gsr { + static std::optional<KeyValue> parse_key_value(std::string_view line) { + const size_t space_index = line.find('|'); + if(space_index == std::string_view::npos) + return std::nullopt; + return KeyValue{line.substr(0, space_index), line.substr(space_index + 1)}; + } + static void parse_system_info_line(GsrInfo *gsr_info, std::string_view line) { const std::optional<KeyValue> key_value = parse_key_value(line); if(!key_value) @@ -156,6 +163,7 @@ namespace gsr { if(WIFEXITED(status)) { switch(WEXITSTATUS(status)) { case 0: return GsrInfoExitStatus::OK; + case 14: return GsrInfoExitStatus::BROKEN_DRIVERS; case 22: return GsrInfoExitStatus::OPENGL_FAILED; case 23: return GsrInfoExitStatus::NO_DRM_CARD; default: return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; @@ -180,14 +188,14 @@ namespace gsr { FILE *f = popen("gpu-screen-recorder --list-audio-devices", "r"); if(!f) { - fprintf(stderr, "error: 'gpu-screen-recorder --info' failed\n"); + fprintf(stderr, "error: 'gpu-screen-recorder --list-audio-devices' failed\n"); return audio_devices; } char output[16384]; ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f); if(bytes_read < 0 || ferror(f)) { - fprintf(stderr, "error: failed to read 'gpu-screen-recorder --info' output\n"); + fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-audio-devices' output\n"); pclose(f); return audio_devices; } @@ -202,4 +210,4 @@ namespace gsr { return audio_devices; } -}
\ No newline at end of file +} diff --git a/src/Theme.cpp b/src/Theme.cpp index 946b4b2..9fcf057 100644 --- a/src/Theme.cpp +++ b/src/Theme.cpp @@ -5,7 +5,7 @@ namespace gsr { static Theme *theme = nullptr; - bool init_theme(const gsr::GsrInfo &gsr_info, mgl::vec2i window_size, const std::string &resources_path) { + bool init_theme(const GsrInfo &gsr_info, mgl::vec2i window_size, const std::string &resources_path) { if(theme) return true; @@ -15,18 +15,18 @@ namespace gsr { theme->window_height = window_size.y; switch(gsr_info.gpu_info.vendor) { - case gsr::GpuVendor::UNKNOWN: { + case GpuVendor::UNKNOWN: { break; } - case gsr::GpuVendor::AMD: { + case GpuVendor::AMD: { theme->tint_color = mgl::Color(221, 0, 49); break; } - case gsr::GpuVendor::INTEL: { + case GpuVendor::INTEL: { theme->tint_color = mgl::Color(8, 109, 183); break; } - case gsr::GpuVendor::NVIDIA: { + case GpuVendor::NVIDIA: { theme->tint_color = mgl::Color(118, 185, 0); break; } @@ -53,6 +53,9 @@ namespace gsr { if(!theme->settings_texture.load_from_file((resources_path + "images/settings.png").c_str(), {false, false, false})) goto error; + if(!theme->folder_texture.load_from_file((resources_path + "images/folder.png").c_str(), {false, false, false})) + goto error; + return true; error: diff --git a/src/Utils.cpp b/src/Utils.cpp index 4252de8..55fc57e 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -22,13 +22,6 @@ namespace gsr { } } - std::optional<KeyValue> parse_key_value(std::string_view line) { - const size_t space_index = line.find(' '); - if(space_index == std::string_view::npos) - return std::nullopt; - return KeyValue{line.substr(0, space_index), line.substr(space_index + 1)}; - } - std::string get_home_dir() { const char *home_dir = getenv("HOME"); if(!home_dir) { diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp index e36d07b..20a771e 100644 --- a/src/gui/Button.cpp +++ b/src/gui/Button.cpp @@ -70,4 +70,8 @@ namespace gsr { void Button::set_border_scale(float scale) { border_scale = scale; } + + const std::string& Button::get_text() const { + return text.get_string(); + } }
\ No newline at end of file diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp index f23a323..b344c4e 100644 --- a/src/gui/ComboBox.cpp +++ b/src/gui/ComboBox.cpp @@ -146,14 +146,14 @@ namespace gsr { dirty = true; } - void ComboBox::set_selected_item(const std::string &id, bool trigger_event) { + void ComboBox::set_selected_item(const std::string &id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) { for(size_t i = 0; i < items.size(); ++i) { auto &item = items[i]; if(item.id == id) { const size_t prev_selected_item = selected_item; selected_item = i; - if(trigger_event && selected_item != prev_selected_item && on_selection_changed) + if(trigger_event && (trigger_event_even_if_selection_not_changed || selected_item != prev_selected_item) && on_selection_changed) on_selection_changed(item.text.get_string(), item.id); break; diff --git a/src/gui/FileChooser.cpp b/src/gui/FileChooser.cpp new file mode 100644 index 0000000..8cc5d74 --- /dev/null +++ b/src/gui/FileChooser.cpp @@ -0,0 +1,174 @@ +#include "../../include/gui/FileChooser.hpp" +#include "../../include/gui/Utils.hpp" +#include "../../include/Theme.hpp" +#include <mglpp/graphics/Rectangle.hpp> +#include <mglpp/graphics/Sprite.hpp> +#include <mglpp/window/Window.hpp> +#include <mglpp/window/Event.hpp> +#include <mglpp/system/FloatRect.hpp> +#include <dirent.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +namespace gsr { + static const float current_directory_padding_top_scale = 0.004629f; + static const float current_directory_padding_bottom_scale = 0.004629f; + 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) + { + set_current_directory(start_directory); + } + + bool FileChooser::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) { + if(!visible) + return true; + + if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) { + if(double_click_timer.get_elapsed_time_seconds() <= get_theme().double_click_timeout_seconds) { + ++times_clicked_within_timer; + } else { + times_clicked_within_timer = 1; + } + double_click_timer.restart(); + + selected_item = mouse_over_item; + + 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()); + set_current_directory(new_directory); + } + } + return true; + } + + void FileChooser::draw(mgl::Window &window, mgl::vec2f offset) { + mouse_over_item = -1; + + if(!visible) + return; + + const mgl::vec2f draw_pos = position + offset; + 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()); + current_directory_background.set_color(mgl::Color(0, 0, 0, 120)); + current_directory_background.set_position(draw_pos.floor()); + window.draw(current_directory_background); + + current_directory_text.set_color(get_theme().text_color); + 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()); + 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()); + window.draw(content_background); + + const mgl::vec2f mouse_pos = window.get_mouse_position().to_vec2f(); + + const int content_padding_top = content_padding_top_scale * get_theme().window_height; + const int content_padding_bottom = content_padding_bottom_scale * get_theme().window_height; + 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 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]; + + mgl::Sprite folder_sprite(&get_theme().folder_texture); + folder_sprite.set_position(folder_pos.floor()); + folder_sprite.set_width((int)folder_width); + + const mgl::vec2f item_pos = folder_pos - mgl::vec2f(content_padding_left, content_padding_top); + const mgl::vec2f item_size = folder_sprite.get_size() + mgl::vec2f(content_padding_left + content_padding_right, content_padding_top + content_padding_bottom); + if(i == selected_item) { + mgl::Rectangle selected_item_background(item_size.floor()); + selected_item_background.set_position(item_pos.floor()); + selected_item_background.set_color(get_theme().tint_color); + window.draw(selected_item_background); + } + if(!has_parent_with_selected_child_widget() && mouse_over_item == -1 && mgl::FloatRect(item_pos, item_size).contains(mouse_pos)) { + // mgl::Rectangle selected_item_background(item_size.floor()); + // selected_item_background.set_position(item_pos.floor()); + // selected_item_background.set_color(mgl::Color(20, 20, 20, 150)); + // window.draw(selected_item_background); + const float border_scale = 0.0015f; + draw_rectangle_outline(window, item_pos.floor(), item_size.floor(), get_theme().tint_color, border_scale * get_theme().window_height); + mouse_over_item = i; + } + + 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_pos.x += width_per_item_after; + if(folder_pos.x + folder_width > content_background.get_position().x + content_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; + } + } + } + + mgl::vec2f FileChooser::get_size() { + 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); + } + + void FileChooser::set_current_directory(const char *directory) { + folders.clear(); + selected_item = -1; + mouse_over_item = -1; + current_directory_text.set_string(directory); + + DIR *d = opendir(directory); + if(!d) { + fprintf(stderr, "gsr-overlay error: failed to open directory: %s, error: %s\n", directory, strerror(errno)); + return; + } + + struct dirent *dir = NULL; + while((dir = readdir(d)) != NULL) { + /* Ignore hidden files */ + if(dir->d_name[0] == '.' || !is_dir(dir, directory)) + continue; + folders.push_back(mgl::Text(dir->d_name, get_theme().body_font)); + } + + closedir(d); + } +}
\ No newline at end of file diff --git a/src/gui/GsrPage.cpp b/src/gui/GsrPage.cpp new file mode 100644 index 0000000..db49ced --- /dev/null +++ b/src/gui/GsrPage.cpp @@ -0,0 +1,126 @@ +#include "../../include/gui/GsrPage.hpp" +#include "../../include/Theme.hpp" + +#include <mglpp/graphics/Rectangle.hpp> +#include <mglpp/graphics/Sprite.hpp> +#include <mglpp/window/Window.hpp> + +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), + label_text("Settings", get_theme().title_font) + { + //set_position(content_page_position); + const float margin = 0.02f; + set_margins(margin, margin, margin, margin); + back_button.set_border_scale(0.003f); + } + + bool GsrPage::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f) { + 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; + } + + void GsrPage::draw(mgl::Window &window, mgl::vec2f offset) { + 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(); + + mgl::Rectangle background(content_page_size); + background.set_position(content_page_position); + background.set_color(get_theme().scrollable_page_bg_color); + window.draw(background); + + mgl::Rectangle border(mgl::vec2f(content_page_size.x, get_border_size()).floor()); + border.set_position(content_page_position); + 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)); + } + + void GsrPage::draw_page_label(mgl::Window &window, mgl::vec2f body_pos) { + const mgl::vec2f window_size = mgl::vec2f(get_theme().window_width, get_theme().window_height).floor(); + + mgl::Rectangle background(mgl::vec2f(window_size.x / 10, window_size.x / 10).floor()); + background.set_position(body_pos.floor() - mgl::vec2f(background.get_size().x + get_horizontal_spacing(), 0.0f).floor()); + background.set_color(mgl::Color(0, 0, 0, 255)); + window.draw(background); + + const int text_margin = background.get_size().y * 0.085; + label_text.set_position((background.get_position() + mgl::vec2f(background.get_size().x * 0.5f - label_text.get_bounds().size.x * 0.5f, text_margin)).floor()); + window.draw(label_text); + + mgl::Sprite icon(&get_theme().settings_texture); + icon.set_height((int)(background.get_size().y * 0.5f)); + icon.set_position((background.get_position() + background.get_size() * 0.5f - icon.get_size() * 0.5f).floor()); + window.draw(icon); + } + + mgl::vec2f GsrPage::get_size() { + if(!visible) + return {0.0f, 0.0f}; + + const mgl::vec2f window_size = mgl::vec2f(get_theme().window_width, get_theme().window_height).floor(); + const mgl::vec2f content_page_size = (window_size * mgl::vec2f(0.3333f, 0.7f)).floor(); + return content_page_size; + } + + mgl::vec2f GsrPage::get_inner_size() { + if(!visible) + return {0.0f, 0.0f}; + + const int margin_top = margin_top_scale * get_theme().window_height; + const int margin_bottom = margin_bottom_scale * get_theme().window_height; + const int margin_left = margin_left_scale * get_theme().window_height; + const int margin_right = margin_right_scale * get_theme().window_height; + return get_size() - mgl::vec2f(margin_left + margin_right, margin_top + margin_bottom + get_border_size()); + } + + void GsrPage::add_widget(std::unique_ptr<Widget> 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<void()> on_click_handler) { + back_button.on_click = std::move(on_click_handler); + } + + float GsrPage::get_border_size() const { + return 0.004f * get_theme().window_height; + } + + float GsrPage::get_horizontal_spacing() const { + return get_theme().window_width / 50; + } +}
\ No newline at end of file diff --git a/src/gui/List.cpp b/src/gui/List.cpp index acdb695..849329f 100644 --- a/src/gui/List.cpp +++ b/src/gui/List.cpp @@ -14,55 +14,25 @@ namespace gsr { if(!visible) return true; - inside_event_handler = true; // We want to store the selected child widget since it can change in the event loop below Widget *selected_widget = selected_child_widget; if(selected_widget) { - if(!selected_widget->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) { - inside_event_handler = false; + if(!selected_widget->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) return false; - } } // Process widgets by visibility (backwards) - for(auto it = widgets.rbegin(), end = widgets.rend(); it != end; ++it) { + return widgets.for_each_reverse([selected_widget, &event, &window](std::unique_ptr<Widget> &widget) { // Ignore offset because widgets are positioned with offset in ::draw, this solution is simpler - if(it->get() != selected_widget) { - if(!(*it)->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) { - inside_event_handler = false; + if(widget.get() != selected_widget) { + if(!widget->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) return false; - } } - } - - inside_event_handler = false; - return true; - } - - // TODO: Maybe call this from main on all widgets instead of from draw - void List::update() { - //widgets.insert(widgets.back(), std::make_move_iterator(add_queue.begin()), std::make_move_iterator(add_queue.end())); - std::move(add_queue.begin(), add_queue.end(), std::back_inserter(widgets)); - add_queue.clear(); - - for(Widget *widget_to_remove : remove_queue) { - remove_widget_immediate(widget_to_remove); - } - remove_queue.clear(); - } - - void List::remove_widget_immediate(Widget *widget) { - for(auto it = widgets.begin(), end = widgets.end(); it != end; ++it) { - if(it->get() == widget) { - widgets.erase(it); - return; - } - } + return true; + }); } void List::draw(mgl::Window &window, mgl::vec2f offset) { - update(); - if(!visible) return; @@ -140,28 +110,15 @@ namespace gsr { void List::add_widget(std::unique_ptr<Widget> widget) { widget->parent_widget = this; - if(inside_event_handler) - add_queue.push_back(std::move(widget)); - else - widgets.push_back(std::move(widget)); + widgets.push_back(std::move(widget)); } void List::remove_widget(Widget *widget) { - for(auto it = add_queue.begin(), end = add_queue.end(); it != end; ++it) { - if(it->get() == widget) { - add_queue.erase(it); - return; - } - } - - if(inside_event_handler) - remove_queue.push_back(widget); - else - remove_widget_immediate(widget); + widgets.remove(widget); } - const std::vector<std::unique_ptr<Widget>>& List::get_child_widgets() const { - return widgets; + void List::for_each_child_widget(std::function<bool(std::unique_ptr<Widget> &widget)> callback) { + widgets.for_each(callback); } Widget* List::get_child_widget_by_index(size_t index) const { diff --git a/src/gui/PageStack.cpp b/src/gui/PageStack.cpp new file mode 100644 index 0000000..94196cd --- /dev/null +++ b/src/gui/PageStack.cpp @@ -0,0 +1,58 @@ +#include "../../include/gui/PageStack.hpp" + +namespace gsr { + PageStack::PageStack() {} + + bool PageStack::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) { + if(!visible) + return true; + + offset = position + offset; + std::unique_ptr<Page> *top_page = widget_stack.back(); + if(top_page) { + if(!(*top_page)->on_event(event, window, offset)) + return false; + } + + return true; + } + + void PageStack::draw(mgl::Window &window, mgl::vec2f offset) { + if(!visible) + return; + + offset = position + offset; + std::unique_ptr<Page> *top_page = widget_stack.back(); + if(top_page) + (*top_page)->draw(window, offset); + } + + mgl::vec2f PageStack::get_size() { + return {0.0f, 0.0f}; + } + + void PageStack::push(std::unique_ptr<Page> widget) { + widget->on_navigate_to_page(); + widget_stack.push_back(std::move(widget)); + } + + void PageStack::pop() { + std::unique_ptr<Page> *top_page = widget_stack.back(); + if(top_page) { + (*top_page)->on_navigate_away_from_page(); + widget_stack.pop_back(); + } + } + + Page* PageStack::top() { + std::unique_ptr<Page> *top_page = widget_stack.back(); + if(top_page) + return top_page->get(); + else + return nullptr; + } + + bool PageStack::empty() const { + return widget_stack.empty(); + } +}
\ No newline at end of file diff --git a/src/gui/RadioButton.cpp b/src/gui/RadioButton.cpp index 87428bf..66f3b69 100644 --- a/src/gui/RadioButton.cpp +++ b/src/gui/RadioButton.cpp @@ -121,14 +121,14 @@ namespace gsr { dirty = true; } - void RadioButton::set_selected_item(const std::string &id, bool trigger_event) { + void RadioButton::set_selected_item(const std::string &id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) { for(size_t i = 0; i < items.size(); ++i) { auto &item = items[i]; if(item.id == id) { const size_t prev_selected_item = selected_item; selected_item = i; - if(trigger_event && selected_item != prev_selected_item && on_selection_changed) + if(trigger_event && (trigger_event_even_if_selection_not_changed || selected_item != prev_selected_item) && on_selection_changed) on_selection_changed(item.text.get_string(), item.id); break; diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp index a0977ce..a2b6c8f 100644 --- a/src/gui/ScrollablePage.cpp +++ b/src/gui/ScrollablePage.cpp @@ -1,7 +1,5 @@ #include "../../include/gui/ScrollablePage.hpp" -#include "../../include/Theme.hpp" -#include <mglpp/graphics/Rectangle.hpp> #include <mglpp/window/Window.hpp> namespace gsr { @@ -11,11 +9,8 @@ namespace gsr { if(!visible) 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 draw_pos = position + offset; - offset = draw_pos + mgl::vec2f(margin_left, get_border_size() + margin_top).floor(); + offset = draw_pos; Widget *selected_widget = selected_child_widget; if(selected_widget) { @@ -38,21 +33,8 @@ namespace gsr { 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 draw_pos = position + offset; - offset = draw_pos + mgl::vec2f(margin_left, get_border_size() + margin_top).floor(); - - mgl::Rectangle background(size.floor()); - background.set_position(draw_pos); - background.set_color(get_theme().scrollable_page_bg_color); - window.draw(background); - - mgl::Rectangle border(mgl::vec2f(size.x, get_border_size()).floor()); - border.set_position(draw_pos); - border.set_color(get_theme().tint_color); - window.draw(border); + offset = draw_pos; mgl_scissor prev_scissor; mgl_window_get_scissor(window.internal_window(), &prev_scissor); @@ -84,25 +66,11 @@ namespace gsr { return size; } - mgl::vec2f ScrollablePage::get_inner_size() { - if(!visible) - return {0.0f, 0.0f}; - - const int margin_top = margin_top_scale * get_theme().window_height; - const int margin_bottom = margin_bottom_scale * get_theme().window_height; - const int margin_left = margin_left_scale * get_theme().window_height; - const int margin_right = margin_right_scale * get_theme().window_height; - return size - mgl::vec2f(margin_left + margin_right, margin_top + margin_bottom + get_border_size()); - } - - void ScrollablePage::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; + void ScrollablePage::set_size(mgl::vec2f size) { + this->size = size; } - float ScrollablePage::get_border_size() const { - return 0.004f * get_theme().window_height; + void ScrollablePage::add_widget(std::unique_ptr<Widget> widget) { + widgets.push_back(std::move(widget)); } }
\ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index 9bf6a12..d6022ab 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -1,6 +1,8 @@ #include "../../include/gui/SettingsPage.hpp" -#include "../../include/gui/ScrollablePage.hpp" +#include "../../include/gui/GsrPage.hpp" #include "../../include/gui/Label.hpp" +#include "../../include/gui/PageStack.hpp" +#include "../../include/gui/FileChooser.hpp" #include "../../include/Theme.hpp" #include "../../include/GsrInfo.hpp" @@ -10,20 +12,17 @@ #include <mglpp/window/Window.hpp> namespace gsr { - SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices, std::optional<Config> &config) : + SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices, std::optional<Config> &config, PageStack *page_stack) : StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), type(type), config(config), + page_stack(page_stack), settings_title_text("Settings", get_theme().title_font) { - const mgl::vec2f window_size = mgl::vec2f(get_theme().window_width, get_theme().window_height).floor(); - const mgl::vec2f content_page_size = (window_size * mgl::vec2f(0.3333f, 0.7f)).floor(); - const mgl::vec2f content_page_position = mgl::vec2f(window_size * 0.5f - content_page_size * 0.5f).floor(); - const float settings_body_margin = 0.02f; - - auto content_page = std::make_unique<ScrollablePage>(content_page_size); - content_page->set_position(content_page_position); - content_page->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin); + auto content_page = std::make_unique<GsrPage>(); + content_page->set_on_back_button_click([page_stack]() { + page_stack->pop(); + }); content_page_ptr = content_page.get(); add_widget(std::move(content_page)); @@ -31,40 +30,6 @@ namespace gsr { add_page_specific_widgets(); } - std::unique_ptr<Button> SettingsPage::create_back_button() { - const mgl::vec2i window_size(get_theme().window_width, get_theme().window_height); - auto back_button = std::make_unique<Button>(&get_theme().title_font, "Back", mgl::vec2f(window_size.x / 10, window_size.y / 15).floor(), get_theme().scrollable_page_bg_color); - back_button->set_position(content_page_ptr->get_position().floor() + mgl::vec2f(content_page_ptr->get_size().x + window_size.x / 50, 0.0f).floor()); - back_button->set_border_scale(0.003f); - back_button->on_click = [this]() { - if(on_back_button_handler) - on_back_button_handler(); - }; - return back_button; - } - - std::unique_ptr<CustomRendererWidget> SettingsPage::create_settings_icon() { - const mgl::vec2i window_size(get_theme().window_width, get_theme().window_height); - auto settings_icon_widget = std::make_unique<CustomRendererWidget>(mgl::vec2f(window_size.x / 10, window_size.x / 10).floor()); - settings_icon_widget->set_position(content_page_ptr->get_position().floor() - mgl::vec2f(settings_icon_widget->get_size().x + window_size.x / 50, 0.0f).floor()); - settings_icon_widget->draw_handler = [&](mgl::Window &window, mgl::vec2f pos, mgl::vec2f size) { - mgl::Rectangle background(size); - background.set_position(pos); - background.set_color(mgl::Color(0, 0, 0, 255)); - window.draw(background); - - const int text_margin = size.y * 0.085; - settings_title_text.set_position((pos + mgl::vec2f(size.x * 0.5f - settings_title_text.get_bounds().size.x * 0.5f, text_margin)).floor()); - window.draw(settings_title_text); - - mgl::Sprite icon(&get_theme().settings_texture); - icon.set_height((int)(size.y * 0.5f)); - icon.set_position((pos + size * 0.5f - icon.get_size() * 0.5f).floor()); - window.draw(icon); - }; - return settings_icon_widget; - } - std::unique_ptr<RadioButton> SettingsPage::create_view_radio_button() { auto view_radio_button = std::make_unique<RadioButton>(&get_theme().body_font); view_radio_button->add_item("Simple view", "simple"); @@ -363,8 +328,6 @@ namespace gsr { } void SettingsPage::add_widgets(const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices) { - add_widget(create_back_button()); - add_widget(create_settings_icon()); content_page_ptr->add_widget(create_settings(gsr_info, audio_devices)); record_area_box_ptr->on_selection_changed = [this](const std::string &text, const std::string &id) { @@ -400,9 +363,20 @@ namespace gsr { std::unique_ptr<List> SettingsPage::create_save_directory(const char *label) { auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL); save_directory_list->add_widget(std::make_unique<Label>(&get_theme().body_font, label, get_theme().text_color)); - auto save_directory_entry = std::make_unique<Entry>(&get_theme().body_font, "/home/dec05eba/Videos", get_theme().body_font.get_character_size() * 20); - save_directory_entry_ptr = save_directory_entry.get(); - save_directory_list->add_widget(std::move(save_directory_entry)); + auto save_directory_button = std::make_unique<Button>(&get_theme().body_font, "/home/dec05eba/Videos", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + save_directory_button->on_click = [this]() { + auto select_directory_page = std::make_unique<GsrPage>(); + select_directory_page->set_on_back_button_click([this]() { + page_stack->pop(); + }); + + auto file_chooser = std::make_unique<gsr::FileChooser>("/home/dec05eba", select_directory_page->get_size()); + select_directory_page->add_widget(std::move(file_chooser)); + + page_stack->push(std::move(select_directory_page)); + }; + save_directory_button_ptr = save_directory_button.get(); + save_directory_list->add_widget(std::move(save_directory_button)); return save_directory_list; } @@ -658,12 +632,12 @@ namespace gsr { static void save_audio_tracks(std::vector<std::string> &audio_tracks, List *audio_devices_list_ptr) { audio_tracks.clear(); - const std::vector<std::unique_ptr<Widget>> &audio_devices_list = audio_devices_list_ptr->get_child_widgets(); - for(const std::unique_ptr<Widget> &child_widget : audio_devices_list) { + audio_devices_list_ptr->for_each_child_widget([&audio_tracks](std::unique_ptr<Widget> &child_widget) { List *audio_device_line = static_cast<List*>(child_widget.get()); ComboBox *audio_device_box = static_cast<ComboBox*>(audio_device_line->get_child_widget_by_index(0)); audio_tracks.push_back(audio_device_box->get_selected_id()); - } + return true; + }); } void SettingsPage::save_common(RecordOptions &record_options) { @@ -705,7 +679,7 @@ namespace gsr { config->replay_config.show_replay_started_notifications = show_replay_started_notification_checkbox_ptr->is_checked(); config->replay_config.show_replay_stopped_notifications = show_replay_stopped_notification_checkbox_ptr->is_checked(); config->replay_config.show_replay_saved_notifications = show_replay_saved_notification_checkbox_ptr->is_checked(); - config->replay_config.save_directory = save_directory_entry_ptr->get_text(); + config->replay_config.save_directory = save_directory_button_ptr->get_text(); config->replay_config.container = container_box_ptr->get_selected_id(); config->replay_config.replay_time = atoi(replay_time_entry_ptr->get_text().c_str()); @@ -719,7 +693,7 @@ namespace gsr { save_common(config->record_config.record_options); config->record_config.show_recording_started_notifications = show_recording_started_notification_checkbox_ptr->is_checked(); config->record_config.show_video_saved_notifications = show_video_saved_notification_checkbox_ptr->is_checked(); - config->record_config.save_directory = save_directory_entry_ptr->get_text(); + config->record_config.save_directory = save_directory_button_ptr->get_text(); config->record_config.container = container_box_ptr->get_selected_id(); } diff --git a/src/main.cpp b/src/main.cpp index be872d9..138cd3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,24 +4,17 @@ #include "../include/gui/CustomRendererWidget.hpp" #include "../include/gui/SettingsPage.hpp" #include "../include/gui/Utils.hpp" +#include "../include/gui/PageStack.hpp" #include "../include/Process.hpp" #include "../include/Theme.hpp" #include "../include/GsrInfo.hpp" #include "../include/window_texture.h" #include "../include/Config.hpp" -#include <stdio.h> -#include <stdlib.h> #include <string.h> -#include <time.h> -#include <errno.h> -#include <libgen.h> #include <signal.h> #include <sys/wait.h> -#include <optional> -#include <signal.h> #include <assert.h> -#include <stack> #include <X11/Xlib.h> #include <X11/cursorfont.h> @@ -235,10 +228,10 @@ int main(int argc, char **argv) { signal(SIGINT, sigint_handler); gsr::GsrInfo gsr_info; - // TODO: + // TODO: Show the error in ui gsr::GsrInfoExitStatus gsr_info_exit_status = gsr::get_gpu_screen_recorder_info(&gsr_info); if(gsr_info_exit_status != gsr::GsrInfoExitStatus::OK) { - fprintf(stderr, "error: failed to get gpu-screen-recorder info\n"); + fprintf(stderr, "error: failed to get gpu-screen-recorder info, error: %d\n", (int)gsr_info_exit_status); exit(1); } @@ -331,8 +324,6 @@ int main(int argc, char **argv) { WindowTexture window_texture; bool window_texture_loaded = false; - mgl_texture window_texture_tex; - memset(&window_texture_tex, 0, sizeof(window_texture_tex)); mgl::Texture window_texture_texture; mgl::Sprite window_texture_sprite; @@ -343,18 +334,7 @@ int main(int argc, char **argv) { window_texture_loaded = window_texture_init(&window_texture, display, mgl_window_get_egl_display(window.internal_window()), window_at_cursor_position, egl_funcs) == 0; if(window_texture_loaded && window_texture.texture_id) { - DrawableGeometry geometry; - get_drawable_geometry(display, (Drawable)window_texture.pixmap, &geometry); - - window_texture_tex.id = window_texture.texture_id; - window_texture_tex.width = geometry.width; - window_texture_tex.height = geometry.height; - window_texture_tex.format = MGL_TEXTURE_FORMAT_RGB; - window_texture_tex.max_width = 1 << 15; - window_texture_tex.max_height = 1 << 15; - window_texture_tex.pixel_coordinates = false; - window_texture_tex.mipmap = false; - window_texture_texture = mgl::Texture::reference(window_texture_tex); + window_texture_texture = mgl::Texture(window_texture.texture_id, MGL_TEXTURE_FORMAT_RGB); window_texture_sprite.set_texture(&window_texture_texture); } else { XImage *img = XGetImage(display, DefaultRootWindow(display), window_pos.x, window_pos.y, window_size.x, window_size.y, AllPlanes, ZPixmap); @@ -376,33 +356,14 @@ int main(int argc, char **argv) { mgl::Rectangle bg_screenshot_overlay(window_size.to_vec2f()); bg_screenshot_overlay.set_color(bg_color); - gsr::StaticPage front_page(window_size.to_vec2f()); + auto front_page = std::make_unique<gsr::StaticPage>(window_size.to_vec2f()); + gsr::StaticPage *front_page_ptr = front_page.get(); - std::stack<gsr::Page*> page_stack; - page_stack.push(&front_page); - - const auto settings_back_button_callback = [&] { - page_stack.top()->on_navigate_away_from_page(); - page_stack.pop(); - }; + gsr::PageStack page_stack; + page_stack.push(std::move(front_page)); std::optional<gsr::Config> config = gsr::read_config(); - gsr::SettingsPage replay_settings_page(gsr::SettingsPage::Type::REPLAY, gsr_info, audio_devices, config); - replay_settings_page.on_back_button_handler = settings_back_button_callback; - - gsr::SettingsPage record_settings_page(gsr::SettingsPage::Type::RECORD, gsr_info, audio_devices, config); - record_settings_page.on_back_button_handler = settings_back_button_callback; - - gsr::SettingsPage stream_settings_page(gsr::SettingsPage::Type::STREAM, gsr_info, audio_devices, config); - stream_settings_page.on_back_button_handler = settings_back_button_callback; - - if(!config) { - replay_settings_page.save(); - record_settings_page.save(); - stream_settings_page.save(); - } - struct MainButton { gsr::DropdownButton* button; gsr::GsrMode mode; @@ -444,7 +405,7 @@ int main(int argc, char **argv) { button->add_item("Start", "start"); button->add_item("Settings", "settings"); gsr::DropdownButton *button_ptr = button.get(); - front_page.add_widget(std::move(button)); + front_page_ptr->add_widget(std::move(button)); MainButton main_button = { button_ptr, @@ -488,7 +449,8 @@ int main(int argc, char **argv) { // Replay main_buttons[0].button->on_click = [&](const std::string &id) { if(id == "settings") { - page_stack.push(&replay_settings_page); + auto replay_settings_page = std::make_unique<gsr::SettingsPage>(gsr::SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack); + page_stack.push(std::move(replay_settings_page)); return; } /* @@ -513,7 +475,8 @@ int main(int argc, char **argv) { // Record main_buttons[1].button->on_click = [&](const std::string &id) { if(id == "settings") { - page_stack.push(&record_settings_page); + auto record_settings_page = std::make_unique<gsr::SettingsPage>(gsr::SettingsPage::Type::RECORD, gsr_info, audio_devices, config, &page_stack); + page_stack.push(std::move(record_settings_page)); return; } @@ -598,7 +561,8 @@ int main(int argc, char **argv) { // Stream main_buttons[2].button->on_click = [&](const std::string &id) { if(id == "settings") { - page_stack.push(&stream_settings_page); + auto stream_settings_page = std::make_unique<gsr::SettingsPage>(gsr::SettingsPage::Type::STREAM, gsr_info, audio_devices, config, &page_stack); + page_stack.push(std::move(stream_settings_page)); return; } }; @@ -733,6 +697,8 @@ int main(int argc, char **argv) { quit: fprintf(stderr, "shutting down!\n"); + XUngrabKeyboard(display, CurrentTime); + XUngrabPointer(display, CurrentTime); if(window_texture_loaded) window_texture_deinit(&window_texture); gsr::deinit_theme(); |