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