Add tooltip for 'record in low-power mode'

This commit is contained in:
dec05eba
2026-01-18 15:25:49 +01:00
parent 74bb6f0070
commit 86424607b7
16 changed files with 225 additions and 8 deletions

BIN
images/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/question_mark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/warning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -47,6 +47,9 @@ namespace gsr {
mgl::Texture trash_texture;
mgl::Texture masked_texture;
mgl::Texture unmasked_texture;
mgl::Texture warning_texture;
mgl::Texture info_texture;
mgl::Texture question_mark_texture;
mgl::Texture ps4_home_texture;
mgl::Texture ps4_options_texture;

View File

@@ -3,6 +3,7 @@
#include "Widget.hpp"
#include <mglpp/graphics/Sprite.hpp>
#include <functional>
namespace gsr {
class Image : public Widget {
@@ -21,6 +22,8 @@ namespace gsr {
void draw(mgl::Window &window, mgl::vec2f offset) override;
mgl::vec2f get_size() override;
std::function<void(bool inside)> on_mouse_move;
private:
mgl::Sprite sprite;
mgl::vec2f size;

View File

@@ -129,7 +129,7 @@ namespace gsr {
std::unique_ptr<CheckBox> create_led_indicator(const char *type);
std::unique_ptr<CheckBox> create_notifications(const char *type);
std::unique_ptr<List> create_indicator(const char *type);
std::unique_ptr<CheckBox> create_low_power_mode_checkbox();
std::unique_ptr<Widget> create_low_power_mode();
void add_replay_widgets();
void add_record_widgets();

22
include/gui/Tooltip.hpp Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "Widget.hpp"
#include <mglpp/graphics/Text.hpp>
namespace gsr {
class Tooltip : public Widget {
public:
Tooltip(mgl::Font *font);
Tooltip(const Tooltip&) = delete;
Tooltip& operator=(const Tooltip&) = delete;
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
void draw(mgl::Window &window, mgl::vec2f offset) override;
mgl::vec2f get_size() override;
void set_text(std::string text);
private:
mgl::Text label;
};
}

View File

@@ -2,6 +2,7 @@
#include <mglpp/system/vec.hpp>
#include <memory>
#include <string>
namespace mgl {
class Event;
@@ -44,9 +45,14 @@ namespace gsr {
Alignment get_vertical_alignment() const;
void set_visible(bool visible);
bool is_visible() const;
Widget* get_parent_widget();
void set_tooltip_text(std::string text);
const std::string& get_tooltip_text() const;
void handle_tooltip_event(mgl::Event &event, mgl::vec2f position, mgl::vec2f size);
void *userdata = nullptr;
protected:
void set_widget_as_selected_in_parent();
@@ -61,8 +67,13 @@ namespace gsr {
Alignment vertical_aligment = Alignment::START;
bool visible = true;
std::string tooltip_text;
};
void add_widget_to_remove(std::unique_ptr<Widget> widget);
void remove_widgets_to_be_removed();
void set_current_tooltip(Widget *widget);
void remove_as_current_tooltip(Widget *widget);
void draw_tooltip(mgl::Window &window);
}

View File

@@ -34,6 +34,7 @@ src = [
'src/gui/GlobalSettingsPage.cpp',
'src/gui/GsrPage.cpp',
'src/gui/Subsection.cpp',
'src/gui/Tooltip.cpp',
'src/GlobalHotkeys/GlobalHotkeysX11.cpp',
'src/GlobalHotkeys/GlobalHotkeysLinux.cpp',
'src/GlobalHotkeys/GlobalHotkeysJoystick.cpp',

View File

@@ -879,6 +879,7 @@ namespace gsr {
close_button_widget.draw(*window, mgl::vec2f(0.0f, 0.0f));
page_stack.draw(*window, mgl::vec2f(0.0f, 0.0f));
draw_tooltip(*window);
if(cursor_texture.is_valid()) {
cursor_sprite.set_position((window->get_mouse_position() - cursor_hotspot).to_vec2f());

View File

@@ -129,6 +129,15 @@ namespace gsr {
if(!theme->unmasked_texture.load_from_file((resources_path + "images/unmasked.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error;
if(!theme->warning_texture.load_from_file((resources_path + "images/warning.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error;
if(!theme->question_mark_texture.load_from_file((resources_path + "images/question_mark.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error;
if(!theme->info_texture.load_from_file((resources_path + "images/info.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error;
if(!theme->ps4_home_texture.load_from_file((resources_path + "images/ps4_home.png").c_str(), mgl::Texture::LoadOptions{false, false, MGL_TEXTURE_SCALE_LINEAR_MIPMAP}))
goto error;

View File

@@ -40,6 +40,8 @@ namespace gsr {
if(!visible)
return true;
handle_tooltip_event(event, position + offset, get_size());
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
const bool clicked_inside = mgl::FloatRect(position + offset, get_size()).contains({ (float)event.mouse_button.x, (float)event.mouse_button.y });
if(clicked_inside) {

View File

@@ -2,6 +2,8 @@
#include "../../include/gui/Utils.hpp"
#include <mglpp/window/Window.hpp>
#include <mglpp/window/Event.hpp>
#include <mglpp/system/FloatRect.hpp>
#include <mglpp/graphics/Texture.hpp>
namespace gsr {
@@ -19,8 +21,15 @@ namespace gsr {
if(!visible)
return;
const mgl::vec2f draw_pos = (position + offset).floor();
if(on_mouse_move) {
const bool mouse_inside = mgl::FloatRect(draw_pos, get_size()).contains(window.get_mouse_position().to_vec2f());
on_mouse_move(mouse_inside);
}
sprite.set_size(get_size());
sprite.set_position((position + offset).floor());
sprite.set_position(draw_pos);
window.draw(sprite);
}

View File

@@ -5,6 +5,7 @@
#include "../../include/gui/FileChooser.hpp"
#include "../../include/gui/Subsection.hpp"
#include "../../include/gui/CustomRendererWidget.hpp"
#include "../../include/gui/Image.hpp"
#include "../../include/gui/Utils.hpp"
#include "../../include/Theme.hpp"
#include "../../include/GsrInfo.hpp"
@@ -1095,12 +1096,31 @@ namespace gsr {
return list;
}
std::unique_ptr<CheckBox> SettingsPage::create_low_power_mode_checkbox() {
// TODO: Show hint that states: May affect recording performance, recommended to use with sync to content frame rate mode
std::unique_ptr<Widget> SettingsPage::create_low_power_mode() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL);
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record in low-power mode");
checkbox->set_visible(gsr_info->gpu_info.vendor == GpuVendor::AMD);
low_power_mode_checkbox_ptr = checkbox.get();
return checkbox;
list->add_widget(std::move(checkbox));
auto info = std::make_unique<Image>(&get_theme().question_mark_texture, low_power_mode_checkbox_ptr->get_size(), Image::ScaleBehavior::SCALE);
info->set_tooltip_text(
"Do not force the GPU to go into high performance mode when recording.\n"
"May affect recording performance, especially when playing a video at the same time.\n"
"If enabled then it's recommended to use sync to content frame rate mode to reduce power usage when idle."
);
Image *info_ptr = info.get();
info->on_mouse_move = [info_ptr](bool inside) {
if(inside)
set_current_tooltip(info_ptr);
else
remove_as_current_tooltip(info_ptr);
};
list->add_widget(std::move(info));
return list;
}
void SettingsPage::add_replay_widgets() {
@@ -1118,7 +1138,7 @@ namespace gsr {
general_list->add_widget(create_save_replay_in_game_folder());
if(gsr_info->system_info.gsr_version >= GsrVersion{5, 0, 3})
general_list->add_widget(create_restart_replay_on_save());
general_list->add_widget(create_low_power_mode_checkbox());
general_list->add_widget(create_low_power_mode());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>("Replay indicator", create_indicator("replay"), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
@@ -1175,7 +1195,7 @@ namespace gsr {
auto general_list = std::make_unique<List>(List::Orientation::VERTICAL);
general_list->add_widget(create_save_recording_in_game_folder());
general_list->add_widget(create_low_power_mode_checkbox());
general_list->add_widget(create_low_power_mode());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>("Recording indicator", create_indicator("recording"), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
@@ -1305,7 +1325,7 @@ namespace gsr {
settings_list_ptr->add_widget(std::make_unique<Subsection>("Streaming info", std::move(streaming_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto general_list = std::make_unique<List>(List::Orientation::VERTICAL);
general_list->add_widget(create_low_power_mode_checkbox());
general_list->add_widget(create_low_power_mode());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
settings_list_ptr->add_widget(std::make_unique<Subsection>("Streaming indicator", create_indicator("streaming"), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));

67
src/gui/Tooltip.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include "../../include/gui/Tooltip.hpp"
#include "../../include/Theme.hpp"
#include <mglpp/graphics/Rectangle.hpp>
#include <mglpp/graphics/Sprite.hpp>
#include <mglpp/window/Window.hpp>
namespace gsr {
static const float padding_top_scale = 0.008f;
static const float padding_bottom_scale = 0.008f;
static const float padding_left_scale = 0.008f;
static const float padding_right_scale = 0.008f;
static const float accent_scale = 0.0025f;
Tooltip::Tooltip(mgl::Font *font) : label("", *font) {}
bool Tooltip::on_event(mgl::Event&, mgl::Window&, mgl::vec2f) {
return true;
}
void Tooltip::draw(mgl::Window &window, mgl::vec2f offset) {
if(!visible)
return;
const mgl::vec2f draw_pos = (window.get_mouse_position().to_vec2f() + offset).floor();
const int padding_top = get_theme().window_height * padding_top_scale;
const int padding_left = get_theme().window_height * padding_left_scale;
const int accent_height = get_theme().window_height * accent_scale;
const int icon_height = label.get_font()->get_character_size();
mgl::Rectangle background(get_size());
background.set_position(draw_pos - mgl::vec2f(0.0f, background.get_size().y));
background.set_color(mgl::Color(0, 0, 0));
window.draw(background);
mgl::Rectangle accent(background.get_position(), mgl::vec2f(background.get_size().x, accent_height).floor());
accent.set_color(get_color_theme().tint_color);
window.draw(accent);
mgl::Sprite icon_sprite(&get_theme().info_texture, background.get_position() + mgl::vec2f(padding_left, accent_height + padding_top).floor());
icon_sprite.set_height(icon_height);
window.draw(icon_sprite);
label.set_position(background.get_position() + mgl::vec2f(padding_left, accent_height + padding_top + icon_sprite.get_size().y).floor());
window.draw(label);
}
mgl::vec2f Tooltip::get_size() {
if(!visible)
return {0.0f, 0.0f};
const int padding_top = get_theme().window_height * padding_top_scale;
const int padding_bottom = get_theme().window_height * padding_bottom_scale;
const int padding_left = get_theme().window_height * padding_left_scale;
const int padding_right = get_theme().window_height * padding_right_scale;
const int accent_height = get_theme().window_height * accent_scale;
const mgl::vec2f text_size = label.get_bounds().size.floor();
const int icon_height = label.get_font()->get_character_size();
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) {
label.set_string(std::move(text));
}
}

View File

@@ -1,8 +1,16 @@
#include "../../include/gui/Widget.hpp"
#include "../../include/gui/Tooltip.hpp"
#include "../../include/Theme.hpp"
#include <vector>
#include <mglpp/window/Event.hpp>
namespace gsr {
static std::vector<std::unique_ptr<Widget>> widgets_to_remove;
static Widget *current_tooltip_widget = nullptr;
static std::unique_ptr<Tooltip> tooltip;
static void set_current_tooltip_text(Widget *widget);
Widget::Widget() {
@@ -10,6 +18,7 @@ namespace gsr {
Widget::~Widget() {
remove_widget_as_selected_in_parent();
remove_as_current_tooltip(this);
}
void Widget::set_position(mgl::vec2f position) {
@@ -64,10 +73,34 @@ namespace gsr {
this->visible = visible;
}
bool Widget::is_visible() const {
return visible;
}
Widget* Widget::get_parent_widget() {
return parent_widget;
}
void Widget::set_tooltip_text(std::string text) {
tooltip_text = std::move(text);
if(current_tooltip_widget == this)
set_current_tooltip_text(current_tooltip_widget);
}
const std::string& Widget::get_tooltip_text() const {
return tooltip_text;
}
void Widget::handle_tooltip_event(mgl::Event &event, mgl::vec2f position, mgl::vec2f size) {
if(event.type == mgl::Event::MouseMoved) {
if(mgl::FloatRect(position, size).contains(mgl::vec2f(event.mouse_move.x, event.mouse_move.y))) {
set_current_tooltip(this);
} else {
remove_as_current_tooltip(this);
}
}
}
void add_widget_to_remove(std::unique_ptr<Widget> widget) {
widgets_to_remove.push_back(std::move(widget));
}
@@ -78,4 +111,40 @@ namespace gsr {
}
widgets_to_remove.clear();
}
void set_current_tooltip(Widget *widget) {
if(current_tooltip_widget == widget)
return;
set_current_tooltip_text(widget);
}
void remove_as_current_tooltip(Widget *widget) {
if(current_tooltip_widget == widget)
set_current_tooltip_text(nullptr);
}
void set_current_tooltip_text(Widget *widget) {
if(widget && !widget->get_tooltip_text().empty()) {
current_tooltip_widget = widget;
if(!tooltip)
tooltip = std::make_unique<Tooltip>(&get_theme().body_font);
tooltip->set_text(current_tooltip_widget->get_tooltip_text());
} else {
current_tooltip_widget = nullptr;
tooltip.reset();
}
}
void draw_tooltip(mgl::Window &window) {
if(!tooltip)
return;
if(!current_tooltip_widget->is_visible()) {
set_current_tooltip(nullptr);
return;
}
tooltip->draw(window, mgl::vec2f(0.0f, 0.0f));
}
}