BuGUI
BUtton Grid User Interface
Loading...
Searching...
No Matches
color_converter.hpp
1#pragma once
2#include "color.hpp"
3#include <concepts/device.hpp>
4
5#include <cstdint>
6#include <limits>
7#include <ranges>
8
9namespace bugui
10{
13template <typename Value_t>
14struct base_converter
15{
16 using color_value_t = Value_t;
17
18 ~base_converter() = default;
19
21 virtual void set(const color& color) = 0;
22
25 bool operator== (const color& other) const
26 {
27 return other == original;
28 }
29
31 Value_t get() const { return value; }
33 Value_t get_secondary() const { return secondary; }
35 Value_t get_state() const { return original.get_state(); }
36
39 virtual void clear() = 0;
42 virtual bool is_clear() = 0;
43
44protected:
45 base_converter() = default;
46
47 Value_t value{};
48 Value_t secondary{};
49 color original{};
50};
51
53template <typename T>
55{
56protected:
57 static constexpr auto palette{T::palette()};
58};
59
61template <hex_color_palette T>
63{
64 static consteval auto make_rgb()
65 {
66 using namespace std;
67
68 auto arr{array<pair<std::array<uint8_t, 3>, uint8_t>
69 , T::palette().size()>{}};
70
71 for (const auto& [hex, rgb]
72 : std::views::zip(T::palette(), arr))
73 {
74 rgb.first[0] = hex.first >> 16; // R
75 auto remain{hex.first - ((rgb.first[0] & 0xff) << 16)};
76 rgb.first[1] = remain >> 8; // G
77 rgb.first[2] = remain - ((rgb.first[1] & 0xff) << 8); // B
78 rgb.second = hex.second; // Value
79 }
80
81 return arr;
82 }
83
84protected:
85 static constexpr auto palette{make_rgb()};
86};
87
90template <has_color_palette T, typename Value_t = uint8_t>
91struct color_converter
92 : base_converter<Value_t>
93 , base_palette<T>
94{
95 color_converter() = default;
96
97 void set(const color& color) override
98 {
99 if (this->original == color) return;
100
101 this->original = color;
102 auto c{this->original.get()};
103
104 float factor{static_cast<float>(c[3] / 255)};
105 uint8_t r = c[0] * factor;
106 uint8_t g = c[1] * factor;
107 uint8_t b = c[2] * factor;
108 int min_d{std::numeric_limits<int>::max()};
109
110 if (this->original.get_state() == color::constant)
111 {
112 // adapted from
113 // github.com/ArthurSonzogni/FTXUI/blob/main/src/ftxui/screen/color.cpp
114 // line 114
115 for (const auto& [rgb, val] : this->palette)
116 {
117 auto dr{r - rgb[0]};
118 auto dg{g - rgb[1]};
119 auto db{b - rgb[2]};
120 auto d = dr*dr + dg*dg + db*db;
121 if (d < min_d)
122 {
123 min_d = d;
124 this->value = val;
125 }
126 }
127 }
128 else
129 {
130 auto sc{this->original.get_secondary()};
131
132 float factor{static_cast<float>(sc[3] / 255)};
133 uint8_t sr = sc[0] * factor;
134 uint8_t sg = sc[1] * factor;
135 uint8_t sb = sc[2] * factor;
136 int s_min_d{std::numeric_limits<int>::max()};
137
138 for (const auto& [rgb, val] : this->palette)
139 {
140 auto dr{r - rgb[0]};
141 auto sdr{sr - rgb[0]};
142 auto dg{g - rgb[1]};
143 auto sdg{sg - rgb[1]};
144 auto db{b - rgb[2]};
145 auto sdb{sb - rgb[2]};
146 auto d = dr*dr + dg*dg + db*db;
147 auto sd = sdr*sdr + sdg*sdg + sdb*sdb;
148 if (d < min_d)
149 {
150 min_d = d;
151 this->value = val;
152 }
153 if (sd < s_min_d)
154 {
155 s_min_d = sd;
156 this->secondary = val;
157 }
158 }
159 }
160 }
161
162 void clear() override
163 {
164 this->value = 0;
165 this->original.clear();
166 }
167
168 bool is_clear() override
169 {
170 return this->original.is_clear()
171 && this->value == 0;
172 }
173};
174
176template <typename T>
177 requires (!has_color_palette<T>)
178struct color_converter<T, color::rgba>
179 : base_converter<color::rgba>
180{
181 void set(const color& color) override
182 {
183 original = color;
184 value = original.get();
185 secondary = original.get_secondary();
186 }
187
188 void clear() override
189 {
190 value[0] = 0;
191 value[1] = 0;
192 value[2] = 0;
193 value[3] = 255;
194 original.clear();
195 }
196
197 bool is_clear() override
198 {
199 return original.is_clear()
200 && value[0] == 0
201 && value[1] == 0
202 && value[2] == 0
203 && value[3] == 255;
204 }
205};
206
209template <typename T>
210 requires (!has_color_palette<T>)
211struct color_converter<T, uint8_t>
212 : base_converter<uint8_t>
213{
214 void set(const color& color) override
215 {
216 if (original == color) return;
217
218 original = color;
219 auto c{original.get()};
220
221 float factor{static_cast<float>(c[3] / 255)};
222 uint8_t r = c[0] * factor;
223 uint8_t g = c[1] * factor;
224 uint8_t b = c[2] * factor;
225
226 // according to
227 // goodcalculators.com/rgb-to-grayscale-conversion-calculator
228 value = 0.299 * r + 0.587 * g + 0.114 * b;
229
230 if (original.get_state() == color::constant) return;
231
232 c = original.get_secondary();
233 factor = static_cast<float>(c[3] / 255);
234 r = c[0] * factor;
235 g = c[1] * factor;
236 b = c[2] * factor;
237
238 secondary = 0.299 * r + 0.587 * g + 0.114 * b;
239 }
240
241 void clear() override
242 {
243 value = 0;
244 original.clear();
245 }
246
247 bool is_clear() override
248 {
249 return original.is_clear()
250 && value == 0;
251 }
252};
253
254} // namespace bugui
Provides access to the device's colour palette.
Definition color_converter.hpp:55
Value_t get_state() const
Retrives the current state.
Definition color_converter.hpp:35
Value_t get_secondary() const
Retrives the secondary device specific colour value.
Definition color_converter.hpp:33
virtual bool is_clear()=0
Checks that the original and device specific colour are set to their initial value.
Value_t get() const
Retrives the main device specific colour value.
Definition color_converter.hpp:31
bool operator==(const color &other) const
Determines equality between the original color and another.
Definition color_converter.hpp:25
virtual void clear()=0
Resets the original and the device specific colour to their initial value.
virtual void set(const color &color)=0
Sets the original color.
void clear() override
Resets the original and the device specific colour to their initial value.
Definition color_converter.hpp:188
void set(const color &color) override
Sets the original color.
Definition color_converter.hpp:181
bool is_clear() override
Checks that the original and device specific colour are set to their initial value.
Definition color_converter.hpp:197
void clear() override
Resets the original and the device specific colour to their initial value.
Definition color_converter.hpp:241
bool is_clear() override
Checks that the original and device specific colour are set to their initial value.
Definition color_converter.hpp:247
void set(const color &color) override
Sets the original color.
Definition color_converter.hpp:214
void clear() override
Resets the original and the device specific colour to their initial value.
Definition color_converter.hpp:162
bool is_clear() override
Checks that the original and device specific colour are set to their initial value.
Definition color_converter.hpp:168
void set(const color &color) override
Sets the original color.
Definition color_converter.hpp:97
Generic colour class holding RGBA values of a primary and a secondary colour. The blinking and pulsin...
Definition color.hpp:12
rgba get_secondary() const noexcept
Retrieves the secondary colour as rgba values.
Definition color.hpp:58
@ constant
Primary colour only.
Definition color.hpp:17
rgba get() const noexcept
Retrieves the primary colour as rgba values.
Definition color.hpp:55