diff options
Diffstat (limited to 'src/gui/SettingsPage.cpp')
-rw-r--r-- | src/gui/SettingsPage.cpp | 461 |
1 files changed, 292 insertions, 169 deletions
diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index 663e941..363b48c 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -11,6 +11,8 @@ #include <string.h> namespace gsr { + static const char *custom_app_audio_tag = "[custom]"; + enum class AudioTrackType { DEVICE, APPLICATION, @@ -194,129 +196,229 @@ namespace gsr { return std::make_unique<Subsection>("Record area", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); } - std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox() { + static bool audio_device_is_output(const std::string &audio_device_id) { + return audio_device_id == "default_output" || ends_with(audio_device_id, ".monitor"); + } + + std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox(AudioDeviceType device_type) { 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); + const bool device_is_output = audio_device_is_output(audio_device.name); + if((device_type == AudioDeviceType::OUTPUT && device_is_output) || (device_type == AudioDeviceType::INPUT && !device_is_output)) { + std::string description = audio_device.description; + if(starts_with(description, "Monitor of ")) + description.erase(0, 11); + audio_device_box->add_item(description, audio_device.name); + } } return audio_device_box; } - std::unique_ptr<Button> SettingsPage::create_remove_audio_device_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_track_list_ptr->remove_widget(audio_device_list_ptr); + static void set_application_audio_options_visible(Subsection *audio_track_subsection, bool visible, const GsrInfo &gsr_info) { + if(!gsr_info.system_info.supports_app_audio) + visible = false; + + List *audio_track_items_list = dynamic_cast<List*>(audio_track_subsection->get_inner_widget()); + + List *buttons_list = dynamic_cast<List*>(audio_track_items_list->get_child_widget_by_index(1)); + Button *add_application_audio_button = dynamic_cast<Button*>(buttons_list->get_child_widget_by_index(2)); + add_application_audio_button->set_visible(visible); + + CheckBox *invert_app_audio_checkbox = dynamic_cast<CheckBox*>(audio_track_items_list->get_child_widget_by_index(3)); + invert_app_audio_checkbox->set_visible(visible); + } + + static void set_application_audio_options_visible(List *audio_track_section_list_ptr, bool visible, const GsrInfo &gsr_info) { + audio_track_section_list_ptr->for_each_child_widget([visible, &gsr_info](std::unique_ptr<Widget> &widget) { + Subsection *audio_track_subsection = dynamic_cast<Subsection*>(widget.get()); + set_application_audio_options_visible(audio_track_subsection, visible, gsr_info); + return true; + }); + } + + std::unique_ptr<Button> SettingsPage::create_remove_audio_device_button(List *audio_input_list_ptr, List *audio_device_list_ptr) { + auto remove_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0)); + remove_audio_track_button->set_icon(&get_theme().trash_texture); + remove_audio_track_button->set_icon_padding_scale(0.75f); + remove_audio_track_button->on_click = [audio_input_list_ptr, audio_device_list_ptr]() { + audio_input_list_ptr->remove_widget(audio_device_list_ptr); }; return remove_audio_track_button; } - std::unique_ptr<List> SettingsPage::create_audio_device() { + std::unique_ptr<List> SettingsPage::create_audio_device(AudioDeviceType device_type, List *audio_input_list_ptr) { auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); audio_device_list->userdata = (void*)(uintptr_t)AudioTrackType::DEVICE; - audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Device:", get_color_theme().text_color)); - audio_device_list->add_widget(create_audio_device_selection_combobox()); - audio_device_list->add_widget(create_remove_audio_device_button(audio_device_list.get())); + audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, device_type == AudioDeviceType::OUTPUT ? "Output device:" : "Input device: ", get_color_theme().text_color)); + audio_device_list->add_widget(create_audio_device_selection_combobox(device_type)); + audio_device_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, audio_device_list.get())); return audio_device_list; } - std::unique_ptr<Button> SettingsPage::create_add_audio_device_button() { - auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Add audio device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - add_audio_track_button->on_click = [this]() { + std::unique_ptr<Button> SettingsPage::create_add_audio_track_button() { + auto button = std::make_unique<Button>(&get_theme().body_font, "Add audio track", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + button->on_click = [this]() { + audio_track_section_list_ptr->add_widget(create_audio_track_section(audio_section_ptr)); + }; + button->set_visible(type != Type::STREAM); + return button; + } + + std::unique_ptr<Button> SettingsPage::create_add_audio_output_device_button(List *audio_input_list_ptr) { + auto button = std::make_unique<Button>(&get_theme().body_font, "Add output device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + button->on_click = [this, audio_input_list_ptr]() { audio_devices = get_audio_devices(); - audio_track_list_ptr->add_widget(create_audio_device()); + audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::OUTPUT, audio_input_list_ptr)); }; - return add_audio_track_button; + return button; + } + + std::unique_ptr<Button> SettingsPage::create_add_audio_input_device_button(List *audio_input_list_ptr) { + auto button = std::make_unique<Button>(&get_theme().body_font, "Add input device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + button->on_click = [this, audio_input_list_ptr]() { + audio_devices = get_audio_devices(); + audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::INPUT, audio_input_list_ptr)); + }; + return button; } - std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox() { + std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox(List *application_audio_row) { auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); + ComboBox *audio_device_box_ptr = audio_device_box.get(); for(const auto &app_audio : application_audio) { audio_device_box->add_item(app_audio, app_audio); } + audio_device_box->add_item("Custom...", custom_app_audio_tag); + + audio_device_box->on_selection_changed = [application_audio_row, audio_device_box_ptr](const std::string&, const std::string &id) { + if(id == custom_app_audio_tag) { + application_audio_row->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM; + auto custom_app_audio_entry = std::make_unique<Entry>(&get_theme().body_font, "", (int)(get_theme().body_font.get_character_size() * 10.0f)); + application_audio_row->replace_widget(audio_device_box_ptr, std::move(custom_app_audio_entry)); + } + }; + return audio_device_box; } - std::unique_ptr<List> SettingsPage::create_application_audio() { + std::unique_ptr<List> SettingsPage::create_application_audio(List *audio_input_list_ptr) { auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION; - application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "App: ", get_color_theme().text_color)); - application_audio_list->add_widget(create_application_audio_selection_combobox()); - application_audio_list->add_widget(create_remove_audio_device_button(application_audio_list.get())); + application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Application: ", get_color_theme().text_color)); + application_audio_list->add_widget(create_application_audio_selection_combobox(application_audio_list.get())); + application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); return application_audio_list; } - std::unique_ptr<List> SettingsPage::create_custom_application_audio() { + std::unique_ptr<List> SettingsPage::create_custom_application_audio(List *audio_input_list_ptr) { auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM; - application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "App: ", get_color_theme().text_color)); + application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Application: ", get_color_theme().text_color)); application_audio_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "", (int)(get_theme().body_font.get_character_size() * 10.0f))); - application_audio_list->add_widget(create_remove_audio_device_button(application_audio_list.get())); + application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); return application_audio_list; } - std::unique_ptr<Button> SettingsPage::create_add_application_audio_button() { + std::unique_ptr<Button> SettingsPage::create_add_application_audio_button(List *audio_input_list_ptr) { auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Add application audio", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - add_application_audio_button_ptr = add_audio_track_button.get(); - add_audio_track_button->on_click = [this]() { + add_audio_track_button->on_click = [this, audio_input_list_ptr]() { application_audio = get_application_audio(); - audio_track_list_ptr->add_widget(create_application_audio()); - }; - return add_audio_track_button; - } - - std::unique_ptr<Button> SettingsPage::create_add_custom_application_audio_button() { - auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Add custom application audio", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - add_custom_application_audio_button_ptr = add_audio_track_button.get(); - add_audio_track_button->on_click = [this]() { - audio_track_list_ptr->add_widget(create_custom_application_audio()); + if(application_audio.empty()) + audio_input_list_ptr->add_widget(create_custom_application_audio(audio_input_list_ptr)); + else + audio_input_list_ptr->add_widget(create_application_audio(audio_input_list_ptr)); }; return add_audio_track_button; } - std::unique_ptr<List> SettingsPage::create_add_audio_buttons() { + std::unique_ptr<List> SettingsPage::create_add_audio_buttons(List *audio_input_list_ptr) { auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); - list->add_widget(create_add_audio_device_button()); - list->add_widget(create_add_application_audio_button()); - list->add_widget(create_add_custom_application_audio_button()); + list->add_widget(create_add_audio_output_device_button(audio_input_list_ptr)); + list->add_widget(create_add_audio_input_device_button(audio_input_list_ptr)); + list->add_widget(create_add_application_audio_button(audio_input_list_ptr)); return list; } - std::unique_ptr<List> SettingsPage::create_audio_track_track_section() { + std::unique_ptr<List> SettingsPage::create_audio_input_section() { auto list = std::make_unique<List>(List::Orientation::VERTICAL); - audio_track_list_ptr = list.get(); - audio_track_list_ptr->add_widget(create_audio_device()); // Add default_output by default + //list->add_widget(create_audio_device(list.get())); // Add default_output by default return list; } - std::unique_ptr<CheckBox> SettingsPage::create_split_audio_checkbox() { - auto split_audio_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Split each device/app audio into separate audio tracks"); - split_audio_checkbox->set_checked(false); - split_audio_checkbox_ptr = split_audio_checkbox.get(); - return split_audio_checkbox; - } - std::unique_ptr<CheckBox> SettingsPage::create_application_audio_invert_checkbox() { auto application_audio_invert_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record audio from all applications except the selected ones"); application_audio_invert_checkbox->set_checked(false); - application_audio_invert_checkbox_ptr = application_audio_invert_checkbox.get(); return application_audio_invert_checkbox; } - std::unique_ptr<Widget> SettingsPage::create_audio_track_section() { + static void update_audio_track_titles(List *audio_track_section_list_ptr) { + int index = 0; + audio_track_section_list_ptr->for_each_child_widget([&index](std::unique_ptr<Widget> &widget) { + char audio_track_name[32]; + snprintf(audio_track_name, sizeof(audio_track_name), "Audio track #%d", 1 + index); + ++index; + + Subsection *subsection = dynamic_cast<Subsection*>(widget.get()); + List *subesection_items = dynamic_cast<List*>(subsection->get_inner_widget()); + Label *audio_track_title = dynamic_cast<Label*>(dynamic_cast<List*>(subesection_items->get_child_widget_by_index(0))->get_child_widget_by_index(0)); + audio_track_title->set_text(audio_track_name); + return true; + }); + } + + std::unique_ptr<List> SettingsPage::create_audio_track_title_and_remove(Subsection *audio_track_subsection, const char *title) { + auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + list->add_widget(std::make_unique<Label>(&get_theme().title_font, title, get_color_theme().text_color)); + + auto remove_track_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0)); + remove_track_button->set_icon(&get_theme().trash_texture); + remove_track_button->set_icon_padding_scale(0.75f); + remove_track_button->on_click = [this, audio_track_subsection]() { + audio_track_section_list_ptr->remove_widget(audio_track_subsection); + update_audio_track_titles(audio_track_section_list_ptr); + }; + list->add_widget(std::move(remove_track_button)); + list->set_visible(type != Type::STREAM); + return list; + } + + std::unique_ptr<Subsection> SettingsPage::create_audio_track_section(Widget *parent_widget) { + char audio_track_name[32]; + snprintf(audio_track_name, sizeof(audio_track_name), "Audio track #%d", 1 + (int)audio_track_section_list_ptr->get_num_children()); + + auto audio_input_section = create_audio_input_section(); + List *audio_input_section_ptr = audio_input_section.get(); + + auto list = std::make_unique<List>(List::Orientation::VERTICAL); + List *list_ptr = list.get(); + auto subsection = std::make_unique<Subsection>("", std::move(std::move(list)), mgl::vec2f(parent_widget->get_inner_size().x, 0.0f)); + subsection->set_bg_color(mgl::Color(35, 40, 44)); + + list_ptr->add_widget(create_audio_track_title_and_remove(subsection.get(), audio_track_name)); + list_ptr->add_widget(create_add_audio_buttons(audio_input_section_ptr)); + list_ptr->add_widget(std::move(audio_input_section)); + list_ptr->add_widget(create_application_audio_invert_checkbox()); + + set_application_audio_options_visible(subsection.get(), view_radio_button_ptr->get_selected_id() == "advanced", *gsr_info); + return subsection; + } + + std::unique_ptr<List> SettingsPage::create_audio_track_section_list() { auto list = std::make_unique<List>(List::Orientation::VERTICAL); - list->add_widget(create_add_audio_buttons()); - list->add_widget(create_audio_track_track_section()); + audio_track_section_list_ptr = list.get(); return list; } std::unique_ptr<Widget> SettingsPage::create_audio_section() { auto audio_device_section_list = std::make_unique<List>(List::Orientation::VERTICAL); - audio_device_section_list->add_widget(create_audio_track_section()); - if(type != Type::STREAM) - audio_device_section_list->add_widget(create_split_audio_checkbox()); - audio_device_section_list->add_widget(create_application_audio_invert_checkbox()); - audio_device_section_list->add_widget(create_audio_codec()); - return std::make_unique<Subsection>("Audio", std::move(audio_device_section_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); + List *audio_device_section_list_ptr = audio_device_section_list.get(); + + auto subsection = std::make_unique<Subsection>("Audio", std::move(audio_device_section_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); + audio_section_ptr = subsection.get(); + audio_device_section_list_ptr->add_widget(create_add_audio_track_button()); + audio_device_section_list_ptr->add_widget(create_audio_track_section_list()); + audio_device_section_list_ptr->add_widget(create_audio_codec()); + return subsection; } std::unique_ptr<List> SettingsPage::create_video_quality_box() { @@ -531,8 +633,7 @@ namespace gsr { void SettingsPage::add_widgets() { content_page_ptr->add_widget(create_settings()); - record_area_box_ptr->on_selection_changed = [this](const std::string &text, const std::string &id) { - (void)text; + record_area_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { const bool window_selected = id == "window"; const bool focused_selected = id == "focused"; const bool portal_selected = id == "portal"; @@ -549,8 +650,7 @@ namespace gsr { video_resolution_list_ptr->set_visible(!focused_selected && checked); }; - video_quality_box_ptr->on_selection_changed = [this](const std::string &text, const std::string &id) { - (void)text; + video_quality_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { const bool custom_selected = id == "custom"; video_bitrate_list_ptr->set_visible(custom_selected); @@ -569,12 +669,6 @@ namespace gsr { record_area_box_ptr->set_selected_item("window"); else record_area_box_ptr->on_selection_changed("", ""); - - if(!gsr_info->system_info.supports_app_audio) { - add_application_audio_button_ptr->set_visible(false); - add_custom_application_audio_button_ptr->set_visible(false); - application_audio_invert_checkbox_ptr->set_visible(false); - } } void SettingsPage::add_page_specific_widgets() { @@ -641,7 +735,7 @@ namespace gsr { auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto replay_time_entry = std::make_unique<Entry>(&get_theme().body_font, "60", get_theme().body_font.get_character_size() * 3); - replay_time_entry->validate_handler = create_entry_validator_integer_in_range(1, 10800); + replay_time_entry->validate_handler = create_entry_validator_integer_in_range(2, 86400); replay_time_entry_ptr = replay_time_entry.get(); list->add_widget(std::move(replay_time_entry)); @@ -659,6 +753,24 @@ namespace gsr { return replay_time_list; } + std::unique_ptr<List> SettingsPage::create_replay_storage() { + auto list = std::make_unique<List>(List::Orientation::VERTICAL); + list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Where should temporary replay data be stored?", get_color_theme().text_color)); + auto replay_storage_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); + replay_storage_button_ptr = replay_storage_button.get(); + replay_storage_button->add_item("RAM", "ram"); + replay_storage_button->add_item("Disk (Not recommended on SSDs)", "disk"); + + replay_storage_button->on_selection_changed = [this](const std::string&, const std::string &id) { + update_estimated_replay_file_size(id); + return true; + }; + + list->add_widget(std::move(replay_storage_button)); + list->set_visible(gsr_info->system_info.gsr_version >= GsrVersion{5, 5, 0}); + return list; + } + std::unique_ptr<RadioButton> SettingsPage::create_start_replay_automatically() { char fullscreen_text[256]; snprintf(fullscreen_text, sizeof(fullscreen_text), "Turn on replay when starting a fullscreen application%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 applications only)"); @@ -692,13 +804,13 @@ namespace gsr { return label; } - void SettingsPage::update_estimated_replay_file_size() { + void SettingsPage::update_estimated_replay_file_size(const std::string &replay_storage_type) { const int64_t replay_time_seconds = atoi(replay_time_entry_ptr->get_text().c_str()); const int64_t video_bitrate_bps = atoi(video_bitrate_entry_ptr->get_text().c_str()) * 1000LL / 8LL; const double video_filesize_mb = ((double)replay_time_seconds * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024; char buffer[256]; - snprintf(buffer, sizeof(buffer), "Estimated video max file size in RAM: %.2fMB.\nChange video bitrate or replay duration to change file size.", video_filesize_mb); + snprintf(buffer, sizeof(buffer), "Estimated video max file size %s: %.2fMB.\nChange video bitrate or replay duration to change file size.", replay_storage_type == "ram" ? "in RAM" : "on disk", video_filesize_mb); estimated_file_size_ptr->set_text(buffer); } @@ -716,6 +828,16 @@ namespace gsr { replay_time_label_ptr->set_text(buffer); } + void SettingsPage::view_changed(bool advanced_view, Subsection *notifications_subsection_ptr) { + color_range_list_ptr->set_visible(advanced_view); + audio_codec_ptr->set_visible(advanced_view); + video_codec_ptr->set_visible(advanced_view); + framerate_mode_list_ptr->set_visible(advanced_view); + notifications_subsection_ptr->set_visible(advanced_view); + set_application_audio_options_visible(audio_track_section_list_ptr, advanced_view, *gsr_info); + settings_scrollable_page_ptr->reset_scroll(); + } + void SettingsPage::add_replay_widgets() { auto file_info_list = std::make_unique<List>(List::Orientation::VERTICAL); auto file_info_data_list = std::make_unique<List>(List::Orientation::HORIZONTAL); @@ -727,12 +849,14 @@ namespace gsr { settings_list_ptr->add_widget(std::make_unique<Subsection>("File info", std::move(file_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); auto general_list = std::make_unique<List>(List::Orientation::VERTICAL); - general_list->add_widget(create_start_replay_automatically()); + general_list->add_widget(create_replay_storage()); general_list->add_widget(create_save_replay_in_game_folder()); if(gsr_info->system_info.gsr_version >= GsrVersion{5, 0, 3}) general_list->add_widget(create_restart_replay_on_save()); settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); + settings_list_ptr->add_widget(std::make_unique<Subsection>("Autostart", create_start_replay_automatically(), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); + auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL); auto show_replay_started_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show replay started notification"); @@ -754,27 +878,19 @@ namespace gsr { Subsection *notifications_subsection_ptr = notifications_subsection.get(); settings_list_ptr->add_widget(std::move(notifications_subsection)); - view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string &text, const std::string &id) { - (void)text; - const bool advanced_view = id == "advanced"; - color_range_list_ptr->set_visible(advanced_view); - audio_codec_ptr->set_visible(advanced_view); - video_codec_ptr->set_visible(advanced_view); - framerate_mode_list_ptr->set_visible(advanced_view); - notifications_subsection_ptr->set_visible(advanced_view); - split_audio_checkbox_ptr->set_visible(advanced_view); - settings_scrollable_page_ptr->reset_scroll(); + view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string&, const std::string &id) { + view_changed(id == "advanced", notifications_subsection_ptr); return true; }; view_radio_button_ptr->on_selection_changed("Simple", "simple"); replay_time_entry_ptr->on_changed = [this](const std::string&) { - update_estimated_replay_file_size(); + update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); update_replay_time_text(); }; video_bitrate_entry_ptr->on_changed = [this](const std::string&) { - update_estimated_replay_file_size(); + update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); }; } @@ -828,16 +944,8 @@ namespace gsr { Subsection *notifications_subsection_ptr = notifications_subsection.get(); settings_list_ptr->add_widget(std::move(notifications_subsection)); - view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string &text, const std::string &id) { - (void)text; - const bool advanced_view = id == "advanced"; - color_range_list_ptr->set_visible(advanced_view); - audio_codec_ptr->set_visible(advanced_view); - video_codec_ptr->set_visible(advanced_view); - framerate_mode_list_ptr->set_visible(advanced_view); - notifications_subsection_ptr->set_visible(advanced_view); - split_audio_checkbox_ptr->set_visible(advanced_view); - settings_scrollable_page_ptr->reset_scroll(); + view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string&, const std::string &id) { + view_changed(id == "advanced", notifications_subsection_ptr); return true; }; view_radio_button_ptr->on_selection_changed("Simple", "simple"); @@ -933,8 +1041,7 @@ namespace gsr { Subsection *notifications_subsection_ptr = notifications_subsection.get(); settings_list_ptr->add_widget(std::move(notifications_subsection)); - streaming_service_box_ptr->on_selection_changed = [this](const std::string &text, const std::string &id) { - (void)text; + streaming_service_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { const bool twitch_option = id == "twitch"; const bool youtube_option = id == "youtube"; const bool custom_option = id == "custom"; @@ -947,15 +1054,8 @@ namespace gsr { }; streaming_service_box_ptr->on_selection_changed("Twitch", "twitch"); - view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string &text, const std::string &id) { - (void)text; - const bool advanced_view = id == "advanced"; - color_range_list_ptr->set_visible(advanced_view); - audio_codec_ptr->set_visible(advanced_view); - video_codec_ptr->set_visible(advanced_view); - framerate_mode_list_ptr->set_visible(advanced_view); - notifications_subsection_ptr->set_visible(advanced_view); - settings_scrollable_page_ptr->reset_scroll(); + view_radio_button_ptr->on_selection_changed = [this, notifications_subsection_ptr](const std::string&, const std::string &id) { + view_changed(id == "advanced", notifications_subsection_ptr); return true; }; view_radio_button_ptr->on_selection_changed("Simple", "simple"); @@ -1006,50 +1106,64 @@ namespace gsr { return nullptr; } - static bool starts_with(std::string_view str, const char *substr) { - size_t len = strlen(substr); - return str.size() >= len && memcmp(str.data(), substr, len) == 0; - } - void SettingsPage::load_audio_tracks(const RecordOptions &record_options) { - audio_track_list_ptr->clear(); - for(const std::string &audio_track : record_options.audio_tracks) { - if(starts_with(audio_track, "app:")) { - if(!gsr_info->system_info.supports_app_audio) - continue; - - std::string audio_track_name = audio_track.substr(4); - const std::string *app_audio = get_application_audio_by_name_case_insensitive(application_audio, audio_track_name); - if(app_audio) { - std::unique_ptr<List> application_audio_widget = create_application_audio(); - ComboBox *application_audio_box = static_cast<ComboBox*>(application_audio_widget->get_child_widget_by_index(1)); - application_audio_box->set_selected_item(*app_audio); - audio_track_list_ptr->add_widget(std::move(application_audio_widget)); + audio_track_section_list_ptr->clear(); + for(const AudioTrack &audio_track : record_options.audio_tracks_list) { + auto audio_track_section = create_audio_track_section(audio_section_ptr); + List *audio_track_section_items_list_ptr = dynamic_cast<List*>(audio_track_section->get_inner_widget()); + List *audio_input_list_ptr = dynamic_cast<List*>(audio_track_section_items_list_ptr->get_child_widget_by_index(2)); + CheckBox *application_audio_invert_checkbox_ptr = dynamic_cast<CheckBox*>(audio_track_section_items_list_ptr->get_child_widget_by_index(3)); + application_audio_invert_checkbox_ptr->set_checked(audio_track.application_audio_invert); + + audio_input_list_ptr->clear(); + for(const std::string &audio_input : audio_track.audio_inputs) { + if(starts_with(audio_input, "app:")) { + if(!gsr_info->system_info.supports_app_audio) + continue; + + std::string audio_track_name = audio_input.substr(4); + const std::string *app_audio = get_application_audio_by_name_case_insensitive(application_audio, audio_track_name); + if(app_audio) { + std::unique_ptr<List> application_audio_widget = create_application_audio(audio_input_list_ptr); + ComboBox *application_audio_box = dynamic_cast<ComboBox*>(application_audio_widget->get_child_widget_by_index(1)); + application_audio_box->set_selected_item(*app_audio); + audio_input_list_ptr->add_widget(std::move(application_audio_widget)); + } else { + std::unique_ptr<List> application_audio_widget = create_custom_application_audio(audio_input_list_ptr); + Entry *application_audio_entry = dynamic_cast<Entry*>(application_audio_widget->get_child_widget_by_index(1)); + application_audio_entry->set_text(std::move(audio_track_name)); + audio_input_list_ptr->add_widget(std::move(application_audio_widget)); + } + } else if(starts_with(audio_input, "device:")) { + const std::string device_name = audio_input.substr(7); + const AudioDeviceType audio_device_type = audio_device_is_output(device_name) ? AudioDeviceType::OUTPUT : AudioDeviceType::INPUT; + std::unique_ptr<List> audio_track_widget = create_audio_device(audio_device_type, audio_input_list_ptr); + ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); + audio_device_box->set_selected_item(device_name); + audio_input_list_ptr->add_widget(std::move(audio_track_widget)); } else { - std::unique_ptr<List> application_audio_widget = create_custom_application_audio(); - Entry *application_audio_entry = static_cast<Entry*>(application_audio_widget->get_child_widget_by_index(1)); - application_audio_entry->set_text(std::move(audio_track_name)); - audio_track_list_ptr->add_widget(std::move(application_audio_widget)); + const AudioDeviceType audio_device_type = audio_device_is_output(audio_input) ? AudioDeviceType::OUTPUT : AudioDeviceType::INPUT; + std::unique_ptr<List> audio_track_widget = create_audio_device(audio_device_type, audio_input_list_ptr); + ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); + audio_device_box->set_selected_item(audio_input); + audio_input_list_ptr->add_widget(std::move(audio_track_widget)); } - } else if(starts_with(audio_track, "device:")) { - std::unique_ptr<List> audio_track_widget = create_audio_device(); - ComboBox *audio_device_box = static_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); - audio_device_box->set_selected_item(audio_track.substr(7)); - audio_track_list_ptr->add_widget(std::move(audio_track_widget)); - } else { - std::unique_ptr<List> audio_track_widget = create_audio_device(); - ComboBox *audio_device_box = static_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); - audio_device_box->set_selected_item(audio_track); - audio_track_list_ptr->add_widget(std::move(audio_track_widget)); } + + audio_track_section_list_ptr->add_widget(std::move(audio_track_section)); + + if(type == Type::STREAM) + break; + } + + if(type == Type::STREAM && audio_track_section_list_ptr->get_num_children() == 0) { + auto audio_track_section = create_audio_track_section(audio_section_ptr); + audio_track_section_list_ptr->add_widget(std::move(audio_track_section)); } } void SettingsPage::load_common(RecordOptions &record_options) { record_area_box_ptr->set_selected_item(record_options.record_area_option); - if(split_audio_checkbox_ptr) - split_audio_checkbox_ptr->set_checked(!record_options.merge_audio_tracks); - application_audio_invert_checkbox_ptr->set_checked(record_options.application_audio_invert); change_video_resolution_checkbox_ptr->set_checked(record_options.change_video_resolution); load_audio_tracks(record_options); color_range_box_ptr->set_selected_item(record_options.color_range); @@ -1102,6 +1216,7 @@ namespace gsr { void SettingsPage::load_replay() { load_common(config.replay_config.record_options); + replay_storage_button_ptr->set_selected_item(config.replay_config.replay_storage); turn_on_replay_automatically_mode_ptr->set_selected_item(config.replay_config.turn_on_replay_automatically_mode); save_replay_in_game_folder_ptr->set_checked(config.replay_config.save_video_in_game_folder); if(restart_replay_on_save) @@ -1114,8 +1229,8 @@ namespace gsr { if(config.replay_config.replay_time < 2) config.replay_config.replay_time = 2; - if(config.replay_config.replay_time > 10800) - config.replay_config.replay_time = 10800; + if(config.replay_config.replay_time > 86400) + config.replay_config.replay_time = 86400; replay_time_entry_ptr->set_text(std::to_string(config.replay_config.replay_time)); } @@ -1139,28 +1254,38 @@ namespace gsr { container_box_ptr->set_selected_item(config.streaming_config.custom.container); } - static void save_audio_tracks(std::vector<std::string> &audio_devices, List *audio_devices_list_ptr) { - audio_devices.clear(); - audio_devices_list_ptr->for_each_child_widget([&audio_devices](std::unique_ptr<Widget> &child_widget) { - List *audio_track_line = static_cast<List*>(child_widget.get()); - const AudioTrackType audio_track_type = (AudioTrackType)(uintptr_t)audio_track_line->userdata; - switch(audio_track_type) { - case AudioTrackType::DEVICE: { - ComboBox *audio_device_box = static_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); - audio_devices.push_back("device:" + audio_device_box->get_selected_id()); - break; + static void save_audio_tracks(std::vector<AudioTrack> &audio_tracks, List *audio_track_section_list_ptr) { + audio_tracks.clear(); + audio_track_section_list_ptr->for_each_child_widget([&audio_tracks](std::unique_ptr<Widget> &child_widget) { + Subsection *audio_subsection = dynamic_cast<Subsection*>(child_widget.get()); + List *audio_track_section_items_list_ptr = dynamic_cast<List*>(audio_subsection->get_inner_widget()); + List *audio_input_list_ptr = dynamic_cast<List*>(audio_track_section_items_list_ptr->get_child_widget_by_index(2)); + CheckBox *application_audio_invert_checkbox_ptr = dynamic_cast<CheckBox*>(audio_track_section_items_list_ptr->get_child_widget_by_index(3)); + + audio_tracks.push_back({std::vector<std::string>{}, application_audio_invert_checkbox_ptr->is_checked()}); + audio_input_list_ptr->for_each_child_widget([&audio_tracks](std::unique_ptr<Widget> &child_widget){ + List *audio_track_line = dynamic_cast<List*>(child_widget.get()); + const AudioTrackType audio_track_type = (AudioTrackType)(uintptr_t)audio_track_line->userdata; + switch(audio_track_type) { + case AudioTrackType::DEVICE: { + ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); + audio_tracks.back().audio_inputs.push_back("device:" + audio_device_box->get_selected_id()); + break; + } + case AudioTrackType::APPLICATION: { + ComboBox *application_audio_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); + audio_tracks.back().audio_inputs.push_back("app:" + application_audio_box->get_selected_id()); + break; + } + case AudioTrackType::APPLICATION_CUSTOM: { + Entry *application_audio_entry = dynamic_cast<Entry*>(audio_track_line->get_child_widget_by_index(1)); + audio_tracks.back().audio_inputs.push_back("app:" + application_audio_entry->get_text()); + break; + } } - case AudioTrackType::APPLICATION: { - ComboBox *application_audio_box = static_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); - audio_devices.push_back("app:" + application_audio_box->get_selected_id()); - break; - } - case AudioTrackType::APPLICATION_CUSTOM: { - Entry *application_audio_entry = static_cast<Entry*>(audio_track_line->get_child_widget_by_index(1)); - audio_devices.push_back("app:" + application_audio_entry->get_text()); - break; - } - } + return true; + }); + return true; }); } @@ -1173,11 +1298,8 @@ namespace gsr { record_options.video_height = atoi(video_height_entry_ptr->get_text().c_str()); record_options.fps = atoi(framerate_entry_ptr->get_text().c_str()); record_options.video_bitrate = atoi(video_bitrate_entry_ptr->get_text().c_str()); - if(split_audio_checkbox_ptr) - record_options.merge_audio_tracks = !split_audio_checkbox_ptr->is_checked(); - record_options.application_audio_invert = application_audio_invert_checkbox_ptr->is_checked(); record_options.change_video_resolution = change_video_resolution_checkbox_ptr->is_checked(); - save_audio_tracks(record_options.audio_tracks, audio_track_list_ptr); + save_audio_tracks(record_options.audio_tracks_list, audio_track_section_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(); @@ -1244,6 +1366,7 @@ namespace gsr { config.replay_config.save_directory = save_directory_button_ptr->get_text(); config.replay_config.container = container_box_ptr->get_selected_id(); config.replay_config.replay_time = atoi(replay_time_entry_ptr->get_text().c_str()); + config.replay_config.replay_storage = replay_storage_button_ptr->get_selected_id(); if(config.replay_config.replay_time < 5) { config.replay_config.replay_time = 5; |