The Battle for Wesnoth  1.15.12+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 <functional>
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 
108  : widget(builder)
109  , items_()
110  , item_builder_(builder.item_definition)
111  , item_id_generator_(0)
112  , placer_(placer_base::build(builder.grow_direction, builder.parallel_items))
113 {
114  connect_signal<event::REQUEST_PLACEMENT>(
115  std::bind(
116  &pane::signal_handler_request_placement, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
118 }
119 
121 {
122  return new pane(builder);
123 }
124 
125 unsigned pane::create_item(const std::map<std::string, string_map>& item_data,
126  const std::map<std::string, std::string>& tags)
127 {
128  item item = { item_id_generator_++, tags, item_builder_->build() };
129 
130  item.item_grid->set_parent(this);
131 
132  for(const auto & data : item_data)
133  {
134  styled_widget* control
135  = find_widget<styled_widget>(item.item_grid, data.first, false, false);
136 
137  if(control) {
138  control->set_members(data.second);
139  }
140  }
141 
142  items_.push_back(item);
143 
145  fire(event::REQUEST_PLACEMENT, *this, message);
146 
147  return item.id;
148 }
149 
150 void pane::place(const point& origin, const point& size)
151 {
152  DBG_GUI_L << LOG_HEADER << '\n';
153  widget::place(origin, size);
154 
155  assert(origin.x == 0);
156  assert(origin.y == 0);
157 
158  place_children();
159 }
160 
161 void pane::layout_initialize(const bool full_initialization)
162 {
163  DBG_GUI_D << LOG_HEADER << '\n';
164 
165  widget::layout_initialize(full_initialization);
166 
167  for(auto & item : items_)
168  {
170  item.item_grid->layout_initialize(full_initialization);
171  }
172  }
173 }
174 
175 void
176 pane::impl_draw_children(surface& frame_buffer, int x_offset, int y_offset)
177 {
178  DBG_GUI_D << LOG_HEADER << '\n';
179 
180  for(auto & item : items_)
181  {
183  item.item_grid->draw_children(frame_buffer, x_offset, y_offset);
184  }
185  }
186 }
187 
189  const std::vector<widget*>& call_stack)
190 {
191  for(auto & item : items_)
192  {
193  std::vector<widget*> child_call_stack = call_stack;
194  item.item_grid->populate_dirty_list(caller, child_call_stack);
195  }
196 }
197 
198 void pane::sort(const compare_functor_t& compare_functor)
199 {
200  items_.sort(compare_functor);
201 
203 }
204 
205 void pane::filter(const filter_functor_t& filter_functor)
206 {
207  for(auto & item : items_)
208  {
209  item.item_grid->set_visible(filter_functor(item)
212  }
213 
215 }
216 
217 void pane::request_reduce_width(const unsigned /*maximum_width*/)
218 {
219 }
220 
221 widget* pane::find_at(const point& coordinate, const bool must_be_active)
222 {
223  return pane_implementation::find_at(this, coordinate, must_be_active);
224 }
225 
227  const bool must_be_active) const
228 {
229  return pane_implementation::find_at(this, coordinate, must_be_active);
230 }
231 
233 {
235  return placer_->get_size();
236 }
237 
239 {
240  return false;
241 }
242 
244 {
245  /**
246  * @todo Implement properly.
247  */
248  return nullptr;
249 }
250 
251 grid* pane::get_grid(const unsigned id)
252 {
253  return pane_implementation::get_grid(this, id);
254 }
255 
256 const grid* pane::get_grid(const unsigned id) const
257 {
258  return pane_implementation::get_grid(this, id);
259 }
260 
262 {
264  unsigned index = 0;
265  for(auto & item : items_)
266  {
268  continue;
269  }
270 
271  const point origin = placer_->get_origin(index);
273  ++index;
274  }
275 }
276 
278 {
280  unsigned index = 0;
281  for(auto & item : items_)
282  {
284  continue;
285  }
286 
287  const point origin = placer_->get_origin(index);
288  item.item_grid->set_origin(origin);
289  ++index;
290  }
291 }
292 
294 {
296  unsigned index = 0;
297  for(auto & item : items_)
298  {
300  continue;
301  }
302 
303  const point origin = placer_->get_origin(index);
306  } else {
307  item.item_grid->set_origin(origin);
308  }
309  ++index;
310  }
311 }
312 
314 {
315  assert(placer_.get());
316  placer_->initialize();
317 
318  for(const auto & item : items_)
319  {
321  continue;
322  }
323 
324  placer_->add_item(item.item_grid->get_best_size());
325  }
326 }
327 
329  const event::ui_event event,
330  bool& handled)
331 {
332  DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
333 
334  widget* wgt = dynamic_cast<widget*>(&dispatcher);
335  if(wgt) {
336  for(auto & item : items_)
337  {
338  if(item.item_grid->has_widget(*wgt)) {
340 
341  /*
342  * This time we call init layout but also the linked widget
343  * update this makes things work properly for the
344  * addon_list. This code can use some more tuning,
345  * polishing and testing.
346  */
349 
350  /*
351  * By not calling init layout it uses its previous size
352  * what seems to work properly when showing and hiding
353  * items. Might fail with new items (haven't tested yet).
354  */
356  }
358  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.\n";
359  handled = true;
360  return;
361  }
362  }
363  }
364 
365  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.\n";
366  assert(false);
367  handled = false;
368 }
369 
370 // }---------- BUILDER -----------{
371 
372 namespace implementation
373 {
374 
375 builder_pane::builder_pane(const config& cfg)
376  : builder_widget(cfg)
377  , grow_direction(
378  lexical_cast<placer_base::grow_direction>(cfg["grow_direction"]))
379  , parallel_items(cfg["parallel_items"])
380  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
381 {
382  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
383 }
384 
386 {
387  return build(replacements_map());
388 }
389 
390 widget* builder_pane::build(const replacements_map& /*replacements*/) const
391 {
392  return pane::build(*this);
393 }
394 
395 } // namespace implementation
396 
397 // }------------ END --------------
398 
399 } // 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:154
#define DBG_GUI_L
Definition: log.hpp:54
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:251
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:166
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:502
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:205
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:154
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:125
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:49
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:161
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:58
#define LOG_HEADER
Definition: pane.cpp:32
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:198
std::unique_ptr< placer_base > placer_
Helper to do the placement.
Definition: pane.hpp:163
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:328
virtual widget * build() const override
Definition: pane.cpp:385
static std::string _(const char *str)
Definition: gettext.hpp:92
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:277
int x
x coordinate.
Definition: point.hpp:44
void place_children()
Places the children on the pane.
Definition: pane.cpp:261
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:188
#define DBG_GUI_D
Definition: log.hpp:28
The message callbacks hold a reference to a message.
Definition: message.hpp:45
grid * item_grid
Definition: pane.hpp:53
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
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:416
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:192
#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:238
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:237
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:232
void set_visible(const visibility visible)
Definition: widget.cpp:475
The walker abstract base class.
Definition: walker.hpp:26
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:313
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:46
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:243
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: pane.cpp:217
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:65
unsigned id
Definition: pane.hpp:50
A pane is a container where new members can be added and removed during run-time. ...
Definition: pane.hpp:42
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:120
The user set the widget invisible, that means:
window * get_window()
Get the parent window.
Definition: widget.cpp:116
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:176
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:56
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:150
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:304
pane(const implementation::builder_pane &builder)
Definition: pane.cpp:107
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:68
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:157
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:386
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:160
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:59
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:221
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:293
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:1070
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:409