diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-08-10 00:45:36 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-08-10 00:45:36 +0200 |
commit | 4ea5ada9050d22fcb7eed67a72358bce11c9b3df (patch) | |
tree | ad5f1e5956d972ad7c6948d4ba2f753d47a4b315 /src/gui | |
parent | 1a49f86e9841035fe670f6b42a3c988f737267d2 (diff) |
Settings page save settings, refactor
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/ComboBox.cpp | 9 | ||||
-rw-r--r-- | src/gui/Entry.cpp | 12 | ||||
-rw-r--r-- | src/gui/List.cpp | 57 | ||||
-rw-r--r-- | src/gui/RadioButton.cpp | 9 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 628 |
5 files changed, 696 insertions, 19 deletions
diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp index 373b06b..f23a323 100644 --- a/src/gui/ComboBox.cpp +++ b/src/gui/ComboBox.cpp @@ -161,6 +161,15 @@ namespace gsr { } } + const std::string& ComboBox::get_selected_id() const { + if(items.empty()) { + static std::string dummy; + return dummy; + } else { + return items[selected_item].id; + } + } + void ComboBox::update_if_dirty() { if(!dirty) return; diff --git a/src/gui/Entry.cpp b/src/gui/Entry.cpp index f337bcf..7978b38 100644 --- a/src/gui/Entry.cpp +++ b/src/gui/Entry.cpp @@ -18,7 +18,7 @@ namespace gsr { Entry::Entry(mgl::Font *font, const char *text, float max_width) : text("", *font), max_width(max_width) { this->text.set_color(get_theme().text_color); - set_string(text); + set_text(text); } bool Entry::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) { @@ -32,12 +32,12 @@ namespace gsr { std::string str = text.get_string(); const size_t prev_index = mgl::utf8_get_start_of_codepoint((const unsigned char*)str.c_str(), str.size(), str.size()); str.erase(prev_index, std::string::npos); - set_string(std::move(str)); + set_text(std::move(str)); } } else if(event.type == mgl::Event::TextEntered && selected && event.text.codepoint >= 32) { std::string str = text.get_string(); str.append(event.text.str, event.text.size); - set_string(std::move(str)); + set_text(std::move(str)); } return true; } @@ -80,7 +80,7 @@ namespace gsr { return { max_width, text.get_bounds().size.y + padding_top + padding_bottom }; } - void Entry::set_string(std::string str) { + void Entry::set_text(std::string str) { if(!validate_handler || validate_handler(str)) { text.set_string(std::move(str)); caret_offset_x = text.find_character_pos(99999).x - this->text.get_position().x; @@ -88,6 +88,10 @@ namespace gsr { } } + const std::string& Entry::get_text() const { + return text.get_string(); + } + static bool is_number(uint8_t c) { return c >= '0' && c <= '9'; } diff --git a/src/gui/List.cpp b/src/gui/List.cpp index 039842d..883a797 100644 --- a/src/gui/List.cpp +++ b/src/gui/List.cpp @@ -15,22 +15,28 @@ 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))) + if(!selected_widget->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) { + inside_event_handler = false; return false; + } } // Process widgets by visibility (backwards) for(auto it = widgets.rbegin(), end = widgets.rend(); it != end; ++it) { // 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))) + if(!(*it)->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) { + inside_event_handler = false; return false; + } } } + inside_event_handler = false; return true; } @@ -72,7 +78,8 @@ namespace gsr { const mgl::vec2f spacing = (spacing_scale * get_theme().window_height).floor(); switch(orientation) { case Orientation::VERTICAL: { - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(!widget->visible) continue; @@ -91,25 +98,28 @@ namespace gsr { if(widget.get() != selected_widget) widget->draw(window, mgl::vec2f(0.0f, 0.0f)); draw_pos.y += widget_size.y; - if(widget_size.y > 0.001f) + if(widget_size.y > 0.001f && i + 1 < widgets.size()) draw_pos.y += spacing.y; } break; } case Orientation::HORIZONTAL: { - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(!widget->visible) continue; const auto widget_size = widget->get_size(); if(content_alignment == Alignment::CENTER) offset.y = floor(size.y * 0.5f - widget_size.y * 0.5f); + else + offset.y = 0.0f; widget->set_position(draw_pos + offset); if(widget.get() != selected_widget) widget->draw(window, mgl::vec2f(0.0f, 0.0f)); draw_pos.x += widget_size.x; - if(widget_size.x > 0.001f) + if(widget_size.x > 0.001f && i + 1 < widgets.size()) draw_pos.x += spacing.x; } break; @@ -131,9 +141,10 @@ namespace gsr { void List::add_widget(std::unique_ptr<Widget> widget) { widget->parent_widget = this; - // TODO: Maybe only do this if this is called inside an event handler - //widgets.push_back(std::move(widget)); - add_queue.push_back(std::move(widget)); + if(inside_event_handler) + add_queue.push_back(std::move(widget)); + else + widgets.push_back(std::move(widget)); } void List::remove_widget(Widget *widget) { @@ -143,8 +154,22 @@ namespace gsr { return; } } - // TODO: Maybe only do this if this is called inside an event handler - remove_queue.push_back(widget); + + if(inside_event_handler) + remove_queue.push_back(widget); + else + remove_widget_immediate(widget); + } + + const std::vector<std::unique_ptr<Widget>>& List::get_child_widgets() const { + return widgets; + } + + Widget* List::get_child_widget_by_index(size_t index) const { + if(index < widgets.size()) + return widgets[index].get(); + else + return nullptr; } // TODO: Cache result @@ -156,26 +181,28 @@ namespace gsr { const mgl::vec2f spacing = (spacing_scale * get_theme().window_height).floor(); switch(orientation) { case Orientation::VERTICAL: { - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(!widget->visible) continue; const auto widget_size = widget->get_size(); size.x = std::max(size.x, widget_size.x); size.y += widget_size.y; - if(widget_size.y > 0.001f) + if(widget_size.y > 0.001f && i + 1 < widgets.size()) size.y += spacing.y; } break; } case Orientation::HORIZONTAL: { - for(auto &widget : widgets) { + for(size_t i = 0; i < widgets.size(); ++i) { + auto &widget = widgets[i]; if(!widget->visible) continue; const auto widget_size = widget->get_size(); size.x += widget_size.x; - if(widget_size.x > 0.001f) + if(widget_size.x > 0.001f && i + 1 < widgets.size()) size.x += spacing.x; size.y = std::max(size.y, widget_size.y); } diff --git a/src/gui/RadioButton.cpp b/src/gui/RadioButton.cpp index eb1f900..87428bf 100644 --- a/src/gui/RadioButton.cpp +++ b/src/gui/RadioButton.cpp @@ -135,4 +135,13 @@ namespace gsr { } } } + + const std::string RadioButton::get_selected_id() const { + if(items.empty()) { + static std::string dummy; + return dummy; + } else { + return items[selected_item].id; + } + } }
\ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp new file mode 100644 index 0000000..277bc3b --- /dev/null +++ b/src/gui/SettingsPage.cpp @@ -0,0 +1,628 @@ +#include "../../include/gui/SettingsPage.hpp" +#include "../../include/gui/ScrollablePage.hpp" +#include "../../include/gui/Label.hpp" +#include "../../include/Theme.hpp" +#include "../../include/GsrInfo.hpp" + +#include <mglpp/graphics/Rectangle.hpp> +#include <mglpp/graphics/Sprite.hpp> +#include <mglpp/graphics/Text.hpp> +#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) : + StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), + type(type), + config(config), + 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); + content_page_ptr = content_page.get(); + add_widget(std::move(content_page)); + + add_widgets(gsr_info, audio_devices); + 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"); + 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(); + return view_radio_button; + } + + std::unique_ptr<ComboBox> SettingsPage::create_record_area_box(const GsrInfo &gsr_info) { + 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(); + return record_area_box; + } + + std::unique_ptr<List> SettingsPage::create_record_area(const GsrInfo &gsr_info) { + 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)); + record_area_list->add_widget(create_record_area_box(gsr_info)); + return record_area_list; + } + + std::unique_ptr<List> SettingsPage::create_select_window() { + 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(); + return select_window_list; + } + + std::unique_ptr<Entry> SettingsPage::create_area_width_entry() { + 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_width_entry_ptr = area_width_entry.get(); + return area_width_entry; + } + + std::unique_ptr<Entry> SettingsPage::create_area_height_entry() { + 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_height_entry_ptr = area_height_entry.get(); + return area_height_entry; + } + + std::unique_ptr<List> SettingsPage::create_area_size() { + auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + area_size_params_list->add_widget(create_area_width_entry()); + area_size_params_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "x", get_theme().text_color)); + area_size_params_list->add_widget(create_area_height_entry()); + return area_size_params_list; + } + + std::unique_ptr<List> SettingsPage::create_area_size_section() { + 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)); + area_size_list->add_widget(create_area_size()); + area_size_list_ptr = area_size_list.get(); + return area_size_list; + } + + std::unique_ptr<CheckBox> SettingsPage::create_restore_portal_session_checkbox() { + auto restore_portal_session_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Restore portal session"); + restore_portal_session_checkbox->set_checked(true); + restore_portal_session_checkbox_ptr = restore_portal_session_checkbox.get(); + return restore_portal_session_checkbox; + } + + std::unique_ptr<List> SettingsPage::create_restore_portal_session_section() { + auto restore_portal_session_list = std::make_unique<List>(List::Orientation::VERTICAL); + restore_portal_session_list->add_widget(std::make_unique<Label>(&get_theme().body_font, " ", get_theme().text_color)); + restore_portal_session_list->add_widget(create_restore_portal_session_checkbox()); + restore_portal_session_list_ptr = restore_portal_session_list.get(); + return restore_portal_session_list; + } + + std::unique_ptr<List> SettingsPage::create_capture_target(const GsrInfo &gsr_info) { + // TODO: List::Alignment::Center causes 1 frame glitch when switching record area but only the first time + auto capture_target_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + capture_target_list->add_widget(create_record_area(gsr_info)); + capture_target_list->add_widget(create_select_window()); + capture_target_list->add_widget(create_area_size_section()); + capture_target_list->add_widget(create_restore_portal_session_section()); + return capture_target_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_audio_track_selection_checkbox(const std::vector<AudioDevice> &audio_devices) { + 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); + } + return audio_device_box; + } + + std::unique_ptr<Button> SettingsPage::create_remove_audio_track_button(List *audio_device_list_ptr) { + 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 = [this, audio_device_list_ptr]() { + audio_devices_list_ptr->remove_widget(audio_device_list_ptr); + }; + return remove_audio_track_button; + } + + std::unique_ptr<List> SettingsPage::create_audio_track(const std::vector<AudioDevice> &audio_devices) { + auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, ">", get_theme().text_color)); + audio_device_list->add_widget(create_audio_track_selection_checkbox(audio_devices)); + audio_device_list->add_widget(create_remove_audio_track_button(audio_device_list.get())); + return audio_device_list; + } + + std::unique_ptr<Button> SettingsPage::create_add_audio_track_button(const std::vector<AudioDevice> &audio_devices) { + 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, this]() { + audio_devices_list_ptr->add_widget(create_audio_track(audio_devices)); + }; + add_audio_track_button->on_click = add_audio_track; + return add_audio_track_button; + } + + std::unique_ptr<List> SettingsPage::create_audio_track_section(const std::vector<AudioDevice> &audio_devices) { + auto audio_devices_list = std::make_unique<List>(List::Orientation::VERTICAL); + audio_devices_list_ptr = audio_devices_list.get(); + audio_devices_list_ptr->add_widget(create_audio_track(audio_devices)); + return audio_devices_list; + } + + std::unique_ptr<CheckBox> SettingsPage::create_merge_audio_tracks_checkbox() { + auto merge_audio_tracks_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Merge audio tracks"); + merge_audio_tracks_checkbox->set_checked(true); + merge_audio_tracks_checkbox_ptr = merge_audio_tracks_checkbox.get(); + return merge_audio_tracks_checkbox; + } + + std::unique_ptr<List> SettingsPage::create_audio_device_section(const std::vector<AudioDevice> &audio_devices) { + 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)); + audio_device_section_list->add_widget(create_add_audio_track_button(audio_devices)); + audio_device_section_list->add_widget(create_audio_track_section(audio_devices)); + audio_device_section_list->add_widget(create_merge_audio_tracks_checkbox()); + return audio_device_section_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_video_quality_box() { + 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_box_ptr = video_quality_box.get(); + return video_quality_box; + } + + std::unique_ptr<List> SettingsPage::create_video_quality() { + 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)); + video_quality_list->add_widget(create_video_quality_box()); + return video_quality_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_color_range_box() { + 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_box_ptr = color_range_box.get(); + return color_range_box; + } + + std::unique_ptr<List> SettingsPage::create_color_range() { + 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)); + color_range_list->add_widget(create_color_range_box()); + color_range_list_ptr = color_range_list.get(); + return color_range_list; + } + + std::unique_ptr<List> SettingsPage::create_video_quality_section() { + auto quality_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + quality_list->add_widget(create_video_quality()); + quality_list->add_widget(create_color_range()); + return quality_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box(const GsrInfo &gsr_info) { + 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_box_ptr = video_codec_box.get(); + return video_codec_box; + } + + std::unique_ptr<List> SettingsPage::create_video_codec(const GsrInfo &gsr_info) { + 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)); + video_codec_list->add_widget(create_video_codec_box(gsr_info)); + return video_codec_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_audio_codec_box() { + 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_box_ptr = audio_codec_box.get(); + return audio_codec_box; + } + + std::unique_ptr<List> SettingsPage::create_audio_codec() { + 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)); + audio_codec_list->add_widget(create_audio_codec_box()); + return audio_codec_list; + } + + std::unique_ptr<List> SettingsPage::create_codec_section(const GsrInfo &gsr_info) { + auto codec_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + codec_list->add_widget(create_video_codec(gsr_info)); + codec_list->add_widget(create_audio_codec()); + codec_list_ptr = codec_list.get(); + return codec_list; + } + + std::unique_ptr<Entry> SettingsPage::create_framerate_entry() { + 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_entry_ptr = framerate_entry.get(); + return framerate_entry; + } + + std::unique_ptr<List> SettingsPage::create_framerate() { + 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)); + framerate_list->add_widget(create_framerate_entry()); + return framerate_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_framerate_mode_box() { + 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_box_ptr = framerate_mode_box.get(); + return framerate_mode_box; + } + + std::unique_ptr<List> SettingsPage::create_framerate_mode() { + 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)); + framerate_mode_list->add_widget(create_framerate_mode_box()); + framerate_mode_list_ptr = framerate_mode_list.get(); + return framerate_mode_list; + } + + std::unique_ptr<List> SettingsPage::create_framerate_section() { + auto framerate_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + framerate_info_list->add_widget(create_framerate()); + framerate_info_list->add_widget(create_framerate_mode()); + return framerate_info_list; + } + + std::unique_ptr<List> SettingsPage::create_settings(const GsrInfo &gsr_info, const std::vector<AudioDevice> &audio_devices) { + auto settings_list = std::make_unique<List>(List::Orientation::VERTICAL); + settings_list->add_widget(create_view_radio_button()); + settings_list->add_widget(create_capture_target(gsr_info)); + settings_list->add_widget(create_audio_device_section(audio_devices)); + settings_list->add_widget(create_video_quality_section()); + settings_list->add_widget(create_codec_section(gsr_info)); + settings_list->add_widget(create_framerate_section()); + settings_list_ptr = settings_list.get(); + return settings_list; + } + + 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 = [=](const std::string &text, const std::string &id) { + (void)text; + const bool window_selected = id == "window"; + const bool focused_selected = id == "focused"; + const bool portal_selected = id == "portal"; + select_window_list_ptr->set_visible(window_selected); + area_size_list_ptr->set_visible(focused_selected); + restore_portal_session_list_ptr->set_visible(portal_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; + } + } + + 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)); + save_directory_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "/home/dec05eba/Videos", get_theme().body_font.get_character_size() * 20)); + return save_directory_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_container_box() { + 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_ptr = container_box.get(); + return container_box; + } + + std::unique_ptr<List> SettingsPage::create_container_section() { + 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)); + container_list->add_widget(create_container_box()); + return container_list; + } + + void SettingsPage::add_replay_widgets() { + auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + file_list->add_widget(create_save_directory("Directory to save replays:")); + file_list->add_widget(create_container_section()); + settings_list_ptr->add_widget(std::move(file_list)); + + auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); + record_cursor_checkbox->set_checked(true); + record_cursor_checkbox_ptr = record_cursor_checkbox.get(); + settings_list_ptr->add_widget(std::move(record_cursor_checkbox)); + + auto show_replay_started_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show replay started notification"); + show_replay_started_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_replay_started_notification_checkbox)); + + auto show_replay_stopped_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show replay stopped notification"); + show_replay_stopped_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_replay_stopped_notification_checkbox)); + + auto show_replay_saved_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show replay saved notification"); + show_replay_saved_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_replay_saved_notification_checkbox)); + } + + void SettingsPage::add_record_widgets() { + auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + file_list->add_widget(create_save_directory("Directory to save the video:")); + file_list->add_widget(create_container_section()); + settings_list_ptr->add_widget(std::move(file_list)); + + auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); + record_cursor_checkbox->set_checked(true); + record_cursor_checkbox_ptr = record_cursor_checkbox.get(); + settings_list_ptr->add_widget(std::move(record_cursor_checkbox)); + + auto show_recording_started_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show recording started notification"); + show_recording_started_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_recording_started_notification_checkbox)); + + auto show_video_saved_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show video saved notification"); + show_video_saved_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_video_saved_notification_checkbox)); + } + + std::unique_ptr<ComboBox> SettingsPage::create_streaming_service_box() { + 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(); + return streaming_service_box; + } + + std::unique_ptr<List> SettingsPage::create_streaming_service_section() { + 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)); + streaming_service_list->add_widget(create_streaming_service_box()); + return streaming_service_list; + } + + std::unique_ptr<List> SettingsPage::create_stream_key_section() { + 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(); + return stream_key_list; + } + + std::unique_ptr<List> SettingsPage::create_stream_url_section() { + 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(); + return stream_url_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_stream_container_box() { + 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_box_ptr = container_box.get(); + return container_box; + } + + std::unique_ptr<List> SettingsPage::create_stream_container_section() { + 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)); + container_list->add_widget(create_stream_container_box()); + container_list_ptr = container_list.get(); + return container_list; + } + + void SettingsPage::add_stream_widgets() { + auto streaming_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + streaming_info_list->add_widget(create_streaming_service_section()); + streaming_info_list->add_widget(create_stream_key_section()); + streaming_info_list->add_widget(create_stream_url_section()); + streaming_info_list->add_widget(create_stream_container_section()); + settings_list_ptr->add_widget(std::move(streaming_info_list)); + + auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); + record_cursor_checkbox->set_checked(true); + record_cursor_checkbox_ptr = record_cursor_checkbox.get(); + settings_list_ptr->add_widget(std::move(record_cursor_checkbox)); + + auto show_streaming_started_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show streaming started notification"); + show_streaming_started_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_streaming_started_notification_checkbox)); + + auto show_streaming_stopped_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show streaming stopped notification"); + show_streaming_stopped_notification_checkbox->set_checked(true); + settings_list_ptr->add_widget(std::move(show_streaming_stopped_notification_checkbox)); + + 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"); + } + + void SettingsPage::on_navigate_away_from_page() { + save(); + } + + void SettingsPage::save() { + if(!config) + config = Config(); + + switch(type) { + case Type::REPLAY: + save_replay(); + break; + case Type::RECORD: + save_record(); + break; + case Type::STREAM: + save_stream(); + break; + } + save_config(config.value()); + } + + 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) { + 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(1)); + audio_tracks.push_back(audio_device_box->get_selected_id()); + } + } + + void SettingsPage::save_common(RecordOptions &record_options) { + record_options.record_area_option = record_area_box_ptr->get_selected_id(); + record_options.record_area_width = atoi(area_width_entry_ptr->get_text().c_str()); + record_options.record_area_height = atoi(area_height_entry_ptr->get_text().c_str()); + record_options.fps = atoi(framerate_entry_ptr->get_text().c_str()); + record_options.merge_audio_tracks = merge_audio_tracks_checkbox_ptr->is_checked(); + save_audio_tracks(record_options.audio_tracks, audio_devices_list_ptr); + record_options.color_range = color_range_box_ptr->get_selected_id(); + record_options.video_quality = video_quality_box_ptr->get_selected_id(); + record_options.video_codec = video_codec_box_ptr->get_selected_id(); + record_options.audio_codec = audio_codec_box_ptr->get_selected_id(); + record_options.framerate_mode = framerate_mode_box_ptr->get_selected_id(); + record_options.advanced_view = view_radio_button_ptr->get_selected_id() == "advanced"; + // TODO: + //record_options.overclock = false; + record_options.record_cursor = record_cursor_checkbox_ptr->is_checked(); + record_options.restore_portal_session = restore_portal_session_checkbox_ptr->is_checked(); + } + + void SettingsPage::save_replay() { + save_common(config->replay_config.record_options); + config->replay_config.container = container_box_ptr->get_selected_id(); + // TODO: More options + } + + void SettingsPage::save_record() { + save_common(config->record_config.record_options); + config->record_config.container = container_box_ptr->get_selected_id(); + // TODO: More options + } + + void SettingsPage::save_stream() { + save_common(config->streaming_config.record_options); + config->streaming_config.custom.container = container_box_ptr->get_selected_id(); + // TODO: More options + } +}
\ No newline at end of file |