diff options
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | TODO | 27 | ||||
m--------- | depends/mglpp | 0 | ||||
-rw-r--r-- | include/Config.hpp | 3 | ||||
-rw-r--r-- | include/GsrInfo.hpp | 1 | ||||
-rw-r--r-- | include/Overlay.hpp | 3 | ||||
-rw-r--r-- | include/gui/Label.hpp | 1 | ||||
-rw-r--r-- | include/gui/LineSeparator.hpp | 24 | ||||
-rw-r--r-- | include/gui/SettingsPage.hpp | 31 | ||||
-rw-r--r-- | include/gui/Subsection.hpp | 1 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rwxr-xr-x | scripts/notify-saved-name.sh | 1 | ||||
-rw-r--r-- | src/Config.cpp | 9 | ||||
-rw-r--r-- | src/GsrInfo.cpp | 26 | ||||
-rw-r--r-- | src/Overlay.cpp | 149 | ||||
-rw-r--r-- | src/gui/CheckBox.cpp | 12 | ||||
-rw-r--r-- | src/gui/Label.cpp | 4 | ||||
-rw-r--r-- | src/gui/LineSeparator.cpp | 45 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 215 | ||||
-rw-r--r-- | src/gui/Subsection.cpp | 18 |
20 files changed, 440 insertions, 136 deletions
@@ -34,3 +34,8 @@ This software is licensed under GPL3.0-only. Files under `fonts/` directory are # Screenshots ![](https://dec05eba.com/images/gsr-overlay-screenshot-front.webp) ![](https://dec05eba.com/images/gsr-overlay-screenshot-settings.webp) + +# Donations +If you want to donate you can donate via bitcoin or monero. +* Bitcoin: bc1qqvuqnwrdyppf707ge27fqz2n9y9gu7lf5ypyuf +* Monero: 4An9kp2qW1C9Gah7ewv4JzcNFQ5TAX7ineGCqXWK6vQnhsGGcRpNgcn8r9EC3tMcgY7vqCKs3nSRXhejMHBaGvFdN2egYet
\ No newline at end of file @@ -52,3 +52,30 @@ Add profiles and hotkey to switch between profiles (show notification when switc Fix first frame being black. Add support for systray. + +Add option to take screenshot. + +Move event callbacks to a global list instead of std::function object in each widget. This reduces the size of widgets, + since most widgets wont have the event callback set. + This event callback would pass the widget as an argument. + This could be done transparently by having a function in the widget to set a callback function + and that could add a wrapper that checks if the callback received _this_, and that would call the callback set by the user. + +Make save-video-in-game-folder.sh and notify-saved-name.sh run ~/.config/gpu-screen-recorder/on-save.sh if it exists. + This could for example be used to automatically convert the video to a different format or to upload it to a server. + Before this script is called gsr-ui should define an environment variable GSR_PROFILE that specifies the name of the profile. + This profile name can be used to decide which action the users script should do, for example to convert the video to a 4chan friendly webm file + if the profile is called 4chan. + Create a directory of such example scripts, including 4chan webm one. + +On nvidia check if suspend fix is applied. If not, show a popup asking the user to apply it (and apply it automatically). + +Show warning when using steam deck or when trying to capture hevc/av1 on amd (the same warnings as gpu screen recorder gtk). + +Add option to capture application audio. This should show a popup where you can use one of the available applications or a custom one and choose to record that application or all applications except that one. + +Add profile option. Convert view to profile, add an option at the bottom that says "Edit profiles..." which should show a popup where you can create/remove profiles. New profiles should always be in advanced view. + +Verify monitor/audio when starting recording. Give an error if the options are no longer valid. + +Add option to record focused monitor. This is less error prone when plugging in monitors, etc.
\ No newline at end of file diff --git a/depends/mglpp b/depends/mglpp -Subproject 23b75905a53abb2e4d5a44b16e0496e7fa4c7e3 +Subproject 84a6eb51b0c54e8f2c5134ff9e3baf39f5da77c diff --git a/include/Config.hpp b/include/Config.hpp index 785af69..fbfc86f 100644 --- a/include/Config.hpp +++ b/include/Config.hpp @@ -23,8 +23,11 @@ namespace gsr { int32_t fps = 60; int32_t video_bitrate = 15000; bool merge_audio_tracks = true; + bool application_audio_invert = false; bool change_video_resolution = false; + std::string audio_type_view = "audio_devices"; std::vector<std::string> audio_tracks; + std::vector<std::string> application_audio; std::string color_range = "limited"; std::string video_quality = "very_high"; std::string video_codec = "auto"; diff --git a/include/GsrInfo.hpp b/include/GsrInfo.hpp index fb12cd4..c3da6d7 100644 --- a/include/GsrInfo.hpp +++ b/include/GsrInfo.hpp @@ -76,4 +76,5 @@ namespace gsr { GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info); std::vector<AudioDevice> get_audio_devices(); + std::vector<std::string> get_application_audio(); }
\ No newline at end of file diff --git a/include/Overlay.hpp b/include/Overlay.hpp index eafb4ab..823e3a6 100644 --- a/include/Overlay.hpp +++ b/include/Overlay.hpp @@ -90,14 +90,13 @@ namespace gsr { std::string resources_path; GsrInfo gsr_info; egl_functions egl_funcs; - std::vector<gsr::AudioDevice> audio_devices; mgl::Texture window_texture_texture; mgl::Sprite window_texture_sprite; mgl::Texture screenshot_texture; mgl::Sprite screenshot_sprite; mgl::Rectangle bg_screenshot_overlay; WindowTexture window_texture; - gsr::PageStack page_stack; + PageStack page_stack; mgl::Rectangle top_bar_background; mgl::Text top_bar_text; mgl::Sprite logo_sprite; diff --git a/include/gui/Label.hpp b/include/gui/Label.hpp index a702497..f9045e0 100644 --- a/include/gui/Label.hpp +++ b/include/gui/Label.hpp @@ -19,6 +19,7 @@ namespace gsr { mgl::vec2f get_size() override; void set_text(std::string str); + const std::string& get_text() const; private: mgl::Text text; }; diff --git a/include/gui/LineSeparator.hpp b/include/gui/LineSeparator.hpp new file mode 100644 index 0000000..8c39114 --- /dev/null +++ b/include/gui/LineSeparator.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "Widget.hpp" + +namespace gsr { + class LineSeparator : public Widget { + public: + enum class Type { + HORIZONTAL + }; + + LineSeparator(Type type, float width); + LineSeparator(const LineSeparator&) = delete; + LineSeparator& operator=(const LineSeparator&) = delete; + + bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override; + void draw(mgl::Window &window, mgl::vec2f offset) override; + + mgl::vec2f get_size() override; + private: + Type type; + float width; + }; +}
\ No newline at end of file diff --git a/include/gui/SettingsPage.hpp b/include/gui/SettingsPage.hpp index 467463f..2fba93b 100644 --- a/include/gui/SettingsPage.hpp +++ b/include/gui/SettingsPage.hpp @@ -24,7 +24,7 @@ namespace gsr { STREAM }; - SettingsPage(Type type, const GsrInfo &gsr_info, std::vector<AudioDevice> audio_devices, Config &config, PageStack *page_stack); + SettingsPage(Type type, const GsrInfo &gsr_info, Config &config, PageStack *page_stack); SettingsPage(const SettingsPage&) = delete; SettingsPage& operator=(const SettingsPage&) = delete; @@ -48,13 +48,23 @@ namespace gsr { std::unique_ptr<List> create_restore_portal_session_section(); std::unique_ptr<Widget> create_change_video_resolution_section(); std::unique_ptr<Widget> create_capture_target(const GsrInfo &gsr_info); - std::unique_ptr<ComboBox> create_audio_track_selection_checkbox(); - std::unique_ptr<Button> create_remove_audio_track_button(List *audio_device_list_ptr); - std::unique_ptr<List> create_audio_track(); - std::unique_ptr<Button> create_add_audio_track_button(); - std::unique_ptr<List> create_audio_track_section(); + std::unique_ptr<ComboBox> create_audio_device_selection_combobox(); + std::unique_ptr<Button> create_remove_audio_device_button(List *audio_device_list_ptr); + std::unique_ptr<List> create_audio_device(); + std::unique_ptr<Button> create_add_audio_device_button(); + std::unique_ptr<List> create_audio_device_track_section(); std::unique_ptr<CheckBox> create_merge_audio_tracks_checkbox(); + std::unique_ptr<RadioButton> create_audio_type_button(); std::unique_ptr<Widget> create_audio_device_section(); + std::unique_ptr<List> create_application_audio_track_section(); + std::unique_ptr<CheckBox> create_application_audio_invert_checkbox(); + std::unique_ptr<List> create_application_audio_section(); + std::unique_ptr<ComboBox> create_application_audio_selection_combobox(); + std::unique_ptr<Button> create_remove_application_audio_button(List *app_audio_item); + std::unique_ptr<List> create_application_audio(); + std::unique_ptr<List> create_custom_application_audio(); + std::unique_ptr<List> create_add_application_audio_buttons(); + std::unique_ptr<Widget> create_audio_section(); std::unique_ptr<List> create_video_quality_box(); std::unique_ptr<Entry> create_video_bitrate_entry(); std::unique_ptr<List> create_video_bitrate(); @@ -98,7 +108,8 @@ namespace gsr { std::unique_ptr<List> create_stream_container_section(); void add_stream_widgets(); - void load_audio_tracks(RecordOptions &record_options); + void load_audio_device_tracks(RecordOptions &record_options); + void load_application_audio_tracks(RecordOptions &record_options); void load_common(RecordOptions &record_options); void load_replay(); void load_record(); @@ -112,6 +123,7 @@ namespace gsr { Type type; Config &config; std::vector<AudioDevice> audio_devices; + std::vector<std::string> application_audio; GsrPage *content_page_ptr = nullptr; ScrollablePage *settings_scrollable_page_ptr = nullptr; @@ -133,7 +145,12 @@ namespace gsr { Entry *video_bitrate_entry_ptr = nullptr; List *video_bitrate_list_ptr = nullptr; List *audio_devices_list_ptr = nullptr; + List *audio_devices_section_list_ptr = nullptr; + List *application_audio_section_list_ptr = nullptr; CheckBox *merge_audio_tracks_checkbox_ptr = nullptr; + RadioButton *audio_type_radio_button_ptr = nullptr; + List *application_audio_list_ptr = nullptr; + CheckBox *application_audio_invert_checkbox_ptr = nullptr; CheckBox *change_video_resolution_checkbox_ptr = nullptr; ComboBox *color_range_box_ptr = nullptr; ComboBox *video_quality_box_ptr = nullptr; diff --git a/include/gui/Subsection.hpp b/include/gui/Subsection.hpp index 90cb798..4da6baf 100644 --- a/include/gui/Subsection.hpp +++ b/include/gui/Subsection.hpp @@ -16,6 +16,7 @@ namespace gsr { void draw(mgl::Window &window, mgl::vec2f offset) override; mgl::vec2f get_size() override; + mgl::vec2f get_inner_size() override; private: Label label; std::unique_ptr<Widget> inner_widget; diff --git a/meson.build b/meson.build index e64b9dc..92262c5 100644 --- a/meson.build +++ b/meson.build @@ -23,6 +23,7 @@ src = [ 'src/gui/Utils.cpp', 'src/gui/DropdownButton.cpp', 'src/gui/Label.cpp', + 'src/gui/LineSeparator.cpp', 'src/gui/CustomRendererWidget.cpp', 'src/gui/FileChooser.cpp', 'src/gui/SettingsPage.cpp', diff --git a/scripts/notify-saved-name.sh b/scripts/notify-saved-name.sh index 09ae9d2..c8ca399 100755 --- a/scripts/notify-saved-name.sh +++ b/scripts/notify-saved-name.sh @@ -6,7 +6,6 @@ filepath="$1" type="$2" file_name="$(basename "$filepath")" -file_dir="$(dirname "$filepath")" case "$type" in "regular") diff --git a/src/Config.cpp b/src/Config.cpp index 86d7732..3a0b70b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -57,8 +57,11 @@ namespace gsr { {"streaming.record_options.fps", &config.streaming_config.record_options.fps}, {"streaming.record_options.video_bitrate", &config.streaming_config.record_options.video_bitrate}, {"streaming.record_options.merge_audio_tracks", &config.streaming_config.record_options.merge_audio_tracks}, + {"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_type_view", &config.streaming_config.record_options.audio_type_view}, {"streaming.record_options.audio_track", &config.streaming_config.record_options.audio_tracks}, + {"streaming.record_options.application_audio", &config.streaming_config.record_options.application_audio}, {"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}, @@ -85,8 +88,11 @@ namespace gsr { {"record.record_options.fps", &config.record_config.record_options.fps}, {"record.record_options.video_bitrate", &config.record_config.record_options.video_bitrate}, {"record.record_options.merge_audio_tracks", &config.record_config.record_options.merge_audio_tracks}, + {"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_type_view", &config.record_config.record_options.audio_type_view}, {"record.record_options.audio_track", &config.record_config.record_options.audio_tracks}, + {"record.record_options.application_audio", &config.record_config.record_options.application_audio}, {"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}, @@ -112,8 +118,11 @@ namespace gsr { {"replay.record_options.fps", &config.replay_config.record_options.fps}, {"replay.record_options.video_bitrate", &config.replay_config.record_options.video_bitrate}, {"replay.record_options.merge_audio_tracks", &config.replay_config.record_options.merge_audio_tracks}, + {"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_type_view", &config.replay_config.record_options.audio_type_view}, {"replay.record_options.audio_track", &config.replay_config.record_options.audio_tracks}, + {"replay.record_options.application_audio", &config.replay_config.record_options.application_audio}, {"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}, diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index 916430c..bb410dc 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -218,4 +218,30 @@ namespace gsr { return audio_devices; } + + std::vector<std::string> get_application_audio() { + std::vector<std::string> application_audio; + + FILE *f = popen("gpu-screen-recorder --list-application-audio", "r"); + if(!f) { + fprintf(stderr, "error: 'gpu-screen-recorder --list-application-audio' failed\n"); + return application_audio; + } + + char output[16384]; + ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f); + if(bytes_read < 0 || ferror(f)) { + fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-application-audio' output\n"); + pclose(f); + return application_audio; + } + output[bytes_read] = '\0'; + + string_split_char({output, (size_t)bytes_read}, '\n', [&](std::string_view line) { + application_audio.emplace_back(line); + return true; + }); + + return application_audio; + } } diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 16dcfe4..e6a218c 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -130,6 +130,15 @@ namespace gsr { && diff_int(geometry.width, monitor->size.x, margin) && diff_int(geometry.height, monitor->size.y, margin); } + static void set_focused_window(Display *dpy, Window window) { + XSetInputFocus(dpy, window, RevertToParent, CurrentTime); + + const Atom net_active_window_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + XChangeProperty(dpy, DefaultRootWindow(dpy), net_active_window_atom, XA_WINDOW, 32, PropModeReplace, (const unsigned char*)&window, 1); + + XFlush(dpy); + } + #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define _NET_WM_STATE_TOGGLE 2 @@ -370,8 +379,6 @@ namespace gsr { update_compositor_texture(focused_monitor); - audio_devices = get_audio_devices(); - top_bar_text = mgl::Text("GPU Screen Recorder", get_theme().top_bar_font); logo_sprite = mgl::Sprite(&get_theme().logo_texture); @@ -418,7 +425,7 @@ namespace gsr { button->set_item_icon("save", &get_theme().save_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack); + auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, config, &page_stack); page_stack.push(std::move(replay_settings_page)); } else if(id == "save") { on_press_save_replay(); @@ -439,7 +446,7 @@ namespace gsr { button->set_item_icon("pause", &get_theme().pause_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, gsr_info, audio_devices, config, &page_stack); + auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, gsr_info, config, &page_stack); page_stack.push(std::move(record_settings_page)); } else if(id == "pause") { toggle_pause(); @@ -458,7 +465,7 @@ namespace gsr { button->set_item_icon("start", &get_theme().play_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { - auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, gsr_info, audio_devices, config, &page_stack); + auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, gsr_info, config, &page_stack); page_stack.push(std::move(stream_settings_page)); } else if(id == "start") { on_press_start_stream(); @@ -521,7 +528,7 @@ namespace gsr { // TODO: This breaks global hotkeys //XGrabKeyboard(display, window->get_system_handle(), True, GrabModeAsync, GrabModeAsync, CurrentTime); - XSetInputFocus(display, window->get_system_handle(), RevertToPointerRoot, CurrentTime); + set_focused_window(display, window->get_system_handle()); XFlush(display); //window->set_fullscreen(true); @@ -864,6 +871,46 @@ namespace gsr { kill(gpu_screen_recorder_process, SIGUSR1); } + static void add_common_gpu_screen_recorder_args(RecordOptions &record_options, std::vector<const char*> &args, const std::string &video_bitrate, const char *region, const std::string &audio_devices_merged, const std::string &application_audio_merged) { + if(record_options.video_quality == "custom") { + args.push_back("-bm"); + args.push_back("cbr"); + args.push_back("-q"); + args.push_back(video_bitrate.c_str()); + } else { + args.push_back("-q"); + args.push_back(record_options.video_quality.c_str()); + } + + if(record_options.record_area_option == "focused" || record_options.change_video_resolution) { + args.push_back("-s"); + args.push_back(region); + } + + if(record_options.audio_type_view == "audio_devices") { + if(record_options.merge_audio_tracks) { + args.push_back("-a"); + args.push_back(audio_devices_merged.c_str()); + } else { + for(const std::string &audio_track : record_options.audio_tracks) { + args.push_back("-a"); + args.push_back(audio_track.c_str()); + } + } + } else if(record_options.audio_type_view == "app_audio") { + const char *app_audio_option = record_options.application_audio_invert ? "-aai" : "-aa"; + if(record_options.merge_audio_tracks) { + args.push_back(app_audio_option); + args.push_back(application_audio_merged.c_str()); + } else { + for(const std::string &app_audio : record_options.application_audio) { + args.push_back(app_audio_option); + args.push_back(app_audio.c_str()); + } + } + } + } + void Overlay::on_press_start_replay(bool disable_notification) { switch(recording_status) { case RecordingStatus::NONE: @@ -900,13 +947,12 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // TODO: Validate input, fallback to valid values 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::string audio_tracks_merged = merge_audio_tracks(config.replay_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.replay_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.replay_config.record_options.application_audio); 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(); @@ -937,30 +983,7 @@ namespace gsr { "-o", output_directory.c_str() }; - if(config.replay_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.replay_config.record_options.video_quality.c_str()); - } - - if(config.replay_config.record_options.record_area_option == "focused" || config.replay_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.replay_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.replay_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.replay_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); setenv("GSR_SHOW_SAVED_NOTIFICATION", config.replay_config.show_replay_saved_notifications ? "1" : "0", true); const std::string script_to_run_on_save = resources_path + (config.replay_config.save_video_in_game_folder ? "scripts/save-video-in-game-folder.sh" : "scripts/notify-saved-name.sh"); @@ -1025,13 +1048,12 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // TODO: Validate input, fallback to valid values 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::string audio_tracks_merged = merge_audio_tracks(config.record_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.record_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.record_config.record_options.application_audio); 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"; @@ -1060,30 +1082,7 @@ namespace gsr { "-o", output_file.c_str() }; - if(config.record_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.record_config.record_options.video_quality.c_str()); - } - - if(config.record_config.record_options.record_area_option == "focused" || config.record_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.record_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.record_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.record_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); setenv("GSR_SHOW_SAVED_NOTIFICATION", config.record_config.show_video_saved_notifications ? "1" : "0", true); const std::string script_to_run_on_save = resources_path + (config.record_config.save_video_in_game_folder ? "scripts/save-video-in-game-folder.sh" : "scripts/notify-saved-name.sh"); @@ -1178,12 +1177,11 @@ namespace gsr { return; } - audio_devices = get_audio_devices(); - // 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::string audio_tracks_merged = merge_audio_tracks(config.streaming_config.record_options.audio_tracks); + const std::string audio_devices_merged = merge_audio_tracks(config.streaming_config.record_options.audio_tracks); + const std::string application_audio_merged = merge_audio_tracks(config.streaming_config.record_options.application_audio); 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"; @@ -1218,30 +1216,7 @@ namespace gsr { "-o", url.c_str() }; - if(config.streaming_config.record_options.video_quality == "custom") { - args.push_back("-bm"); - args.push_back("cbr"); - args.push_back("-q"); - args.push_back(video_bitrate.c_str()); - } else { - args.push_back("-q"); - args.push_back(config.streaming_config.record_options.video_quality.c_str()); - } - - if(config.streaming_config.record_options.record_area_option == "focused" || config.streaming_config.record_options.change_video_resolution) { - args.push_back("-s"); - args.push_back(region); - } - - if(config.streaming_config.record_options.merge_audio_tracks) { - args.push_back("-a"); - args.push_back(audio_tracks_merged.c_str()); - } else { - for(const std::string &audio_track : config.streaming_config.record_options.audio_tracks) { - args.push_back("-a"); - args.push_back(audio_track.c_str()); - } - } + add_common_gpu_screen_recorder_args(config.streaming_config.record_options, args, video_bitrate, region, audio_devices_merged, application_audio_merged); args.push_back(nullptr); diff --git a/src/gui/CheckBox.cpp b/src/gui/CheckBox.cpp index 9ae3b41..e2f591c 100644 --- a/src/gui/CheckBox.cpp +++ b/src/gui/CheckBox.cpp @@ -10,7 +10,7 @@ namespace gsr { static const float spacing_scale = 0.005f; static const float check_animation_speed = 10.0f; - static mgl::Color color_multiply(mgl::Color color, float multiply) { + static mgl::Color color_multiply_ignore_alpha(mgl::Color color, float multiply) { return mgl::Color(color.r * multiply, color.g * multiply, color.b * multiply, color.a); } @@ -18,12 +18,12 @@ namespace gsr { return source + (destination - source) * interpolation; } - static mgl::Color interpolate_color(mgl::Color source, mgl::Color destination, float interpolation) { + static mgl::Color interpolate_color_ignore_alpha(mgl::Color source, mgl::Color destination, float interpolation) { mgl::Color color; color.r = linear_interpolation(source.r, destination.r, interpolation); color.g = linear_interpolation(source.g, destination.g, interpolation); color.b = linear_interpolation(source.b, destination.b, interpolation); - color.a = linear_interpolation(source.a, destination.a, interpolation); + color.a = source.a; return color; } @@ -61,9 +61,9 @@ namespace gsr { apply_animation(); - const mgl::Color background_color_unchecked(0, 0, 0, 120); - const mgl::Color background_color_checked = color_multiply(get_color_theme().tint_color, 0.6f); - background_sprite.set_color(interpolate_color(background_color_unchecked, background_color_checked, toggle_animation_value)); + const mgl::Color background_color_unchecked = color_multiply_ignore_alpha(mgl::Color(25, 30, 34), 0.6f); + const mgl::Color background_color_checked = color_multiply_ignore_alpha(get_color_theme().tint_color, 0.6f); + background_sprite.set_color(interpolate_color_ignore_alpha(background_color_unchecked, background_color_checked, toggle_animation_value)); background_sprite.set_position(draw_pos.floor()); window.draw(background_sprite); diff --git a/src/gui/Label.cpp b/src/gui/Label.cpp index 22a302f..773c2f9 100644 --- a/src/gui/Label.cpp +++ b/src/gui/Label.cpp @@ -22,6 +22,10 @@ namespace gsr { text.set_string(std::move(str)); } + const std::string& Label::get_text() const { + return text.get_string(); + } + mgl::vec2f Label::get_size() { if(!visible) return {0.0f, 0.0f}; diff --git a/src/gui/LineSeparator.cpp b/src/gui/LineSeparator.cpp new file mode 100644 index 0000000..637c84f --- /dev/null +++ b/src/gui/LineSeparator.cpp @@ -0,0 +1,45 @@ +#include "../../include/gui/LineSeparator.hpp" +#include "../../include/Theme.hpp" + +#include <mglpp/window/Window.hpp> +#include <mglpp/graphics/Rectangle.hpp> + +namespace gsr { + static const float height_scale = 0.001f; + + static mgl::Color color_add_ignore_alpha(mgl::Color color, mgl::Color add) { + return { + (uint8_t)std::min((int)color.r + (int)add.r, 255), + (uint8_t)std::min((int)color.g + (int)add.g, 255), + (uint8_t)std::min((int)color.b + (int)add.b, 255), + color.a + }; + } + + LineSeparator::LineSeparator(Type type, float width) : type(type), width(width) { + + } + + bool LineSeparator::on_event(mgl::Event&, mgl::Window&, mgl::vec2f) { + return true; + } + + void LineSeparator::draw(mgl::Window &window, mgl::vec2f offset) { + if(!visible) + return; + + const mgl::vec2f draw_pos = (position + offset).floor(); + const mgl::vec2f size = mgl::vec2f(width, std::max(1.0f, height_scale * get_theme().window_height)).floor(); + mgl::Rectangle rectangle(draw_pos, size); + rectangle.set_color(color_add_ignore_alpha(mgl::Color(25, 30, 34), mgl::Color(30, 30, 30))); + window.draw(rectangle); + } + + mgl::vec2f LineSeparator::get_size() { + if(!visible) + return {0.0f, 0.0f}; + + const mgl::vec2f size = mgl::vec2f(width, std::max(1.0f, height_scale * get_theme().window_height)).floor(); + return size; + } +}
\ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index a08bd52..083fec5 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -1,6 +1,7 @@ #include "../../include/gui/SettingsPage.hpp" #include "../../include/gui/GsrPage.hpp" #include "../../include/gui/Label.hpp" +#include "../../include/gui/LineSeparator.hpp" #include "../../include/gui/PageStack.hpp" #include "../../include/gui/FileChooser.hpp" #include "../../include/gui/Subsection.hpp" @@ -13,15 +14,19 @@ #include <mglpp/graphics/Text.hpp> #include <mglpp/window/Window.hpp> +#include <string.h> + namespace gsr { - SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, std::vector<AudioDevice> audio_devices, Config &config, PageStack *page_stack) : + SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, Config &config, PageStack *page_stack) : StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), type(type), config(config), - audio_devices(std::move(audio_devices)), page_stack(page_stack), settings_title_text("Settings", get_theme().title_font) { + audio_devices = get_audio_devices(); + application_audio = get_application_audio(); + auto content_page = std::make_unique<GsrPage>(); content_page->add_button("Back", "back", get_color_theme().page_bg_color); content_page->on_click = [page_stack](const std::string &id) { @@ -177,7 +182,7 @@ 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_track_selection_checkbox() { + std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox() { 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); @@ -185,7 +190,7 @@ namespace gsr { return audio_device_box; } - std::unique_ptr<Button> SettingsPage::create_remove_audio_track_button(List *audio_device_list_ptr) { + 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_devices_list_ptr->remove_widget(audio_device_list_ptr); @@ -193,26 +198,25 @@ namespace gsr { return remove_audio_track_button; } - std::unique_ptr<List> SettingsPage::create_audio_track() { + std::unique_ptr<List> SettingsPage::create_audio_device() { auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); - audio_device_list->add_widget(create_audio_track_selection_checkbox()); - audio_device_list->add_widget(create_remove_audio_track_button(audio_device_list.get())); + audio_device_list->add_widget(create_audio_device_selection_combobox()); + audio_device_list->add_widget(create_remove_audio_device_button(audio_device_list.get())); return audio_device_list; } - std::unique_ptr<Button> SettingsPage::create_add_audio_track_button() { - 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 = [this]() { - audio_devices_list_ptr->add_widget(create_audio_track()); + 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]() { + audio_devices_list_ptr->add_widget(create_audio_device()); }; - add_audio_track_button->on_click = add_audio_track; return add_audio_track_button; } - std::unique_ptr<List> SettingsPage::create_audio_track_section() { + std::unique_ptr<List> SettingsPage::create_audio_device_track_section() { 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_list_ptr->add_widget(create_audio_device()); return audio_devices_list; } @@ -223,13 +227,107 @@ namespace gsr { return merge_audio_tracks_checkbox; } + std::unique_ptr<RadioButton> SettingsPage::create_audio_type_button() { + auto audio_type_radio_button = std::make_unique<RadioButton>(&get_theme().body_font); + audio_type_radio_button->add_item("Audio devices", "audio_devices"); + audio_type_radio_button->add_item("Application audio", "app_audio"); + audio_type_radio_button_ptr = audio_type_radio_button.get(); + return audio_type_radio_button; + } + std::unique_ptr<Widget> SettingsPage::create_audio_device_section() { + auto audio_devices_section_list = std::make_unique<List>(List::Orientation::VERTICAL); + audio_devices_section_list_ptr = audio_devices_section_list.get(); + audio_devices_section_list->add_widget(std::make_unique<Label>(&get_theme().title_font, "Audio devices", get_color_theme().text_color)); + audio_devices_section_list->add_widget(create_add_audio_device_button()); + audio_devices_section_list->add_widget(create_audio_device_track_section()); + return audio_devices_section_list; + } + + std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox() { + auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); + for(const auto &app_audio : application_audio) { + audio_device_box->add_item(app_audio, app_audio); + } + return audio_device_box; + } + + std::unique_ptr<Button> SettingsPage::create_remove_application_audio_button(List *app_audio_item) { + 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, app_audio_item]() { + application_audio_list_ptr->remove_widget(app_audio_item); + }; + return remove_audio_track_button; + } + + std::unique_ptr<List> SettingsPage::create_application_audio() { + auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + application_audio_list->add_widget(create_application_audio_selection_combobox()); + application_audio_list->add_widget(create_remove_application_audio_button(application_audio_list.get())); + return application_audio_list; + } + + std::unique_ptr<List> SettingsPage::create_custom_application_audio() { + auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + 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_application_audio_button(application_audio_list.get())); + return application_audio_list; + } + + std::unique_ptr<List> SettingsPage::create_add_application_audio_buttons() { + auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + + auto add_application_audio_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->on_click = [this]() { + application_audio_list_ptr->add_widget(create_application_audio()); + }; + list->add_widget(std::move(add_application_audio_button)); + + auto add_custom_application_audio_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->on_click = [this]() { + application_audio_list_ptr->add_widget(create_custom_application_audio()); + }; + list->add_widget(std::move(add_custom_application_audio_button)); + + return list; + } + + std::unique_ptr<List> SettingsPage::create_application_audio_track_section() { + auto application_audio_list = std::make_unique<List>(List::Orientation::VERTICAL); + application_audio_list_ptr = application_audio_list.get(); + return application_audio_list; + } + + std::unique_ptr<CheckBox> SettingsPage::create_application_audio_invert_checkbox() { + auto application_audio_invert_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record 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<List> SettingsPage::create_application_audio_section() { + auto application_audio_section_list = std::make_unique<List>(List::Orientation::VERTICAL); + application_audio_section_list_ptr = application_audio_section_list.get(); + application_audio_section_list->add_widget(std::make_unique<Label>(&get_theme().title_font, "Application audio", get_color_theme().text_color)); + application_audio_section_list->add_widget(create_add_application_audio_buttons()); + application_audio_section_list->add_widget(create_application_audio_track_section()); + application_audio_section_list->add_widget(create_application_audio_invert_checkbox()); + return application_audio_section_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_add_audio_track_button()); - audio_device_section_list->add_widget(create_audio_track_section()); - audio_device_section_list->add_widget(create_merge_audio_tracks_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 audio_section = std::make_unique<Subsection>("Audio", std::move(audio_device_section_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); + + audio_device_section_list_ptr->add_widget(create_audio_type_button()); + audio_device_section_list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Type::HORIZONTAL, audio_section->get_inner_size().x)); + audio_device_section_list_ptr->add_widget(create_audio_device_section()); + audio_device_section_list_ptr->add_widget(create_application_audio_section()); + //audio_device_section_list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Type::HORIZONTAL, audio_section->get_inner_size().x)); + audio_device_section_list_ptr->add_widget(create_merge_audio_tracks_checkbox()); + audio_device_section_list_ptr->add_widget(create_audio_codec()); + return audio_section; } std::unique_ptr<List> SettingsPage::create_video_quality_box() { @@ -418,7 +516,7 @@ namespace gsr { auto settings_list = std::make_unique<List>(List::Orientation::VERTICAL); settings_list->set_spacing(0.018f); settings_list->add_widget(create_capture_target(gsr_info)); - settings_list->add_widget(create_audio_device_section()); + settings_list->add_widget(create_audio_section()); settings_list->add_widget(create_video_section(gsr_info)); settings_list_ptr = settings_list.get(); settings_scrollable_page_ptr->add_widget(std::move(settings_list)); @@ -463,6 +561,17 @@ namespace gsr { record_area_box_ptr->set_selected_item("window"); else record_area_box_ptr->on_selection_changed("", ""); + + audio_type_radio_button_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { + if(id == "audio_devices") { + audio_devices_section_list_ptr->set_visible(true); + application_audio_section_list_ptr->set_visible(false); + } else if(id == "app_audio") { + audio_devices_section_list_ptr->set_visible(false); + application_audio_section_list_ptr->set_visible(true); + } + }; + audio_type_radio_button_ptr->on_selection_changed("", "audio_devices"); } void SettingsPage::add_page_specific_widgets() { @@ -496,7 +605,8 @@ namespace gsr { select_directory_page->on_click = [this, file_chooser_ptr](const std::string &id) { if(id == "save") save_directory_button_ptr->set_text(file_chooser_ptr->get_current_directory()); - page_stack->pop(); + else if(id == "cancel") + page_stack->pop(); }; page_stack->push(std::move(select_directory_page)); @@ -811,22 +921,50 @@ namespace gsr { save_config(config); } - void SettingsPage::load_audio_tracks(RecordOptions &record_options) { + static const std::string* get_application_audio_by_name_case_insensitive(const std::vector<std::string> &application_audio, const std::string &name) { + for(const auto &app_audio : application_audio) { + if(strcasecmp(app_audio.c_str(), name.c_str()) == 0) + return &app_audio; + } + return nullptr; + } + + void SettingsPage::load_audio_device_tracks(RecordOptions &record_options) { audio_devices_list_ptr->clear(); for(const std::string &audio_track : record_options.audio_tracks) { - std::unique_ptr<List> audio_track_widget = create_audio_track(); + 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(0)); audio_device_box->set_selected_item(audio_track); audio_devices_list_ptr->add_widget(std::move(audio_track_widget)); } } + void SettingsPage::load_application_audio_tracks(RecordOptions &record_options) { + application_audio_list_ptr->clear(); + for(const std::string &audio_track : record_options.application_audio) { + const std::string *app_audio = get_application_audio_by_name_case_insensitive(application_audio, audio_track); + 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(0)); + application_audio_box->set_selected_item(*app_audio); + application_audio_list_ptr->add_widget(std::move(application_audio_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(0)); + application_audio_entry->set_text(audio_track); + application_audio_list_ptr->add_widget(std::move(application_audio_widget)); + } + } + } + void SettingsPage::load_common(RecordOptions &record_options) { record_area_box_ptr->set_selected_item(record_options.record_area_option); merge_audio_tracks_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); + audio_type_radio_button_ptr->set_selected_item(record_options.audio_type_view); + load_audio_device_tracks(record_options); + load_application_audio_tracks(record_options); color_range_box_ptr->set_selected_item(record_options.color_range); video_quality_box_ptr->set_selected_item(record_options.video_quality); video_codec_box_ptr->set_selected_item(record_options.video_codec); @@ -910,12 +1048,26 @@ namespace gsr { container_box_ptr->set_selected_item(config.streaming_config.custom.container); } - static void save_audio_tracks(std::vector<std::string> &audio_tracks, List *audio_devices_list_ptr) { - audio_tracks.clear(); - audio_devices_list_ptr->for_each_child_widget([&audio_tracks](std::unique_ptr<Widget> &child_widget) { + static void save_audio_device_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_device_line = static_cast<List*>(child_widget.get()); ComboBox *audio_device_box = static_cast<ComboBox*>(audio_device_line->get_child_widget_by_index(0)); - audio_tracks.push_back(audio_device_box->get_selected_id()); + audio_devices.push_back(audio_device_box->get_selected_id()); + return true; + }); + } + + static void save_application_audio_tracks(std::vector<std::string> &application_audio, List *application_audio_list_ptr) { + application_audio.clear(); + application_audio_list_ptr->for_each_child_widget([&application_audio](std::unique_ptr<Widget> &child_widget) { + List *application_audio_line = static_cast<List*>(child_widget.get()); + ComboBox *application_audio_box = dynamic_cast<ComboBox*>(application_audio_line->get_child_widget_by_index(0)); + Entry *application_audio_entry = dynamic_cast<Entry*>(application_audio_line->get_child_widget_by_index(0)); + if(application_audio_box) + application_audio.push_back(application_audio_box->get_selected_id()); + else if(application_audio_entry) + application_audio.push_back(application_audio_entry->get_text()); return true; }); } @@ -929,8 +1081,11 @@ namespace gsr { record_options.fps = atoi(framerate_entry_ptr->get_text().c_str()); record_options.video_bitrate = atoi(video_bitrate_entry_ptr->get_text().c_str()); record_options.merge_audio_tracks = merge_audio_tracks_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_devices_list_ptr); + record_options.audio_type_view = audio_type_radio_button_ptr->get_selected_id(); + save_audio_device_tracks(record_options.audio_tracks, audio_devices_list_ptr); + save_application_audio_tracks(record_options.application_audio, application_audio_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(); diff --git a/src/gui/Subsection.cpp b/src/gui/Subsection.cpp index 16d6828..15eac04 100644 --- a/src/gui/Subsection.cpp +++ b/src/gui/Subsection.cpp @@ -36,8 +36,11 @@ namespace gsr { window.draw(background); draw_pos += mgl::vec2f(margin_left_scale, margin_top_scale) * mgl::vec2f(get_theme().window_height, get_theme().window_height); - label.draw(window, draw_pos); - draw_pos.y += label.get_size().y + title_spacing_scale * get_theme().window_height; + + if(!label.get_text().empty()) { + label.draw(window, draw_pos); + draw_pos.y += label.get_size().y + title_spacing_scale * get_theme().window_height; + } inner_widget->set_position(draw_pos); inner_widget->draw(window, mgl::vec2f(0.0f, 0.0f)); @@ -48,7 +51,8 @@ namespace gsr { return {0.0f, 0.0f}; const mgl::vec2f margin_size = mgl::vec2f(margin_left_scale + margin_right_scale, margin_top_scale + margin_bottom_scale) * mgl::vec2f(get_theme().window_height, get_theme().window_height); - mgl::vec2f widgets_size = mgl::vec2f(0.0f, label.get_size().y + title_spacing_scale * get_theme().window_height) + inner_widget->get_size() + margin_size; + const float title_height = !label.get_text().empty() ? (label.get_size().y + title_spacing_scale * get_theme().window_height) : 0.0f; + mgl::vec2f widgets_size = mgl::vec2f(0.0f, title_height) + inner_widget->get_size() + margin_size; if(std::abs(size.x) > 0.001f) widgets_size.x = size.x; @@ -57,4 +61,12 @@ namespace gsr { return widgets_size; } + + mgl::vec2f Subsection::get_inner_size() { + if(!visible) + return {0.0f, 0.0f}; + + const mgl::vec2f margin_size = mgl::vec2f(margin_left_scale + margin_right_scale, margin_top_scale + margin_bottom_scale) * mgl::vec2f(get_theme().window_height, get_theme().window_height); + return get_size() - margin_size; + } }
\ No newline at end of file |