The Battle for Wesnoth  1.15.0-dev
policy_order.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
19 #include "gui/core/log.hpp"
20 #include "gui/widgets/widget.hpp"
21 
22 #include <iostream>
23 
24 namespace gui2
25 {
26 
27 namespace iteration
28 {
29 
30 namespace policy
31 {
32 
33 namespace order
34 {
35 
36 template <bool VW, bool VG, bool VC>
37 class bottom_up : public visit_level<VW, walker_base::self>,
38  public visit_level<VG, walker_base::internal>,
39  public visit_level<VC, walker_base::child>
40 {
44 
45 public:
46  explicit bottom_up(widget& root) : root_(root.create_walker()), stack_()
47  {
48  TST_GUI_I << "Constructor: ";
49  while(!visit_child::at_end(*root_)) {
50  stack_.push_back(std::move(root_));
51  root_ = visit_child::get(*stack_.back())->create_walker();
52  TST_GUI_I << " Down widget '" << operator*().id() << "'.";
53  }
54 
55  if(!at_end()) {
56  TST_GUI_I << " Finished at '" << operator*().id() << "'.\n";
57  } else {
58  TST_GUI_I << " Finished at the end.\n";
59  }
60  }
61 
63  {
64  }
65 
66  bool at_end() const
67  {
68  return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
69  && visit_child::at_end(*root_);
70  }
71 
72  bool next()
73  {
74  if(at_end()) {
75  ERR_GUI_I << "Tried to move beyond end of the iteration range."
76  << std::endl;
77  throw range_error("Tried to move beyond end of range.");
78  }
79 
80  TST_GUI_I << "At '" << operator*().id() << "'.";
81 
82  /***** WIDGET *****/
83  TST_GUI_I << " Iterate widget:";
84  if(!visit_widget::at_end(*root_)) {
85  switch(visit_widget::next(*root_)) {
86  case walker_base::valid:
87  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
88  return true;
90  TST_GUI_I << " reached the end.";
91  break;
92  case walker_base::fail:
93  TST_GUI_I << "\n";
94  ERR_GUI_E << "Tried to move beyond end of "
95  "the widget iteration range.\n";
96  throw range_error("Tried to move beyond end of range.");
97  }
98  } else {
99  TST_GUI_I << " failed.";
100  }
101 
102  /***** GRID *****/
103  TST_GUI_I << " Iterate grid:";
104  if(!visit_grid::at_end(*root_)) {
105  switch(visit_grid::next(*root_)) {
106  case walker_base::valid:
107  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
108  return true;
110  TST_GUI_I << " reached the end.";
111  break;
112  case walker_base::fail:
113  TST_GUI_I << "\n";
114  ERR_GUI_E << "Tried to move beyond end of "
115  "the grid iteration range.\n";
116  throw range_error("Tried to move beyond end of range.");
117  }
118  } else {
119  TST_GUI_I << " failed.";
120  }
121 
122  /***** TRAVERSE CHILDREN *****/
123 
124  TST_GUI_I << " Iterate child:";
125  if(visit_child::at_end(*root_)) {
126  if(stack_.empty()) {
127  TST_GUI_I << " Finished iteration.\n";
128  return false;
129  } else {
130  root_ = std::move(stack_.back());
131  stack_.pop_back();
132  TST_GUI_I << " Up '" << operator*().id() << "'.";
133  }
134  }
135  TST_GUI_I << " Iterate child:";
136  if(!visit_child::at_end(*root_)) {
137  switch(visit_child::next(*root_)) {
138  case walker_base::valid:
139  TST_GUI_I << " visit '" << operator*().id() << "'.";
140  break;
142  TST_GUI_I << " reached the end.";
143  break;
144  case walker_base::fail:
145  TST_GUI_I << "\n";
146  ERR_GUI_E << "Tried to move beyond end of "
147  "the child iteration range.\n";
148  throw range_error("Tried to move beyond end of range.");
149  }
150  } else {
151  TST_GUI_I << " already at the end.";
152  }
153 
154  while(!visit_child::at_end(*root_)) {
155  stack_.push_back(std::move(root_));
156  root_ = visit_child::get(*stack_.back())->create_walker();
157  TST_GUI_I << " Down widget '" << operator*().id() << "'.";
158  }
159  TST_GUI_I << " Visit '" << operator*().id() << "'.\n";
160  return true;
161  }
162 
164  {
165  if(at_end()) {
166  ERR_GUI_I << "Tried to defer beyond end its "
167  "iteration range iterator.\n";
168  throw logic_error("Tried to defer an invalid iterator.");
169  }
170  if(!visit_widget::at_end(*root_)) {
171  return *visit_widget::get(*root_);
172  }
173  if(!visit_grid::at_end(*root_)) {
174  return *visit_grid::get(*root_);
175  }
176  if(!visit_child::at_end(*root_)) {
177  return *visit_child::get(*root_);
178  }
179  ERR_GUI_I << "The iterator ended in an unknown "
180  "state while deferring itself.\n";
181  throw logic_error("Tried to defer an invalid iterator.");
182  }
183 
184 private:
186 
187  std::vector<iteration::walker_ptr> stack_;
188 };
189 
190 template <bool VW, bool VG, bool VC>
191 class top_down : public visit_level<VW, walker_base::self>,
192  public visit_level<VG, walker_base::internal>,
193  public visit_level<VC, walker_base::child>
194 {
198 
199 public:
200  explicit top_down(widget& root) : root_(root.create_walker()), stack_()
201  {
202  }
203 
205  {
206  }
207 
208  bool at_end() const
209  {
210  return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
211  && visit_child::at_end(*root_);
212  }
213 
214  bool next()
215  {
216  if(at_end()) {
217  ERR_GUI_I << "Tried to move beyond end of the iteration range."
218  << std::endl;
219  throw range_error("Tried to move beyond end of range.");
220  }
221 
222  TST_GUI_I << "At '" << operator*().id() << "'.";
223 
224  /***** WIDGET *****/
225  TST_GUI_I << " Iterate widget:";
226  if(!visit_widget::at_end(*root_)) {
227  switch(visit_widget::next(*root_)) {
228  case walker_base::valid:
229  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
230  return true;
232  TST_GUI_I << " reached the end.";
233  break;
234  case walker_base::fail:
235  TST_GUI_I << "\n";
236  ERR_GUI_E << "Tried to move beyond end of the "
237  "widget iteration range.\n";
238  throw range_error("Tried to move beyond end of range.");
239  }
240  } else {
241  TST_GUI_I << " failed.";
242  }
243 
244  /***** GRID *****/
245  TST_GUI_I << " Iterate grid:";
246  if(!visit_grid::at_end(*root_)) {
247  switch(visit_grid::next(*root_)) {
248  case walker_base::valid:
249  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
250  return true;
252  TST_GUI_I << " reached the end.";
253  break;
254  case walker_base::fail:
255  TST_GUI_I << "\n";
256  ERR_GUI_E << "Tried to move beyond end of the grid "
257  "iteration range.\n";
258  throw range_error("Tried to move beyond end of range.");
259  }
260  } else {
261  TST_GUI_I << " failed.";
262  }
263 
264  /***** TRAVERSE CHILDREN *****/
265 
266  TST_GUI_I << " Iterate child:";
267  if(visit_child::at_end(*root_)) {
268  TST_GUI_I << " reached the end.";
269  up();
270  } else {
271  TST_GUI_I << " proceed.";
272  }
273 
274  if(!visit_child::at_end(*root_)) {
275  stack_.push_back(std::move(root_));
276  root_ = visit_child::get(*stack_.back())->create_walker();
277 
278  assert(root_);
279  assert(!at_end());
280  TST_GUI_I << " Down and visit '" << operator*().id() << "'.\n";
281  return true;
282  }
283 
284  TST_GUI_I << " Finished iteration.\n";
285  return false;
286  }
287 
289  {
290  if(at_end()) {
291  ERR_GUI_I << "Tried to defer beyond end of the iteration "
292  "range iterator.\n";
293  throw logic_error("Tried to defer an invalid iterator.");
294  }
295  if(!visit_widget::at_end(*root_)) {
296  return *visit_widget::get(*root_);
297  }
298  if(!visit_grid::at_end(*root_)) {
299  return *visit_grid::get(*root_);
300  }
301  if(!visit_child::at_end(*root_)) {
302  return *visit_child::get(*root_);
303  }
304  ERR_GUI_I << "The iterator ended in an unknown "
305  "state while deferring iteself.\n";
306  throw logic_error("Tried to defer an invalid iterator.");
307  }
308 
309 private:
310  bool up()
311  {
312  while(!stack_.empty()) {
313  root_ = std::move(stack_.back());
314  stack_.pop_back();
315  TST_GUI_I << " Up widget '" << operator*().id() << "'. Iterate:";
316  switch(visit_child::next(*root_)) {
317  case walker_base::valid:
318  TST_GUI_I << " reached '" << operator*().id() << "'.";
319  return true;
321  TST_GUI_I << " failed.";
322  break;
323  case walker_base::fail:
324  throw range_error("Tried to move beyond end of range.");
325  }
326  }
327  return true;
328  }
329 
331 
332  std::vector<iteration::walker_ptr> stack_;
333 };
334 
335 } // namespace order
336 
337 } // namespace policy
338 
339 } // namespace iteration
340 
341 } // namespace gui2
Define the common log macros for the gui toolkit.
#define ERR_GUI_E
Definition: log.hpp:37
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:38
When calling next the following it has the following results.
Definition: walker.hpp:68
When calling next the following it has the following results.
Definition: walker.hpp:57
const std::string & id() const
Definition: widget.cpp:106
Helper class to select to visit or skip a level.
Base class for all widgets.
Definition: widget.hpp:48
Contains the exceptions thrown by the gui2::iteration::iterator classes.
Generic file dialog.
Definition: field-fwd.hpp:22
visit_level< VW, walker_base::self > visit_widget
visit_level< VC, walker_base::child > visit_child
visit_level< VW, walker_base::self > visit_widget
std::vector< iteration::walker_ptr > stack_
Thrown when moving an invalid iterator.
Definition: exception.hpp:56
#define TST_GUI_I
Definition: log.hpp:46
visit_level< VC, walker_base::child > visit_child
CURSOR_TYPE get()
Definition: cursor.cpp:213
visit_level< VG, walker_base::internal > visit_grid
#define ERR_GUI_I
Definition: log.hpp:54
#define next(ls)
Definition: llex.cpp:32
Thrown when deferring an invalid iterator.
Definition: exception.hpp:38
std::vector< iteration::walker_ptr > stack_
visit_level< VG, walker_base::internal > visit_grid