Lumiera  0.pre.03
»edit your freedom«
ui-coord-resolver.hpp
Go to the documentation of this file.
1 /*
2  UI-COORD-RESOLVER.hpp - resolve UI coordinate spec against actual window topology
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 
106 #ifndef STAGE_INTERACT_UI_COORD_RESOLVER_H
107 #define STAGE_INTERACT_UI_COORD_RESOLVER_H
108 
109 #include "lib/error.hpp"
110 #include "lib/symbol.hpp"
111 #include "lib/format-string.hpp"
113 #include "lib/iter-explorer.hpp"
114 #include "lib/iter-source.hpp"
115 #include "lib/depend.hpp"
116 #include "lib/util.hpp"
117 
118 #include <utility>
119 #include <memory>
120 
121 
122 namespace stage {
123 namespace interact {
124 
125  namespace error = lumiera::error;
126 
127  using std::unique_ptr;
128  using util::unConst;
129  using lib::Literal;
130  using lib::Symbol;
131 
132 
133 
134 
141  : public lib::IterSource<Literal>
142  {
143  public:
144  virtual ~TreeStructureNavigator();
145 
158  virtual TreeStructureNavigator* expandChildren() const =0;
159 
160 
168  static auto
170  {
171  return lib::explore (source)
172  .expand([](TreeStructureNavigator& parent){ return parent.expandChildren(); });
173  }
174  };
175 
176 
177 
178 
179 
192  {
193  public:
194  virtual ~LocationQuery();
195 
198 
199 
200  using ChildIter = decltype (TreeStructureNavigator::buildIterator(0));
201 
202 
214  virtual Literal determineAnchor (UICoord const& path) =0;
215 
216 
226  virtual size_t determineCoverage (UICoord const& path) =0;
227 
239  virtual ChildIter getChildren (UICoord const& path, size_t pos) =0;
240  };
241 
242 
243 
244 
245 
246 
277  : public UICoord::Builder
278  {
279 
280  struct Resolution
281  {
282  const char* anchor = nullptr;
283  size_t depth = 0;
284  unique_ptr<UICoord> covfefe{};
285  bool isResolved = false;
286  };
287 
288  LocationQuery& query_;
289  Resolution res_;
290 
291  public:
292  UICoordResolver (UICoord const& uic, LocationQuery& queryAPI)
293  : Builder{uic}
294  , query_{queryAPI}
295  , res_{}
296  {
297  attempt_trivialResolution();
298  }
299 
300  UICoordResolver (UICoord && uic, LocationQuery& queryAPI)
301  : Builder{std::move(uic)}
302  , query_{queryAPI}
303  , res_{}
304  {
305  attempt_trivialResolution();
306  }
307 
308 
309  /* === query functions === */
310 
314  bool
315  isAnchored() const
316  {
317  return res_.anchor
318  and res_.anchor != Symbol::BOTTOM;
319  }
320 
328  bool
329  canAnchor() const
330  {
331  return isAnchored()
332  or (res_.isResolved and res_.covfefe)
333  or unConst(this)->pathResolution()
334  or isAnchored(); // resolution failed, but computed at least an anchor
335  }
336 
343  bool
345  {
346  return res_.isResolved
347  and res_.depth > 0;
348  }
349 
354  bool
355  isCovered() const
356  {
357  return res_.isResolved
358  and res_.depth == this->uic_.size();
359  }
360 
362  bool
364  {
365  return isCovered();
366  }
367 
368 
378  bool
379  canCover() const
380  {
381  return isCovered() // either explicit coverage known
382  or (res_.isResolved and res_.covfefe) // or previous matching run found (partial) solution
383  or unConst(this)->pathResolution() // perform matching run now to find total coverage
384  or (res_.covfefe); // or at least partial coverage was found
385  }
386 
387 
388 
389  /* === mutation functions === */
390 
401  {
402  if (isCoveredPartially() and not res_.covfefe)
403  {
404  ASSERT (res_.anchor); // depth > 0 implies anchorage
405  window (res_.anchor); // thus make this anchor explicit
406  truncateTo (res_.depth);
407  }
408  else if (canCover())
409  {
410  ASSERT (res_.isResolved);
411  REQUIRE (res_.covfefe);
412  res_.depth = res_.covfefe->size();
413  this->uic_ = std::move (*res_.covfefe);
414  res_.covfefe.reset();
415  }
416  else
417  {
418  ASSERT (res_.isResolved);
419  REQUIRE (res_.depth == 0);
420  REQUIRE (not res_.covfefe);
421  truncateTo (0);
422  }
423  ENSURE (isCovered());
424  return std::move (*this);
425  }
426 
427 
436  {
437  if (isCoveredPartially() and not res_.covfefe)
438  {
439  ASSERT (res_.anchor);
440  window (res_.anchor); // just ensure the anchor info is explicit,
441  } // the rest is already in place and explicit
442  else if (canCover())
443  {
444  ASSERT (res_.isResolved);
445  REQUIRE (res_.covfefe);
446  REQUIRE (uic_.size() >= res_.covfefe->size());
447  res_.depth = res_.covfefe->size();
448  // possibly overwrite placeholders by explicitly resolved info...
449  for (size_t pos = 0; pos < res_.depth; ++pos )
450  overwrite (pos, (*res_.covfefe)[pos]);
451  res_.covfefe.reset();
452  }
453  else
454  {
455  ASSERT (res_.isResolved);
456  REQUIRE (res_.depth == 0);
457  REQUIRE (not res_.covfefe);
458  truncateTo (0);
459  }
460  ENSURE (empty() or (isCoveredPartially() and uic_.isExplicit()));
461  return std::move (*this); // no wildcards remain
462  }
463 
464 
476  {
477  if (canAnchor())
478  {
479  window (res_.anchor);
480  normalise();
481  }
482  return std::move (*this);
483  }
484 
485 
486 
493  extend (Literal pathExtension)
494  {
495  if (not isCovered())
496  cover();
497  ENSURE (isCovered());
498  append (pathExtension);
499  res_.depth = query_.determineCoverage (this->uic_); // coverage may grow
500  return std::move (*this);
501  }
502 
510  extend (UICoord const& partialExtensionSpec)
511  {
512  if (not canCover())
513  uic_ = partialExtensionSpec;
514  else
515  {
516  REQUIRE (res_.isResolved);
517  size_t coverable = res_.covfefe? res_.covfefe->size() : res_.depth;
518  auto newContent = partialExtensionSpec.begin();
519  size_t extensionPos = newContent? partialExtensionSpec.indexOf(*newContent) : coverable;
520  if (coverable > extensionPos)
521  throw error::Invalid (util::_Fmt{"Attempt to extend covered path %s with %s "
522  "would overwrite positions %d to %d (incl)"}
523  % (res_.covfefe? *res_.covfefe : UICoord{uic_.rebuild().truncateTo(res_.depth)})
524  % partialExtensionSpec
525  % extensionPos
526  % (coverable-1));
527  cover();
528  for ( ; newContent; ++newContent, ++extensionPos )
529  overwrite (extensionPos, *newContent);
530  normalise();
531  }
532  res_ = Resolution{}; // start over with pristine resolution state
533  attempt_trivialResolution();
534  canCover();
535  return std::move (*this);
536  }
537 
538 
550  {
551  if (pos < uic_.size() and not uic_.isPresent(pos))
552  overwrite (pos, UIC_ELIDED);
553  return std::move (*this);
554  }
555 
556 
557 
559  operator string() const { return string(this->uic_); }
560  size_t coverDepth() const { return res_.depth; }
561 
562 
563 
564  private:
572  void
574  {
575  res_.anchor = query_.determineAnchor (this->uic_);
576  if (not uic_.isExplicit()) return;
577  res_.depth = query_.determineCoverage(this->uic_);
578  if (util::contains (this->uic_, UIC_ELIDED)) return; // existentially quantified
579  res_.isResolved = true;
580  }
581 
586  bool pathResolution();
587  };
588 
589 
590 
591 }}// namespace stage::interact
592 #endif /*STAGE_INTERACT_UI_COORD_RESOLVER_H*/
Builder && truncateTo(size_t depth)
possibly shorten this path specification to a limited depth
Definition: ui-coord.hpp:624
Describe a location within the UI through structural/topological coordinates.
Definition: ui-coord.hpp:129
UICoordResolver && cover()
mutate the path to get it totally covered
virtual TreeStructureNavigator * expandChildren() const =0
expand into exploration of child elements at "current position".
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
bool canAnchor() const
determine if a mutation is possible to anchor the path explicitly
UICoordResolver && existentiallyQuantify(size_t pos)
mutate to turn a wildcard into existentially quantified. This means to assume (or require) that an el...
bool isAnchored() const
is this path explicitly anchored at an existing window?
virtual Literal determineAnchor(UICoord const &path)=0
make the real anchor point explicit.
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
const Symbol UIC_ELIDED
indicate that a component is elided or irrelevant here
UICoordResolver && extend(UICoord const &partialExtensionSpec)
mutate the path and extend it with components at fixed positions
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Token or Atom with distinct identity.
Definition: symbol.hpp:117
Iteration source interface to abstract a data source, which then can be accessed through IterAdapter ...
Definition: iter-source.hpp:79
bool isCovered() const
this path is completely covered by the currently existing UI structure;
Marker types to indicate a literal string and a Symbol.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
iterator begin() const
Definition: path-array.hpp:380
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
UICoordResolver && anchor()
mutate the window part of the path such as to make the anchorage explicit, if possible ...
A topological addressing scheme to designate structural locations within the UI.
Interface to locate and move within a tree shaped structure.
Query and mutate UICoord specifications in relation to actual UI topology.
bool isCoveredPartially() const
is this path at least partially covered? A covered path describes an access path through widgets actu...
bool canCover() const
determine if a mutation is possible to get the path (partially) covered.
Singleton services and Dependency Injection.
Interface to discover a backing structure for the purpose of path navigation and resolution.
Lumiera error handling (C++ interface).
static auto buildIterator(TreeStructureNavigator *source)
build a Lumiera Forward Iterator as front-end and managing Handle for a TreeStructureNavigator or sub...
static lib::Depend< LocationQuery > service
access point to global LocationQuery service implementation
void attempt_trivialResolution()
establish a trivial anchorage and coverage, if possible.
UICoordResolver && extend(Literal pathExtension)
mutate the path to extend it while keeping it partially covered
virtual ~TreeStructureNavigator()
this is an interface
bool isCoveredTotally() const
synonymous to isCovered()
Building tree expanding and backtracking evaluations within hierarchical scopes.
Extension module to build an opaque data source, accessible as Lumiera Forward Iterator.
size_t indexOf(Literal const &content) const
reverse lookup of actual path content
Definition: path-array.hpp:331
UICoordResolver && coverPartially()
mutate the path by resolving all wildcards to achieve partial coverage
virtual size_t determineCoverage(UICoord const &path)=0
evaluate to what extent a UIcoord spec matches the actual UI