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 http://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 
20 #include "gui/core/log.hpp"
21 #include "gui/widgets/grid.hpp"
22 #include "gui/widgets/window.hpp"
23 #include "utils/const_clone.hpp"
25 #include "gettext.hpp"
26 #include "lexical_cast.hpp"
27 #include "sdl/rect.hpp"
28 
29 #include "utils/functional.hpp"
30 
31 #define LOG_SCOPE_HEADER "pane [" + id() + "] " + __func__
32 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
33 
34 namespace gui2
35 {
36 
37 // ------------ WIDGET -----------{
38 
39 /**
40  * Helper to implement private functions without modifying the header.
41  *
42  * The class is a helper to avoid recompilation and only has static
43  * functions. It also facilitates to create duplicates of functions for a const
44  * and a non-const member function.
45  */
47 {
48  /**
49  * Implementation for the wrappers for
50  * [const] widget* pane::find_at(const point&, const bool) [const].
51  *
52  * @tparam W A pointer to the pane.
53  */
54  template <class W>
56  find_at(W pane, point coordinate, const bool must_be_active)
57  {
58 
59  /*
60  * First test whether the mouse is at the pane.
61  */
62  if(pane->widget::find_at(coordinate, must_be_active) != pane) {
63  return nullptr;
64  }
65 
66  for(auto item : pane->items_)
67  {
68 
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  {
97 
98  if(item.id == id) {
99  return item.item_grid;
100  }
101  }
102 
103  return nullptr;
104  }
105 };
106 
107 pane::pane(const builder_grid_ptr item_builder)
108  : widget()
109  , items_()
110  , item_builder_(item_builder)
111  , item_id_generator_(0)
112  , placer_(placer_base::build(placer_base::tgrow_direction::vertical, 1))
113 {
114  connect_signal<event::REQUEST_PLACEMENT>(
115  std::bind(
116  &pane::signal_handler_request_placement, this, _1, _2, _3),
118 }
119 
121  : widget(builder)
122  , items_()
123  , item_builder_(builder.item_definition)
124  , item_id_generator_(0)
125  , placer_(placer_base::build(builder.grow_direction, builder.parallel_items))
126 {
127  connect_signal<event::REQUEST_PLACEMENT>(
128  std::bind(
129  &pane::signal_handler_request_placement, this, _1, _2, _3),
131 }
132 
134 {
135  return new pane(builder);
136 }
137 
138 unsigned pane::create_item(const std::map<std::string, string_map>& item_data,
139  const std::map<std::string, std::string>& tags)
140 {
141  item item = { item_id_generator_++, tags, item_builder_->build() };
142 
143  item.item_grid->set_parent(this);
144 
145  for(const auto & data : item_data)
146  {
147  styled_widget* control
148  = find_widget<styled_widget>(item.item_grid, data.first, false, false);
149 
150  if(control) {
151  control->set_members(data.second);
152  }
153  }
154 
155  items_.push_back(item);
156 
158  fire(event::REQUEST_PLACEMENT, *this, message);
159 
160  return item.id;
161 }
162 
163 void pane::place(const point& origin, const point& size)
164 {
165  DBG_GUI_L << LOG_HEADER << '\n';
166  widget::place(origin, size);
167 
168  assert(origin.x == 0);
169  assert(origin.y == 0);
170 
171  place_children();
172 }
173 
174 void pane::layout_initialize(const bool full_initialization)
175 {
176  DBG_GUI_D << LOG_HEADER << '\n';
177 
178  widget::layout_initialize(full_initialization);
179 
180  for(auto & item : items_)
181  {
183  item.item_grid->layout_initialize(full_initialization);
184  }
185  }
186 }
187 
188 void
189 pane::impl_draw_children(int x_offset, int y_offset)
190 {
191  DBG_GUI_D << LOG_HEADER << '\n';
192 
193  for(auto & item : items_)
194  {
196  item.item_grid->draw_children(x_offset, y_offset);
197  }
198  }
199 }
200 
201 void pane::sort(const compare_functor_t& compare_functor)
202 {
203  items_.sort(compare_functor);
204 
206 }
207 
208 void pane::filter(const filter_functor_t& filter_functor)
209 {
210  for(auto & item : items_)
211  {
212  item.item_grid->set_visible(filter_functor(item)
215  }
216 
218 }
219 
220 void pane::request_reduce_width(const unsigned /*maximum_width*/)
221 {
222 }
223 
224 widget* pane::find_at(const point& coordinate, const bool must_be_active)
225 {
226  return pane_implementation::find_at(this, coordinate, must_be_active);
227 }
228 
230  const bool must_be_active) const
231 {
232  return pane_implementation::find_at(this, coordinate, must_be_active);
233 }
234 
236 {
238  return placer_->get_size();
239 }
240 
242 {
243  return false;
244 }
245 
247 {
248  /**
249  * @todo Implement properly.
250  */
251  return nullptr;
252 }
253 
254 grid* pane::get_grid(const unsigned id)
255 {
256  return pane_implementation::get_grid(this, id);
257 }
258 
259 const grid* pane::get_grid(const unsigned id) const
260 {
261  return pane_implementation::get_grid(this, id);
262 }
263 
265 {
267  unsigned index = 0;
268  for(auto & item : items_)
269  {
271  continue;
272  }
273 
274  const point origin = placer_->get_origin(index);
276  ++index;
277  }
278 }
279 
281 {
283  unsigned index = 0;
284  for(auto & item : items_)
285  {
287  continue;
288  }
289 
290  const point origin = placer_->get_origin(index);
291  item.item_grid->set_origin(origin);
292  ++index;
293  }
294 }
295 
297 {
299  unsigned index = 0;
300  for(auto & item : items_)
301  {
303  continue;
304  }
305 
306  const point origin = placer_->get_origin(index);
309  } else {
310  item.item_grid->set_origin(origin);
311  }
312  ++index;
313  }
314 }
315 
317 {
318  assert(placer_.get());
319  placer_->initialize();
320 
321  for(const auto & item : items_)
322  {
324  continue;
325  }
326 
327  placer_->add_item(item.item_grid->get_best_size());
328  }
329 }
330 
332  const event::ui_event event,
333  bool& handled)
334 {
335  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
336 
337  widget* wgt = dynamic_cast<widget*>(&dispatcher);
338  if(wgt) {
339  for(auto & item : items_)
340  {
341  if(item.item_grid->has_widget(*wgt)) {
343 
344  /*
345  * This time we call init layout but also the linked widget
346  * update this makes things work properly for the
347  * addon_list. This code can use some more tuning,
348  * polishing and testing.
349  */
352 
353  /*
354  * By not calling init layout it uses its previous size
355  * what seems to work properly when showing and hiding
356  * items. Might fail with new items (haven't tested yet).
357  */
359  }
361  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
362  handled = true;
363  return;
364  }
365  }
366  }
367 
368  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
369  assert(false);
370  handled = false;
371 }
372 
373 // }---------- BUILDER -----------{
374 
375 /*WIKI_MACRO
376  * @begin{macro}{pane_description}
377  *
378  * A pane is a container where new members can be added and removed
379  * during run-time.
380  * @end{macro}
381  */
382 
383 /*WIKI
384  * @page = GUIWidgetInstanceWML
385  * @order = 2_viewport
386  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
387  * @begin{tag}{name="pane"}{min=0}{max=-1}{super="generic/widget_instance"}
388  * == Label ==
389  *
390  * @macro = viewport_description
391  *
392  * List with the label specific variables:
393  * @begin{table}{config}
394  * grow_direction & grow_direction & &
395  * The direction in which new items grow. $
396  * parallel_items & unsigned & &
397  * The number of items that are growing in
398  * parallel. $
399  * item_definition & section & &
400  * The definition of a new item. $
401  * @end{table}
402  *
403  * @begin{tag}{name="item_definition"}{min=1}{max=1}{super="gui/window/resolution/grid"}
404  * @end{tag}{name="item_definition"}
405  * @end{tag}{name="pane"}
406  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
407  */
408 
409 namespace implementation
410 {
411 
412 builder_pane::builder_pane(const config& cfg)
413  : builder_widget(cfg)
414  , grow_direction(
415  lexical_cast<placer_base::tgrow_direction>(cfg["grow_direction"]))
416  , parallel_items(cfg["parallel_items"])
417  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
418 {
419  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
420 }
421 
423 {
424  return build(replacements_map());
425 }
426 
427 widget* builder_pane::build(const replacements_map& /*replacements*/) const
428 {
429  return pane::build(*this);
430 }
431 
432 } // namespace implementation
433 
434 // }------------ END --------------
435 
436 } // 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
void set_parent(widget *parent)
Definition: widget.cpp:151
#define DBG_GUI_L
Definition: log.hpp:57
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:254
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:93
visibility get_visible() const
Definition: widget.cpp:481
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:208
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:145
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:138
virtual bool has_widget(const widget &widget) const override
See widget::has_widget.
Definition: grid.cpp:651
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:47
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:174
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:53
#define LOG_HEADER
Definition: pane.cpp:32
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:201
std::unique_ptr< placer_base > placer_
Helper to do the placement.
Definition: pane.hpp:154
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:331
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:280
int x
x coordinate.
Definition: point.hpp:44
void place_children()
Places the children on the pane.
Definition: pane.cpp:264
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
grid * item_grid
Definition: pane.hpp:48
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: grid.cpp:185
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:56
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
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:189
#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:241
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:235
void draw_children(int x_offset, int y_offset)
Draws the children of a widget.
Definition: widget.cpp:419
void set_visible(const visibility visible)
Definition: widget.cpp:456
pane(const builder_grid_ptr item_builder)
Definition: pane.cpp:107
The walker abstract base class.
Definition: walker.hpp:26
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:316
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:246
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: pane.cpp:220
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:65
unsigned id
Definition: pane.hpp:45
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:22
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: grid.cpp:479
#define DBG_GUI_E
Definition: log.hpp:34
static pane * build(const implementation::builder_pane &builder)
Definition: pane.cpp:133
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:51
virtual void set_origin(const point &origin) override
See widget::set_origin.
Definition: grid.cpp:586
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:163
Helper to implement private functions without modifying the header.
Definition: pane.cpp:46
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:297
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:66
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:148
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:151
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:224
virtual void impl_draw_children(int x_offset, int y_offset) override
See widget::impl_draw_children.
Definition: pane.cpp:189
std::shared_ptr< builder_grid > builder_grid_ptr
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:296
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:883