The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
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"
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
35namespace 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
117unsigned 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
142void 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
151}
152
153void 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
179void pane::sort(const compare_functor_t& compare_functor)
180{
181 items_.sort(compare_functor);
182
184}
185
186void 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
196void pane::request_reduce_width(const unsigned /*maximum_width*/)
197{
198}
199
200widget* 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
205const widget* pane::find_at(const point& coordinate,
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
230grid* pane::get_grid(const unsigned id)
231{
232 return pane_implementation::get_grid(this, id);
233}
234
235const 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
307void 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
351namespace implementation
352{
353
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
363std::unique_ptr<widget> builder_pane::build() const
364{
365 return build(replacements_map());
366}
367
368std::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:157
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.
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:1028
This file contains the definitions for the gui2::event::message class.
#define LOG_HEADER
const config * cfg
static std::string _(const char *str)
Definition gettext.hpp:100
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...
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
@ REQUEST_PLACEMENT
Definition handler.hpp:182
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.
typename const_clone< D, S >::pointer const_clone_ptr
std::string_view data
Definition picture.cpp:188
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.