diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Config.cpp | 55 | ||||
-rw-r--r-- | src/SettingsPage.cpp | 464 | ||||
-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 | ||||
-rw-r--r-- | src/main.cpp | 35 |
8 files changed, 748 insertions, 521 deletions
diff --git a/src/Config.cpp b/src/Config.cpp index e7b99de..b4825a3 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,4 +1,5 @@ #include "../include/Config.hpp" +#include "../include/Utils.hpp" #include <variant> #include <limits.h> #include <inttypes.h> @@ -13,7 +14,7 @@ namespace gsr { using ConfigValue = std::variant<bool*, std::string*, int32_t*, ConfigHotkey*, std::vector<std::string>*>; - static std::unordered_map<std::string_view, ConfigValue> get_config_options(Config &config) { + static std::map<std::string_view, ConfigValue> get_config_options(Config &config) { return { {"main.config_file_version", &config.main_config.config_file_version}, {"main.software_encoding_warning_shown", &config.main_config.software_encoding_warning_shown}, @@ -23,20 +24,18 @@ namespace gsr { {"streaming.record_options.record_area_height", &config.streaming_config.record_options.record_area_height}, {"streaming.record_options.fps", &config.streaming_config.record_options.fps}, {"streaming.record_options.merge_audio_tracks", &config.streaming_config.record_options.merge_audio_tracks}, - {"streaming.record_options.audio_input", &config.streaming_config.record_options.audio_input}, + {"streaming.record_options.audio_track", &config.streaming_config.record_options.audio_tracks}, {"streaming.record_options.color_range", &config.streaming_config.record_options.color_range}, - {"streaming.record_options.quality", &config.streaming_config.record_options.quality}, + {"streaming.record_options.video_quality", &config.streaming_config.record_options.video_quality}, {"streaming.record_options.codec", &config.streaming_config.record_options.video_codec}, {"streaming.record_options.audio_codec", &config.streaming_config.record_options.audio_codec}, {"streaming.record_options.framerate_mode", &config.streaming_config.record_options.framerate_mode}, {"streaming.record_options.advanced_view", &config.streaming_config.record_options.advanced_view}, {"streaming.record_options.overclock", &config.streaming_config.record_options.overclock}, - {"streaming.record_options.show_recording_started_notifications", &config.streaming_config.record_options.show_recording_started_notifications}, - {"streaming.record_options.show_recording_stopped_notifications", &config.streaming_config.record_options.show_recording_stopped_notifications}, - {"streaming.record_options.show_recording_saved_notifications", &config.streaming_config.record_options.show_recording_saved_notifications}, {"streaming.record_options.record_cursor", &config.streaming_config.record_options.record_cursor}, - {"streaming.record_options.hide_window_when_recording", &config.streaming_config.record_options.hide_window_when_recording}, {"streaming.record_options.restore_portal_session", &config.streaming_config.record_options.restore_portal_session}, + {"streaming.show_streaming_started_notifications", &config.streaming_config.show_streaming_started_notifications}, + {"streaming.show_streaming_stopped_notifications", &config.streaming_config.show_streaming_stopped_notifications}, {"streaming.service", &config.streaming_config.streaming_service}, {"streaming.youtube.key", &config.streaming_config.youtube.stream_key}, {"streaming.twitch.key", &config.streaming_config.twitch.stream_key}, @@ -49,20 +48,18 @@ namespace gsr { {"record.record_options.record_area_height", &config.record_config.record_options.record_area_height}, {"record.record_options.fps", &config.record_config.record_options.fps}, {"record.record_options.merge_audio_tracks", &config.record_config.record_options.merge_audio_tracks}, - {"record.record_options.audio_input", &config.record_config.record_options.audio_input}, + {"record.record_options.audio_track", &config.record_config.record_options.audio_tracks}, {"record.record_options.color_range", &config.record_config.record_options.color_range}, - {"record.record_options.quality", &config.record_config.record_options.quality}, + {"record.record_options.video_quality", &config.record_config.record_options.video_quality}, {"record.record_options.codec", &config.record_config.record_options.video_codec}, {"record.record_options.audio_codec", &config.record_config.record_options.audio_codec}, {"record.record_options.framerate_mode", &config.record_config.record_options.framerate_mode}, {"record.record_options.advanced_view", &config.record_config.record_options.advanced_view}, {"record.record_options.overclock", &config.record_config.record_options.overclock}, - {"record.record_options.show_recording_started_notifications", &config.record_config.record_options.show_recording_started_notifications}, - {"record.record_options.show_recording_stopped_notifications", &config.record_config.record_options.show_recording_stopped_notifications}, - {"record.record_options.show_recording_saved_notifications", &config.record_config.record_options.show_recording_saved_notifications}, {"record.record_options.record_cursor", &config.record_config.record_options.record_cursor}, - {"record.record_options.hide_window_when_recording", &config.record_config.record_options.hide_window_when_recording}, {"record.record_options.restore_portal_session", &config.record_config.record_options.restore_portal_session}, + {"record.show_recording_started_notifications", &config.record_config.show_recording_started_notifications}, + {"record.show_video_saved_notifications", &config.record_config.show_video_saved_notifications}, {"record.save_directory", &config.record_config.save_directory}, {"record.container", &config.record_config.container}, {"record.start_stop_recording_hotkey", &config.record_config.start_stop_recording_hotkey}, @@ -73,20 +70,19 @@ namespace gsr { {"replay.record_options.record_area_height", &config.replay_config.record_options.record_area_height}, {"replay.record_options.fps", &config.replay_config.record_options.fps}, {"replay.record_options.merge_audio_tracks", &config.replay_config.record_options.merge_audio_tracks}, - {"replay.record_options.audio_input", &config.replay_config.record_options.audio_input}, + {"replay.record_options.audio_track", &config.replay_config.record_options.audio_tracks}, {"replay.record_options.color_range", &config.replay_config.record_options.color_range}, - {"replay.record_options.quality", &config.replay_config.record_options.quality}, + {"replay.record_options.video_quality", &config.replay_config.record_options.video_quality}, {"replay.record_options.codec", &config.replay_config.record_options.video_codec}, {"replay.record_options.audio_codec", &config.replay_config.record_options.audio_codec}, {"replay.record_options.framerate_mode", &config.replay_config.record_options.framerate_mode}, {"replay.record_options.advanced_view", &config.replay_config.record_options.advanced_view}, {"replay.record_options.overclock", &config.replay_config.record_options.overclock}, - {"replay.record_options.show_recording_started_notifications", &config.replay_config.record_options.show_recording_started_notifications}, - {"replay.record_options.show_recording_stopped_notifications", &config.replay_config.record_options.show_recording_stopped_notifications}, - {"replay.record_options.show_recording_saved_notifications", &config.replay_config.record_options.show_recording_saved_notifications}, {"replay.record_options.record_cursor", &config.replay_config.record_options.record_cursor}, - {"replay.record_options.hide_window_when_recording", &config.replay_config.record_options.hide_window_when_recording}, {"replay.record_options.restore_portal_session", &config.replay_config.record_options.restore_portal_session}, + {"replay.show_replay_started_notifications", &config.replay_config.show_replay_started_notifications}, + {"replay.show_replay_stopped_notifications", &config.replay_config.show_replay_stopped_notifications}, + {"replay.show_replay_saved_notifications", &config.replay_config.show_replay_saved_notifications}, {"replay.save_directory", &config.replay_config.save_directory}, {"replay.container", &config.replay_config.container}, {"replay.time", &config.replay_config.replay_time}, @@ -95,18 +91,18 @@ namespace gsr { }; } - Config read_config(bool &config_empty) { - Config config; + std::optional<Config> read_config() { + std::optional<Config> config; - const std::string config_path = get_config_dir() + "/config"; + const std::string config_path = get_config_dir() + "/overlay_config"; std::string file_content; if(!file_get_content(config_path.c_str(), file_content)) { fprintf(stderr, "Warning: Failed to read config file: %s\n", config_path.c_str()); - config_empty = true; return config; } - auto config_options = get_config_options(config); + config = Config(); + auto config_options = get_config_options(config.value()); string_split_char(file_content, '\n', [&](std::string_view line) { const std::optional<KeyValue> key_value = parse_key_value(line); @@ -141,7 +137,7 @@ namespace gsr { config_hotkey->keysym = 0; config_hotkey->modifiers = 0; } - } else if(std::holds_alternative<ConfigHotkey*>(it->second)) { + } else if(std::holds_alternative<std::vector<std::string>*>(it->second)) { std::string array_value(key_value->value); std::get<std::vector<std::string>*>(it->second)->push_back(std::move(array_value)); } @@ -149,10 +145,9 @@ namespace gsr { return true; }); - if(config.main_config.config_file_version != CONFIG_FILE_VERSION) { + if(config->main_config.config_file_version != CONFIG_FILE_VERSION) { fprintf(stderr, "Info: the config file is outdated, resetting it\n"); - config_empty = true; - config = Config(); + config = std::nullopt; } return config; @@ -161,7 +156,7 @@ namespace gsr { void save_config(Config &config) { config.main_config.config_file_version = CONFIG_FILE_VERSION; - const std::string config_path = get_config_dir() + "/config"; + const std::string config_path = get_config_dir() + "/overlay_config"; char dir_tmp[PATH_MAX]; snprintf(dir_tmp, sizeof(dir_tmp), "%s", config_path.c_str()); @@ -189,7 +184,7 @@ namespace gsr { } else if(std::holds_alternative<ConfigHotkey*>(it.second)) { const ConfigHotkey *config_hotkey = std::get<ConfigHotkey*>(it.second); fprintf(file, "%.*s " FORMAT_I64 " " FORMAT_U32 "\n", (int)it.first.size(), it.first.data(), config_hotkey->keysym, config_hotkey->modifiers); - } else if(std::holds_alternative<ConfigHotkey*>(it.second)) { + } else if(std::holds_alternative<std::vector<std::string>*>(it.second)) { std::vector<std::string> *array = std::get<std::vector<std::string>*>(it.second); for(const std::string &value : *array) { fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), value.c_str()); diff --git a/src/SettingsPage.cpp b/src/SettingsPage.cpp deleted file mode 100644 index e4c41c8..0000000 --- a/src/SettingsPage.cpp +++ /dev/null @@ -1,464 +0,0 @@ -#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/gui/CustomRendererWidget.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::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_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; - mgl::Text title("Settings", get_theme().title_font); - title.set_position((pos + mgl::vec2f(size.x * 0.5f - title.get_bounds().size.x * 0.5f, text_margin)).floor()); - window.draw(title); - - 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); - }; - page.add_widget(std::move(settings_icon_widget)); - - 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)); - - auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); - record_cursor_checkbox->set_checked(true); - 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); - { - 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)); - - auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); - record_cursor_checkbox->set_checked(true); - 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)); - } - - 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)); - - auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record cursor"); - record_cursor_checkbox->set_checked(true); - 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"); - } -}
\ No newline at end of file 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 diff --git a/src/main.cpp b/src/main.cpp index 196f7e1..be872d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,12 +2,13 @@ #include "../include/gui/StaticPage.hpp" #include "../include/gui/DropdownButton.hpp" #include "../include/gui/CustomRendererWidget.hpp" +#include "../include/gui/SettingsPage.hpp" #include "../include/gui/Utils.hpp" #include "../include/Process.hpp" #include "../include/Theme.hpp" #include "../include/GsrInfo.hpp" #include "../include/window_texture.h" -#include "../include/SettingsPage.hpp" +#include "../include/Config.hpp" #include <stdio.h> #include <stdlib.h> @@ -227,6 +228,7 @@ static const mgl_monitor* find_monitor_by_cursor_position(mgl::Window &window) { } int main(int argc, char **argv) { + (void)argv; if(argc != 1) usage(); @@ -380,12 +382,26 @@ int main(int argc, char **argv) { page_stack.push(&front_page); const auto settings_back_button_callback = [&] { + page_stack.top()->on_navigate_away_from_page(); 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); + 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; @@ -472,7 +488,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.get_page()); + page_stack.push(&replay_settings_page); return; } /* @@ -497,7 +513,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.get_page()); + page_stack.push(&record_settings_page); return; } @@ -582,7 +598,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.get_page()); + page_stack.push(&stream_settings_page); return; } }; @@ -597,6 +613,7 @@ int main(int argc, char **argv) { // TODO: Retry if these fail. // TODO: Hmm, these dont work in owlboy. Maybe owlboy uses xi2 and that breaks this (does it?). + // Remove these grabs when debugging with a debugger, or your X11 session will appear frozen XGrabPointer(display, window.get_system_handle(), True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask | @@ -695,8 +712,10 @@ int main(int argc, char **argv) { page_stack.top()->on_event(event, window, mgl::vec2f(0.0f, 0.0f)); close_button_widget.on_event(event, window, mgl::vec2f(0.0f, 0.0f)); if(event.type == mgl::Event::KeyReleased) { - if(event.key.code == mgl::Keyboard::Escape && !page_stack.empty()) + if(event.key.code == mgl::Keyboard::Escape && !page_stack.empty()) { + page_stack.top()->on_navigate_away_from_page(); page_stack.pop(); + } } if(page_stack.empty()) |