The Battle for Wesnoth  1.17.12+dev
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2022
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 
22 #include "gui/core/log.hpp"
23 #include "gui/widgets/grid.hpp"
24 #include "gui/widgets/window.hpp"
25 #include "utils/const_clone.hpp"
27 #include "gettext.hpp"
28 #include "lexical_cast.hpp"
29 #include "sdl/rect.hpp"
30 
31 #include <functional>
32 
33 #define LOG_SCOPE_HEADER "pane [" + id() + "] " + __func__
34 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
35 
36 namespace gui2
37 {
38 
39 // ------------ WIDGET -----------{
40 
41 /**
42  * Helper to implement private functions without modifying the header.
43  *
44  * The class is a helper to avoid recompilation and only has static
45  * functions. It also facilitates to create duplicates of functions for a const
46  * and a non-const member function.
47  */
49 {
50  /**
51  * Implementation for the wrappers for
52  * [const] widget* pane::find_at(const point&, const bool) [const].
53  *
54  * @tparam W A pointer to the pane.
55  */
56  template <class W>
58  find_at(W pane, point coordinate, const bool must_be_active)
59  {
60 
61  /*
62  * First test whether the mouse is at the pane.
63  */
64  if(pane->widget::find_at(coordinate, must_be_active) != pane) {
65  return nullptr;
66  }
67 
68  for(auto& item : pane->items_) {
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(item.item_grid->get_rectangle().contains(coordinate)) {
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  if(item.id == id) {
97  return item.item_grid.get();
98  }
99  }
100 
101  return nullptr;
102  }
103 };
104 
106  : widget(builder)
107  , items_()
108  , item_builder_(builder.item_definition)
109  , item_id_generator_(0)
110  , placer_(placer_base::build(builder.grow_dir, builder.parallel_items))
111 {
112  connect_signal<event::REQUEST_PLACEMENT>(
113  std::bind(
114  &pane::signal_handler_request_placement, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
116 }
117 
118 unsigned pane::create_item(const widget_data& item_data,
119  const std::map<std::string, std::string>& tags)
120 {
121  item item{item_id_generator_++, tags, std::unique_ptr<grid>{static_cast<grid*>(item_builder_->build().release())}};
122 
123  item.item_grid->set_parent(this);
124 
125  for(const auto & data : item_data)
126  {
127  styled_widget* control
128  = find_widget<styled_widget>(item.item_grid.get(), data.first, false, false);
129 
130  if(control) {
131  control->set_members(data.second);
132  }
133  }
134 
135  items_.push_back(std::move(item));
136 
138  fire(event::REQUEST_PLACEMENT, *this, message);
139 
140  return item.id;
141 }
142 
143 void pane::place(const point& origin, const point& size)
144 {
146  widget::place(origin, size);
147 
148  assert(origin.x == 0);
149  assert(origin.y == 0);
150 
151  place_children();
152 }
153 
154 void pane::layout_initialize(const bool full_initialization)
155 {
157 
158  widget::layout_initialize(full_initialization);
159 
160  for(auto & item : items_)
161  {
162  if(item.item_grid->get_visible() != widget::visibility::invisible) {
163  item.item_grid->layout_initialize(full_initialization);
164  }
165  }
166 }
167 
169 {
171 
172  for(auto & item : items_)
173  {
174  if(item.item_grid->get_visible() != widget::visibility::invisible) {
175  item.item_grid->draw_children();
176  }
177  }
178 }
179 
180 void pane::sort(const compare_functor_t& compare_functor)
181 {
182  items_.sort(compare_functor);
183 
185 }
186 
187 void pane::filter(const filter_functor_t& filter_functor)
188 {
189  for(auto & item : items_)
190  {
191  item.item_grid->set_visible(filter_functor(item)
194  }
195 
197 }
198 
199 void pane::request_reduce_width(const unsigned /*maximum_width*/)
200 {
201 }
202 
203 widget* pane::find_at(const point& coordinate, const bool must_be_active)
204 {
205  return pane_implementation::find_at(this, coordinate, must_be_active);
206 }
207 
209  const bool must_be_active) const
210 {
211  return pane_implementation::find_at(this, coordinate, must_be_active);
212 }
213 
215 {
217  return placer_->get_size();
218 }
219 
221 {
222  return false;
223 }
224 
226 {
227  /**
228  * @todo Implement properly.
229  */
230  return nullptr;
231 }
232 
233 grid* pane::get_grid(const unsigned id)
234 {
235  return pane_implementation::get_grid(this, id);
236 }
237 
238 const grid* pane::get_grid(const unsigned id) const
239 {
240  return pane_implementation::get_grid(this, id);
241 }
242 
244 {
246  unsigned index = 0;
247  for(auto & item : items_)
248  {
249  if(item.item_grid->get_visible() == widget::visibility::invisible) {
250  continue;
251  }
252 
253  const point origin = placer_->get_origin(index);
254  item.item_grid->place(origin, item.item_grid->get_best_size());
255  ++index;
256  }
257 }
258 
260 {
262  unsigned index = 0;
263  for(auto & item : items_)
264  {
265  if(item.item_grid->get_visible() == widget::visibility::invisible) {
266  continue;
267  }
268 
269  const point origin = placer_->get_origin(index);
270  item.item_grid->set_origin(origin);
271  ++index;
272  }
273 }
274 
276 {
278  unsigned index = 0;
279  for(auto & item : items_)
280  {
281  if(item.item_grid->get_visible() == widget::visibility::invisible) {
282  continue;
283  }
284 
285  const point origin = placer_->get_origin(index);
286  if(item.item_grid->get_size() != item.item_grid->get_best_size()) {
287  item.item_grid->place(origin, item.item_grid->get_best_size());
288  } else {
289  item.item_grid->set_origin(origin);
290  }
291  ++index;
292  }
293 }
294 
296 {
297  assert(placer_.get());
298  placer_->initialize();
299 
300  for(const auto & item : items_)
301  {
302  if(item.item_grid->get_visible() == widget::visibility::invisible) {
303  continue;
304  }
305 
306  placer_->add_item(item.item_grid->get_best_size());
307  }
308 }
309 
311  const event::ui_event event,
312  bool& handled)
313 {
314  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
315 
316  widget* wgt = dynamic_cast<widget*>(&dispatcher);
317  if(wgt) {
318  for(auto & item : items_)
319  {
320  if(item.item_grid->has_widget(*wgt)) {
321  if(item.item_grid->get_visible() != widget::visibility::invisible) {
322 
323  /*
324  * This time we call init layout but also the linked widget
325  * update this makes things work properly for the
326  * addon_list. This code can use some more tuning,
327  * polishing and testing.
328  */
329  item.item_grid->layout_initialize(false);
331 
332  /*
333  * By not calling init layout it uses its previous size
334  * what seems to work properly when showing and hiding
335  * items. Might fail with new items (haven't tested yet).
336  */
337  item.item_grid->place(point(), item.item_grid->get_best_size());
338  }
340  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.";
341  handled = true;
342  return;
343  }
344  }
345  }
346 
347  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.";
348  assert(false);
349  handled = false;
350 }
351 
352 // }---------- BUILDER -----------{
353 
354 namespace implementation
355 {
356 
357 builder_pane::builder_pane(const config& cfg)
358  : builder_widget(cfg)
359  , grow_dir(*grow_direction::get_enum(cfg["grow_direction"].str()))
360  , parallel_items(cfg["parallel_items"])
361  , item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
362 {
363  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
364 }
365 
366 std::unique_ptr<widget> builder_pane::build() const
367 {
368  return build(replacements_map());
369 }
370 
371 std::unique_ptr<widget> builder_pane::build(const replacements_map& /*replacements*/) const
372 {
373  return std::make_unique<pane>(*this);
374 }
375 
376 } // namespace implementation
377 
378 // }------------ END --------------
379 
380 } // 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
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:43
#define DBG_GUI_L
Definition: log.hpp:55
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:233
std::unique_ptr< grid > item_grid
Definition: pane.hpp:55
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:168
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
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
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:187
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:146
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:53
std::string_view data
Definition: picture.cpp:206
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:154
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:60
#define LOG_HEADER
Definition: pane.cpp:34
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:180
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:155
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:310
static std::string _(const char *str)
Definition: gettext.hpp:93
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:259
void place_children()
Places the children on the pane.
Definition: pane.cpp:243
Generic file dialog.
#define DBG_GUI_D
Definition: log.hpp:29
The message callbacks hold a reference to a message.
Definition: message.hpp:45
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
Definition: pane.cpp:225
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:58
Base container class.
Definition: grid.hpp:31
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
#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:220
The base template for associating string values with enum values.
Definition: enum_base.hpp:32
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:214
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:295
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:199
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:66
unsigned id
Definition: pane.hpp:52
A pane is a container where new members can be added and removed during run-time. ...
Definition: pane.hpp:43
virtual std::unique_ptr< widget > build() const override
Definition: pane.cpp:366
#define DBG_GUI_E
Definition: log.hpp:35
The user set the widget invisible, that means:
window * get_window()
Get the parent window.
Definition: widget.cpp:118
Holds a 2D point.
Definition: point.hpp:24
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:58
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:143
Helper to implement private functions without modifying the header.
Definition: pane.cpp:48
pane(const implementation::builder_pane &builder)
Definition: pane.cpp:105
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:168
unsigned create_item(const widget_data &item_data, const std::map< std::string, std::string > &tags)
Creates a new item.
Definition: pane.cpp:118
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:76
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:149
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:152
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:60
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: pane.cpp:203
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:275
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:962
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414