rpcsx/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h

222 lines
6.4 KiB
C++

#pragma once
#include "Emu/RSX/Overlays/overlays.h"
#include "Utilities/Config.h"
namespace rsx
{
namespace overlays
{
static constexpr u16 menu_entry_height = 40;
static constexpr u16 menu_entry_margin = 20;
static constexpr u16 available_side_width = (overlay::virtual_width - 6 * menu_entry_margin) / 2;
static constexpr u16 element_height = 25;
enum class page_navigation
{
stay,
back,
next,
exit
};
struct home_menu_entry : horizontal_layout
{
public:
home_menu_entry(const std::string& text);
};
template <typename T, typename C>
struct home_menu_setting : horizontal_layout
{
public:
home_menu_setting(C* setting, const std::string& text) : m_setting(setting)
{
std::unique_ptr<overlay_element> layout = std::make_unique<vertical_layout>();
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
std::unique_ptr<overlay_element> title = std::make_unique<label>(text);
padding->set_size(1, 1);
title->set_size(available_side_width, menu_entry_height);
title->set_font("Arial", 16);
title->set_wrap_text(true);
title->align_text(text_align::right);
// Make back color transparent for text
title->back_color.a = 0.f;
static_cast<vertical_layout*>(layout.get())->pack_padding = 5;
static_cast<vertical_layout*>(layout.get())->add_element(padding);
static_cast<vertical_layout*>(layout.get())->add_element(title);
// Pack
this->pack_padding = 15;
add_element(layout);
update_value(true);
}
void update_value(bool initializing = false)
{
if (m_setting)
{
if (const T new_value = m_setting->get(); new_value != m_last_value || initializing)
{
m_last_value = new_value;
is_compiled = false;
}
}
}
protected:
T m_last_value = {};
C* m_setting = nullptr;
};
struct home_menu_checkbox : public home_menu_setting<bool, cfg::_bool>
{
public:
home_menu_checkbox(cfg::_bool* setting, const std::string& text);
compiled_resource& get_compiled() override;
private:
overlay_element m_background;
overlay_element m_checkbox;
};
template <typename T>
struct home_menu_dropdown : public home_menu_setting<T, cfg::_enum<T>>
{
public:
home_menu_dropdown(cfg::_enum<T>* setting, const std::string& text) : home_menu_setting<T, cfg::_enum<T>>(setting, text)
{
m_dropdown.set_size(available_side_width / 2, element_height);
m_dropdown.set_pos(overlay::virtual_width / 2 + menu_entry_margin, 0);
m_dropdown.set_font("Arial", 14);
m_dropdown.align_text(home_menu_dropdown<T>::text_align::center);
m_dropdown.back_color = { 0.3f, 0.3f, 0.3f, 1.0f };
}
compiled_resource& get_compiled() override
{
this->update_value();
if (!this->is_compiled)
{
m_dropdown.set_text(fmt::format("%s", this->m_last_value));
m_dropdown.set_pos(m_dropdown.x, this->y + (this->h - m_dropdown.h) / 2);
this->compiled_resources = horizontal_layout::get_compiled();
this->compiled_resources.add(m_dropdown.get_compiled());
}
return this->compiled_resources;
}
private:
label m_dropdown;
};
template <typename T, typename C>
struct home_menu_slider : public home_menu_setting<T, C>
{
public:
home_menu_slider(C* setting, const std::string& text, const std::string& suffix, std::map<T, std::string> special_labels = {}, T minimum = C::min, T maximum = C::max)
: home_menu_setting<T, C>(setting, text)
, m_suffix(suffix)
, m_special_labels(std::move(special_labels))
, m_minimum(minimum)
, m_maximum(maximum)
{
m_slider.set_size(available_side_width / 2, element_height);
m_slider.set_pos(overlay::virtual_width / 2 + menu_entry_margin, 0);
m_slider.back_color = { 0.3f, 0.3f, 0.3f, 1.0f };
m_handle.set_size(element_height / 2, element_height);
m_handle.set_pos(m_slider.x, 0);
m_handle.back_color = { 1.0f, 1.0f, 1.0f, 1.0f };
m_value_label.back_color = m_slider.back_color;
m_value_label.set_font("Arial", 14);
}
compiled_resource& get_compiled() override
{
this->update_value();
if (!this->is_compiled)
{
const f64 percentage = std::clamp((this->m_last_value - static_cast<T>(m_minimum)) / std::fabs(m_maximum - m_minimum), 0.0, 1.0);
m_slider.set_pos(m_slider.x, this->y + (this->h - m_slider.h) / 2);
m_handle.set_pos(m_slider.x + static_cast<u16>(percentage * (m_slider.w - m_handle.w)), this->y + (this->h - m_handle.h) / 2);
const auto set_label_text = [this]() -> void
{
if (const auto it = m_special_labels.find(this->m_last_value); it != m_special_labels.cend())
{
m_value_label.set_text(it->second);
return;
}
if constexpr (std::is_floating_point<T>::value)
{
m_value_label.set_text(fmt::format("%.2f%s", this->m_last_value, m_suffix));
}
else
{
m_value_label.set_text(fmt::format("%d%s", this->m_last_value, m_suffix));
}
};
set_label_text();
m_value_label.auto_resize();
constexpr u16 handle_margin = 10;
if ((m_handle.x - m_slider.x) > (m_slider.w - (m_handle.w + 2 * handle_margin + m_value_label.w)))
{
m_value_label.set_pos(m_handle.x - (handle_margin + m_value_label.w), m_handle.y);
}
else
{
m_value_label.set_pos(m_handle.x + m_handle.w + handle_margin, m_handle.y);
}
this->compiled_resources = horizontal_layout::get_compiled();
this->compiled_resources.add(m_slider.get_compiled());
this->compiled_resources.add(m_handle.get_compiled());
this->compiled_resources.add(m_value_label.get_compiled());
}
return this->compiled_resources;
}
private:
overlay_element m_slider;
overlay_element m_handle;
label m_value_label;
std::string m_suffix;
std::map<T, std::string> m_special_labels;
T m_minimum{};
T m_maximum{};
};
template <s64 Min, s64 Max>
struct home_menu_signed_slider : public home_menu_slider<s64, cfg::_int<Min, Max>>
{
using home_menu_slider<s64, cfg::_int<Min, Max>>::home_menu_slider;
};
template <u64 Min, u64 Max>
struct home_menu_unsigned_slider : public home_menu_slider<u64, cfg::uint<Min, Max>>
{
using home_menu_slider<u64, cfg::uint<Min, Max>>::home_menu_slider;
};
template <s32 Min, s32 Max>
struct home_menu_float_slider : public home_menu_slider<f64, cfg::_float<Min, Max>>
{
using home_menu_slider<f64, cfg::_float<Min, Max>>::home_menu_slider;
};
}
}