Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
ui-coord.hpp
Go to the documentation of this file.
1/*
2 UI-COORD.hpp - generic topological location addressing scheme within the UI
3
4 Copyright (C)
5 2017, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
73#ifndef STAGE_INTERACT_UI_COORD_H
74#define STAGE_INTERACT_UI_COORD_H
75
76#include "lib/error.hpp"
77#include "lib/symbol.hpp"
78#include "lib/path-array.hpp"
79#include "lib/nocopy.hpp"
80#include "lib/util.hpp"
81
82#include <cstring>
83#include <string>
84#include <vector>
85#include <utility>
86
87
88namespace stage {
89namespace interact {
90
91 namespace error = lumiera::error;
92
93 using std::string;
94 using lib::Literal;
95 using lib::Symbol;
96 using util::unConst;
97 using util::isnil;
98 using util::min;
99
100 enum {
102 };
103
104 /* === predefined DSL symbols === */
105
115
116
117 extern const Symbol UIC_CURRENT_WINDOW;
118 extern const Symbol UIC_FIRST_WINDOW;
119 extern const Symbol UIC_ELIDED;
120
121
122
130 : public lib::PathArray<UIC_INLINE_SIZE>
131 {
132
133 public:
143 template<typename...ARGS>
144 explicit
145 UICoord (ARGS&& ...args) : PathArray(std::forward<ARGS> (args)...) { }
146
147 UICoord (UICoord&&) = default;
148 UICoord (UICoord const&) = default;
149 UICoord (UICoord& o) : UICoord((UICoord const&)o) { }
150
151 UICoord& operator= (UICoord const&) = default;
152 UICoord& operator= (UICoord &&) = default;
153
154
155
156 /* === Builder API === */
157
158 class Builder;
159
161 UICoord (Builder&& builder);
162
164 static Builder firstWindow();
165
167 static Builder currentWindow();
168
170 static Builder window (Literal windowID);
171
172 //----- convenience shortcuts to start a copy-builder....
173 Builder persp (Literal perspectiveID) const;
174 Builder panel (Literal panelID)const;
175 Builder view (Literal viewID) const;
176 Builder tab (Literal tabID) const;
177 Builder tab (uint tabIdx) const;
178 Builder noTab () const;
179
180 //----- convenience shortcuts to start mutation on a copy...
181 Builder path (Literal pathDefinition) const;
182 Builder append (Literal elmID) const;
183 Builder prepend (Literal elmID) const;
184 Builder rebuild() const;
185
186
187
188 /* === named component access === */
189
194 Literal getTab() const { return accesComponent (UIC_TAB); }
195
196
197
198 /* === query functions === */
199
205 bool
207 {
208 return not empty()
209 and isnil (getWindow());
210 }
211
212 bool
214 {
215 return not empty()
216 and not isnil (getWindow());
217 }
218
219
224 bool
226 {
227 return isComplete()
228 and not util::contains (*this, Symbol::ANY);
229 }
230
231
232 bool
233 isPresent (size_t idx) const
234 {
235 Literal* elm = unConst(this)->getPosition(idx);
236 return not isnil(elm)
237 and *elm != Symbol::ANY;
238 }
239
240
241 bool
242 isWildcard (size_t idx) const
243 {
244 Literal* elm = unConst(this)->getPosition(idx);
245 return elm
246 and *elm == Symbol::ANY;
247 }
248
249
261 bool
262 isExtendedBelow (UICoord const& parent) const
263 {
264 size_t subSiz = this->size(),
265 parSiz = parent.size(),
266 idx = 0;
267
268 if (parSiz >= subSiz)
269 return false;
270
271 while (idx < parSiz
272 and ( (*this)[idx]== parent[idx]
273 or Symbol::ANY == parent[idx]
274 or isnil (parent[idx])))
275 ++idx;
276
277 ENSURE (idx < subSiz);
278 return idx == parSiz;
279 } // meaning: this goes further down
280
281
282
283 /* === String representation === */
284
285 explicit
286 operator string() const
287 {
288 if (isnil (*this))
289 return "UI:?";
290
291 string component = getComp();
292 string path = getPath();
293
294 if (isnil (component))
295 return "UI:?/" + path;
296
297 if (isnil (path))
298 return "UI:" + component;
299 else
300 return "UI:" + component + "/" + path;
301 }
302
303 string
304 getComp() const
305 {
306 if (empty()) return "";
307
308 size_t end = min (size(), UIC_PATH);
309 size_t pos = indexOf (*begin());
310
311 if (pos >= end)
312 return ""; // empty or path information only
313
314 string buff;
315 buff.reserve(80);
316
317 if (0 < pos) // incomplete UI-Coordinates (not anchored)
318 buff += "?";
319
320 for ( ; pos<end; ++pos )
321 switch (pos) {
322 case UIC_WINDOW:
323 buff += getWindow();
324 break;
325 case UIC_PERSP:
326 buff += "["+getPersp()+"]";
327 break;
328 case UIC_PANEL:
329 buff += "-"+getPanel();
330 break;
331 case UIC_VIEW:
332 buff += "."+getView();
333 break;
334 case UIC_TAB:
335 if (UIC_ELIDED != getTab())
336 buff += "."+getTab();
337 break;
338 default:
339 NOTREACHED ("component index numbering broken");
340 }
341 return buff;
342 }
343
344 string
345 getPath() const
346 {
347 size_t siz = size();
348 if (siz <= UIC_PATH)
349 return ""; // no path information
350
351 string buff; // heuristic pre-allocation
352 buff.reserve (10 * (siz - UIC_PATH));
353
354 iterator elm = pathSeq();
355 if (isnil (*elm))
356 { // irregular case : only a path fragment
357 elm = this->begin();
358 buff += "?/";
359 }
360
361 for ( ; elm; ++elm )
362 buff += *elm + "/";
363
364 // chop off last delimiter
365 size_t len = buff.length();
366 ASSERT (len >= 1);
367 buff.resize(len-1);
368 return buff;
369 }
370
373 pathSeq() const
374 {
375 return size()<= UIC_PATH? end()
376 : iterator{this, unConst(this)->getPosition(UIC_PATH)};
377 }
378
379
380 private:
382 friend class Builder;
383
384 size_t
386 {
387 REQUIRE (not empty());
388 return indexOf (*begin());
389 }
390
391 Literal
393 {
394 Literal* elm = unConst(this)->getPosition(idx);
395 return elm? *elm : Symbol::EMPTY;
396 }
397
398 void
399 setComponent (size_t idx, Literal newContent)
400 {
401 Literal* storage = expandPosition (idx);
402 setContent (storage, newContent);
403 }
404
405
413 void
414 setTailSequence (size_t idx, Literal newContent)
415 {
416 std::vector<Literal> elms;
417 if (not isnil (newContent))
418 {
419 if (not std::strchr (newContent, '/'))
420 {
421 // single element: just place it as-is
422 // and remove any further content behind
423 elms.emplace_back (newContent);
424 }
425 else
426 { // it is actually a sequence of elements,
427 // which need to be split first, and then
428 // interned into the global symbol table
429 string sequence{newContent};
430 size_t pos = 0;
431 size_t last = 0;
432 while (string::npos != (last = sequence.find ('/', pos)))
433 {
434 elms.emplace_back (Symbol{sequence.substr(pos, last - pos)});
435 pos = last + 1; // delimiter stripped
436 }
437 sequence = sequence.substr(pos);
438 if (not isnil (sequence))
439 elms.emplace_back (Symbol{sequence});
440 } }
441
442 setTailSequence (idx, elms);
443 }
444
453 void
454 setTailSequence (size_t idx, std::vector<Literal>& pathElms)
455 {
456 size_t cnt = pathElms.size();
457 expandPosition (idx + cnt); // preallocate
458 for (size_t i=0 ; i < cnt; ++i)
459 setContent (expandPosition(idx + i), pathElms[i]);
460 size_t end = size();
461 for (size_t i = idx+cnt; i<end; ++i)
462 setContent (expandPosition(i), nullptr);
463 }
464
465
466 public: /* ===== relational operators : equality and partial order ===== */
467
468 friend bool
469 operator== (UICoord const& l, UICoord const& r)
470 {
471 return static_cast<PathArray const&> (l) == static_cast<PathArray const&> (r);
472 }
473
474 friend bool
475 operator< (UICoord const& l, UICoord const& r)
476 {
477 return l.isExtendedBelow (r);
478 }
479
480 friend bool operator> (UICoord const& l, UICoord const& r) { return (r < l); }
481 friend bool operator<= (UICoord const& l, UICoord const& r) { return (l < r) or (l == r); }
482 friend bool operator>= (UICoord const& l, UICoord const& r) { return (r < l) or (l == r); }
483 friend bool operator!= (UICoord const& l, UICoord const& r) { return not (l == r); }
484 };
485
486
487
488
489
490 /* === Builder API === */
491
492 class LocationClause;
493
497 {
498 protected:
500
501 template<typename...ARGS>
502 explicit
503 Builder (ARGS&& ...args) : uic_{std::forward<ARGS> (args)...} { }
504 Builder (UICoord && anonRef) : uic_{std::move(anonRef)} { }
505 Builder (UICoord const& base) : uic_{base} { }
506
508 friend class UICoord;
509
510 public:
512 Builder (Builder &&) = default;
513
514 size_t size() const { return uic_.size(); }
515 bool empty() const { return uic_.empty();}
516
519 UICoord const&
521 {
522 return uic_;
523 }
524
525
526 /* == Builder functions == */
527
530 Builder&&
531 window (Literal windowID)
532 {
533 uic_.setComponent (UIC_WINDOW, windowID);
534 return std::move (*this);
535 }
536
538 Builder&&
539 persp (Literal perspectiveID)
540 {
541 uic_.setComponent (UIC_PERSP, perspectiveID);
542 return std::move (*this);
543 }
544
546 Builder&&
547 panel (Literal panelID)
548 {
549 uic_.setComponent (UIC_PANEL, panelID);
550 return std::move (*this);
551 }
552
554 Builder&&
555 view (Literal viewID)
556 {
557 uic_.setComponent (UIC_VIEW, viewID);
558 return std::move (*this);
559 }
560
562 Builder&&
563 tab (Literal tabID)
564 {
565 uic_.setComponent (UIC_TAB, tabID);
566 return std::move (*this);
567 }
568
570 Builder&&
571 tab (uint tabIdx)
572 {
574 return std::move (*this);
575 }
576
579 Builder&&
581 {
583 return std::move (*this);
584 }
585
586
591 Builder&&
593 {
594 if (not isnil(elm))
595 uic_.setTailSequence (uic_.size(), elm);
596 return std::move (*this);
597 }
598
600 Builder&&
602 {
603 if (not uic_.isIncomplete())
604 throw error::Logic ("Attempt to prepend "+elmID
605 +" to the complete rooted path "+string(uic_));
606
607 uic_.setComponent (uic_.findStartIdx() - 1, elmID);
608 return std::move (*this);
609 }
610
616 Builder&&
617 path (Literal pathDef)
618 {
619 uic_.setTailSequence (UIC_PATH, pathDef);
620 return std::move (*this);
621 }
622
624 Builder&&
625 truncateTo (size_t depth)
626 {
627 uic_.truncateTo (depth);
628 return std::move (*this);
629 }
630
632 operator LocationClause();
634
635 protected:
636 Builder&&
638 {
639 uic_.normalise();
640 return std::move (*this);
641 }
642
643 Builder&&
644 overwrite (size_t depth, Literal newSpec)
645 {
646 Literal* storage = uic_.expandPosition (depth);
647 uic_.setContent (storage, newSpec);
648 return std::move (*this);
649 }
650 };
651
652
653
658 inline
660 : UICoord{std::move (builder.uic_)}
661 {
662 PathArray::normalise();
663 }
664
665
669 inline UICoord::Builder
674
675 inline UICoord::Builder
677 {
678 return window (UIC_FIRST_WINDOW);
679 }
680
682 inline UICoord::Builder
684 {
685 return Builder{windowID};
686 }
687
688
695 inline UICoord::Builder
696 UICoord::persp (Literal perspectiveID) const
697 {
698 return Builder(*this).persp (perspectiveID);
699 }
700
701 inline UICoord::Builder
702 UICoord::panel (Literal panelID) const
703 {
704 return Builder(*this).panel (panelID);
705 }
706
707 inline UICoord::Builder
708 UICoord::view (Literal viewID) const
709 {
710 return Builder(*this).view (viewID);
711 }
712
713 inline UICoord::Builder
714 UICoord::tab (Literal tabID) const
715 {
716 return Builder(*this).tab (tabID);
717 }
718
719 inline UICoord::Builder
720 UICoord::tab (uint tabIdx) const
721 {
722 return Builder(*this).tab (tabIdx);
723 }
724
725 inline UICoord::Builder
727 {
728 return Builder(*this).noTab();
729 }
730
736 inline UICoord::Builder
737 UICoord::path (Literal pathDefinition) const
738 {
739 return Builder(*this).path (pathDefinition);
740 }
741
742 inline UICoord::Builder
744 {
745 return Builder(*this).append (elmID);
746 }
747
748 inline UICoord::Builder
750 {
751 return Builder(*this).prepend (elmID);
752 }
753
754 inline UICoord::Builder
756 {
757 return Builder(*this);
758 }
759
760
761
762}}// namespace stage::interact
763#endif /*STAGE_INTERACT_UI_COORD_H*/
Adapter for building an implementation of the »Lumiera Forward Iterator« concept.
Inline string literal.
Definition symbol.hpp:78
Abstraction for path-like topological coordinates.
size_t indexOf(Literal const &content) const
reverse lookup of actual path content
void truncateTo(size_t newSize)
PathArray(IndexSeq< prefix... >, IndexSeq< rest... >, ARGS &&...args)
Literal * expandPosition(size_t idx)
void normalise()
establish the contract of PathArray
void setContent(Literal *pos, const char *val)
Token or Atom with distinct identity.
Definition symbol.hpp:120
static Symbol ANY
Definition symbol.hpp:122
static Symbol EMPTY
Definition symbol.hpp:123
Builder && view(Literal viewID)
augment UI coordinates to indicate a specific view to be used
Definition ui-coord.hpp:555
Builder && overwrite(size_t depth, Literal newSpec)
Definition ui-coord.hpp:644
Builder && tab(Literal tabID)
augment UI coordinates to indicate a specific tab within the view"
Definition ui-coord.hpp:563
Builder && prepend(Literal elmID)
augment partially defined UI coordinates by extending them towards the root
Definition ui-coord.hpp:601
Builder && path(Literal pathDef)
augment UI coordinates to define a complete local path
Definition ui-coord.hpp:617
Builder && panel(Literal panelID)
augment UI coordinates to indicate a specific view to be used
Definition ui-coord.hpp:547
LocationClause create()
interprets the current (inline) builder contents as create clause, which has the meaning "create a ne...
Builder && persp(Literal perspectiveID)
augment UI coordinates to mandate a specific perspective to be active within the window
Definition ui-coord.hpp:539
Builder && window(Literal windowID)
change UI coordinate spec to define it to be rooted within the given window
Definition ui-coord.hpp:531
Builder && truncateTo(size_t depth)
possibly shorten this path specification to a limited depth
Definition ui-coord.hpp:625
Builder && noTab()
augment UI coordinates to indicate that no tab specification is necessary
Definition ui-coord.hpp:580
Builder && append(Literal elm)
augment UI coordinates by appending a further component at the end.
Definition ui-coord.hpp:592
Builder(UICoord const &base)
Definition ui-coord.hpp:505
Builder && tab(uint tabIdx)
augment UI coordinates to indicate a tab specified by index number
Definition ui-coord.hpp:571
Describe a location within the UI through structural/topological coordinates.
Definition ui-coord.hpp:131
size_t findStartIdx() const
Definition ui-coord.hpp:385
friend bool operator>=(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:482
Builder rebuild() const
Definition ui-coord.hpp:755
string getComp() const
Definition ui-coord.hpp:304
Literal getView() const
Definition ui-coord.hpp:193
friend bool operator<(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:475
Literal getPanel() const
Definition ui-coord.hpp:192
friend bool operator<=(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:481
friend bool operator==(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:469
Literal getTab() const
Definition ui-coord.hpp:194
iterator pathSeq() const
iterative access to the path sequence section
Definition ui-coord.hpp:373
Builder noTab() const
Definition ui-coord.hpp:726
static Builder window(Literal windowID)
Builder: start definition of UI-Coordinates rooted in given window.
Definition ui-coord.hpp:683
static Builder firstWindow()
Builder: start definition of UI-Coordinates rooted in the firstWindow
Definition ui-coord.hpp:676
Builder tab(Literal tabID) const
Definition ui-coord.hpp:714
void setTailSequence(size_t idx, std::vector< Literal > &pathElms)
replace the existing path information with the given elements
Definition ui-coord.hpp:454
void setComponent(size_t idx, Literal newContent)
Definition ui-coord.hpp:399
Builder path(Literal pathDefinition) const
convenience builder function so set a full path definition
Definition ui-coord.hpp:737
Builder persp(Literal perspectiveID) const
Definition ui-coord.hpp:696
Builder panel(Literal panelID) const
Definition ui-coord.hpp:702
Literal getWindow() const
Definition ui-coord.hpp:190
string getPath() const
Definition ui-coord.hpp:345
bool isExtendedBelow(UICoord const &parent) const
Check if this coordinate spec can be seen as an extension of the given parent coordinates and thus re...
Definition ui-coord.hpp:262
UICoord(ARGS &&...args)
UI-Coordinates can be created explicitly by specifying a sequence of Literal tokens,...
Definition ui-coord.hpp:145
UICoord(UICoord const &)=default
UICoord(UICoord &&)=default
bool isIncomplete() const
Definition ui-coord.hpp:206
Literal getPersp() const
Definition ui-coord.hpp:191
void setTailSequence(size_t idx, Literal newContent)
replace / overwrite existing content starting at given index.
Definition ui-coord.hpp:414
Builder append(Literal elmID) const
Definition ui-coord.hpp:743
Builder prepend(Literal elmID) const
Definition ui-coord.hpp:749
bool isPresent(size_t idx) const
Definition ui-coord.hpp:233
UICoord & operator=(UICoord const &)=default
Builder view(Literal viewID) const
Definition ui-coord.hpp:708
bool isWildcard(size_t idx) const
Definition ui-coord.hpp:242
friend bool operator!=(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:483
friend bool operator>(UICoord const &l, UICoord const &r)
Definition ui-coord.hpp:480
static Builder currentWindow()
Builder: start definition of UI-Coordinates rooted in the currentWindow
Definition ui-coord.hpp:670
Literal accesComponent(UIPathElm idx) const
Definition ui-coord.hpp:392
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Lumiera error handling (C++ interface).
unsigned int uint
Definition integral.hpp:29
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
const Symbol UIC_ELIDED
indicate that a component is elided or irrelevant here
const Symbol UIC_FIRST_WINDOW
window spec to refer to the first window of the application
const Symbol UIC_CURRENT_WINDOW
window spec to refer to the current window
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
STL namespace.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
Definition util.hpp:230
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
auto min(IT &&elms)
bool isnil(lib::time::Duration const &dur)
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Foundation abstraction to implement path-like component sequences.
A single location specification to be matched and fulfilled.
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...