#pragma once #include #include #include #include #include #include "../../config/ConfigValue.hpp" namespace Desktop::Types { struct SAlphaValue { float alpha = 1.F; bool overridden = false; float applyAlpha(float a) const { if (overridden) return alpha; else return alpha * a; }; }; enum eOverridePriority : uint8_t { PRIORITY_LAYOUT = 0, PRIORITY_WORKSPACE_RULE, PRIORITY_WINDOW_RULE, PRIORITY_SET_PROP, PRIORITY_END, }; template T clampOptional(T const& value, std::optional const& min, std::optional const& max) { return std::clamp(value, min.value_or(std::numeric_limits::min()), max.value_or(std::numeric_limits::max())); } template || std::is_same_v || std::is_same_v> class COverridableVar { public: COverridableVar(T const& value, eOverridePriority priority) { m_values[priority] = value; } COverridableVar(T const& value) : m_defaultValue{value} {} COverridableVar(T const& value, std::optional const& min, std::optional const& max = std::nullopt) : m_defaultValue{value}, m_minValue{min}, m_maxValue{max} {} COverridableVar(std::string const& value) requires(Extended && !std::is_same_v) : m_configValue(SP>(new CConfigValue(value))) {} COverridableVar(std::string const& value, std::optional const& min, std::optional const& max = std::nullopt) requires(Extended && !std::is_same_v) : m_minValue(min), m_maxValue(max), m_configValue(SP>(new CConfigValue(value))) {} COverridableVar() = default; ~COverridableVar() = default; COverridableVar& operator=(COverridableVar const& other) { // Self-assignment check if (this == &other) return *this; for (size_t i = 0; i < PRIORITY_END; ++i) { if constexpr (Extended && !std::is_same_v) m_values[i] = other.m_values[i].has_value() ? clampOptional(*other.m_values[i], m_minValue, m_maxValue) : other.m_values[i]; else if (other.m_values[i].has_value()) m_values[i] = other.m_values[i]; } return *this; } void set(T value, eOverridePriority priority) { m_values[priority] = value; } void unset(eOverridePriority priority) { m_values[priority] = std::nullopt; } bool hasValue() const { return std::ranges::any_of(m_values, [](const auto& e) { return e.has_value(); }); } T value() const { for (const auto& v : m_values | std::ranges::views::reverse) { if (v) return *v; } throw std::bad_optional_access(); } T valueOr(T const& other) const { if (hasValue()) return value(); else return other; } T valueOrDefault() const requires(Extended && !std::is_same_v) { if (hasValue()) return value(); else if (m_defaultValue.has_value()) return m_defaultValue.value(); else return **std::any_cast>>(m_configValue); } T valueOrDefault() const requires(!Extended || std::is_same_v) { if (hasValue()) return value(); else if (!m_defaultValue.has_value()) throw std::bad_optional_access(); else return m_defaultValue.value(); } eOverridePriority getPriority() const { for (int i = PRIORITY_END - 1; i >= 0; --i) { if (m_values[i]) return sc(i); } throw std::bad_optional_access(); } void increment(T const& other, eOverridePriority priority) { if constexpr (std::is_same_v) m_values[priority] = valueOr(false) ^ other; else m_values[priority] = clampOptional(valueOrDefault() + other, m_minValue, m_maxValue); } void matchOptional(std::optional const& optValue, eOverridePriority priority) { if (optValue.has_value()) m_values[priority] = optValue.value(); else unset(priority); } operator std::optional() { if (hasValue()) return value(); else return std::nullopt; } private: std::array, PRIORITY_END> m_values; std::optional m_defaultValue; // used for toggling, so required for bool std::optional m_minValue; std::optional m_maxValue; std::any m_configValue; // only there for select variables }; }