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) Lumiera.org
5  2017, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
61 #ifndef STAGE_INTERACT_GEN_NODE_LOCATION_QUERY_H
62 #define STAGE_INTERACT_GEN_NODE_LOCATION_QUERY_H
63 
64 #include "lib/error.hpp"
65 #include "lib/symbol.hpp"
67 #include "lib/diff/gen-node.hpp"
68 #include "lib/format-string.hpp"
69 #include "lib/iter-explorer.hpp"
70 #include "lib/iter-source.hpp"
71 #include "lib/itertools.hpp"
72 #include "lib/util.hpp"
73 
74 #include <utility>
75 #include <string>
76 
77 
78 namespace stage {
79 namespace interact {
80 
81  namespace error = lumiera::error;
82 
83  using lib::Symbol;
84  using lib::Literal;
85  using lib::diff::Rec;
86  using util::isnil;
87  using util::_Fmt;
88  using std::forward;
89  using std::string;
90 
91 
92 
93 
100  : public LocationQuery
101  {
102  Rec tree_;
103 
104  public:
105  template<class REC>
106  GenNodeLocationQuery(REC&& backingStructure)
107  : tree_(std::forward<REC>(backingStructure))
108  { }
109 
110 
111  /* === LocationQuery interface === */
112 
114  virtual Literal
115  determineAnchor (UICoord const& path) override
116  {
117  if (isnil(tree_) or not path.isPresent(UIC_WINDOW))
118  return Symbol::BOTTOM;
119  if (UIC_FIRST_WINDOW == path.getWindow())
120  return getFirstWindow();
121  if (UIC_CURRENT_WINDOW == path.getWindow())
122  return getCurrentWindow();
123  if (not tree_.hasAttribute(string{path.getWindow()}))
124  return Symbol::BOTTOM;
125  return path.getWindow();
126  }
127 
128 
130  virtual size_t
131  determineCoverage (UICoord const& path) override
132  {
133  size_t depth = 0;
134  drillDown (tree_, path, path.size(), depth);
135  return depth;
136  }
137 
139  virtual ChildIter
140  getChildren (UICoord const& path, size_t pos) override
141  {
142  size_t depth = 0;
143  Rec const& node = drillDown (tree_, path, pos, depth);
144  if (depth != pos)
145  throw error::State(_Fmt{"unable to drill down to depth %d: "
146  "element %s at pos %d in path %s is in "
147  "contradiction to actual UI structure"}
148  % pos
149  % (depth<path.size()? path[depth] : Symbol::BOTTOM)
150  % depth
151  % path
152  );
154  childNavigator (node, depth));
155  }
156 
157  private:
158  Literal
159  getFirstWindow()
160  {
161  return Symbol{*tree_.keys()};
162  }
163  Literal
164  getCurrentWindow()
165  {
166  return Symbol{lib::pull_last (tree_.keys())};
167  } // special convention for unit-tests
168 
169  Literal
170  resolveElm (UICoord const& path, size_t depth)
171  {
172  REQUIRE (path.isPresent(depth));
173  return depth==UIC_WINDOW? GenNodeLocationQuery::determineAnchor(path)
174  : path[depth];
175  }
176 
177 
178  Rec const&
179  drillDown (Rec const& tree, UICoord const& path, size_t maxDepth, size_t& depth)
180  {
181  if (depth<maxDepth and path.isPresent(depth))
182  {
183  const char* pathElm = resolveElm (path, depth);
184  if (hasNode (tree, pathElm, depth))
185  {
186  ++depth;
187  return drillDown (descendInto(tree,depth-1,pathElm), path, maxDepth, depth);
188  }
189  }
190  return tree;
191  }
192 
200  static bool
201  hasNode (Rec const& tree, const char* pathElm, size_t depth)
202  {
203  return depth==UIC_PERSP? pathElm == tree.getType()
204  : tree.hasAttribute(pathElm);
205  }
206 
208  static Rec const&
209  descendInto (Rec const& tree, size_t depth, const char* pathElm)
210  {
211  return depth==UIC_PERSP? tree // perspective info is attached as type at the parent node
212  : tree.get(pathElm).data.get<Rec>();
213  }
214 
215 
216 
217 
218  /* ==== iterate over siblings with the ability to expand one node's children ==== */
219 
223  static TreeStructureNavigator*
224  childNavigator (Rec const& node, size_t depth)
225  {
227  auto internedString = [](string const& id) -> Literal
228  {
229  return Symbol{id};
230  };
231  return depth==UIC_PERSP? buildNavigator (node, depth, singleValIterator (internedString (node.getType())))
232  : buildNavigator (node, depth, transformIterator (node.keys(), internedString));
233  }
234 
235 
243  template<class PAR>
245  : public PAR
246  {
247  Rec const& pos_;
248  size_t depth_;
249 
250  virtual TreeStructureNavigator*
251  expandChildren() const override
252  {
253  return childNavigator (descendInto (pos_,depth_, currentChild_), depth_+1);
254  }
255 
257  // The design of IterSource attempts to be too clever, and we have to pay for it now...
258  // If IterSource would just work like a StateCore and expose the "current element" via API call,
259  // then we'd be able to retrieve the name of the current child node. Unfortunately it doesn't
260  // and thus we rig a "wire tap" here and capture the node names whenever an iteration happens.
261  //
262  Literal currentChild_ = Symbol::BOTTOM;
263 
264  using Pos = typename PAR::Pos;
265 
266  virtual Pos
267  firstResult () override
268  {
269  Pos pos = PAR::firstResult();
270  if (pos) currentChild_ = *pos;
271  return pos;
272  }
273 
274  virtual void
275  nextResult(Pos& pos) override
276  {
277  PAR::nextResult (pos);
278  if (pos) currentChild_ = *pos;
279  }
281 
282 
283  public:
284  template<class IT>
285  GenNodeNavigator(Rec const& node, size_t depth, IT&& rawChildIter)
286  : PAR{forward<IT> (rawChildIter)}
287  , pos_{node}
288  , depth_{depth}
289  { }
290  };
291 
292 
294  template<class IT>
295  static TreeStructureNavigator*
296  buildNavigator (Rec const& node, size_t depth, IT && rawIterator)
297  {
298  return new GenNodeNavigator<
300  TreeStructureNavigator>> {node, depth, forward<IT> (rawIterator)};
301  }
302  };
303 
304 
305 
306 }}// namespace stage::interact
307 #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:138
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:85
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:199
Token or Atom with distinct identity.
Definition: symbol.hpp:126
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:46
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:664
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:797
object-like record of data.
Definition: record.hpp:150
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