The Battle for Wesnoth  1.19.9+dev
pane.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2025
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  const auto item_id = item.id;
134  items_.push_back(std::move(item));
135 
138 
139  return item_id;
140 }
141 
142 void pane::place(const point& origin, const point& size)
143 {
145  widget::place(origin, size);
146 
147  assert(origin.x == 0);
148  assert(origin.y == 0);
149 
150  place_children();
151 }
152 
153 void pane::layout_initialize(const bool full_initialization)
154 {
156 
157  widget::layout_initialize(full_initialization);
158 
159  for(auto & item : items_)
160  {
161  if(item.item_grid->get_visible() != widget::visibility::invisible) {
162  item.item_grid->layout_initialize(full_initialization);
163  }
164  }
165 }
166 
168 {
170 
171  for(auto & item : items_)
172  {
173  if(item.item_grid->get_visible() != widget::visibility::invisible) {
174  item.item_grid->draw_children();
175  }
176  }
177 }
178 
179 void pane::sort(const compare_functor_t& compare_functor)
180 {
181  items_.sort(compare_functor);
182 
184 }
185 
186 void pane::filter(const filter_functor_t& filter_functor)
187 {
188  for(auto & item : items_)
189  {
190  item.item_grid->set_visible(filter_functor(item));
191  }
192 
194 }
195 
196 void pane::request_reduce_width(const unsigned /*maximum_width*/)
197 {
198 }
199 
200 widget* pane::find_at(const point& coordinate, const bool must_be_active)
201 {
202  return pane_implementation::find_at(this, coordinate, must_be_active);
203 }
204 
206  const bool must_be_active) const
207 {
208  return pane_implementation::find_at(this, coordinate, must_be_active);
209 }
210 
212 {
214  return placer_->get_size();
215 }
216 
218 {
219  return false;
220 }
221 
223 {
224  /**
225  * @todo Implement properly.
226  */
227  return nullptr;
228 }
229 
230 grid* pane::get_grid(const unsigned id)
231 {
232  return pane_implementation::get_grid(this, id);
233 }
234 
235 const grid* pane::get_grid(const unsigned id) const
236 {
237  return pane_implementation::get_grid(this, id);
238 }
239 
241 {
243  unsigned index = 0;
244  for(auto & item : items_)
245  {
246  if(item.item_grid->get_visible() == widget::visibility::invisible) {
247  continue;
248  }
249 
250  const point origin = placer_->get_origin(index);
251  item.item_grid->place(origin, item.item_grid->get_best_size());
252  ++index;
253  }
254 }
255 
257 {
259  unsigned index = 0;
260  for(auto & item : items_)
261  {
262  if(item.item_grid->get_visible() == widget::visibility::invisible) {
263  continue;
264  }
265 
266  const point origin = placer_->get_origin(index);
267  item.item_grid->set_origin(origin);
268  ++index;
269  }
270 }
271 
273 {
275  unsigned index = 0;
276  for(auto & item : items_)
277  {
278  if(item.item_grid->get_visible() == widget::visibility::invisible) {
279  continue;
280  }
281 
282  const point origin = placer_->get_origin(index);
283  if(item.item_grid->get_size() != item.item_grid->get_best_size()) {
284  item.item_grid->place(origin, item.item_grid->get_best_size());
285  } else {
286  item.item_grid->set_origin(origin);
287  }
288  ++index;
289  }
290 }
291 
293 {
294  assert(placer_.get());
295  placer_->initialize();
296 
297  for(const auto & item : items_)
298  {
299  if(item.item_grid->get_visible() == widget::visibility::invisible) {
300  continue;
301  }
302 
303  placer_->add_item(item.item_grid->get_best_size());
304  }
305 }
306 
307 void pane::signal_handler_request_placement(dispatcher& dispatcher,
308  const event::ui_event event,
309  bool& handled)
310 {
311  DBG_GUI_E << LOG_HEADER << ' ' << event << ".";
312 
313  widget* wgt = dynamic_cast<widget*>(&dispatcher);
314  if(wgt) {
315  for(auto & item : items_)
316  {
317  if(item.item_grid->has_widget(*wgt)) {
318  if(item.item_grid->get_visible() != widget::visibility::invisible) {
319 
320  /*
321  * This time we call init layout but also the linked widget
322  * update this makes things work properly for the
323  * addon_list. This code can use some more tuning,
324  * polishing and testing.
325  */
326  item.item_grid->layout_initialize(false);
328 
329  /*
330  * By not calling init layout it uses its previous size
331  * what seems to work properly when showing and hiding
332  * items. Might fail with new items (haven't tested yet).
333  */
334  item.item_grid->place(point(), item.item_grid->get_best_size());
335  }
337  DBG_GUI_E << LOG_HEADER << ' ' << event << " handled.";
338  handled = true;
339  return;
340  }
341  }
342  }
343 
344  DBG_GUI_E << LOG_HEADER << ' ' << event << " failed to handle.";
345  assert(false);
346  handled = false;
347 }
348 
349 // }---------- BUILDER -----------{
350 
351 namespace implementation
352 {
353 
355  : builder_widget(cfg)
356  , grow_dir(*grow_direction::get_enum(cfg["grow_direction"].str()))
357  , parallel_items(cfg["parallel_items"].to_int())
358  , item_definition(new builder_grid(VALIDATE_WML_CHILD(cfg, "item_definition", missing_mandatory_wml_tag("pane", "item_definition"))))
359 {
360  VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
361 }
362 
363 std::unique_ptr<widget> builder_pane::build() const
364 {
365  return build(replacements_map());
366 }
367 
368 std::unique_ptr<widget> builder_pane::build(const replacements_map& /*replacements*/) const
369 {
370  return std::make_unique<pane>(*this);
371 }
372 
373 } // namespace implementation
374 
375 // }------------ END --------------
376 
377 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
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:272
void signal_handler_request_placement(dispatcher &dispatcher, const event::ui_event event, bool &handled)
Definition: pane.cpp:307
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:230
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: pane.cpp:217
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:200
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:222
void sort(const compare_functor_t &compare_functor)
Sorts the contents of the pane.
Definition: pane.cpp:179
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:211
virtual void impl_draw_children() override
See widget::impl_draw_children.
Definition: pane.cpp:167
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: pane.cpp:142
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:196
void place_children()
Places the children on the pane.
Definition: pane.cpp:240
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:153
void filter(const filter_functor_t &filter_functor)
Filters the contents of the pane.
Definition: pane.cpp:186
void set_origin_children()
Moves the children on the pane.
Definition: pane.cpp:256
void prepare_placement() const
Updates the placement for the child items.
Definition: pane.cpp:292
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:1024
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:209
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:354
virtual std::unique_ptr< widget > build() const override
Definition: pane.cpp:363
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.