1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
#pragma once
#include <cstdint>
#include <type_traits>
#include <any>
#include <ranges>
#include <algorithm>
#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 <typename T>
T clampOptional(T const& value, std::optional<T> const& min, std::optional<T> const& max) {
return std::clamp(value, min.value_or(std::numeric_limits<T>::min()), max.value_or(std::numeric_limits<T>::max()));
}
template <typename T, bool Extended = std::is_same_v<T, bool> || std::is_same_v<T, Config::INTEGER> || std::is_same_v<T, Config::FLOAT>>
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<T> const& min, std::optional<T> const& max = std::nullopt) : m_defaultValue{value}, m_minValue{min}, m_maxValue{max} {}
COverridableVar(std::string const& value)
requires(Extended && !std::is_same_v<T, bool>)
: m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
COverridableVar(std::string const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt)
requires(Extended && !std::is_same_v<T, bool>)
: m_minValue(min), m_maxValue(max), m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
COverridableVar() = default;
~COverridableVar() = default;
COverridableVar& operator=(COverridableVar<T> 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<T, bool>)
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<T, bool>)
{
if (hasValue())
return value();
else if (m_defaultValue.has_value())
return m_defaultValue.value();
else
return **std::any_cast<SP<CConfigValue<T>>>(m_configValue);
}
T valueOrDefault() const
requires(!Extended || std::is_same_v<T, bool>)
{
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<eOverridePriority>(i);
}
throw std::bad_optional_access();
}
void increment(T const& other, eOverridePriority priority) {
if constexpr (std::is_same_v<T, bool>)
m_values[priority] = valueOr(false) ^ other;
else
m_values[priority] = clampOptional(valueOrDefault() + other, m_minValue, m_maxValue);
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
m_values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::array<std::optional<T>, PRIORITY_END> m_values;
std::optional<T> m_defaultValue; // used for toggling, so required for bool
std::optional<T> m_minValue;
std::optional<T> m_maxValue;
std::any m_configValue; // only there for select variables
};
}
|