The Battle for Wesnoth  1.17.17+dev
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2023
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 
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 
310 void pane::signal_handler_request_placement(dispatcher& dispatcher,
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 
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(VALIDATE_WML_CHILD(cfg, "item_definition", _("Missing [item_definition] in [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
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
Main class to show messages to the user.
Definition: message.hpp:36
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:76
Base container class.
Definition: grid.hpp:32
A pane is a container where new members can be added and removed during run-time.
Definition: pane.hpp:44
void place_or_set_origin_children()
Places or moves the children on the pane.
Definition: pane.cpp:275
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:310
std::function< bool(const item &, const item &)> compare_functor_t
Definition: pane.hpp:58
grid * get_grid(const unsigned id)
Returns a grid in the pane.
Definition: pane.cpp:233
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: pane.cpp:220
std::function< bool(const item &)> filter_functor_t
Definition: pane.hpp:60
std::list< item > items_
The items in the pane.
Definition: pane.hpp:146
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
Definition: pane.cpp:203
pane(const implementation::builder_pane &builder)
Definition: pane.cpp:105
std::unique_ptr< placer_base > placer_
Helper to do the placement.
Definition: pane.hpp:155
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
Definition: pane.cpp:225
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:180
builder_grid_ptr item_builder_
The builer for the items in the list.
Definition: pane.hpp:149
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: pane.cpp:214
virtual void impl_draw_children() override
See widget::impl_draw_children.
Definition: pane.cpp:168
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:143
unsigned create_item(const widget_data &item_data, const std::map< std::string, std::string > &tags)
Creates a new item.
Definition: pane.cpp:118
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
Definition: pane.cpp:199
void place_children()
Places the children on the pane.
Definition: pane.cpp:243
unsigned item_id_generator_
The id generator for the items.
Definition: pane.hpp:152
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: pane.cpp:154
void filter(const filter_functor_t &filter_functor)
Filters the contents of the pane.
Definition: pane.cpp:187
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:259
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:295
Base class for the placement helper.
Definition: placer.hpp:52
Base class for all visible items.
virtual void set_members(const widget_item &data)
Sets the members of the styled_widget.
Base class for all widgets.
Definition: widget.hpp:54
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
virtual void layout_initialize(const bool full_initialization)
How the layout engine works.
Definition: widget.cpp:168
window * get_window()
Get the parent window.
Definition: widget.cpp:118
@ visible
The user sets the widget visible, that means:
@ invisible
The user set the widget invisible, that means:
void layout_linked_widgets()
Layouts the linked widgets.
Definition: window.cpp:961
This file contains the definitions for the gui2::event::message class.
static std::string _(const char *str)
Definition: gettext.hpp:93
Define the common log macros for the gui toolkit.
#define DBG_GUI_L
Definition: log.hpp:55
#define DBG_GUI_E
Definition: log.hpp:35
#define DBG_GUI_D
Definition: log.hpp:29
This file contains the window object, this object is a top level container which has the event manage...
New lexcical_cast header.
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
@ REQUEST_PLACEMENT
Definition: handler.hpp:163
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:43
Generic file dialog.
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.
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
Contains the implementation details for lexical_cast and shouldn't be used directly.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
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
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
typename const_clone< D, S >::pointer const_clone_ptr
Definition: const_clone.hpp:66
#define LOG_HEADER
Definition: pane.cpp:34
std::string_view data
Definition: picture.cpp:199
Contains the SDL_Rect helper code.
Contains the info needed to instantiate a widget.
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
The message callbacks hold a reference to a message.
Definition: message.hpp:46
builder_pane(const config &cfg)
Definition: pane.cpp:357
virtual std::unique_ptr< widget > build() const override
Definition: pane.cpp:366
unsigned id
Definition: pane.hpp:52
std::unique_ptr< grid > item_grid
Definition: pane.hpp:55
Helper to implement private functions without modifying the header.
Definition: pane.cpp:49
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
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
Holds a 2D point.
Definition: point.hpp:25
The base template for associating string values with enum values.
Definition: enum_base.hpp:33
#define VALIDATE_WML_CHILD(cfg, key, message)
#define VALIDATE(cond, message)
The macro to use for the validation of WML.