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) Lumiera.org
5  2018, 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 
70 #ifndef STAGE_INTERACT_UI_LOCATION_SOLVER_H
71 #define STAGE_INTERACT_UI_LOCATION_SOLVER_H
72 
73 #include "lib/error.hpp"
74 #include "lib/symbol.hpp"
75 #include "lib/format-util.hpp"
78 #include "lib/nocopy.hpp"
79 
80 #include <utility>
81 #include <vector>
82 #include <string>
83 
84 
85 namespace stage {
86 namespace interact {
87 
88  using lib::Literal;
89  using std::string;
90  using std::move;
91 
92 
93  class LocationQuery;
94  using LocationQueryAccess = std::function<LocationQuery&()>;
95 
96 
97 
98 
107  {
108  UICoord pattern;
109  bool createParents;
110 
111 
112  LocationClause (UICoord && locationPattern, bool allowCreate =false)
113  : pattern{move (locationPattern)}
114  , createParents{allowCreate}
115  { }
117  : pattern{move (rr.pattern)}
118  , createParents{rr.createParents}
119  { }
120 
121  operator string() const;
122  };
123 
124 
133  {
134  using Clauses = std::vector<LocationClause>;
135 
136  Clauses clauses_;
137 
138  public:
139  LocationRule (LocationClause && firstRule)
140  : clauses_{}
141  {
142  this->append (move (firstRule));
143  }
144  LocationRule (LocationRule && rr)
145  : clauses_{move (rr.clauses_)}
146  { }
147 
148 
149  LocationRule&&
150  append (LocationClause && furtherRule)
151  {
152  clauses_.emplace_back (move (furtherRule));
153  return move (*this);
154  }
155 
156 
158  iterator begin() const { return iterator{clauses_.begin(), clauses_.end()}; }
159  iterator end() const { return iterator(); }
160 
161  operator string() const;
162  };
163 
164 
165 
166 
167  /* ==== Support of UI-Coordinate notation within the ViewSpec-DSL ==== */
168 
175  inline
176  UICoord::Builder::operator LocationClause()
177  {
178  return LocationClause{move(*this), false};
179  }
180 
183  inline LocationClause
185  {
186  return LocationClause{move(*this), true};
187  }
188 
189 
196  inline LocationRule
197  operator or (UICoord::Builder && firstRule, UICoord secondRule)
198  {
199  return LocationRule{move (firstRule)}
200  .append (move (secondRule));
201  }
202 
203  inline LocationRule&&
204  operator or (LocationRule && ruleSet, UICoord furtherRule)
205  {
206  ruleSet.append (move (furtherRule));
207  return move(ruleSet);
208  }
209 
210 
211 
212  /* === diagnostics === */
213 
214  inline
215  LocationClause::operator string() const
216  {
217  return string{pattern}
218  + (createParents? " create!":"");
219  }
220  inline
221  LocationRule::operator string() const
222  {
223  return "=~\t.. "
224  + util::join(clauses_, "\n\tOR ");
225  }
226 
227 
228 
229 
237  {
238  LocationQueryAccess getLocationQuery;
239 
240  public:
241  explicit
242  UILocationSolver (LocationQueryAccess accessor)
243  : getLocationQuery{accessor}
244  { }
245 
246  explicit
247  UILocationSolver (LocationQuery& locationQueryService)
248  : getLocationQuery{[&]() -> LocationQuery& { return locationQueryService; }}
249  { }
250 
251 
265  UICoord
266  solve (LocationRule const& rule, size_t depth, Literal elementTypeID)
267  {
268  for (auto& clause : rule)
269  {
270  // Clauses which do not at least describe an element at parent level
271  // will never lead to a solution and can thus be skipped
272  if (depth+1 < clause.pattern.size()
273  or depth > clause.pattern.size())
274  continue;
275 
276  // try to solve the current Clause by matching against real UI topology
277  UICoordResolver resolver{clause.pattern, getLocationQuery()};
278  preprocess (resolver, clause);
279  resolver.coverPartially(); // now either holds a solution or is empty
280 
281  if (not isnil(resolver) // Solution found!
282  and (clause.createParents // The "create" case requires only some part to exist,
283  or resolver.isCoveredTotally())) // while in the default case we demand complete coverage
284  {
285  if (depth == clause.pattern.size())
286  // append ID of the new element to be created
287  // unless it's already there (and thus exists)
288  resolver.append (elementTypeID);
289  return move (resolver);
290  // use the first suitable solution and exit
291  }
292  else
293  if (clause.createParents and clause.pattern.isExplicit())
294  // allow creation of a totally new path from scratch
295  // as long as it is complete and explicitly given
296  {
297  if (depth == clause.pattern.size())
298  return clause.pattern.append (elementTypeID);
299  else
300  return clause.pattern;
301  }
302  }
303  //all clauses tried without success...
304  return UICoord();
305  }
306 
307  private:
314  void
315  preprocess (UICoordResolver& builder, LocationClause const& clause)
316  {
317  if (clause.createParents
318  and clause.pattern.isComplete())
319  {
320  builder.existentiallyQuantify (UIC_PERSP);
321  }
322  }
323  };
324 
325 
326 
327 
328 }}// namespace stage::interact
329 #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:138
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:46
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
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:46
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 ...