Loading...
Searching...
No Matches
AlignSVG.h
1/*
2
3MIT License
4
5Copyright (c) 2023 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31/*
32 * TreeSVG.h
33 *
34 * Created on: Nov, 2024
35 * Author: mpeura
36 */
37
38#ifndef DRAIN_ALIGN_SVG
39#define DRAIN_ALIGN_SVG
40
41#include <drain/Enum.h>
42#include <string>
43
44namespace drain {
45
46namespace image {
47
48
50struct AlignBase {
51
52public:
53
55 enum Pos {
56 UNDEFINED_POS = 0,
57 MIN = 1, // LEFT (if HORZ) or TOP (when VERT) 0b01010101,
58 MAX = 2, // RIGHT (if HORZ) or BOTTOM (when VERT) 0b10101010,
59 MID = 3, // 0b11111111,
60 FILL = 4,
61 // ABSOLUTE?
62 };
63
64 enum Axis {
65 // Index, must contain 0 and 1 for HORZ and VERT
66 HORZ = 0, // 0b00110011,
67 VERT = 1, // b11001100,
68 UNDEFINED_AXIS = 2,
69 };
70
71
73 /*
74 enum Axis {
75 // Index, must contain 0 and 1 for HORZ and VERT
76 UNDEFINED_AXIS = 0,
77 HORZ = 1, // 0b00110011,
78 VERT = 2, // b11001100,
79 };
80 */
81
82 static inline
83 Axis flip(Axis axis){
84 switch (axis){
85 case HORZ:
86 return VERT;
87 case VERT:
88 return HORZ;
89 default:
90 return UNDEFINED_AXIS;
91 }
92 };
93
94 //typedef drain::Enum<Coord>::dict_t pos_dict_t;
95
96 static inline
98 switch (pos){
99 case MAX:
100 return MIN;
101 case MIN:
102 return MAX;
103 case MID:
104 case FILL:
105 case UNDEFINED_POS:
106 default:
107 return pos;
108 }
109 };
110
111};
112
113
114// template <> const drain::Enum<AlignBase::Axis>::dict_t drain::Enum<AlignBase::Axis>::dict;
115DRAIN_ENUM_DICT(AlignBase::Axis);
116DRAIN_ENUM_OSTREAM(AlignBase::Axis);
117
118// template <>const drain::Enum<AlignBase::Pos>::dict_t drain::Enum<AlignBase::Pos>::dict;
119DRAIN_ENUM_DICT(AlignBase::Pos);
120DRAIN_ENUM_OSTREAM(AlignBase::Pos);
121
122
124
135template <typename AX = AlignBase::Axis, AlignBase::Axis A = AlignBase::Axis::UNDEFINED_AXIS> //, typename POS = AlignBase::Pos> // , Align::Coord POS = Align::Coord::UNDEFINED_POS>
136struct Alignment {
137
138 // Align::Axis
139 AX axis; // = V; // compiler error if different type?
140
141 //AlignBase::Pos pos
142 AlignBase::Pos pos = AlignBase::Pos::UNDEFINED_POS; // or middle?
143 //POS pos = AlignBase::Pos::UNDEFINED_POS; // or middle?
144
146 inline
147 Alignment(AlignBase::Pos pos = AlignBase::Pos::UNDEFINED_POS) : axis(A), pos(pos){
148 }
149
151 inline
152 Alignment(const Alignment & ac) : axis(ac.axis), pos(ac.pos){
153 }
154
155
156 inline
157 Alignment(AlignBase::Axis axis, AlignBase::Pos pos = AlignBase::Pos::UNDEFINED_POS): axis(axis), pos(pos){
158 }
159
160 template <typename AX2, AlignBase::Axis A2>
161 inline
162 Alignment(const Alignment<AX2,A2> & align) : pos(align.pos){ // axis(ac.axis),
163 axis = align.axis; // error if const
164 }
165
167 inline virtual
169
170
171 inline
172 const AlignBase::Axis & get(const AlignBase::Axis & defaultValue) const {
173 if (axis != AlignBase::Axis::UNDEFINED_AXIS){
174 return axis;
175 }
176 else {
177 return defaultValue;
178 }
179 }
180
181 inline
182 const AlignBase::Pos & get(const AlignBase::Pos & defaultValue) const {
183 if (pos != AlignBase::Pos::UNDEFINED_POS){
184 return pos;
185 }
186 else {
187 return defaultValue;
188 }
189 }
190
191
192 virtual inline
193 void reset(){
194 axis = AlignBase::Axis::UNDEFINED_AXIS;
195 pos = AlignBase::Pos::UNDEFINED_POS;
196 }
197
198
199 template <typename AX2, AlignBase::Axis A2>
200 inline
201 bool operator==(const Alignment<AX2,A2> & align) const {
202 return (align.axis == axis) && (align.pos == pos);
203 // return compare(ad) == 0;
204 }
205
206
207};
208
209
210
211template <typename AX, AlignBase::Axis V>
212inline
213std::ostream & operator<<(std::ostream &ostr, const Alignment<AX,V> & align){
214 //return ostr << align.axis << '_' << align.pos; // enums resolved above
215 return ostr << align.axis << '_' << align.pos;
216}
217
218
219
220
221//struct Alignment2;
222
224
230struct AlignSVG { // : protected Align {
231
232
233 virtual
234 ~AlignSVG(){};
235
237
239 static
241
243 static
245
247 static
249
251 static
253
254 static
255 const HorzAlign UNDEFINED_HORZ;
256
257 // ----------------------
258
260
262 static
264
266 static
268
270 static
272
274 static
276
277 static
278 const VertAlign UNDEFINED_VERT;
279
280
281 enum Owner {
282 OBJECT = 0, // 0b00001111,
283 ANCHOR = 1, // 0b11110000,
284 };
285
286
287 enum Topol {
288 INSIDE = 0,
289 OUTSIDE = 1,
290 UNDEFINED_TOPOL = 2,
291 };
292
293
295 /*
296 * Notice that for an alignment to be complete, this function should be called twice:
297 * setting partial alignment for both owner=OBJECT and owner=ANCHOR .
298 *
299 * \tparam OBJ - enum type \c Owner or string
300 * \tparam A - enum type \c Axis or string
301 * \tparam V - enum type \c Alignment or string
302 * \param pos - enum value \c OBJ or \c REF
303 * \param axis - enum value \c HORZ or \c VERT
304 * \param value - enum value \c MAX , \c MID , or \c MIN (or string)
305 */
306 template <typename OBJ, typename A, typename V>
307 inline // in problems, rename this function, ie. remove polymorphism
308 void setAlign(const OBJ & owner, const A & axis, const V &value){
309 modifyAlign(owner, axis, value);
310 updateAlign();
311 }
312
314
323 inline
324 void setAlign(const AlignBase::Axis & axis, const AlignBase::Pos & pos, Topol topol=Topol::INSIDE){
325 if (pos != AlignBase::FILL){
326 modifyAlign(ANCHOR, axis, pos);
327 }
328 modifyAlign(OBJECT, axis, (topol==INSIDE) ? pos : AlignBase::flip(pos));
329 updateAlign();
330 }
331
333 /*
334 * Template supports empty arg list.
335 *
336 * \tparam T - enum type \c Topol or string
337 * \tparam AX - axis enum type: Axis or const Axis
338 * \tparam A - axis enum value: HORZ, VERT or UNDEFINED_AXIS
339 * \param align - \c HorzAlign or \c VertAlign
340 */
341 template <typename ...T, typename AX, AlignBase::Axis A>
342 void setAlign(const Alignment<AX,A> & align, const T... args){
343 if (align.pos == AlignBase::FILL){
344 // Makes sense only for OBJECT, as it will be changed (and ANCHOR is never unchanged).
345 setAlign(AlignSVG::OBJECT, align.axis, align.pos);
346 }
347 else {
348 setAlign(align.axis, align.pos, args...);
349 }
350 }
351
352 // Convenience: set both horz and vert alignments (INSIDE)
353 /*
354 */
355 template <typename AX1, AlignBase::Axis A1, typename AX2, AlignBase::Axis A2>
356 void setAlign(const Alignment<AX1,A1> & align1, const Alignment<AX2,A2> & align2){
357 setAlign(align1.axis, align1.pos, AlignSVG::Topol::INSIDE);
358 setAlign(align2.axis, align2.pos, AlignSVG::Topol::INSIDE);
359 }
360
362 template <typename AX, AlignBase::Axis A>
363 void setAlign(const Alignment<AX,A> & align1, const Alignment<AX,A> & align2);
364
365
367 /*
368 * \tparam T - enum type \c Topol or string: \c INSIDE or \c OUTSIDE .
369 * \param align - Horizontal or vertical Alignment: \c LEFT|CENTER|RIGHT or \c TOP|MIDDLE|BOTTOM
370 * \param topol - \c INSIDE or \c OUTSIDE
371 */
372 template <typename T>
373 void setAlign(const std::string & align, const T & topol){
374 const Alignment<> & a = Enum<Alignment<> >::getValue(align, false);
375 const Topol & t = Enum<AlignSVG::Topol>::getValue(topol, false);
376 //const Alignment<> & a = Enum<Alignment<> >::getValue(align, false);
377 setAlign(a.axis, a.pos, t);
378 }
379
381
383 void setAlign(const std::string & align);
384 // Note: no mixed type, ANCHOR:LEFT
385
387 bool isAligned() const;
388
389 void resetAlign();
390
391 void swapAlign(AlignSVG & align);
392
394 /*
395 * \tparam P - enum type Owner \c REF or \c OBJ , or respective string.
396 * \tparam A - enum type axis_t \c HORZ or \c VERT , or respective string.
397 * \param pos - target object \c OBJ or referred anchor object \c REF
398 * \param axis - horizontal \c HORZ or vertical \c AXIS .
399 */
400 template <typename P, typename A>
401 AlignBase::Pos & getAlign(const P & pos, const A & axis);
402
403
405 /*
406 * \tparam P - enum type Owner \c REF or \c OBJ , or respective string.
407 * \tparam A - enum type axis_t \c HORZ or \c VERT , or respective string.
408 * \param pos - target object \c OBJ or referred anchor object \c REF
409 * \param axis - horizontal \c HORZ or vertical \c AXIS .
410 *
411 */
412 template <typename P, typename A>
413 const AlignBase::Pos & getAlign(const P & pos, const A & axis) const;
414
418 void confToStream(std::ostream & ostr) const;
419
420 inline
421 const std::string & getAlignStr() const {
422 return alignStr;
423 }
424
425 void swapAlign();
426 /*
428 template <typename ...TT>
429 bool isAlignSet(const TT... args) const {
430 bitvect_t v = combineAlign(args...);
431 return (alignment & v) == v;
432 }
433
434 */
435
436protected:
437
438 // Future extension
439 typedef int bitvect_t; // or int_t ?
440
441 // Future extension
442 mutable
443 bitvect_t alignment = 0;
444
445 std::string alignStr;
446
448 template <typename P, typename A, typename V>
449 void modifyAlign(const P & owner, const A & axis, const V &value){
450 getAlign(owner, axis) = Enum<AlignBase::Pos>::getValue(value, false);
451 }
452
453
454 void updateAlignStr();
455
456 virtual inline
457 void updateAlign(){
458 updateAlignStr();
459 };
460
461
462 typedef std::vector<AlignBase::Pos> align_vect_t;
463 typedef std::vector<align_vect_t > align_conf_t;
464
465 align_conf_t alignments = align_conf_t(2, align_vect_t(2, AlignBase::Pos::UNDEFINED_POS));
466
468
469
470};
471
472
473inline
474std::ostream & operator<<(std::ostream &ostr, const AlignSVG & align){
475 //return ostr << align.axis << '_' << align.pos; // enums resolved above
476 align.confToStream(ostr);
477 return ostr; // << "UNDER CONSTR..."; // RESOLVE!
478}
479
480
481// template <>
482// const drain::Enum<AlignSVG::Owner>::dict_t drain::Enum<AlignSVG::Owner>::dict;
483DRAIN_ENUM_DICT(AlignSVG::Owner);
484DRAIN_ENUM_OSTREAM(AlignSVG::Owner);
485
486//template <>
487//const drain::Enum<AlignSVG::Topol>::dict_t drain::Enum<AlignSVG::Topol>::dict;
488DRAIN_ENUM_DICT(AlignSVG::Topol);
489DRAIN_ENUM_OSTREAM(AlignSVG::Topol);
490
491template <>
492inline
493void AlignSVG::HorzAlign::reset(){
494 // axis = AlignBase::Axis::UNDEFINED_AXIS;
495 pos = AlignBase::Pos::UNDEFINED_POS;
496}
497
498template <>
499inline
500void AlignSVG::VertAlign::reset(){
501 // axis = AlignBase::Axis::UNDEFINED_AXIS;
502 pos = AlignBase::Pos::UNDEFINED_POS;
503}
504
505DRAIN_TYPENAME(AlignSVG::HorzAlign);
506
507DRAIN_TYPENAME(AlignSVG::VertAlign);
508
510/*
511template <>
512const drain::Enum<AlignSVG::HorzAlign>::dict_t drain::Enum<AlignSVG::HorzAlign>::dict;
513
515template <>
516const drain::Enum<AlignSVG::VertAlign>::dict_t drain::Enum<AlignSVG::VertAlign>::dict;
517
518
520template <>
521const drain::Enum<Alignment<> >::dict_t drain::Enum<Alignment<> >::dict;
522*/
523
524DRAIN_ENUM_DICT(AlignSVG::HorzAlign);
525DRAIN_ENUM_DICT(AlignSVG::VertAlign);
526DRAIN_ENUM_DICT(Alignment<>);
527
528
529
530template <typename OBJ, typename A>
531AlignBase::Pos & AlignSVG::getAlign(const OBJ & owner, const A & axis){
532 const AlignSVG::Owner p = Enum<AlignSVG::Owner>::getValue(owner, false); // raise error
533 const AlignBase::Axis a = Enum<AlignBase::Axis>::getValue(axis, false); // raise error
534 return alignments[p][a];
535}
536
537template <typename OBJ, typename A>
538const AlignBase::Pos & AlignSVG::getAlign(const OBJ & owner, const A & axis) const {
539 const AlignSVG::Owner p = Enum<AlignSVG::Owner>::getValue(owner, false); // raise error
540 const AlignBase::Axis a = Enum<AlignBase::Axis>::getValue(axis, false); // raise error
541 return alignments[p][a];
542}
543
544
545
546
547
548
550
563template <typename AX = AlignBase::Axis, AlignBase::Axis A = AlignBase::Axis::UNDEFINED_AXIS> // , Align::Coord POS = Align::Coord::UNDEFINED_POS>
564struct CompleteAlignment : public Alignment<AX,A> {
565
566 AlignSVG::Topol topol = AlignSVG::Topol::INSIDE; // or undef?
567
569 template <class ...TT>
570 CompleteAlignment(const TT... args) : Alignment<AX,A>() {
571 set(args...);
572 }
573
574 inline
576
577 virtual inline
578 bool isSet() const {
579 return (this->axis != AlignBase::Axis::UNDEFINED_AXIS) &&
580 (this->pos != AlignBase::Pos::UNDEFINED_POS) &&
581 (topol != AlignSVG::Topol::UNDEFINED_TOPOL);
582 // return Alignment<AX,A>::isSet() && (topol != AlignSVG::Topol::UNDEFINED_TOPOL);
583 }
584
585 inline
586 const AlignSVG::Topol & getOrDefault(const AlignSVG::Topol & defaultValue) const {
587 if (topol != AlignSVG::Topol::UNDEFINED_TOPOL){
588 return topol;
589 }
590 else {
591 return defaultValue;
592 }
593 }
594
595
596 // Sets all members to UNDEFINED state.
597 virtual inline
598 void reset(){
599 Alignment<AX,A>::reset();
600 topol = AlignSVG::Topol::UNDEFINED_TOPOL;
601 // this->updateAlign();
602 }
603
604
605 template <typename AX2, AlignBase::Axis A2, class ...TT>
606 void set(const Alignment<AX2,A2> & align, const TT... args){
607 this->axis = align.axis;
608 this->pos = align.pos;
609 set(args...);
610 }
611
612 template <class ...TT>
613 void set(AlignSVG::Topol topol, const TT... args){
614 this->topol = topol;
615 set(args...);
616 }
617
618 template <class ...TT>
619 void set(AlignBase::Axis axis, const TT... args){
620 this->axis = axis;
621 set(args...);
622 }
623
624 template <class ...TT>
625 void set(AlignBase::Pos coord, const TT... args){
626 this->pos = coord;
627 set(args...);
628 }
629
630 template <class ...TT>
631 void set(const std::string & key, const TT... args){
632 if (Enum<AlignSVG::Topol>::setValue(key, topol)){
633 // ok
634 }
635 else if (Enum<Alignment<> >::setValue(key, *this)){ // RIGHT or?
636 // ok
637 }
638 else if (Enum<AlignBase::Axis>::setValue(key, this->axis)){
639 // ok
640 }
641 else if (Enum<AlignBase::Pos>::setValue(key, this->pos)){
642 // ok
643 }
644 else {
645 // Advice: keys
646 throw std::runtime_error(drain::StringBuilder<>("key '", key, "' not found. Appeared in: ", args...));
647 }
648
649 set(args...);
650 }
651
652 template <class ...TT>
653 void set(const char *key, const TT... args){
654 set(std::string(key), args...);
655 }
656
657
658protected:
659
660 inline
661 void set(){
662 // this->updateAlign(); // ok?
663 }
664
665};
666
667
668
669template <typename AX, AlignBase::Axis A>
670std::ostream & operator<<(std::ostream &ostr, const CompleteAlignment<AX,A> & ad){
671 return ostr << ad.topol << '_' << ad.axis << ':' << ad.pos;
672}
673
674
675
676
677
678
679
680} // image::
681
682} // drain::
683
684
685DRAIN_ENUM_OSTREAM(drain::image::AlignBase::Axis);
686DRAIN_ENUM_OSTREAM(drain::image::AlignBase::Pos);
687DRAIN_ENUM_OSTREAM(drain::image::AlignSVG::Owner);
688
689
690#endif // DRAIN_ALIGN_SVG_H_
691
Definition StringBuilder.h:58
Definition DataSelector.cpp:1277
DRAIN_TYPENAME(void)
Add a specialization for each type of those you want to support.
A container for a static dictionary of enumeration values.
Definition Enum.h:51
static E getValue(const E &value, bool lenient=true)
Convenience for object.set(...) like commands.
Definition Enum.h:96
static bool setValue(const std::string &key, E &value)
Assign string values to an enumeration type.
Definition Enum.h:78
Low level alignment instructions.
Definition AlignSVG.h:50
static Axis flip(Axis axis)
supporting simultaneous HORZ|VERT
Definition AlignSVG.h:83
Pos
Reference position at Axis (HORZ or VERT)
Definition AlignSVG.h:55
User-friendly programming interface for alignment considering two elements.
Definition AlignSVG.h:230
static const HorzAlign LEFT
Alias for {HORZ:MIN}.
Definition AlignSVG.h:240
static const VertAlign MIDDLE
Alias for {VERT:MID}.
Definition AlignSVG.h:267
void setAlign(const std::string &align, const T &topol)
High-level, user friendlier interface for setting the alignments for both OBJECT itself and its ANCHO...
Definition AlignSVG.h:373
void setAlign(const OBJ &owner, const A &axis, const V &value)
Low-level, "atomic" setter of alignment for OBJECT itself or its ANCHOR object.
Definition AlignSVG.h:308
void setAlign(const AlignBase::Axis &axis, const AlignBase::Pos &pos, Topol topol=Topol::INSIDE)
Set a single alignment setting. "Intermediate-level": axis and pos are given separately.
Definition AlignSVG.h:324
const AlignBase::Pos & getAlign(const P &pos, const A &axis) const
Return alignment setting of an object along horizontal or vertical axis .
void confToStream(std::ostream &ostr) const
Definition AlignSVG.cpp:168
bool isAligned() const
Returns true, if any setting is set...
Definition AlignSVG.cpp:259
static const HorzAlign RIGHT
Alias for {HORZ:MAX}.
Definition AlignSVG.h:248
static const HorzAlign HORZ_FILL
Alias for {HORZ:FILL}.
Definition AlignSVG.h:252
void setAlign(const Alignment< AX, A > &align1, const Alignment< AX, A > &align2)
Compiler trap: unimplemented for two of same kind: either HorzAlign or VertAlign twice.
void modifyAlign(const P &owner, const A &axis, const V &value)
Change alignment configuration without updating the alignStr.
Definition AlignSVG.h:449
static const VertAlign VERT_FILL
Alias for {VERT:FILL}.
Definition AlignSVG.h:275
static const VertAlign BOTTOM
Alias for {VERT:MAX}.
Definition AlignSVG.h:271
void setAlign(const Alignment< AX, A > &align, const T... args)
NEW High-level, user friendlier interface for setting INSIDE the alignments for both OBJECT itself an...
Definition AlignSVG.h:342
static const HorzAlign CENTER
Alias for {HORZ:MID}.
Definition AlignSVG.h:244
static const VertAlign TOP
Alias for {VERT:MIN}.
Definition AlignSVG.h:263
AlignBase::Pos & getAlign(const P &pos, const A &axis)
Return alignment setting of an object along horizontal or vertical axis .
Container for Axis and Pos.
Definition AlignSVG.h:136
Alignment(const Alignment &ac)
Copy constructor.
Definition AlignSVG.h:152
Alignment(AlignBase::Pos pos=AlignBase::Pos::UNDEFINED_POS)
Default constructor.
Definition AlignSVG.h:147
virtual ~Alignment()
Destructor.
Definition AlignSVG.h:168
"Alternative" partial alignment configuration for single object. Partial means that either OBJECT its...
Definition AlignSVG.h:564
CompleteAlignment(const TT... args)
Constructor not setting Axis.
Definition AlignSVG.h:570