The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
policy_order.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2011 - 2025
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"
22
23#include <cassert>
24
26{
27
28template <bool VW, bool VG, bool VC>
29class bottom_up : public visit_level<VW, walker_base::self>,
30 public visit_level<VG, walker_base::internal>,
31 public visit_level<VC, walker_base::child>
32{
36
37public:
38 explicit bottom_up(widget& root) : root_(root.create_walker()), stack_()
39 {
40 TST_GUI_I << "Constructor: ";
41 while(!visit_child::at_end(*root_)) {
42 stack_.push_back(std::exchange(root_, visit_child::get(*root_)->create_walker()));
43 TST_GUI_I << " Down widget '" << operator*().id() << "'.";
44 }
45
46 if(!at_end()) {
47 TST_GUI_I << " Finished at '" << operator*().id() << "'.\n";
48 } else {
49 TST_GUI_I << " Finished at the end.\n";
50 }
51 }
52
54 {
55 }
56
57 bool at_end() const
58 {
59 return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
60 && visit_child::at_end(*root_);
61 }
62
63 bool next()
64 {
65 if(at_end()) {
66 ERR_GUI_I << "Tried to move beyond end of the iteration range.";
67 throw range_error("Tried to move beyond end of range.");
68 }
69
70 TST_GUI_I << "At '" << operator*().id() << "'.";
71
72 /***** WIDGET *****/
73 TST_GUI_I << " Iterate widget:";
74 if(!visit_widget::at_end(*root_)) {
75 switch(visit_widget::next(*root_)) {
77 TST_GUI_I << " visit '" << operator*().id() << "'.\n";
78 return true;
80 TST_GUI_I << " reached the end.";
81 break;
83 TST_GUI_I << "\n";
84 ERR_GUI_E << "Tried to move beyond end of "
85 "the widget iteration range.";
86 throw range_error("Tried to move beyond end of range.");
87 }
88 } else {
89 TST_GUI_I << " failed.";
90 }
91
92 /***** GRID *****/
93 TST_GUI_I << " Iterate grid:";
94 if(!visit_grid::at_end(*root_)) {
95 switch(visit_grid::next(*root_)) {
97 TST_GUI_I << " visit '" << operator*().id() << "'.\n";
98 return true;
100 TST_GUI_I << " reached the end.";
101 break;
103 TST_GUI_I << "\n";
104 ERR_GUI_E << "Tried to move beyond end of "
105 "the grid iteration range.";
106 throw range_error("Tried to move beyond end of range.");
107 }
108 } else {
109 TST_GUI_I << " failed.";
110 }
111
112 /***** TRAVERSE CHILDREN *****/
113
114 TST_GUI_I << " Iterate child:";
115 if(visit_child::at_end(*root_)) {
116 if(stack_.empty()) {
117 TST_GUI_I << " Finished iteration.\n";
118 return false;
119 } else {
120 root_ = std::move(stack_.back());
121 stack_.pop_back();
122 TST_GUI_I << " Up '" << operator*().id() << "'.";
123 }
124 }
125 TST_GUI_I << " Iterate child:";
126 if(!visit_child::at_end(*root_)) {
127 switch(visit_child::next(*root_)) {
129 TST_GUI_I << " visit '" << operator*().id() << "'.";
130 break;
132 TST_GUI_I << " reached the end.";
133 break;
135 TST_GUI_I << "\n";
136 ERR_GUI_E << "Tried to move beyond end of "
137 "the child iteration range.";
138 throw range_error("Tried to move beyond end of range.");
139 }
140 } else {
141 TST_GUI_I << " already at the end.";
142 }
143
144 while(!visit_child::at_end(*root_)) {
145 stack_.push_back(std::exchange(root_, visit_child::get(*root_)->create_walker()));
146 TST_GUI_I << " Down widget '" << operator*().id() << "'.";
147 }
148 TST_GUI_I << " Visit '" << operator*().id() << "'.\n";
149 return true;
150 }
151
153 {
154 if(at_end()) {
155 ERR_GUI_I << "Tried to defer beyond end its "
156 "iteration range iterator.";
157 throw logic_error("Tried to defer an invalid iterator.");
158 }
159 if(!visit_widget::at_end(*root_)) {
160 return *visit_widget::get(*root_);
161 }
162 if(!visit_grid::at_end(*root_)) {
163 return *visit_grid::get(*root_);
164 }
165 if(!visit_child::at_end(*root_)) {
166 return *visit_child::get(*root_);
167 }
168 ERR_GUI_I << "The iterator ended in an unknown "
169 "state while deferring itself.";
170 throw logic_error("Tried to defer an invalid iterator.");
171 }
172
173private:
175
176 std::vector<iteration::walker_ptr> stack_;
177};
178
179template <bool VW, bool VG, bool VC>
180class top_down : public visit_level<VW, walker_base::self>,
181 public visit_level<VG, walker_base::internal>,
182 public visit_level<VC, walker_base::child>
183{
187
188public:
189 explicit top_down(widget& root) : root_(root.create_walker()), stack_()
190 {
191 }
192
194 {
195 }
196
197 bool at_end() const
198 {
199 if(!root_) return true;
200 return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
201 && visit_child::at_end(*root_);
202 }
203
204 bool next()
205 {
206 if(at_end()) {
207 ERR_GUI_I << "Tried to move beyond end of the iteration range.";
208 throw range_error("Tried to move beyond end of range.");
209 }
210
211 TST_GUI_I << "At '" << operator*().id() << "'.";
212
213 /***** WIDGET *****/
214 TST_GUI_I << " Iterate widget:";
215 if(!visit_widget::at_end(*root_)) {
216 switch(visit_widget::next(*root_)) {
218 TST_GUI_I << " visit '" << operator*().id() << "'.\n";
219 return true;
221 TST_GUI_I << " reached the end.";
222 break;
224 TST_GUI_I << "\n";
225 ERR_GUI_E << "Tried to move beyond end of the "
226 "widget iteration range.";
227 throw range_error("Tried to move beyond end of range.");
228 }
229 } else {
230 TST_GUI_I << " failed.";
231 }
232
233 /***** GRID *****/
234 TST_GUI_I << " Iterate grid:";
235 if(!visit_grid::at_end(*root_)) {
236 switch(visit_grid::next(*root_)) {
238 TST_GUI_I << " visit '" << operator*().id() << "'.\n";
239 return true;
241 TST_GUI_I << " reached the end.";
242 break;
244 TST_GUI_I << "\n";
245 ERR_GUI_E << "Tried to move beyond end of the grid "
246 "iteration range.";
247 throw range_error("Tried to move beyond end of range.");
248 }
249 } else {
250 TST_GUI_I << " failed.";
251 }
252
253 /***** TRAVERSE CHILDREN *****/
254
255 TST_GUI_I << " Iterate child:";
256 if(visit_child::at_end(*root_)) {
257 TST_GUI_I << " reached the end.";
258 up();
259 } else {
260 TST_GUI_I << " proceed.";
261 }
262
263 if(!visit_child::at_end(*root_)) {
264 stack_.push_back(std::exchange(root_, visit_child::get(*root_)->create_walker()));
265
266 assert(root_);
267 TST_GUI_I << " Down and visit '" << operator*().id() << "'.\n";
268 if(at_end()) up();
269 return true;
270 }
271
272 TST_GUI_I << " Finished iteration.\n";
273 return false;
274 }
275
277 {
278 if(at_end()) {
279 ERR_GUI_I << "Tried to defer beyond end of the iteration "
280 "range iterator.";
281 throw logic_error("Tried to defer an invalid iterator.");
282 }
283 if(!visit_widget::at_end(*root_)) {
284 return *visit_widget::get(*root_);
285 }
286 if(!visit_grid::at_end(*root_)) {
287 return *visit_grid::get(*root_);
288 }
289 if(!visit_child::at_end(*root_)) {
290 return *visit_child::get(*root_);
291 }
292 ERR_GUI_I << "The iterator ended in an unknown "
293 "state while deferring iteself.";
294 throw logic_error("Tried to defer an invalid iterator.");
295 }
296
297private:
298 bool up()
299 {
300 while(!stack_.empty()) {
301 root_ = std::move(stack_.back());
302 stack_.pop_back();
303 TST_GUI_I << " Up widget '" << operator*().id() << "'. Iterate:";
304 switch(visit_child::next(*root_)) {
306 TST_GUI_I << " reached '" << operator*().id() << "'.";
307 return true;
309 TST_GUI_I << " failed.";
310 break;
312 throw range_error("Tried to move beyond end of range.");
313 }
314 }
315 return true;
316 }
317
319
320 std::vector<iteration::walker_ptr> stack_;
321};
322
323} // namespace gui2::iteration::policy::order
Thrown when deferring an invalid iterator.
Definition exception.hpp:37
visit_level< VW, walker_base::self > visit_widget
std::vector< iteration::walker_ptr > stack_
visit_level< VG, walker_base::internal > visit_grid
visit_level< VC, walker_base::child > visit_child
visit_level< VC, walker_base::child > visit_child
visit_level< VG, walker_base::internal > visit_grid
std::vector< iteration::walker_ptr > stack_
visit_level< VW, walker_base::self > visit_widget
Helper class to select to visit or skip a level.
Thrown when moving an invalid iterator.
Definition exception.hpp:56
@ invalid
When calling next the following it has the following results.
Definition walker.hpp:69
@ valid
When calling next the following it has the following results.
Definition walker.hpp:58
Base class for all widgets.
Definition widget.hpp:55
const std::string & id() const
Definition widget.cpp:110
Contains the exceptions thrown by the gui2::iteration::iterator classes.
Define the common log macros for the gui toolkit.
#define ERR_GUI_E
Definition log.hpp:38
#define TST_GUI_I
Definition log.hpp:48
#define ERR_GUI_I
Definition log.hpp:52
std::unique_ptr< class walker_base > walker_ptr
Definition widget.hpp:44