Lumiera  0.pre.03
»edit your freedom«
gen-node-location-query.hpp
Go to the documentation of this file.
1 /*
2  GEN-NODE-LOCATION-QUERY.hpp - pose UI-coordinate location queries against a GenNode structure
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 
52 #ifndef STAGE_INTERACT_GEN_NODE_LOCATION_QUERY_H
53 #define STAGE_INTERACT_GEN_NODE_LOCATION_QUERY_H
54 
55 #include "lib/error.hpp"
56 #include "lib/symbol.hpp"
58 #include "lib/diff/gen-node.hpp"
59 #include "lib/format-string.hpp"
60 #include "lib/iter-explorer.hpp"
61 #include "lib/iter-source.hpp"
62 #include "lib/itertools.hpp"
63 #include "lib/util.hpp"
64 
65 #include <utility>
66 #include <string>
67 
68 
69 namespace stage {
70 namespace interact {
71 
72  namespace error = lumiera::error;
73 
74  using lib::Symbol;
75  using lib::Literal;
76  using lib::diff::Rec;
77  using util::isnil;
78  using util::_Fmt;
79  using std::forward;
80  using std::string;
81 
82 
83 
84 
91  : public LocationQuery
92  {
93  Rec tree_;
94 
95  public:
96  template<class REC>
97  GenNodeLocationQuery(REC&& backingStructure)
98  : tree_(std::forward<REC>(backingStructure))
99  { }
100 
101 
102  /* === LocationQuery interface === */
103 
105  virtual Literal
106  determineAnchor (UICoord const& path) override
107  {
108  if (isnil(tree_) or not path.isPresent(UIC_WINDOW))
109  return Symbol::BOTTOM;
110  if (UIC_FIRST_WINDOW == path.getWindow())
111  return getFirstWindow();
112  if (UIC_CURRENT_WINDOW == path.getWindow())
113  return getCurrentWindow();
114  if (not tree_.hasAttribute(string{path.getWindow()}))
115  return Symbol::BOTTOM;
116  return path.getWindow();
117  }
118 
119 
121  virtual size_t
122  determineCoverage (UICoord const& path) override
123  {
124  size_t depth = 0;
125  drillDown (tree_, path, path.size(), depth);
126  return depth;
127  }
128 
130  virtual ChildIter
131  getChildren (UICoord const& path, size_t pos) override
132  {
133  size_t depth = 0;
134  Rec const& node = drillDown (tree_, path, pos, depth);
135  if (depth != pos)
136  throw error::State(_Fmt{"unable to drill down to depth %d: "
137  "element %s at pos %d in path %s is in "
138  "contradiction to actual UI structure"}
139  % pos
140  % (depth<path.size()? path[depth] : Symbol::BOTTOM)
141  % depth
142  % path
143  );
145  childNavigator (node, depth));
146  }
147 
148  private:
149  Literal
150  getFirstWindow()
151  {
152  return Symbol{*tree_.keys()};
153  }
154  Literal
155  getCurrentWindow()
156  {
157  return Symbol{lib::pull_last (tree_.keys())};
158  } // special convention for unit-tests
159 
160  Literal
161  resolveElm (UICoord const& path, size_t depth)
162  {
163  REQUIRE (path.isPresent(depth));
164  return depth==UIC_WINDOW? GenNodeLocationQuery::determineAnchor(path)
165  : path[depth];
166  }
167 
168 
169  Rec const&
170  drillDown (Rec const& tree, UICoord const& path, size_t maxDepth, size_t& depth)
171  {
172  if (depth<maxDepth and path.isPresent(depth))
173  {
174  const char* pathElm = resolveElm (path, depth);
175  if (hasNode (tree, pathElm, depth))
176  {
177  ++depth;
178  return drillDown (descendInto(tree,depth-1,pathElm), path, maxDepth, depth);
179  }
180  }
181  return tree;
182  }
183 
191  static bool
192  hasNode (Rec const& tree, const char* pathElm, size_t depth)
193  {
194  return depth==UIC_PERSP? pathElm == tree.getType()
195  : tree.hasAttribute(pathElm);
196  }
197 
199  static Rec const&
200  descendInto (Rec const& tree, size_t depth, const char* pathElm)
201  {
202  return depth==UIC_PERSP? tree // perspective info is attached as type at the parent node
203  : tree.get(pathElm).data.get<Rec>();
204  }
205 
206 
207 
208 
209  /* ==== iterate over siblings with the ability to expand one node's children ==== */
210 
214  static TreeStructureNavigator*
215  childNavigator (Rec const& node, size_t depth)
216  {
218  auto internedString = [](string const& id) -> Literal
219  {
220  return Symbol{id};
221  };
222  return depth==UIC_PERSP? buildNavigator (node, depth, singleValIterator (internedString (node.getType())))
223  : buildNavigator (node, depth, transformIterator (node.keys(), internedString));
224  }
225 
226 
234  template<class PAR>
236  : public PAR
237  {
238  Rec const& pos_;
239  size_t depth_;
240 
241  virtual TreeStructureNavigator*
242  expandChildren() const override
243  {
244  return childNavigator (descendInto (pos_,depth_, currentChild_), depth_+1);
245  }
246 
248  // The design of IterSource attempts to be too clever, and we have to pay for it now...
249  // If IterSource would just work like a StateCore and expose the "current element" via API call,
250  // then we'd be able to retrieve the name of the current child node. Unfortunately it doesn't
251  // and thus we rig a "wire tap" here and capture the node names whenever an iteration happens.
252  //
253  Literal currentChild_ = Symbol::BOTTOM;
254 
255  using Pos = typename PAR::Pos;
256 
257  virtual Pos
258  firstResult () override
259  {
260  Pos pos = PAR::firstResult();
261  if (pos) currentChild_ = *pos;
262  return pos;
263  }
264 
265  virtual void
266  nextResult(Pos& pos) override
267  {
268  PAR::nextResult (pos);
269  if (pos) currentChild_ = *pos;
270  }
272 
273 
274  public:
275  template<class IT>
276  GenNodeNavigator(Rec const& node, size_t depth, IT&& rawChildIter)
277  : PAR{forward<IT> (rawChildIter)}
278  , pos_{node}
279  , depth_{depth}
280  { }
281  };
282 
283 
285  template<class IT>
286  static TreeStructureNavigator*
287  buildNavigator (Rec const& node, size_t depth, IT && rawIterator)
288  {
289  return new GenNodeNavigator<
291  TreeStructureNavigator>> {node, depth, forward<IT> (rawIterator)};
292  }
293  };
294 
295 
296 
297 }}// namespace stage::interact
298 #endif /*STAGE_INTERACT_GEN_NODE_LOCATION_QUERY_H*/
Test/Diagnostics: implementation of the LocationQuery-API based on a abstract topological structure g...
Describe a location within the UI through structural/topological coordinates.
Definition: ui-coord.hpp:129
virtual size_t determineCoverage(UICoord const &path) override
evaluate to what extent a UIcoord spec matches the structure given as GenNode tree ...
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Front-end for printf-style string template interpolation.
virtual ChildIter getChildren(UICoord const &path, size_t pos) override
get the sequence of child IDs at a designated position in the backing GenNode tree ...
virtual Literal determineAnchor(UICoord const &path) override
resolve Anchor against GenNode tree
A front-end for using printf-style formatting.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Token or Atom with distinct identity.
Definition: symbol.hpp:117
static bool hasNode(Rec const &tree, const char *pathElm, size_t depth)
does the guiding tree contain the element as requested by the UICoord path?
static Rec const & descendInto(Rec const &tree, size_t depth, const char *pathElm)
within tree at level depth descend into the child element designated by pathElm
Marker types to indicate a literal string and a Symbol.
Helper to navigate a tree topology represented as GenNode tree.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Interface to locate and move within a tree shaped structure.
const Symbol UIC_CURRENT_WINDOW
window spec to refer to the current window
static TreeStructureNavigator * childNavigator(Rec const &node, size_t depth)
Generic building block for tree shaped (meta)data structures.
auto singleValIterator(VAL &&something)
Build a SingleValIter: convenience free function shortcut, to pick up just any value and wrap it as L...
Definition: itertools.hpp:655
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...
Evaluation of UI coordinates against a concrete window topology.
Helpers for working with iterators based on the pipeline model.
const Symbol UIC_FIRST_WINDOW
window spec to refer to the first window of the application
Building tree expanding and backtracking evaluations within hierarchical scopes.
auto transformIterator(IT const &src, FUN processingFunc)
Build a TransformIter: convenience free function shortcut, picking up the involved types automaticall...
Definition: itertools.hpp:788
object-like record of data.
Definition: record.hpp:141
Extension module to build an opaque data source, accessible as Lumiera Forward Iterator.
Standard implementation of the IterSource interface: a wrapped "Lumiera Forward Iterator".
static TreeStructureNavigator * buildNavigator(Rec const &node, size_t depth, IT &&rawIterator)
type rebinding helper to pick up the concrete child iterator type IT