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 
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(surface& frame_buffer, 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(frame_buffer, x_offset, y_offset);
197  }
198  }
199 }
200 
202  const std::vector<widget*>& call_stack)
203 {
204  for(auto & item : items_)
205  {
206  std::vector<widget*> child_call_stack = call_stack;
207  item.item_grid->populate_dirty_list(caller, child_call_stack);
208  }
209 }
210 
211 void pane::sort(const compare_functor_t& compare_functor)
212 {
213  items_.sort(compare_functor);
214 
216 }
217 
218 void pane::filter(const filter_functor_t& filter_functor)
219 {
220  for(auto & item : items_)
221  {
222  item.item_grid->set_visible(filter_functor(item)
225  }
226 
228 }
229 
230 void pane::request_reduce_width(const unsigned /*maximum_width*/)
231 {
232 }
233 
234 widget* pane::find_at(const point& coordinate, const bool must_be_active)
235 {
236  return pane_implementation::find_at(this, coordinate, must_be_active);
237 }
238 
240  const bool must_be_active) const
241 {
242  return pane_implementation::find_at(this, coordinate, must_be_active);
243 }
244 
246 {
248  return placer_->get_size();
249 }
250 
252 {
253  return false;
254 }
255 
257 {
258  /**
259  * @todo Implement properly.
260  */
261  return nullptr;
262 }
263 
264 grid* pane::get_grid(const unsigned id)
265 {
266  return pane_implementation::get_grid(this, id);
267 }
268 
269 const grid* pane::get_grid(const unsigned id) const
270 {
271  return pane_implementation::get_grid(this, id);
272 }
273 
275 {
277  unsigned index = 0;
278  for(auto & item : items_)
279  {
281  continue;
282  }
283 
284  const point origin = placer_->get_origin(index);
286  ++index;
287  }
288 }
289 
291 {
293  unsigned index = 0;
294  for(auto & item : items_)
295  {
297  continue;
298  }
299 
300  const point origin = placer_->get_origin(index);
301  item.item_grid->set_origin(origin);
302  ++index;
303  }
304 }
305 
307 {
309  unsigned index = 0;
310  for(auto & item : items_)
311  {
313  continue;
314  }
315 
316  const point origin = placer_->get_origin(index);
319  } else {
320  item.item_grid->set_origin(origin);
321  }
322  ++index;
323  }
324 }
325 
327 {
328  assert(placer_.get());
329  placer_->initialize();
330 
331  for(const auto & item : items_)
332  {
334  continue;
335  }
336 
337  placer_->add_item(item.item_grid->get_best_size());
338  }
339 }
340 
342  const event::ui_event event,
343  bool& handled)
344 {
345  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
346 
347  widget* wgt = dynamic_cast<widget*>(&dispatcher);
348  if(wgt) {
349  for(auto & item : items_)
350  {
351  if(item.item_grid->has_widget(*wgt)) {
353 
354  /*
355  * This time we call init layout but also the linked widget
356  * update this makes things work properly for the
357  * addon_list. This code can use some more tuning,
358  * polishing and testing.
359  */
362 
363  /*
364  * By not calling init layout it uses its previous size
365  * what seems to work properly when showing and hiding
366  * items. Might fail with new items (haven't tested yet).
367  */
369  }
371  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
372  handled = true;
373  return;
374  }
375  }
376  }
377 
378  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
379  assert(false);
380  handled = false;
381 }
382 
383 // }---------- BUILDER -----------{
384 
385 /*WIKI_MACRO
386  * @begin{macro}{pane_description}
387  *
388  * A pane is a container where new members can be added and removed
389  * during run-time.
390  * @end{macro}
391  */
392 
393 /*WIKI
394  * @page = GUIWidgetInstanceWML
395  * @order = 2_viewport
396  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
397  * @begin{tag}{name="pane"}{min=0}{max=-1}{super="generic/widget_instance"}
398  * == Label ==
399  *
400  * @macro = viewport_description
401  *
402  * List with the label specific variables:
403  * @begin{table}{config}
404  * grow_direction & grow_direction & &
405  * The direction in which new items grow. $
406  * parallel_items & unsigned & &
407  * The number of items that are growing in
408  * parallel. $
409  * item_definition & section & &
410  * The definition of a new item. $
411  * @end{table}
412  *
413  * @begin{tag}{name="item_definition"}{min=1}{max=1}{super="gui/window/resolution/grid"}
414  * @end{tag}{name="item_definition"}
415  * @end{tag}{name="pane"}
416  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
417  */
418 
419 namespace implementation
420 {
421 
422 builder_pane::builder_pane(const config& cfg)
423  : builder_widget(cfg)
424  , grow_direction(
425  lexical_cast<placer_base::tgrow_direction>(cfg["grow_direction"]))
426  , parallel_items(cfg["parallel_items"])
427  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
428 {
429  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
430 }
431 
433 {
434  return build(replacements_map());
435 }
436 
437 widget* builder_pane::build(const replacements_map& /*replacements*/) const
438 {
439  return pane::build(*this);
440 }
441 
442 } // namespace implementation
443 
444 // }------------ END --------------
445 
446 } // 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:152
#define DBG_GUI_L
Definition: log.hpp:57
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:264
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:164
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:500
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:218
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:152
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:666
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:211
std::unique_ptr< placer_base > placer_
Helper to do the placement.
Definition: pane.hpp:161
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:341
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:290
int x
x coordinate.
Definition: point.hpp:44
void place_children()
Places the children on the pane.
Definition: pane.cpp:274
Generic file dialog.
Definition: field-fwd.hpp:22
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
Definition: pane.cpp:201
#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
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:414
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:102
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:190
#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:251
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:235
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:245
void set_visible(const visibility visible)
Definition: widget.cpp:473
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:326
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:256
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: pane.cpp:230
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:114
window * build(const builder_window::window_resolution *definition)
Builds a window.
Holds a 2D point.
Definition: point.hpp:23
virtual void impl_draw_children(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_children.
Definition: pane.cpp:189
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:302
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:120
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:155
void draw_children(surface &frame_buffer, int x_offset, int y_offset)
Draws the children of a widget.
Definition: widget.cpp:384
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:158
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:92
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:234
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
std::shared_ptr< builder_grid > builder_grid_ptr
static std::deque< std::string > call_stack
Definition: function.cpp:39
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:306
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:55
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:1079