diff options
-rw-r--r-- | include/SettingsPage.hpp | 37 | ||||
-rw-r--r-- | include/Theme.hpp | 1 | ||||
-rw-r--r-- | include/gui/ComboBox.hpp | 6 | ||||
-rw-r--r-- | include/gui/RadioButton.hpp | 2 | ||||
-rw-r--r-- | include/gui/ScrollablePage.hpp | 1 | ||||
-rw-r--r-- | include/gui/Widget.hpp | 2 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/SettingsPage.cpp | 411 | ||||
-rw-r--r-- | src/Theme.cpp | 1 | ||||
-rw-r--r-- | src/gui/ComboBox.cpp | 15 | ||||
-rw-r--r-- | src/gui/List.cpp | 6 | ||||
-rw-r--r-- | src/gui/RadioButton.cpp | 10 | ||||
-rw-r--r-- | src/gui/ScrollablePage.cpp | 9 | ||||
-rw-r--r-- | src/main.cpp | 315 |
14 files changed, 504 insertions, 313 deletions
diff --git a/include/SettingsPage.hpp b/include/SettingsPage.hpp new file mode 100644 index 0000000..aec7bed --- /dev/null +++ b/include/SettingsPage.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "gui/StaticPage.hpp" +#include "GsrInfo.hpp" + +#include <functional> + +namespace gsr { + class ScrollablePage; + class List; + + class SettingsPage { + public: + enum class Type { + REPLAY, + RECORD, + STREAM + }; + + SettingsPage(Type type, const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices, std::function<void()> back_button_callback); + SettingsPage(const SettingsPage&) = delete; + SettingsPage& operator=(const SettingsPage&) = delete; + + Page& get_page(); + private: + void add_widgets(const gsr::GsrInfo &gsr_info, const std::vector<gsr::AudioDevice> &audio_devices, std::function<void()> back_button_callback); + void add_page_specific_widgets(); + void add_replay_widgets(); + void add_record_widgets(); + void add_stream_widgets(); + private: + StaticPage page; + ScrollablePage *content_page_ptr = nullptr; + List *settings_list_ptr = nullptr; + Type type; + }; +}
\ No newline at end of file diff --git a/include/Theme.hpp b/include/Theme.hpp index a28c249..ced85bd 100644 --- a/include/Theme.hpp +++ b/include/Theme.hpp @@ -15,6 +15,7 @@ namespace gsr { Theme(const Theme&) = delete; Theme& operator=(const Theme&) = delete; + float window_width = 0.0f; float window_height = 0.0f; mgl::Color tint_color = mgl::Color(118, 185, 0); diff --git a/include/gui/ComboBox.hpp b/include/gui/ComboBox.hpp index b4e7b78..ac9d02b 100644 --- a/include/gui/ComboBox.hpp +++ b/include/gui/ComboBox.hpp @@ -3,6 +3,8 @@ #include "Widget.hpp" #include <mglpp/graphics/Text.hpp> #include <mglpp/graphics/Sprite.hpp> + +#include <functional> #include <string> #include <vector> @@ -17,9 +19,11 @@ namespace gsr { void draw(mgl::Window &window, mgl::vec2f offset) override; void add_item(const std::string &text, const std::string &id); - void set_selected_item(const std::string &id); + void set_selected_item(const std::string &id, bool trigger_event = true); mgl::vec2f get_size() override; + + std::function<void(const std::string &text, const std::string &id)> on_selection_changed; private: void update_if_dirty(); float get_dropdown_arrow_height() const; diff --git a/include/gui/RadioButton.hpp b/include/gui/RadioButton.hpp index d4b1103..60f3e82 100644 --- a/include/gui/RadioButton.hpp +++ b/include/gui/RadioButton.hpp @@ -17,7 +17,7 @@ namespace gsr { void draw(mgl::Window &window, mgl::vec2f offset) override; void add_item(const std::string &text, const std::string &id); - void set_selected_item(const std::string &id); + void set_selected_item(const std::string &id, bool trigger_event = true); mgl::vec2f get_size() override; diff --git a/include/gui/ScrollablePage.hpp b/include/gui/ScrollablePage.hpp index 9d4623b..60d719f 100644 --- a/include/gui/ScrollablePage.hpp +++ b/include/gui/ScrollablePage.hpp @@ -13,6 +13,7 @@ namespace gsr { void draw(mgl::Window &window, mgl::vec2f offset) override; mgl::vec2f get_size() override; + mgl::vec2f get_inner_size() override; void set_margins(float top, float bottom, float left, float right); private: diff --git a/include/gui/Widget.hpp b/include/gui/Widget.hpp index 5b582da..498ca05 100644 --- a/include/gui/Widget.hpp +++ b/include/gui/Widget.hpp @@ -34,6 +34,8 @@ namespace gsr { virtual mgl::vec2f get_position() const; virtual mgl::vec2f get_size() = 0; + // This can be different from get_size, for example with ScrollablePage this excludes the margins + virtual mgl::vec2f get_inner_size() { return get_size(); } void set_horizontal_alignment(Alignment alignment); void set_vertical_alignment(Alignment alignment); diff --git a/meson.build b/meson.build index 8a35e5a..f04ec23 100644 --- a/meson.build +++ b/meson.build @@ -21,6 +21,7 @@ src = [ 'src/gui/Utils.cpp', 'src/gui/DropdownButton.cpp', 'src/gui/Label.cpp', + 'src/SettingsPage.cpp', 'src/Utils.cpp', 'src/Config.cpp', 'src/GsrInfo.cpp', diff --git a/src/SettingsPage.cpp b/src/SettingsPage.cpp new file mode 100644 index 0000000..187d414 --- /dev/null +++ b/src/SettingsPage.cpp @@ -0,0 +1,411 @@ +#include "../include/SettingsPage.hpp" +#include "../include/Theme.hpp" +#include "../include/gui/Button.hpp" +#include "../include/gui/RadioButton.hpp" +#include "../include/gui/List.hpp" +#include "../include/gui/ComboBox.hpp" +#include "../include/gui/Label.hpp" +#include "../include/gui/Entry.hpp" +#include "../include/gui/CheckBox.hpp" +#include "../include/gui/ScrollablePage.hpp" +#include "../include/GsrInfo.hpp" + +namespace gsr { + SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices, std::function<void()> back_button_callback) : + page(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), + type(type) + { + 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); + content_page_ptr = content_page.get(); + page.add_widget(std::move(content_page)); + + add_widgets(gsr_info, audio_devices, back_button_callback); + add_page_specific_widgets(); + } + + Page& SettingsPage::get_page() { + return page; + } + + void SettingsPage::add_widgets(const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices, std::function<void()> back_button_callback) { + RadioButton *view_radio_button_ptr = nullptr; + ComboBox *record_area_box_ptr = nullptr; + List *select_window_list_ptr = nullptr; + List *area_size_list_ptr = nullptr; + Widget *color_range_list_ptr = nullptr; + Widget *codec_list_ptr = nullptr; + Widget *framerate_mode_list_ptr = nullptr; + + 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 = back_button_callback; + page.add_widget(std::move(back_button)); + + auto settings_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + auto view_radio_button = std::make_unique<RadioButton>(&get_theme().body_font); + view_radio_button->add_item("Simple view", "simple"); + view_radio_button->add_item("Advanced view", "advanced"); + view_radio_button->set_horizontal_alignment(Widget::Alignment::CENTER); + view_radio_button_ptr = view_radio_button.get(); + settings_list->add_widget(std::move(view_radio_button)); + + auto capture_target_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + record_area_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Record area:", get_theme().text_color)); + auto record_area_box = std::make_unique<ComboBox>(&get_theme().body_font); + // TODO: Show options not supported but disable them + if(gsr_info.supported_capture_options.window) + record_area_box->add_item("Window", "window"); + if(gsr_info.supported_capture_options.focused) + record_area_box->add_item("Follow focused window", "focused"); + if(gsr_info.supported_capture_options.screen) + record_area_box->add_item("All monitors", "screen"); + for(const auto &monitor : gsr_info.supported_capture_options.monitors) { + char name[256]; + snprintf(name, sizeof(name), "Monitor %s (%dx%d)", monitor.name.c_str(), monitor.size.x, monitor.size.y); + record_area_box->add_item(name, monitor.name); + } + if(gsr_info.supported_capture_options.portal) + record_area_box->add_item("Desktop portal", "portal"); + record_area_box_ptr = record_area_box.get(); + record_area_list->add_widget(std::move(record_area_box)); + } + capture_target_list->add_widget(std::move(record_area_list)); + + auto select_window_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + select_window_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Select window:", get_theme().text_color)); + select_window_list->add_widget(std::make_unique<Button>(&get_theme().body_font, "Click here to select a window...", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120))); + } + select_window_list_ptr = select_window_list.get(); + capture_target_list->add_widget(std::move(select_window_list)); + + auto area_size_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + area_size_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Area size:", get_theme().text_color)); + auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + { + auto area_width_entry = std::make_unique<Entry>(&get_theme().body_font, "1920", get_theme().body_font.get_character_size() * 5); + area_width_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); + area_size_params_list->add_widget(std::move(area_width_entry)); + + area_size_params_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "x", get_theme().text_color)); + + auto area_height_entry = std::make_unique<Entry>(&get_theme().body_font, "1080", get_theme().body_font.get_character_size() * 5); + area_height_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); + area_size_params_list->add_widget(std::move(area_height_entry)); + } + area_size_list->add_widget(std::move(area_size_params_list)); + } + area_size_list_ptr = area_size_list.get(); + capture_target_list->add_widget(std::move(area_size_list)); + } + settings_list->add_widget(std::move(capture_target_list)); + + auto audio_device_section_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + audio_device_section_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Audio:", get_theme().text_color)); + auto audio_devices_list = std::make_unique<List>(List::Orientation::VERTICAL); + List *audio_devices_list_ptr = audio_devices_list.get(); + + auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Add audio track", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + auto add_audio_track = [&audio_devices, audio_devices_list_ptr]() { + auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + List *audio_device_list_ptr = audio_device_list.get(); + { + audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, ">", get_theme().text_color)); + auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); + for(const auto &audio_device : audio_devices) { + audio_device_box->add_item(audio_device.description, audio_device.name); + } + audio_device_list->add_widget(std::move(audio_device_box)); + auto remove_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Remove", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + remove_audio_track_button->on_click = [=]() { + audio_devices_list_ptr->remove_widget(audio_device_list_ptr); + }; + audio_device_list->add_widget(std::move(remove_audio_track_button)); + } + audio_devices_list_ptr->add_widget(std::move(audio_device_list)); + }; + add_audio_track_button->on_click = add_audio_track; + audio_device_section_list->add_widget(std::move(add_audio_track_button)); + + for(int i = 0; i < 3; ++i) { + add_audio_track(); + } + audio_device_section_list->add_widget(std::move(audio_devices_list)); + } + settings_list->add_widget(std::move(audio_device_section_list)); + + auto quality_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto video_quality_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + video_quality_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video quality:", get_theme().text_color)); + auto video_quality_box = std::make_unique<ComboBox>(&get_theme().body_font); + video_quality_box->add_item("Medium", "medium"); + video_quality_box->add_item("High (Recommended for live streaming)", "high"); + video_quality_box->add_item("Very high (Recommended)", "very_high"); + video_quality_box->add_item("Ultra", "ultra"); + video_quality_box->set_selected_item("very_high"); + video_quality_list->add_widget(std::move(video_quality_box)); + } + quality_list->add_widget(std::move(video_quality_list)); + + auto color_range_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + color_range_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Color range:", get_theme().text_color)); + auto color_range_box = std::make_unique<ComboBox>(&get_theme().body_font); + color_range_box->add_item("Limited", "limited"); + color_range_box->add_item("Full", "full"); + color_range_list->add_widget(std::move(color_range_box)); + } + color_range_list_ptr = color_range_list.get(); + quality_list->add_widget(std::move(color_range_list)); + } + settings_list->add_widget(std::move(quality_list)); + + auto codec_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto video_codec_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + video_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video codec:", get_theme().text_color)); + auto video_codec_box = std::make_unique<ComboBox>(&get_theme().body_font); + // TODO: Show options not supported but disable them + video_codec_box->add_item("Auto (Recommended)", "auto"); + if(gsr_info.supported_video_codecs.h264) + video_codec_box->add_item("H264", "h264"); + if(gsr_info.supported_video_codecs.hevc) + video_codec_box->add_item("HEVC", "hevc"); + if(gsr_info.supported_video_codecs.av1) + video_codec_box->add_item("AV1", "av1"); + if(gsr_info.supported_video_codecs.vp8) + video_codec_box->add_item("VP8", "vp8"); + if(gsr_info.supported_video_codecs.vp9) + video_codec_box->add_item("VP9", "vp9"); + // TODO: Add hdr options + if(gsr_info.supported_video_codecs.h264_software) + video_codec_box->add_item("H264 Software Encoder (Slow, not recommended)", "h264_software"); + video_codec_list->add_widget(std::move(video_codec_box)); + } + codec_list->add_widget(std::move(video_codec_list)); + + auto audio_codec_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + audio_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Audio codec:", get_theme().text_color)); + auto audio_codec_box = std::make_unique<ComboBox>(&get_theme().body_font); + audio_codec_box->add_item("Opus (Recommended)", "opus"); + audio_codec_box->add_item("AAC", "aac"); + audio_codec_list->add_widget(std::move(audio_codec_box)); + } + codec_list->add_widget(std::move(audio_codec_list)); + } + codec_list_ptr = codec_list.get(); + settings_list->add_widget(std::move(codec_list)); + + auto framerate_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto framerate_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + framerate_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Frame rate:", get_theme().text_color)); + auto framerate_entry = std::make_unique<Entry>(&get_theme().body_font, "60", get_theme().body_font.get_character_size() * 3); + framerate_entry->validate_handler = create_entry_validator_integer_in_range(1, 500); + framerate_list->add_widget(std::move(framerate_entry)); + } + framerate_info_list->add_widget(std::move(framerate_list)); + + auto framerate_mode_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + framerate_mode_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Frame rate mode:", get_theme().text_color)); + auto framerate_mode_box = std::make_unique<ComboBox>(&get_theme().body_font); + framerate_mode_box->add_item("Auto (Recommended)", "auto"); + framerate_mode_box->add_item("Constant", "cfr"); + framerate_mode_box->add_item("Variable", "vfr"); + framerate_mode_list->add_widget(std::move(framerate_mode_box)); + } + framerate_mode_list_ptr = framerate_mode_list.get(); + framerate_info_list->add_widget(std::move(framerate_mode_list)); + } + settings_list->add_widget(std::move(framerate_info_list)); + } + settings_list_ptr = settings_list.get(); + content_page_ptr->add_widget(std::move(settings_list)); + + record_area_box_ptr->on_selection_changed = [=](const std::string &text, const std::string &id) { + (void)text; + const bool window_selected = id == "window"; + const bool focused_selected = id == "focused"; + select_window_list_ptr->set_visible(window_selected); + area_size_list_ptr->set_visible(focused_selected); + }; + + view_radio_button_ptr->on_selection_changed = [=](const std::string &text, const std::string &id) { + (void)text; + const bool advanced_view = id == "advanced"; + color_range_list_ptr->set_visible(advanced_view); + codec_list_ptr->set_visible(advanced_view); + framerate_mode_list_ptr->set_visible(advanced_view); + }; + view_radio_button_ptr->on_selection_changed("Simple", "simple"); + + if(!gsr_info.supported_capture_options.monitors.empty()) + record_area_box_ptr->set_selected_item(gsr_info.supported_capture_options.monitors.front().name); + else if(gsr_info.supported_capture_options.portal) + record_area_box_ptr->set_selected_item("portal"); + } + + void SettingsPage::add_page_specific_widgets() { + switch(type) { + case Type::REPLAY: + add_replay_widgets(); + break; + case Type::RECORD: + add_record_widgets(); + break; + case Type::STREAM: + add_stream_widgets(); + break; + } + } + + void SettingsPage::add_replay_widgets() { + auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + save_directory_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Directory to save replays:", get_theme().text_color)); + // TODO: + save_directory_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "/home/dec05eba/Videos", get_theme().body_font.get_character_size() * 20)); + } + file_list->add_widget(std::move(save_directory_list)); + + auto container_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + container_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Container:", get_theme().text_color)); + auto container_box = std::make_unique<ComboBox>(&get_theme().body_font); + container_box->add_item("mp4", "mp4"); + container_box->add_item("mkv", "matroska"); + container_box->add_item("flv", "flv"); + container_box->add_item("mov", "mov"); + container_list->add_widget(std::move(container_box)); + } + file_list->add_widget(std::move(container_list)); + } + settings_list_ptr->add_widget(std::move(file_list)); + + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show replay started notification")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show replay stopped notification")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show replay saved notification")); + } + + void SettingsPage::add_record_widgets() { + auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + save_directory_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Directory to save the video:", get_theme().text_color)); + // TODO: + save_directory_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "/home/dec05eba/Videos", get_theme().body_font.get_character_size() * 20)); + } + file_list->add_widget(std::move(save_directory_list)); + + auto container_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + container_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Container:", get_theme().text_color)); + auto container_box = std::make_unique<ComboBox>(&get_theme().body_font); + container_box->add_item("mp4", "mp4"); + container_box->add_item("mkv", "matroska"); + container_box->add_item("flv", "flv"); + container_box->add_item("mov", "mov"); + container_list->add_widget(std::move(container_box)); + } + file_list->add_widget(std::move(container_list)); + } + settings_list_ptr->add_widget(std::move(file_list)); + + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show recording started notification")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show video saved notification")); + } + + void SettingsPage::add_stream_widgets() { + ComboBox *streaming_service_box_ptr = nullptr; + List *stream_key_list_ptr = nullptr; + List *stream_url_list_ptr = nullptr; + List *container_list_ptr = nullptr; + + auto streaming_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + { + auto streaming_service_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + streaming_service_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Stream service:", get_theme().text_color)); + auto streaming_service_box = std::make_unique<ComboBox>(&get_theme().body_font); + streaming_service_box->add_item("Twitch", "twitch"); + streaming_service_box->add_item("YouTube", "youtube"); + streaming_service_box->add_item("Custom", "custom"); + streaming_service_box_ptr = streaming_service_box.get(); + streaming_service_list->add_widget(std::move(streaming_service_box)); + } + streaming_info_list->add_widget(std::move(streaming_service_list)); + + auto stream_key_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + stream_key_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Stream key:", get_theme().text_color)); + stream_key_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20)); + } + stream_key_list_ptr = stream_key_list.get(); + streaming_info_list->add_widget(std::move(stream_key_list)); + + auto stream_url_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + stream_url_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "URL:", get_theme().text_color)); + stream_url_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20)); + } + stream_url_list_ptr = stream_url_list.get(); + streaming_info_list->add_widget(std::move(stream_url_list)); + + auto container_list = std::make_unique<List>(List::Orientation::VERTICAL); + { + container_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Container:", get_theme().text_color)); + auto container_box = std::make_unique<ComboBox>(&get_theme().body_font); + container_box->add_item("mp4", "mp4"); + container_box->add_item("mkv", "matroska"); + container_box->add_item("flv", "flv"); + container_box->add_item("mov", "mov"); + container_box->add_item("ts", "mpegts"); + container_box->add_item("m3u8", "hls"); + container_list->add_widget(std::move(container_box)); + } + container_list_ptr = container_list.get(); + streaming_info_list->add_widget(std::move(container_list)); + } + settings_list_ptr->add_widget(std::move(streaming_info_list)); + + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show streaming started notification")); + settings_list_ptr->add_widget(std::make_unique<CheckBox>(&get_theme().body_font, "Show streaming stopped notification")); + + streaming_service_box_ptr->on_selection_changed = [=](const std::string &text, const std::string &id) { + (void)text; + const bool custom_option = id == "custom"; + stream_key_list_ptr->set_visible(!custom_option); + stream_url_list_ptr->set_visible(custom_option); + container_list_ptr->set_visible(custom_option); + }; + streaming_service_box_ptr->on_selection_changed("Twitch", "twitch"); + } +}
\ No newline at end of file diff --git a/src/Theme.cpp b/src/Theme.cpp index 8ab58ec..0849eed 100644 --- a/src/Theme.cpp +++ b/src/Theme.cpp @@ -11,6 +11,7 @@ namespace gsr { theme = new Theme(); + theme->window_width = window_size.x; theme->window_height = window_size.y; switch(gsr_info.gpu_info.vendor) { diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp index 0b232f2..6aff979 100644 --- a/src/gui/ComboBox.cpp +++ b/src/gui/ComboBox.cpp @@ -39,9 +39,14 @@ namespace gsr { Item &item = items[i]; const mgl::FloatRect text_bounds = item.text.get_bounds(); if(mgl::FloatRect(pos - mgl::vec2f(padding_left, padding_top), item_size).contains(mouse_pos)) { + const size_t prev_selected_item = selected_item; selected_item = i; show_dropdown = false; remove_widget_as_selected_in_parent(); + + if(selected_item != prev_selected_item && on_selection_changed) + on_selection_changed(item.text.get_string(), item.id); + return false; } pos.y += text_bounds.size.y + padding_top + padding_bottom; @@ -141,10 +146,16 @@ namespace gsr { dirty = true; } - void ComboBox::set_selected_item(const std::string &id) { + void ComboBox::set_selected_item(const std::string &id, bool trigger_event) { for(size_t i = 0; i < items.size(); ++i) { - if(items[i].id == id) { + 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) + on_selection_changed(item.text.get_string(), item.id); + break; } } diff --git a/src/gui/List.cpp b/src/gui/List.cpp index 5e5a172..039842d 100644 --- a/src/gui/List.cpp +++ b/src/gui/List.cpp @@ -67,7 +67,7 @@ namespace gsr { // TODO: Handle start/end alignment const mgl::vec2f size = get_size(); - const mgl::vec2f parent_size = parent_widget ? parent_widget->get_size() : mgl::vec2f(0.0f, 0.0f); + const mgl::vec2f parent_inner_size = parent_widget ? parent_widget->get_inner_size() : mgl::vec2f(0.0f, 0.0f); const mgl::vec2f spacing = (spacing_scale * get_theme().window_height).floor(); switch(orientation) { @@ -80,8 +80,8 @@ namespace gsr { // TODO: Do this parent widget alignment for horizontal alignment and for other types of widget alignment // and other widgets. // Also take this widget alignment into consideration in get_size. - if(widget->get_horizontal_alignment() == Widget::Alignment::CENTER && parent_size.x > 0.001f) - offset.x = floor(parent_size.x * 0.5f - widget_size.x * 0.5f); + if(widget->get_horizontal_alignment() == Widget::Alignment::CENTER && parent_inner_size.x > 0.001f) + offset.x = floor(parent_inner_size.x * 0.5f - widget_size.x * 0.5f); else if(content_alignment == Alignment::CENTER) offset.x = floor(size.x * 0.5f - widget_size.x * 0.5f); else diff --git a/src/gui/RadioButton.cpp b/src/gui/RadioButton.cpp index b3e9a4e..15b0989 100644 --- a/src/gui/RadioButton.cpp +++ b/src/gui/RadioButton.cpp @@ -121,10 +121,16 @@ namespace gsr { dirty = true; } - void RadioButton::set_selected_item(const std::string &id) { + void RadioButton::set_selected_item(const std::string &id, bool trigger_event) { for(size_t i = 0; i < items.size(); ++i) { - if(items[i].id == id) { + 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) + on_selection_changed(item.text.get_string(), item.id); + break; } } diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp index 2c1143a..a0977ce 100644 --- a/src/gui/ScrollablePage.cpp +++ b/src/gui/ScrollablePage.cpp @@ -57,7 +57,7 @@ namespace gsr { mgl_scissor prev_scissor; mgl_window_get_scissor(window.internal_window(), &prev_scissor); - const mgl::vec2f content_size = get_size(); + const mgl::vec2f content_size = get_inner_size(); mgl_scissor new_scissor = { mgl_vec2i{(int)offset.x, (int)offset.y}, mgl_vec2i{(int)content_size.x, (int)content_size.y} @@ -81,6 +81,13 @@ namespace gsr { if(!visible) return {0.0f, 0.0f}; + 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; diff --git a/src/main.cpp b/src/main.cpp index 38b2df4..0649c09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,11 @@ #include "../include/gui/StaticPage.hpp" -#include "../include/gui/ScrollablePage.hpp" #include "../include/gui/DropdownButton.hpp" -#include "../include/gui/Button.hpp" -#include "../include/gui/RadioButton.hpp" -#include "../include/gui/Entry.hpp" -#include "../include/gui/CheckBox.hpp" -#include "../include/gui/ComboBox.hpp" -#include "../include/gui/Label.hpp" -#include "../include/gui/List.hpp" #include "../include/Process.hpp" #include "../include/Theme.hpp" #include "../include/GsrInfo.hpp" #include "../include/window_texture.h" +#include "../include/SettingsPage.hpp" #include <stdio.h> #include <stdlib.h> @@ -231,246 +224,6 @@ static const mgl_monitor* find_monitor_by_cursor_position(mgl::Window &window) { return &win->monitors[0]; } -/* -{ - { - gsr::List::Orientation::VERTICAL, - "Record area:", - { - {"Window, "window"}, - {"Focused window", "focused"}, - }, - }, - { - gsr::List::Orientation::VERTICAL, - "Video quality:", - { - {"Medium, "medium"}, - {"High", "high"}, - {"Very high", "very_high"}, - }, - } -} -*/ - -static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f settings_page_position, mgl::vec2f settings_page_size, gsr::Page *settings_page, gsr::Page *settings_content_page, const gsr::GsrInfo &gsr_info, const std::vector<gsr::AudioDevice> &audio_devices, std::function<void()> settings_back_button_callback) { - auto back_button = std::make_unique<gsr::Button>(&gsr::get_theme().title_font, "Back", mgl::vec2f(window_size.x / 10, window_size.y / 15), gsr::get_theme().scrollable_page_bg_color); - back_button->set_position(settings_page_position + mgl::vec2f(settings_page_size.x + window_size.x / 50, 0.0f).floor()); - back_button->set_border_scale(0.003f); - back_button->on_click = settings_back_button_callback; - settings_page->add_widget(std::move(back_button)); - - auto settings_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - auto view_radio_button = std::make_unique<gsr::RadioButton>(&gsr::get_theme().body_font); - view_radio_button->add_item("Simple view", "simple"); - view_radio_button->add_item("Advanced view", "advanced"); - view_radio_button->set_horizontal_alignment(gsr::Widget::Alignment::CENTER); - gsr::RadioButton *view_radio_button_ptr = view_radio_button.get(); - settings_list->add_widget(std::move(view_radio_button)); - - gsr::Widget *color_range_list_ptr = nullptr; - gsr::Widget *codec_list_ptr = nullptr; - gsr::Widget *framerate_mode_list_ptr = nullptr; - - auto record_area_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - record_area_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Record area:", gsr::get_theme().text_color)); - auto record_area_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - // TODO: Show options not supported but disable them - if(gsr_info.supported_capture_options.window) - record_area_box->add_item("Window", "window"); - if(gsr_info.supported_capture_options.focused) - record_area_box->add_item("Focused window", "focused"); - if(gsr_info.supported_capture_options.screen) - record_area_box->add_item("All monitors", "screen"); - for(const auto &monitor : gsr_info.supported_capture_options.monitors) { - char name[256]; - snprintf(name, sizeof(name), "Monitor %s (%dx%d)", monitor.name.c_str(), monitor.size.x, monitor.size.y); - record_area_box->add_item(name, monitor.name); - } - if(gsr_info.supported_capture_options.portal) - record_area_box->add_item("Desktop portal", "portal"); - - if(!gsr_info.supported_capture_options.monitors.empty()) - record_area_box->set_selected_item(gsr_info.supported_capture_options.monitors.front().name); - else if(gsr_info.supported_capture_options.portal) - record_area_box->set_selected_item("portal"); - - record_area_list->add_widget(std::move(record_area_box)); - } - settings_list->add_widget(std::move(record_area_list)); - - auto audio_device_section_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - audio_device_section_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Audio:", gsr::get_theme().text_color)); - auto audio_devices_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - gsr::List *audio_devices_list_ptr = audio_devices_list.get(); - - auto add_audio_track_button = std::make_unique<gsr::Button>(&gsr::get_theme().body_font, "Add audio track", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - auto add_audio_track = [&audio_devices, audio_devices_list_ptr]() { - auto audio_device_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL, gsr::List::Alignment::CENTER); - gsr::List *audio_device_list_ptr = audio_device_list.get(); - { - audio_device_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, " ", gsr::get_theme().text_color)); - auto audio_device_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - for(const auto &audio_device : audio_devices) { - audio_device_box->add_item(audio_device.description, audio_device.name); - } - audio_device_list->add_widget(std::move(audio_device_box)); - auto remove_audio_track_button = std::make_unique<gsr::Button>(&gsr::get_theme().body_font, "Remove", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - remove_audio_track_button->on_click = [=]() { - audio_devices_list_ptr->remove_widget(audio_device_list_ptr); - }; - audio_device_list->add_widget(std::move(remove_audio_track_button)); - } - audio_devices_list_ptr->add_widget(std::move(audio_device_list)); - }; - add_audio_track_button->on_click = add_audio_track; - audio_device_section_list->add_widget(std::move(add_audio_track_button)); - - for(int i = 0; i < 3; ++i) { - add_audio_track(); - } - audio_device_section_list->add_widget(std::move(audio_devices_list)); - } - settings_list->add_widget(std::move(audio_device_section_list)); - - auto quality_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL); - { - auto video_quality_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - video_quality_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Video quality:", gsr::get_theme().text_color)); - auto video_quality_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - video_quality_box->add_item("Medium", "medium"); - video_quality_box->add_item("High (Recommended for live streaming)", "high"); - video_quality_box->add_item("Very high (Recommended)", "very_high"); - video_quality_box->add_item("Ultra", "ultra"); - video_quality_box->set_selected_item("very_high"); - video_quality_list->add_widget(std::move(video_quality_box)); - } - quality_list->add_widget(std::move(video_quality_list)); - - auto color_range_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - color_range_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Color range:", gsr::get_theme().text_color)); - auto color_range_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - color_range_box->add_item("Limited", "limited"); - color_range_box->add_item("Full", "full"); - color_range_list->add_widget(std::move(color_range_box)); - } - color_range_list_ptr = color_range_list.get(); - quality_list->add_widget(std::move(color_range_list)); - } - settings_list->add_widget(std::move(quality_list)); - - auto codec_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL); - { - auto video_codec_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - video_codec_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Video codec:", gsr::get_theme().text_color)); - auto video_codec_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - // TODO: Show options not supported but disable them - video_codec_box->add_item("Auto (Recommended)", "auto"); - if(gsr_info.supported_video_codecs.h264) - video_codec_box->add_item("H264", "h264"); - if(gsr_info.supported_video_codecs.hevc) - video_codec_box->add_item("HEVC", "hevc"); - if(gsr_info.supported_video_codecs.av1) - video_codec_box->add_item("AV1", "av1"); - if(gsr_info.supported_video_codecs.vp8) - video_codec_box->add_item("VP8", "vp8"); - if(gsr_info.supported_video_codecs.vp9) - video_codec_box->add_item("VP9", "vp9"); - // TODO: Add hdr options - if(gsr_info.supported_video_codecs.h264_software) - video_codec_box->add_item("H264 Software Encoder (Slow, not recommended)", "h264_software"); - video_codec_list->add_widget(std::move(video_codec_box)); - } - codec_list->add_widget(std::move(video_codec_list)); - - auto audio_codec_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - audio_codec_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Audio codec:", gsr::get_theme().text_color)); - auto audio_codec_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - audio_codec_box->add_item("Opus (Recommended)", "opus"); - audio_codec_box->add_item("AAC", "aac"); - audio_codec_list->add_widget(std::move(audio_codec_box)); - } - codec_list->add_widget(std::move(audio_codec_list)); - } - codec_list_ptr = codec_list.get(); - settings_list->add_widget(std::move(codec_list)); - - auto framerate_info_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL); - { - auto framerate_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - framerate_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Frame rate:", gsr::get_theme().text_color)); - auto framerate_entry = std::make_unique<gsr::Entry>(&gsr::get_theme().body_font, "60", gsr::get_theme().body_font.get_character_size() * 3); - framerate_entry->validate_handler = gsr::create_entry_validator_integer_in_range(1, 500); - framerate_list->add_widget(std::move(framerate_entry)); - } - framerate_info_list->add_widget(std::move(framerate_list)); - - auto framerate_mode_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - framerate_mode_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Frame rate mode:", gsr::get_theme().text_color)); - auto framerate_mode_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - framerate_mode_box->add_item("Auto (Recommended)", "auto"); - framerate_mode_box->add_item("Constant", "cfr"); - framerate_mode_box->add_item("Variable", "vfr"); - framerate_mode_list->add_widget(std::move(framerate_mode_box)); - } - framerate_mode_list_ptr = framerate_mode_list.get(); - framerate_info_list->add_widget(std::move(framerate_mode_list)); - } - settings_list->add_widget(std::move(framerate_info_list)); - - auto file_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL); - { - auto save_directory_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - save_directory_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Directory to save the video:", gsr::get_theme().text_color)); - // TODO: - save_directory_list->add_widget(std::make_unique<gsr::Entry>(&gsr::get_theme().body_font, "/home/dec05eba/Videos", gsr::get_theme().body_font.get_character_size() * 20)); - } - file_list->add_widget(std::move(save_directory_list)); - - auto container_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL); - { - container_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Container:", gsr::get_theme().text_color)); - auto container_box = std::make_unique<gsr::ComboBox>(&gsr::get_theme().body_font); - container_box->add_item("mp4", "mp4"); - container_box->add_item("mkv", "matroska"); - container_box->add_item("flv", "flv"); - container_box->add_item("mov", "mov"); - container_box->add_item("ts", "mpegts"); - container_box->add_item("m3u8", "hls"); - container_list->add_widget(std::move(container_box)); - } - file_list->add_widget(std::move(container_list)); - } - settings_list->add_widget(std::move(file_list)); - - settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Record cursor")); - settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show recording started notification")); - //settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show recording stopped notification")); - settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show video saved notification")); - - view_radio_button_ptr->on_selection_changed = [=](const std::string &text, const std::string &id) { - (void)text; - const bool advanced_view = id == "advanced"; - color_range_list_ptr->set_visible(advanced_view); - codec_list_ptr->set_visible(advanced_view); - framerate_mode_list_ptr->set_visible(advanced_view); - }; - - view_radio_button_ptr->on_selection_changed("Simple", "simple"); - } - settings_content_page->add_widget(std::move(settings_list)); -} - int main(int argc, char **argv) { if(argc != 1) usage(); @@ -621,37 +374,17 @@ int main(int argc, char **argv) { gsr::StaticPage front_page(window_size.to_vec2f()); - const mgl::vec2f settings_page_size(window_size.x * 0.3333f, window_size.y * 0.7f); - const mgl::vec2f settings_page_position = (window_size.to_vec2f() * 0.5f - settings_page_size * 0.5f).floor(); - const float settings_body_margin = 0.02f; - - auto replay_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size); - gsr::ScrollablePage *replay_settings_content_ptr = replay_settings_content.get(); - replay_settings_content->set_position(settings_page_position); - replay_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin); - - auto record_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size); - gsr::ScrollablePage *record_settings_content_ptr = record_settings_content.get(); - record_settings_content->set_position(settings_page_position); - record_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin); - - auto stream_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size); - gsr::ScrollablePage *stream_settings_content_ptr = stream_settings_content.get(); - stream_settings_content->set_position(settings_page_position); - stream_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin); - - gsr::StaticPage replay_settings_page(window_size.to_vec2f()); - replay_settings_page.add_widget(std::move(replay_settings_content)); - - gsr::StaticPage record_settings_page(window_size.to_vec2f()); - record_settings_page.add_widget(std::move(record_settings_content)); - - gsr::StaticPage stream_settings_page(window_size.to_vec2f()); - stream_settings_page.add_widget(std::move(stream_settings_content)); - std::stack<gsr::Page*> page_stack; page_stack.push(&front_page); + const auto settings_back_button_callback = [&] { + page_stack.pop(); + }; + + gsr::SettingsPage replay_settings_page(gsr::SettingsPage::Type::REPLAY, gsr_info, audio_devices, settings_back_button_callback); + gsr::SettingsPage record_settings_page(gsr::SettingsPage::Type::RECORD, gsr_info, audio_devices, settings_back_button_callback); + gsr::SettingsPage stream_settings_page(gsr::SettingsPage::Type::STREAM, gsr_info, audio_devices, settings_back_button_callback); + struct MainButton { gsr::DropdownButton* button; gsr::GsrMode mode; @@ -737,7 +470,7 @@ 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); + page_stack.push(&replay_settings_page.get_page()); return; } /* @@ -762,7 +495,7 @@ 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); + page_stack.push(&record_settings_page.get_page()); return; } @@ -847,7 +580,7 @@ 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); + page_stack.push(&stream_settings_page.get_page()); return; } }; @@ -883,30 +616,6 @@ int main(int argc, char **argv) { //top_bar_text.set_color(gsr::get_theme().tint_color); top_bar_text.set_position((top_bar_background.get_position() + top_bar_background.get_size()*0.5f - top_bar_text.get_bounds().size*0.5f).floor()); - const int num_settings_pages = 3; - - gsr::Page *settings_pages[num_settings_pages] = { - &replay_settings_page, - &record_settings_page, - &stream_settings_page - }; - - gsr::Page *settings_content_pages[num_settings_pages] = { - replay_settings_content_ptr, - record_settings_content_ptr, - stream_settings_content_ptr - }; - - const auto settings_back_button_callback = [&] { - page_stack.pop(); - }; - - for(int i = 0; i < num_settings_pages; ++i) { - gsr::Page *settings_page = settings_pages[i]; - gsr::Page *settings_content_page = settings_content_pages[i]; - add_widgets_to_settings_page(window_size, settings_page_position, settings_page_size, settings_page, settings_content_page, gsr_info, audio_devices, settings_back_button_callback); - } - mgl::Texture close_texture; if(!close_texture.load_from_file((resources_path + "images/cross.png").c_str())) startup_error("failed to load texture: images/cross.png"); |