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