Change text renderer to pango (supports all languages and loads font automatically), start on game detection

This commit is contained in:
dec05eba
2026-04-18 00:37:16 +02:00
parent 72c8c79896
commit 010787854e
39 changed files with 636 additions and 886 deletions

View File

@@ -31,7 +31,8 @@ These are the dependencies needed to build GPU Screen Recorder UI:
* libdrm * libdrm
* libdbus * libdbus
* wayland (wayland-client, wayland-egl, wayland-scanner) * wayland (wayland-client, wayland-egl, wayland-scanner)
* setcap (libcap) * libcap
* libpango (pangoft2)
## Runtime dependencies ## Runtime dependencies
There are also additional dependencies needed at runtime: There are also additional dependencies needed at runtime:
@@ -52,7 +53,7 @@ as gpu screen recorder tries to grab keys and keyd grabs gpu screen recorder, le
If you are stuck in such a lock where you cant press and keyboard keys you can press (left) ctrl+shift+alt+esc to close gpu screen recorder and remove it from system startup. If you are stuck in such a lock where you cant press and keyboard keys you can press (left) ctrl+shift+alt+esc to close gpu screen recorder and remove it from system startup.
# License # License
This software is licensed under GPL-3.0-only, see the LICENSE file for more information. Files under `fonts/` directory belong to the Noto Sans Google fonts project and they are licensed under `SIL Open Font License`.\ This software is licensed under GPL-3.0-only, see the LICENSE file for more information.
`images/default.cur` it part of the [Adwaita icon theme](https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/tree/master) which is licensed under `CC BY-SA 3.0`.\ `images/default.cur` it part of the [Adwaita icon theme](https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/tree/master) which is licensed under `CC BY-SA 3.0`.\
The controller buttons under `images/` were created by [Julio Cacko](https://juliocacko.itch.io/free-input-prompts) and they are licensed under `CC0 1.0 Universal`.\ The controller buttons under `images/` were created by [Julio Cacko](https://juliocacko.itch.io/free-input-prompts) and they are licensed under `CC0 1.0 Universal`.\
The PlayStation logo under `images/` was created by [ArksDigital](https://arks.itch.io/ps4-buttons) and it's licensed under `CC BY 4.0`. The PlayStation logo under `images/` was created by [ArksDigital](https://arks.itch.io/ps4-buttons) and it's licensed under `CC BY 4.0`.

8
TODO
View File

@@ -129,8 +129,6 @@ If CursorTrackerWayland fails then fallback to getting focused monitor by window
Maybe automatically switch to recording with the device that controls the monitor. Maybe automatically switch to recording with the device that controls the monitor.
In that case also add all monitors available to capture in the capture list and automatically choose the gpu that controls the monitor. In that case also add all monitors available to capture in the capture list and automatically choose the gpu that controls the monitor.
Support cjk font. Use fc-match to find the location of the font. This also works in flatpak, in which case the fonts are in /run/host/..., where it lists system fonts.
Keyboard layout is incorrect on wayland when using kde plasma keyboard settings to setup multiple keyboards, for example when changing to french. Keyboard layout is incorrect on wayland when using kde plasma keyboard settings to setup multiple keyboards, for example when changing to french.
Text input is correct, but hotkey is incorrect. Text input is correct, but hotkey is incorrect.
Need to use "setxkbmap fr" as well. Need to use "setxkbmap fr" as well.
@@ -164,8 +162,6 @@ Show message that replay/streaming has to be restarted if recording settings are
Support vector graphics. Maybe support svg, rendering it to a texture for better performance. Support vector graphics. Maybe support svg, rendering it to a texture for better performance.
Support freetype for text rendering. Maybe load freetype as runtime (with dlopen) and use that when available and fallback to stb_freetype if not available.
Show .webm container option. It's currently chosen automatically if vp8/vp9 is chosen. The available containers should automatically switch depending on the video codec. Show .webm container option. It's currently chosen automatically if vp8/vp9 is chosen. The available containers should automatically switch depending on the video codec.
In settings show audio levels for each audio. Maybe show audio level image beside the audio name in the dropdown box and switch to a different image (have 3-4 different images for each level) depending on the volume. In settings show audio levels for each audio. Maybe show audio level image beside the audio name in the dropdown box and switch to a different image (have 3-4 different images for each level) depending on the volume.
@@ -260,3 +256,7 @@ Add simple video cutting in the ui.
Keep replay turned on when opening a fullscreen application and alt-tabbing. Only stop replay when closing the application (when closing all fullscreen applications). Keep replay turned on when opening a fullscreen application and alt-tabbing. Only stop replay when closing the application (when closing all fullscreen applications).
When alt-tabbing check if the previously fullscreen window still exists. When alt-tabbing check if the previously fullscreen window still exists.
Show vulkan codec options.
Use game information to save video under the game title if available, fallback to window title.

Binary file not shown.

Binary file not shown.

View File

@@ -114,7 +114,7 @@ namespace gsr {
void handle_keyboard_mapping_event(); void handle_keyboard_mapping_event();
void on_event(mgl::Event &event); void on_event(mgl::Event &event);
void recreate_global_hotkeys(const char *hotkey_option); void recreate_global_hotkeys(std::string_view hotkey_option);
void update_led_indicator_after_settings_change(); void update_led_indicator_after_settings_change();
void recreate_frontpage_ui_components(); void recreate_frontpage_ui_components();
void xi_setup(); void xi_setup();
@@ -255,6 +255,11 @@ namespace gsr {
XEvent x11_xev; XEvent x11_xev;
Atom net_active_window_atom; Atom net_active_window_atom;
bool update_focused_window = true; bool update_focused_window = true;
std::vector<Window> game_windows;
double event_current_time_seconds = 0.0;
double gamescope_running_last_checked_seconds = 0.0;
bool is_gamescope_running = false;
bool is_game_running = false;
struct wl_display *wayland_dpy = nullptr; struct wl_display *wayland_dpy = nullptr;

View File

@@ -2,7 +2,6 @@
#include <mglpp/system/MemoryMappedFile.hpp> #include <mglpp/system/MemoryMappedFile.hpp>
#include <mglpp/graphics/Color.hpp> #include <mglpp/graphics/Color.hpp>
#include <mglpp/graphics/Font.hpp>
#include <mglpp/graphics/Texture.hpp> #include <mglpp/graphics/Texture.hpp>
#include <string> #include <string>
@@ -19,12 +18,10 @@ namespace gsr {
float window_width = 0.0f; float window_width = 0.0f;
float window_height = 0.0f; float window_height = 0.0f;
mgl::MemoryMappedFile body_font_file; std::string body_font_desc;
mgl::MemoryMappedFile title_font_file; std::string title_font_desc;
mgl::Font body_font; std::string top_bar_font_desc;
mgl::Font title_font; std::string camera_setup_font_desc;
mgl::Font top_bar_font;
mgl::Font camera_setup_font;
mgl::Texture combobox_arrow_texture; mgl::Texture combobox_arrow_texture;
mgl::Texture settings_texture; mgl::Texture settings_texture;

View File

@@ -8,8 +8,8 @@ namespace gsr {
public: public:
static Translation& instance(); static Translation& instance();
void init(const char* translations_directory, const char* initial_language = nullptr); void init(const char* translations_directory, const char* initial_language = nullptr);
bool load_language(const char* lang); bool load_language(std::string_view lang);
bool is_language_supported(const char* lang); bool is_language_supported(std::string_view lang);
bool plural_numbers_are_complex(); bool plural_numbers_are_complex();
const char* translate(const char* key); const char* translate(const char* key);

View File

@@ -12,7 +12,7 @@ namespace gsr {
public: public:
// If width is 0 then the width of the text is used instead (with padding). // If width is 0 then the width of the text is used instead (with padding).
// If height is 0 then the height of the text is used instead (with padding). // If height is 0 then the height of the text is used instead (with padding).
Button(mgl::Font *font, const char *text, mgl::vec2f size, mgl::Color bg_color); Button(const char *font_desc, const char *text, mgl::vec2f size, mgl::Color bg_color);
Button(const Button&) = delete; Button(const Button&) = delete;
Button& operator=(const Button&) = delete; Button& operator=(const Button&) = delete;
@@ -25,8 +25,8 @@ namespace gsr {
void set_bg_hover_color(mgl::Color color); void set_bg_hover_color(mgl::Color color);
void set_icon(mgl::Texture *texture); void set_icon(mgl::Texture *texture);
const std::string& get_text() const; std::string_view get_text() const;
void set_text(std::string str); void set_text(std::string_view str);
std::function<void()> on_click; std::function<void()> on_click;
private: private:

View File

@@ -11,7 +11,7 @@
namespace gsr { namespace gsr {
class CheckBox : public Widget { class CheckBox : public Widget {
public: public:
CheckBox(mgl::Font *font, const char *text); CheckBox(const char *font_desc, const char *text);
CheckBox(const CheckBox&) = delete; CheckBox(const CheckBox&) = delete;
CheckBox& operator=(const CheckBox&) = delete; CheckBox& operator=(const CheckBox&) = delete;

View File

@@ -11,24 +11,24 @@
namespace gsr { namespace gsr {
class ComboBox : public Widget { class ComboBox : public Widget {
public: public:
ComboBox(mgl::Font *font); ComboBox(const char *font_desc);
ComboBox(const ComboBox&) = delete; ComboBox(const ComboBox&) = delete;
ComboBox& operator=(const ComboBox&) = delete; ComboBox& operator=(const ComboBox&) = delete;
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override; bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
void draw(mgl::Window &window, mgl::vec2f offset) override; void draw(mgl::Window &window, mgl::vec2f offset) override;
void add_item(const std::string &text, const std::string &id, bool allow_duplicate = true); void add_item(std::string_view text, const std::string &id, bool allow_duplicate = true);
void clear_items(); void clear_items();
// The item can only be selected if it's enabled // The item can only be selected if it's enabled
void set_selected_item(const std::string &id, bool trigger_event = true, bool trigger_event_even_if_selection_not_changed = true); void set_selected_item(std::string_view id, bool trigger_event = true, bool trigger_event_even_if_selection_not_changed = true);
void set_item_enabled(const std::string &id, bool enabled); void set_item_enabled(std::string_view id, bool enabled);
const std::string& get_selected_id() const; std::string_view get_selected_id() const;
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
std::function<void(const std::string &text, const std::string &id)> on_selection_changed; std::function<void(std::string_view text, std::string_view id)> on_selection_changed;
private: private:
void draw_selected(mgl::Window &window, mgl::vec2f draw_pos); void draw_selected(mgl::Window &window, mgl::vec2f draw_pos);
void draw_unselected(mgl::Window &window, mgl::vec2f draw_pos); void draw_unselected(mgl::Window &window, mgl::vec2f draw_pos);
@@ -44,7 +44,8 @@ namespace gsr {
}; };
mgl::vec2f max_size; mgl::vec2f max_size;
mgl::Font *font; std::string font_desc;
int font_size = 0;
std::vector<Item> items; std::vector<Item> items;
mgl::Sprite dropdown_arrow; mgl::Sprite dropdown_arrow;
bool dirty = true; bool dirty = true;

View File

@@ -10,7 +10,7 @@
namespace gsr { namespace gsr {
class DropdownButton : public Widget { class DropdownButton : public Widget {
public: public:
DropdownButton(mgl::Font *title_font, mgl::Font *description_font, const char *title, const char *description, mgl::Texture *icon_texture, mgl::vec2f size); DropdownButton(const char *title_font_desc, const char *description_font_desc, const char *title, const char *description, mgl::Texture *icon_texture, mgl::vec2f size);
DropdownButton(const DropdownButton&) = delete; DropdownButton(const DropdownButton&) = delete;
DropdownButton& operator=(const DropdownButton&) = delete; DropdownButton& operator=(const DropdownButton&) = delete;
@@ -18,10 +18,10 @@ namespace gsr {
void draw(mgl::Window &window, mgl::vec2f offset) override; void draw(mgl::Window &window, mgl::vec2f offset) override;
void add_item(const std::string &text, const std::string &id, const std::string &description = ""); void add_item(const std::string &text, const std::string &id, const std::string &description = "");
void set_item_label(const std::string &id, const std::string &new_label); void set_item_label(std::string_view id, const std::string &new_label);
void set_item_icon(const std::string &id, mgl::Texture *texture); void set_item_icon(std::string_view id, mgl::Texture *texture);
void set_item_description(const std::string &id, const std::string &new_description); void set_item_description(std::string_view id, const std::string &new_description);
void set_item_enabled(const std::string &id, bool enabled); void set_item_enabled(std::string_view id, bool enabled);
void set_description(std::string description_text); void set_description(std::string description_text);
void set_activated(bool activated); void set_activated(bool activated);
@@ -41,8 +41,8 @@ namespace gsr {
}; };
std::vector<Item> items; std::vector<Item> items;
mgl::Font *title_font; std::string title_font_desc;
mgl::Font *description_font; std::string description_font_desc;
mgl::vec2f size; mgl::vec2f size;
bool mouse_inside = false; bool mouse_inside = false;
bool show_dropdown = false; bool show_dropdown = false;

View File

@@ -4,32 +4,16 @@
#include <functional> #include <functional>
#include <mglpp/graphics/Color.hpp> #include <mglpp/graphics/Color.hpp>
#include <mglpp/graphics/Text32.hpp> #include <mglpp/graphics/TextEdit.hpp>
#include <mglpp/graphics/Text.hpp>
#include <mglpp/graphics/Rectangle.hpp> #include <mglpp/graphics/Rectangle.hpp>
namespace gsr { namespace gsr {
class Entry; class Entry;
enum class EntryValidateHandlerResult {
DENY,
ALLOW,
REPLACED
};
using EntryValidateHandler = std::function<EntryValidateHandlerResult(Entry &entry, const std::u32string &str)>;
struct CaretIndexPos {
int index;
mgl::vec2f pos;
};
class Entry : public Widget { class Entry : public Widget {
public: public:
enum class Direction { Entry(const char *font_desc, const char *text, float max_width);
LEFT,
RIGHT
};
Entry(mgl::Font *font, const char *text, float max_width);
Entry(const Entry&) = delete; Entry(const Entry&) = delete;
Entry& operator=(const Entry&) = delete; Entry& operator=(const Entry&) = delete;
@@ -38,44 +22,18 @@ namespace gsr {
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
EntryValidateHandlerResult set_text(const std::string &str); void set_text(std::string_view str);
std::string get_text() const; std::string_view get_text() const;
void set_masked(bool masked); void set_masked(bool masked);
bool is_masked() const; bool is_masked() const;
// Return false to specify that the string should not be accepted. This reverts the string back to its previous value. void set_number_mode(bool enabled, int min_val, int max_val);
// The input can be changed by changing the input parameter and returning true.
EntryValidateHandler validate_handler;
std::function<void(const std::string &text)> on_changed; std::function<void(std::string_view text)> on_changed;
private: private:
// Also updates the cursor position
void replace_text(size_t index, size_t size, const std::u32string &replacement);
void move_caret_word(Direction direction, size_t max_codepoints);
EntryValidateHandlerResult set_text_internal(std::u32string str);
void draw_caret(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
void draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size);
CaretIndexPos find_closest_caret_index_by_position(mgl::vec2f position);
private:
struct Caret {
float offset_x = 0.0f;
int index = 0;
};
mgl::Rectangle background; mgl::Rectangle background;
mgl::Text32 text; mgl::TextEdit text_edit;
mgl::Text32 masked_text; float max_width = 0.0f;
float max_width;
bool selected = false;
bool selecting_text = false;
bool selecting_with_keyboard = false;
bool show_selection = false;
bool masked = false;
Caret caret;
Caret selection_start_caret;
float text_overflow = 0.0f;
}; };
EntryValidateHandler create_entry_validator_integer_in_range(int min, int max);
} }

View File

@@ -29,7 +29,7 @@ namespace gsr {
mgl::vec2f get_inner_size() override; mgl::vec2f get_inner_size() override;
void set_size(mgl::vec2f size); void set_size(mgl::vec2f size);
private: private:
void set_current_directory(const char *directory); void set_current_directory(std::string_view directory);
private: private:
struct Folder { struct Folder {
mgl::Text text; mgl::Text text;
@@ -48,7 +48,7 @@ namespace gsr {
class FileChooser : public Widget { class FileChooser : public Widget {
public: public:
FileChooser(const char *start_directory, mgl::vec2f size); FileChooser(std::string_view start_directory, mgl::vec2f size);
FileChooser(const FileChooser&) = delete; FileChooser(const FileChooser&) = delete;
FileChooser& operator=(const FileChooser&) = delete; FileChooser& operator=(const FileChooser&) = delete;
@@ -58,10 +58,10 @@ namespace gsr {
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
void set_current_directory(const char *directory); void set_current_directory(std::string_view directory);
void open_subdirectory(const char *name); void open_subdirectory(std::string_view name);
void open_parent_directory(); void open_parent_directory();
const std::string& get_current_directory() const; std::string_view get_current_directory() const;
private: private:
struct Folder { struct Folder {
mgl::Text text; mgl::Text text;

View File

@@ -49,9 +49,9 @@ namespace gsr {
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override; bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
std::function<void(bool enable, int exit_status)> on_startup_changed; std::function<void(bool enable, int exit_status)> on_startup_changed;
std::function<void(const char *reason)> on_click_exit_program_button; std::function<void(std::string_view reason)> on_click_exit_program_button;
std::function<void(const char *hotkey_option)> on_keyboard_hotkey_changed; std::function<void(std::string_view hotkey_option)> on_keyboard_hotkey_changed;
std::function<void(const char *hotkey_option)> on_joystick_hotkey_changed; std::function<void(std::string_view hotkey_option)> on_joystick_hotkey_changed;
std::function<void()> on_page_closed; std::function<void()> on_page_closed;
private: private:
void load_hotkeys(); void load_hotkeys();

View File

@@ -8,8 +8,7 @@
namespace gsr { namespace gsr {
class Label : public Widget { class Label : public Widget {
public: public:
// TODO: Allow specifying max width, at which either a line-break should occur or elipses should show Label(const char *font_desc, const char *text, mgl::Color color);
Label(mgl::Font *font, const char *text, mgl::Color color);
Label(const Label&) = delete; Label(const Label&) = delete;
Label& operator=(const Label&) = delete; Label& operator=(const Label&) = delete;
@@ -18,8 +17,14 @@ namespace gsr {
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
void set_text(std::string str); void set_text(std::string_view str);
const std::string& get_text() const; std::string_view get_text() const;
// Set to 0 to disable
void set_wrap_width(int width);
// Set to 0 to disable
void set_max_rows(int max_rows);
private: private:
mgl::Text text; mgl::Text text;
}; };

View File

@@ -14,7 +14,7 @@ namespace gsr {
HORIZONTAL HORIZONTAL
}; };
RadioButton(mgl::Font *font, Orientation orientation); RadioButton(const char *font_desc, Orientation orientation);
RadioButton(const RadioButton&) = delete; RadioButton(const RadioButton&) = delete;
RadioButton& operator=(const RadioButton&) = delete; RadioButton& operator=(const RadioButton&) = delete;
@@ -22,14 +22,14 @@ namespace gsr {
void draw(mgl::Window &window, mgl::vec2f offset) override; void draw(mgl::Window &window, mgl::vec2f offset) override;
void add_item(const std::string &text, const std::string &id); void add_item(const std::string &text, const std::string &id);
void set_selected_item(const std::string &id, bool trigger_event = true, bool trigger_event_even_if_selection_not_changed = true); void set_selected_item(std::string_view id, bool trigger_event = true, bool trigger_event_even_if_selection_not_changed = true);
const std::string& get_selected_id() const; std::string_view get_selected_id() const;
const std::string& get_selected_text() const; std::string_view get_selected_text() const;
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
// Return false to revert the change // Return false to revert the change
std::function<bool(const std::string &text, const std::string &id)> on_selection_changed; std::function<bool(std::string_view text, std::string_view id)> on_selection_changed;
private: private:
void update_if_dirty(); void update_if_dirty();
private: private:
@@ -38,7 +38,7 @@ namespace gsr {
std::string id; std::string id;
}; };
mgl::Font *font; std::string font_desc;
Orientation orientation; Orientation orientation;
std::vector<Item> items; std::vector<Item> items;
size_t selected_item = 0; size_t selected_item = 0;

View File

@@ -125,7 +125,7 @@ namespace gsr {
std::unique_ptr<CheckBox> create_save_replay_in_game_folder(); std::unique_ptr<CheckBox> create_save_replay_in_game_folder();
std::unique_ptr<CheckBox> create_restart_replay_on_save(); std::unique_ptr<CheckBox> create_restart_replay_on_save();
std::unique_ptr<Label> create_estimated_replay_file_size(); std::unique_ptr<Label> create_estimated_replay_file_size();
void update_estimated_replay_file_size(const std::string &replay_storage_type); void update_estimated_replay_file_size(std::string_view replay_storage_type);
void update_replay_time_text(); void update_replay_time_text();
std::unique_ptr<CheckBox> create_save_recording_in_game_folder(); std::unique_ptr<CheckBox> create_save_recording_in_game_folder();
std::unique_ptr<Label> create_estimated_record_file_size(); std::unique_ptr<Label> create_estimated_record_file_size();
@@ -140,6 +140,9 @@ namespace gsr {
std::unique_ptr<ComboBox> create_streaming_service_box(); std::unique_ptr<ComboBox> create_streaming_service_box();
std::unique_ptr<List> create_streaming_service_section(); std::unique_ptr<List> create_streaming_service_section();
std::unique_ptr<List> create_stream_key_section(); std::unique_ptr<List> create_stream_key_section();
std::unique_ptr<List> create_stream_kick_url();
std::unique_ptr<List> create_stream_kick_key();
std::unique_ptr<List> create_stream_kick_section();
std::unique_ptr<List> create_stream_custom_url(); std::unique_ptr<List> create_stream_custom_url();
std::unique_ptr<List> create_stream_custom_key(); std::unique_ptr<List> create_stream_custom_key();
std::unique_ptr<List> create_stream_custom_section(); std::unique_ptr<List> create_stream_custom_section();
@@ -200,6 +203,7 @@ namespace gsr {
ComboBox *streaming_service_box_ptr = nullptr; ComboBox *streaming_service_box_ptr = nullptr;
List *stream_key_list_ptr = nullptr; List *stream_key_list_ptr = nullptr;
List *custom_stream_list_ptr = nullptr; List *custom_stream_list_ptr = nullptr;
List *kick_stream_list_ptr = nullptr;
CheckBox *save_replay_in_game_folder_ptr = nullptr; CheckBox *save_replay_in_game_folder_ptr = nullptr;
CheckBox *restart_replay_on_save = nullptr; CheckBox *restart_replay_on_save = nullptr;
Label *estimated_file_size_ptr = nullptr; Label *estimated_file_size_ptr = nullptr;

View File

@@ -6,7 +6,7 @@
namespace gsr { namespace gsr {
class Tooltip : public Widget { class Tooltip : public Widget {
public: public:
Tooltip(mgl::Font *font); Tooltip(const char *font_desc);
Tooltip(const Tooltip&) = delete; Tooltip(const Tooltip&) = delete;
Tooltip& operator=(const Tooltip&) = delete; Tooltip& operator=(const Tooltip&) = delete;
@@ -15,7 +15,7 @@ namespace gsr {
mgl::vec2f get_size() override; mgl::vec2f get_size() override;
void set_text(std::string text); void set_text(std::string_view text);
private: private:
mgl::Text label; mgl::Text label;
}; };

View File

@@ -141,7 +141,6 @@ executable(
) )
install_subdir('images', install_dir : gsr_ui_resources_path) install_subdir('images', install_dir : gsr_ui_resources_path)
install_subdir('fonts', install_dir : gsr_ui_resources_path)
install_subdir('translations', install_dir : gsr_ui_resources_path) install_subdir('translations', install_dir : gsr_ui_resources_path)
if get_option('desktop-files') == true if get_option('desktop-files') == true

View File

@@ -39,13 +39,13 @@ namespace gsr {
static uint32_t mgl_key_modifiers_to_x11_modifier_mask(const mgl::Event::KeyEvent &key_event) { static uint32_t mgl_key_modifiers_to_x11_modifier_mask(const mgl::Event::KeyEvent &key_event) {
uint32_t mask = 0; uint32_t mask = 0;
if(key_event.shift) if(key_event.key_states.shift)
mask |= ShiftMask; mask |= ShiftMask;
if(key_event.control) if(key_event.key_states.control)
mask |= ControlMask; mask |= ControlMask;
if(key_event.alt) if(key_event.key_states.alt)
mask |= Mod1Mask; mask |= Mod1Mask;
if(key_event.system) if(key_event.key_states.system)
mask |= Mod4Mask; mask |= Mod4Mask;
return mask; return mask;
} }

View File

@@ -466,6 +466,14 @@ namespace gsr {
} }
} }
static double clock_get_monotonic_seconds(void) {
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (double)ts.tv_sec + (double)ts.tv_nsec * 0.000000001;
}
Overlay::Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, 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)), resources_path(std::move(resources_path)),
gsr_info(std::move(gsr_info)), gsr_info(std::move(gsr_info)),
@@ -476,6 +484,9 @@ namespace gsr {
top_bar_background({0.0f, 0.0f}), top_bar_background({0.0f, 0.0f}),
close_button_widget({0.0f, 0.0f}) close_button_widget({0.0f, 0.0f})
{ {
event_current_time_seconds = clock_get_monotonic_seconds();
gamescope_running_last_checked_seconds = event_current_time_seconds - 10.0;
if(this->gsr_info.system_info.display_server == DisplayServer::WAYLAND) { if(this->gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
wayland_dpy = wl_display_connect(nullptr); wayland_dpy = wl_display_connect(nullptr);
if(!wayland_dpy) if(!wayland_dpy)
@@ -487,10 +498,10 @@ namespace gsr {
gsr_icon_path = this->resources_path + "images/gpu_screen_recorder_logo.png"; gsr_icon_path = this->resources_path + "images/gpu_screen_recorder_logo.png";
key_bindings[0].key_event.code = mgl::Keyboard::Escape; key_bindings[0].key_event.code = mgl::Keyboard::Escape;
key_bindings[0].key_event.alt = false; key_bindings[0].key_event.key_states.alt = false;
key_bindings[0].key_event.control = false; key_bindings[0].key_event.key_states.control = false;
key_bindings[0].key_event.shift = false; key_bindings[0].key_event.key_states.shift = false;
key_bindings[0].key_event.system = false; key_bindings[0].key_event.key_states.system = false;
key_bindings[0].callback = [this]() { key_bindings[0].callback = [this]() {
page_stack.pop(); page_stack.pop();
}; };
@@ -712,10 +723,10 @@ namespace gsr {
} }
static uint32_t key_event_to_bitmask(mgl::Event::KeyEvent key_event) { static uint32_t key_event_to_bitmask(mgl::Event::KeyEvent key_event) {
return ((uint32_t)key_event.alt << (uint32_t)0) return ((uint32_t)key_event.key_states.alt << (uint32_t)0)
| ((uint32_t)key_event.control << (uint32_t)1) | ((uint32_t)key_event.key_states.control << (uint32_t)1)
| ((uint32_t)key_event.shift << (uint32_t)2) | ((uint32_t)key_event.key_states.shift << (uint32_t)2)
| ((uint32_t)key_event.system << (uint32_t)3); | ((uint32_t)key_event.key_states.system << (uint32_t)3);
} }
void Overlay::process_key_bindings(mgl::Event &event) { void Overlay::process_key_bindings(mgl::Event &event) {
@@ -729,6 +740,64 @@ namespace gsr {
} }
} }
static bool x11_window_is_steam_game(Display *dpy, Window window) {
unsigned long steam_game_id = 0;
unsigned int property_size = 0;
unsigned char* steam_game_property = window_get_property(dpy, window, XA_CARDINAL, "STEAM_GAME", &property_size);
if(steam_game_property) {
if(property_size == 8)
steam_game_id = *(unsigned long*)steam_game_property;
XFree(steam_game_property);
}
const unsigned long steam_webhelper_game_id = 769;
return steam_game_id != 0 && steam_game_id != steam_webhelper_game_id;
}
// WINE/Godot/Unity application detection
static bool x11_window_class_is_game(Display *dpy, Window window) {
XClassHint class_hint = {nullptr, nullptr};
XGetClassHint(dpy, window, &class_hint);
const bool is_godot_application = class_hint.res_name && strcmp(class_hint.res_name, "Godot_Engine") == 0;
const bool is_wine_application = class_hint.res_class && (ends_with(class_hint.res_class, ".exe") || ends_with(class_hint.res_class, ".EXE"));
const bool is_native_unity_32bit_application = class_hint.res_class && ends_with(class_hint.res_class, ".x86");
const bool is_native_unity_64bit_application = class_hint.res_class && (ends_with(class_hint.res_class, ".x86_64") || ends_with(class_hint.res_class, ".x64"));
if(class_hint.res_name)
XFree(class_hint.res_name);
if(class_hint.res_class)
XFree(class_hint.res_class);
return is_godot_application || is_wine_application || is_native_unity_32bit_application || is_native_unity_64bit_application;
}
static bool x11_window_is_game(Display *dpy, Window window) {
return x11_window_is_steam_game(dpy, window) || x11_window_class_is_game(dpy, window);
}
static bool x11_is_server_gamescope(Display *dpy) {
bool is_gamescope = false;
unsigned int property_size = 0;
unsigned char* gamescope_focused_window = window_get_property(dpy, DefaultRootWindow(dpy), XA_CARDINAL, "GAMESCOPE_FOCUSED_WINDOW", &property_size);
if(gamescope_focused_window) {
is_gamescope = true;
XFree(gamescope_focused_window);
}
return is_gamescope;
}
static bool is_gamescope_x11_server_running() {
bool is_gamescope = false;
Display *gamescope_x11_dpy = XOpenDisplay(":2");
if(gamescope_x11_dpy) {
is_gamescope = x11_is_server_gamescope(gamescope_x11_dpy);
XCloseDisplay(gamescope_x11_dpy);
}
return is_gamescope;
}
void Overlay::handle_keyboard_mapping_event() { void Overlay::handle_keyboard_mapping_event() {
if(!x11_dpy) if(!x11_dpy)
return; return;
@@ -743,9 +812,14 @@ namespace gsr {
break; break;
} }
case PropertyNotify: { case PropertyNotify: {
if(x11_xev.xproperty.state == PropertyNewValue && x11_xev.xproperty.atom == net_active_window_atom) { if(x11_xev.xproperty.state == PropertyNewValue && x11_xev.xproperty.atom == net_active_window_atom)
update_focused_window = true; update_focused_window = true;
break;
} }
case DestroyNotify: {
auto it = std::find(game_windows.begin(), game_windows.end(), x11_xev.xdestroywindow.window);
if(it != game_windows.end())
game_windows.erase(it);
break; break;
} }
} }
@@ -756,10 +830,35 @@ namespace gsr {
if(update_focused_window) { if(update_focused_window) {
update_focused_window = false; update_focused_window = false;
const Window focused_window = get_focused_window(x11_dpy, WindowCaptureType::FOCUSED, false);
if(x11_window_is_game(x11_dpy, focused_window)) {
if(std::find(game_windows.begin(), game_windows.end(), focused_window) == game_windows.end()) {
XSelectInput(x11_dpy, focused_window, StructureNotifyMask);
game_windows.push_back(focused_window);
}
}
}
if(event_current_time_seconds - gamescope_running_last_checked_seconds >= 3.0) {
gamescope_running_last_checked_seconds = event_current_time_seconds;
is_gamescope_running = is_gamescope_x11_server_running();
}
const bool prev_game_is_running = is_game_running;
is_game_running = !game_windows.empty() || is_gamescope_running;
if(is_game_running != prev_game_is_running) {
if(is_game_running) {
//fprintf(stderr, "started game\n");
} else {
//fprintf(stderr, "stopped game\n");
}
} }
} }
void Overlay::handle_events() { void Overlay::handle_events() {
event_current_time_seconds = clock_get_monotonic_seconds();
if(led_indicator) if(led_indicator)
led_indicator->update(); led_indicator->update();
@@ -788,6 +887,7 @@ namespace gsr {
} }
handle_keyboard_mapping_event(); handle_keyboard_mapping_event();
region_selector.poll_events(); region_selector.poll_events();
if(region_selector.take_canceled()) { if(region_selector.take_canceled()) {
on_region_selected = nullptr; on_region_selected = nullptr;
@@ -1189,15 +1289,15 @@ namespace gsr {
draw(); draw();
} }
void Overlay::recreate_global_hotkeys(const char *hotkey_option) { void Overlay::recreate_global_hotkeys(std::string_view hotkey_option) {
global_hotkeys.reset(); global_hotkeys.reset();
if(strcmp(hotkey_option, "enable_hotkeys") == 0) if(hotkey_option == "enable_hotkeys")
global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::ALL); global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::ALL);
else if(strcmp(hotkey_option, "enable_hotkeys_virtual_devices") == 0) else if(hotkey_option == "enable_hotkeys_virtual_devices")
global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::VIRTUAL); global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::VIRTUAL);
else if(strcmp(hotkey_option, "enable_hotkeys_no_grab") == 0) else if(hotkey_option == "enable_hotkeys_no_grab")
global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::NO_GRAB); global_hotkeys = register_linux_hotkeys(this, GlobalHotkeysLinux::GrabType::NO_GRAB);
else if(strcmp(hotkey_option, "disable_hotkeys") == 0) else if(hotkey_option == "disable_hotkeys")
global_hotkeys.reset(); global_hotkeys.reset();
} }
@@ -1213,7 +1313,7 @@ namespace gsr {
void Overlay::recreate_frontpage_ui_components() { void Overlay::recreate_frontpage_ui_components() {
bg_screenshot_overlay = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height)); bg_screenshot_overlay = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height));
top_bar_background = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height*0.06f).floor()); top_bar_background = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height*0.06f).floor());
top_bar_text = mgl::Text("GPU Screen Recorder", get_theme().top_bar_font); top_bar_text = mgl::Text("GPU Screen Recorder", get_theme().top_bar_font_desc.c_str());
logo_sprite = mgl::Sprite(&get_theme().logo_texture); logo_sprite = mgl::Sprite(&get_theme().logo_texture);
close_button_widget.set_size(mgl::vec2f(top_bar_background.get_size().y * 0.35f, top_bar_background.get_size().y * 0.35f).floor()); close_button_widget.set_size(mgl::vec2f(top_bar_background.get_size().y * 0.35f, top_bar_background.get_size().y * 0.35f).floor());
@@ -1245,7 +1345,7 @@ namespace gsr {
List * main_buttons_list_ptr = main_buttons_list.get(); List * main_buttons_list_ptr = main_buttons_list.get();
main_buttons_list->set_spacing(0.0f); main_buttons_list->set_spacing(0.0f);
{ {
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, TR("Instant Replay"), TR("Off"), &get_theme().replay_button_texture, auto button = std::make_unique<DropdownButton>(get_theme().title_font_desc.c_str(), get_theme().body_font_desc.c_str(), TR("Instant Replay"), TR("Off"), &get_theme().replay_button_texture,
mgl::vec2f(button_width, button_height)); mgl::vec2f(button_width, button_height));
replay_dropdown_button_ptr = button.get(); replay_dropdown_button_ptr = button.get();
button->add_item(TR("Turn on"), "start", config.replay_config.start_stop_hotkey.to_string(false, false)); button->add_item(TR("Turn on"), "start", config.replay_config.start_stop_hotkey.to_string(false, false));
@@ -1285,7 +1385,7 @@ namespace gsr {
main_buttons_list->add_widget(std::move(button)); main_buttons_list->add_widget(std::move(button));
} }
{ {
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, TR("Record"), TR("Not recording"), &get_theme().record_button_texture, auto button = std::make_unique<DropdownButton>(get_theme().title_font_desc.c_str(), get_theme().body_font_desc.c_str(), TR("Record"), TR("Not recording"), &get_theme().record_button_texture,
mgl::vec2f(button_width, button_height)); mgl::vec2f(button_width, button_height));
record_dropdown_button_ptr = button.get(); record_dropdown_button_ptr = button.get();
button->add_item(TR("Start"), "start", config.record_config.start_stop_hotkey.to_string(false, false)); button->add_item(TR("Start"), "start", config.record_config.start_stop_hotkey.to_string(false, false));
@@ -1314,7 +1414,7 @@ namespace gsr {
main_buttons_list->add_widget(std::move(button)); main_buttons_list->add_widget(std::move(button));
} }
{ {
auto button = std::make_unique<DropdownButton>(&get_theme().title_font, &get_theme().body_font, TR("Livestream"), TR("Not streaming"), &get_theme().stream_button_texture, auto button = std::make_unique<DropdownButton>(get_theme().title_font_desc.c_str(), get_theme().body_font_desc.c_str(), TR("Livestream"), TR("Not streaming"), &get_theme().stream_button_texture,
mgl::vec2f(button_width, button_height)); mgl::vec2f(button_width, button_height));
stream_dropdown_button_ptr = button.get(); stream_dropdown_button_ptr = button.get();
button->add_item(TR("Start"), "start", config.streaming_config.start_stop_hotkey.to_string(false, false)); button->add_item(TR("Start"), "start", config.streaming_config.start_stop_hotkey.to_string(false, false));
@@ -1345,7 +1445,7 @@ namespace gsr {
{ {
const mgl::vec2f main_buttons_size = main_buttons_list_ptr->get_size(); const mgl::vec2f main_buttons_size = main_buttons_list_ptr->get_size();
const int settings_button_size = main_buttons_size.y * 0.33f; const int settings_button_size = main_buttons_size.y * 0.33f;
auto button = std::make_unique<Button>(&get_theme().title_font, "", mgl::vec2f(settings_button_size, settings_button_size), mgl::Color(0, 0, 0, 180)); auto button = std::make_unique<Button>(get_theme().title_font_desc.c_str(), "", 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_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_bg_hover_color(mgl::Color(0, 0, 0, 255));
button->set_icon(&get_theme().settings_small_texture); button->set_icon(&get_theme().settings_small_texture);
@@ -1378,20 +1478,20 @@ namespace gsr {
show_notification(TR("Failed to remove GPU Screen Recorder from system startup"), notification_timeout_seconds, mgl::Color(255, 255, 255), mgl::Color(255, 0, 0), NotificationType::NOTICE, nullptr, NotificationLevel::ERROR); show_notification(TR("Failed to remove GPU Screen Recorder from system startup"), notification_timeout_seconds, mgl::Color(255, 255, 255), mgl::Color(255, 0, 0), NotificationType::NOTICE, nullptr, NotificationLevel::ERROR);
}; };
settings_page->on_click_exit_program_button = [this](const char *reason) { settings_page->on_click_exit_program_button = [this](std::string_view reason) {
do_exit = true; do_exit = true;
exit_reason = reason; exit_reason = reason;
}; };
settings_page->on_keyboard_hotkey_changed = [this](const char *hotkey_option) { settings_page->on_keyboard_hotkey_changed = [this](std::string_view hotkey_option) {
recreate_global_hotkeys(hotkey_option); recreate_global_hotkeys(hotkey_option);
}; };
settings_page->on_joystick_hotkey_changed = [this](const char *hotkey_option) { settings_page->on_joystick_hotkey_changed = [this](std::string_view hotkey_option) {
global_hotkeys_js.reset(); global_hotkeys_js.reset();
if(strcmp(hotkey_option, "enable_hotkeys") == 0) if(hotkey_option == "enable_hotkeys")
global_hotkeys_js = register_joystick_hotkeys(this); global_hotkeys_js = register_joystick_hotkeys(this);
else if(strcmp(hotkey_option, "disable_hotkeys") == 0) else if(hotkey_option == "disable_hotkeys")
global_hotkeys_js.reset(); global_hotkeys_js.reset();
}; };
@@ -1418,7 +1518,7 @@ namespace gsr {
{ {
const mgl::vec2f main_buttons_size = main_buttons_list_ptr->get_size(); const mgl::vec2f main_buttons_size = main_buttons_list_ptr->get_size();
const int settings_button_size = main_buttons_size.y * 0.33f; const int settings_button_size = main_buttons_size.y * 0.33f;
auto button = std::make_unique<Button>(&get_theme().title_font, "", mgl::vec2f(settings_button_size, settings_button_size), mgl::Color(0, 0, 0, 180)); auto button = std::make_unique<Button>(get_theme().title_font_desc.c_str(), "", 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*2) + mgl::vec2f(settings_button_size * 0.333f, 0.0f)).floor()); button->set_position((main_buttons_list_ptr->get_position() + main_buttons_size - mgl::vec2f(0.0f, settings_button_size*2) + mgl::vec2f(settings_button_size * 0.333f, 0.0f)).floor());
button->set_bg_hover_color(mgl::Color(0, 0, 0, 255)); button->set_bg_hover_color(mgl::Color(0, 0, 0, 255));
button->set_icon(&get_theme().screenshot_texture); button->set_icon(&get_theme().screenshot_texture);

View File

@@ -39,17 +39,10 @@ namespace gsr {
window_width = window_size.x; window_width = window_size.x;
window_height = window_size.y; window_height = window_size.y;
if(!theme->title_font.load_from_file(theme->title_font_file, std::max(16.0f, window_size.y * 0.019f))) theme->title_font_desc = std::string("Noto Sans Bold ") + std::to_string((int)(std::max(16.0f, window_size.y * 0.019f)/1.8));
return false; theme->top_bar_font_desc = std::string("Noto Sans Bold ") + std::to_string((int)(std::max(23.0f, window_size.y * 0.03f)/1.8));
theme->body_font_desc = std::string("Noto Sans ") + std::to_string((int)(std::max(13.0f, window_size.y * 0.015f)/1.8));
if(!theme->top_bar_font.load_from_file(theme->title_font_file, std::max(23.0f, window_size.y * 0.03f))) theme->camera_setup_font_desc = "Noto Sans 14";
return false;
if(!theme->body_font.load_from_file(theme->body_font_file, std::max(13.0f, window_size.y * 0.015f)))
return false;
if(!theme->camera_setup_font.load_from_file(theme->body_font_file, 24))
return false;
return true; return true;
} }
@@ -60,12 +53,6 @@ namespace gsr {
theme = new Theme(); theme = new Theme();
if(!theme->body_font_file.load((resources_path + "fonts/NotoSans-Regular.ttf").c_str(), mgl::MemoryMappedFile::LoadOptions{true, false}))
goto error;
if(!theme->title_font_file.load((resources_path + "fonts/NotoSans-Bold.ttf").c_str(), mgl::MemoryMappedFile::LoadOptions{true, false}))
goto error;
if(!theme->combobox_arrow_texture.load_from_file((resources_path + "images/combobox_arrow.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP})) if(!theme->combobox_arrow_texture.load_from_file((resources_path + "images/combobox_arrow.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error; goto error;

View File

@@ -42,13 +42,13 @@ namespace gsr {
} }
} }
bool Translation::is_language_supported(const char* lang) { bool Translation::is_language_supported(std::string_view lang) {
if(strcmp(lang, "en") == 0) if(lang == "en")
return true; return true;
std::string paths[] = { std::string paths[] = {
std::string("translations/") + lang + ".txt", std::string("translations/") + std::string(lang) + ".txt",
std::string(this->translations_directory) + lang + ".txt" std::string(this->translations_directory) + std::string(lang) + ".txt"
}; };
for (const auto& path : paths) { for (const auto& path : paths) {
@@ -61,27 +61,27 @@ namespace gsr {
return false; return false;
} }
bool Translation::load_language(const char* lang) { bool Translation::load_language(std::string_view lang) {
translations.clear(); translations.clear();
const std::string system_language = get_system_language(); const std::string system_language = get_system_language();
if(!lang || lang[0] == '\0') if(lang.empty())
lang = system_language.c_str(); lang = system_language;
if (!is_language_supported(lang)) { if (!is_language_supported(lang)) {
fprintf(stderr, "Warning: language '%s' is not supported\n", lang); fprintf(stderr, "Warning: language '%.*s' is not supported\n", (int)lang.size(), lang.data());
return false; return false;
} }
current_language = lang; current_language = lang;
if (strcmp(lang, "en") == 0) { if (lang == "en") {
return true; // english is the base return true; // english is the base
} }
std::string paths[] = { std::string paths[] = {
std::string("translations/") + lang + ".txt", std::string("translations/") + std::string(lang) + ".txt",
std::string(this->translations_directory) + lang + ".txt" std::string(this->translations_directory) + std::string(lang) + ".txt"
}; };
for (const auto& path : paths) { for (const auto& path : paths) {
@@ -105,11 +105,11 @@ namespace gsr {
translations[key] = value; translations[key] = value;
} }
fprintf(stderr, "Info: Loaded translation file for '%s' from %s\n", lang, path.c_str()); fprintf(stderr, "Info: Loaded translation file for '%.*s' from %s\n", (int)lang.size(), lang.data(), path.c_str());
return true; return true;
} }
fprintf(stderr, "Warning: translation file for '%s' not found\n", lang); fprintf(stderr, "Warning: translation file for '%.*s' not found\n", (int)lang.size(), lang.data());
return false; return false;
} }

View File

@@ -18,8 +18,8 @@ namespace gsr {
//static const float padding_left_icon_scale = 0.25f; //static const float padding_left_icon_scale = 0.25f;
static const float padding_right_icon_scale = 0.15f; static const float padding_right_icon_scale = 0.15f;
Button::Button(mgl::Font *font, const char *text, mgl::vec2f size, mgl::Color bg_color) : Button::Button(const char *font_desc, const char *text, mgl::vec2f size, mgl::Color bg_color) :
size(size), bg_color(bg_color), bg_hover_color(bg_color), text(text, *font) size(size), bg_color(bg_color), bg_hover_color(bg_color), text(text, font_desc)
{ {
} }
@@ -117,12 +117,12 @@ namespace gsr {
sprite.set_texture(texture); sprite.set_texture(texture);
} }
const std::string& Button::get_text() const { std::string_view Button::get_text() const {
return text.get_string(); return text.get_string();
} }
void Button::set_text(std::string str) { void Button::set_text(std::string_view str) {
text.set_string(std::move(str)); text.set_string(str);
} }
void Button::scale_sprite_to_button_size() { void Button::scale_sprite_to_button_size() {

View File

@@ -27,8 +27,8 @@ namespace gsr {
return color; return color;
} }
CheckBox::CheckBox(mgl::Font *font, const char *text) : CheckBox::CheckBox(const char *font_desc, const char *text) :
text(text, *font), text(text, font_desc),
background_sprite(&get_theme().checkbox_background_texture), background_sprite(&get_theme().checkbox_background_texture),
circle_sprite(&get_theme().checkbox_circle_texture) circle_sprite(&get_theme().checkbox_circle_texture)
{ {

View File

@@ -2,7 +2,6 @@
#include "../../include/gui/Utils.hpp" #include "../../include/gui/Utils.hpp"
#include "../../include/Theme.hpp" #include "../../include/Theme.hpp"
#include <mglpp/graphics/Rectangle.hpp> #include <mglpp/graphics/Rectangle.hpp>
#include <mglpp/graphics/Font.hpp>
#include <mglpp/window/Window.hpp> #include <mglpp/window/Window.hpp>
#include <mglpp/window/Event.hpp> #include <mglpp/window/Event.hpp>
#include <assert.h> #include <assert.h>
@@ -14,8 +13,9 @@ namespace gsr {
static const float padding_right_scale = 0.007f; static const float padding_right_scale = 0.007f;
static const float border_scale = 0.0015f; static const float border_scale = 0.0015f;
ComboBox::ComboBox(mgl::Font *font) : font(font), dropdown_arrow(&get_theme().combobox_arrow_texture) { ComboBox::ComboBox(const char *font_desc) : font_desc(font_desc), dropdown_arrow(&get_theme().combobox_arrow_texture) {
assert(font); assert(font_desc);
font_size = mgl::Text::get_font_size_from_font_description(font_desc);
} }
bool ComboBox::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) { bool ComboBox::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
@@ -83,7 +83,7 @@ namespace gsr {
draw_unselected(window, draw_pos); draw_unselected(window, draw_pos);
} }
void ComboBox::add_item(const std::string &text, const std::string &id, bool allow_duplicate) { void ComboBox::add_item(std::string_view text, const std::string &id, bool allow_duplicate) {
if(!allow_duplicate) { if(!allow_duplicate) {
for(const auto &item : items) { for(const auto &item : items) {
if(item.id == id) if(item.id == id)
@@ -91,9 +91,9 @@ namespace gsr {
} }
} }
items.push_back({mgl::Text(text, *font), id, {0.0f, 0.0f}}); items.push_back({mgl::Text(text, font_desc.c_str()), id, {0.0f, 0.0f}});
items.back().text.set_max_width(font->get_character_size() * 20); // TODO: Make a proper solution items.back().text.set_wrap_width(items.back().text.get_font_size() * 40); // TODO: Make a proper solution
//items.back().text.set_max_rows(1); items.back().text.set_max_rows(2);
dirty = true; dirty = true;
} }
@@ -104,7 +104,7 @@ namespace gsr {
dirty = true; dirty = true;
} }
void ComboBox::set_selected_item(const std::string &id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) { void ComboBox::set_selected_item(std::string_view id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) {
for(size_t i = 0; i < items.size(); ++i) { for(size_t i = 0; i < items.size(); ++i) {
auto &item = items[i]; auto &item = items[i];
if(item.id == id && item.enabled) { if(item.id == id && item.enabled) {
@@ -120,7 +120,7 @@ namespace gsr {
} }
} }
void ComboBox::set_item_enabled(const std::string &id, bool enabled) { void ComboBox::set_item_enabled(std::string_view id, bool enabled) {
for(size_t i = 0; i < items.size(); ++i) { for(size_t i = 0; i < items.size(); ++i) {
auto &item = items[i]; auto &item = items[i];
if(item.id == id) { if(item.id == id) {
@@ -136,10 +136,9 @@ namespace gsr {
} }
} }
const std::string& ComboBox::get_selected_id() const { std::string_view ComboBox::get_selected_id() const {
if(items.empty()) { if(items.empty()) {
static std::string dummy; return "";
return dummy;
} else { } else {
return items[selected_item].id; return items[selected_item].id;
} }
@@ -240,7 +239,7 @@ namespace gsr {
const int padding_right = padding_right_scale * get_theme().window_height; const int padding_right = padding_right_scale * get_theme().window_height;
Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr; Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr;
max_size = { 0.0f, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : font->get_character_size()) }; max_size = { 0.0f, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : font_size) };
for(Item &item : items) { for(Item &item : items) {
const mgl::vec2f bounds = item.text.get_bounds().size; const mgl::vec2f bounds = item.text.get_bounds().size;
max_size.x = std::max(max_size.x, bounds.x + padding_left + padding_right); max_size.x = std::max(max_size.x, bounds.x + padding_left + padding_right);
@@ -263,12 +262,12 @@ namespace gsr {
const int padding_top = padding_top_scale * get_theme().window_height; const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_bottom = padding_bottom_scale * get_theme().window_height; const int padding_bottom = padding_bottom_scale * get_theme().window_height;
Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr; Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr;
return { max_size.x, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : font->get_character_size()) }; return { max_size.x, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : font_size) };
} }
float ComboBox::get_dropdown_arrow_height() const { float ComboBox::get_dropdown_arrow_height() const {
const int padding_top = padding_top_scale * get_theme().window_height; const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_bottom = padding_bottom_scale * get_theme().window_height; const int padding_bottom = padding_bottom_scale * get_theme().window_height;
return (font->get_character_size() + padding_top + padding_bottom) * 0.4f; return (font_size * 2.0f + padding_top + padding_bottom) * 0.4f;
} }
} }

View File

@@ -15,8 +15,12 @@ namespace gsr {
static const float icon_spacing_scale = 0.008f; static const float icon_spacing_scale = 0.008f;
static const float border_scale = 0.003f; static const float border_scale = 0.003f;
DropdownButton::DropdownButton(mgl::Font *title_font, mgl::Font *description_font, const char *title, const char *description, mgl::Texture *icon_texture, mgl::vec2f size) : DropdownButton::DropdownButton(const char *title_font_desc, const char *description_font_desc, const char *title, const char *description, mgl::Texture *icon_texture, mgl::vec2f size) :
title_font(title_font), description_font(description_font), size(size), title(title, *title_font), description(description, *description_font) title_font_desc(title_font_desc),
description_font_desc(description_font_desc),
size(size),
title(title, title_font_desc),
description(description, description_font_desc)
{ {
if(icon_texture && icon_texture->is_valid()) { if(icon_texture && icon_texture->is_valid()) {
icon_sprite.set_texture(icon_texture); icon_sprite.set_texture(icon_texture);
@@ -193,11 +197,11 @@ namespace gsr {
if(item.id == id) if(item.id == id)
return; return;
} }
items.push_back({mgl::Text(text, *title_font), mgl::Text(description, *description_font), nullptr, id}); items.push_back({mgl::Text(text, title_font_desc.c_str()), mgl::Text(description, description_font_desc.c_str()), nullptr, id});
dirty = true; dirty = true;
} }
void DropdownButton::set_item_label(const std::string &id, const std::string &new_label) { void DropdownButton::set_item_label(std::string_view id, const std::string &new_label) {
for(auto &item : items) { for(auto &item : items) {
if(item.id == id) { if(item.id == id) {
item.text.set_string(new_label); item.text.set_string(new_label);
@@ -206,7 +210,7 @@ namespace gsr {
} }
} }
void DropdownButton::set_item_icon(const std::string &id, mgl::Texture *texture) { void DropdownButton::set_item_icon(std::string_view id, mgl::Texture *texture) {
for(auto &item : items) { for(auto &item : items) {
if(item.id == id) { if(item.id == id) {
item.icon_texture = texture; item.icon_texture = texture;
@@ -215,7 +219,7 @@ namespace gsr {
} }
} }
void DropdownButton::set_item_description(const std::string &id, const std::string &new_description) { void DropdownButton::set_item_description(std::string_view id, const std::string &new_description) {
for(auto &item : items) { for(auto &item : items) {
if(item.id == id) { if(item.id == id) {
item.description_text.set_string(new_description); item.description_text.set_string(new_description);
@@ -224,7 +228,7 @@ namespace gsr {
} }
} }
void DropdownButton::set_item_enabled(const std::string &id, bool enabled) { void DropdownButton::set_item_enabled(std::string_view id, bool enabled) {
for(auto &item : items) { for(auto &item : items) {
if(item.id == id) { if(item.id == id) {
item.enabled = enabled; item.enabled = enabled;

View File

@@ -3,10 +3,7 @@
#include "../../include/Theme.hpp" #include "../../include/Theme.hpp"
#include <mglpp/window/Window.hpp> #include <mglpp/window/Window.hpp>
#include <mglpp/window/Event.hpp> #include <mglpp/window/Event.hpp>
#include <mglpp/system/FloatRect.hpp> #include <string>
#include <mglpp/system/Utf8.hpp>
#include <optional>
#include <string.h>
namespace gsr { namespace gsr {
static const float padding_top_scale = 0.004629f; static const float padding_top_scale = 0.004629f;
@@ -14,153 +11,30 @@ namespace gsr {
static const float padding_left_scale = 0.007f; static const float padding_left_scale = 0.007f;
static const float padding_right_scale = 0.007f; static const float padding_right_scale = 0.007f;
static const float border_scale = 0.0015f; static const float border_scale = 0.0015f;
static const float caret_width_scale = 0.001f;
static void string_replace_all(std::string &str, char old_char, char new_char) { Entry::Entry(const char *font_desc, const char *text, float max_width) :
for(char &c : str) { text_edit(font_desc, std::max(0.0f, max_width - (padding_left_scale * get_theme().window_height) - (padding_right_scale * get_theme().window_height))),
if(c == old_char)
c = new_char;
}
}
Entry::Entry(mgl::Font *font, const char *text, float max_width) :
text(std::u32string(), *font),
masked_text(std::u32string(), *font),
max_width(max_width) max_width(max_width)
{ {
this->text.set_color(get_color_theme().text_color); const int padding_top = padding_top_scale * get_theme().window_height;
this->masked_text.set_color(get_color_theme().text_color); const int padding_bottom = padding_bottom_scale * get_theme().window_height;
const int padding_left = padding_left_scale * get_theme().window_height;
const int padding_right = padding_right_scale * get_theme().window_height;
text_edit.set_single_paragraph_mode(true);
text_edit.set_color(get_color_theme().text_color);
text_edit.set_margins(padding_left, padding_top, padding_right, padding_bottom);
set_text(text); set_text(text);
text_edit.sync();
} }
bool Entry::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) { bool Entry::on_event(mgl::Event &event, mgl::Window &/*window*/, mgl::vec2f /*offset*/) {
if(!visible) if(!visible)
return true; return true;
mgl::Text32 &active_text = masked ? masked_text : text; if(text_edit.handle_event(event)) {
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left)
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) { return true;
const mgl::vec2f mouse_pos = { (float)event.mouse_button.x, (float)event.mouse_button.y };
selected = mgl::FloatRect(position + offset, get_size()).contains(mouse_pos);
if(selected) {
selecting_text = true;
const auto caret_index_mouse = find_closest_caret_index_by_position(mouse_pos);
caret.index = caret_index_mouse.index;
caret.offset_x = caret_index_mouse.pos.x - active_text.get_position().x;
selection_start_caret = caret;
show_selection = true;
} else {
selecting_text = false;
selecting_with_keyboard = false;
show_selection = false;
}
} else if(event.type == mgl::Event::MouseButtonReleased && event.mouse_button.button == mgl::Mouse::Left) {
selecting_text = false;
if(caret.index == selection_start_caret.index)
show_selection = false;
} else if(event.type == mgl::Event::MouseMoved && selected) {
if(selecting_text) {
const auto caret_index_mouse = find_closest_caret_index_by_position(mgl::vec2f(event.mouse_move.x, event.mouse_move.y));
caret.index = caret_index_mouse.index;
caret.offset_x = caret_index_mouse.pos.x - active_text.get_position().x;
return false;
}
} else if(event.type == mgl::Event::KeyPressed && selected) {
int selection_start_byte = caret.index;
int selection_end_byte = caret.index;
if(show_selection) {
selection_start_byte = std::min(caret.index, selection_start_caret.index);
selection_end_byte = std::max(caret.index, selection_start_caret.index);
}
if(event.key.code == mgl::Keyboard::Backspace) {
if(selection_start_byte == selection_end_byte && caret.index > 0)
selection_start_byte -= 1;
replace_text(selection_start_byte, selection_end_byte - selection_start_byte, std::u32string());
} else if(event.key.code == mgl::Keyboard::Delete) {
if(selection_start_byte == selection_end_byte && caret.index < (int)active_text.get_string().size())
selection_end_byte += 1;
replace_text(selection_start_byte, selection_end_byte - selection_start_byte, std::u32string());
} else if(event.key.code == mgl::Keyboard::C && event.key.control) {
const size_t selection_num_bytes = selection_end_byte - selection_start_byte;
if(selection_num_bytes > 0)
window.set_clipboard(mgl::utf32_to_utf8(text.get_string().substr(selection_start_byte, selection_num_bytes)));
} else if(event.key.code == mgl::Keyboard::V && event.key.control) {
std::string clipboard_string = window.get_clipboard_string();
string_replace_all(clipboard_string, '\n', ' ');
replace_text(selection_start_byte, selection_end_byte - selection_start_byte, mgl::utf8_to_utf32(clipboard_string));
} else if(event.key.code == mgl::Keyboard::A && event.key.control) {
selection_start_caret.index = 0;
selection_start_caret.offset_x = 0.0f;
caret.index = active_text.get_string().size();
// TODO: Optimize
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
show_selection = true;
} else if(event.key.code == mgl::Keyboard::Left) {
if(!selecting_with_keyboard && show_selection)
show_selection = false;
else
move_caret_word(Direction::LEFT, event.key.control ? 999999 : 1);
if(!selecting_with_keyboard) {
selection_start_caret = caret;
show_selection = false;
}
} else if(event.key.code == mgl::Keyboard::Right) {
if(!selecting_with_keyboard && show_selection)
show_selection = false;
else
move_caret_word(Direction::RIGHT, event.key.control ? 999999 : 1);
if(!selecting_with_keyboard) {
selection_start_caret = caret;
show_selection = false;
}
} else if(event.key.code == mgl::Keyboard::Home) {
caret.index = 0;
caret.offset_x = 0.0f;
if(!selecting_with_keyboard) {
selection_start_caret = caret;
show_selection = false;
}
} else if(event.key.code == mgl::Keyboard::End) {
caret.index = active_text.get_string().size();
// TODO: Optimize
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
if(!selecting_with_keyboard) {
selection_start_caret = caret;
show_selection = false;
}
} else if(event.key.code == mgl::Keyboard::LShift || event.key.code == mgl::Keyboard::RShift) {
if(!show_selection)
selection_start_caret = caret;
selecting_with_keyboard = true;
show_selection = true;
}
return false;
} else if(event.type == mgl::Event::KeyReleased && selected) {
if(event.key.code == mgl::Keyboard::LShift || event.key.code == mgl::Keyboard::RShift) {
selecting_with_keyboard = false;
}
return false;
} else if(event.type == mgl::Event::TextEntered && selected && event.text.codepoint >= 32 && event.text.codepoint != 127) {
int selection_start_byte = caret.index;
int selection_end_byte = caret.index;
if(show_selection) {
selection_start_byte = std::min(caret.index, selection_start_caret.index);
selection_end_byte = std::max(caret.index, selection_start_caret.index);
}
replace_text(selection_start_byte, selection_end_byte - selection_start_byte, mgl::utf8_to_utf32((const unsigned char*)event.text.str, event.text.size));
return false; return false;
} }
@@ -173,297 +47,47 @@ namespace gsr {
const mgl::vec2f draw_pos = position + offset; const mgl::vec2f draw_pos = position + offset;
const int padding_top = padding_top_scale * get_theme().window_height; const mgl::vec2f size = get_size();
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
const int padding_left = padding_left_scale * get_theme().window_height;
const int padding_right = padding_right_scale * get_theme().window_height;
mgl::Text32 &active_text = masked ? masked_text : text; background.set_size(size);
background.set_size(get_size());
background.set_position(draw_pos.floor()); background.set_position(draw_pos.floor());
background.set_color(selected ? mgl::Color(0, 0, 0, 255) : mgl::Color(0, 0, 0, 120)); background.set_color(text_edit.is_focused() ? mgl::Color(0, 0, 0, 255) : mgl::Color(0, 0, 0, 120));
window.draw(background); window.draw(background);
const int caret_width = std::max(1.0f, caret_width_scale * get_theme().window_height); if(text_edit.is_focused()) {
const mgl::vec2f caret_size = mgl::vec2f(caret_width, active_text.get_bounds().size.y).floor();
const float overflow_left = (caret.offset_x + padding_left) - (padding_left + text_overflow);
if(overflow_left < 0.0f)
text_overflow += overflow_left;
const float overflow_right = (caret.offset_x + padding_left) - (background.get_size().x - padding_right);
if(overflow_right - text_overflow > 0.0f)
text_overflow = overflow_right;
active_text.set_position((draw_pos + mgl::vec2f(padding_left, get_size().y * 0.5f - active_text.get_bounds().size.y * 0.5f) - mgl::vec2f(text_overflow, 0.0f)).floor());
const auto text_bounds = active_text.get_bounds();
const bool text_larger_than_background = text_bounds.size.x > (background.get_size().x - padding_left - padding_right);
const float text_overflow_right = (text_bounds.position.x + text_bounds.size.x) - (background.get_position().x + background.get_size().x - padding_right);
if(text_larger_than_background) {
if(text_overflow_right < 0.0f) {
text_overflow += text_overflow_right;
active_text.set_position(active_text.get_position() + mgl::vec2f(-text_overflow_right, 0.0f));
}
} else {
active_text.set_position(active_text.get_position() + mgl::vec2f(-text_overflow, 0.0f));
text_overflow = 0.0f;
}
if(selected) {
const int border_size = std::max(1.0f, border_scale * get_theme().window_height); const int border_size = std::max(1.0f, border_scale * get_theme().window_height);
draw_rectangle_outline(window, draw_pos.floor(), get_size().floor(), get_color_theme().tint_color, border_size); draw_rectangle_outline(window, draw_pos.floor(), size.floor(), get_color_theme().tint_color, border_size);
draw_caret(window, draw_pos, caret_size);
} }
const mgl::Scissor parent_scissor = window.get_scissor(); text_edit.set_position(draw_pos.floor());
const mgl::Scissor scissor = scissor_get_sub_area(parent_scissor, window.draw(text_edit);
mgl::Scissor{
(background.get_position() + mgl::vec2f(padding_left, padding_top)).to_vec2i(),
(background.get_size() - mgl::vec2f(padding_left + padding_right, padding_top + padding_bottom)).to_vec2i()
});
window.set_scissor(scissor);
window.draw(active_text);
if(show_selection)
draw_caret_selection(window, draw_pos, caret_size);
window.set_scissor(parent_scissor);
}
void Entry::draw_caret(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size) {
const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_left = padding_left_scale * get_theme().window_height;
mgl::Rectangle caret_rect(caret_size);
mgl::vec2f caret_draw_pos = draw_pos + mgl::vec2f(padding_left + caret.offset_x - text_overflow, padding_top);
caret_rect.set_position(caret_draw_pos.floor());
caret_rect.set_color(mgl::Color(255, 255, 255));
window.draw(caret_rect);
}
void Entry::draw_caret_selection(mgl::Window &window, mgl::vec2f draw_pos, mgl::vec2f caret_size) {
if(selection_start_caret.index == caret.index)
return;
const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_left = padding_left_scale * get_theme().window_height;
const int caret_width = std::max(1.0f, caret_width_scale * get_theme().window_height);
const int offset = caret.index < selection_start_caret.index ? caret_width : 0;
mgl::Rectangle caret_selection_rect(mgl::vec2f(std::abs(selection_start_caret.offset_x - caret.offset_x) - offset, caret_size.y).floor());
caret_selection_rect.set_position((draw_pos + mgl::vec2f(padding_left + std::min(caret.offset_x, selection_start_caret.offset_x) - text_overflow + offset, padding_top)).floor());
mgl::Color caret_select_color = get_color_theme().tint_color;
caret_select_color.a = 100;
caret_selection_rect.set_color(caret_select_color);
window.draw(caret_selection_rect);
} }
mgl::vec2f Entry::get_size() { mgl::vec2f Entry::get_size() {
if(!visible) if(!visible)
return {0.0f, 0.0f}; return {0.0f, 0.0f};
const int padding_top = padding_top_scale * get_theme().window_height; const mgl::vec2i text_size = text_edit.get_size(true);
const int padding_bottom = padding_bottom_scale * get_theme().window_height; return text_size.to_vec2f();
return { max_width, text.get_bounds().size.y + padding_top + padding_bottom };
} }
void Entry::move_caret_word(Direction direction, size_t max_codepoints) { void Entry::set_text(std::string_view str) {
mgl::Text32 &active_text = masked ? masked_text : text; text_edit.set_text(std::string(str).c_str());
const int dir_step = direction == Direction::LEFT ? -1 : 1;
const int num_delimiter_chars = 15;
const char delimiter_chars[num_delimiter_chars + 1] = " \t\n/.,:;\\[](){}";
const char32_t *text_str = active_text.get_string().data();
int num_non_delimiter_chars_found = 0;
for(size_t i = 0; i < max_codepoints; ++i) {
const uint32_t codepoint = text_str[caret.index];
const bool is_delimiter_char = codepoint < 127 && !!memchr(delimiter_chars, codepoint, num_delimiter_chars);
if(is_delimiter_char) {
if(num_non_delimiter_chars_found > 0)
break;
} else {
++num_non_delimiter_chars_found;
} }
if(caret.index + dir_step < 0 || caret.index + dir_step > (int)active_text.get_string().size()) std::string_view Entry::get_text() const {
break; return text_edit.get_text();
caret.index += dir_step;
}
// TODO: Move right by some characters instead of calculating every character to caret index
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
}
EntryValidateHandlerResult Entry::set_text(const std::string &str) {
EntryValidateHandlerResult validate_result = set_text_internal(mgl::utf8_to_utf32(str));
if(validate_result == EntryValidateHandlerResult::ALLOW) {
mgl::Text32 &active_text = masked ? masked_text : text;
caret.index = active_text.get_string().size();
// TODO: Optimize
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
selection_start_caret = caret;
selecting_text = false;
selecting_with_keyboard = false;
show_selection = false;
}
return validate_result;
}
EntryValidateHandlerResult Entry::set_text_internal(std::u32string str) {
EntryValidateHandlerResult validate_result = EntryValidateHandlerResult::ALLOW;
if(validate_handler)
validate_result = validate_handler(*this, str);
if(validate_result == EntryValidateHandlerResult::ALLOW) {
text.set_string(std::move(str));
if(masked)
masked_text.set_string(std::u32string(text.get_string().size(), '*'));
// TODO: Call callback with utf32 instead?
if(on_changed)
on_changed(mgl::utf32_to_utf8(text.get_string()));
}
return validate_result;
}
std::string Entry::get_text() const {
return mgl::utf32_to_utf8(text.get_string());
} }
void Entry::set_masked(bool masked) { void Entry::set_masked(bool masked) {
if(masked == this->masked) text_edit.set_masked(masked);
return;
this->masked = masked;
if(masked)
masked_text.set_string(std::u32string(text.get_string().size(), '*'));
else
masked_text.set_string(std::u32string());
mgl::Text32 &active_text = masked ? masked_text : text;
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
selection_start_caret.offset_x = active_text.find_character_pos(selection_start_caret.index).x - active_text.get_position().x;
} }
bool Entry::is_masked() const { bool Entry::is_masked() const {
return masked; return text_edit.is_masked();
} }
void Entry::replace_text(size_t index, size_t size, const std::u32string &replacement) { void Entry::set_number_mode(bool enabled, int min_val, int max_val) {
if(index + size > text.get_string().size()) text_edit.set_number_mode(enabled, min_val, max_val);
return;
const auto prev_caret = caret;
if((int)index >= caret.index)
caret.index += replacement.size();
else
caret.index = caret.index - size + replacement.size();
std::u32string str = text.get_string();
str.replace(index, size, replacement);
const EntryValidateHandlerResult validate_result = set_text_internal(std::move(str));
if(validate_result == EntryValidateHandlerResult::DENY) {
caret = prev_caret;
return;
} else if(validate_result == EntryValidateHandlerResult::REPLACED) {
return;
}
mgl::Text32 &active_text = masked ? masked_text : text;
// TODO: Optimize
caret.offset_x = active_text.find_character_pos(caret.index).x - active_text.get_position().x;
selection_start_caret = caret;
selecting_text = false;
selecting_with_keyboard = false;
show_selection = false;
}
CaretIndexPos Entry::find_closest_caret_index_by_position(mgl::vec2f position) {
mgl::Text32 &active_text = masked ? masked_text : text;
const std::u32string &str = active_text.get_string();
mgl::Font *font = active_text.get_font();
CaretIndexPos result = {0, {active_text.get_position().x, active_text.get_position().y}};
for(result.index = 0; result.index < (int)str.size(); ++result.index) {
const uint32_t codepoint = str[result.index];
float glyph_width = 0.0f;
if(codepoint == '\t') {
const auto glyph = font->get_glyph(' ');
const int tab_width = 4;
glyph_width = glyph.advance * tab_width;
} else {
const auto glyph = font->get_glyph(codepoint);
glyph_width = glyph.advance;
}
if(result.pos.x + glyph_width * 0.5f >= position.x)
break;
result.pos.x += glyph_width;
}
return result;
}
static bool is_number(uint8_t c) {
return c >= '0' && c <= '9';
}
static std::optional<int> to_integer(const std::u32string &str) {
if(str.empty())
return std::nullopt;
size_t i = 0;
const bool negative = str[0] == '-';
if(negative)
i = 1;
int number = 0;
for(; i < str.size(); ++i) {
if(!is_number(str[i]))
return std::nullopt;
const int new_number = number * 10 + (str[i] - '0');
if(new_number < number)
return std::nullopt; // Overflow
number = new_number;
}
if(negative)
number = -number;
return number;
}
EntryValidateHandler create_entry_validator_integer_in_range(int min, int max) {
return [min, max](Entry &entry, const std::u32string &str) {
if(str.empty())
return EntryValidateHandlerResult::ALLOW;
const std::optional<int> number = to_integer(str);
if(!number)
return EntryValidateHandlerResult::DENY;
if(number.value() < min) {
entry.set_text(std::to_string(min));
return EntryValidateHandlerResult::REPLACED;
} else if(number.value() > max) {
entry.set_text(std::to_string(max));
return EntryValidateHandlerResult::REPLACED;
}
return EntryValidateHandlerResult::ALLOW;
};
} }
} }

View File

@@ -54,7 +54,7 @@ namespace gsr {
times_clicked_within_timer = 1; times_clicked_within_timer = 1;
if(selected_item != -1 && times_clicked_within_timer > 0 && times_clicked_within_timer % 2 == 0) { if(selected_item != -1 && times_clicked_within_timer > 0 && times_clicked_within_timer % 2 == 0) {
file_chooser->open_subdirectory(folders[selected_item].text.get_string().c_str()); file_chooser->open_subdirectory(folders[selected_item].text.get_string());
} }
} }
return true; return true;
@@ -115,7 +115,7 @@ namespace gsr {
window.draw(folder_sprite); window.draw(folder_sprite);
// TODO: Dont allow text to go further left/right than item_pos (on the left side) and item_pos + item_size (on the right side). // TODO: Dont allow text to go further left/right than item_pos (on the left side) and item_pos + item_size (on the right side).
folder.text.set_max_width(item_size.x); folder.text.set_wrap_width(item_size.x);
folder.text.set_max_rows(2); folder.text.set_max_rows(2);
folder.text.set_position((folder_sprite.get_position() + mgl::vec2f(folder_sprite.get_size().x * 0.5f - folder.text.get_bounds().size.x * 0.5f, folder_sprite.get_size().y + folder_text_spacing_scale * get_theme().window_height)).floor()); folder.text.set_position((folder_sprite.get_position() + mgl::vec2f(folder_sprite.get_size().x * 0.5f - folder.text.get_bounds().size.x * 0.5f, folder_sprite.get_size().y + folder_text_spacing_scale * get_theme().window_height)).floor());
window.draw(folder.text); window.draw(folder.text);
@@ -136,14 +136,17 @@ namespace gsr {
inner_size = mgl::vec2f(size.x, folder_pos.y - draw_pos.y); inner_size = mgl::vec2f(size.x, folder_pos.y - draw_pos.y);
} }
void FileChooserBody::set_current_directory(const char *directory) { void FileChooserBody::set_current_directory(std::string_view directory) {
folders.clear(); folders.clear();
selected_item = -1; selected_item = -1;
mouse_over_item = -1; mouse_over_item = -1;
DIR *d = opendir(directory); char path[4096];
snprintf(path, sizeof(path), "%.*s", (int)directory.size(), directory.data());
DIR *d = opendir(path);
if(!d) { if(!d) {
fprintf(stderr, "gsr-ui error: failed to open directory: %s, error: %s\n", directory, strerror(errno)); fprintf(stderr, "gsr-ui error: failed to open directory: %s, error: %s\n", path, strerror(errno));
return; return;
} }
@@ -154,7 +157,7 @@ namespace gsr {
if(dir->d_name[0] == '.') if(dir->d_name[0] == '.')
continue; continue;
snprintf(filepath, sizeof(filepath), "%s/%s", directory, dir->d_name); snprintf(filepath, sizeof(filepath), "%s/%s", path, dir->d_name);
struct stat st; struct stat st;
if(stat(filepath, &st) == -1) if(stat(filepath, &st) == -1)
@@ -163,7 +166,7 @@ namespace gsr {
if(!S_ISDIR(st.st_mode)) if(!S_ISDIR(st.st_mode))
continue; continue;
folders.push_back({mgl::Text(dir->d_name, get_theme().body_font), st.st_mtim.tv_sec}); folders.push_back({mgl::Text(dir->d_name, get_theme().body_font_desc.c_str()), st.st_mtim.tv_sec});
} }
closedir(d); closedir(d);
@@ -191,9 +194,9 @@ namespace gsr {
this->size = size; this->size = size;
} }
FileChooser::FileChooser(const char *start_directory, mgl::vec2f size) : FileChooser::FileChooser(std::string_view start_directory, mgl::vec2f size) :
size(size), size(size),
current_directory_text(start_directory, get_theme().body_font), current_directory_text(start_directory, get_theme().body_font_desc.c_str()),
up_arrow_sprite(&get_theme().up_arrow_texture), up_arrow_sprite(&get_theme().up_arrow_texture),
scrollable_page(size) scrollable_page(size)
{ {
@@ -275,18 +278,20 @@ namespace gsr {
return size; return size;
} }
void FileChooser::set_current_directory(const char *directory) { void FileChooser::set_current_directory(std::string_view directory) {
current_directory_text.set_string(directory); current_directory_text.set_string(directory);
file_chooser_body_ptr->set_current_directory(directory); file_chooser_body_ptr->set_current_directory(directory);
scrollable_page.reset_scroll(); scrollable_page.reset_scroll();
} }
void FileChooser::open_subdirectory(const char *name) { void FileChooser::open_subdirectory(std::string_view name) {
char filepath[PATH_MAX]; char filepath[PATH_MAX];
if(current_directory_text.get_string() == "/") const std::string_view current_dir = current_directory_text.get_string();
snprintf(filepath, sizeof(filepath), "/%s", name); if(current_dir == "/") {
else snprintf(filepath, sizeof(filepath), "/%.*s", (int)name.size(), name.data());
snprintf(filepath, sizeof(filepath), "%s/%s", current_directory_text.get_string().c_str(), name); } else {
snprintf(filepath, sizeof(filepath), "%.*s/%.*s", (int)current_dir.size(), current_dir.data(), (int)name.size(), name.data());
}
set_current_directory(filepath); set_current_directory(filepath);
} }
@@ -294,7 +299,7 @@ namespace gsr {
set_current_directory(get_parent_directory(current_directory_text.get_string()).c_str()); set_current_directory(get_parent_directory(current_directory_text.get_string()).c_str());
} }
const std::string& FileChooser::get_current_directory() const { std::string_view FileChooser::get_current_directory() const {
return current_directory_text.get_string(); return current_directory_text.get_string();
} }
} }

View File

@@ -101,9 +101,9 @@ namespace gsr {
if(!configure_hotkey_button) if(!configure_hotkey_button)
return; return;
mgl::Text title_text(TRF("Press a key combination to use for the hotkey: \"%s\"", hotkey_configure_action_name.c_str()), get_theme().title_font); mgl::Text title_text(TRF("Press a key combination to use for the hotkey: \"%s\"", hotkey_configure_action_name.c_str()), get_theme().title_font_desc.c_str());
mgl::Text hotkey_text(configure_hotkey_button->get_text(), get_theme().top_bar_font); mgl::Text hotkey_text(configure_hotkey_button->get_text(), get_theme().top_bar_font_desc.c_str());
mgl::Text description_text(TR("Alpha-numerical keys can't be used alone in hotkeys, they have to be used one or more of these keys: Alt, Ctrl, Shift and Super.\nPress Esc to cancel or Backspace to remove the hotkey."), get_theme().body_font); mgl::Text description_text(TR("Alpha-numerical keys can't be used alone in hotkeys, they have to be used one or more of these keys: Alt, Ctrl, Shift and Super.\nPress Esc to cancel or Backspace to remove the hotkey."), get_theme().body_font_desc.c_str());
const float text_max_width = std::max(title_text.get_bounds().size.x, std::max(hotkey_text.get_bounds().size.x, description_text.get_bounds().size.x)); const float text_max_width = std::max(title_text.get_bounds().size.x, std::max(hotkey_text.get_bounds().size.x, description_text.get_bounds().size.x));
const float padding_horizontal = int(get_theme().window_height * 0.01f); const float padding_horizontal = int(get_theme().window_height * 0.01f);
@@ -146,13 +146,13 @@ namespace gsr {
std::unique_ptr<Subsection> GlobalSettingsPage::create_appearance_subsection(ScrollablePage *parent_page) { std::unique_ptr<Subsection> GlobalSettingsPage::create_appearance_subsection(ScrollablePage *parent_page) {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Accent color"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Accent color"), get_color_theme().text_color));
auto tint_color_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto tint_color_radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
tint_color_radio_button_ptr = tint_color_radio_button.get(); tint_color_radio_button_ptr = tint_color_radio_button.get();
tint_color_radio_button->add_item(TR("Red"), "amd"); tint_color_radio_button->add_item(TR("Red"), "amd");
tint_color_radio_button->add_item(TR("Green"), "nvidia"); tint_color_radio_button->add_item(TR("Green"), "nvidia");
tint_color_radio_button->add_item(TR("Blue"), "intel"); tint_color_radio_button->add_item(TR("Blue"), "intel");
tint_color_radio_button->on_selection_changed = [](const std::string&, const std::string &id) { tint_color_radio_button->on_selection_changed = [](std::string_view, std::string_view id) {
if(id == "amd") if(id == "amd")
get_color_theme().tint_color = mgl::Color(221, 0, 49); get_color_theme().tint_color = mgl::Color(221, 0, 49);
else if(id == "nvidia") else if(id == "nvidia")
@@ -167,12 +167,12 @@ namespace gsr {
std::unique_ptr<Subsection> GlobalSettingsPage::create_startup_subsection(ScrollablePage *parent_page) { std::unique_ptr<Subsection> GlobalSettingsPage::create_startup_subsection(ScrollablePage *parent_page) {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Start program on system startup?"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Start program on system startup?"), get_color_theme().text_color));
auto startup_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto startup_radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
startup_radio_button_ptr = startup_radio_button.get(); startup_radio_button_ptr = startup_radio_button.get();
startup_radio_button->add_item(TR("Yes"), "start_on_system_startup"); startup_radio_button->add_item(TR("Yes"), "start_on_system_startup");
startup_radio_button->add_item(TR("No"), "dont_start_on_system_startup"); startup_radio_button->add_item(TR("No"), "dont_start_on_system_startup");
startup_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) { startup_radio_button->on_selection_changed = [&](std::string_view, std::string_view id) {
bool enable = false; bool enable = false;
if(id == "dont_start_on_system_startup") if(id == "dont_start_on_system_startup")
enable = false; enable = false;
@@ -191,28 +191,28 @@ namespace gsr {
} }
std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_keyboard_hotkeys_button() { std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_keyboard_hotkeys_button() {
auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::VERTICAL); auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::VERTICAL);
enable_keyboard_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get(); enable_keyboard_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get();
enable_hotkeys_radio_button->add_item(TR("Yes"), "enable_hotkeys"); enable_hotkeys_radio_button->add_item(TR("Yes"), "enable_hotkeys");
enable_hotkeys_radio_button->add_item(TR("Yes, but only grab virtual devices (supports some input remapping software)"), "enable_hotkeys_virtual_devices"); enable_hotkeys_radio_button->add_item(TR("Yes, but only grab virtual devices (supports some input remapping software)"), "enable_hotkeys_virtual_devices");
enable_hotkeys_radio_button->add_item(TR("Yes, but don't grab devices (supports all input remapping software)"), "enable_hotkeys_no_grab"); enable_hotkeys_radio_button->add_item(TR("Yes, but don't grab devices (supports all input remapping software)"), "enable_hotkeys_no_grab");
enable_hotkeys_radio_button->add_item(TR("No"), "disable_hotkeys"); enable_hotkeys_radio_button->add_item(TR("No"), "disable_hotkeys");
enable_hotkeys_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) { enable_hotkeys_radio_button->on_selection_changed = [&](std::string_view, std::string_view id) {
if(on_keyboard_hotkey_changed) if(on_keyboard_hotkey_changed)
on_keyboard_hotkey_changed(id.c_str()); on_keyboard_hotkey_changed(id);
return true; return true;
}; };
return enable_hotkeys_radio_button; return enable_hotkeys_radio_button;
} }
std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_joystick_hotkeys_button() { std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_joystick_hotkeys_button() {
auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
enable_joystick_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get(); enable_joystick_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get();
enable_hotkeys_radio_button->add_item(TR("Yes"), "enable_hotkeys"); enable_hotkeys_radio_button->add_item(TR("Yes"), "enable_hotkeys");
enable_hotkeys_radio_button->add_item(TR("No"), "disable_hotkeys"); enable_hotkeys_radio_button->add_item(TR("No"), "disable_hotkeys");
enable_hotkeys_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) { enable_hotkeys_radio_button->on_selection_changed = [&](std::string_view, std::string_view id) {
if(on_joystick_hotkey_changed) if(on_joystick_hotkey_changed)
on_joystick_hotkey_changed(id.c_str()); on_joystick_hotkey_changed(id);
return true; return true;
}; };
return enable_hotkeys_radio_button; return enable_hotkeys_radio_button;
@@ -221,8 +221,8 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_show_hide_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_show_hide_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Show/hide UI:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Show/hide UI:"), get_color_theme().text_color));
auto show_hide_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto show_hide_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
show_hide_button_ptr = show_hide_button.get(); show_hide_button_ptr = show_hide_button.get();
list->add_widget(std::move(show_hide_button)); list->add_widget(std::move(show_hide_button));
@@ -236,13 +236,13 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_replay_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_replay_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Turn replay on/off:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Turn replay on/off:"), get_color_theme().text_color));
auto turn_replay_on_off_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto turn_replay_on_off_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
turn_replay_on_off_button_ptr = turn_replay_on_off_button.get(); turn_replay_on_off_button_ptr = turn_replay_on_off_button.get();
list->add_widget(std::move(turn_replay_on_off_button)); list->add_widget(std::move(turn_replay_on_off_button));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Save replay:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Save replay:"), get_color_theme().text_color));
auto save_replay_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto save_replay_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
save_replay_button_ptr = save_replay_button.get(); save_replay_button_ptr = save_replay_button.get();
list->add_widget(std::move(save_replay_button)); list->add_widget(std::move(save_replay_button));
@@ -260,13 +260,13 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_replay_partial_save_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_replay_partial_save_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Save 1 minute replay:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Save 1 minute replay:"), get_color_theme().text_color));
auto save_replay_1_min_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto save_replay_1_min_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
save_replay_1_min_button_ptr = save_replay_1_min_button.get(); save_replay_1_min_button_ptr = save_replay_1_min_button.get();
list->add_widget(std::move(save_replay_1_min_button)); list->add_widget(std::move(save_replay_1_min_button));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Save 10 minute replay:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Save 10 minute replay:"), get_color_theme().text_color));
auto save_replay_10_min_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto save_replay_10_min_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
save_replay_10_min_button_ptr = save_replay_10_min_button.get(); save_replay_10_min_button_ptr = save_replay_10_min_button.get();
list->add_widget(std::move(save_replay_10_min_button)); list->add_widget(std::move(save_replay_10_min_button));
@@ -284,13 +284,13 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_record_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_record_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Start/stop recording:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Start/stop recording:"), get_color_theme().text_color));
auto start_stop_recording_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto start_stop_recording_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_recording_button_ptr = start_stop_recording_button.get(); start_stop_recording_button_ptr = start_stop_recording_button.get();
list->add_widget(std::move(start_stop_recording_button)); list->add_widget(std::move(start_stop_recording_button));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Pause/unpause recording:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Pause/unpause recording:"), get_color_theme().text_color));
auto pause_unpause_recording_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto pause_unpause_recording_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
pause_unpause_recording_button_ptr = pause_unpause_recording_button.get(); pause_unpause_recording_button_ptr = pause_unpause_recording_button.get();
list->add_widget(std::move(pause_unpause_recording_button)); list->add_widget(std::move(pause_unpause_recording_button));
@@ -308,8 +308,8 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_record_hotkey_window_region_options() { std::unique_ptr<List> GlobalSettingsPage::create_record_hotkey_window_region_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Start/stop recording a region:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Start/stop recording a region:"), get_color_theme().text_color));
auto start_stop_recording_region_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto start_stop_recording_region_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_recording_region_button_ptr = start_stop_recording_region_button.get(); start_stop_recording_region_button_ptr = start_stop_recording_region_button.get();
list->add_widget(std::move(start_stop_recording_region_button)); list->add_widget(std::move(start_stop_recording_region_button));
@@ -329,8 +329,8 @@ namespace gsr {
else else
snprintf(str, sizeof(str), "%s", TR("Start/stop recording with desktop portal:")); snprintf(str, sizeof(str), "%s", TR("Start/stop recording with desktop portal:"));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
auto start_stop_recording_window_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto start_stop_recording_window_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_recording_window_button_ptr = start_stop_recording_window_button.get(); start_stop_recording_window_button_ptr = start_stop_recording_window_button.get();
list->add_widget(std::move(start_stop_recording_window_button)); list->add_widget(std::move(start_stop_recording_window_button));
@@ -344,8 +344,8 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_stream_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_stream_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Start/stop streaming:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Start/stop streaming:"), get_color_theme().text_color));
auto start_stop_streaming_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto start_stop_streaming_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_streaming_button_ptr = start_stop_streaming_button.get(); start_stop_streaming_button_ptr = start_stop_streaming_button.get();
list->add_widget(std::move(start_stop_streaming_button)); list->add_widget(std::move(start_stop_streaming_button));
@@ -359,8 +359,8 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_screenshot_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_screenshot_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Take a screenshot:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Take a screenshot:"), get_color_theme().text_color));
auto take_screenshot_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto take_screenshot_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
take_screenshot_button_ptr = take_screenshot_button.get(); take_screenshot_button_ptr = take_screenshot_button.get();
list->add_widget(std::move(take_screenshot_button)); list->add_widget(std::move(take_screenshot_button));
@@ -374,8 +374,8 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_screenshot_region_hotkey_options() { std::unique_ptr<List> GlobalSettingsPage::create_screenshot_region_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Take a screenshot of a region:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Take a screenshot of a region:"), get_color_theme().text_color));
auto take_screenshot_region_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto take_screenshot_region_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
take_screenshot_region_button_ptr = take_screenshot_region_button.get(); take_screenshot_region_button_ptr = take_screenshot_region_button.get();
list->add_widget(std::move(take_screenshot_region_button)); list->add_widget(std::move(take_screenshot_region_button));
@@ -395,8 +395,8 @@ namespace gsr {
else else
snprintf(str, sizeof(str), "%s", TR("Take a screenshot with desktop portal:")); snprintf(str, sizeof(str), "%s", TR("Take a screenshot with desktop portal:"));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
auto take_screenshot_window_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto take_screenshot_window_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
take_screenshot_window_button_ptr = take_screenshot_window_button.get(); take_screenshot_window_button_ptr = take_screenshot_window_button.get();
list->add_widget(std::move(take_screenshot_window_button)); list->add_widget(std::move(take_screenshot_window_button));
@@ -410,7 +410,7 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_hotkey_control_buttons() { std::unique_ptr<List> GlobalSettingsPage::create_hotkey_control_buttons() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto clear_hotkeys_button = std::make_unique<Button>(&get_theme().body_font, TR("Clear hotkeys"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto clear_hotkeys_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Clear hotkeys"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
clear_hotkeys_button->on_click = [this] { clear_hotkeys_button->on_click = [this] {
for_each_config_hotkey([&](ConfigHotkey *config_hotkey_item) { for_each_config_hotkey([&](ConfigHotkey *config_hotkey_item) {
*config_hotkey_item = {mgl::Keyboard::Unknown, 0}; *config_hotkey_item = {mgl::Keyboard::Unknown, 0};
@@ -420,7 +420,7 @@ namespace gsr {
}; };
list->add_widget(std::move(clear_hotkeys_button)); list->add_widget(std::move(clear_hotkeys_button));
auto reset_hotkeys_button = std::make_unique<Button>(&get_theme().body_font, TR("Reset hotkeys to default"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto reset_hotkeys_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Reset hotkeys to default"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
reset_hotkeys_button->on_click = [this] { reset_hotkeys_button->on_click = [this] {
config.set_hotkeys_to_default(); config.set_hotkeys_to_default();
load_hotkeys(); load_hotkeys();
@@ -433,11 +433,11 @@ namespace gsr {
static std::unique_ptr<List> create_joystick_hotkey_text(mgl::Texture *image1, mgl::Texture *image2, float max_height, const char *suffix) { static std::unique_ptr<List> create_joystick_hotkey_text(mgl::Texture *image1, mgl::Texture *image2, float max_height, const char *suffix) {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Press"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Press"), get_color_theme().text_color));
list->add_widget(std::make_unique<Image>(image1, mgl::vec2f{max_height, 1000.0f}, Image::ScaleBehavior::SCALE)); list->add_widget(std::make_unique<Image>(image1, mgl::vec2f{max_height, 1000.0f}, Image::ScaleBehavior::SCALE));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("and"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("and"), get_color_theme().text_color));
list->add_widget(std::make_unique<Image>(image2, mgl::vec2f{max_height, 1000.0f}, Image::ScaleBehavior::SCALE)); list->add_widget(std::make_unique<Image>(image2, mgl::vec2f{max_height, 1000.0f}, Image::ScaleBehavior::SCALE));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, suffix, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), suffix, get_color_theme().text_color));
return list; return list;
} }
@@ -446,7 +446,7 @@ namespace gsr {
List *list_ptr = list.get(); List *list_ptr = list.get();
auto subsection = std::make_unique<Subsection>(TR("Keyboard hotkeys"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f)); auto subsection = std::make_unique<Subsection>(TR("Keyboard hotkeys"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Enable keyboard hotkeys?"), get_color_theme().text_color)); list_ptr->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Enable keyboard hotkeys?"), get_color_theme().text_color));
list_ptr->add_widget(create_enable_keyboard_hotkeys_button()); list_ptr->add_widget(create_enable_keyboard_hotkeys_button());
list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x)); list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x));
list_ptr->add_widget(create_show_hide_hotkey_options()); list_ptr->add_widget(create_show_hide_hotkey_options());
@@ -459,7 +459,7 @@ namespace gsr {
list_ptr->add_widget(create_screenshot_hotkey_options()); list_ptr->add_widget(create_screenshot_hotkey_options());
list_ptr->add_widget(create_screenshot_region_hotkey_options()); list_ptr->add_widget(create_screenshot_region_hotkey_options());
list_ptr->add_widget(create_screenshot_window_hotkey_options()); list_ptr->add_widget(create_screenshot_window_hotkey_options());
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Press ESC to go back to the previous page/close the UI."), get_color_theme().text_color)); list_ptr->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Press ESC to go back to the previous page/close the UI."), get_color_theme().text_color));
list_ptr->add_widget(create_hotkey_control_buttons()); list_ptr->add_widget(create_hotkey_control_buttons());
return subsection; return subsection;
} }
@@ -469,21 +469,21 @@ namespace gsr {
List *list_ptr = list.get(); List *list_ptr = list.get();
auto subsection = std::make_unique<Subsection>(TR("Controller hotkeys"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f)); auto subsection = std::make_unique<Subsection>(TR("Controller hotkeys"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Enable controller hotkeys?"), get_color_theme().text_color)); list_ptr->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Enable controller hotkeys?"), get_color_theme().text_color));
list_ptr->add_widget(create_enable_joystick_hotkeys_button()); list_ptr->add_widget(create_enable_joystick_hotkeys_button());
list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x)); list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_options_texture, get_theme().body_font.get_character_size(), TR("to show/hide the UI"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_options_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to show/hide the UI")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_up_texture, get_theme().body_font.get_character_size(), TR("to take a screenshot"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_up_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to take a screenshot")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_down_texture, get_theme().body_font.get_character_size(), TR("to save a replay"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_down_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to save a replay")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_left_texture, get_theme().body_font.get_character_size(), TR("to start/stop recording"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_left_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to start/stop recording")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_right_texture, get_theme().body_font.get_character_size(), TR("to turn replay on/off"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_right_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to turn replay on/off")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_cross_texture, get_theme().body_font.get_character_size(), TR("to save a 1 minute replay"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_cross_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to save a 1 minute replay")));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_triangle_texture, get_theme().body_font.get_character_size(), TR("to save a 10 minute replay"))); list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_triangle_texture, 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()), TR("to save a 10 minute replay")));
return subsection; return subsection;
} }
std::unique_ptr<Button> GlobalSettingsPage::create_exit_program_button() { std::unique_ptr<Button> GlobalSettingsPage::create_exit_program_button() {
auto exit_program_button = std::make_unique<Button>(&get_theme().body_font, TR("Exit program"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto exit_program_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Exit program"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
exit_program_button->on_click = [&]() { exit_program_button->on_click = [&]() {
if(on_click_exit_program_button) if(on_click_exit_program_button)
on_click_exit_program_button("exit"); on_click_exit_program_button("exit");
@@ -492,7 +492,7 @@ namespace gsr {
} }
std::unique_ptr<Button> GlobalSettingsPage::create_go_back_to_old_ui_button() { std::unique_ptr<Button> GlobalSettingsPage::create_go_back_to_old_ui_button() {
auto exit_program_button = std::make_unique<Button>(&get_theme().body_font, TR("Go back to the old UI"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto exit_program_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Go back to the old UI"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
exit_program_button->on_click = [&]() { exit_program_button->on_click = [&]() {
if(on_click_exit_program_button) if(on_click_exit_program_button)
on_click_exit_program_button("back-to-old-ui"); on_click_exit_program_button("back-to-old-ui");
@@ -502,13 +502,13 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_notification_speed() { std::unique_ptr<List> GlobalSettingsPage::create_notification_speed() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Notification speed"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Notification speed"), get_color_theme().text_color));
auto radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
notification_speed_button_ptr = radio_button.get(); notification_speed_button_ptr = radio_button.get();
radio_button->add_item(TR("Normal"), "normal"); radio_button->add_item(TR("Normal"), "normal");
radio_button->add_item(TR("Fast"), "fast"); radio_button->add_item(TR("Fast"), "fast");
radio_button->on_selection_changed = [this](const std::string&, const std::string &id) { radio_button->on_selection_changed = [this](std::string_view, std::string_view id) {
if(id == "normal") if(id == "normal")
overlay->set_notification_speed(NotificationSpeed::NORMAL); overlay->set_notification_speed(NotificationSpeed::NORMAL);
else if(id == "fast") else if(id == "fast")
@@ -522,9 +522,9 @@ namespace gsr {
std::unique_ptr<List> GlobalSettingsPage::create_language() { std::unique_ptr<List> GlobalSettingsPage::create_language() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Language"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Language"), get_color_theme().text_color));
auto combo_box = std::make_unique<ComboBox>(&get_theme().body_font); auto combo_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
language_combo_box_ptr = combo_box.get(); language_combo_box_ptr = combo_box.get();
combo_box->add_item(TR("System language"), ""); combo_box->add_item(TR("System language"), "");
combo_box->add_item("English", "en"); combo_box->add_item("English", "en");
@@ -533,8 +533,8 @@ namespace gsr {
combo_box->add_item("Magyar", "hu"); combo_box->add_item("Magyar", "hu");
combo_box->add_item("Русский", "ru"); combo_box->add_item("Русский", "ru");
combo_box->add_item("Українська", "uk"); combo_box->add_item("Українська", "uk");
combo_box->on_selection_changed = [](const std::string&, const std::string &id) { combo_box->on_selection_changed = [](std::string_view, std::string_view id) {
Translation::instance().load_language(id.c_str()); Translation::instance().load_language(id);
return true; return true;
}; };
list->add_widget(std::move(combo_box)); list->add_widget(std::move(combo_box));
@@ -573,27 +573,27 @@ namespace gsr {
char str[128]; char str[128];
const std::string gsr_version = gsr_info->system_info.gsr_version.to_string(); const std::string gsr_version = gsr_info->system_info.gsr_version.to_string();
snprintf(str, sizeof(str), TR("GSR version: %s"), gsr_version.c_str()); snprintf(str, sizeof(str), TR("GSR version: %s"), gsr_version.c_str());
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
snprintf(str, sizeof(str), TR("GSR-UI version: %s"), GSR_UI_VERSION); snprintf(str, sizeof(str), TR("GSR-UI version: %s"), GSR_UI_VERSION);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
if(inside_flatpak) { if(inside_flatpak) {
snprintf(str, sizeof(str), TR("Flatpak version: %s"), GSR_FLATPAK_VERSION); snprintf(str, sizeof(str), TR("Flatpak version: %s"), GSR_FLATPAK_VERSION);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
} }
snprintf(str, sizeof(str), TR("GPU vendor: %s"), gpu_vendor_to_string(gsr_info->gpu_info.vendor)); snprintf(str, sizeof(str), TR("GPU vendor: %s"), gpu_vendor_to_string(gsr_info->gpu_info.vendor));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), str, get_color_theme().text_color));
return std::make_unique<Subsection>(TR("Application info"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f)); return std::make_unique<Subsection>(TR("Application info"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
} }
std::unique_ptr<Subsection> GlobalSettingsPage::create_donate_subsection(ScrollablePage *parent_page) { std::unique_ptr<Subsection> GlobalSettingsPage::create_donate_subsection(ScrollablePage *parent_page) {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("If you would like to donate you can do so by donating at https://buymeacoffee.com/dec05eba:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("If you would like to donate you can do so by donating at https://buymeacoffee.com/dec05eba:"), get_color_theme().text_color));
auto donate_button = std::make_unique<Button>(&get_theme().body_font, TR("Donate"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto donate_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Donate"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
donate_button->on_click = [this] { donate_button->on_click = [this] {
const char *args[] = { "xdg-open", "https://buymeacoffee.com/dec05eba", nullptr }; const char *args[] = { "xdg-open", "https://buymeacoffee.com/dec05eba", nullptr };
exec_program_daemonized(args); exec_program_daemonized(args);
@@ -601,7 +601,7 @@ namespace gsr {
}; };
list->add_widget(std::move(donate_button)); list->add_widget(std::move(donate_button));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("All donations go toward developing software (including GPU Screen Recorder)\nand buying hardware to test the software."), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("All donations go toward developing software (including GPU Screen Recorder)\nand buying hardware to test the software."), get_color_theme().text_color));
return std::make_unique<Subsection>(TR("Donate"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f)); return std::make_unique<Subsection>(TR("Donate"), std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
} }

View File

@@ -9,8 +9,8 @@ namespace gsr {
static const float button_spacing_scale = 0.015f; static const float button_spacing_scale = 0.015f;
GsrPage::GsrPage(const char *top_text, const char *bottom_text) : GsrPage::GsrPage(const char *top_text, const char *bottom_text) :
top_text(top_text, get_theme().title_font), top_text(top_text, get_theme().title_font_desc.c_str()),
bottom_text(bottom_text, get_theme().title_font) bottom_text(bottom_text, get_theme().title_font_desc.c_str())
{ {
const float margin = 0.02f; const float margin = 0.02f;
set_margins(margin, margin, margin, margin); set_margins(margin, margin, margin, margin);
@@ -151,7 +151,7 @@ namespace gsr {
} }
void GsrPage::add_button(const std::string &text, const std::string &id, mgl::Color color) { void GsrPage::add_button(const std::string &text, const std::string &id, mgl::Color color) {
auto button = std::make_unique<Button>(&get_theme().title_font, text.c_str(), auto button = std::make_unique<Button>(get_theme().title_font_desc.c_str(), text.c_str(),
mgl::vec2f(get_theme().window_width / 10, get_theme().window_height / 15).floor(), color); mgl::vec2f(get_theme().window_width / 10, get_theme().window_height / 15).floor(), color);
button->set_border_scale(0.003f); button->set_border_scale(0.003f);
button->on_click = [this, id]() { button->on_click = [this, id]() {

View File

@@ -2,7 +2,7 @@
#include <mglpp/window/Window.hpp> #include <mglpp/window/Window.hpp>
namespace gsr { namespace gsr {
Label::Label(mgl::Font *font, const char *text, mgl::Color color) : text(text, *font) { Label::Label(const char *font_desc, const char *text, mgl::Color color) : text(text, font_desc) {
this->text.set_color(color); this->text.set_color(color);
} }
@@ -18,11 +18,11 @@ namespace gsr {
window.draw(text); window.draw(text);
} }
void Label::set_text(std::string str) { void Label::set_text(std::string_view str) {
text.set_string(std::move(str)); text.set_string(str);
} }
const std::string& Label::get_text() const { std::string_view Label::get_text() const {
return text.get_string(); return text.get_string();
} }
@@ -32,4 +32,14 @@ namespace gsr {
return text.get_bounds().size; return text.get_bounds().size;
} }
// Set to 0 to disable
void Label::set_wrap_width(int width) {
text.set_wrap_width(width);
}
// Set to 0 to disable
void Label::set_max_rows(int max_rows) {
text.set_max_rows(max_rows);
}
} }

View File

@@ -14,7 +14,7 @@ namespace gsr {
static const float spacing_scale = 0.007f; static const float spacing_scale = 0.007f;
static const float border_scale = 0.0015f; static const float border_scale = 0.0015f;
RadioButton::RadioButton(mgl::Font *font, Orientation orientation) : font(font), orientation(orientation) { RadioButton::RadioButton(const char *font_desc, Orientation orientation) : font_desc(font_desc), orientation(orientation) {
} }
@@ -122,7 +122,7 @@ namespace gsr {
break; break;
case Orientation::HORIZONTAL: case Orientation::HORIZONTAL:
size.x += bounds.x + padding_left + padding_right; size.x += bounds.x + padding_left + padding_right;
size.y = font->get_character_size() + (float)padding_top + (float)padding_bottom; size.y = item.text.get_font_size()*2.0f + (float)padding_top + (float)padding_bottom;
break; break;
} }
} }
@@ -150,11 +150,11 @@ namespace gsr {
} }
void RadioButton::add_item(const std::string &text, const std::string &id) { void RadioButton::add_item(const std::string &text, const std::string &id) {
items.push_back({mgl::Text(text, *font), id}); items.push_back({mgl::Text(text, font_desc.c_str()), id});
dirty = true; dirty = true;
} }
void RadioButton::set_selected_item(const std::string &id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) { void RadioButton::set_selected_item(std::string_view id, bool trigger_event, bool trigger_event_even_if_selection_not_changed) {
for(size_t i = 0; i < items.size(); ++i) { for(size_t i = 0; i < items.size(); ++i) {
auto &item = items[i]; auto &item = items[i];
if(item.id == id) { if(item.id == id) {
@@ -169,19 +169,17 @@ namespace gsr {
} }
} }
const std::string& RadioButton::get_selected_id() const { std::string_view RadioButton::get_selected_id() const {
if(items.empty()) { if(items.empty()) {
static std::string dummy; return "";
return dummy;
} else { } else {
return items[selected_item].id; return items[selected_item].id;
} }
} }
const std::string& RadioButton::get_selected_text() const { std::string_view RadioButton::get_selected_text() const {
if(items.empty()) { if(items.empty()) {
static std::string dummy; return "";
return dummy;
} else { } else {
return items[selected_item].text.get_string(); return items[selected_item].text.get_string();
} }

View File

@@ -11,7 +11,16 @@
#include "../../include/gui/Subsection.hpp" #include "../../include/gui/Subsection.hpp"
#include "../../include/gui/FileChooser.hpp" #include "../../include/gui/FileChooser.hpp"
#include <charconv>
namespace gsr { namespace gsr {
template <typename T>
static T sv_to_int(std::string_view str) {
T result = 0;
std::from_chars(str.data(), str.data() + str.size(), result);
return result;
}
ScreenshotSettingsPage::ScreenshotSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack, bool supports_window_title) : ScreenshotSettingsPage::ScreenshotSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack, bool supports_window_title) :
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
config(config), config(config),
@@ -35,7 +44,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> ScreenshotSettingsPage::create_record_area_box() { std::unique_ptr<ComboBox> ScreenshotSettingsPage::create_record_area_box() {
auto record_area_box = std::make_unique<ComboBox>(&get_theme().body_font); auto record_area_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
// TODO: Show options not supported but disable them // TODO: Show options not supported but disable them
if(capture_options.window) if(capture_options.window)
record_area_box->add_item(TR("Window"), "window"); record_area_box->add_item(TR("Window"), "window");
@@ -56,21 +65,21 @@ namespace gsr {
std::unique_ptr<Widget> ScreenshotSettingsPage::create_record_area() { std::unique_ptr<Widget> ScreenshotSettingsPage::create_record_area() {
auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL); auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL);
record_area_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Capture source:"), get_color_theme().text_color)); record_area_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Capture source:"), get_color_theme().text_color));
record_area_list->add_widget(create_record_area_box()); record_area_list->add_widget(create_record_area_box());
return record_area_list; return record_area_list;
} }
std::unique_ptr<Entry> ScreenshotSettingsPage::create_image_width_entry() { std::unique_ptr<Entry> ScreenshotSettingsPage::create_image_width_entry() {
auto image_width_entry = std::make_unique<Entry>(&get_theme().body_font, "1920", get_theme().body_font.get_character_size() * 3); auto image_width_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1920", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
image_width_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); image_width_entry->set_number_mode(true, 1, 1 << 15);
image_width_entry_ptr = image_width_entry.get(); image_width_entry_ptr = image_width_entry.get();
return image_width_entry; return image_width_entry;
} }
std::unique_ptr<Entry> ScreenshotSettingsPage::create_image_height_entry() { std::unique_ptr<Entry> ScreenshotSettingsPage::create_image_height_entry() {
auto image_height_entry = std::make_unique<Entry>(&get_theme().body_font, "1080", get_theme().body_font.get_character_size() * 3); auto image_height_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1080", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
image_height_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); image_height_entry->set_number_mode(true, 1, 1 << 15);
image_height_entry_ptr = image_height_entry.get(); image_height_entry_ptr = image_height_entry.get();
return image_height_entry; return image_height_entry;
} }
@@ -78,21 +87,21 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_image_resolution() { std::unique_ptr<List> ScreenshotSettingsPage::create_image_resolution() {
auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
area_size_params_list->add_widget(create_image_width_entry()); area_size_params_list->add_widget(create_image_width_entry());
area_size_params_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "x", get_color_theme().text_color)); area_size_params_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), "x", get_color_theme().text_color));
area_size_params_list->add_widget(create_image_height_entry()); area_size_params_list->add_widget(create_image_height_entry());
return area_size_params_list; return area_size_params_list;
} }
std::unique_ptr<List> ScreenshotSettingsPage::create_image_resolution_section() { std::unique_ptr<List> ScreenshotSettingsPage::create_image_resolution_section() {
auto image_resolution_list = std::make_unique<List>(List::Orientation::VERTICAL); auto image_resolution_list = std::make_unique<List>(List::Orientation::VERTICAL);
image_resolution_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Image resolution limit:"), get_color_theme().text_color)); image_resolution_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Image resolution limit:"), get_color_theme().text_color));
image_resolution_list->add_widget(create_image_resolution()); image_resolution_list->add_widget(create_image_resolution());
image_resolution_list_ptr = image_resolution_list.get(); image_resolution_list_ptr = image_resolution_list.get();
return image_resolution_list; return image_resolution_list;
} }
std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_restore_portal_session_checkbox() { std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_restore_portal_session_checkbox() {
auto restore_portal_session_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Restore portal session")); auto restore_portal_session_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Restore portal session"));
restore_portal_session_checkbox->set_checked(true); restore_portal_session_checkbox->set_checked(true);
restore_portal_session_checkbox_ptr = restore_portal_session_checkbox.get(); restore_portal_session_checkbox_ptr = restore_portal_session_checkbox.get();
return restore_portal_session_checkbox; return restore_portal_session_checkbox;
@@ -100,14 +109,14 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_restore_portal_session_section() { std::unique_ptr<List> ScreenshotSettingsPage::create_restore_portal_session_section() {
auto restore_portal_session_list = std::make_unique<List>(List::Orientation::VERTICAL); auto restore_portal_session_list = std::make_unique<List>(List::Orientation::VERTICAL);
restore_portal_session_list->add_widget(std::make_unique<Label>(&get_theme().body_font, " ", get_color_theme().text_color)); restore_portal_session_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), " ", get_color_theme().text_color));
restore_portal_session_list->add_widget(create_restore_portal_session_checkbox()); restore_portal_session_list->add_widget(create_restore_portal_session_checkbox());
restore_portal_session_list_ptr = restore_portal_session_list.get(); restore_portal_session_list_ptr = restore_portal_session_list.get();
return restore_portal_session_list; return restore_portal_session_list;
} }
std::unique_ptr<Widget> ScreenshotSettingsPage::create_change_image_resolution_section() { std::unique_ptr<Widget> ScreenshotSettingsPage::create_change_image_resolution_section() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Change image resolution")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Change image resolution"));
change_image_resolution_checkbox_ptr = checkbox.get(); change_image_resolution_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
} }
@@ -127,9 +136,9 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_image_quality_section() { std::unique_ptr<List> ScreenshotSettingsPage::create_image_quality_section() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Image quality:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Image quality:"), get_color_theme().text_color));
auto image_quality_box = std::make_unique<ComboBox>(&get_theme().body_font); auto image_quality_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
image_quality_box->add_item(TR("Medium"), "medium"); image_quality_box->add_item(TR("Medium"), "medium");
image_quality_box->add_item(TR("High"), "high"); image_quality_box->add_item(TR("High"), "high");
image_quality_box->add_item(TR("Very high (Recommended)"), "very_high"); image_quality_box->add_item(TR("Very high (Recommended)"), "very_high");
@@ -143,7 +152,7 @@ namespace gsr {
} }
std::unique_ptr<Widget> ScreenshotSettingsPage::create_record_cursor_section() { std::unique_ptr<Widget> ScreenshotSettingsPage::create_record_cursor_section() {
auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Record cursor")); auto record_cursor_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Record cursor"));
record_cursor_checkbox->set_checked(true); record_cursor_checkbox->set_checked(true);
record_cursor_checkbox_ptr = record_cursor_checkbox.get(); record_cursor_checkbox_ptr = record_cursor_checkbox.get();
return record_cursor_checkbox; return record_cursor_checkbox;
@@ -158,15 +167,15 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_save_directory(const char *label) { std::unique_ptr<List> ScreenshotSettingsPage::create_save_directory(const char *label) {
auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL); auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL);
save_directory_list->add_widget(std::make_unique<Label>(&get_theme().body_font, label, get_color_theme().text_color)); save_directory_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), label, get_color_theme().text_color));
auto save_directory_button = std::make_unique<Button>(&get_theme().body_font, get_pictures_dir().c_str(), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto save_directory_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), get_pictures_dir().c_str(), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
save_directory_button_ptr = save_directory_button.get(); save_directory_button_ptr = save_directory_button.get();
save_directory_button->on_click = [this]() { save_directory_button->on_click = [this]() {
auto select_directory_page = std::make_unique<GsrPage>(TR("File"), TR("Settings")); auto select_directory_page = std::make_unique<GsrPage>(TR("File"), TR("Settings"));
select_directory_page->add_button(TR("Save"), "save", get_color_theme().tint_color); select_directory_page->add_button(TR("Save"), "save", get_color_theme().tint_color);
select_directory_page->add_button(TR("Cancel"), "cancel", get_color_theme().page_bg_color); select_directory_page->add_button(TR("Cancel"), "cancel", get_color_theme().page_bg_color);
auto file_chooser = std::make_unique<FileChooser>(save_directory_button_ptr->get_text().c_str(), select_directory_page->get_inner_size()); auto file_chooser = std::make_unique<FileChooser>(save_directory_button_ptr->get_text(), select_directory_page->get_inner_size());
FileChooser *file_chooser_ptr = file_chooser.get(); FileChooser *file_chooser_ptr = file_chooser.get();
select_directory_page->add_widget(std::move(file_chooser)); select_directory_page->add_widget(std::move(file_chooser));
@@ -186,7 +195,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> ScreenshotSettingsPage::create_image_format_box() { std::unique_ptr<ComboBox> ScreenshotSettingsPage::create_image_format_box() {
auto box = std::make_unique<ComboBox>(&get_theme().body_font); auto box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
if(gsr_info->supported_image_formats.jpeg) if(gsr_info->supported_image_formats.jpeg)
box->add_item("jpg", "jpg"); box->add_item("jpg", "jpg");
if(gsr_info->supported_image_formats.png) if(gsr_info->supported_image_formats.png)
@@ -197,7 +206,7 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_image_format_section() { std::unique_ptr<List> ScreenshotSettingsPage::create_image_format_section() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Image format:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Image format:"), get_color_theme().text_color));
list->add_widget(create_image_format_box()); list->add_widget(create_image_format_box());
return list; return list;
} }
@@ -212,33 +221,33 @@ namespace gsr {
std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_in_game_folder() { std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_in_game_folder() {
char text[256]; char text[256];
snprintf(text, sizeof(text), "%s%s", TR("Save screenshot in a folder based on the games name"), supports_window_title ? "" : " (X11 applications only)"); snprintf(text, sizeof(text), "%s%s", TR("Save screenshot in a folder based on the games name"), supports_window_title ? "" : " (X11 applications only)");
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), text);
save_screenshot_in_game_folder_checkbox_ptr = checkbox.get(); save_screenshot_in_game_folder_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_to_clipboard() { std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_to_clipboard() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, gsr_info->system_info.display_server == DisplayServer::X11 ? TR("Save screenshot to clipboard") : TR("Save screenshot to clipboard (Not supported properly by Wayland)")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), gsr_info->system_info.display_server == DisplayServer::X11 ? TR("Save screenshot to clipboard") : TR("Save screenshot to clipboard (Not supported properly by Wayland)"));
save_screenshot_to_clipboard_checkbox_ptr = checkbox.get(); save_screenshot_to_clipboard_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_to_disk() { std::unique_ptr<CheckBox> ScreenshotSettingsPage::create_save_screenshot_to_disk() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Save screenshot to disk")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Save screenshot to disk"));
save_screenshot_to_disk_checkbox_ptr = checkbox.get(); save_screenshot_to_disk_checkbox_ptr = checkbox.get();
checkbox->set_checked(true); checkbox->set_checked(true);
return checkbox; return checkbox;
} }
std::unique_ptr<Widget> ScreenshotSettingsPage::create_notifications() { std::unique_ptr<Widget> ScreenshotSettingsPage::create_notifications() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Show screenshot notifications")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Show screenshot notifications"));
checkbox->set_checked(true); checkbox->set_checked(true);
show_notification_checkbox_ptr = checkbox.get(); show_notification_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<Widget> ScreenshotSettingsPage::create_led_indicator() { std::unique_ptr<Widget> ScreenshotSettingsPage::create_led_indicator() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Blink scroll lock led when taking a screenshot")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Blink scroll lock led when taking a screenshot"));
checkbox->set_checked(true); checkbox->set_checked(true);
led_indicator_checkbox_ptr = checkbox.get(); led_indicator_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
@@ -262,7 +271,7 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_custom_script_screenshot_entry() { std::unique_ptr<List> ScreenshotSettingsPage::create_custom_script_screenshot_entry() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::VERTICAL, List::Alignment::CENTER);
auto create_custom_script_screenshot_entry = std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20); auto create_custom_script_screenshot_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
create_custom_script_screenshot_entry_ptr = create_custom_script_screenshot_entry.get(); create_custom_script_screenshot_entry_ptr = create_custom_script_screenshot_entry.get();
list->add_widget(std::move(create_custom_script_screenshot_entry)); list->add_widget(std::move(create_custom_script_screenshot_entry));
@@ -271,7 +280,7 @@ namespace gsr {
std::unique_ptr<List> ScreenshotSettingsPage::create_custom_script_screenshot() { std::unique_ptr<List> ScreenshotSettingsPage::create_custom_script_screenshot() {
auto custom_script_screenshot_list = std::make_unique<List>(List::Orientation::VERTICAL); auto custom_script_screenshot_list = std::make_unique<List>(List::Orientation::VERTICAL);
custom_script_screenshot_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Command to open the screenshot with:"), get_color_theme().text_color)); custom_script_screenshot_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Command to open the screenshot with:"), get_color_theme().text_color));
custom_script_screenshot_list->add_widget(create_custom_script_screenshot_entry()); custom_script_screenshot_list->add_widget(create_custom_script_screenshot_entry());
return custom_script_screenshot_list; return custom_script_screenshot_list;
} }
@@ -302,7 +311,7 @@ namespace gsr {
void ScreenshotSettingsPage::add_widgets() { void ScreenshotSettingsPage::add_widgets() {
content_page_ptr->add_widget(create_settings()); content_page_ptr->add_widget(create_settings());
record_area_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { record_area_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
const bool portal_selected = id == "portal"; const bool portal_selected = id == "portal";
image_resolution_list_ptr->set_visible(change_image_resolution_checkbox_ptr->is_checked()); image_resolution_list_ptr->set_visible(change_image_resolution_checkbox_ptr->is_checked());
restore_portal_session_list_ptr->set_visible(portal_selected); restore_portal_session_list_ptr->set_visible(portal_selected);
@@ -362,8 +371,8 @@ namespace gsr {
Config prev_config = config; Config prev_config = config;
config.screenshot_config.record_area_option = record_area_box_ptr->get_selected_id(); config.screenshot_config.record_area_option = record_area_box_ptr->get_selected_id();
config.screenshot_config.image_width = atoi(image_width_entry_ptr->get_text().c_str()); config.screenshot_config.image_width = sv_to_int<int32_t>(image_width_entry_ptr->get_text());
config.screenshot_config.image_height = atoi(image_height_entry_ptr->get_text().c_str()); config.screenshot_config.image_height = sv_to_int<int32_t>(image_height_entry_ptr->get_text());
config.screenshot_config.change_image_resolution = change_image_resolution_checkbox_ptr->is_checked(); config.screenshot_config.change_image_resolution = change_image_resolution_checkbox_ptr->is_checked();
config.screenshot_config.image_quality = image_quality_box_ptr->get_selected_id(); config.screenshot_config.image_quality = image_quality_box_ptr->get_selected_id();
config.screenshot_config.image_format = image_format_box_ptr->get_selected_id(); config.screenshot_config.image_format = image_format_box_ptr->get_selected_id();

View File

@@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <string.h> #include <string.h>
#include <charconv>
namespace gsr { namespace gsr {
static const char *custom_app_audio_tag = "[custom]"; static const char *custom_app_audio_tag = "[custom]";
@@ -37,6 +38,13 @@ namespace gsr {
return ""; return "";
} }
template <typename T>
static T sv_to_int(std::string_view str) {
T result = 0;
std::from_chars(str.data(), str.data() + str.size(), result);
return result;
}
SettingsPage::SettingsPage(Type type, const GsrInfo *gsr_info, Config &config, PageStack *page_stack, bool supports_window_title, bool supports_window_fullscreen_state) : SettingsPage::SettingsPage(Type type, const GsrInfo *gsr_info, Config &config, PageStack *page_stack, bool supports_window_title, bool supports_window_fullscreen_state) :
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()), StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
type(type), type(type),
@@ -65,7 +73,7 @@ namespace gsr {
} }
std::unique_ptr<RadioButton> SettingsPage::create_view_radio_button() { std::unique_ptr<RadioButton> SettingsPage::create_view_radio_button() {
auto view_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto view_radio_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
view_radio_button->add_item(TR("Simple view"), "simple"); view_radio_button->add_item(TR("Simple view"), "simple");
view_radio_button->add_item(TR("Advanced view"), "advanced"); view_radio_button->add_item(TR("Advanced view"), "advanced");
view_radio_button->set_horizontal_alignment(Widget::Alignment::CENTER); view_radio_button->set_horizontal_alignment(Widget::Alignment::CENTER);
@@ -74,7 +82,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_record_area_box() { std::unique_ptr<ComboBox> SettingsPage::create_record_area_box() {
auto record_area_box = std::make_unique<ComboBox>(&get_theme().body_font); auto record_area_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
// TODO: Show options not supported but disable them // TODO: Show options not supported but disable them
if(capture_options.window) if(capture_options.window)
record_area_box->add_item(TR("Window"), "window"); record_area_box->add_item(TR("Window"), "window");
@@ -97,21 +105,21 @@ namespace gsr {
std::unique_ptr<Widget> SettingsPage::create_record_area() { std::unique_ptr<Widget> SettingsPage::create_record_area() {
auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL); auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL);
record_area_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Capture source:"), get_color_theme().text_color)); record_area_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Capture source:"), get_color_theme().text_color));
record_area_list->add_widget(create_record_area_box()); record_area_list->add_widget(create_record_area_box());
return record_area_list; return record_area_list;
} }
std::unique_ptr<Entry> SettingsPage::create_area_width_entry() { std::unique_ptr<Entry> SettingsPage::create_area_width_entry() {
auto area_width_entry = std::make_unique<Entry>(&get_theme().body_font, "1920", get_theme().body_font.get_character_size() * 3); auto area_width_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1920", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
area_width_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); area_width_entry->set_number_mode(true, 1, 1 << 15);
area_width_entry_ptr = area_width_entry.get(); area_width_entry_ptr = area_width_entry.get();
return area_width_entry; return area_width_entry;
} }
std::unique_ptr<Entry> SettingsPage::create_area_height_entry() { std::unique_ptr<Entry> SettingsPage::create_area_height_entry() {
auto area_height_entry = std::make_unique<Entry>(&get_theme().body_font, "1080", get_theme().body_font.get_character_size() * 3); auto area_height_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1080", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
area_height_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); area_height_entry->set_number_mode(true, 1, 1 << 15);
area_height_entry_ptr = area_height_entry.get(); area_height_entry_ptr = area_height_entry.get();
return area_height_entry; return area_height_entry;
} }
@@ -119,29 +127,29 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_area_size() { std::unique_ptr<List> SettingsPage::create_area_size() {
auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
area_size_params_list->add_widget(create_area_width_entry()); area_size_params_list->add_widget(create_area_width_entry());
area_size_params_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "x", get_color_theme().text_color)); area_size_params_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), "x", get_color_theme().text_color));
area_size_params_list->add_widget(create_area_height_entry()); area_size_params_list->add_widget(create_area_height_entry());
return area_size_params_list; return area_size_params_list;
} }
std::unique_ptr<List> SettingsPage::create_area_size_section() { std::unique_ptr<List> SettingsPage::create_area_size_section() {
auto area_size_list = std::make_unique<List>(List::Orientation::VERTICAL); auto area_size_list = std::make_unique<List>(List::Orientation::VERTICAL);
area_size_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Area size:"), get_color_theme().text_color)); area_size_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Area size:"), get_color_theme().text_color));
area_size_list->add_widget(create_area_size()); area_size_list->add_widget(create_area_size());
area_size_list_ptr = area_size_list.get(); area_size_list_ptr = area_size_list.get();
return area_size_list; return area_size_list;
} }
std::unique_ptr<Entry> SettingsPage::create_video_width_entry() { std::unique_ptr<Entry> SettingsPage::create_video_width_entry() {
auto video_width_entry = std::make_unique<Entry>(&get_theme().body_font, "1920", get_theme().body_font.get_character_size() * 3); auto video_width_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1920", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
video_width_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); video_width_entry->set_number_mode(true, 1, 1 << 15);
video_width_entry_ptr = video_width_entry.get(); video_width_entry_ptr = video_width_entry.get();
return video_width_entry; return video_width_entry;
} }
std::unique_ptr<Entry> SettingsPage::create_video_height_entry() { std::unique_ptr<Entry> SettingsPage::create_video_height_entry() {
auto video_height_entry = std::make_unique<Entry>(&get_theme().body_font, "1080", get_theme().body_font.get_character_size() * 3); auto video_height_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "1080", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
video_height_entry->validate_handler = create_entry_validator_integer_in_range(1, 1 << 15); video_height_entry->set_number_mode(true, 1, 1 << 15);
video_height_entry_ptr = video_height_entry.get(); video_height_entry_ptr = video_height_entry.get();
return video_height_entry; return video_height_entry;
} }
@@ -149,21 +157,21 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_resolution() { std::unique_ptr<List> SettingsPage::create_video_resolution() {
auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto area_size_params_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
area_size_params_list->add_widget(create_video_width_entry()); area_size_params_list->add_widget(create_video_width_entry());
area_size_params_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "x", get_color_theme().text_color)); area_size_params_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), "x", get_color_theme().text_color));
area_size_params_list->add_widget(create_video_height_entry()); area_size_params_list->add_widget(create_video_height_entry());
return area_size_params_list; return area_size_params_list;
} }
std::unique_ptr<List> SettingsPage::create_video_resolution_section() { std::unique_ptr<List> SettingsPage::create_video_resolution_section() {
auto video_resolution_list = std::make_unique<List>(List::Orientation::VERTICAL); auto video_resolution_list = std::make_unique<List>(List::Orientation::VERTICAL);
video_resolution_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video resolution limit:"), get_color_theme().text_color)); video_resolution_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video resolution limit:"), get_color_theme().text_color));
video_resolution_list->add_widget(create_video_resolution()); video_resolution_list->add_widget(create_video_resolution());
video_resolution_list_ptr = video_resolution_list.get(); video_resolution_list_ptr = video_resolution_list.get();
return video_resolution_list; return video_resolution_list;
} }
std::unique_ptr<CheckBox> SettingsPage::create_restore_portal_session_checkbox() { std::unique_ptr<CheckBox> SettingsPage::create_restore_portal_session_checkbox() {
auto restore_portal_session_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Restore portal session")); auto restore_portal_session_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Restore portal session"));
restore_portal_session_checkbox->set_checked(true); restore_portal_session_checkbox->set_checked(true);
restore_portal_session_checkbox_ptr = restore_portal_session_checkbox.get(); restore_portal_session_checkbox_ptr = restore_portal_session_checkbox.get();
return restore_portal_session_checkbox; return restore_portal_session_checkbox;
@@ -171,14 +179,14 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_restore_portal_session_section() { std::unique_ptr<List> SettingsPage::create_restore_portal_session_section() {
auto restore_portal_session_list = std::make_unique<List>(List::Orientation::VERTICAL); auto restore_portal_session_list = std::make_unique<List>(List::Orientation::VERTICAL);
restore_portal_session_list->add_widget(std::make_unique<Label>(&get_theme().body_font, " ", get_color_theme().text_color)); restore_portal_session_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), " ", get_color_theme().text_color));
restore_portal_session_list->add_widget(create_restore_portal_session_checkbox()); restore_portal_session_list->add_widget(create_restore_portal_session_checkbox());
restore_portal_session_list_ptr = restore_portal_session_list.get(); restore_portal_session_list_ptr = restore_portal_session_list.get();
return restore_portal_session_list; return restore_portal_session_list;
} }
std::unique_ptr<Widget> SettingsPage::create_change_video_resolution_section() { std::unique_ptr<Widget> SettingsPage::create_change_video_resolution_section() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Change video resolution")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Change video resolution"));
change_video_resolution_checkbox_ptr = checkbox.get(); change_video_resolution_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
} }
@@ -199,16 +207,16 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_webcam_sources() { std::unique_ptr<List> SettingsPage::create_webcam_sources() {
auto ll = std::make_unique<List>(List::Orientation::VERTICAL); auto ll = std::make_unique<List>(List::Orientation::VERTICAL);
ll->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Webcam source:"), get_color_theme().text_color)); ll->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Webcam source:"), get_color_theme().text_color));
auto combobox = std::make_unique<ComboBox>(&get_theme().body_font); auto combobox = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
combobox->add_item(TR("None"), ""); combobox->add_item(TR("None"), "");
for(const GsrCamera &camera : capture_options.cameras) { for(const GsrCamera &camera : capture_options.cameras) {
combobox->add_item(camera.path, camera.path); combobox->add_item(camera.path, camera.path);
} }
webcam_sources_box_ptr = combobox.get(); webcam_sources_box_ptr = combobox.get();
webcam_sources_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { webcam_sources_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
selected_camera = std::nullopt; selected_camera = std::nullopt;
selected_camera_setup = std::nullopt; selected_camera_setup = std::nullopt;
webcam_video_format_box_ptr->clear_items(); webcam_video_format_box_ptr->clear_items();
@@ -244,16 +252,19 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_webcam_video_setups() { std::unique_ptr<List> SettingsPage::create_webcam_video_setups() {
auto ll = std::make_unique<List>(List::Orientation::VERTICAL); auto ll = std::make_unique<List>(List::Orientation::VERTICAL);
ll->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video setup:"), get_color_theme().text_color)); ll->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video setup:"), get_color_theme().text_color));
auto combobox = std::make_unique<ComboBox>(&get_theme().body_font); auto combobox = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
webcam_video_setup_box_ptr = combobox.get(); webcam_video_setup_box_ptr = combobox.get();
webcam_video_setup_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { webcam_video_setup_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
int camera_width = 0; int camera_width = 0;
int camera_height = 0; int camera_height = 0;
int camera_fps = 0; int camera_fps = 0;
sscanf(id.c_str(), "%dx%d@%dhz", &camera_width, &camera_height, &camera_fps);
char id_str[256];
snprintf(id_str, sizeof(id_str), "%.*s", (int)id.size(), id.data());
sscanf(id_str, "%dx%d@%dhz", &camera_width, &camera_height, &camera_fps);
RecordOptions &current_record_options = get_current_record_options(); RecordOptions &current_record_options = get_current_record_options();
current_record_options.webcam_camera_width = camera_width; current_record_options.webcam_camera_width = camera_width;
@@ -279,12 +290,12 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_webcam_video_format() { std::unique_ptr<List> SettingsPage::create_webcam_video_format() {
auto ll = std::make_unique<List>(List::Orientation::VERTICAL); auto ll = std::make_unique<List>(List::Orientation::VERTICAL);
ll->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video format:"), get_color_theme().text_color)); ll->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video format:"), get_color_theme().text_color));
auto combobox = std::make_unique<ComboBox>(&get_theme().body_font); auto combobox = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
webcam_video_format_box_ptr = combobox.get(); webcam_video_format_box_ptr = combobox.get();
webcam_video_format_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { webcam_video_format_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
get_current_record_options().webcam_video_format = id; get_current_record_options().webcam_video_format = id;
auto it = std::find_if(capture_options.cameras.begin(), capture_options.cameras.end(), [&](const GsrCamera &camera) { auto it = std::find_if(capture_options.cameras.begin(), capture_options.cameras.end(), [&](const GsrCamera &camera) {
@@ -393,7 +404,7 @@ namespace gsr {
{ {
draw_rectangle_outline(window, pos, size, mgl::Color(255, 0, 0, 255), screen_border); draw_rectangle_outline(window, pos, size, mgl::Color(255, 0, 0, 255), screen_border);
mgl::Text screen_text(TR("Screen"), get_theme().camera_setup_font); mgl::Text screen_text(TR("Screen"), get_theme().camera_setup_font_desc.c_str());
screen_text.set_position((pos + size * 0.5f - screen_text.get_bounds().size * 0.5f).floor()); screen_text.set_position((pos + size * 0.5f - screen_text.get_bounds().size * 0.5f).floor());
window.draw(screen_text); window.draw(screen_text);
} }
@@ -408,7 +419,7 @@ namespace gsr {
// resize_area.set_color(mgl::Color(0, 0, 255, 255)); // resize_area.set_color(mgl::Color(0, 0, 255, 255));
// window.draw(resize_area); // window.draw(resize_area);
mgl::Text webcam_text(TR("Webcam"), get_theme().camera_setup_font); mgl::Text webcam_text(TR("Webcam"), get_theme().camera_setup_font_desc.c_str());
webcam_text.set_position((webcam_box_drawn_pos + webcam_box_drawn_size * 0.5f - webcam_text.get_bounds().size * 0.5f).floor()); webcam_text.set_position((webcam_box_drawn_pos + webcam_box_drawn_size * 0.5f - webcam_text.get_bounds().size * 0.5f).floor());
window.draw(webcam_text); window.draw(webcam_text);
} }
@@ -468,7 +479,7 @@ namespace gsr {
} }
std::unique_ptr<CheckBox> SettingsPage::create_flip_camera_checkbox() { std::unique_ptr<CheckBox> SettingsPage::create_flip_camera_checkbox() {
auto flip_camera_horizontally_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Flip camera horizontally")); auto flip_camera_horizontally_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Flip camera horizontally"));
flip_camera_horizontally_checkbox_ptr = flip_camera_horizontally_checkbox.get(); flip_camera_horizontally_checkbox_ptr = flip_camera_horizontally_checkbox.get();
return flip_camera_horizontally_checkbox; return flip_camera_horizontally_checkbox;
} }
@@ -478,7 +489,7 @@ namespace gsr {
webcam_body_list_ptr = body_list.get(); webcam_body_list_ptr = body_list.get();
body_list->set_visible(false); body_list->set_visible(false);
body_list->add_widget(create_webcam_location_widget()); body_list->add_widget(create_webcam_location_widget());
body_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("* Right click in the bottom right corner to resize the webcam"), get_color_theme().text_color)); body_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("* Right click in the bottom right corner to resize the webcam"), get_color_theme().text_color));
body_list->add_widget(create_flip_camera_checkbox()); body_list->add_widget(create_flip_camera_checkbox());
body_list->add_widget(create_webcam_video_setup_list()); body_list->add_widget(create_webcam_video_setup_list());
return body_list; return body_list;
@@ -496,7 +507,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox(AudioDeviceType device_type) { std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox(AudioDeviceType device_type) {
auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); auto audio_device_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
for(const auto &audio_device : audio_devices) { for(const auto &audio_device : audio_devices) {
const bool device_is_output = audio_device_is_output(audio_device.name); const bool device_is_output = audio_device_is_output(audio_device.name);
if((device_type == AudioDeviceType::OUTPUT && device_is_output) || (device_type == AudioDeviceType::INPUT && !device_is_output)) { if((device_type == AudioDeviceType::OUTPUT && device_is_output) || (device_type == AudioDeviceType::INPUT && !device_is_output)) {
@@ -532,7 +543,7 @@ namespace gsr {
} }
std::unique_ptr<Button> SettingsPage::create_remove_audio_device_button(List *audio_input_list_ptr, List *audio_device_list_ptr) { std::unique_ptr<Button> SettingsPage::create_remove_audio_device_button(List *audio_input_list_ptr, List *audio_device_list_ptr) {
auto remove_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0)); auto remove_audio_track_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0));
remove_audio_track_button->set_icon(&get_theme().trash_texture); remove_audio_track_button->set_icon(&get_theme().trash_texture);
remove_audio_track_button->set_icon_padding_scale(0.75f); remove_audio_track_button->set_icon_padding_scale(0.75f);
remove_audio_track_button->on_click = [this, audio_input_list_ptr, audio_device_list_ptr]() { remove_audio_track_button->on_click = [this, audio_input_list_ptr, audio_device_list_ptr]() {
@@ -545,14 +556,14 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_audio_device(AudioDeviceType device_type, List *audio_input_list_ptr) { std::unique_ptr<List> SettingsPage::create_audio_device(AudioDeviceType device_type, List *audio_input_list_ptr) {
auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
audio_device_list->userdata = (void*)(uintptr_t)AudioTrackType::DEVICE; audio_device_list->userdata = (void*)(uintptr_t)AudioTrackType::DEVICE;
audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, device_type == AudioDeviceType::OUTPUT ? TR("Output device:") : TR("Input device: "), get_color_theme().text_color)); audio_device_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), device_type == AudioDeviceType::OUTPUT ? TR("Output device:") : TR("Input device: "), get_color_theme().text_color));
audio_device_list->add_widget(create_audio_device_selection_combobox(device_type)); audio_device_list->add_widget(create_audio_device_selection_combobox(device_type));
audio_device_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, audio_device_list.get())); audio_device_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, audio_device_list.get()));
return audio_device_list; return audio_device_list;
} }
std::unique_ptr<Button> SettingsPage::create_add_audio_track_button() { std::unique_ptr<Button> SettingsPage::create_add_audio_track_button() {
auto button = std::make_unique<Button>(&get_theme().body_font, TR("Add audio track"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Add audio track"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
button->on_click = [this]() { button->on_click = [this]() {
audio_track_section_list_ptr->add_widget(create_audio_track_section(audio_section_ptr)); audio_track_section_list_ptr->add_widget(create_audio_track_section(audio_section_ptr));
}; };
@@ -577,7 +588,7 @@ namespace gsr {
switch(audio_track_type) { switch(audio_track_type) {
case AudioTrackType::DEVICE: { case AudioTrackType::DEVICE: {
Label *label = dynamic_cast<Label*>(audio_track_line->get_child_widget_by_index(0)); Label *label = dynamic_cast<Label*>(audio_track_line->get_child_widget_by_index(0));
const bool is_output_device = starts_with(label->get_text().c_str(), TR("Output device")); const bool is_output_device = starts_with(label->get_text(), TR("Output device"));
if(is_output_device) if(is_output_device)
num_output_devices++; num_output_devices++;
break; break;
@@ -597,7 +608,7 @@ namespace gsr {
} }
std::unique_ptr<Button> SettingsPage::create_add_audio_output_device_button(List *audio_input_list_ptr) { std::unique_ptr<Button> SettingsPage::create_add_audio_output_device_button(List *audio_input_list_ptr) {
auto button = std::make_unique<Button>(&get_theme().body_font, TR("Add output device"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Add output device"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
button->on_click = [this, audio_input_list_ptr]() { button->on_click = [this, audio_input_list_ptr]() {
audio_devices = get_audio_devices(); audio_devices = get_audio_devices();
audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::OUTPUT, audio_input_list_ptr)); audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::OUTPUT, audio_input_list_ptr));
@@ -607,7 +618,7 @@ namespace gsr {
} }
std::unique_ptr<Button> SettingsPage::create_add_audio_input_device_button(List *audio_input_list_ptr) { std::unique_ptr<Button> SettingsPage::create_add_audio_input_device_button(List *audio_input_list_ptr) {
auto button = std::make_unique<Button>(&get_theme().body_font, TR("Add input device"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Add input device"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
button->on_click = [this, audio_input_list_ptr]() { button->on_click = [this, audio_input_list_ptr]() {
audio_devices = get_audio_devices(); audio_devices = get_audio_devices();
audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::INPUT, audio_input_list_ptr)); audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::INPUT, audio_input_list_ptr));
@@ -616,17 +627,17 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox(List *application_audio_row) { std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox(List *application_audio_row) {
auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); auto audio_device_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
ComboBox *audio_device_box_ptr = audio_device_box.get(); ComboBox *audio_device_box_ptr = audio_device_box.get();
for(const auto &app_audio : application_audio) { for(const auto &app_audio : application_audio) {
audio_device_box->add_item(app_audio, app_audio); audio_device_box->add_item(app_audio, app_audio);
} }
audio_device_box->add_item(TR("Custom..."), custom_app_audio_tag); audio_device_box->add_item(TR("Custom..."), custom_app_audio_tag);
audio_device_box->on_selection_changed = [application_audio_row, audio_device_box_ptr](const std::string&, const std::string &id) { audio_device_box->on_selection_changed = [application_audio_row, audio_device_box_ptr](std::string_view, std::string_view id) {
if(id == custom_app_audio_tag) { if(id == custom_app_audio_tag) {
application_audio_row->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM; application_audio_row->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM;
auto custom_app_audio_entry = std::make_unique<Entry>(&get_theme().body_font, "", (int)(get_theme().body_font.get_character_size() * 10.0f)); auto custom_app_audio_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", (int)(2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 10.0f));
application_audio_row->replace_widget(audio_device_box_ptr, std::move(custom_app_audio_entry)); application_audio_row->replace_widget(audio_device_box_ptr, std::move(custom_app_audio_entry));
} }
}; };
@@ -637,7 +648,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_application_audio(List *audio_input_list_ptr) { std::unique_ptr<List> SettingsPage::create_application_audio(List *audio_input_list_ptr) {
auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION; application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION;
application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Application: "), get_color_theme().text_color)); application_audio_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Application: "), get_color_theme().text_color));
application_audio_list->add_widget(create_application_audio_selection_combobox(application_audio_list.get())); application_audio_list->add_widget(create_application_audio_selection_combobox(application_audio_list.get()));
application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get()));
return application_audio_list; return application_audio_list;
@@ -646,14 +657,14 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_custom_application_audio(List *audio_input_list_ptr) { std::unique_ptr<List> SettingsPage::create_custom_application_audio(List *audio_input_list_ptr) {
auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM; application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM;
application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Application: "), get_color_theme().text_color)); application_audio_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Application: "), get_color_theme().text_color));
application_audio_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "", (int)(get_theme().body_font.get_character_size() * 10.0f))); application_audio_list->add_widget(std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", (int)(2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 10.0f)));
application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get()));
return application_audio_list; return application_audio_list;
} }
std::unique_ptr<Button> SettingsPage::create_add_application_audio_button(List *audio_input_list_ptr) { std::unique_ptr<Button> SettingsPage::create_add_application_audio_button(List *audio_input_list_ptr) {
auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, TR("Add application audio"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto add_audio_track_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), TR("Add application audio"), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
add_audio_track_button->on_click = [this, audio_input_list_ptr]() { add_audio_track_button->on_click = [this, audio_input_list_ptr]() {
application_audio = get_application_audio(); application_audio = get_application_audio();
if(application_audio.empty()) if(application_audio.empty())
@@ -681,7 +692,7 @@ namespace gsr {
} }
std::unique_ptr<CheckBox> SettingsPage::create_application_audio_invert_checkbox() { std::unique_ptr<CheckBox> SettingsPage::create_application_audio_invert_checkbox() {
auto application_audio_invert_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Record audio from all applications except the selected ones")); auto application_audio_invert_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Record audio from all applications except the selected ones"));
application_audio_invert_checkbox->set_checked(false); application_audio_invert_checkbox->set_checked(false);
application_audio_invert_checkbox->on_changed = [this](bool) { application_audio_invert_checkbox->on_changed = [this](bool) {
update_application_audio_warning_visibility(); update_application_audio_warning_visibility();
@@ -694,9 +705,9 @@ namespace gsr {
list->set_spacing(0.003f); list->set_spacing(0.003f);
list->set_visible(false); list->set_visible(false);
const int font_character_size = get_theme().body_font.get_character_size(); const int font_character_size = 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str());
list->add_widget(std::make_unique<Image>(&get_theme().warning_texture, mgl::vec2f(font_character_size, font_character_size), Image::ScaleBehavior::SCALE)); list->add_widget(std::make_unique<Image>(&get_theme().warning_texture, mgl::vec2f(font_character_size, font_character_size), Image::ScaleBehavior::SCALE));
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Recording output devices and application audio may record all output audio, which is likely\nnot what you want to do. Remove the output devices."), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Recording output devices and application audio may record all output audio, which is likely\nnot what you want to do. Remove the output devices."), get_color_theme().text_color));
return list; return list;
} }
@@ -718,9 +729,9 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_audio_track_title_and_remove(Subsection *audio_track_subsection, const char *title) { std::unique_ptr<List> SettingsPage::create_audio_track_title_and_remove(Subsection *audio_track_subsection, const char *title) {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().title_font, title, get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().title_font_desc.c_str(), title, get_color_theme().text_color));
auto remove_track_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0)); auto remove_track_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 0));
remove_track_button->set_icon(&get_theme().trash_texture); remove_track_button->set_icon(&get_theme().trash_texture);
remove_track_button->set_icon_padding_scale(0.75f); remove_track_button->set_icon_padding_scale(0.75f);
remove_track_button->on_click = [this, audio_track_subsection]() { remove_track_button->on_click = [this, audio_track_subsection]() {
@@ -774,9 +785,9 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_quality_box() { std::unique_ptr<List> SettingsPage::create_video_quality_box() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video quality:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video quality:"), get_color_theme().text_color));
auto video_quality_box = std::make_unique<ComboBox>(&get_theme().body_font); auto video_quality_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
if(type == Type::REPLAY || type == Type::STREAM) if(type == Type::REPLAY || type == Type::STREAM)
video_quality_box->add_item(TR("Constant bitrate (Recommended)"), "custom"); video_quality_box->add_item(TR("Constant bitrate (Recommended)"), "custom");
else else
@@ -802,18 +813,18 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_bitrate_entry() { std::unique_ptr<List> SettingsPage::create_video_bitrate_entry() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto video_bitrate_entry = std::make_unique<Entry>(&get_theme().body_font, "8000", (int)(get_theme().body_font.get_character_size() * 4.0f)); auto video_bitrate_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "8000", (int)(2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 5));
video_bitrate_entry->validate_handler = create_entry_validator_integer_in_range(1, 500000); video_bitrate_entry->set_number_mode(true, 1, 500000);
video_bitrate_entry_ptr = video_bitrate_entry.get(); video_bitrate_entry_ptr = video_bitrate_entry.get();
list->add_widget(std::move(video_bitrate_entry)); list->add_widget(std::move(video_bitrate_entry));
if(type == Type::STREAM) { if(type == Type::STREAM) {
auto size_mb_label = std::make_unique<Label>(&get_theme().body_font, "", get_color_theme().text_color); auto size_mb_label = std::make_unique<Label>(get_theme().body_font_desc.c_str(), "", get_color_theme().text_color);
Label *size_mb_label_ptr = size_mb_label.get(); Label *size_mb_label_ptr = size_mb_label.get();
list->add_widget(std::move(size_mb_label)); list->add_widget(std::move(size_mb_label));
video_bitrate_entry_ptr->on_changed = [size_mb_label_ptr](const std::string &text) { video_bitrate_entry_ptr->on_changed = [size_mb_label_ptr](std::string_view text) {
const double video_bitrate_mbits_per_seconds = (double)atoi(text.c_str()) / 1024.0; const double video_bitrate_mbits_per_seconds = (double)sv_to_int<int64_t>(text) / 1024.0;
char buffer[32]; char buffer[32];
snprintf(buffer, sizeof(buffer), "%.2fMbps", video_bitrate_mbits_per_seconds); snprintf(buffer, sizeof(buffer), "%.2fMbps", video_bitrate_mbits_per_seconds);
size_mb_label_ptr->set_text(buffer); size_mb_label_ptr->set_text(buffer);
@@ -825,14 +836,14 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_bitrate() { std::unique_ptr<List> SettingsPage::create_video_bitrate() {
auto video_bitrate_list = std::make_unique<List>(List::Orientation::VERTICAL); auto video_bitrate_list = std::make_unique<List>(List::Orientation::VERTICAL);
video_bitrate_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video bitrate (Kbps):"), get_color_theme().text_color)); video_bitrate_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video bitrate (Kbps):"), get_color_theme().text_color));
video_bitrate_list->add_widget(create_video_bitrate_entry()); video_bitrate_list->add_widget(create_video_bitrate_entry());
video_bitrate_list_ptr = video_bitrate_list.get(); video_bitrate_list_ptr = video_bitrate_list.get();
return video_bitrate_list; return video_bitrate_list;
} }
std::unique_ptr<ComboBox> SettingsPage::create_color_range_box() { std::unique_ptr<ComboBox> SettingsPage::create_color_range_box() {
auto color_range_box = std::make_unique<ComboBox>(&get_theme().body_font); auto color_range_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
color_range_box->add_item(TR("Limited"), "limited"); color_range_box->add_item(TR("Limited"), "limited");
color_range_box->add_item(TR("Full"), "full"); color_range_box->add_item(TR("Full"), "full");
color_range_box_ptr = color_range_box.get(); color_range_box_ptr = color_range_box.get();
@@ -841,7 +852,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_color_range() { std::unique_ptr<List> SettingsPage::create_color_range() {
auto color_range_list = std::make_unique<List>(List::Orientation::VERTICAL); auto color_range_list = std::make_unique<List>(List::Orientation::VERTICAL);
color_range_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Color range:"), get_color_theme().text_color)); color_range_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Color range:"), get_color_theme().text_color));
color_range_list->add_widget(create_color_range_box()); color_range_list->add_widget(create_color_range_box());
color_range_list_ptr = color_range_list.get(); color_range_list_ptr = color_range_list.get();
return color_range_list; return color_range_list;
@@ -856,7 +867,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box() { std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box() {
auto video_codec_box = std::make_unique<ComboBox>(&get_theme().body_font); auto video_codec_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
// TODO: Show options not supported but disable them. // TODO: Show options not supported but disable them.
// TODO: Show error if no encoders are supported. // TODO: Show error if no encoders are supported.
// TODO: Show warning (once) if only software encoder is available. // TODO: Show warning (once) if only software encoder is available.
@@ -887,14 +898,14 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_codec() { std::unique_ptr<List> SettingsPage::create_video_codec() {
auto video_codec_list = std::make_unique<List>(List::Orientation::VERTICAL); auto video_codec_list = std::make_unique<List>(List::Orientation::VERTICAL);
video_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Video codec:"), get_color_theme().text_color)); video_codec_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Video codec:"), get_color_theme().text_color));
video_codec_list->add_widget(create_video_codec_box()); video_codec_list->add_widget(create_video_codec_box());
video_codec_ptr = video_codec_list.get(); video_codec_ptr = video_codec_list.get();
return video_codec_list; return video_codec_list;
} }
std::unique_ptr<ComboBox> SettingsPage::create_audio_codec_box() { std::unique_ptr<ComboBox> SettingsPage::create_audio_codec_box() {
auto audio_codec_box = std::make_unique<ComboBox>(&get_theme().body_font); auto audio_codec_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
audio_codec_box->add_item(TR("Opus (Recommended)"), "opus"); audio_codec_box->add_item(TR("Opus (Recommended)"), "opus");
audio_codec_box->add_item(TR("AAC"), "aac"); audio_codec_box->add_item(TR("AAC"), "aac");
audio_codec_box_ptr = audio_codec_box.get(); audio_codec_box_ptr = audio_codec_box.get();
@@ -903,28 +914,28 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_audio_codec() { std::unique_ptr<List> SettingsPage::create_audio_codec() {
auto audio_codec_list = std::make_unique<List>(List::Orientation::VERTICAL); auto audio_codec_list = std::make_unique<List>(List::Orientation::VERTICAL);
audio_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Audio codec:"), get_color_theme().text_color)); audio_codec_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Audio codec:"), get_color_theme().text_color));
audio_codec_list->add_widget(create_audio_codec_box()); audio_codec_list->add_widget(create_audio_codec_box());
audio_codec_ptr = audio_codec_list.get(); audio_codec_ptr = audio_codec_list.get();
return audio_codec_list; return audio_codec_list;
} }
std::unique_ptr<Entry> SettingsPage::create_framerate_entry() { std::unique_ptr<Entry> SettingsPage::create_framerate_entry() {
auto framerate_entry = std::make_unique<Entry>(&get_theme().body_font, "60", (int)(get_theme().body_font.get_character_size() * 2.5f)); auto framerate_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "60", (int)(2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 3));
framerate_entry->validate_handler = create_entry_validator_integer_in_range(1, 500); framerate_entry->set_number_mode(true, 1, 500);
framerate_entry_ptr = framerate_entry.get(); framerate_entry_ptr = framerate_entry.get();
return framerate_entry; return framerate_entry;
} }
std::unique_ptr<List> SettingsPage::create_framerate() { std::unique_ptr<List> SettingsPage::create_framerate() {
auto framerate_list = std::make_unique<List>(List::Orientation::VERTICAL); auto framerate_list = std::make_unique<List>(List::Orientation::VERTICAL);
framerate_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Frame rate:"), get_color_theme().text_color)); framerate_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Frame rate:"), get_color_theme().text_color));
framerate_list->add_widget(create_framerate_entry()); framerate_list->add_widget(create_framerate_entry());
return framerate_list; return framerate_list;
} }
std::unique_ptr<ComboBox> SettingsPage::create_framerate_mode_box() { std::unique_ptr<ComboBox> SettingsPage::create_framerate_mode_box() {
auto framerate_mode_box = std::make_unique<ComboBox>(&get_theme().body_font); auto framerate_mode_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
framerate_mode_box->add_item(TR("Auto (Recommended)"), "auto"); framerate_mode_box->add_item(TR("Auto (Recommended)"), "auto");
framerate_mode_box->add_item(TR("Constant"), "cfr"); framerate_mode_box->add_item(TR("Constant"), "cfr");
framerate_mode_box->add_item(TR("Variable"), "vfr"); framerate_mode_box->add_item(TR("Variable"), "vfr");
@@ -938,7 +949,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_framerate_mode() { std::unique_ptr<List> SettingsPage::create_framerate_mode() {
auto framerate_mode_list = std::make_unique<List>(List::Orientation::VERTICAL); auto framerate_mode_list = std::make_unique<List>(List::Orientation::VERTICAL);
framerate_mode_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Frame rate mode:"), get_color_theme().text_color)); framerate_mode_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Frame rate mode:"), get_color_theme().text_color));
framerate_mode_list->add_widget(create_framerate_mode_box()); framerate_mode_list->add_widget(create_framerate_mode_box());
framerate_mode_list_ptr = framerate_mode_list.get(); framerate_mode_list_ptr = framerate_mode_list.get();
return framerate_mode_list; return framerate_mode_list;
@@ -952,7 +963,7 @@ namespace gsr {
} }
std::unique_ptr<Widget> SettingsPage::create_record_cursor_section() { std::unique_ptr<Widget> SettingsPage::create_record_cursor_section() {
auto record_cursor_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Record cursor")); auto record_cursor_checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Record cursor"));
record_cursor_checkbox->set_checked(true); record_cursor_checkbox->set_checked(true);
record_cursor_checkbox_ptr = record_cursor_checkbox.get(); record_cursor_checkbox_ptr = record_cursor_checkbox.get();
return record_cursor_checkbox; return record_cursor_checkbox;
@@ -989,7 +1000,7 @@ namespace gsr {
void SettingsPage::add_widgets() { void SettingsPage::add_widgets() {
content_page_ptr->add_widget(create_settings()); content_page_ptr->add_widget(create_settings());
record_area_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { record_area_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
const bool focused_selected = id == "focused"; const bool focused_selected = id == "focused";
const bool portal_selected = id == "portal"; const bool portal_selected = id == "portal";
area_size_list_ptr->set_visible(focused_selected); area_size_list_ptr->set_visible(focused_selected);
@@ -1004,7 +1015,7 @@ namespace gsr {
video_resolution_list_ptr->set_visible(!focused_selected && checked); video_resolution_list_ptr->set_visible(!focused_selected && checked);
}; };
video_quality_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { video_quality_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
const bool custom_selected = id == "custom"; const bool custom_selected = id == "custom";
video_bitrate_list_ptr->set_visible(custom_selected); video_bitrate_list_ptr->set_visible(custom_selected);
@@ -1041,15 +1052,15 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_save_directory(const char *label) { std::unique_ptr<List> SettingsPage::create_save_directory(const char *label) {
auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL); auto save_directory_list = std::make_unique<List>(List::Orientation::VERTICAL);
save_directory_list->add_widget(std::make_unique<Label>(&get_theme().body_font, label, get_color_theme().text_color)); save_directory_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), label, get_color_theme().text_color));
auto save_directory_button = std::make_unique<Button>(&get_theme().body_font, get_videos_dir().c_str(), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); auto save_directory_button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), get_videos_dir().c_str(), mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
save_directory_button_ptr = save_directory_button.get(); save_directory_button_ptr = save_directory_button.get();
save_directory_button->on_click = [this]() { save_directory_button->on_click = [this]() {
auto select_directory_page = std::make_unique<GsrPage>(TR("File"), TR("Settings")); auto select_directory_page = std::make_unique<GsrPage>(TR("File"), TR("Settings"));
select_directory_page->add_button(TR("Save"), "save", get_color_theme().tint_color); select_directory_page->add_button(TR("Save"), "save", get_color_theme().tint_color);
select_directory_page->add_button(TR("Cancel"), "cancel", get_color_theme().page_bg_color); select_directory_page->add_button(TR("Cancel"), "cancel", get_color_theme().page_bg_color);
auto file_chooser = std::make_unique<FileChooser>(save_directory_button_ptr->get_text().c_str(), select_directory_page->get_inner_size()); auto file_chooser = std::make_unique<FileChooser>(save_directory_button_ptr->get_text(), select_directory_page->get_inner_size());
FileChooser *file_chooser_ptr = file_chooser.get(); FileChooser *file_chooser_ptr = file_chooser.get();
select_directory_page->add_widget(std::move(file_chooser)); select_directory_page->add_widget(std::move(file_chooser));
@@ -1069,7 +1080,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_container_box() { std::unique_ptr<ComboBox> SettingsPage::create_container_box() {
auto container_box = std::make_unique<ComboBox>(&get_theme().body_font); auto container_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
container_box->add_item("mp4", "mp4"); container_box->add_item("mp4", "mp4");
container_box->add_item("mkv", "matroska"); container_box->add_item("mkv", "matroska");
container_box->add_item("flv", "flv"); container_box->add_item("flv", "flv");
@@ -1080,7 +1091,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_container_section() { std::unique_ptr<List> SettingsPage::create_container_section() {
auto container_list = std::make_unique<List>(List::Orientation::VERTICAL); auto container_list = std::make_unique<List>(List::Orientation::VERTICAL);
container_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Container:"), get_color_theme().text_color)); container_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Container:"), get_color_theme().text_color));
container_list->add_widget(create_container_box()); container_list->add_widget(create_container_box());
return container_list; return container_list;
} }
@@ -1088,12 +1099,12 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_replay_time_entry() { std::unique_ptr<List> SettingsPage::create_replay_time_entry() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto replay_time_entry = std::make_unique<Entry>(&get_theme().body_font, "60", get_theme().body_font.get_character_size() * 3); auto replay_time_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "60", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 4);
replay_time_entry->validate_handler = create_entry_validator_integer_in_range(1, 86400); replay_time_entry->set_number_mode(true, 1, 86400);
replay_time_entry_ptr = replay_time_entry.get(); replay_time_entry_ptr = replay_time_entry.get();
list->add_widget(std::move(replay_time_entry)); list->add_widget(std::move(replay_time_entry));
auto replay_time_label = std::make_unique<Label>(&get_theme().body_font, "00h:00m:00s", get_color_theme().text_color); auto replay_time_label = std::make_unique<Label>(get_theme().body_font_desc.c_str(), "00h:00m:00s", get_color_theme().text_color);
replay_time_label_ptr = replay_time_label.get(); replay_time_label_ptr = replay_time_label.get();
list->add_widget(std::move(replay_time_label)); list->add_widget(std::move(replay_time_label));
@@ -1102,20 +1113,20 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_replay_time() { std::unique_ptr<List> SettingsPage::create_replay_time() {
auto replay_time_list = std::make_unique<List>(List::Orientation::VERTICAL); auto replay_time_list = std::make_unique<List>(List::Orientation::VERTICAL);
replay_time_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Replay duration in seconds:"), get_color_theme().text_color)); replay_time_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Replay duration in seconds:"), get_color_theme().text_color));
replay_time_list->add_widget(create_replay_time_entry()); replay_time_list->add_widget(create_replay_time_entry());
return replay_time_list; return replay_time_list;
} }
std::unique_ptr<List> SettingsPage::create_replay_storage() { std::unique_ptr<List> SettingsPage::create_replay_storage() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Where should temporary replay data be stored?"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Where should temporary replay data be stored?"), get_color_theme().text_color));
auto replay_storage_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); auto replay_storage_button = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::HORIZONTAL);
replay_storage_button_ptr = replay_storage_button.get(); replay_storage_button_ptr = replay_storage_button.get();
replay_storage_button->add_item(TR("RAM"), "ram"); replay_storage_button->add_item(TR("RAM"), "ram");
replay_storage_button->add_item(TR("Disk (Not recommended on SSDs)"), "disk"); replay_storage_button->add_item(TR("Disk (Not recommended on SSDs)"), "disk");
replay_storage_button->on_selection_changed = [this](const std::string&, const std::string &id) { replay_storage_button->on_selection_changed = [this](std::string_view, std::string_view id) {
update_estimated_replay_file_size(id); update_estimated_replay_file_size(id);
return true; return true;
}; };
@@ -1130,7 +1141,7 @@ namespace gsr {
char fullscreen_text[256]; char fullscreen_text[256];
snprintf(fullscreen_text, sizeof(fullscreen_text), TR("Turn on replay when starting a fullscreen application%s"), supports_window_fullscreen_state ? "" : TR(" (X11 applications only)")); snprintf(fullscreen_text, sizeof(fullscreen_text), TR("Turn on replay when starting a fullscreen application%s"), supports_window_fullscreen_state ? "" : TR(" (X11 applications only)"));
auto radiobutton = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::VERTICAL); auto radiobutton = std::make_unique<RadioButton>(get_theme().body_font_desc.c_str(), RadioButton::Orientation::VERTICAL);
radiobutton->add_item(TR("Don't turn on replay automatically"), "dont_turn_on_automatically"); radiobutton->add_item(TR("Don't turn on replay automatically"), "dont_turn_on_automatically");
radiobutton->add_item(TR("Turn on replay when this program starts"), "turn_on_at_system_startup"); radiobutton->add_item(TR("Turn on replay when this program starts"), "turn_on_at_system_startup");
radiobutton->add_item(fullscreen_text, "turn_on_at_fullscreen"); radiobutton->add_item(fullscreen_text, "turn_on_at_fullscreen");
@@ -1142,26 +1153,26 @@ namespace gsr {
std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder() { std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder() {
char text[256]; char text[256];
snprintf(text, sizeof(text), TR("Save video in a folder based on the games name%s"), supports_window_title ? "" : TR(" (X11 applications only)")); snprintf(text, sizeof(text), TR("Save video in a folder based on the games name%s"), supports_window_title ? "" : TR(" (X11 applications only)"));
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), text);
save_replay_in_game_folder_ptr = checkbox.get(); save_replay_in_game_folder_ptr = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<CheckBox> SettingsPage::create_restart_replay_on_save() { std::unique_ptr<CheckBox> SettingsPage::create_restart_replay_on_save() {
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Restart replay on save")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Restart replay on save"));
restart_replay_on_save = checkbox.get(); restart_replay_on_save = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<Label> SettingsPage::create_estimated_replay_file_size() { std::unique_ptr<Label> SettingsPage::create_estimated_replay_file_size() {
auto label = std::make_unique<Label>(&get_theme().body_font, "Estimated video max file size in RAM: 57.60MB", get_color_theme().text_color); auto label = std::make_unique<Label>(get_theme().body_font_desc.c_str(), "Estimated video max file size in RAM: 57.60MB", get_color_theme().text_color);
estimated_file_size_ptr = label.get(); estimated_file_size_ptr = label.get();
return label; return label;
} }
void SettingsPage::update_estimated_replay_file_size(const std::string &replay_storage_type) { void SettingsPage::update_estimated_replay_file_size(std::string_view replay_storage_type) {
const int64_t replay_time_seconds = atoi(replay_time_entry_ptr->get_text().c_str()); const int64_t replay_time_seconds = sv_to_int<int64_t>(replay_time_entry_ptr->get_text());
const int64_t video_bitrate_bps = atoi(video_bitrate_entry_ptr->get_text().c_str()) * 1000LL / 8LL; const int64_t video_bitrate_bps = sv_to_int<int64_t>(video_bitrate_entry_ptr->get_text()) * 1000LL / 8LL;
const double video_filesize_mb = ((double)replay_time_seconds * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024; const double video_filesize_mb = ((double)replay_time_seconds * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024;
char buffer[256]; char buffer[256];
@@ -1170,7 +1181,7 @@ namespace gsr {
} }
void SettingsPage::update_replay_time_text() { void SettingsPage::update_replay_time_text() {
int seconds = atoi(replay_time_entry_ptr->get_text().c_str()); int seconds = sv_to_int<int>(replay_time_entry_ptr->get_text());
const int hours = seconds / 60 / 60; const int hours = seconds / 60 / 60;
seconds -= (hours * 60 * 60); seconds -= (hours * 60 * 60);
@@ -1206,7 +1217,7 @@ namespace gsr {
char label_str[256]; char label_str[256];
snprintf(label_str, sizeof(label_str), TR("Show %s status with scroll lock LED"), type); snprintf(label_str, sizeof(label_str), TR("Show %s status with scroll lock LED"), type);
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, label_str); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), label_str);
checkbox->set_checked(false); checkbox->set_checked(false);
led_indicator_checkbox_ptr = checkbox.get(); led_indicator_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
@@ -1215,7 +1226,7 @@ namespace gsr {
std::unique_ptr<CheckBox> SettingsPage::create_notifications(const char *type) { std::unique_ptr<CheckBox> SettingsPage::create_notifications(const char *type) {
char label_str[256]; char label_str[256];
snprintf(label_str, sizeof(label_str), TR("Show %s notifications"), type); snprintf(label_str, sizeof(label_str), TR("Show %s notifications"), type);
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, label_str); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), label_str);
checkbox->set_checked(true); checkbox->set_checked(true);
show_notification_checkbox_ptr = checkbox.get(); show_notification_checkbox_ptr = checkbox.get();
return checkbox; return checkbox;
@@ -1232,7 +1243,7 @@ namespace gsr {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->set_visible(gsr_info->gpu_info.vendor == GpuVendor::AMD); list->set_visible(gsr_info->gpu_info.vendor == GpuVendor::AMD);
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, TR("Record in low-power mode")); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), TR("Record in low-power mode"));
low_power_mode_checkbox_ptr = checkbox.get(); low_power_mode_checkbox_ptr = checkbox.get();
list->add_widget(std::move(checkbox)); list->add_widget(std::move(checkbox));
@@ -1276,18 +1287,18 @@ namespace gsr {
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Replay indicator"), create_indicator(TR("replay")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Replay indicator"), create_indicator(TR("replay")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Autostart"), create_start_replay_automatically(), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Autostart"), create_start_replay_automatically(), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
view_radio_button_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { view_radio_button_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
view_changed(id == "advanced"); view_changed(id == "advanced");
return true; return true;
}; };
view_radio_button_ptr->on_selection_changed(TR("Simple"), "simple"); view_radio_button_ptr->on_selection_changed(TR("Simple"), "simple");
replay_time_entry_ptr->on_changed = [this](const std::string&) { replay_time_entry_ptr->on_changed = [this](std::string_view) {
update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id());
update_replay_time_text(); update_replay_time_text();
}; };
video_bitrate_entry_ptr->on_changed = [this](const std::string&) { video_bitrate_entry_ptr->on_changed = [this](std::string_view) {
update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id());
}; };
} }
@@ -1295,19 +1306,19 @@ namespace gsr {
std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder() { std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder() {
char text[256]; char text[256];
snprintf(text, sizeof(text), TR("Save video in a folder based on the games name%s"), supports_window_title ? "" : TR(" (X11 applications only)")); snprintf(text, sizeof(text), TR("Save video in a folder based on the games name%s"), supports_window_title ? "" : TR(" (X11 applications only)"));
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text); auto checkbox = std::make_unique<CheckBox>(get_theme().body_font_desc.c_str(), text);
save_recording_in_game_folder_ptr = checkbox.get(); save_recording_in_game_folder_ptr = checkbox.get();
return checkbox; return checkbox;
} }
std::unique_ptr<Label> SettingsPage::create_estimated_record_file_size() { std::unique_ptr<Label> SettingsPage::create_estimated_record_file_size() {
auto label = std::make_unique<Label>(&get_theme().body_font, "Estimated video file size per minute (excluding audio): 345.60MB", get_color_theme().text_color); auto label = std::make_unique<Label>(get_theme().body_font_desc.c_str(), "Estimated video file size per minute (excluding audio): 345.60MB", get_color_theme().text_color);
estimated_file_size_ptr = label.get(); estimated_file_size_ptr = label.get();
return label; return label;
} }
void SettingsPage::update_estimated_record_file_size() { void SettingsPage::update_estimated_record_file_size() {
const int64_t video_bitrate_bps = atoi(video_bitrate_entry_ptr->get_text().c_str()) * 1000LL / 8LL; const int64_t video_bitrate_bps = sv_to_int<int64_t>(video_bitrate_entry_ptr->get_text()) * 1000LL / 8LL;
const double video_filesize_mb_per_minute = (60.0 * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024; const double video_filesize_mb_per_minute = (60.0 * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024;
char buffer[512]; char buffer[512];
@@ -1332,19 +1343,19 @@ namespace gsr {
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("General"), std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("General"), std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Recording indicator"), create_indicator(TR("recording")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Recording indicator"), create_indicator(TR("recording")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
view_radio_button_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { view_radio_button_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
view_changed(id == "advanced"); view_changed(id == "advanced");
return true; return true;
}; };
view_radio_button_ptr->on_selection_changed(TR("Simple"), "simple"); view_radio_button_ptr->on_selection_changed(TR("Simple"), "simple");
video_bitrate_entry_ptr->on_changed = [this](const std::string&) { video_bitrate_entry_ptr->on_changed = [this](std::string_view) {
update_estimated_record_file_size(); update_estimated_record_file_size();
}; };
} }
std::unique_ptr<ComboBox> SettingsPage::create_streaming_service_box() { std::unique_ptr<ComboBox> SettingsPage::create_streaming_service_box() {
auto streaming_service_box = std::make_unique<ComboBox>(&get_theme().body_font); auto streaming_service_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
streaming_service_box->add_item(TR("Twitch"), "twitch"); streaming_service_box->add_item(TR("Twitch"), "twitch");
streaming_service_box->add_item(TR("YouTube"), "youtube"); streaming_service_box->add_item(TR("YouTube"), "youtube");
streaming_service_box->add_item(TR("Rumble"), "rumble"); streaming_service_box->add_item(TR("Rumble"), "rumble");
@@ -1356,13 +1367,13 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_streaming_service_section() { std::unique_ptr<List> SettingsPage::create_streaming_service_section() {
auto streaming_service_list = std::make_unique<List>(List::Orientation::VERTICAL); auto streaming_service_list = std::make_unique<List>(List::Orientation::VERTICAL);
streaming_service_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Stream service:"), get_color_theme().text_color)); streaming_service_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream service:"), get_color_theme().text_color));
streaming_service_list->add_widget(create_streaming_service_box()); streaming_service_list->add_widget(create_streaming_service_box());
return streaming_service_list; return streaming_service_list;
} }
static std::unique_ptr<Button> create_mask_toggle_button(Entry *entry_to_toggle, mgl::vec2f size) { static std::unique_ptr<Button> create_mask_toggle_button(Entry *entry_to_toggle, mgl::vec2f size) {
auto button = std::make_unique<Button>(&get_theme().body_font, "", size, mgl::Color(0, 0, 0, 0)); auto button = std::make_unique<Button>(get_theme().body_font_desc.c_str(), "", size, mgl::Color(0, 0, 0, 0));
Button *button_ptr = button.get(); Button *button_ptr = button.get();
button->set_icon(&get_theme().masked_texture); button->set_icon(&get_theme().masked_texture);
button->on_click = [entry_to_toggle, button_ptr]() { button->on_click = [entry_to_toggle, button_ptr]() {
@@ -1375,7 +1386,7 @@ namespace gsr {
static Entry* add_stream_key_entry_to_list(List *stream_key_list) { static Entry* add_stream_key_entry_to_list(List *stream_key_list) {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto key_entry = std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20); auto key_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
key_entry->set_masked(true); key_entry->set_masked(true);
Entry *key_entry_ptr = key_entry.get(); Entry *key_entry_ptr = key_entry.get();
const float mask_icon_size = key_entry_ptr->get_size().y * 0.9f; const float mask_icon_size = key_entry_ptr->get_size().y * 0.9f;
@@ -1387,30 +1398,62 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_stream_key_section() { std::unique_ptr<List> SettingsPage::create_stream_key_section() {
auto stream_key_list = std::make_unique<List>(List::Orientation::VERTICAL); auto stream_key_list = std::make_unique<List>(List::Orientation::VERTICAL);
stream_key_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Stream key:"), get_color_theme().text_color)); stream_key_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream key:"), get_color_theme().text_color));
twitch_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get()); twitch_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get());
youtube_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get()); youtube_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get());
rumble_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get()); rumble_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get());
kick_stream_url_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get());
kick_stream_key_entry_ptr = add_stream_key_entry_to_list(stream_key_list.get());
stream_key_list_ptr = stream_key_list.get(); stream_key_list_ptr = stream_key_list.get();
return stream_key_list; return stream_key_list;
} }
std::unique_ptr<List> SettingsPage::create_stream_kick_url() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL);
auto stream_url_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
kick_stream_url_entry_ptr = stream_url_entry.get();
list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream URL:"), get_color_theme().text_color));
list->add_widget(std::move(stream_url_entry));
return list;
}
std::unique_ptr<List> SettingsPage::create_stream_kick_key() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto stream_key_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
stream_key_entry->set_masked(true);
kick_stream_key_entry_ptr = stream_key_entry.get();
const float mask_icon_size = kick_stream_key_entry_ptr->get_size().y * 1.0f;
list->add_widget(std::move(stream_key_entry));
list->add_widget(create_mask_toggle_button(kick_stream_key_entry_ptr, mgl::vec2f(mask_icon_size, mask_icon_size)));
return list;
}
std::unique_ptr<List> SettingsPage::create_stream_kick_section() {
auto kick_stream_list = std::make_unique<List>(List::Orientation::VERTICAL);
auto stream_url_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
stream_url_list->add_widget(create_stream_kick_url());
kick_stream_list->add_widget(std::move(stream_url_list));
kick_stream_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream key:"), get_color_theme().text_color));
kick_stream_list->add_widget(create_stream_kick_key());
kick_stream_list_ptr = kick_stream_list.get();
return kick_stream_list;
}
std::unique_ptr<List> SettingsPage::create_stream_custom_url() { std::unique_ptr<List> SettingsPage::create_stream_custom_url() {
auto list = std::make_unique<List>(List::Orientation::VERTICAL); auto list = std::make_unique<List>(List::Orientation::VERTICAL);
auto stream_url_entry = std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20); auto stream_url_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
stream_url_entry_ptr = stream_url_entry.get(); stream_url_entry_ptr = stream_url_entry.get();
list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Stream URL:"), get_color_theme().text_color)); list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream URL:"), get_color_theme().text_color));
list->add_widget(std::move(stream_url_entry)); list->add_widget(std::move(stream_url_entry));
return list; return list;
} }
std::unique_ptr<List> SettingsPage::create_stream_custom_key() { std::unique_ptr<List> SettingsPage::create_stream_custom_key() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
auto stream_key_entry = std::make_unique<Entry>(&get_theme().body_font, "", get_theme().body_font.get_character_size() * 20); auto stream_key_entry = std::make_unique<Entry>(get_theme().body_font_desc.c_str(), "", 2.0f*mgl::Text::get_font_size_from_font_description(get_theme().body_font_desc.c_str()) * 20);
stream_key_entry->set_masked(true); stream_key_entry->set_masked(true);
stream_key_entry_ptr = stream_key_entry.get(); stream_key_entry_ptr = stream_key_entry.get();
const float mask_icon_size = stream_key_entry_ptr->get_size().y * 0.9f; const float mask_icon_size = stream_key_entry_ptr->get_size().y * 0.9f;
@@ -1427,7 +1470,7 @@ namespace gsr {
stream_url_list->add_widget(create_stream_container()); stream_url_list->add_widget(create_stream_container());
custom_stream_list->add_widget(std::move(stream_url_list)); custom_stream_list->add_widget(std::move(stream_url_list));
custom_stream_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Stream key:"), get_color_theme().text_color)); custom_stream_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Stream key:"), get_color_theme().text_color));
custom_stream_list->add_widget(create_stream_custom_key()); custom_stream_list->add_widget(create_stream_custom_key());
custom_stream_list_ptr = custom_stream_list.get(); custom_stream_list_ptr = custom_stream_list.get();
@@ -1435,7 +1478,7 @@ namespace gsr {
} }
std::unique_ptr<ComboBox> SettingsPage::create_stream_container_box() { std::unique_ptr<ComboBox> SettingsPage::create_stream_container_box() {
auto container_box = std::make_unique<ComboBox>(&get_theme().body_font); auto container_box = std::make_unique<ComboBox>(get_theme().body_font_desc.c_str());
container_box->add_item("mp4", "mp4"); container_box->add_item("mp4", "mp4");
container_box->add_item("flv", "flv"); container_box->add_item("flv", "flv");
container_box->add_item("ts", "mpegts"); container_box->add_item("ts", "mpegts");
@@ -1446,7 +1489,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_stream_container() { std::unique_ptr<List> SettingsPage::create_stream_container() {
auto container_list = std::make_unique<List>(List::Orientation::VERTICAL); auto container_list = std::make_unique<List>(List::Orientation::VERTICAL);
container_list->add_widget(std::make_unique<Label>(&get_theme().body_font, TR("Container:"), get_color_theme().text_color)); container_list->add_widget(std::make_unique<Label>(get_theme().body_font_desc.c_str(), TR("Container:"), get_color_theme().text_color));
container_list->add_widget(create_stream_container_box()); container_list->add_widget(create_stream_container_box());
return container_list; return container_list;
} }
@@ -1455,6 +1498,7 @@ namespace gsr {
auto streaming_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL); 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_streaming_service_section());
streaming_info_list->add_widget(create_stream_key_section()); streaming_info_list->add_widget(create_stream_key_section());
streaming_info_list->add_widget(create_stream_kick_section());
streaming_info_list->add_widget(create_stream_custom_section()); streaming_info_list->add_widget(create_stream_custom_section());
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Streaming info"), std::move(streaming_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Streaming info"), std::move(streaming_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
@@ -1465,24 +1509,23 @@ namespace gsr {
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("General"), std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("General"), std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Streaming indicator"), create_indicator(TR("streaming")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); settings_list_ptr->add_widget(std::make_unique<Subsection>(TR("Streaming indicator"), create_indicator(TR("streaming")), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
streaming_service_box_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { streaming_service_box_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
const bool twitch_option = id == "twitch"; const bool twitch_option = id == "twitch";
const bool youtube_option = id == "youtube"; const bool youtube_option = id == "youtube";
const bool rumble_option = id == "rumble"; const bool rumble_option = id == "rumble";
const bool kick_option = id == "kick"; const bool kick_option = id == "kick";
const bool custom_option = id == "custom"; const bool custom_option = id == "custom";
stream_key_list_ptr->set_visible(!custom_option); stream_key_list_ptr->set_visible(!custom_option && !kick_option);
custom_stream_list_ptr->set_visible(custom_option); custom_stream_list_ptr->set_visible(custom_option);
kick_stream_list_ptr->set_visible(kick_option);
twitch_stream_key_entry_ptr->get_parent_widget()->set_visible(twitch_option); twitch_stream_key_entry_ptr->get_parent_widget()->set_visible(twitch_option);
youtube_stream_key_entry_ptr->get_parent_widget()->set_visible(youtube_option); youtube_stream_key_entry_ptr->get_parent_widget()->set_visible(youtube_option);
rumble_stream_key_entry_ptr->get_parent_widget()->set_visible(rumble_option); rumble_stream_key_entry_ptr->get_parent_widget()->set_visible(rumble_option);
kick_stream_url_entry_ptr->get_parent_widget()->set_visible(kick_option);
kick_stream_key_entry_ptr->get_parent_widget()->set_visible(kick_option);
return true; return true;
}; };
streaming_service_box_ptr->on_selection_changed("Twitch", "twitch"); streaming_service_box_ptr->on_selection_changed("Twitch", "twitch");
view_radio_button_ptr->on_selection_changed = [this](const std::string&, const std::string &id) { view_radio_button_ptr->on_selection_changed = [this](std::string_view, std::string_view id) {
view_changed(id == "advanced"); view_changed(id == "advanced");
return true; return true;
}; };
@@ -1715,17 +1758,17 @@ namespace gsr {
switch(audio_track_type) { switch(audio_track_type) {
case AudioTrackType::DEVICE: { case AudioTrackType::DEVICE: {
ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1));
audio_tracks.back().audio_inputs.push_back("device:" + audio_device_box->get_selected_id()); audio_tracks.back().audio_inputs.push_back("device:" + std::string(audio_device_box->get_selected_id()));
break; break;
} }
case AudioTrackType::APPLICATION: { case AudioTrackType::APPLICATION: {
ComboBox *application_audio_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1)); ComboBox *application_audio_box = dynamic_cast<ComboBox*>(audio_track_line->get_child_widget_by_index(1));
audio_tracks.back().audio_inputs.push_back("app:" + application_audio_box->get_selected_id()); audio_tracks.back().audio_inputs.push_back("app:" + std::string(application_audio_box->get_selected_id()));
break; break;
} }
case AudioTrackType::APPLICATION_CUSTOM: { case AudioTrackType::APPLICATION_CUSTOM: {
Entry *application_audio_entry = dynamic_cast<Entry*>(audio_track_line->get_child_widget_by_index(1)); Entry *application_audio_entry = dynamic_cast<Entry*>(audio_track_line->get_child_widget_by_index(1));
audio_tracks.back().audio_inputs.push_back("app:" + application_audio_entry->get_text()); audio_tracks.back().audio_inputs.push_back("app:" + std::string(application_audio_entry->get_text()));
break; break;
} }
} }
@@ -1737,13 +1780,14 @@ namespace gsr {
} }
void SettingsPage::save_common(RecordOptions &record_options) { void SettingsPage::save_common(RecordOptions &record_options) {
std::stoi("23");
record_options.record_area_option = record_area_box_ptr->get_selected_id(); record_options.record_area_option = record_area_box_ptr->get_selected_id();
record_options.record_area_width = atoi(area_width_entry_ptr->get_text().c_str()); record_options.record_area_width = sv_to_int<int32_t>(area_width_entry_ptr->get_text());
record_options.record_area_height = atoi(area_height_entry_ptr->get_text().c_str()); record_options.record_area_height = sv_to_int<int32_t>(area_height_entry_ptr->get_text());
record_options.video_width = atoi(video_width_entry_ptr->get_text().c_str()); record_options.video_width = sv_to_int<int32_t>(video_width_entry_ptr->get_text());
record_options.video_height = atoi(video_height_entry_ptr->get_text().c_str()); record_options.video_height = sv_to_int<int32_t>(video_height_entry_ptr->get_text());
record_options.fps = atoi(framerate_entry_ptr->get_text().c_str()); record_options.fps = sv_to_int<int32_t>(framerate_entry_ptr->get_text());
record_options.video_bitrate = atoi(video_bitrate_entry_ptr->get_text().c_str()); record_options.video_bitrate = sv_to_int<int32_t>(video_bitrate_entry_ptr->get_text());
record_options.change_video_resolution = change_video_resolution_checkbox_ptr->is_checked(); record_options.change_video_resolution = change_video_resolution_checkbox_ptr->is_checked();
save_audio_tracks(record_options.audio_tracks_list, audio_track_section_list_ptr); save_audio_tracks(record_options.audio_tracks_list, audio_track_section_list_ptr);
record_options.color_range = color_range_box_ptr->get_selected_id(); record_options.color_range = color_range_box_ptr->get_selected_id();
@@ -1823,7 +1867,7 @@ namespace gsr {
config.replay_config.restart_replay_on_save = restart_replay_on_save->is_checked(); config.replay_config.restart_replay_on_save = restart_replay_on_save->is_checked();
config.replay_config.save_directory = save_directory_button_ptr->get_text(); config.replay_config.save_directory = save_directory_button_ptr->get_text();
config.replay_config.container = container_box_ptr->get_selected_id(); config.replay_config.container = container_box_ptr->get_selected_id();
config.replay_config.replay_time = atoi(replay_time_entry_ptr->get_text().c_str()); config.replay_config.replay_time = sv_to_int<int32_t>(replay_time_entry_ptr->get_text());
config.replay_config.replay_storage = replay_storage_button_ptr->get_selected_id(); config.replay_config.replay_storage = replay_storage_button_ptr->get_selected_id();
if(config.replay_config.replay_time < 5) { if(config.replay_config.replay_time < 5) {

View File

@@ -12,7 +12,7 @@ namespace gsr {
static const float title_spacing_scale = 0.010f; static const float title_spacing_scale = 0.010f;
Subsection::Subsection(const char *title, std::unique_ptr<Widget> inner_widget, mgl::vec2f size) : Subsection::Subsection(const char *title, std::unique_ptr<Widget> inner_widget, mgl::vec2f size) :
label(&get_theme().title_font, title ? title : "", get_color_theme().text_color), label(get_theme().title_font_desc.c_str(), title ? title : "", get_color_theme().text_color),
inner_widget(std::move(inner_widget)), inner_widget(std::move(inner_widget)),
size(size) size(size)
{ {

View File

@@ -12,7 +12,7 @@ namespace gsr {
static const float padding_right_scale = 0.008f; static const float padding_right_scale = 0.008f;
static const float accent_scale = 0.0025f; static const float accent_scale = 0.0025f;
Tooltip::Tooltip(mgl::Font *font) : label("", *font) {} Tooltip::Tooltip(const char *font_desc) : label("", font_desc) {}
bool Tooltip::on_event(mgl::Event&, mgl::Window&, mgl::vec2f) { bool Tooltip::on_event(mgl::Event&, mgl::Window&, mgl::vec2f) {
return true; return true;
@@ -27,7 +27,7 @@ namespace gsr {
const int padding_top = get_theme().window_height * padding_top_scale; const int padding_top = get_theme().window_height * padding_top_scale;
const int padding_left = get_theme().window_height * padding_left_scale; const int padding_left = get_theme().window_height * padding_left_scale;
const int accent_height = get_theme().window_height * accent_scale; const int accent_height = get_theme().window_height * accent_scale;
const int icon_height = label.get_font()->get_character_size(); const int icon_height = label.get_font_size()*2.0f;
mgl::Rectangle background(get_size()); mgl::Rectangle background(get_size());
background.set_position(draw_pos - mgl::vec2f(0.0f, background.get_size().y)); background.set_position(draw_pos - mgl::vec2f(0.0f, background.get_size().y));
@@ -56,12 +56,12 @@ namespace gsr {
const int padding_right = get_theme().window_height * padding_right_scale; const int padding_right = get_theme().window_height * padding_right_scale;
const int accent_height = get_theme().window_height * accent_scale; const int accent_height = get_theme().window_height * accent_scale;
const mgl::vec2f text_size = label.get_bounds().size.floor(); const mgl::vec2f text_size = label.get_bounds().size.floor();
const int icon_height = label.get_font()->get_character_size(); const int icon_height = label.get_font_size()*2.0f;
return mgl::vec2f(padding_left + text_size.x + padding_right, accent_height + padding_top + icon_height + text_size.y + padding_bottom).floor(); return mgl::vec2f(padding_left + text_size.x + padding_right, accent_height + padding_top + icon_height + text_size.y + padding_bottom).floor();
} }
void Tooltip::set_text(std::string text) { void Tooltip::set_text(std::string_view text) {
label.set_string(std::move(text)); label.set_string(text);
} }
} }

View File

@@ -128,7 +128,7 @@ namespace gsr {
if(widget && !widget->get_tooltip_text().empty()) { if(widget && !widget->get_tooltip_text().empty()) {
current_tooltip_widget = widget; current_tooltip_widget = widget;
if(!tooltip) if(!tooltip)
tooltip = std::make_unique<Tooltip>(&get_theme().body_font); tooltip = std::make_unique<Tooltip>(get_theme().body_font_desc.c_str());
tooltip->set_text(current_tooltip_widget->get_tooltip_text()); tooltip->set_text(current_tooltip_widget->get_tooltip_text());
} else { } else {
current_tooltip_widget = nullptr; current_tooltip_widget = nullptr;