Lumiera  0.pre.03
»edit your freedom«
ui-location-solver.hpp
Go to the documentation of this file.
1 /*
2  UI-LOCATION-SOLVER.hpp - decide upon a possible location for some UI component
3 
4  Copyright (C)
5  2018, 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 
61 #ifndef STAGE_INTERACT_UI_LOCATION_SOLVER_H
62 #define STAGE_INTERACT_UI_LOCATION_SOLVER_H
63 
64 #include "lib/error.hpp"
65 #include "lib/symbol.hpp"
66 #include "lib/format-util.hpp"
69 #include "lib/nocopy.hpp"
70 
71 #include <utility>
72 #include <vector>
73 #include <string>
74 
75 
76 namespace stage {
77 namespace interact {
78 
79  using lib::Literal;
80  using std::string;
81  using std::move;
82 
83 
84  class LocationQuery;
85  using LocationQueryAccess = std::function<LocationQuery&()>;
86 
87 
88 
89 
98  {
99  UICoord pattern;
100  bool createParents;
101 
102 
103  LocationClause (UICoord && locationPattern, bool allowCreate =false)
104  : pattern{move (locationPattern)}
105  , createParents{allowCreate}
106  { }
108  : pattern{move (rr.pattern)}
109  , createParents{rr.createParents}
110  { }
111 
112  operator string() const;
113  };
114 
115 
124  {
125  using Clauses = std::vector<LocationClause>;
126 
127  Clauses clauses_;
128 
129  public:
130  LocationRule (LocationClause && firstRule)
131  : clauses_{}
132  {
133  this->append (move (firstRule));
134  }
135  LocationRule (LocationRule && rr)
136  : clauses_{move (rr.clauses_)}
137  { }
138 
139 
140  LocationRule&&
141  append (LocationClause && furtherRule)
142  {
143  clauses_.emplace_back (move (furtherRule));
144  return move (*this);
145  }
146 
147 
149  iterator begin() const { return iterator{clauses_.begin(), clauses_.end()}; }
150  iterator end() const { return iterator(); }
151 
152  operator string() const;
153  };
154 
155 
156 
157 
158  /* ==== Support of UI-Coordinate notation within the ViewSpec-DSL ==== */
159 
166  inline
167  UICoord::Builder::operator LocationClause()
168  {
169  return LocationClause{move(*this), false};
170  }
171 
174  inline LocationClause
176  {
177  return LocationClause{move(*this), true};
178  }
179 
180 
187  inline LocationRule
188  operator or (UICoord::Builder && firstRule, UICoord secondRule)
189  {
190  return LocationRule{move (firstRule)}
191  .append (move (secondRule));
192  }
193 
194  inline LocationRule&&
195  operator or (LocationRule && ruleSet, UICoord furtherRule)
196  {
197  ruleSet.append (move (furtherRule));
198  return move(ruleSet);
199  }
200 
201 
202 
203  /* === diagnostics === */
204 
205  inline
206  LocationClause::operator string() const
207  {
208  return string{pattern}
209  + (createParents? " create!":"");
210  }
211  inline
212  LocationRule::operator string() const
213  {
214  return "=~\t.. "
215  + util::join(clauses_, "\n\tOR ");
216  }
217 
218 
219 
220 
228  {
229  LocationQueryAccess getLocationQuery;
230 
231  public:
232  explicit
233  UILocationSolver (LocationQueryAccess accessor)
234  : getLocationQuery{accessor}
235  { }
236 
237  explicit
238  UILocationSolver (LocationQuery& locationQueryService)
239  : getLocationQuery{[&]() -> LocationQuery& { return locationQueryService; }}
240  { }
241 
242 
256  UICoord
257  solve (LocationRule const& rule, size_t depth, Literal elementTypeID)
258  {
259  for (auto& clause : rule)
260  {
261  // Clauses which do not at least describe an element at parent level
262  // will never lead to a solution and can thus be skipped
263  if (depth+1 < clause.pattern.size()
264  or depth > clause.pattern.size())
265  continue;
266 
267  // try to solve the current Clause by matching against real UI topology
268  UICoordResolver resolver{clause.pattern, getLocationQuery()};
269  preprocess (resolver, clause);
270  resolver.coverPartially(); // now either holds a solution or is empty
271 
272  if (not isnil(resolver) // Solution found!
273  and (clause.createParents // The "create" case requires only some part to exist,
274  or resolver.isCoveredTotally())) // while in the default case we demand complete coverage
275  {
276  if (depth == clause.pattern.size())
277  // append ID of the new element to be created
278  // unless it's already there (and thus exists)
279  resolver.append (elementTypeID);
280  return move (resolver);
281  // use the first suitable solution and exit
282  }
283  else
284  if (clause.createParents and clause.pattern.isExplicit())
285  // allow creation of a totally new path from scratch
286  // as long as it is complete and explicitly given
287  {
288  if (depth == clause.pattern.size())
289  return clause.pattern.append (elementTypeID);
290  else
291  return clause.pattern;
292  }
293  }
294  //all clauses tried without success...
295  return UICoord();
296  }
297 
298  private:
305  void
306  preprocess (UICoordResolver& builder, LocationClause const& clause)
307  {
308  if (clause.createParents
309  and clause.pattern.isComplete())
310  {
311  builder.existentiallyQuantify (UIC_PERSP);
312  }
313  }
314  };
315 
316 
317 
318 
319 }}// namespace stage::interact
320 #endif /*STAGE_INTERACT_UI_LOCATION_SOLVER_H*/
LocationClause create()
interprets the current (inline) builder contents as create clause, which has the meaning "create a ne...
Describe a location within the UI through structural/topological coordinates.
Definition: ui-coord.hpp:129
Service to determine the location of an UI component view.
UICoordResolver && existentiallyQuantify(size_t pos)
mutate to turn a wildcard into existentially quantified. This means to assume (or require) that an el...
UICoord solve(LocationRule const &rule, size_t depth, Literal elementTypeID)
Solve for a location according to the given location rule.
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Mix-Ins to allow or prohibit various degrees of copying and cloning.
A single location specification to be matched and fulfilled.
Marker types to indicate a literal string and a Symbol.
Lumiera GTK UI implementation root.
Definition: guifacade.cpp:37
A topological addressing scheme to designate structural locations within the UI.
Query and mutate UICoord specifications in relation to actual UI topology.
Interface to discover a backing structure for the purpose of path navigation and resolution.
Lumiera error handling (C++ interface).
A rule to determine some location by matching against the UI-tree.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Evaluation of UI coordinates against a concrete window topology.
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
void preprocess(UICoordResolver &builder, LocationClause const &clause)
perform adjustments on the current pattern to support some very specific situations ...