The Battle for Wesnoth  1.15.0-dev
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "gui/widgets/pane.hpp"
18 
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 "utils/functional.hpp"
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.get();
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, _1, _2, _3),
119 }
120 
121 unsigned pane::create_item(const widget_data& item_data,
122  const std::map<std::string, std::string>& tags)
123 {
124  item item { item_id_generator_++, tags, std::dynamic_pointer_cast<grid>(item_builder_->build()) };
125 
126  item.item_grid->set_parent(this);
127 
128  for(const auto & data : item_data)
129  {
130  styled_widget* control
131  = find_widget<styled_widget>(item.item_grid.get(), data.first, false, false);
132 
133  if(control) {
134  control->set_members(data.second);
135  }
136  }
137 
138  items_.push_back(item);
139 
141  fire(event::REQUEST_PLACEMENT, *this, message);
142 
143  return item.id;
144 }
145 
146 void pane::place(const point& origin, const point& size)
147 {
148  DBG_GUI_L << LOG_HEADER << '\n';
149  widget::place(origin, size);
150 
151  assert(origin.x == 0);
152  assert(origin.y == 0);
153 
154  place_children();
155 }
156 
157 void pane::layout_initialize(const bool full_initialization)
158 {
159  DBG_GUI_D << LOG_HEADER << '\n';
160 
161  widget::layout_initialize(full_initialization);
162 
163  for(auto & item : items_)
164  {
165  if(item.item_grid->get_visible() != widget::visibility::invisible) {
166  item.item_grid->layout_initialize(full_initialization);
167  }
168  }
169 }
170 
171 void
173 {
174  DBG_GUI_D << LOG_HEADER << '\n';
175 
176  for(auto & item : items_)
177  {
178  if(item.item_grid->get_visible() != widget::visibility::invisible) {
179  item.item_grid->draw_children();
180  }
181  }
182 }
183 
184 void pane::sort(const compare_functor_t& compare_functor)
185 {
186  items_.sort(compare_functor);
187 
189 }
190 
191 void pane::filter(const filter_functor_t& filter_functor)
192 {
193  for(auto & item : items_)
194  {
195  item.item_grid->set_visible(filter_functor(item)
198  }
199 
201 }
202 
203 void pane::request_reduce_width(const unsigned /*maximum_width*/)
204 {
205 }
206 
207 widget* pane::find_at(const point& coordinate, const bool must_be_active)
208 {
209  return pane_implementation::find_at(this, coordinate, must_be_active);
210 }
211 
213  const bool must_be_active) const
214 {
215  return pane_implementation::find_at(this, coordinate, must_be_active);
216 }
217 
219 {
221  return placer_->get_size();
222 }
223 
225 {
226  return false;
227 }
228 
230 {
231  return nullptr;
232 }
233 
234 grid* pane::get_grid(const unsigned id)
235 {
236  return pane_implementation::get_grid(this, id);
237 }
238 
239 const grid* pane::get_grid(const unsigned id) const
240 {
241  return pane_implementation::get_grid(this, id);
242 }
243 
245 {
247  unsigned index = 0;
248  for(auto & item : items_)
249  {
250  if(item.item_grid->get_visible() == widget::visibility::invisible) {
251  continue;
252  }
253 
254  const point origin = placer_->get_origin(index);
255  item.item_grid->place(origin, item.item_grid->get_best_size());
256  ++index;
257  }
258 }
259 
261 {
263  unsigned index = 0;
264  for(auto & item : items_)
265  {
266  if(item.item_grid->get_visible() == widget::visibility::invisible) {
267  continue;
268  }
269 
270  const point origin = placer_->get_origin(index);
271  item.item_grid->set_origin(origin);
272  ++index;
273  }
274 }
275 
277 {
279  unsigned index = 0;
280  for(auto & item : items_)
281  {
282  if(item.item_grid->get_visible() == widget::visibility::invisible) {
283  continue;
284  }
285 
286  const point origin = placer_->get_origin(index);
287  if(item.item_grid->get_size() != item.item_grid->get_best_size()) {
288  item.item_grid->place(origin, item.item_grid->get_best_size());
289  } else {
290  item.item_grid->set_origin(origin);
291  }
292  ++index;
293  }
294 }
295 
297 {
298  assert(placer_.get());
299  placer_->initialize();
300 
301  for(const auto & item : items_)
302  {
303  if(item.item_grid->get_visible() == widget::visibility::invisible) {
304  continue;
305  }
306 
307  placer_->add_item(item.item_grid->get_best_size());
308  }
309 }
310 
312  const event::ui_event event,
313  bool& handled)
314 {
315  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
316 
317  widget* wgt = dynamic_cast<widget*>(&dispatcher);
318  if(wgt) {
319  for(auto & item : items_)
320  {
321  if(item.item_grid->has_widget(*wgt)) {
322  if(item.item_grid->get_visible() != widget::visibility::invisible) {
323 
324  /*
325  * This time we call init layout but also the linked widget
326  * update this makes things work properly for the
327  * addon_list. This code can use some more tuning,
328  * polishing and testing.
329  */
330  item.item_grid->layout_initialize(false);
332 
333  /*
334  * By not calling init layout it uses its previous size
335  * what seems to work properly when showing and hiding
336  * items. Might fail with new items (haven't tested yet).
337  */
338  item.item_grid->place(point(), item.item_grid->get_best_size());
339  }
341  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
342  handled = true;
343  return;
344  }
345  }
346  }
347 
348  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
349  assert(false);
350  handled = false;
351 }
352 
353 // }---------- BUILDER -----------{
354 
355 /*WIKI_MACRO
356  * @begin{macro}{pane_description}
357  *
358  * A pane is a container where new members can be added and removed
359  * during run-time.
360  * @end{macro}
361  */
362 
363 /*WIKI
364  * @page = GUIWidgetInstanceWML
365  * @order = 2_viewport
366  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
367  * @begin{tag}{name="pane"}{min=0}{max=-1}{super="generic/widget_instance"}
368  * == Label ==
369  *
370  * @macro = viewport_description
371  *
372  * List with the label specific variables:
373  * @begin{table}{config}
374  * grow_direction & grow_direction & &
375  * The direction in which new items grow. $
376  * parallel_items & unsigned & &
377  * The number of items that are growing in
378  * parallel. $
379  * item_definition & section & &
380  * The definition of a new item. $
381  * @end{table}
382  *
383  * @begin{tag}{name="item_definition"}{min=1}{max=1}{super="gui/window/resolution/grid"}
384  * @end{tag}{name="item_definition"}
385  * @end{tag}{name="pane"}
386  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
387  */
388 
389 namespace implementation
390 {
391 
392 builder_pane::builder_pane(const config& cfg)
393  : builder_widget(cfg)
394  , grow_direction(
395  lexical_cast<placer_base::grow_direction>(cfg["grow_direction"]))
396  , parallel_items(cfg["parallel_items"])
397  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
398 {
399  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
400 }
401 
403 {
404  return build(replacements_map());
405 }
406 
407 widget_ptr builder_pane::build(const replacements_map& /*replacements*/) const
408 {
409  return std::make_shared<pane>(*this);
410 }
411 
412 } // namespace implementation
413 
414 // }------------ END --------------
415 
416 } // 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:50
grid_ptr item_grid
Definition: pane.hpp:47
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:38
#define DBG_GUI_L
Definition: log.hpp:57
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:234
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:163
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
Main class to show messages to the user.
Definition: message.hpp:34
void filter(const filter_functor_t &filter_functor)
Filters the contents of the pane.
Definition: pane.cpp:191
virtual void set_members(const widget_item &data)
Sets the members of the styled_widget.
New lexcical_cast header.
std::list< item > items_
The items in the pane.
Definition: pane.hpp:138
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:48
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:157
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:52
#define LOG_HEADER
Definition: pane.cpp:33
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:184
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:147
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:311
To lexical_cast(From value)
Lexical cast converts one type to another.
virtual widget_ptr build() const override
Definition: pane.cpp:402
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:260
int x
x coordinate.
Definition: point.hpp:44
void place_children()
Places the children on the pane.
Definition: pane.cpp:244
Generic file dialog.
Definition: field-fwd.hpp:22
#define DBG_GUI_D
Definition: log.hpp:28
The message callbacks hold a reference to a message.
Definition: message.hpp:46
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
Definition: pane.cpp:229
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:30
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
Request to place the widget.
Definition: handler.hpp:94
#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:224
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:232
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:218
std::shared_ptr< widget > widget_ptr
Definition: widget.hpp:732
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:296
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:203
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:65
unsigned id
Definition: pane.hpp:44
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:22
#define DBG_GUI_E
Definition: log.hpp:34
The user set the widget invisible, that means:
window * get_window()
Get the parent window.
Definition: widget.cpp:113
Holds a 2D point.
Definition: point.hpp:23
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:71
Base class for all visible items.
std::function< bool(const item &, const item &)> compare_functor_t
Definition: pane.hpp:50
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:146
Helper to implement private functions without modifying the header.
Definition: pane.cpp:47
pane(const implementation::builder_pane &builder)
Definition: pane.cpp:108
Contains the SDL_Rect helper code.
The user sets the widget visible, that means:
virtual void impl_draw_children() override
See widget::impl_draw_children.
Definition: pane.cpp:172
unsigned create_item(const widget_data &item_data, const std::map< std::string, std::string > &tags)
Definition: pane.cpp:121
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:66
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:141
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:30
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:144
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:68
int y
y coordinate.
Definition: point.hpp:47
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: pane.cpp:207
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:276
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:47
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:882