The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
listbox.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 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
19
20#include "gettext.hpp"
21#include "gui/core/log.hpp"
30#include "sdl/rect.hpp"
31#include "wml_exception.hpp"
32#include <functional>
34
35#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
36#define LOG_HEADER LOG_SCOPE_HEADER + ':'
37
38namespace gui2
39{
40// ------------ WIDGET -----------{
41
42REGISTER_WIDGET(listbox)
43REGISTER_WIDGET3(listbox_definition, horizontal_listbox, nullptr)
44REGISTER_WIDGET3(listbox_definition, grid_listbox, nullptr)
45
46listbox::listbox(const implementation::builder_listbox_base& builder)
47 : scrollbar_container(builder, type())
48 , generator_(nullptr)
49 , placement_(builder.placement)
50 , list_builder_(builder.list_builder)
51 , orders_()
52 , callback_order_change_()
53{
54 const auto conf = cast_config_to<listbox_definition>();
55 assert(conf);
56
57 // FIXME: replacements (rightfully) clobber IDs. Is there a way around that?
59
60 if(auto header = builder.header) {
61 header->id = "_header_grid";
62 replacements.try_emplace("_header_grid_placeholder", std::move(header));
63 }
64
65 if(auto footer = builder.footer) {
66 footer->id = "_footer_grid";
67 replacements.try_emplace("_footer_grid_placeholder", std::move(footer));
68 }
69
70 conf->grid->build(get_grid(), replacements);
71
72 // "Inherited."
74
76 builder.has_minimum,
77 builder.has_maximum,
78 builder.placement,
79 builder.allow_selection);
80
81 // Save our *non-owning* pointer before this gets moved into the grid.
82 generator_ = generator.get();
83 assert(generator_);
84
85 generator->create_items(-1, *list_builder_, builder.list_data,
86 std::bind(&listbox::list_item_clicked, this, std::placeholders::_1));
87
88 // TODO: can we use the replacements system here?
89 swap_grid(nullptr, content_grid(), std::move(generator), "_list_grid");
90}
91
92grid& listbox::add_row(const widget_item& item, const int index)
93{
94 grid& row = generator_->create_item(index, *list_builder_, item, std::bind(&listbox::list_item_clicked, this, std::placeholders::_1));
95
96 resize_content(row);
97 return row;
98}
99
100grid& listbox::add_row(const widget_data& data, const int index)
101{
102 grid& row = generator_->create_item(index, *list_builder_, data, std::bind(&listbox::list_item_clicked, this, std::placeholders::_1));
103
104 resize_content(row);
105 return row;
106}
107
108void listbox::remove_row(const unsigned row, unsigned count)
109{
110 if(row >= get_item_count()) {
111 return;
112 }
113
114 if(!count || count + row > get_item_count()) {
115 count = get_item_count() - row;
116 }
117
118 int height_reduced = 0;
119 int width_reduced = 0;
120
121 const bool is_horizontal = placement_ == generator_base::horizontal_list;
122
123 // TODO: Fix this for horizontal listboxes
124 // Note the we have to use content_grid_ and cannot use "_list_grid" which is what generator_ uses.
125 int row_pos_y = is_horizontal ? -1 : generator_->item(row).get_y() - content_grid_->get_y();
126 int row_pos_x = is_horizontal ? -1 : 0;
127
128 for(; count; --count) {
130 if(is_horizontal) {
131 width_reduced += generator_->item(row).get_width();
132 } else {
133 height_reduced += generator_->item(row).get_height();
134 }
135 }
136
138 }
139
140 if((height_reduced != 0 || width_reduced != 0) && get_item_count() != 0) {
141 resize_content(-width_reduced, -height_reduced, row_pos_x, row_pos_y);
142 } else {
144 }
145}
146
148{
149 generator_->clear();
151}
152
154{
155 return generator_->get_item_count();
156}
157
158void listbox::set_row_active(const unsigned row, const bool active)
159{
160 generator_->item(row).set_active(active);
161}
162
163void listbox::set_row_shown(const unsigned row, const bool shown)
164{
166 assert(window);
167
168 const int selected_row = get_selected_row();
169
170 bool resize_needed = false;
171
172 // Local scope for invalidate_layout_blocker
173 {
174 window::invalidate_layout_blocker invalidate_layout_blocker(*window);
175
176 generator_->set_item_shown(row, shown);
177
178 point best_size = generator_->calculate_best_size();
179 generator_->place(generator_->get_origin(), {std::max(best_size.x, content_visible_area().w), best_size.y});
180
181 resize_needed = !content_resize_request();
182 }
183
184 if(resize_needed) {
186 } else {
187 content_grid_->set_visible_rectangle(content_visible_area());
188 queue_redraw(); // TODO: draw_manager - does this get the right area?
189 }
190
191 if(selected_row != get_selected_row()) {
192 fire(event::NOTIFY_MODIFIED, *this, nullptr);
193 }
194}
195
196void listbox::set_row_shown(const boost::dynamic_bitset<>& shown)
197{
198 assert(shown.size() == get_item_count());
199
200 if(generator_->get_items_shown() == shown) {
201 LOG_GUI_G << LOG_HEADER << " returning early";
202 return;
203 }
204
206 assert(window);
207
208 const int selected_row = get_selected_row();
209
210 bool resize_needed = false;
211
212 // Local scope for invalidate_layout_blocker
213 {
214 window::invalidate_layout_blocker invalidate_layout_blocker(*window);
215
216 for(std::size_t i = 0; i < shown.size(); ++i) {
217 generator_->set_item_shown(i, shown[i]);
218 }
219
220 point best_size = generator_->calculate_best_size();
221 generator_->place(generator_->get_origin(), {std::max(best_size.x, content_visible_area().w), best_size.y});
222
223 resize_needed = !content_resize_request(true);
224 }
225
226 if(resize_needed) {
228 } else {
229 content_grid_->set_visible_rectangle(content_visible_area());
230 queue_redraw(); // TODO: draw_manager - does this get the right area?
231 }
232
233 if(selected_row != get_selected_row()) {
234 fire(event::NOTIFY_MODIFIED, *this, nullptr);
235 }
236}
237
238std::size_t listbox::filter_rows_by(const std::function<bool(std::size_t)>& filter)
239{
240 boost::dynamic_bitset<> mask;
241 mask.resize(get_item_count(), true);
242
243 for(std::size_t i = 0; i < mask.size(); ++i) {
244 mask[i] = std::invoke(filter, i);
245 }
246
247 set_row_shown(mask);
248 return mask.count();
249}
250
251boost::dynamic_bitset<> listbox::get_rows_shown() const
252{
253 return generator_->get_items_shown();
254}
255
256const grid* listbox::get_row_grid(const unsigned row) const
257{
258 // rename this function and can we return a reference??
259 return &generator_->item(row);
260}
261
262grid* listbox::get_row_grid(const unsigned row)
263{
264 return &generator_->item(row);
265}
266
267bool listbox::select_row(const unsigned row, const bool select)
268{
269 if(row >= get_item_count()) {
270 throw std::invalid_argument("accessing invalid index " + std::to_string(row)
271 + " >= max " + std::to_string(get_item_count()) + " for listbox ‘" + id() + "’");
272 }
273
274 unsigned int before = generator_->get_selected_item_count();
275 generator_->select_item(row, select);
276
277 return before != generator_->get_selected_item_count();
278}
279
280bool listbox::select_row_at(const unsigned row, const bool select)
281{
282 return select_row(generator_->get_item_at_ordered(row), select);
283}
284
285bool listbox::row_selected(const unsigned row)
286{
287 return generator_->is_selected(row);
288}
289
291{
293}
294
296{
297 /** @todo Hack to capture the keyboard focus. */
299
300 for(std::size_t i = 0; i < generator_->get_item_count(); ++i) {
301 if(generator_->item(i).has_widget(caller)) {
302 toggle_button* checkbox = dynamic_cast<toggle_button*>(&caller);
303
304 if(checkbox != nullptr) {
305 generator_->select_item(i, checkbox->get_value_bool());
306 } else {
308 }
309
310 // TODO: enable this code once toggle_panel::set_value dispatches
311 // NOTIFY_MODIFED events. See comment in said function for more details.
312#if 0
313 selectable_item& selectable = dynamic_cast<selectable_item&>(caller);
314
315 generator_->select_item(i, selectable.get_value_bool());
316#endif
317
318 fire(event::NOTIFY_MODIFIED, *this, nullptr);
319 break;
320 }
321 }
322
323 const int selected_item = generator_->get_selected_item();
324 if(selected_item == -1) {
325 return;
326 }
327
329 rect r = generator_->item(selected_item).get_rectangle();
330
331 if(visible.overlaps(r)) {
332 r.x = visible.x;
333 r.w = visible.w;
334
336 }
337}
338
339void listbox::set_self_active(const bool /*active*/)
340{
341 /* DO NOTHING */
342}
343
345{
347 return true;
348 }
349
350 if(get_size() == point()) {
351 return false;
352 }
353
354 if(content_resize_request(true)) {
355 content_grid_->set_visible_rectangle(content_visible_area());
356 queue_redraw(); // TODO: draw_manager - does this get the right area?
357 return true;
358 }
359
360 return false;
361}
362
363void listbox::place(const point& origin, const point& size)
364{
365 utils::optional<unsigned> vertical_scrollbar_position, horizontal_scrollbar_position;
366
367 // Check if this is the first time placing the list box
368 if(get_origin() != point {-1, -1}) {
369 vertical_scrollbar_position = get_vertical_scrollbar_item_position();
370 horizontal_scrollbar_position = get_horizontal_scrollbar_item_position();
371 }
372
373 // Inherited.
374 scrollbar_container::place(origin, size);
375
376 const int selected_item = generator_->get_selected_item();
377 if(vertical_scrollbar_position && horizontal_scrollbar_position) {
378 LOG_GUI_L << LOG_HEADER << " restoring scroll position";
379
380 set_vertical_scrollbar_item_position(*vertical_scrollbar_position);
381 set_horizontal_scrollbar_item_position(*horizontal_scrollbar_position);
382 } else if(selected_item != -1) {
383 LOG_GUI_L << LOG_HEADER << " making the initially selected item visible";
384
386 rect rect = generator_->item(selected_item).get_rectangle();
387
388 rect.x = visible.x;
389 rect.w = visible.w;
390
392 }
393}
394
395void listbox::resize_content(const int width_modification,
396 const int height_modification,
397 const int width_modification_pos,
398 const int height_modification_pos)
399{
400 DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
401 << width_modification << " height_modification " << height_modification << ".";
402
404 width_modification, height_modification, width_modification_pos, height_modification_pos))
405 {
406 // Calculate new size.
407 point size = content_grid()->get_size();
408 size.x += width_modification;
409 size.y += height_modification;
410
411 // Set new size.
412 content_grid()->set_size(size);
414
415 // If the content grows assume it "overwrites" the old content.
416 if(width_modification < 0 || height_modification < 0) {
417 queue_redraw();
418 }
419
420 DBG_GUI_L << LOG_HEADER << " succeeded.";
421 } else {
422 DBG_GUI_L << LOG_HEADER << " failed.";
423 }
424}
425
427{
429 return;
430 }
431
432 DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " row size " << row.get_best_size()
433 << ".";
434
435 const point content = content_grid()->get_size();
436 point size = row.get_best_size();
437
438 if(size.x < content.x) {
439 size.x = 0;
440 } else {
441 size.x -= content.x;
442 }
443
444 resize_content(size.x, size.y);
445}
446
448{
449 // Get the size from the base class, then add any extra space for the header and footer.
451
452 if(const grid* header = get_grid().find_widget<const grid>("_header_grid", false, false)) {
453 if(header->get_visible() != widget::visibility::invisible) {
454 result.y += header->get_best_size().y;
455 }
456 }
457
458 if(const grid* footer = get_grid().find_widget<const grid>("_footer_grid", false, false)) {
459 if(footer->get_visible() != widget::visibility::invisible) {
460 result.y += footer->get_best_size().y;
461 }
462 }
463
464 return result;
465}
466
468{
471
472 // When scrolling make sure the new items are visible...
473 if(direction == KEY_VERTICAL) {
474 // ...but leave the horizontal scrollbar position.
475 rect.x = visible.x;
476 rect.w = visible.w;
477 } else {
478 // ...but leave the vertical scrollbar position.
479 rect.y = visible.y;
480 rect.h = visible.h;
481 }
482
484
485 fire(event::NOTIFY_MODIFIED, *this, nullptr);
486}
487
488void listbox::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
489{
490 generator_->handle_key_up_arrow(modifier, handled);
491
492 if(handled) {
494 } else {
495 // Inherited.
497 }
498}
499
500void listbox::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
501{
502 generator_->handle_key_down_arrow(modifier, handled);
503
504 if(handled) {
506 } else {
507 // Inherited.
509 }
510}
511
512void listbox::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
513{
514 generator_->handle_key_left_arrow(modifier, handled);
515
516 // Inherited.
517 if(handled) {
519 } else {
521 }
522}
523
524void listbox::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
525{
526 generator_->handle_key_right_arrow(modifier, handled);
527
528 // Inherited.
529 if(handled) {
531 } else {
533 }
534}
535
536void listbox::initialize_sorter(std::string_view id, generator_sort_array&& array)
537{
538 auto header = find_widget<grid>("_header_grid", false, false);
539 if(!header) return;
540
541 auto toggle = header->find_widget<selectable_item>(id, false, false);
542 if(!toggle) return;
543
544 const std::size_t i = orders_.size();
545 orders_.emplace_back(toggle, std::move(array));
546
547 widget& w = dynamic_cast<widget&>(*toggle);
548
549 // If the toggle was hidden previously, show it
551
552 // TODO: we can bind the pair directly if we remove the on-order callback
553 connect_signal_notify_modified(w,
554 std::bind(&listbox::order_by_column, this, i, std::placeholders::_1));
555}
556
558{
559 selectable_item& selectable = dynamic_cast<selectable_item&>(widget);
560
561 for(auto& [w, _] : orders_) {
562 if(w && w != &selectable) {
563 w->set_value(utils::to_underlying(sort_order::type::none));
564 }
565 }
566
567 auto order = sort_order::get_enum(selectable.get_value()).value_or(sort_order::type::none);
568 if(static_cast<unsigned>(order) > orders_[column].second.size()) {
569 return;
570 }
571
572 if(order == sort_order::type::none) {
573 order_by(std::less<unsigned>());
574 } else {
575 order_by(orders_[column].second[utils::to_underlying(order) - 1]);
576 }
577
578 if(callback_order_change_ != nullptr) {
579 callback_order_change_(column, order);
580 }
581}
582
588
589bool listbox::sort_helper::less(const t_string& lhs, const t_string& rhs)
590{
591 return translation::icompare(lhs, rhs) < 0;
592}
593
594bool listbox::sort_helper::more(const t_string& lhs, const t_string& rhs)
595{
596 return translation::icompare(lhs, rhs) > 0;
597}
598
599void listbox::set_active_sorter(std::string_view id, sort_order::type order, bool select_first)
600{
601 for(auto& [w, _] : orders_) {
602 if(!w || dynamic_cast<widget*>(w)->id() != id) continue;
603
604 // Set the state and fire a modified event to handle updating the list
605 w->set_value(utils::to_underlying(order), true);
606
607 if(select_first && generator_->get_item_count() > 0) {
608 select_row_at(0);
609 }
610 }
611}
612
613std::pair<widget*, sort_order::type> listbox::get_active_sorter() const
614{
615 for(const auto& [w, _] : orders_) {
616 if(!w) continue;
617
618 auto sort = sort_order::get_enum(w->get_value()).value_or(sort_order::type::none);
619 if(sort != sort_order::type::none) {
620 return { dynamic_cast<widget*>(w), sort };
621 }
622 }
623
624 return { nullptr, sort_order::type::none };
625}
626
628{
629 for(auto& [w, _] : orders_) {
630 if(w) {
631 w->set_value(utils::to_underlying(sort_order::type::none));
632 }
633 }
634}
635
636void listbox::set_content_size(const point& origin, const point& size)
637{
638 /** @todo This function needs more testing. */
639 assert(content_grid());
640
641 const int best_height = content_grid()->get_best_size().y;
642 const point s(size.x, size.y < best_height ? size.y : best_height);
643
644 content_grid()->place(origin, s);
645}
646
648{
649 assert(content_grid());
650
651 // If we haven't initialized, or have no content, just return.
652 point size = content_grid()->get_size();
653 if(size.x <= 0 || size.y <= 0) {
654 return;
655 }
656
658
661
662 queue_redraw();
663}
664
665// }---------- DEFINITION ---------{
666
669{
670 DBG_GUI_P << "Parsing listbox " << id;
671 load_resolutions<resolution>(cfg);
672}
673
676 , grid(nullptr)
677{
678 // Note the order should be the same as the enum state_t in listbox.hpp.
679 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("listbox_definition][resolution", "state_enabled")));
680 state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("listbox_definition][resolution", "state_disabled")));
681
682 auto child = VALIDATE_WML_CHILD(cfg, "grid", missing_mandatory_wml_tag("listbox_definition][resolution", "grid"));
683 grid = std::make_shared<builder_grid>(child);
684}
685
686namespace implementation
687{
688static std::vector<widget_data> parse_list_data(const config& data, const unsigned int req_cols)
689{
690 std::vector<widget_data> list_data;
691
692 for(const auto& row : data.child_range("row")) {
693 auto cols = row.child_range("column");
694
695 VALIDATE(static_cast<unsigned>(cols.size()) == req_cols,
696 _("‘list_data’ must have the same number of columns as the ‘list_definition’.")
697 );
698
699 for(const auto& c : cols) {
700 list_data.emplace_back();
701
702 for(const auto& [key, value] : c.attribute_range()) {
703 list_data.back()[""][key] = value.t_str();
704 }
705
706 for(const auto& w : c.child_range("widget")) {
707 VALIDATE(w.has_attribute("id"), missing_mandatory_wml_key("[list_data][row][column][widget]", "id"));
708
709 for(const auto& [key, value] : w.attribute_range()) {
710 list_data.back()[w["id"]][key] = value.t_str();
711 }
712 }
713 }
714 }
715
716 return list_data;
717}
718
719builder_listbox_base::builder_listbox_base(const config& cfg, const generator_base::placement placement)
721 , placement(placement)
722 , header(nullptr)
723 , footer(nullptr)
724 , list_builder(nullptr)
725 , list_data()
726 , has_minimum(cfg["has_minimum"].to_bool(true))
727 , has_maximum(cfg["has_maximum"].to_bool(true))
728 , allow_selection(cfg["allow_selection"].to_bool(true))
729{
730 auto l = cfg.optional_child("list_definition");
731 VALIDATE(l, _("No list defined."));
732
733 list_builder = std::make_shared<builder_grid>(*l);
734 assert(list_builder);
735
736 VALIDATE(list_builder->rows == 1, _("A ‘list_definition’ should contain one row."));
737
738 if(cfg.has_child("list_data")) {
740 }
741}
742
743std::unique_ptr<widget> builder_listbox_base::build() const
744{
745 auto widget = std::make_unique<listbox>(*this);
746 DBG_GUI_G << "Window builder: placed listbox '" << id << "' with definition '" << definition << "'.";
747 return widget;
748}
749
751 : builder_listbox_base(cfg, generator_base::vertical_list)
752{
753 if(auto h = cfg.optional_child("header")) {
754 header = std::make_shared<builder_grid>(*h);
755 }
756
757 if(auto f = cfg.optional_child("footer")) {
758 footer = std::make_shared<builder_grid>(*f);
759 }
760}
761
762} // namespace implementation
763
764// }------------ END --------------
765
766} // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
bool has_child(std::string_view key) const
Determine whether a config has a child or not.
Definition config.cpp:312
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
const grid & get_grid() const
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Abstract base class for the generator.
Definition generator.hpp:39
std::function< bool(unsigned, unsigned)> order_func
virtual void set_order(const order_func &order)=0
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)=0
Left arrow key pressed.
virtual unsigned get_selected_item_count() const =0
Returns the number of selected items.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)=0
Right arrow key pressed.
virtual void set_item_shown(const unsigned index, const bool show)=0
Shows or hides an item.
virtual void delete_item(const unsigned index)=0
Deletes an item.
virtual grid & item(const unsigned index)=0
Gets the grid of an item.
boost::dynamic_bitset get_items_shown() const
Returns the visibility of all the items as a bit set.
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)=0
Up arrow key pressed.
virtual void place(const point &origin, const point &size) override=0
See widget::place.
virtual grid & create_item(const int index, const builder_grid &list_builder, const widget_item &item_data, const std::function< void(widget &)> &callback)=0
Creates a new item.
virtual point calculate_best_size() const override=0
See widget::calculate_best_size.
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)=0
Down arrow key pressed.
virtual void select_item(const unsigned index, const bool select)=0
(De)selects an item.
virtual unsigned get_item_count() const =0
Returns the number of items.
static std::unique_ptr< generator_base > build(const bool has_minimum, const bool has_maximum, const placement placement, const bool select)
Create a new generator.
void toggle_item(const unsigned index)
Toggles the selection state of an item.
Definition generator.hpp:96
virtual bool is_selected(const unsigned index) const =0
Returns whether the item is selected.
placement
Determines how the items are placed.
Definition generator.hpp:48
virtual unsigned get_item_at_ordered(unsigned index_ordered) const =0
If a sort-order is being applied, maps from sorted to unsorted indices.
virtual void clear()=0
Deletes all items.
virtual int get_selected_item() const =0
Returns the selected item.
Basic template class to generate new items.
virtual void create_items(const int index, const builder_grid &list_builder, const std::vector< widget_data > &data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
Base container class.
Definition grid.hpp:32
void set_active(const bool active)
Activates all children.
Definition grid.cpp:167
virtual bool has_widget(const widget &widget) const override
See widget::has_widget.
Definition grid.cpp:655
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition grid.cpp:484
virtual void set_visible_rectangle(const rect &rectangle) override
See widget::set_visible_rectangle.
Definition grid.cpp:608
The listbox class.
Definition listbox.hpp:41
void update_layout()
Updates internal layout.
Definition listbox.cpp:647
void list_item_clicked(widget &caller)
Function to call after the user clicked on a row.
Definition listbox.cpp:295
void mark_as_unsorted()
Deactivates all sorting toggle buttons at the top, making the list look like it's not sorted.
Definition listbox.cpp:627
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition listbox.cpp:447
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition listbox.cpp:524
void set_row_active(const unsigned row, const bool active)
Makes a row active or inactive.
Definition listbox.cpp:158
std::vector< std::pair< selectable_item *, generator_sort_array > > orders_
Definition listbox.hpp:387
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition listbox.cpp:163
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition listbox.cpp:512
void order_by_column(unsigned column, widget &widget)
Definition listbox.cpp:557
void resize_content(const int width_modification, const int height_modification, const int width_modification_pos=-1, const int height_modification_pos=-1)
Resizes the content.
Definition listbox.cpp:395
void order_by(const generator_base::order_func &func)
Definition listbox.cpp:583
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition listbox.cpp:339
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition listbox.cpp:92
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition listbox.cpp:256
void set_active_sorter(std::string_view id, sort_order::type order, bool select_first=false)
Sorts the listbox by a pre-set sorting option.
Definition listbox.cpp:599
generator_base::placement placement_
Definition listbox.hpp:382
virtual void set_content_size(const point &origin, const point &size) override
Inherited from scrollbar_container.
Definition listbox.cpp:636
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition listbox.cpp:363
void update_visible_area_on_key_event(const KEY_SCROLL_DIRECTION direction)
Helper to update visible area after a key event.
Definition listbox.cpp:467
void initialize_sorter(std::string_view id, generator_sort_array &&)
Implementation detail of set_single_sorter.
Definition listbox.cpp:536
generator_base * generator_
Contains a pointer to the generator.
Definition listbox.hpp:380
std::function< void(unsigned, sort_order::type)> callback_order_change_
Definition listbox.hpp:389
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition listbox.cpp:267
bool update_content_size()
Request to update the size of the content after changing the content.
Definition listbox.cpp:344
boost::dynamic_bitset get_rows_shown() const
Returns a list of visible rows.
Definition listbox.cpp:251
std::size_t filter_rows_by(const std::function< bool(std::size_t)> &filter)
Hides all rows for which the given predicate returns false.
Definition listbox.cpp:238
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition listbox.cpp:500
std::pair< widget *, sort_order::type > get_active_sorter() const
Returns a widget pointer to the active sorter, along with its corresponding order.
Definition listbox.cpp:613
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition listbox.cpp:108
void clear()
Removes all the rows in the listbox, clearing it.
Definition listbox.cpp:147
int get_selected_row() const
Returns the first selected row.
Definition listbox.cpp:290
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition listbox.cpp:153
bool select_row_at(const unsigned row, const bool select=true)
Selects a row at the given position, regardless of sorting order.
Definition listbox.cpp:280
builder_grid_const_ptr list_builder_
Contains the builder for the new items.
Definition listbox.hpp:385
bool row_selected(const unsigned row)
Check if a row is selected.
Definition listbox.cpp:285
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition listbox.cpp:488
Base class for creating containers with one or two scrollbar(s).
void set_horizontal_scrollbar_item_position(const unsigned position)
Move the horizontal scrollbar to a position.
void show_content_rect(const rect &rect)
Shows a certain part of the content.
rect content_visible_area_
Cache for the visible area for the content.
void finalize_setup()
The builder needs to call us so we do our setup.
unsigned get_horizontal_scrollbar_item_position() const
Returns current position of the horizontal scrollbar.
virtual void place(const point &origin, const point &size) override
See widget::place.
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
const rect & content_visible_area() const
virtual point calculate_best_size() const override
See widget::calculate_best_size.
std::unique_ptr< grid > content_grid_
The grid that holds the content.
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
Small abstract helper class.
virtual void set_value(unsigned value, bool fire_event=false)=0
Select the styled_widget.
virtual unsigned get_value() const =0
Is the styled_widget selected?
Base class for all widgets.
Definition widget.hpp:55
point get_best_size() const
Gets the best size for the widget.
Definition widget.cpp:203
void set_visible(const visibility visible)
Definition widget.cpp:479
void queue_redraw()
Indicates that this widget should be redrawn.
Definition widget.cpp:464
visibility get_visible() const
Definition widget.cpp:506
point get_origin() const
Returns the screen origin of the widget.
Definition widget.cpp:311
unsigned get_width() const
Definition widget.cpp:336
int get_y() const
Definition widget.cpp:331
point get_size() const
Returns the size of the widget.
Definition widget.cpp:316
unsigned get_height() const
Definition widget.cpp:341
const std::string & id() const
Definition widget.cpp:110
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:
rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition widget.cpp:321
virtual void set_size(const point &size)
Sets the size of the widget.
Definition widget.cpp:236
Helper class to block invalidate_layout.
Definition window.hpp:232
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition window.hpp:59
void keyboard_capture(widget *widget)
Definition window.cpp:1197
void invalidate_layout()
Updates the size of the window.
Definition window.cpp:759
#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 LOG_GUI_G
Definition log.hpp:42
#define DBG_GUI_G
Definition log.hpp:41
#define DBG_GUI_P
Definition log.hpp:66
#define LOG_GUI_L
Definition log.hpp:56
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
This file contains the window object, this object is a top level container which has the event manage...
static std::vector< widget_data > parse_list_data(const config &data, const unsigned int req_cols)
Definition listbox.cpp:688
Generic file dialog.
std::array< generator_base::order_func, 2 > generator_sort_array
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
std::map< std::string, t_string > widget_item
Definition widget.hpp:33
void swap_grid(grid *g, grid *content_grid, std::unique_ptr< widget > widget, const std::string &id)
Swaps an item in a grid for another one.
Contains the implementation details for lexical_cast and shouldn't be used directly.
int icompare(const std::string &s1, const std::string &s2)
Case-insensitive lexicographical comparison.
Definition gettext.cpp:519
constexpr std::underlying_type_t< Enum > to_underlying(Enum e) noexcept
Definition general.hpp:42
int w
Definition pathfind.cpp:188
std::string_view data
Definition picture.cpp:188
Contains the SDL_Rect helper code.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
#define REGISTER_WIDGET3(type, id, key)
Registers a widget.
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
std::vector< widget_data > list_data
Listbox data.
Definition listbox.hpp:480
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
Definition listbox.cpp:743
std::string definition
Parameters for the styled_widget.
static bool less(const T &lhs, const T &rhs)
Definition listbox.hpp:258
static bool more(const T &lhs, const T &rhs)
Definition listbox.hpp:264
listbox_definition(const config &cfg)
Definition listbox.cpp:667
std::vector< state_definition > state
Holds a 2D point.
Definition point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
static constexpr utils::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition enum_base.hpp:57
static map_location::direction s
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
std::string missing_mandatory_wml_key(const std::string &section, const std::string &key, const std::string &primary_key, const std::string &primary_value)
Returns a standard message for a missing wml key (attribute).
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.
#define i
#define h
#define f
#define c