The Battle for Wesnoth  1.19.7+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));
190  }
191 
193 }
194 
195 void pane::request_reduce_width(const unsigned /*maximum_width*/)
196 {
197 }
198 
199 widget* pane::find_at(const point& coordinate, const bool must_be_active)
200 {
201  return pane_implementation::find_at(this, coordinate, must_be_active);
202 }
203 
205  const bool must_be_active) const
206 {
207  return pane_implementation::find_at(this, coordinate, must_be_active);
208 }
209 
211 {
213  return placer_->get_size();
214 }
215 
217 {
218  return false;
219 }
220 
222 {
223  /**
224  * @todo Implement properly.
225  */
226  return nullptr;
227 }
228 
229 grid* pane::get_grid(const unsigned id)
230 {
231  return pane_implementation::get_grid(this, id);
232 }
233 
234 const grid* pane::get_grid(const unsigned id) const
235 {
236  return pane_implementation::get_grid(this, id);
237 }
238 
240 {
242  unsigned index = 0;
243  for(auto & item : items_)
244  {
245  if(item.item_grid->get_visible() == widget::visibility::invisible) {
246  continue;
247  }
248 
249  const point origin = placer_->get_origin(index);
250  item.item_grid->place(origin, item.item_grid->get_best_size());
251  ++index;
252  }
253 }
254 
256 {
258  unsigned index = 0;
259  for(auto & item : items_)
260  {
261  if(item.item_grid->get_visible() == widget::visibility::invisible) {
262  continue;
263  }
264 
265  const point origin = placer_->get_origin(index);
266  item.item_grid->set_origin(origin);
267  ++index;
268  }
269 }
270 
272 {
274  unsigned index = 0;
275  for(auto & item : items_)
276  {
277  if(item.item_grid->get_visible() == widget::visibility::invisible) {
278  continue;
279  }
280 
281  const point origin = placer_->get_origin(index);
282  if(item.item_grid->get_size() != item.item_grid->get_best_size()) {
283  item.item_grid->place(origin, item.item_grid->get_best_size());
284  } else {
285  item.item_grid->set_origin(origin);
286  }
287  ++index;
288  }
289 }
290 
292 {
293  assert(placer_.get());
294  placer_->initialize();
295 
296  for(const auto & item : items_)
297  {
298  if(item.item_grid->get_visible() == widget::visibility::invisible) {
299  continue;
300  }
301 
302  placer_->add_item(item.item_grid->get_best_size());
303  }
304 }
305 
306 void pane::signal_handler_request_placement(dispatcher& dispatcher,
307  const event::ui_event event,
308  bool& handled)
309 {
310  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
311 
312  widget* wgt = dynamic_cast<widget*>(&dispatcher);
313  if(wgt) {
314  for(auto & item : items_)
315  {
316  if(item.item_grid->has_widget(*wgt)) {
317  if(item.item_grid->get_visible() != widget::visibility::invisible) {
318 
319  /*
320  * This time we call init layout but also the linked widget
321  * update this makes things work properly for the
322  * addon_list. This code can use some more tuning,
323  * polishing and testing.
324  */
325  item.item_grid->layout_initialize(false);
327 
328  /*
329  * By not calling init layout it uses its previous size
330  * what seems to work properly when showing and hiding
331  * items. Might fail with new items (haven't tested yet).
332  */
333  item.item_grid->place(point(), item.item_grid->get_best_size());
334  }
336  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.";
337  handled = true;
338  return;
339  }
340  }
341  }
342 
343  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.";
344  assert(false);
345  handled = false;
346 }
347 
348 // }---------- BUILDER -----------{
349 
350 namespace implementation
351 {
352 
354  : builder_widget(cfg)
355  , grow_dir(*grow_direction::get_enum(cfg["grow_direction"].str()))
356  , parallel_items(cfg["parallel_items"].to_int())
357  , item_definition(new builder_grid(VALIDATE_WML_CHILD(cfg, "item_definition", missing_mandatory_wml_tag("pane", "item_definition"))))
358 {
359  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
360 }
361 
362 std::unique_ptr<widget> builder_pane::build() const
363 {
364  return build(replacements_map());
365 }
366 
367 std::unique_ptr<widget> builder_pane::build(const replacements_map& /*replacements*/) const
368 {
369  return std::make_unique<pane>(*this);
370 }
371 
372 } // namespace implementation
373 
374 // }------------ END --------------
375 
376 } // 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:271
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:306
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:229
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: pane.cpp:216
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:199
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:221
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:210
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:195
void place_children()
Places the children on the pane.
Definition: pane.cpp:239
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:255
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:291
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
@ 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 size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
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:353
virtual std::unique_ptr< widget > build() const override
Definition: pane.cpp:362
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.