The Battle for Wesnoth  1.17.4+dev
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2022
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "gui/widgets/pane.hpp"
19 
22 #include "gui/core/log.hpp"
23 #include "gui/widgets/grid.hpp"
24 #include "gui/widgets/window.hpp"
25 #include "utils/const_clone.hpp"
27 #include "gettext.hpp"
28 #include "lexical_cast.hpp"
29 #include "sdl/rect.hpp"
30 
31 #include <functional>
32 
33 #define LOG_SCOPE_HEADER "pane [" + id() + "] " + __func__
34 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
35 
36 namespace gui2
37 {
38 
39 // ------------ WIDGET -----------{
40 
41 /**
42  * Helper to implement private functions without modifying the header.
43  *
44  * The class is a helper to avoid recompilation and only has static
45  * functions. It also facilitates to create duplicates of functions for a const
46  * and a non-const member function.
47  */
49 {
50  /**
51  * Implementation for the wrappers for
52  * [const] widget* pane::find_at(const point&, const bool) [const].
53  *
54  * @tparam W A pointer to the pane.
55  */
56  template <class W>
58  find_at(W pane, point coordinate, const bool must_be_active)
59  {
60 
61  /*
62  * First test whether the mouse is at the pane.
63  */
64  if(pane->widget::find_at(coordinate, must_be_active) != pane) {
65  return nullptr;
66  }
67 
68  for(auto& item : pane->items_) {
69  if(item.item_grid->get_visible() == widget::visibility::invisible) {
70  continue;
71  }
72 
73  /*
74  * If the adjusted coordinate is in the item's grid let the grid
75  * resolve the coordinate.
76  */
77  if(sdl::point_in_rect(coordinate, item.item_grid->get_rectangle())) {
78  return item.item_grid->find_at(coordinate, must_be_active);
79  }
80  }
81 
82  return nullptr;
83  }
84 
85  /**
86  * Implementation for the wrappers for
87  * [const] grid* pane::grid(const unsigned id) [const].
88  *
89  * @tparam W A pointer to the pane.
90  */
91  template <class W>
93  get_grid(W pane, const unsigned id)
94  {
95  for(auto& item : pane->items_) {
96  if(item.id == id) {
97  return item.item_grid.get();
98  }
99  }
100 
101  return nullptr;
102  }
103 };
104 
106  : widget(builder)
107  , items_()
108  , item_builder_(builder.item_definition)
109  , item_id_generator_(0)
110  , placer_(placer_base::build(builder.grow_dir, builder.parallel_items))
111 {
112  connect_signal<event::REQUEST_PLACEMENT>(
113  std::bind(
114  &pane::signal_handler_request_placement, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
116 }
117 
118 unsigned pane::create_item(const std::map<std::string, string_map>& item_data,
119  const std::map<std::string, std::string>& tags)
120 {
121  item item{item_id_generator_++, tags, std::unique_ptr<grid>{static_cast<grid*>(item_builder_->build().release())}};
122 
123  item.item_grid->set_parent(this);
124 
125  for(const auto & data : item_data)
126  {
127  styled_widget* control
128  = find_widget<styled_widget>(item.item_grid.get(), data.first, false, false);
129 
130  if(control) {
131  control->set_members(data.second);
132  }
133  }
134 
135  items_.push_back(std::move(item));
136 
138  fire(event::REQUEST_PLACEMENT, *this, message);
139 
140  return item.id;
141 }
142 
143 void pane::place(const point& origin, const point& size)
144 {
145  DBG_GUI_L << LOG_HEADER << '\n';
146  widget::place(origin, size);
147 
148  assert(origin.x == 0);
149  assert(origin.y == 0);
150 
151  place_children();
152 }
153 
154 void pane::layout_initialize(const bool full_initialization)
155 {
156  DBG_GUI_D << LOG_HEADER << '\n';
157 
158  widget::layout_initialize(full_initialization);
159 
160  for(auto & item : items_)
161  {
162  if(item.item_grid->get_visible() != widget::visibility::invisible) {
163  item.item_grid->layout_initialize(full_initialization);
164  }
165  }
166 }
167 
168 void pane::impl_draw_children(int x_offset, int y_offset)
169 {
170  DBG_GUI_D << LOG_HEADER << '\n';
171 
172  for(auto & item : items_)
173  {
174  if(item.item_grid->get_visible() != widget::visibility::invisible) {
175  item.item_grid->draw_children(x_offset, y_offset);
176  }
177  }
178 }
179 
181  const std::vector<widget*>& call_stack)
182 {
183  for(auto & item : items_)
184  {
185  std::vector<widget*> child_call_stack = call_stack;
186  item.item_grid->populate_dirty_list(caller, child_call_stack);
187  }
188 }
189 
190 void pane::sort(const compare_functor_t& compare_functor)
191 {
192  items_.sort(compare_functor);
193 
195 }
196 
197 void pane::filter(const filter_functor_t& filter_functor)
198 {
199  for(auto & item : items_)
200  {
201  item.item_grid->set_visible(filter_functor(item)
204  }
205 
207 }
208 
209 void pane::request_reduce_width(const unsigned /*maximum_width*/)
210 {
211 }
212 
213 widget* pane::find_at(const point& coordinate, const bool must_be_active)
214 {
215  return pane_implementation::find_at(this, coordinate, must_be_active);
216 }
217 
219  const bool must_be_active) const
220 {
221  return pane_implementation::find_at(this, coordinate, must_be_active);
222 }
223 
225 {
227  return placer_->get_size();
228 }
229 
231 {
232  return false;
233 }
234 
236 {
237  /**
238  * @todo Implement properly.
239  */
240  return nullptr;
241 }
242 
243 grid* pane::get_grid(const unsigned id)
244 {
245  return pane_implementation::get_grid(this, id);
246 }
247 
248 const grid* pane::get_grid(const unsigned id) const
249 {
250  return pane_implementation::get_grid(this, id);
251 }
252 
254 {
256  unsigned index = 0;
257  for(auto & item : items_)
258  {
259  if(item.item_grid->get_visible() == widget::visibility::invisible) {
260  continue;
261  }
262 
263  const point origin = placer_->get_origin(index);
264  item.item_grid->place(origin, item.item_grid->get_best_size());
265  ++index;
266  }
267 }
268 
270 {
272  unsigned index = 0;
273  for(auto & item : items_)
274  {
275  if(item.item_grid->get_visible() == widget::visibility::invisible) {
276  continue;
277  }
278 
279  const point origin = placer_->get_origin(index);
280  item.item_grid->set_origin(origin);
281  ++index;
282  }
283 }
284 
286 {
288  unsigned index = 0;
289  for(auto & item : items_)
290  {
291  if(item.item_grid->get_visible() == widget::visibility::invisible) {
292  continue;
293  }
294 
295  const point origin = placer_->get_origin(index);
296  if(item.item_grid->get_size() != item.item_grid->get_best_size()) {
297  item.item_grid->place(origin, item.item_grid->get_best_size());
298  } else {
299  item.item_grid->set_origin(origin);
300  }
301  ++index;
302  }
303 }
304 
306 {
307  assert(placer_.get());
308  placer_->initialize();
309 
310  for(const auto & item : items_)
311  {
312  if(item.item_grid->get_visible() == widget::visibility::invisible) {
313  continue;
314  }
315 
316  placer_->add_item(item.item_grid->get_best_size());
317  }
318 }
319 
321  const event::ui_event event,
322  bool& handled)
323 {
324  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
325 
326  widget* wgt = dynamic_cast<widget*>(&dispatcher);
327  if(wgt) {
328  for(auto & item : items_)
329  {
330  if(item.item_grid->has_widget(*wgt)) {
331  if(item.item_grid->get_visible() != widget::visibility::invisible) {
332 
333  /*
334  * This time we call init layout but also the linked widget
335  * update this makes things work properly for the
336  * addon_list. This code can use some more tuning,
337  * polishing and testing.
338  */
339  item.item_grid->layout_initialize(false);
341 
342  /*
343  * By not calling init layout it uses its previous size
344  * what seems to work properly when showing and hiding
345  * items. Might fail with new items (haven't tested yet).
346  */
347  item.item_grid->place(point(), item.item_grid->get_best_size());
348  }
350  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
351  handled = true;
352  return;
353  }
354  }
355  }
356 
357  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
358  assert(false);
359  handled = false;
360 }
361 
362 // }---------- BUILDER -----------{
363 
364 namespace implementation
365 {
366 
367 builder_pane::builder_pane(const config& cfg)
368  : builder_widget(cfg)
369  , grow_dir(*grow_direction::get_enum(cfg["grow_direction"].str()))
370  , parallel_items(cfg["parallel_items"])
371  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
372 {
373  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
374 }
375 
376 std::unique_ptr<widget> builder_pane::build() const
377 {
378  return build(replacements_map());
379 }
380 
381 std::unique_ptr<widget> builder_pane::build(const replacements_map& /*replacements*/) const
382 {
383  return std::make_unique<pane>(*this);
384 }
385 
386 } // namespace implementation
387 
388 // }------------ END --------------
389 
390 } // namespace gui2
Define the common log macros for the gui toolkit.
Contains the info needed to instantiate a widget.
Base class for the placement helper.
Definition: placer.hpp:51
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:39
#define DBG_GUI_L
Definition: log.hpp:55
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:243
std::unique_ptr< grid > item_grid
Definition: pane.hpp:55
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:168
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
static utils::const_clone_ptr< grid, W > get_grid(W pane, const unsigned id)
Implementation for the wrappers for [const] grid* pane::grid(const unsigned id) [const].
Definition: pane.cpp:93
Main class to show messages to the user.
Definition: message.hpp:35
void filter(const filter_functor_t &filter_functor)
Filters the contents of the pane.
Definition: pane.cpp:197
virtual void set_members(const string_map &data)
Sets the members of the styled_widget.
New lexcical_cast header.
std::list< item > items_
The items in the pane.
Definition: pane.hpp:151
unsigned create_item(const std::map< std::string, string_map > &item_data, const std::map< std::string, std::string > &tags)
Creates a new item.
Definition: pane.cpp:118
This file contains the window object, this object is a top level container which has the event manage...
Base class for all widgets.
Definition: widget.hpp:49
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:154
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:60
#define LOG_HEADER
Definition: pane.cpp:34
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:190
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
std::unique_ptr< placer_base > placer_
Helper to do the placement.
Definition: pane.hpp:160
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:320
static std::string _(const char *str)
Definition: gettext.hpp:93
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:269
int x
x coordinate.
Definition: point.hpp:45
void place_children()
Places the children on the pane.
Definition: pane.cpp:253
Generic file dialog.
Definition: field-fwd.hpp:23
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
Definition: pane.cpp:180
#define DBG_GUI_D
Definition: log.hpp:29
The message callbacks hold a reference to a message.
Definition: message.hpp:45
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
Definition: pane.cpp:235
static utils::const_clone_ptr< widget, W > find_at(W pane, point coordinate, const bool must_be_active)
Implementation for the wrappers for [const] widget* pane::find_at(const point&, const bool) [const]...
Definition: pane.cpp:58
Base container class.
Definition: grid.hpp:31
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: pane.cpp:230
The base template for associating string values with enum values.
Definition: enum_base.hpp:30
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:224
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:305
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:47
This file contains the definitions for the gui2::event::message class.
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: pane.cpp:209
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:66
unsigned id
Definition: pane.hpp:52
A pane is a container where new members can be added and removed during run-time. ...
Definition: pane.hpp:43
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:23
virtual std::unique_ptr< widget > build() const override
Definition: pane.cpp:376
#define DBG_GUI_E
Definition: log.hpp:35
The user set the widget invisible, that means:
window * get_window()
Get the parent window.
Definition: widget.cpp:118
Holds a 2D point.
Definition: point.hpp:24
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
Base class for all visible items.
std::function< bool(const item &, const item &)> compare_functor_t
Definition: pane.hpp:58
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:143
Helper to implement private functions without modifying the header.
Definition: pane.cpp:48
pane(const implementation::builder_pane &builder)
Definition: pane.cpp:105
Contains the SDL_Rect helper code.
The user sets the widget visible, that means:
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:69
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:154
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:157
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
int y
y coordinate.
Definition: point.hpp:48
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: pane.cpp:213
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:66
virtual void impl_draw_children(int x_offset, int y_offset) override
See widget::impl_draw_children.
Definition: pane.cpp:168
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:285
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:1071
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:410