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