CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
attributes.cppm
Go to the documentation of this file.
1// Copyright (c) 2024, Víctor Castillo Agüero.
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4module;
5#include <cairomm-1.16/cairomm/cairomm.h>
6
8
9import std;
10export import quantify;
11
13
14export
15namespace vg {
21 };
23 struct base_i {
24 virtual ~base_i() = default;
25 virtual void apply_to_source(pixelmap_editor_t& editor, double opacity) const = 0;
26 virtual color::Color sample(int x, int y) const = 0;
28 virtual base_i* make_copy() const = 0;
30 virtual paint_type_e get_type() const = 0;
32 virtual bool operator==(const base_i& rhl) const = 0;
33 };
35 struct solid: public base_i {
36 color::Color c = "#00000000"_color;
38 solid() = default;
40 : c(_c) {}
42 void apply_to_source(pixelmap_editor_t& editor, double opacity) const override {
43 editor->set_source_rgba(c.r, c.g, c.b, c.a * opacity);
44 }
46 color::Color sample(int x, int y) const override {
47 return c;
48 }
49
50 [[nodiscard]]
51 base_i* make_copy() const override {
52 return new solid{*this};
53 }
55 paint_type_e get_type() const override {
56 return SOLID;
57 }
59 bool operator==(const base_i& rhl) const override {
60 if (rhl.get_type() != get_type())
61 return false;
62 return c == ((const solid*)&rhl)->c;
63 }
64 };
66 namespace gradient {
67 struct base_i: public paint::base_i {
68 std::vector<Cairo::ColorStop> color_stops{};
69 int x0, y0;
70 int x1, y1;
71 };
73 struct linear: public gradient::base_i {
74 linear(
75 std::pair<int, int> start,
76 std::pair<int, int> end,
77 const std::vector<std::pair<double, color::Color>>& _color_stops
78 ) {
79 x0 = start.first;
80 y0 = start.second;
81 x1 = end.first;
82 y1 = end.second;
83 for (auto& item: _color_stops) {
84 color_stops.push_back({
85 .offset = item.first,
86 .red = item.second.r,
87 .green = item.second.g,
88 .blue = item.second.b,
89 .alpha = item.second.a,
90 });
91 }
92 }
94 void apply_to_source(pixelmap_editor_t& editor, double opacity) const override {
95 auto lg = Cairo::LinearGradient::create(x0, y0, x1, y1);
96 for (auto& item: color_stops) {
97 lg->add_color_stop_rgba(item.offset, item.red, item.green, item.blue, item.alpha);
98 }
99 editor->set_source(lg);
101 color::Color sample(int x, int y) const override {
102 return "#00000000"_color;
103 }
104
105 [[nodiscard]]
106 base_i* make_copy() const override {
107 return new linear{*this};
108 }
110 paint_type_e get_type() const override {
111 return GRADIENT_LINEAR;
112 }
114 bool operator==(const paint::base_i& rhl_) const override {
115 if (rhl_.get_type() != get_type())
116 return false;
117 linear& rhl = *((linear*)&rhl_);
118 return x0 == rhl.x0 && x1 == rhl.x1 && y0 == rhl.y0 && y1 == rhl.y1;
119 }
120 };
121 struct radial: public gradient::base_i {
122 int r0, r1;
124 radial(
125 std::pair<int, int> start,
126 int r0,
127 std::pair<int, int> end,
128 int r1,
129 const std::vector<std::pair<double, color::Color>>& _color_stops
130 ) {
131 x0 = start.first;
132 y0 = start.second;
133 this->r0 = r0;
134 x1 = end.first;
135 y1 = end.second;
136 this->r1 = r1;
137 for (auto& item: _color_stops) {
138 color_stops.push_back({
139 .offset = item.first,
140 .red = item.second.r,
141 .green = item.second.g,
142 .blue = item.second.b,
143 .alpha = item.second.a,
144 });
145 }
146 }
148 void apply_to_source(pixelmap_editor_t& editor, double opacity) const override {
149 auto lg = Cairo::RadialGradient::create(x0, y0, r0, x1, y1, r1);
150 for (auto& item: color_stops) {
151 lg->add_color_stop_rgba(item.offset, item.red, item.green, item.blue, item.alpha);
152 }
153 editor->set_source(lg);
155 color::Color sample(int x, int y) const override {
156 return "#00000000"_color;
157 }
158
159 [[nodiscard]]
160 base_i* make_copy() const override {
161 return new radial{*this};
162 }
164 paint_type_e get_type() const override {
165 return GRADIENT_RADIAL;
166 }
168 bool operator==(const paint::base_i& rhl_) const override {
169 if (rhl_.get_type() != get_type())
170 return false;
171 radial& rhl = *((radial*)&rhl_);
172 return x0 == rhl.x0 && x1 == rhl.x1 && y0 == rhl.y0 && y1 == rhl.y1 && r0 == rhl.r0
173 && r1 == rhl.r1;
174 }
175 };
176 } // namespace gradient
178 namespace pixelmap {
179 struct base_i: public paint::base_i {};
180 } // namespace pixelmap
181
182 // using type = std::variant<
183 // solid,
184 // gradient::linear,
185 // gradient::radial
186 // >;
188 struct type {
189 using enum paint_type_e;
191 std::unique_ptr<base_i> paint_data = std::make_unique<solid>();
193 type(decltype(paint_type) type_, std::unique_ptr<base_i>&& paint_data_)
194 : paint_type(type_),
195 paint_data(std::move(paint_data_)) {}
196
197 template <typename Paint>
198 static type make (Paint paint_data_) {
199 return type{paint_data_.get_type(), std::make_unique<Paint>(paint_data_)};
200 }
202 type(const type& rhl)
203 : paint_type(rhl.paint_type),
204 paint_data(rhl.paint_data->make_copy()) {}
205 type& operator=(const type& rhl) {
206 this->paint_type = rhl.paint_type;
207 auto new_paint_data = std::unique_ptr<base_i>(rhl.paint_data->make_copy());
208 std::swap(this->paint_data, new_paint_data);
209 return *this;
210 };
212 bool operator==(const type& rhl) const {
213 return paint_type == rhl.paint_type && (*paint_data) == (*rhl.paint_data);
214 }
215 };
216 } // namespace paint
218 struct attribute_i {};
220#define VG_ATTRIBUTE(TYPE, NAME, DEFAULT) \
221 template <typename E> \
222 struct attr_##NAME: public attribute_i { \
223 inline E& NAME(TYPE& _##NAME##_) { \
224 this->_##NAME = _##NAME##_; \
225 return *(E*)this; \
226 } \
227 inline E& NAME(TYPE&& _##NAME##_) { \
228 this->_##NAME = _##NAME##_; \
229 return *(E*)this; \
230 } \
231 TYPE _##NAME = DEFAULT; \
232 }
234#define VG_ATTRIBUTE_AUTO(TYPE, NAME, DEFAULT) \
235 template <typename E> \
236 struct attr_##NAME: public attribute_i { \
237 inline E& NAME(auto& _##NAME##_) { \
238 this->_##NAME = _##NAME##_; \
239 return *(E*)this; \
240 } \
241 inline E& NAME(auto&& _##NAME##_) { \
242 this->_##NAME = _##NAME##_; \
243 return *(E*)this; \
244 } \
245 TYPE _##NAME = DEFAULT; \
246 }
248#define VG_ATTRIBUTE_PAINT(NAME) \
249 template <typename E> \
250 struct attr_##NAME: public attribute_i { \
251 inline E& NAME(vg::paint::type& _##NAME##_) { \
252 this->_##NAME = _##NAME##_; \
253 return *(E*)this; \
254 } \
255 inline E& NAME(vg::paint::type&& _##NAME##_) { \
256 this->_##NAME = _##NAME##_; \
257 return *(E*)this; \
258 } \
259 inline E& NAME(vg::paint::solid& _##NAME##_) { \
260 this->_##NAME.paint_data = std::make_unique<vg::paint::solid>(_##NAME##_); \
261 this->_##NAME.paint_type = vg::paint::type::SOLID; \
262 return *(E*)this; \
263 } \
264 inline E& NAME(vg::paint::solid&& _##NAME##_) { \
265 this->_##NAME.paint_data = std::make_unique<vg::paint::solid>(_##NAME##_); \
266 this->_##NAME.paint_type = vg::paint::type::SOLID; \
267 return *(E*)this; \
268 } \
269 inline E& NAME(vg::paint::gradient::linear& _##NAME##_) { \
270 this->_##NAME.paint_data = std::make_unique<vg::paint::gradient::linear>(_##NAME##_); \
271 this->_##NAME.paint_type = vg::paint::type::GRADIENT_LINEAR; \
272 return *(E*)this; \
273 } \
274 inline E& NAME(vg::paint::gradient::linear&& _##NAME##_) { \
275 this->_##NAME.paint_data = std::make_unique<vg::paint::gradient::linear>(_##NAME##_); \
276 this->_##NAME.paint_type = vg::paint::type::GRADIENT_LINEAR; \
277 return *(E*)this; \
278 } \
279 inline E& NAME(vg::paint::gradient::radial& _##NAME##_) { \
280 this->_##NAME.paint_data = std::make_unique<vg::paint::gradient::radial>(_##NAME##_); \
281 this->_##NAME.paint_type = vg::paint::type::GRADIENT_RADIAL; \
282 return *(E*)this; \
283 } \
284 inline E& NAME(vg::paint::gradient::radial&& _##NAME##_) { \
285 this->_##NAME.paint_data = std::make_unique<vg::paint::gradient::radial>(_##NAME##_); \
286 this->_##NAME.paint_type = vg::paint::type::GRADIENT_RADIAL; \
287 return *(E*)this; \
288 } \
289 vg::paint::type _##NAME{vg::paint::type::SOLID, std::make_unique<vg::paint::solid>()}; \
290 }
292#define VG_ATTRIBUTE_DIMENSION(NAME, DEFAULT) \
293 template <typename E> \
294 struct attr_##NAME: public attribute_i { \
295 template <typename UNIT, typename T> \
296 inline E& NAME(const quantify::quantity_t<UNIT, T>& _##NAME##_) { \
297 this->_##NAME = _##NAME##_.value_as_base_unit(); \
298 return *(E*)this; \
299 } \
300 template <typename UNIT, typename T> \
301 inline E& NAME(quantify::quantity_t<UNIT, T>&& _##NAME##_) { \
302 this->_##NAME = _##NAME##_.value_as_base_unit(); \
303 return *(E*)this; \
304 } \
305 inline E& NAME(const int& _##NAME##_) { \
306 this->_##NAME = _##NAME##_; \
307 return *(E*)this; \
308 } \
309 inline E& NAME(int&& _##NAME##_) { \
310 this->_##NAME = _##NAME##_; \
311 return *(E*)this; \
312 } \
313 int _##NAME = DEFAULT; \
314 }
315
317 VG_ATTRIBUTE(std::string, id, " ");
319 VG_ATTRIBUTE(std::vector<std::string>, style_class, std::vector<std::string>{});
320
344 VG_ATTRIBUTE(double, rotate, 0);
350 VG_ATTRIBUTE(double, a1, 0);
352 VG_ATTRIBUTE(double, a2, 0);
354 VG_ATTRIBUTE(double, scale_x, 1);
356 VG_ATTRIBUTE(double, scale_y, 1);
358 using point_list_t = std::vector<std::array<int, 2>>;
361
363 VG_ATTRIBUTE(std::string, path_str, std::string{});
364
369
371 VG_ATTRIBUTE(bool, hidden, 1.0);
373 VG_ATTRIBUTE(float, opacity, 1.0);
374
375 // ?* STROKE ATTRIBUTES
379 VG_ATTRIBUTE(std::valarray<double>, stroke_dasharray, std::valarray<double>{});
381 VG_ATTRIBUTE(double, stroke_dashoffset, 0.0);
382
383 // enum class stroke_linecap_e {
384 // BUTT,
385 // ROUND,
386 // SQUARE,
387 // };
388 using stroke_linecap_e = Cairo::Context::LineCap;
389
391 VG_ATTRIBUTE(stroke_linecap_e, stroke_linecap, stroke_linecap_e::BUTT);
392
393 // enum class stroke_linejoin_e {
394 // ARCS,
395 // BEVEL,
396 // MITER,
397 // MITER_CLIP,
398 // ROUND,
399 // };
400 using stroke_linejoin_e = Cairo::Context::LineJoin;
401
403 VG_ATTRIBUTE(stroke_linejoin_e, stroke_linejoin, stroke_linejoin_e::MITER);
404
408 VG_ATTRIBUTE(float, stroke_opacity, 1.0);
411
412 // ?* TEXT ATTRIBUTES
414 VG_ATTRIBUTE(std::string, font_family, "default");
416 VG_ATTRIBUTE(int, font_size, 12);
417 // brief font-size-adjust
418 // VG_ATTRIBUTE(double, font_size_adjust, 0.0); What is this?
420 VG_ATTRIBUTE(double, font_stretch, 1.0);
422 using font_style_e = Cairo::ToyFontFace::Slant;
424 VG_ATTRIBUTE(font_style_e, font_style, font_style_e::NORMAL);
426 using font_weight_e = Cairo::ToyFontFace::Weight;
428 VG_ATTRIBUTE(font_weight_e, font_weight, font_weight_e::NORMAL);
434 };
435
440 bool underline = false;
441 bool overline = false;
442 bool strike_through = false;
443 };
444
447
448 // ?* COLOR ATTRIBUTES
449 // brief color
453 VG_ATTRIBUTE(double, fill_opacity, 1.0);
455 using fill_rule_e = Cairo::Context::FillRule;
456
458 VG_ATTRIBUTE(fill_rule_e, fill_rule, fill_rule_e::WINDING);
459
460 // ?* CLIP ATTRIBUTES
461 // brief clip-path
462 // brief clip-rule
463 // brief clipPathUnits
464
465 // ? ATTRIBUTE GROUPS
466 template <typename T>
467 struct attrs_stroke: attr_stroke<T>,
475 protected:
476 void apply_stroke(pixelmap_editor_t& editor) const {
477 editor->set_line_width(this->_stroke_width);
478 editor->set_line_cap(this->_stroke_linecap);
479 editor->set_line_join(this->_stroke_linejoin);
480 editor->set_dash(this->_stroke_dasharray, this->_stroke_dashoffset);
481 editor->set_miter_limit(this->_stroke_miterlimit);
482 }
484 void set_source_to_stroke(pixelmap_editor_t& editor) const {
485 this->_stroke.paint_data->apply_to_source(editor, this->_stroke_opacity);
486 }
487
488 [[nodiscard]]
489 color::Color sample_stroke(int x, int y) const {
490 return this->_stroke.paint_data->sample(x, y);
491 }
492 };
493
494 template <typename T>
496 protected:
497 void apply_fill(pixelmap_editor_t& editor) const {
498 editor->set_fill_rule(this->_fill_rule);
499 }
501 void set_source_to_fill(pixelmap_editor_t& editor) const {
502 this->_fill.paint_data->apply_to_source(editor, this->_fill_opacity);
503 }
504
505 [[nodiscard]]
506 color::Color sample_fill(int x, int y) const {
507 return this->_fill.paint_data->sample(x, y);
508 }
509 };
510
511 template <typename T>
512 struct attrs_font: attr_font_family<T>,
517 protected:
518 void apply_font(pixelmap_editor_t& editor) const {
519 // TODO - select_font_face is aparently a 'toy' implementation, shouldn't use it!
520 editor->select_font_face(this->_font_family, this->_font_style, this->_font_weight);
521 editor->set_font_size(this->_font_size);
522 }
523 };
524
525 template <typename T>
526 struct attrs_core:
527 // attr_id<T>,
528 // attr_style_class<T>,
529 attr_hidden<T>,
530 attr_opacity<T> {};
531}
532
533
535
541
542// ? --------------------------------------------------------------------------
546
561
755
#define VG_ATTRIBUTE_PAINT(NAME)
#define VG_ATTRIBUTE_DIMENSION(NAME, DEFAULT)
#define VG_ATTRIBUTE(TYPE, NAME, DEFAULT)
Cairo::Context::FillRule fill_rule_e
Cairo::ToyFontFace::Weight font_weight_e
text_anchor_e
Cairo::Context::LineCap stroke_linecap_e
std::vector< std::array< int, 2 > > point_list_t
Cairo::ToyFontFace::Slant font_style_e
UNUSED.
Cairo::Context::LineJoin stroke_linejoin_e
E & a1(double &_a1_)
E & a2(double &_a2_)
E & cx(const quantify::quantity_t< UNIT, T > &_cx_)
E & cy(const quantify::quantity_t< UNIT, T > &_cy_)
E & fill_opacity(double &_fill_opacity_)
E & fill_rule(fill_rule_e &_fill_rule_)
vg::paint::type _fill
E & fill(vg::paint::type &_fill_)
E & font_family(std::string &_font_family_)
E & font_size(int &_font_size_)
E & font_stretch(double &_font_stretch_)
E & font_style(font_style_e &_font_style_)
E & font_weight(font_weight_e &_font_weight_)
E & h(const quantify::quantity_t< UNIT, T > &_h_)
hidden - replaces display="none" from SVG
E & hidden(bool &_hidden_)
E & opacity(float &_opacity_)
E & path_str(std::string &_path_str_)
E & pivot_x(const quantify::quantity_t< UNIT, T > &_pivot_x_)
E & pivot_y(const quantify::quantity_t< UNIT, T > &_pivot_y_)
E & points(point_list_t &_points_)
E & r(const quantify::quantity_t< UNIT, T > &_r_)
E & rotate(double &_rotate_)
E & rx(const quantify::quantity_t< UNIT, T > &_rx_)
E & ry(const quantify::quantity_t< UNIT, T > &_ry_)
E & scale_x(double &_scale_x_)
E & scale_y(double &_scale_y_)
std::valarray< double > _stroke_dasharray
E & stroke_dasharray(std::valarray< double > &_stroke_dasharray_)
E & stroke_dashoffset(double &_stroke_dashoffset_)
E & stroke_linecap(stroke_linecap_e &_stroke_linecap_)
stroke_linecap_e _stroke_linecap
E & stroke_linejoin(stroke_linejoin_e &_stroke_linejoin_)
stroke_linejoin_e _stroke_linejoin
E & stroke_miterlimit(int &_stroke_miterlimit_)
E & stroke_opacity(float &_stroke_opacity_)
E & stroke_width(const quantify::quantity_t< UNIT, T > &_stroke_width_)
vg::paint::type _stroke
E & stroke(vg::paint::type &_stroke_)
E & style_class(std::vector< std::string > &_style_class_)
E & text_anchor(text_anchor_e &_text_anchor_)
E & text_decoration(text_decoration_t &_text_decoration_)
E & w(const quantify::quantity_t< UNIT, T > &_w_)
E & x1(const quantify::quantity_t< UNIT, T > &_x1_)
E & x2(const quantify::quantity_t< UNIT, T > &_x2_)
E & x(const quantify::quantity_t< UNIT, T > &_x_)
E & y1(const quantify::quantity_t< UNIT, T > &_y1_)
E & y2(const quantify::quantity_t< UNIT, T > &_y2_)
E & y(const quantify::quantity_t< UNIT, T > &_y_)
void apply_fill(pixelmap_editor_t &editor) const
void set_source_to_fill(pixelmap_editor_t &editor) const
color::Color sample_fill(int x, int y) const
void apply_font(pixelmap_editor_t &editor) const
void set_source_to_stroke(pixelmap_editor_t &editor) const
void apply_stroke(pixelmap_editor_t &editor) const
color::Color sample_stroke(int x, int y) const
virtual void apply_to_source(pixelmap_editor_t &editor, double opacity) const =0
virtual color::Color sample(int x, int y) const =0
virtual bool operator==(const base_i &rhl) const =0
virtual paint_type_e get_type() const =0
virtual ~base_i()=default
virtual base_i * make_copy() const =0
std::vector< Cairo::ColorStop > color_stops
bool operator==(const paint::base_i &rhl_) const override
void apply_to_source(pixelmap_editor_t &editor, double opacity) const override
paint_type_e get_type() const override
base_i * make_copy() const override
color::Color sample(int x, int y) const override
linear(std::pair< int, int > start, std::pair< int, int > end, const std::vector< std::pair< double, color::Color > > &_color_stops)
paint_type_e get_type() const override
radial(std::pair< int, int > start, int r0, std::pair< int, int > end, int r1, const std::vector< std::pair< double, color::Color > > &_color_stops)
void apply_to_source(pixelmap_editor_t &editor, double opacity) const override
bool operator==(const paint::base_i &rhl_) const override
color::Color sample(int x, int y) const override
base_i * make_copy() const override
solid(color::Color _c)
bool operator==(const base_i &rhl) const override
paint_type_e get_type() const override
color::Color sample(int x, int y) const override
void apply_to_source(pixelmap_editor_t &editor, double opacity) const override
color::Color c
base_i * make_copy() const override
bool operator==(const type &rhl) const
static type make(Paint paint_data_)
paint_type_e paint_type
type(decltype(paint_type) type_, std::unique_ptr< base_i > &&paint_data_)
type & operator=(const type &rhl)
std::unique_ptr< base_i > paint_data