diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Config.cpp | 15 | ||||
-rw-r--r-- | src/GsrInfo.cpp | 167 | ||||
-rw-r--r-- | src/Overlay.cpp | 105 | ||||
-rw-r--r-- | src/Process.cpp | 48 | ||||
-rw-r--r-- | src/Theme.cpp | 48 | ||||
-rw-r--r-- | src/gui/Button.cpp | 44 | ||||
-rw-r--r-- | src/gui/GlobalSettingsPage.cpp | 83 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 146 | ||||
-rw-r--r-- | src/gui/Utils.cpp | 17 | ||||
-rw-r--r-- | src/main.cpp | 11 |
10 files changed, 481 insertions, 203 deletions
diff --git a/src/Config.cpp b/src/Config.cpp index 112688a..4deaaf4 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -13,7 +13,7 @@ #define CONFIG_FILE_VERSION 1 namespace gsr { - Config::Config(const GsrInfo &gsr_info) { + Config::Config(const SupportedCaptureOptions &capture_options) { const std::string default_save_directory = get_videos_dir(); streaming_config.record_options.video_quality = "custom"; @@ -29,10 +29,10 @@ namespace gsr { replay_config.record_options.audio_tracks.push_back("default_output"); replay_config.record_options.video_bitrate = 45000; - if(!gsr_info.supported_capture_options.monitors.empty()) { - streaming_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name; - record_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name; - replay_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name; + if(!capture_options.monitors.empty()) { + streaming_config.record_options.record_area_option = capture_options.monitors.front().name; + record_config.record_options.record_area_option = capture_options.monitors.front().name; + replay_config.record_options.record_area_option = capture_options.monitors.front().name; } } @@ -49,6 +49,7 @@ namespace gsr { return { {"main.config_file_version", &config.main_config.config_file_version}, {"main.software_encoding_warning_shown", &config.main_config.software_encoding_warning_shown}, + {"main.tint_color", &config.main_config.tint_color}, {"streaming.record_options.record_area_option", &config.streaming_config.record_options.record_area_option}, {"streaming.record_options.record_area_width", &config.streaming_config.record_options.record_area_width}, @@ -140,7 +141,7 @@ namespace gsr { }; } - std::optional<Config> read_config(const GsrInfo &gsr_info) { + std::optional<Config> read_config(const SupportedCaptureOptions &capture_options) { std::optional<Config> config; const std::string config_path = get_config_dir() + "/config_ui"; @@ -150,7 +151,7 @@ namespace gsr { return config; } - config = Config(gsr_info); + 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(); diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp index 276870b..c35ccfb 100644 --- a/src/GsrInfo.cpp +++ b/src/GsrInfo.cpp @@ -1,5 +1,7 @@ #include "../include/GsrInfo.hpp" #include "../include/Utils.hpp" +#include "../include/Process.hpp" + #include <optional> #include <string.h> @@ -38,6 +40,8 @@ namespace gsr { gsr_info->gpu_info.vendor = GpuVendor::INTEL; else if(key_value->value == "nvidia") gsr_info->gpu_info.vendor = GpuVendor::NVIDIA; + } else if(key_value->key == "card_path") { + gsr_info->gpu_info.card_path = key_value->value; } } @@ -64,38 +68,6 @@ namespace gsr { gsr_info->supported_video_codecs.vp9 = true; } - static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) { - std::optional<GsrMonitor> monitor; - const std::optional<KeyValue> key_value = parse_key_value(line); - if(!key_value) - return monitor; - - char value_buffer[256]; - snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value->value.size(), key_value->value.data()); - - monitor = GsrMonitor{std::string(key_value->key), mgl::vec2i{0, 0}}; - if(sscanf(value_buffer, "%dx%d", &monitor->size.x, &monitor->size.y) != 2) - monitor->size = {0, 0}; - - return monitor; - } - - static void parse_capture_options_line(GsrInfo *gsr_info, std::string_view line) { - if(line == "window") - gsr_info->supported_capture_options.window = true; - else if(line == "focused") - gsr_info->supported_capture_options.focused = true; - else if(line == "screen") - gsr_info->supported_capture_options.screen = true; - else if(line == "portal") - gsr_info->supported_capture_options.portal = true; - else { - std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line); - if(monitor) - gsr_info->supported_capture_options.monitors.push_back(std::move(monitor.value())); - } - } - enum class GsrInfoSection { UNKNOWN, SYSTEM_INFO, @@ -112,23 +84,19 @@ namespace gsr { GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info) { *gsr_info = GsrInfo{}; - FILE *f = popen("gpu-screen-recorder --info", "r"); - if(!f) { - fprintf(stderr, "error: 'gpu-screen-recorder --info' failed\n"); - return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; - } - - char output[8192]; - 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 --info' output\n"); - pclose(f); - return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; + std::string stdout_str; + const char *args[] = { "gpu-screen-recorder", "--info", nullptr }; + const int exit_status = exec_program_get_stdout(args, stdout_str); + switch(exit_status) { + case 0: break; + case 14: return GsrInfoExitStatus::BROKEN_DRIVERS; + case 22: return GsrInfoExitStatus::OPENGL_FAILED; + case 23: return GsrInfoExitStatus::NO_DRM_CARD; + default: return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; } - output[bytes_read] = '\0'; GsrInfoSection section = GsrInfoSection::UNKNOWN; - string_split_char({output, (size_t)bytes_read}, '\n', [&](std::string_view line) { + string_split_char(stdout_str, '\n', [&](std::string_view line) { if(starts_with(line, "section=")) { const std::string_view section_name = line.substr(8); if(section_name == "system_info") @@ -161,7 +129,7 @@ namespace gsr { break; } case GsrInfoSection::CAPTURE_OPTIONS: { - parse_capture_options_line(gsr_info, line); + // Intentionally ignore, get capture options with get_supported_capture_options instead break; } } @@ -169,18 +137,7 @@ namespace gsr { return true; }); - int status = pclose(f); - if(WIFEXITED(status)) { - switch(WEXITSTATUS(status)) { - case 0: return GsrInfoExitStatus::OK; - case 14: return GsrInfoExitStatus::BROKEN_DRIVERS; - case 22: return GsrInfoExitStatus::OPENGL_FAILED; - case 23: return GsrInfoExitStatus::NO_DRM_CARD; - default: return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; - } - } - - return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND; + return GsrInfoExitStatus::OK; } static std::optional<AudioDevice> parse_audio_device_line(std::string_view line) { @@ -196,22 +153,14 @@ namespace gsr { std::vector<AudioDevice> get_audio_devices() { std::vector<AudioDevice> audio_devices; - FILE *f = popen("gpu-screen-recorder --list-audio-devices", "r"); - if(!f) { + std::string stdout_str; + const char *args[] = { "gpu-screen-recorder", "--list-audio-devices", nullptr }; + if(exec_program_get_stdout(args, stdout_str) != 0) { fprintf(stderr, "error: 'gpu-screen-recorder --list-audio-devices' failed\n"); return audio_devices; } - 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-audio-devices' output\n"); - pclose(f); - return audio_devices; - } - output[bytes_read] = '\0'; - - string_split_char({output, (size_t)bytes_read}, '\n', [&](std::string_view line) { + string_split_char(stdout_str, '\n', [&](std::string_view line) { std::optional<AudioDevice> audio_device = parse_audio_device_line(line); if(audio_device) audio_devices.push_back(std::move(audio_device.value())); @@ -224,26 +173,78 @@ namespace gsr { 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) { + std::string stdout_str; + const char *args[] = { "gpu-screen-recorder", "--list-application-audio", nullptr }; + if(exec_program_get_stdout(args, stdout_str) != 0) { 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) { + string_split_char(stdout_str, '\n', [&](std::string_view line) { application_audio.emplace_back(line); return true; }); return application_audio; } + + static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) { + std::optional<GsrMonitor> monitor; + const std::optional<KeyValue> key_value = parse_key_value(line); + if(!key_value) + return monitor; + + char value_buffer[256]; + snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value->value.size(), key_value->value.data()); + + monitor = GsrMonitor{std::string(key_value->key), mgl::vec2i{0, 0}}; + if(sscanf(value_buffer, "%dx%d", &monitor->size.x, &monitor->size.y) != 2) + monitor->size = {0, 0}; + + return monitor; + } + + static void parse_capture_options_line(SupportedCaptureOptions &capture_options, std::string_view line) { + if(line == "window") + capture_options.window = true; + else if(line == "focused") + capture_options.focused = true; + else if(line == "screen") + capture_options.screen = true; + else if(line == "portal") + capture_options.portal = true; + else { + std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line); + if(monitor) + capture_options.monitors.push_back(std::move(monitor.value())); + } + } + + static const char* gpu_vendor_to_string(GpuVendor vendor) { + switch(vendor) { + case GpuVendor::UNKNOWN: return "unknown"; + case GpuVendor::AMD: return "amd"; + case GpuVendor::INTEL: return "intel"; + case GpuVendor::NVIDIA: return "nvidia"; + } + return "unknown"; + } + + SupportedCaptureOptions get_supported_capture_options(const GsrInfo &gsr_info) { + SupportedCaptureOptions capture_options; + + std::string stdout_str; + const char *args[] = { "gpu-screen-recorder", "--list-capture-options", gsr_info.gpu_info.card_path.c_str(), gpu_vendor_to_string(gsr_info.gpu_info.vendor), nullptr }; + if(exec_program_get_stdout(args, stdout_str) != 0) { + fprintf(stderr, "error: 'gpu-screen-recorder --list-capture-options' failed\n"); + return capture_options; + } + + string_split_char(stdout_str, '\n', [&](std::string_view line) { + parse_capture_options_line(capture_options, line); + return true; + }); + + return capture_options; + } } diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 5a2783b..88625d6 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -7,8 +7,10 @@ #include "../include/gui/DropdownButton.hpp" #include "../include/gui/CustomRendererWidget.hpp" #include "../include/gui/SettingsPage.hpp" +#include "../include/gui/GlobalSettingsPage.hpp" #include "../include/gui/Utils.hpp" #include "../include/gui/PageStack.hpp" +#include "../include/gui/GsrPage.hpp" #include "../include/WindowUtils.hpp" #include "../include/GlobalHotkeys.hpp" @@ -17,6 +19,7 @@ #include <sys/wait.h> #include <limits.h> #include <fcntl.h> +#include <poll.h> #include <stdexcept> #include <X11/Xlib.h> @@ -297,10 +300,11 @@ namespace gsr { } static mgl::vec2i create_window_get_center_position(Display *display) { - const int screen = DefaultScreen(display); + const int size = 16; XSetWindowAttributes window_attr; window_attr.event_mask = StructureNotifyMask; - const Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 32, 32, 0, DefaultDepth(display, screen), InputOutput, DefaultVisual(display, screen), CWEventMask, &window_attr); + window_attr.background_pixel = 0; + const Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, size, size, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackPixel | CWEventMask, &window_attr); if(!window) return {0, 0}; @@ -319,12 +323,36 @@ namespace gsr { const unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha); XChangeProperty(display, window, net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1L); + XSizeHints *size_hints = XAllocSizeHints(); + size_hints->width = size; + size_hints->min_width = size; + size_hints->max_width = size; + size_hints->height = size; + size_hints->min_height = size; + size_hints->max_height = size; + size_hints->flags = PSize | PMinSize | PMaxSize; + XSetWMNormalHints(display, window, size_hints); + XFree(size_hints); + XMapWindow(display, window); XFlush(display); + const int x_fd = XConnectionNumber(display); mgl::vec2i window_pos; XEvent xev; while(true) { + struct pollfd poll_fd; + poll_fd.fd = x_fd; + poll_fd.events = POLLIN; + poll_fd.revents = 0; + const int fds_ready = poll(&poll_fd, 1, 1000); + if(fds_ready == 0) { + fprintf(stderr, "Error: timed out waiting for ConfigureNotify after XCreateWindow\n"); + break; + } else if(fds_ready == -1 || !(poll_fd.revents & POLLIN)) { + continue; + } + XNextEvent(display, &xev); if(xev.type == ConfigureNotify) { window_pos.x = xev.xconfigure.x + xev.xconfigure.width / 2; @@ -394,11 +422,11 @@ namespace gsr { return true; } - Overlay::Overlay(std::string resources_path, GsrInfo gsr_info, egl_functions egl_funcs) : + Overlay::Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs) : resources_path(std::move(resources_path)), - gsr_info(gsr_info), + gsr_info(std::move(gsr_info)), egl_funcs(egl_funcs), - config(gsr_info), + config(capture_options), bg_screenshot_overlay({0.0f, 0.0f}), top_bar_background({0.0f, 0.0f}), close_button_widget({0.0f, 0.0f}) @@ -417,11 +445,11 @@ namespace gsr { memset(&window_texture, 0, sizeof(window_texture)); - std::optional<Config> new_config = read_config(gsr_info); + std::optional<Config> new_config = read_config(capture_options); if(new_config) config = std::move(new_config.value()); - init_color_theme(gsr_info); + init_color_theme(config, this->gsr_info); power_supply_online_filepath = get_power_supply_online_filepath(); @@ -864,6 +892,7 @@ namespace gsr { const int button_width = button_height; auto main_buttons_list = std::make_unique<List>(List::Orientation::HORIZONTAL); + List * main_buttons_list_ptr = main_buttons_list.get(); main_buttons_list->set_spacing(0.0f); { auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, "Instant Replay", "Off", &get_theme().replay_button_texture, @@ -876,7 +905,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, 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(); @@ -897,7 +926,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, 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(); @@ -916,7 +945,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, 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(); @@ -929,6 +958,20 @@ namespace gsr { main_buttons_list->set_position((mgl::vec2f(window_size.x * 0.5f, window_size.y * 0.25f) - main_buttons_list_size * 0.5f).floor()); front_page_ptr->add_widget(std::move(main_buttons_list)); + { + const mgl::vec2f main_buttons_size = main_buttons_list_ptr->get_size(); + const int settings_button_size = main_buttons_size.y * 0.2f; + auto button = std::make_unique<Button>(&get_theme().title_font, "", mgl::vec2f(settings_button_size, settings_button_size), mgl::Color(0, 0, 0, 180)); + button->set_position((main_buttons_list_ptr->get_position() + main_buttons_size - mgl::vec2f(0.0f, settings_button_size) + mgl::vec2f(settings_button_size * 0.333f, 0.0f)).floor()); + button->set_bg_hover_color(mgl::Color(0, 0, 0, 255)); + button->set_icon(&get_theme().settings_small_texture); + button->on_click = [&]() { + auto settings_page = std::make_unique<GlobalSettingsPage>(&gsr_info, config, &page_stack); + page_stack.push(std::move(settings_page)); + }; + front_page_ptr->add_widget(std::move(button)); + } + close_button_widget.draw_handler = [&](mgl::Window &window, mgl::vec2f pos, mgl::vec2f size) { const int border_size = std::max(1.0f, 0.0015f * get_theme().window_height); const float padding_size = std::max(1.0f, 0.003f * get_theme().window_height); @@ -986,8 +1029,7 @@ namespace gsr { // XFlush(display); // } - if(!prevent_game_minimizing) - window->set_fullscreen(true); + window->set_fullscreen(true); visible = true; @@ -1526,6 +1568,24 @@ namespace gsr { } } + static bool validate_capture_target(const GsrInfo &gsr_info, const std::string &capture_target) { + const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info); + // TODO: Also check x11 window when enabled (check if capture_target is a decminal/hex number) + if(capture_target == "focused" && !capture_options.focused) { + return false; + } else if(capture_target == "screen" && !capture_options.screen) { + return false; + } else if(capture_target == "portal" && !capture_options.portal) { + return false; + } else { + for(const GsrMonitor &monitor : capture_options.monitors) { + if(capture_target == monitor.name) + return true; + } + return false; + } + } + void Overlay::on_press_save_replay() { if(recording_status != RecordingStatus::REPLAY || gpu_screen_recorder_process <= 0) return; @@ -1571,6 +1631,13 @@ namespace gsr { return; } + if(!validate_capture_target(gsr_info, config.replay_config.record_options.record_area_option)) { + char err_msg[256]; + snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid. Please change capture target in settings", config.replay_config.record_options.record_area_option.c_str()); + show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::REPLAY); + return; + } + // 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); @@ -1678,6 +1745,13 @@ namespace gsr { return; } + if(!validate_capture_target(gsr_info, config.record_config.record_options.record_area_option)) { + char err_msg[256]; + snprintf(err_msg, sizeof(err_msg), "Failed to start recording, capture target \"%s\" is invalid. Please change capture target in settings", config.record_config.record_options.record_area_option.c_str()); + show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::RECORD); + return; + } + record_filepath.clear(); // TODO: Validate input, fallback to valid values @@ -1807,6 +1881,13 @@ namespace gsr { return; } + if(!validate_capture_target(gsr_info, config.streaming_config.record_options.record_area_option)) { + char err_msg[256]; + snprintf(err_msg, sizeof(err_msg), "Failed to start streaming, capture target \"%s\" is invalid. Please change capture target in settings", config.streaming_config.record_options.record_area_option.c_str()); + show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::STREAM); + return; + } + // 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); diff --git a/src/Process.cpp b/src/Process.cpp index e5886c0..a9c5103 100644 --- a/src/Process.cpp +++ b/src/Process.cpp @@ -29,7 +29,7 @@ namespace gsr { debug_print_args(args); - pid_t pid = vfork(); + const pid_t pid = vfork(); if(pid == -1) { perror("Failed to vfork"); return false; @@ -38,7 +38,7 @@ namespace gsr { signal(SIGHUP, SIG_IGN); // Daemonize child to make the parent the init process which will reap the zombie child - pid_t second_child = vfork(); + const pid_t second_child = vfork(); if(second_child == 0) { // child execvp(args[0], (char* const*)args); perror("execvp"); @@ -68,7 +68,7 @@ namespace gsr { debug_print_args(args); - pid_t pid = vfork(); + const pid_t pid = vfork(); if(pid == -1) { close(fds[PIPE_READ]); close(fds[PIPE_WRITE]); @@ -92,6 +92,48 @@ namespace gsr { } } + int exec_program_get_stdout(const char **args, std::string &result) { + result.clear(); + int read_fd = -1; + const pid_t process_id = exec_program(args, &read_fd); + if(process_id == -1) + return -1; + + int exit_status = 0; + char buffer[8192]; + for(;;) { + ssize_t bytes_read = read(read_fd, buffer, sizeof(buffer)); + if(bytes_read == 0) { + break; + } else if(bytes_read == -1) { + fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(errno)); + exit_status = -1; + break; + } + + buffer[bytes_read] = '\0'; + result.append(buffer, bytes_read); + } + + if(exit_status != 0) + kill(process_id, SIGKILL); + + int status = 0; + if(waitpid(process_id, &status, 0) == -1) { + perror("waitpid failed"); + exit_status = -1; + } + + if(!WIFEXITED(status)) + exit_status = -1; + + if(exit_status == 0) + exit_status = WEXITSTATUS(status); + + close(read_fd); + return exit_status; + } + bool read_cmdline_arg0(const char *filepath, char *output_buffer) { output_buffer[0] = '\0'; diff --git a/src/Theme.cpp b/src/Theme.cpp index a88aa1e..a6d1050 100644 --- a/src/Theme.cpp +++ b/src/Theme.cpp @@ -1,4 +1,5 @@ #include "../include/Theme.hpp" +#include "../include/Config.hpp" #include "../include/GsrInfo.hpp" #include <assert.h> @@ -7,6 +8,27 @@ namespace gsr { static Theme *theme = nullptr; static ColorTheme *color_theme = nullptr; + static mgl::Color gpu_vendor_to_color(GpuVendor vendor) { + switch(vendor) { + case GpuVendor::UNKNOWN: return mgl::Color(221, 0, 49); + case GpuVendor::AMD: return mgl::Color(221, 0, 49); + case GpuVendor::INTEL: return mgl::Color(8, 109, 183); + case GpuVendor::NVIDIA: return mgl::Color(118, 185, 0); + } + return mgl::Color(221, 0, 49); + } + + static mgl::Color color_name_to_color(const std::string &color_name) { + GpuVendor vendor = GpuVendor::UNKNOWN; + if(color_name == "amd") + vendor = GpuVendor::AMD; + else if(color_name == "intel") + vendor = GpuVendor::INTEL; + else if(color_name == "nvidia") + vendor = GpuVendor::NVIDIA; + return gpu_vendor_to_color(vendor); + } + bool Theme::set_window_size(mgl::vec2i window_size) { if(std::abs(window_size.x - window_width) < 0.1f && std::abs(window_size.y - window_height) < 0.1f) return true; @@ -44,6 +66,9 @@ namespace gsr { if(!theme->settings_texture.load_from_file((resources_path + "images/settings.png").c_str())) goto error; + if(!theme->settings_small_texture.load_from_file((resources_path + "images/settings_small.png").c_str())) + goto error; + if(!theme->folder_texture.load_from_file((resources_path + "images/folder.png").c_str())) goto error; @@ -102,29 +127,16 @@ namespace gsr { return *theme; } - bool init_color_theme(const GsrInfo &gsr_info) { + bool init_color_theme(const Config &config, const GsrInfo &gsr_info) { if(color_theme) return true; color_theme = new ColorTheme(); - switch(gsr_info.gpu_info.vendor) { - case GpuVendor::UNKNOWN: { - break; - } - case GpuVendor::AMD: { - color_theme->tint_color = mgl::Color(221, 0, 49); - break; - } - case GpuVendor::INTEL: { - color_theme->tint_color = mgl::Color(8, 109, 183); - break; - } - case GpuVendor::NVIDIA: { - color_theme->tint_color = mgl::Color(118, 185, 0); - break; - } - } + if(config.main_config.tint_color.empty()) + color_theme->tint_color = gpu_vendor_to_color(gsr_info.gpu_info.vendor); + else + color_theme->tint_color = color_name_to_color(config.main_config.tint_color); return true; } diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp index fbf5cdd..54d1854 100644 --- a/src/gui/Button.cpp +++ b/src/gui/Button.cpp @@ -12,7 +12,15 @@ namespace gsr { static const float padding_left_scale = 0.007f; static const float padding_right_scale = 0.007f; - Button::Button(mgl::Font *font, const char *text, mgl::vec2f size, mgl::Color bg_color) : size(size), bg_color(bg_color), text(text, *font) { + // These are relative to the button size + static const float padding_top_icon_scale = 0.25f; + static const float padding_bottom_icon_scale = 0.25f; + static const float padding_left_icon_scale = 0.25f; + static const float padding_right_icon_scale = 0.25f; + + Button::Button(mgl::Font *font, const char *text, mgl::vec2f size, mgl::Color bg_color) : + size(size), bg_color(bg_color), bg_hover_color(bg_color), text(text, *font) + { } @@ -37,17 +45,23 @@ namespace gsr { return; const mgl::vec2f draw_pos = position + offset; - const mgl::vec2f item_size = get_size().floor(); + const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f()) && !has_parent_with_selected_child_widget(); + mgl::Rectangle background(item_size); background.set_position(draw_pos.floor()); - background.set_color(bg_color); + background.set_color(mouse_inside ? bg_hover_color : bg_color); window.draw(background); text.set_position((draw_pos + item_size * 0.5f - text.get_bounds().size * 0.5f).floor()); window.draw(text); - const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f()) && !has_parent_with_selected_child_widget(); + if(sprite.get_texture() && sprite.get_texture()->is_valid()) { + scale_sprite_to_button_size(); + sprite.set_position((background.get_position() + background.get_size() * 0.5f - sprite.get_size() * 0.5f).floor()); + window.draw(sprite); + } + if(mouse_inside) { const mgl::Color outline_color = (bg_color == get_color_theme().tint_color) ? mgl::Color(255, 255, 255) : get_color_theme().tint_color; draw_rectangle_outline(window, draw_pos, item_size, outline_color, std::max(1.0f, border_scale * get_theme().window_height)); @@ -76,6 +90,14 @@ namespace gsr { border_scale = scale; } + void Button::set_bg_hover_color(mgl::Color color) { + bg_hover_color = color; + } + + void Button::set_icon(mgl::Texture *texture) { + sprite.set_texture(texture); + } + const std::string& Button::get_text() const { return text.get_string(); } @@ -83,4 +105,18 @@ namespace gsr { void Button::set_text(std::string str) { text.set_string(std::move(str)); } + + void Button::scale_sprite_to_button_size() { + if(!sprite.get_texture() || !sprite.get_texture()->is_valid()) + return; + + const mgl::vec2f button_size = get_size(); + const int padding_icon_top = padding_top_icon_scale * button_size.y; + const int padding_icon_bottom = padding_bottom_icon_scale * button_size.y; + const int padding_icon_left = padding_left_icon_scale * button_size.y; + const int padding_icon_right = padding_right_icon_scale * button_size.y; + + const mgl::vec2f desired_size = button_size - mgl::vec2f(padding_icon_left + padding_icon_right, padding_icon_top + padding_icon_bottom); + sprite.set_size(scale_keep_aspect_ratio(sprite.get_texture()->get_size().to_vec2f(), desired_size).floor()); + } }
\ No newline at end of file diff --git a/src/gui/GlobalSettingsPage.cpp b/src/gui/GlobalSettingsPage.cpp new file mode 100644 index 0000000..6c25663 --- /dev/null +++ b/src/gui/GlobalSettingsPage.cpp @@ -0,0 +1,83 @@ +#include "../../include/gui/GlobalSettingsPage.hpp" + +#include "../../include/Theme.hpp" +#include "../../include/gui/GsrPage.hpp" +#include "../../include/gui/PageStack.hpp" +#include "../../include/gui/ScrollablePage.hpp" +#include "../../include/gui/Subsection.hpp" +#include "../../include/gui/List.hpp" +#include "../../include/gui/Label.hpp" +#include "../../include/gui/RadioButton.hpp" + +namespace gsr { + static const char* gpu_vendor_to_color_name(GpuVendor vendor) { + switch(vendor) { + case GpuVendor::UNKNOWN: return "amd"; + case GpuVendor::AMD: return "amd"; + case GpuVendor::INTEL: return "intel"; + case GpuVendor::NVIDIA: return "nvidia"; + } + return "amd"; + } + + GlobalSettingsPage::GlobalSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack) : + StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), + config(config), + gsr_info(gsr_info), + page_stack(page_stack) + { + 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) { + if(id == "back") + page_stack->pop(); + }; + content_page_ptr = content_page.get(); + add_widget(std::move(content_page)); + + add_widgets(); + load(); + } + + std::unique_ptr<Subsection> GlobalSettingsPage::create_appearance_subsection(ScrollablePage *parent_page) { + auto list = std::make_unique<List>(List::Orientation::VERTICAL); + list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Tint color", get_color_theme().text_color)); + auto tint_color_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); + 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->on_selection_changed = [](const std::string&, const std::string &id) { + if(id == "amd") + get_color_theme().tint_color = mgl::Color(221, 0, 49); + else if(id == "nvidia") + get_color_theme().tint_color = mgl::Color(118, 185, 0); + else if(id == "intel") + get_color_theme().tint_color = mgl::Color(8, 109, 183); + }; + list->add_widget(std::move(tint_color_radio_button)); + return std::make_unique<Subsection>("Appearance", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f)); + } + + void GlobalSettingsPage::add_widgets() { + auto scrollable_page = std::make_unique<ScrollablePage>(content_page_ptr->get_inner_size()); + scrollable_page->add_widget(create_appearance_subsection(scrollable_page.get())); + content_page_ptr->add_widget(std::move(scrollable_page)); + } + + void GlobalSettingsPage::on_navigate_away_from_page() { + save(); + } + + void GlobalSettingsPage::load() { + if(config.main_config.tint_color.empty()) + tint_color_radio_button_ptr->set_selected_item(gpu_vendor_to_color_name(gsr_info->gpu_info.vendor)); + else + tint_color_radio_button_ptr->set_selected_item(config.main_config.tint_color); + } + + void GlobalSettingsPage::save() { + config.main_config.tint_color = tint_color_radio_button_ptr->get_selected_id(); + save_config(config); + } +}
\ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index 79f6c52..28821d1 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -22,15 +22,16 @@ namespace gsr { APPLICATION_CUSTOM }; - SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, 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), - page_stack(page_stack), - settings_title_text("Settings", get_theme().title_font) + gsr_info(gsr_info), + page_stack(page_stack) { audio_devices = get_audio_devices(); application_audio = get_application_audio(); + capture_options = get_supported_capture_options(*gsr_info); auto content_page = std::make_unique<GsrPage>(); content_page->add_button("Back", "back", get_color_theme().page_bg_color); @@ -41,9 +42,9 @@ namespace gsr { content_page_ptr = content_page.get(); add_widget(std::move(content_page)); - add_widgets(gsr_info); - add_page_specific_widgets(gsr_info); - load(gsr_info); + add_widgets(); + add_page_specific_widgets(); + load(); } std::unique_ptr<RadioButton> SettingsPage::create_view_radio_button() { @@ -55,31 +56,32 @@ namespace gsr { return view_radio_button; } - std::unique_ptr<ComboBox> SettingsPage::create_record_area_box(const GsrInfo &gsr_info) { + std::unique_ptr<ComboBox> SettingsPage::create_record_area_box() { auto record_area_box = std::make_unique<ComboBox>(&get_theme().body_font); // TODO: Show options not supported but disable them // TODO: Enable this - //if(gsr_info.supported_capture_options.window) + //if(capture_options.window) // record_area_box->add_item("Window", "window"); - if(gsr_info.supported_capture_options.focused) + if(capture_options.focused) record_area_box->add_item("Follow focused window", "focused"); - if(gsr_info.supported_capture_options.screen) - record_area_box->add_item("All monitors", "screen"); - for(const auto &monitor : gsr_info.supported_capture_options.monitors) { + // Do we really need this? it's only available on nvidia x11 + //if(capture_options.screen) + // record_area_box->add_item("All monitors", "screen"); + for(const auto &monitor : capture_options.monitors) { char name[256]; snprintf(name, sizeof(name), "Monitor %s (%dx%d)", monitor.name.c_str(), monitor.size.x, monitor.size.y); record_area_box->add_item(name, monitor.name); } - if(gsr_info.supported_capture_options.portal) + if(capture_options.portal) record_area_box->add_item("Desktop portal", "portal"); record_area_box_ptr = record_area_box.get(); return record_area_box; } - std::unique_ptr<Widget> SettingsPage::create_record_area(const GsrInfo &gsr_info) { + std::unique_ptr<Widget> SettingsPage::create_record_area() { auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL); record_area_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Capture target:", get_color_theme().text_color)); - record_area_list->add_widget(create_record_area_box(gsr_info)); + record_area_list->add_widget(create_record_area_box()); return record_area_list; } @@ -172,11 +174,11 @@ namespace gsr { return checkbox; } - std::unique_ptr<Widget> SettingsPage::create_capture_target(const GsrInfo &gsr_info) { + std::unique_ptr<Widget> SettingsPage::create_capture_target() { auto ll = std::make_unique<List>(List::Orientation::VERTICAL); auto capture_target_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); - capture_target_list->add_widget(create_record_area(gsr_info)); + capture_target_list->add_widget(create_record_area()); capture_target_list->add_widget(create_select_window()); capture_target_list->add_widget(create_area_size_section()); capture_target_list->add_widget(create_video_resolution_section()); @@ -378,40 +380,40 @@ namespace gsr { return quality_list; } - std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box(const GsrInfo &gsr_info) { + std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box() { auto video_codec_box = std::make_unique<ComboBox>(&get_theme().body_font); // TODO: Show options not supported but disable them. // TODO: Show error if no encoders are supported. // TODO: Show warning (once) if only software encoder is available. video_codec_box->add_item("Auto (Recommended)", "auto"); - if(gsr_info.supported_video_codecs.h264) + if(gsr_info->supported_video_codecs.h264) video_codec_box->add_item("H264", "h264"); - if(gsr_info.supported_video_codecs.hevc) + if(gsr_info->supported_video_codecs.hevc) video_codec_box->add_item("HEVC", "hevc"); - if(gsr_info.supported_video_codecs.av1) + if(gsr_info->supported_video_codecs.av1) video_codec_box->add_item("AV1", "av1"); - if(gsr_info.supported_video_codecs.vp8) + if(gsr_info->supported_video_codecs.vp8) video_codec_box->add_item("VP8", "vp8"); - if(gsr_info.supported_video_codecs.vp9) + if(gsr_info->supported_video_codecs.vp9) video_codec_box->add_item("VP9", "vp9"); - if(gsr_info.supported_video_codecs.hevc_hdr) + if(gsr_info->supported_video_codecs.hevc_hdr) video_codec_box->add_item("HEVC (HDR)", "hevc_hdr"); - if(gsr_info.supported_video_codecs.hevc_10bit) + if(gsr_info->supported_video_codecs.hevc_10bit) video_codec_box->add_item("HEVC (10 bit, reduces banding)", "hevc_10bit"); - if(gsr_info.supported_video_codecs.av1_hdr) + if(gsr_info->supported_video_codecs.av1_hdr) video_codec_box->add_item("AV1 (HDR)", "av1_hdr"); - if(gsr_info.supported_video_codecs.av1_10bit) + if(gsr_info->supported_video_codecs.av1_10bit) video_codec_box->add_item("AV1 (10 bit, reduces banding)", "av1_10bit"); - if(gsr_info.supported_video_codecs.h264_software) + if(gsr_info->supported_video_codecs.h264_software) video_codec_box->add_item("H264 Software Encoder (Slow, not recommended)", "h264_software"); video_codec_box_ptr = video_codec_box.get(); return video_codec_box; } - std::unique_ptr<List> SettingsPage::create_video_codec(const GsrInfo &gsr_info) { + std::unique_ptr<List> SettingsPage::create_video_codec() { auto video_codec_list = std::make_unique<List>(List::Orientation::VERTICAL); video_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video codec:", get_color_theme().text_color)); - video_codec_list->add_widget(create_video_codec_box(gsr_info)); + video_codec_list->add_widget(create_video_codec_box()); video_codec_ptr = video_codec_list.get(); return video_codec_list; } @@ -477,16 +479,16 @@ namespace gsr { return record_cursor_checkbox; } - std::unique_ptr<Widget> SettingsPage::create_video_section(const GsrInfo &gsr_info) { + std::unique_ptr<Widget> SettingsPage::create_video_section() { auto video_section_list = std::make_unique<List>(List::Orientation::VERTICAL); video_section_list->add_widget(create_video_quality_section()); - video_section_list->add_widget(create_video_codec(gsr_info)); + video_section_list->add_widget(create_video_codec()); video_section_list->add_widget(create_framerate_section()); video_section_list->add_widget(create_record_cursor_section()); return std::make_unique<Subsection>("Video", std::move(video_section_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); } - std::unique_ptr<Widget> SettingsPage::create_settings(const GsrInfo &gsr_info) { + std::unique_ptr<Widget> SettingsPage::create_settings() { auto page_list = std::make_unique<List>(List::Orientation::VERTICAL); page_list->set_spacing(0.018f); page_list->add_widget(create_view_radio_button()); @@ -496,16 +498,16 @@ 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_capture_target()); settings_list->add_widget(create_audio_section()); - settings_list->add_widget(create_video_section(gsr_info)); + settings_list->add_widget(create_video_section()); settings_list_ptr = settings_list.get(); settings_scrollable_page_ptr->add_widget(std::move(settings_list)); return page_list; } - void SettingsPage::add_widgets(const GsrInfo &gsr_info) { - content_page_ptr->add_widget(create_settings(gsr_info)); + 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; @@ -534,32 +536,32 @@ namespace gsr { }; video_quality_box_ptr->on_selection_changed("", video_quality_box_ptr->get_selected_id()); - if(!gsr_info.supported_capture_options.monitors.empty()) - record_area_box_ptr->set_selected_item(gsr_info.supported_capture_options.monitors.front().name); - else if(gsr_info.supported_capture_options.portal) + if(!capture_options.monitors.empty()) + record_area_box_ptr->set_selected_item(capture_options.monitors.front().name); + else if(capture_options.portal) record_area_box_ptr->set_selected_item("portal"); - else if(gsr_info.supported_capture_options.window) + else if(capture_options.window) record_area_box_ptr->set_selected_item("window"); else record_area_box_ptr->on_selection_changed("", ""); - if(!gsr_info.system_info.supports_app_audio) { + 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(const GsrInfo &gsr_info) { + void SettingsPage::add_page_specific_widgets() { switch(type) { case Type::REPLAY: - add_replay_widgets(gsr_info); + add_replay_widgets(); break; case Type::RECORD: - add_record_widgets(gsr_info); + add_record_widgets(); break; case Type::STREAM: - add_stream_widgets(gsr_info); + add_stream_widgets(); break; } } @@ -622,9 +624,9 @@ namespace gsr { return replay_time_list; } - std::unique_ptr<RadioButton> SettingsPage::create_start_replay_automatically(const GsrInfo &gsr_info) { + 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 only)"); + snprintf(fullscreen_text, sizeof(fullscreen_text), "Turn on replay when starting a fullscreen application%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)"); auto radiobutton = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::VERTICAL); radiobutton->add_item("Don't turn on replay automatically", "dont_turn_on_automatically"); @@ -635,9 +637,9 @@ namespace gsr { return radiobutton; } - std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder(const GsrInfo &gsr_info) { + std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder() { char text[256]; - snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info.system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)"); + snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)"); auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text); save_replay_in_game_folder_ptr = checkbox.get(); return checkbox; @@ -659,7 +661,7 @@ namespace gsr { estimated_file_size_ptr->set_text(buffer); } - void SettingsPage::add_replay_widgets(const GsrInfo &gsr_info) { + 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); file_info_data_list->add_widget(create_save_directory("Directory to save replays:")); @@ -670,8 +672,8 @@ 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(gsr_info)); - general_list->add_widget(create_save_replay_in_game_folder(gsr_info)); + general_list->add_widget(create_start_replay_automatically()); + general_list->add_widget(create_save_replay_in_game_folder()); 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))); auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL); @@ -716,22 +718,22 @@ namespace gsr { }; } - std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder(const GsrInfo &gsr_info) { + std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder() { char text[256]; - snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info.system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)"); + snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)"); auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text); save_recording_in_game_folder_ptr = checkbox.get(); return checkbox; } - void SettingsPage::add_record_widgets(const GsrInfo &gsr_info) { + void SettingsPage::add_record_widgets() { auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL); file_list->add_widget(create_save_directory("Directory to save the video:")); file_list->add_widget(create_container_section()); settings_list_ptr->add_widget(std::make_unique<Subsection>("File info", std::move(file_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_save_recording_in_game_folder(gsr_info)); + general_list->add_widget(create_save_recording_in_game_folder()); 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))); auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL); @@ -825,7 +827,7 @@ namespace gsr { return container_list; } - void SettingsPage::add_stream_widgets(const GsrInfo&) { + void SettingsPage::add_stream_widgets() { auto streaming_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); streaming_info_list->add_widget(create_streaming_service_section()); streaming_info_list->add_widget(create_stream_key_section()); @@ -879,16 +881,16 @@ namespace gsr { save(); } - void SettingsPage::load(const GsrInfo &gsr_info) { + void SettingsPage::load() { switch(type) { case Type::REPLAY: - load_replay(gsr_info); + load_replay(); break; case Type::RECORD: - load_record(gsr_info); + load_record(); break; case Type::STREAM: - load_stream(gsr_info); + load_stream(); break; } } @@ -921,11 +923,11 @@ namespace gsr { return str.size() >= len && memcmp(str.data(), substr, len) == 0; } - void SettingsPage::load_audio_tracks(const RecordOptions &record_options, const GsrInfo &gsr_info) { + 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) + if(!gsr_info->system_info.supports_app_audio) continue; std::string audio_track_name = audio_track.substr(4); @@ -955,12 +957,12 @@ namespace gsr { } } - void SettingsPage::load_common(RecordOptions &record_options, const GsrInfo &gsr_info) { + 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, gsr_info); + load_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); @@ -1009,8 +1011,8 @@ namespace gsr { video_bitrate_entry_ptr->set_text(std::to_string(record_options.video_bitrate)); } - void SettingsPage::load_replay(const GsrInfo &gsr_info) { - load_common(config.replay_config.record_options, gsr_info); + void SettingsPage::load_replay() { + load_common(config.replay_config.record_options); 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); show_replay_started_notification_checkbox_ptr->set_checked(config.replay_config.show_replay_started_notifications); @@ -1024,8 +1026,8 @@ namespace gsr { replay_time_entry_ptr->set_text(std::to_string(config.replay_config.replay_time)); } - void SettingsPage::load_record(const GsrInfo &gsr_info) { - load_common(config.record_config.record_options, gsr_info); + void SettingsPage::load_record() { + load_common(config.record_config.record_options); save_recording_in_game_folder_ptr->set_checked(config.record_config.save_video_in_game_folder); show_recording_started_notification_checkbox_ptr->set_checked(config.record_config.show_recording_started_notifications); show_video_saved_notification_checkbox_ptr->set_checked(config.record_config.show_video_saved_notifications); @@ -1033,8 +1035,8 @@ namespace gsr { container_box_ptr->set_selected_item(config.record_config.container); } - void SettingsPage::load_stream(const GsrInfo &gsr_info) { - load_common(config.streaming_config.record_options, gsr_info); + void SettingsPage::load_stream() { + load_common(config.streaming_config.record_options); show_streaming_started_notification_checkbox_ptr->set_checked(config.streaming_config.show_streaming_started_notifications); show_streaming_stopped_notification_checkbox_ptr->set_checked(config.streaming_config.show_streaming_stopped_notifications); streaming_service_box_ptr->set_selected_item(config.streaming_config.streaming_service); diff --git a/src/gui/Utils.cpp b/src/gui/Utils.cpp index e000b7a..d1643f2 100644 --- a/src/gui/Utils.cpp +++ b/src/gui/Utils.cpp @@ -50,4 +50,21 @@ namespace gsr { void set_frame_delta_seconds(double frame_delta) { frame_delta_seconds = frame_delta; } + + mgl::vec2f scale_keep_aspect_ratio(mgl::vec2f from, mgl::vec2f to) { + if(std::abs(from.x) <= 0.0001f || std::abs(from.y) <= 0.0001f) + return {0.0f, 0.0f}; + + const double height_to_width_ratio = (double)from.y / (double)from.x; + from.x = to.x; + from.y = from.x * height_to_width_ratio; + + if(from.y > to.y) { + const double width_height_ratio = (double)from.x / (double)from.y; + from.y = to.y; + from.x = from.y * width_height_ratio; + } + + return from; + } }
\ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 7002288..98b1ce3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -168,8 +168,11 @@ int main(void) { exit(1); } - if(gsr_info.system_info.display_server == gsr::DisplayServer::WAYLAND) - fprintf(stderr, "warning: Wayland support is experimental and requires XWayland. Things may not work as expected.\n"); + const gsr::DisplayServer display_server = gsr_info.system_info.display_server; + if(display_server == gsr::DisplayServer::WAYLAND) + fprintf(stderr, "warning: Wayland support is experimental and requires XWayland. Things may not work as expected.\n"); + + gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info); std::string resources_path; if(access("sibs-build", F_OK) == 0) { @@ -197,11 +200,11 @@ int main(void) { fprintf(stderr, "info: gsr ui is now ready, waiting for inputs. Press alt+z to show/hide the overlay\n"); - auto overlay = std::make_unique<gsr::Overlay>(resources_path, gsr_info, egl_funcs); + auto overlay = std::make_unique<gsr::Overlay>(resources_path, std::move(gsr_info), std::move(capture_options), egl_funcs); //overlay.show(); std::unique_ptr<gsr::GlobalHotkeys> global_hotkeys = nullptr; - if(gsr_info.system_info.display_server == gsr::DisplayServer::X11) { + if(display_server == gsr::DisplayServer::X11) { global_hotkeys = register_x11_hotkeys(overlay.get()); if(!global_hotkeys) { fprintf(stderr, "info: failed to register some x11 hotkeys because they are registered by another program. Will use linux hotkeys instead that can clash with keys used by other applications\n"); |