From 0018788780d756dbf0d3a77f6b40b384183348f7 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 14 Apr 2025 11:38:52 +0200 Subject: Redesign audio to support multiple audio tracks explicitly --- src/Config.cpp | 82 +++++++- src/GlobalHotkeysLinux.cpp | 2 + src/GsrInfo.cpp | 5 - src/Overlay.cpp | 117 ++++++------ src/Theme.cpp | 9 +- src/Utils.cpp | 5 + src/gui/ComboBox.cpp | 2 +- src/gui/GlobalSettingsPage.cpp | 2 +- src/gui/GsrPage.cpp | 5 +- src/gui/List.cpp | 30 +-- src/gui/Page.cpp | 15 +- src/gui/ScreenshotSettingsPage.cpp | 3 +- src/gui/ScrollablePage.cpp | 13 +- src/gui/SettingsPage.cpp | 382 ++++++++++++++++++++++--------------- src/gui/StaticPage.cpp | 5 +- src/gui/Subsection.cpp | 17 +- src/gui/Widget.cpp | 16 +- src/main.cpp | 5 +- 18 files changed, 449 insertions(+), 266 deletions(-) (limited to 'src') diff --git a/src/Config.cpp b/src/Config.cpp index 9847c45..3832c83 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -15,6 +15,8 @@ #define FORMAT_U32 "%" PRIu32 namespace gsr { + static const std::string_view add_audio_track_tag = "[add_audio_track]"; + static std::vector hotkey_modifiers_to_mgl_keys(uint32_t modifiers) { std::vector result; if(modifiers & HOTKEY_MOD_LCTRL) @@ -101,6 +103,14 @@ namespace gsr { return result; } + bool AudioTrack::operator==(const AudioTrack &other) const { + return audio_inputs == other.audio_inputs && application_audio_invert == other.application_audio_invert; + } + + bool AudioTrack::operator!=(const AudioTrack &other) const { + return !operator==(other); + } + Config::Config(const SupportedCaptureOptions &capture_options) { const std::string default_videos_save_directory = get_videos_dir(); const std::string default_pictures_save_directory = get_pictures_dir(); @@ -108,16 +118,16 @@ namespace gsr { set_hotkeys_to_default(); streaming_config.record_options.video_quality = "custom"; - streaming_config.record_options.audio_tracks.push_back("default_output"); + streaming_config.record_options.audio_tracks_list.push_back({std::vector{"default_output"}, false}); streaming_config.record_options.video_bitrate = 15000; record_config.save_directory = default_videos_save_directory; - record_config.record_options.audio_tracks.push_back("default_output"); + record_config.record_options.audio_tracks_list.push_back({std::vector{"default_output"}, false}); record_config.record_options.video_bitrate = 45000; replay_config.record_options.video_quality = "custom"; replay_config.save_directory = default_videos_save_directory; - replay_config.record_options.audio_tracks.push_back("default_output"); + replay_config.record_options.audio_tracks_list.push_back({std::vector{"default_output"}, false}); replay_config.record_options.video_bitrate = 45000; screenshot_config.save_directory = default_pictures_save_directory; @@ -152,7 +162,7 @@ namespace gsr { return KeyValue{line.substr(0, space_index), line.substr(space_index + 1)}; } - using ConfigValue = std::variant*>; + using ConfigValue = std::variant*, std::vector*>; static std::map get_config_options(Config &config) { return { @@ -174,6 +184,7 @@ namespace gsr { {"streaming.record_options.application_audio_invert", &config.streaming_config.record_options.application_audio_invert}, {"streaming.record_options.change_video_resolution", &config.streaming_config.record_options.change_video_resolution}, {"streaming.record_options.audio_track", &config.streaming_config.record_options.audio_tracks}, + {"streaming.record_options.audio_track_item", &config.streaming_config.record_options.audio_tracks_list}, {"streaming.record_options.color_range", &config.streaming_config.record_options.color_range}, {"streaming.record_options.video_quality", &config.streaming_config.record_options.video_quality}, {"streaming.record_options.codec", &config.streaming_config.record_options.video_codec}, @@ -203,6 +214,7 @@ namespace gsr { {"record.record_options.application_audio_invert", &config.record_config.record_options.application_audio_invert}, {"record.record_options.change_video_resolution", &config.record_config.record_options.change_video_resolution}, {"record.record_options.audio_track", &config.record_config.record_options.audio_tracks}, + {"record.record_options.audio_track_item", &config.record_config.record_options.audio_tracks_list}, {"record.record_options.color_range", &config.record_config.record_options.color_range}, {"record.record_options.video_quality", &config.record_config.record_options.video_quality}, {"record.record_options.codec", &config.record_config.record_options.video_codec}, @@ -231,6 +243,7 @@ namespace gsr { {"replay.record_options.application_audio_invert", &config.replay_config.record_options.application_audio_invert}, {"replay.record_options.change_video_resolution", &config.replay_config.record_options.change_video_resolution}, {"replay.record_options.audio_track", &config.replay_config.record_options.audio_tracks}, + {"replay.record_options.audio_track_item", &config.replay_config.record_options.audio_tracks_list}, {"replay.record_options.color_range", &config.replay_config.record_options.color_range}, {"replay.record_options.video_quality", &config.replay_config.record_options.video_quality}, {"replay.record_options.codec", &config.replay_config.record_options.video_codec}, @@ -291,6 +304,9 @@ namespace gsr { } else if(std::holds_alternative*>(it.second)) { if(*std::get*>(it.second) != *std::get*>(it_other->second)) return false; + } else if(std::holds_alternative*>(it.second)) { + if(*std::get*>(it.second) != *std::get*>(it_other->second)) + return false; } else { assert(false); } @@ -302,6 +318,17 @@ namespace gsr { return !operator==(other); } + static void populate_new_audio_track_from_old(RecordOptions &record_options) { + if(record_options.merge_audio_tracks) { + record_options.audio_tracks_list.push_back({std::move(record_options.audio_tracks), record_options.application_audio_invert}); + } else { + for(const std::string &audio_input : record_options.audio_tracks) { + record_options.audio_tracks_list.push_back({std::vector{audio_input}, record_options.application_audio_invert}); + } + } + record_options.audio_tracks.clear(); + } + std::optional read_config(const SupportedCaptureOptions &capture_options) { std::optional config; @@ -313,10 +340,15 @@ namespace gsr { } config = Config(capture_options); + config->streaming_config.record_options.audio_tracks.clear(); config->record_config.record_options.audio_tracks.clear(); config->replay_config.record_options.audio_tracks.clear(); + config->streaming_config.record_options.audio_tracks_list.clear(); + config->record_config.record_options.audio_tracks_list.clear(); + config->replay_config.record_options.audio_tracks_list.clear(); + auto config_options = get_config_options(config.value()); string_split_char(file_content, '\n', [&](std::string_view line) { @@ -355,6 +387,23 @@ namespace gsr { } else if(std::holds_alternative*>(it->second)) { std::string array_value(key_value->value); std::get*>(it->second)->push_back(std::move(array_value)); + } else if(std::holds_alternative*>(it->second)) { + const size_t space_index = key_value->value.find(' '); + if(space_index == std::string_view::npos) { + fprintf(stderr, "Warning: Invalid config option value for %.*s\n", (int)key_value->key.size(), key_value->key.data()); + return true; + } + + const bool application_audio_invert = key_value->value.substr(0, space_index) == "true"; + const std::string_view audio_input = key_value->value.substr(space_index + 1); + std::vector &audio_tracks = *std::get*>(it->second); + + if(audio_input == add_audio_track_tag) { + audio_tracks.push_back({std::vector{}, application_audio_invert}); + } else if(!audio_tracks.empty()) { + audio_tracks.back().application_audio_invert = application_audio_invert; + audio_tracks.back().audio_inputs.emplace_back(audio_input); + } } else { assert(false); } @@ -362,11 +411,16 @@ namespace gsr { return true; }); - if(config->main_config.config_file_version != GSR_CONFIG_FILE_VERSION) { - fprintf(stderr, "Info: the config file is outdated, resetting it\n"); - config = std::nullopt; + if(config->main_config.config_file_version == 1) { + populate_new_audio_track_from_old(config->streaming_config.record_options); + populate_new_audio_track_from_old(config->record_config.record_options); + populate_new_audio_track_from_old(config->replay_config.record_options); } + config->streaming_config.record_options.audio_tracks.clear(); + config->record_config.record_options.audio_tracks.clear(); + config->replay_config.record_options.audio_tracks.clear(); + return config; } @@ -402,9 +456,17 @@ namespace gsr { const ConfigHotkey *config_hotkey = std::get(it.second); fprintf(file, "%.*s " FORMAT_I64 " " FORMAT_U32 "\n", (int)it.first.size(), it.first.data(), config_hotkey->key, config_hotkey->modifiers); } else if(std::holds_alternative*>(it.second)) { - std::vector *array = std::get*>(it.second); - for(const std::string &value : *array) { - fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), value.c_str()); + std::vector *audio_inputs = std::get*>(it.second); + for(const std::string &audio_input : *audio_inputs) { + fprintf(file, "%.*s %s\n", (int)it.first.size(), it.first.data(), audio_input.c_str()); + } + } else if(std::holds_alternative*>(it.second)) { + std::vector *audio_tracks = std::get*>(it.second); + for(const AudioTrack &audio_track : *audio_tracks) { + fprintf(file, "%.*s %s %.*s\n", (int)it.first.size(), it.first.data(), audio_track.application_audio_invert ? "true" : "false", (int)add_audio_track_tag.size(), add_audio_track_tag.data()); + for(const std::string &audio_input : audio_track.audio_inputs) { + fprintf(file, "%.*s %s %s\n", (int)it.first.size(), it.first.data(), audio_track.application_audio_invert ? "true" : "false", audio_input.c_str()); + } } } else { assert(false); diff --git a/src/GlobalHotkeysLinux.cpp b/src/GlobalHotkeysLinux.cpp index 20b089f..d780916 100644 --- a/src/GlobalHotkeysLinux.cpp +++ b/src/GlobalHotkeysLinux.cpp @@ -77,6 +77,8 @@ namespace gsr { fprintf(stderr, "Error: GlobalHotkeysLinux::~GlobalHotkeysLinux: failed to write command to gsr-global-hotkeys, error: %s\n", strerror(errno)); close_fds(); } + } else { + close_fds(); } if(process_id > 0) { diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index 5af6397..d7212d7 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -175,11 +175,6 @@ namespace gsr { CAPTURE_OPTIONS }; - 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; - } - GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info) { *gsr_info = GsrInfo{}; diff --git a/src/Overlay.cpp b/src/Overlay.cpp index c342d37..fe7c88e 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -685,6 +685,8 @@ namespace gsr { } bool Overlay::draw() { + remove_widgets_to_be_removed(); + update_notification_process_status(); update_gsr_replay_save(); update_gsr_process_status(); @@ -1249,6 +1251,7 @@ namespace gsr { while(!page_stack.empty()) { page_stack.pop(); } + remove_widgets_to_be_removed(); if(default_cursor) { XFreeCursor(display, default_cursor); @@ -1742,28 +1745,25 @@ namespace gsr { gpu_screen_recorder_screenshot_process = -1; } - 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; - } - - static bool are_all_audio_tracks_available_to_capture(const std::vector &audio_tracks) { + static bool are_all_audio_tracks_available_to_capture(const std::vector &audio_tracks) { const auto audio_devices = get_audio_devices(); - for(const std::string &audio_track : audio_tracks) { - std::string_view audio_track_name(audio_track.c_str()); - const bool is_app_audio = starts_with(audio_track_name, "app:"); - if(is_app_audio) - continue; + for(const AudioTrack &audio_track : audio_tracks) { + for(const std::string &audio_input : audio_track.audio_inputs) { + std::string_view audio_track_name(audio_input.c_str()); + const bool is_app_audio = starts_with(audio_track_name, "app:"); + if(is_app_audio) + continue; - if(starts_with(audio_track_name, "device:")) - audio_track_name.remove_prefix(7); + if(starts_with(audio_track_name, "device:")) + audio_track_name.remove_prefix(7); - auto it = std::find_if(audio_devices.begin(), audio_devices.end(), [&](const auto &audio_device) { - return audio_device.name == audio_track_name; - }); - if(it == audio_devices.end()) { - //fprintf(stderr, "Audio not ready\n"); - return false; + auto it = std::find_if(audio_devices.begin(), audio_devices.end(), [&](const auto &audio_device) { + return audio_device.name == audio_track_name; + }); + if(it == audio_devices.end()) { + //fprintf(stderr, "Audio not ready\n"); + return false; + } } } return true; @@ -1794,7 +1794,7 @@ namespace gsr { focused_window_is_fullscreen = focused_window != 0 && window_is_fullscreen(display, focused_window); if(focused_window_is_fullscreen != prev_focused_window_is_fullscreen) { if(recording_status == RecordingStatus::NONE && focused_window_is_fullscreen) { - if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks_list)) on_press_start_replay(false, false); } else if(recording_status == RecordingStatus::REPLAY && !focused_window_is_fullscreen) { on_press_start_replay(true, false); @@ -1811,7 +1811,7 @@ namespace gsr { power_supply_connected = power_supply_online_filepath.empty() || power_supply_is_connected(power_supply_online_filepath.c_str()); if(power_supply_connected != prev_power_supply_status) { if(recording_status == RecordingStatus::NONE && power_supply_connected) { - if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks_list)) on_press_start_replay(false, false); } else if(recording_status == RecordingStatus::REPLAY && !power_supply_connected) { on_press_start_replay(false, false); @@ -1823,7 +1823,7 @@ namespace gsr { if(replay_startup_mode != ReplayStartupMode::TURN_ON_AT_SYSTEM_STARTUP || recording_status != RecordingStatus::NONE || !try_replay_startup) return; - if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks)) + if(are_all_audio_tracks_available_to_capture(config.replay_config.record_options.audio_tracks_list)) on_press_start_replay(true, false); } @@ -1947,29 +1947,31 @@ namespace gsr { return container; } - static std::vector create_audio_tracks_real_names(const std::vector &audio_tracks, bool application_audio_invert, const GsrInfo &gsr_info) { + static std::vector create_audio_tracks_cli_args(const std::vector &audio_tracks, const GsrInfo &gsr_info) { std::vector result; - for(const std::string &audio_track : audio_tracks) { - std::string audio_track_name = audio_track; - const bool is_app_audio = starts_with(audio_track_name, "app:"); - if(is_app_audio && !gsr_info.system_info.supports_app_audio) - continue; + result.reserve(audio_tracks.size()); + + for(const AudioTrack &audio_track : audio_tracks) { + std::string audio_track_merged; + for(const std::string &audio_input_name : audio_track.audio_inputs) { + std::string new_audio_input_name = audio_input_name; + const bool is_app_audio = starts_with(new_audio_input_name, "app:"); + if(is_app_audio && !gsr_info.system_info.supports_app_audio) + continue; - if(is_app_audio && application_audio_invert) - audio_track_name.replace(0, 4, "app-inverse:"); + if(is_app_audio && audio_track.application_audio_invert) + new_audio_input_name.replace(0, 4, "app-inverse:"); - result.push_back(std::move(audio_track_name)); - } - return result; - } + if(!audio_track_merged.empty()) + audio_track_merged += "|"; - static std::string merge_audio_tracks(const std::vector &audio_tracks) { - std::string result; - for(size_t i = 0; i < audio_tracks.size(); ++i) { - if(i > 0) - result += "|"; - result += audio_tracks[i]; + audio_track_merged += new_audio_input_name; + } + + if(!audio_track_merged.empty()) + result.push_back(std::move(audio_track_merged)); } + return result; } @@ -1984,7 +1986,7 @@ namespace gsr { args.push_back(region_str); } - static void add_common_gpu_screen_recorder_args(std::vector &args, const RecordOptions &record_options, const std::vector &audio_tracks, const std::string &video_bitrate, const char *region, const std::string &audio_devices_merged, char *region_str, int region_str_size, const RegionSelector ®ion_selector) { + static void add_common_gpu_screen_recorder_args(std::vector &args, const RecordOptions &record_options, const std::vector &audio_tracks, const std::string &video_bitrate, const char *region, char *region_str, int region_str_size, const RegionSelector ®ion_selector) { if(record_options.video_quality == "custom") { args.push_back("-bm"); args.push_back("cbr"); @@ -2000,16 +2002,9 @@ namespace gsr { args.push_back(region); } - if(record_options.merge_audio_tracks) { - if(!audio_devices_merged.empty()) { - args.push_back("-a"); - args.push_back(audio_devices_merged.c_str()); - } - } else { - for(const std::string &audio_track : audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } + for(const std::string &audio_track : audio_tracks) { + args.push_back("-a"); + args.push_back(audio_track.c_str()); } if(record_options.restore_portal_session) { @@ -2133,8 +2128,7 @@ namespace gsr { const std::string fps = std::to_string(config.replay_config.record_options.fps); const std::string video_bitrate = std::to_string(config.replay_config.record_options.video_bitrate); const std::string output_directory = config.replay_config.save_directory; - const std::vector audio_tracks = create_audio_tracks_real_names(config.replay_config.record_options.audio_tracks, config.replay_config.record_options.application_audio_invert, gsr_info); - const std::string audio_tracks_merged = merge_audio_tracks(audio_tracks); + const std::vector audio_tracks = create_audio_tracks_cli_args(config.replay_config.record_options.audio_tracks_list, gsr_info); const std::string framerate_mode = config.replay_config.record_options.framerate_mode == "auto" ? "vfr" : config.replay_config.record_options.framerate_mode; const std::string replay_time = std::to_string(config.replay_config.replay_time); const char *video_codec = config.replay_config.record_options.video_codec.c_str(); @@ -2173,7 +2167,7 @@ namespace gsr { } char region_str[128]; - add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, audio_tracks_merged, region_str, sizeof(region_str), region_selector); + add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector); args.push_back(nullptr); @@ -2276,8 +2270,7 @@ namespace gsr { const std::string fps = std::to_string(config.record_config.record_options.fps); const std::string video_bitrate = std::to_string(config.record_config.record_options.video_bitrate); const std::string output_file = config.record_config.save_directory + "/Video_" + get_date_str() + "." + container_to_file_extension(config.record_config.container.c_str()); - const std::vector audio_tracks = create_audio_tracks_real_names(config.record_config.record_options.audio_tracks, config.record_config.record_options.application_audio_invert, gsr_info); - const std::string audio_tracks_merged = merge_audio_tracks(audio_tracks); + const std::vector audio_tracks = create_audio_tracks_cli_args(config.record_config.record_options.audio_tracks_list, gsr_info); const std::string framerate_mode = config.record_config.record_options.framerate_mode == "auto" ? "vfr" : config.record_config.record_options.framerate_mode; const char *video_codec = config.record_config.record_options.video_codec.c_str(); const char *encoder = "gpu"; @@ -2309,7 +2302,7 @@ namespace gsr { }; char region_str[128]; - add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, audio_tracks_merged, region_str, sizeof(region_str), region_selector); + add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector); args.push_back(nullptr); @@ -2429,8 +2422,11 @@ namespace gsr { // TODO: Validate input, fallback to valid values const std::string fps = std::to_string(config.streaming_config.record_options.fps); const std::string video_bitrate = std::to_string(config.streaming_config.record_options.video_bitrate); - const std::vector audio_tracks = create_audio_tracks_real_names(config.streaming_config.record_options.audio_tracks, config.streaming_config.record_options.application_audio_invert, gsr_info); - const std::string audio_tracks_merged = merge_audio_tracks(audio_tracks); + std::vector audio_tracks = create_audio_tracks_cli_args(config.streaming_config.record_options.audio_tracks_list, gsr_info); + // This isn't possible unless the user modified the config file manually, + // But we check it anyways as streaming on some sites can fail if there is more than one audio track + if(audio_tracks.size() > 1) + audio_tracks.resize(1); const std::string framerate_mode = config.streaming_config.record_options.framerate_mode == "auto" ? "vfr" : config.streaming_config.record_options.framerate_mode; const char *video_codec = config.streaming_config.record_options.video_codec.c_str(); const char *encoder = "gpu"; @@ -2466,9 +2462,8 @@ namespace gsr { "-o", url.c_str() }; - config.streaming_config.record_options.merge_audio_tracks = true; char region_str[128]; - add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, audio_tracks_merged, region_str, sizeof(region_str), region_selector); + add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector); args.push_back(nullptr); diff --git a/src/Theme.cpp b/src/Theme.cpp index 2001f7d..c813834 100644 --- a/src/Theme.cpp +++ b/src/Theme.cpp @@ -75,7 +75,7 @@ namespace gsr { if(!theme->folder_texture.load_from_file((resources_path + "images/folder.png").c_str())) goto error; - if(!theme->up_arrow_texture.load_from_file((resources_path + "images/up_arrow.png").c_str())) + if(!theme->up_arrow_texture.load_from_file((resources_path + "images/up_arrow.png").c_str(), mgl::Texture::LoadOptions{false, false, true})) goto error; if(!theme->replay_button_texture.load_from_file((resources_path + "images/replay.png").c_str())) @@ -93,10 +93,10 @@ namespace gsr { if(!theme->logo_texture.load_from_file((resources_path + "images/gpu_screen_recorder_logo.png").c_str())) goto error; - if(!theme->checkbox_circle_texture.load_from_file((resources_path + "images/checkbox_circle.png").c_str())) + if(!theme->checkbox_circle_texture.load_from_file((resources_path + "images/checkbox_circle.png").c_str(), mgl::Texture::LoadOptions{false, false, true})) goto error; - if(!theme->checkbox_background_texture.load_from_file((resources_path + "images/checkbox_background.png").c_str())) + if(!theme->checkbox_background_texture.load_from_file((resources_path + "images/checkbox_background.png").c_str(), mgl::Texture::LoadOptions{false, false, true})) goto error; if(!theme->play_texture.load_from_file((resources_path + "images/play.png").c_str())) @@ -114,6 +114,9 @@ namespace gsr { if(!theme->screenshot_texture.load_from_file((resources_path + "images/screenshot.png").c_str())) goto error; + if(!theme->trash_texture.load_from_file((resources_path + "images/trash.png").c_str(), mgl::Texture::LoadOptions{false, false, true})) + goto error; + if(!theme->ps4_home_texture.load_from_file((resources_path + "images/ps4_home.png").c_str(), mgl::Texture::LoadOptions{false, false, true})) goto error; diff --git a/src/Utils.cpp b/src/Utils.cpp index df6db2f..bc7b1f2 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -22,6 +22,11 @@ namespace gsr { } } + 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; + } + std::string get_home_dir() { const char *home_dir = getenv("HOME"); if(!home_dir) { diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp index dbe9aa0..08c4ec2 100644 --- a/src/gui/ComboBox.cpp +++ b/src/gui/ComboBox.cpp @@ -85,7 +85,7 @@ namespace gsr { void ComboBox::add_item(const std::string &text, const std::string &id) { items.push_back({mgl::Text(text, *font), id, {0.0f, 0.0f}}); - items.back().text.set_max_width(font->get_character_size() * 22); // TODO: Make a proper solution + items.back().text.set_max_width(font->get_character_size() * 25); // TODO: Make a proper solution //items.back().text.set_max_rows(1); dirty = true; } diff --git a/src/gui/GlobalSettingsPage.cpp b/src/gui/GlobalSettingsPage.cpp index 1e2a444..fd4b6b8 100644 --- a/src/gui/GlobalSettingsPage.cpp +++ b/src/gui/GlobalSettingsPage.cpp @@ -149,7 +149,7 @@ namespace gsr { tint_color_radio_button_ptr = tint_color_radio_button.get(); tint_color_radio_button->add_item("Red", "amd"); tint_color_radio_button->add_item("Green", "nvidia"); - tint_color_radio_button->add_item("blue", "intel"); + tint_color_radio_button->add_item("Blue", "intel"); tint_color_radio_button->on_selection_changed = [](const std::string&, const std::string &id) { if(id == "amd") get_color_theme().tint_color = mgl::Color(221, 0, 49); diff --git a/src/gui/GsrPage.cpp b/src/gui/GsrPage.cpp index 663187c..b4005f5 100644 --- a/src/gui/GsrPage.cpp +++ b/src/gui/GsrPage.cpp @@ -39,8 +39,9 @@ namespace gsr { // Process widgets by visibility (backwards) return widgets.for_each_reverse([selected_widget, &window, &event, content_page_position](std::unique_ptr &widget) { - if(widget.get() != selected_widget) { - if(!widget->on_event(event, window, content_page_position)) + Widget *p = widget.get(); + if(p != selected_widget) { + if(!p->on_event(event, window, content_page_position)) return false; } return true; diff --git a/src/gui/List.cpp b/src/gui/List.cpp index 5294e36..57a6045 100644 --- a/src/gui/List.cpp +++ b/src/gui/List.cpp @@ -24,14 +24,23 @@ namespace gsr { // Process widgets by visibility (backwards) return widgets.for_each_reverse([selected_widget, &event, &window](std::unique_ptr &widget) { // Ignore offset because widgets are positioned with offset in ::draw, this solution is simpler - if(widget.get() != selected_widget) { - if(!widget->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) + Widget *p = widget.get(); + if(p != selected_widget) { + if(!p->on_event(event, window, mgl::vec2f(0.0f, 0.0f))) return false; } return true; }); } + List::~List() { + widgets.for_each([this](std::unique_ptr &widget) { + if(widget->parent_widget == this) + widget->parent_widget = nullptr; + return true; + }, true); + } + void List::draw(mgl::Window &window, mgl::vec2f offset) { if(!visible) return; @@ -104,15 +113,6 @@ namespace gsr { selected_widget->draw(window, mgl::vec2f(0.0f, 0.0f)); } - // void List::remove_child_widget(Widget *widget) { - // for(auto it = widgets.begin(), end = widgets.end(); it != end; ++it) { - // if(it->get() == widget) { - // widgets.erase(it); - // return; - // } - // } - // } - void List::add_widget(std::unique_ptr widget) { widget->parent_widget = this; widgets.push_back(std::move(widget)); @@ -122,6 +122,10 @@ namespace gsr { widgets.remove(widget); } + void List::replace_widget(Widget *widget, std::unique_ptr new_widget) { + widgets.replace_item(widget, std::move(new_widget)); + } + void List::clear() { widgets.clear(); } @@ -137,6 +141,10 @@ namespace gsr { return nullptr; } + size_t List::get_num_children() const { + return widgets.size(); + } + void List::set_spacing(float spacing) { spacing_scale = spacing; } diff --git a/src/gui/Page.cpp b/src/gui/Page.cpp index ae13d82..5f21b71 100644 --- a/src/gui/Page.cpp +++ b/src/gui/Page.cpp @@ -1,14 +1,13 @@ #include "../../include/gui/Page.hpp" namespace gsr { - // void Page::remove_child_widget(Widget *widget) { - // for(auto it = widgets.begin(), end = widgets.end(); it != end; ++it) { - // if(it->get() == widget) { - // widgets.erase(it); - // return; - // } - // } - // } + Page::~Page() { + widgets.for_each([this](std::unique_ptr &widget) { + if(widget->parent_widget == this) + widget->parent_widget = nullptr; + return true; + }, true); + } void Page::add_widget(std::unique_ptr widget) { widget->parent_widget = this; diff --git a/src/gui/ScreenshotSettingsPage.cpp b/src/gui/ScreenshotSettingsPage.cpp index 2dedd86..5b8efbd 100644 --- a/src/gui/ScreenshotSettingsPage.cpp +++ b/src/gui/ScreenshotSettingsPage.cpp @@ -257,8 +257,7 @@ namespace gsr { void ScreenshotSettingsPage::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 portal_selected = id == "portal"; select_window_list_ptr->set_visible(window_selected); diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp index d5e92d0..cec20d3 100644 --- a/src/gui/ScrollablePage.cpp +++ b/src/gui/ScrollablePage.cpp @@ -15,6 +15,14 @@ namespace gsr { ScrollablePage::ScrollablePage(mgl::vec2f size) : size(size) {} + ScrollablePage::~ScrollablePage() { + widgets.for_each([this](std::unique_ptr &widget) { + if(widget->parent_widget == this) + widget->parent_widget = nullptr; + return true; + }, true); + } + bool ScrollablePage::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) { if(!visible) return true; @@ -57,8 +65,9 @@ namespace gsr { // Process widgets by visibility (backwards) const bool continue_events = widgets.for_each_reverse([selected_widget, &window, &event, offset](std::unique_ptr &widget) { - if(widget.get() != selected_widget) { - if(!widget->on_event(event, window, offset)) + Widget *p = widget.get(); + if(p != selected_widget) { + if(!p->on_event(event, window, offset)) return false; } return true; diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index 663e941..94eeb0d 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -11,6 +11,8 @@ #include namespace gsr { + static const char *custom_app_audio_tag = "[custom]"; + enum class AudioTrackType { DEVICE, APPLICATION, @@ -202,121 +204,199 @@ namespace gsr { return audio_device_box; } - std::unique_ptr