The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
listbox.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #ifndef GUI2_EXPERIMENTAL_LISTBOX
16 
17 #define GETTEXT_DOMAIN "wesnoth-lib"
18 
19 #include "gui/widgets/listbox.hpp"
20 
21 #include "gettext.hpp"
24 #include "gui/core/log.hpp"
29 #include "gui/widgets/pane.hpp"
31 #include "gui/widgets/settings.hpp"
33 #include "gui/widgets/viewport.hpp"
35 #include "gui/widgets/window.hpp"
36 #include "sdl/rect.hpp"
37 #include "utils/functional.hpp"
38 
39 #include <boost/optional.hpp>
40 
41 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
42 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
43 
44 namespace gui2
45 {
46 // ------------ WIDGET -----------{
47 
48 REGISTER_WIDGET(listbox)
49 REGISTER_WIDGET3(listbox_definition, horizontal_listbox, nullptr)
50 REGISTER_WIDGET3(listbox_definition, grid_listbox, nullptr)
51 
52 listbox::listbox(const implementation::builder_styled_widget& builder,
53  const generator_base::placement placement,
54  builder_grid_ptr list_builder,
55  const bool has_minimum,
56  const bool has_maximum,
57  const bool select)
58  : scrollbar_container(builder, get_control_type())
59  , generator_(generator_base::build(has_minimum, has_maximum, placement, select))
60  , is_horizontal_(placement == generator_base::horizontal_list)
61  , list_builder_(list_builder)
62  , need_layout_(false)
63  , orders_()
64  , callback_order_change_()
65 {
66 }
67 
68 grid& listbox::add_row(const string_map& item, const int index)
69 {
70  assert(generator_);
71  grid& row = generator_->create_item(index, list_builder_, item, std::bind(&listbox::list_item_clicked, this, _1));
72 
73  resize_content(row);
74 
75  return row;
76 }
77 
78 grid& listbox::add_row(const std::map<std::string /* widget id */, string_map>& data, const int index)
79 {
80  assert(generator_);
81  grid& row = generator_->create_item(index, list_builder_, data, std::bind(&listbox::list_item_clicked, this, _1));
82 
83  resize_content(row);
84 
85  return row;
86 }
87 
88 void listbox::remove_row(const unsigned row, unsigned count)
89 {
90  assert(generator_);
91 
92  if(row >= get_item_count()) {
93  return;
94  }
95 
96  if(!count || count + row > get_item_count()) {
97  count = get_item_count() - row;
98  }
99 
100  int height_reduced = 0;
101  int width_reduced = 0;
102 
103  // TODO: Fix this for horizontal listboxes
104  // Note the we have to use content_grid_ and cannot use "_list_grid" which is what generator_ uses.
105  int row_pos_y = is_horizontal_ ? -1 : generator_->item(row).get_y() - content_grid_->get_y();
106  int row_pos_x = is_horizontal_ ? -1 : 0;
107 
108  for(; count; --count) {
110  if(is_horizontal_) {
111  width_reduced += generator_->item(row).get_width();
112  } else {
113  height_reduced += generator_->item(row).get_height();
114  }
115  }
116 
117  generator_->delete_item(row);
118  }
119 
120  if((height_reduced != 0 || width_reduced != 0) && get_item_count() != 0) {
121  resize_content(-width_reduced, -height_reduced, row_pos_x, row_pos_y);
122  } else {
124  }
125 }
126 
128 {
129  generator_->clear();
131 }
132 
133 unsigned listbox::get_item_count() const
134 {
135  assert(generator_);
136  return generator_->get_item_count();
137 }
138 
139 void listbox::set_row_active(const unsigned row, const bool active)
140 {
141  assert(generator_);
142  generator_->item(row).set_active(active);
143 }
144 
145 void listbox::set_row_shown(const unsigned row, const bool shown)
146 {
147  assert(generator_);
148 
149  window* window = get_window();
150  assert(window);
151 
152  const int selected_row = get_selected_row();
153 
154  bool resize_needed = false;
155 
156  // Local scope for invalidate_layout_blocker
157  {
158  window::invalidate_layout_blocker invalidate_layout_blocker(*window);
159 
160  generator_->set_item_shown(row, shown);
161 
162  point best_size = generator_->calculate_best_size();
163  generator_->place(generator_->get_origin(), {std::max(best_size.x, content_visible_area().w), best_size.y});
164 
165  resize_needed = !content_resize_request();
166  }
167 
168  if(resize_needed) {
169  window->invalidate_layout();
170  } else {
171  content_grid_->set_visible_rectangle(content_visible_area());
172  set_is_dirty(true);
173  }
174 
175  if(selected_row != get_selected_row()) {
176  fire(event::NOTIFY_MODIFIED, *this, nullptr);
177  }
178 }
179 
180 void listbox::set_row_shown(const boost::dynamic_bitset<>& shown)
181 {
182  assert(generator_);
183  assert(shown.size() == get_item_count());
184 
185  if(generator_->get_items_shown() == shown) {
186  LOG_GUI_G << LOG_HEADER << " returning early" << std::endl;
187  return;
188  }
189 
190  window* window = get_window();
191  assert(window);
192 
193  const int selected_row = get_selected_row();
194 
195  bool resize_needed = false;
196 
197  // Local scope for invalidate_layout_blocker
198  {
199  window::invalidate_layout_blocker invalidate_layout_blocker(*window);
200 
201  for(size_t i = 0; i < shown.size(); ++i) {
202  generator_->set_item_shown(i, shown[i]);
203  }
204 
205  point best_size = generator_->calculate_best_size();
206  generator_->place(generator_->get_origin(), {std::max(best_size.x, content_visible_area().w), best_size.y});
207 
208  resize_needed = !content_resize_request();
209  }
210 
211  if(resize_needed) {
212  window->invalidate_layout();
213  } else {
214  content_grid_->set_visible_rectangle(content_visible_area());
215  set_is_dirty(true);
216  }
217 
218  if(selected_row != get_selected_row()) {
219  fire(event::NOTIFY_MODIFIED, *this, nullptr);
220  }
221 }
222 
223 boost::dynamic_bitset<> listbox::get_rows_shown() const
224 {
225  return generator_->get_items_shown();
226 }
227 
229 {
230  for(size_t i = 0; i < get_item_count(); i++) {
231  if(generator_->get_item_shown(i)) {
232  return true;
233  }
234  }
235 
236  return false;
237 }
238 
239 const grid* listbox::get_row_grid(const unsigned row) const
240 {
241  assert(generator_);
242  // rename this function and can we return a reference??
243  return &generator_->item(row);
244 }
245 
246 grid* listbox::get_row_grid(const unsigned row)
247 {
248  assert(generator_);
249  return &generator_->item(row);
250 }
251 
252 bool listbox::select_row(const unsigned row, const bool select)
253 {
254  assert(generator_);
255 
256  unsigned int before = generator_->get_selected_item_count();
257  generator_->select_item(row, select);
258 
259  return before != generator_->get_selected_item_count();
260 }
261 
262 bool listbox::select_row_at(const unsigned row, const bool select)
263 {
264  assert(generator_);
265  return select_row(generator_->get_item_at_ordered(row), select);
266 }
267 
268 bool listbox::row_selected(const unsigned row)
269 {
270  assert(generator_);
271  return generator_->is_selected(row);
272 }
273 
275 {
276  assert(generator_);
277  return generator_->get_selected_item();
278 }
279 
281 {
282  assert(generator_);
283 
284  /** @todo Hack to capture the keyboard focus. */
285  get_window()->keyboard_capture(this);
286 
287  for(size_t i = 0; i < generator_->get_item_count(); ++i) {
288  if(generator_->item(i).has_widget(caller)) {
289  toggle_button* checkbox = dynamic_cast<toggle_button*>(&caller);
290 
291  if(checkbox != nullptr) {
292  generator_->select_item(i, checkbox->get_value_bool());
293  } else {
295  }
296 
297  // TODO: enable this code once toggle_panel::set_value dispatches
298  // NOTIFY_MODIFED events. See comment in said function for more details.
299 #if 0
300  selectable_item& selectable = dynamic_cast<selectable_item&>(caller);
301 
302  generator_->select_item(i, selectable.get_value_bool());
303 #endif
304 
305  fire(event::NOTIFY_MODIFIED, *this, nullptr);
306  break;
307  }
308  }
309 
310  const int selected_item = generator_->get_selected_item();
311  if(selected_item == -1) {
312  return;
313  }
314 
315  const SDL_Rect& visible = content_visible_area();
316  SDL_Rect rect = generator_->item(selected_item).get_rectangle();
317 
318  if(sdl::rects_overlap(visible, rect)) {
319  rect.x = visible.x;
320  rect.w = visible.w;
321 
322  show_content_rect(rect);
323  }
324 }
325 
326 void listbox::set_self_active(const bool /*active*/)
327 {
328  /* DO NOTHING */
329 }
330 
332 {
334  return true;
335  }
336 
337  if(get_size() == point()) {
338  return false;
339  }
340 
341  if(content_resize_request(true)) {
342  content_grid_->set_visible_rectangle(content_visible_area());
343  set_is_dirty(true);
344  return true;
345  }
346 
347  return false;
348 }
349 
350 void listbox::place(const point& origin, const point& size)
351 {
352  boost::optional<unsigned> vertical_scrollbar_position, horizontal_scrollbar_position;
353 
354  // Check if this is the first time placing the list box
355  if(get_origin() != point {-1, -1}) {
356  vertical_scrollbar_position = get_vertical_scrollbar_item_position();
357  horizontal_scrollbar_position = get_horizontal_scrollbar_item_position();
358  }
359 
360  // Inherited.
361  scrollbar_container::place(origin, size);
362 
363  const int selected_item = generator_->get_selected_item();
364  if(vertical_scrollbar_position && horizontal_scrollbar_position) {
365  LOG_GUI_L << LOG_HEADER << " restoring scroll position" << std::endl;
366 
367  set_vertical_scrollbar_item_position(*vertical_scrollbar_position);
368  set_horizontal_scrollbar_item_position(*horizontal_scrollbar_position);
369  } else if(selected_item != -1) {
370  LOG_GUI_L << LOG_HEADER << " making the initially selected item visible" << std::endl;
371 
372  const SDL_Rect& visible = content_visible_area();
373  SDL_Rect rect = generator_->item(selected_item).get_rectangle();
374 
375  rect.x = visible.x;
376  rect.w = visible.w;
377 
378  show_content_rect(rect);
379  }
380 }
381 
382 void listbox::resize_content(const int width_modification,
383  const int height_modification,
384  const int width_modification_pos,
385  const int height_modification_pos)
386 {
387  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " width_modification "
388  << width_modification << " height_modification " << height_modification << ".\n";
389 
391  width_modification, height_modification, width_modification_pos, height_modification_pos))
392  {
393  // Calculate new size.
395  size.x += width_modification;
396  size.y += height_modification;
397 
398  // Set new size.
399  content_grid()->set_size(size);
400 
401  // Set status.
402  need_layout_ = true;
403 
404  // If the content grows assume it "overwrites" the old content.
405  if(width_modification < 0 || height_modification < 0) {
406  set_is_dirty(true);
407  }
408 
409  DBG_GUI_L << LOG_HEADER << " succeeded.\n";
410  } else {
411  DBG_GUI_L << LOG_HEADER << " failed.\n";
412  }
413 }
414 
416 {
417  if(row.get_visible() == visibility::invisible) {
418  return;
419  }
420 
421  DBG_GUI_L << LOG_HEADER << " current size " << content_grid()->get_size() << " row size " << row.get_best_size()
422  << ".\n";
423 
424  const point content = content_grid()->get_size();
425  point size = row.get_best_size();
426 
427  if(size.x < content.x) {
428  size.x = 0;
429  } else {
430  size.x -= content.x;
431  }
432 
433  resize_content(size.x, size.y);
434 }
435 
437 {
438  layout_children(false);
439 }
440 
441 void listbox::child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack)
442 {
443  // Inherited.
445 
446  assert(generator_);
447  std::vector<widget*> child_call_stack = call_stack;
448  generator_->populate_dirty_list(caller, child_call_stack);
449 }
450 
452 {
453  // Get the size from the base class, then add any extra space for the header and footer.
455 
456  if(const grid* header = find_widget<const grid>(&get_grid(), "_header_grid", false, false)) {
457  result.y += header->get_best_size().y;
458  }
459 
460  if(const grid* footer = find_widget<const grid>(&get_grid(), "_footer_grid", false, false)) {
461  result.y += footer->get_best_size().y;
462  }
463 
464  return result;
465 }
466 
468 {
469  const SDL_Rect& visible = content_visible_area();
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 
483  show_content_rect(rect);
484 
485  fire(event::NOTIFY_MODIFIED, *this, nullptr);
486 }
487 
488 void listbox::handle_key_up_arrow(SDL_Keymod modifier, bool& handled)
489 {
490  assert(generator_);
491 
492  generator_->handle_key_up_arrow(modifier, handled);
493 
494  if(handled) {
496  } else {
497  // Inherited.
498  scrollbar_container::handle_key_up_arrow(modifier, handled);
499  }
500 }
501 
502 void listbox::handle_key_down_arrow(SDL_Keymod modifier, bool& handled)
503 {
504  assert(generator_);
505 
506  generator_->handle_key_down_arrow(modifier, handled);
507 
508  if(handled) {
510  } else {
511  // Inherited.
512  scrollbar_container::handle_key_up_arrow(modifier, handled);
513  }
514 }
515 
516 void listbox::handle_key_left_arrow(SDL_Keymod modifier, bool& handled)
517 {
518  assert(generator_);
519 
520  generator_->handle_key_left_arrow(modifier, handled);
521 
522  // Inherited.
523  if(handled) {
525  } else {
527  }
528 }
529 
530 void listbox::handle_key_right_arrow(SDL_Keymod modifier, bool& handled)
531 {
532  assert(generator_);
533 
534  generator_->handle_key_right_arrow(modifier, handled);
535 
536  // Inherited.
537  if(handled) {
539  } else {
541  }
542 }
543 
545  builder_grid_const_ptr footer,
546  const std::vector<std::map<std::string, string_map>>& list_data)
547 {
548  // "Inherited."
550 
551  assert(generator_);
552 
553  if(header) {
554  swap_grid(&get_grid(), content_grid(), header->build(), "_header_grid");
555  }
556 
557  grid& p = find_widget<grid>(this, "_header_grid", false);
558 
559  for(unsigned i = 0, max = std::max(p.get_cols(), p.get_rows()); i < max; ++i) {
560  //
561  // TODO: I had to change this to case to a toggle_button in order to use a signal handler.
562  // Should probably look into a way to make it more general like it was before (used to be
563  // cast to selectable_item).
564  //
565  // - vultraz, 2017-08-23
566  //
567  if(toggle_button* selectable = find_widget<toggle_button>(&p, "sort_" + std::to_string(i), false, false)) {
568  // Register callback to sort the list.
569  connect_signal_notify_modified(*selectable, std::bind(&listbox::order_by_column, this, i, _1));
570 
571  if(orders_.size() < max) {
572  orders_.resize(max);
573  }
574 
575  orders_[i].first = selectable;
576  }
577  }
578 
579  if(footer) {
580  swap_grid(&get_grid(), content_grid(), footer->build(), "_footer_grid");
581  }
582 
583  generator_->create_items(-1, list_builder_, list_data, std::bind(&listbox::list_item_clicked, this, _1));
584  swap_grid(nullptr, content_grid(), generator_, "_list_grid");
585 }
586 
587 void listbox::order_by_column(unsigned column, widget& widget)
588 {
589  selectable_item& selectable = dynamic_cast<selectable_item&>(widget);
590  if(column >= orders_.size()) {
591  return;
592  }
593 
594  for(auto& pair : orders_) {
595  if(pair.first != nullptr && pair.first != &selectable) {
596  pair.first->set_value(SORT_NONE);
597  }
598  }
599 
600  SORT_ORDER order = static_cast<SORT_ORDER>(selectable.get_value());
601 
602  if(static_cast<unsigned int>(order) > orders_[column].second.size()) {
603  return;
604  }
605 
606  if(order == SORT_NONE) {
607  order_by(std::less<unsigned>());
608  } else {
609  order_by(orders_[column].second[order - 1]);
610  }
611 
612  if(callback_order_change_ != nullptr) {
613  callback_order_change_(column, order);
614  }
615 }
616 
618 {
619  generator_->set_order(func);
620 
621  set_is_dirty(true);
622  need_layout_ = true;
623 }
624 
625 void listbox::set_column_order(unsigned col, const generator_sort_array& func)
626 {
627  if(col >= orders_.size()) {
628  orders_.resize(col + 1);
629  }
630 
631  orders_[col].second = func;
632 }
633 
635 {
636  set_column_order(col, {{
637  [f](int lhs, int rhs) { return translation::icompare(f(lhs), f(rhs)) < 0; },
638  [f](int lhs, int rhs) { return translation::icompare(f(lhs), f(rhs)) > 0; }
639  }});
640 }
641 
642 void listbox::set_active_sorting_option(const order_pair& sort_by, const bool select_first)
643 {
644  // TODO: should this be moved to a public header_grid() getter function?
645  grid& header_grid = find_widget<grid>(this, "_header_grid", false);
646 
647  selectable_item& w = find_widget<selectable_item>(&header_grid, "sort_" + std::to_string(sort_by.first), false);
648 
649  // Set the sorting toggle widgets' value (in this case, its state) to the given sorting
650  // order. This is necessary since the widget's value is used to determine the order in
651  // @ref order_by_column in lieu of a direction being passed directly.
652  w.set_value(static_cast<int>(sort_by.second));
653 
654  order_by_column(sort_by.first, dynamic_cast<widget&>(w));
655 
656  if(select_first && generator_->get_item_count() > 0) {
657  select_row_at(0);
658  }
659 }
660 
662 {
663  for(unsigned int column = 0; column < orders_.size(); ++column) {
664  selectable_item* w = orders_[column].first;
665 
666  if(w && w->get_value() != SORT_NONE) {
667  return std::make_pair(column, static_cast<SORT_ORDER>(w->get_value()));
668  }
669  }
670 
671  return std::make_pair(-1, SORT_NONE);
672 }
673 
675 {
676  for(auto& pair : orders_) {
677  if(pair.first != nullptr) {
678  pair.first->set_value(SORT_NONE);
679  }
680  }
681 }
682 
683 void listbox::set_content_size(const point& origin, const point& size)
684 {
685  /** @todo This function needs more testing. */
686  assert(content_grid());
687 
688  const int best_height = content_grid()->get_best_size().y;
689  const point s(size.x, size.y < best_height ? size.y : best_height);
690 
691  content_grid()->place(origin, s);
692 }
693 
694 void listbox::layout_children(const bool force)
695 {
696  assert(content_grid());
697 
698  if(need_layout_ || force) {
699  const int selected_item = generator_->get_selected_item();
700 
702 
703  const SDL_Rect& visible = content_visible_area_;
704 
706 
707  if(selected_item != -1) {
708  SDL_Rect rect = generator_->item(selected_item).get_rectangle();
709 
710  rect.x = visible.x;
711  rect.w = visible.w;
712 
713  show_content_rect(rect);
714  }
715 
716  need_layout_ = false;
717  set_is_dirty(true);
718  }
719 }
720 
721 // }---------- DEFINITION ---------{
722 
725 {
726  DBG_GUI_P << "Parsing listbox " << id << '\n';
727 
728  load_resolutions<resolution>(cfg);
729 }
730 
731 /*WIKI
732  * @page = GUIWidgetDefinitionWML
733  * @order = 1_listbox
734  * @begin{parent}{name="gui/"}
735  * @begin{tag}{name="listbox_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
736  * == Listbox ==
737  *
738  * @macro = listbox_description
739  *
740  * The definition of a listbox contains the definition of its scrollbar.
741  *
742  * The resolution for a listbox also contains the following keys:
743  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super=generic/widget_definition/resolution}
744  * @begin{table}{config}
745  * scrollbar & section & & A grid containing the widgets for the
746  * scrollbar. The scrollbar has some special
747  * widgets so it can make default behavior
748  * for certain widgets. $
749  * @end{table}
750  * @begin{table}{dialog_widgets}
751  * _begin & & clickable & o & Moves the position to the beginning
752  * of the list. $
753  * _line_up & & clickable & o & Move the position one item up. (NOTE
754  * if too many items to move per item it
755  * might be more items.) $
756  * _half_page_up & & clickable & o &
757  * Move the position half the number of the
758  * visible items up. (See note at
759  * _line_up.) $
760  * _page_up & & clickable & o & Move the position the number of
761  * visible items up. (See note at
762  * _line_up.) $
763  *
764  * _end & & clickable & o & Moves the position to the end of the
765  * list. $
766  * _line_down & & clickable & o & Move the position one item down.(See
767  * note at _line_up.) $
768  * _half_page_down & & clickable & o &
769  * Move the position half the number of the
770  * visible items down. (See note at
771  * _line_up.) $
772  * _page_down & & clickable & o & Move the position the number of
773  * visible items down. (See note at
774  * _line_up.) $
775  *
776  * _scrollbar & & vertical_scrollbar & m &
777  * This is the scrollbar so the user can
778  * scroll through the list. $
779  * @end{table}
780  * A clickable is one of:
781  * * button
782  * * repeating_button
783  * @{allow}{link}{name="gui/window/resolution/grid/row/column/button"}
784  * @{allow}{link}{name="gui/window/resolution/grid/row/column/repeating_button"}
785  * The following states exist:
786  * * state_enabled, the listbox is enabled.
787  * * state_disabled, the listbox is disabled.
788  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
789  * @end{tag}{name="state_enabled"}
790  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
791  * @end{tag}{name="state_disabled"}
792  * @allow{link}{name="gui/window/resolution/grid"}
793  * @end{tag}{name="resolution"}
794  * @end{tag}{name="listbox_definition"}
795  * @end{parent}{name="gui/"}
796  */
797 
798 /*WIKI
799  * @page = GUIWidgetDefinitionWML
800  * @order = 1_horizonal_listbox
801  *
802  * == Horizontal listbox ==
803  * @begin{parent}{name="gui/"}
804  * @begin{tag}{name="horizontal_listbox_definition"}{min=0}{max=-1}{super="gui/listbox_definition"}
805  * @end{tag}{name="horizontal_listbox_definition"}
806  * @end{parent}{name="gui/"}
807  * @macro = horizontal_listbox_description
808  * The definition of a horizontal listbox is the same as for a normal listbox.
809  */
811  : resolution_definition(cfg)
812  , grid(nullptr)
813 {
814  // Note the order should be the same as the enum state_t in listbox.hpp.
815  state.emplace_back(cfg.child("state_enabled"));
816  state.emplace_back(cfg.child("state_disabled"));
817 
818  const config& child = cfg.child("grid");
819  VALIDATE(child, _("No grid defined."));
820 
821  grid = std::make_shared<builder_grid>(child);
822 }
823 
824 // }---------- BUILDER -----------{
825 
826 /*WIKI_MACRO
827  * @begin{macro}{listbox_description}
828  *
829  * A listbox is a styled_widget that holds several items of the same type.
830  * Normally the items in a listbox are ordered in rows, this version
831  * might allow more options for ordering the items in the future.
832  * @end{macro}
833  */
834 
835 /*WIKI
836  * @page = GUIWidgetInstanceWML
837  * @order = 2_listbox
838  *
839  * == Listbox ==
840  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
841  * @begin{tag}{name="listbox"}{min=0}{max=-1}{super="generic/widget_instance"}
842  * @macro = listbox_description
843  *
844  * List with the listbox specific variables:
845  * @begin{table}{config}
846  * vertical_scrollbar_mode & scrollbar_mode & initial_auto &
847  * Determines whether or not to show the
848  * scrollbar. $
849  * horizontal_scrollbar_mode & scrollbar_mode & initial_auto &
850  * Determines whether or not to show the
851  * scrollbar. $
852  *
853  * header & grid & [] & Defines the grid for the optional
854  * header. (This grid will automatically
855  * get the id _header_grid.) $
856  * footer & grid & [] & Defines the grid for the optional
857  * footer. (This grid will automatically
858  * get the id _footer_grid.) $
859  *
860  * list_definition & section & & This defines how a listbox item
861  * looks. It must contain the grid
862  * definition for 1 row of the list. $
863  *
864  * list_data & section & [] & A grid alike section which stores the
865  * initial data for the listbox. Every row
866  * must have the same number of columns as
867  * the 'list_definition'. $
868  *
869  * has_minimum & bool & true & If false, less than one row can be selected. $
870  *
871  * has_maximum & bool & true & If false, more than one row can be selected. $
872  *
873  * @end{table}
874  * @begin{tag}{name="header"}{min=0}{max=1}{super="gui/window/resolution/grid"}
875  * @end{tag}{name="header"}
876  * @begin{tag}{name="footer"}{min=0}{max=1}{super="gui/window/resolution/grid"}
877  * @end{tag}{name="footer"}
878  * @begin{tag}{name="list_definition"}{min=0}{max=1}
879  * @begin{tag}{name="row"}{min=1}{max=1}{super="generic/listbox_grid/row"}
880  * @end{tag}{name="row"}
881  * @end{tag}{name="list_definition"}x
882  * @begin{tag}{name="list_data"}{min=0}{max=1}{super="generic/listbox_grid"}
883  * @end{tag}{name="list_data"}
884  *
885  * In order to force widgets to be the same size inside a listbox, the widgets
886  * need to be inside a linked_group.
887  *
888  * Inside the list section there are only the following widgets allowed
889  * * grid (to nest)
890  * * selectable widgets which are
891  * ** toggle_button
892  * ** toggle_panel
893  * @end{tag}{name="listbox"}
894  *
895  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
896  */
897 
898 /*WIKI
899  * @begin{parent}{name="generic/"}
900  * @begin{tag}{name="listbox_grid"}{min="0"}{max="-1"}
901  * @begin{tag}{name="row"}{min="0"}{max="-1"}
902  * @begin{table}{config}
903  * grow_factor & unsigned & 0 & The grow factor for a row. $
904  * @end{table}
905  * @begin{tag}{name="column"}{min="0"}{max="-1"}{super="gui/window/resolution/grid/row/column"}
906  * @begin{table}{config}
907  * label & t_string & "" & $
908  * tooltip & t_string & "" & $
909  * icon & t_string & "" & $
910  * @end{table}
911  * @allow{link}{name="gui/window/resolution/grid/row/column/toggle_button"}
912  * @allow{link}{name="gui/window/resolution/grid/row/column/toggle_panel"}
913  * @end{tag}{name="column"}
914  * @end{tag}{name="row"}
915  * @end{tag}{name="listbox_grid"}
916  * @end{parent}{name="generic/"}
917  */
918 
919 namespace implementation
920 {
921 static std::vector<std::map<std::string, string_map>> parse_list_data(const config& data, const unsigned int req_cols)
922 {
923  std::vector<std::map<std::string, string_map>> list_data;
924 
925  for(const auto& row : data.child_range("row")) {
926  auto cols = row.child_range("column");
927 
928  VALIDATE(static_cast<unsigned>(cols.size()) == req_cols,
929  _("'list_data' must have the same number of columns as the 'list_definition'.")
930  );
931 
932  for(const auto& c : cols) {
933  list_data.emplace_back();
934 
935  for(const auto& i : c.attribute_range()) {
936  list_data.back()[""][i.first] = i.second;
937  }
938 
939  for(const auto& w : c.child_range("widget")) {
940  VALIDATE(w.has_attribute("id"), missing_mandatory_wml_key("[list_data][row][column][widget]", "id"));
941 
942  for(const auto& i : w.attribute_range()) {
943  list_data.back()[w["id"]][i.first] = i.second;
944  }
945  }
946  }
947  }
948 
949  return list_data;
950 }
951 
952 builder_listbox::builder_listbox(const config& cfg)
953  : builder_styled_widget(cfg)
954  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
955  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
956  , header(nullptr)
957  , footer(nullptr)
958  , list_builder(nullptr)
959  , list_data()
960  , has_minimum_(cfg["has_minimum"].to_bool(true))
961  , has_maximum_(cfg["has_maximum"].to_bool(true))
962 {
963  if(const config& h = cfg.child("header")) {
964  header = std::make_shared<builder_grid>(h);
965  }
966 
967  if(const config& f = cfg.child("footer")) {
968  footer = std::make_shared<builder_grid>(f);
969  }
970 
971  const config& l = cfg.child("list_definition");
972 
973  VALIDATE(l, _("No list defined."));
974 
975  list_builder = std::make_shared<builder_grid>(l);
976  assert(list_builder);
977 
978  VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
979 
980  if(cfg.has_child("list_data")) {
981  list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
982  }
983 }
984 
986 {
987 #ifdef GUI2_EXPERIMENTAL_LISTBOX
988  list_view* widget = new list_view(true, true, generator_base::vertical_list, true, list_builder);
989 
990  // init_control(widget);
991  if(!list_data.empty()) {
992  widget->append_rows(list_data);
993  }
994 
995  return widget;
996 #else
997 
999 
1002 
1003  DBG_GUI_G << "Window builder: placed listbox '" << id << "' with definition '" << definition << "'.\n";
1004 
1005  const auto conf = widget->cast_config_to<listbox_definition>();
1006  assert(conf);
1007 
1008  widget->init_grid(conf->grid);
1009 
1010  widget->finalize(header, footer, list_data);
1011 
1012  return widget;
1013 #endif
1014 }
1015 
1016 /*WIKI_MACRO
1017  * @begin{macro}{horizontal_listbox_description}
1018  *
1019  * A horizontal listbox is a styled_widget that holds several items of the
1020  * same type. Normally the items in a listbox are ordered in rows,
1021  * this version orders them in columns instead.
1022  * @end{macro}
1023  */
1024 
1025 /*WIKI
1026  * @page = GUIWidgetInstanceWML
1027  * @order = 2_horizontal_listbox
1028  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
1029  * @begin{tag}{name="horizontal_listbox"}{min="0"}{max="-1"}{super="generic/widget_instance"}
1030  * == Horizontal listbox ==
1031  *
1032  * @macro = horizontal_listbox_description
1033  *
1034  * List with the horizontal listbox specific variables:
1035  * @begin{table}{config}
1036  * vertical_scrollbar_mode & scrollbar_mode & initial_auto &
1037  * Determines whether or not to show the
1038  * scrollbar. $
1039  * horizontal_scrollbar_mode & scrollbar_mode & initial_auto &
1040  * Determines whether or not to show the
1041  * scrollbar. $
1042  *
1043  * list_definition & section & & This defines how a listbox item
1044  * looks. It must contain the grid
1045  * definition for 1 column of the list. $
1046  *
1047  * list_data & section & [] & A grid alike section which stores the
1048  * initial data for the listbox. Every row
1049  * must have the same number of columns as
1050  * the 'list_definition'. $
1051  *
1052  * has_minimum & bool & true & If false, less than one row can be selected. $
1053  *
1054  * has_maximum & bool & true & If false, more than one row can be selected. $
1055  *
1056  * @end{table}
1057  * @begin{tag}{name="header"}{min=0}{max=1}{super="gui/window/resolution/grid"}
1058  * @end{tag}{name="header"}
1059  * @begin{tag}{name="footer"}{min=0}{max=1}{super="gui/window/resolution/grid"}
1060  * @end{tag}{name="footer"}
1061  * @begin{tag}{name="list_definition"}{min=0}{max=1}
1062  * @begin{tag}{name="row"}{min=1}{max=1}{super="generic/listbox_grid/row"}
1063  * @end{tag}{name="row"}
1064  * @end{tag}{name="list_definition"}
1065  * @begin{tag}{name="list_data"}{min=0}{max=1}{super="generic/listbox_grid"}
1066  * @end{tag}{name="list_data"}
1067  * In order to force widgets to be the same size inside a horizontal listbox,
1068  * the widgets need to be inside a linked_group.
1069  *
1070  * Inside the list section there are only the following widgets allowed
1071  * * grid (to nest)
1072  * * selectable widgets which are
1073  * ** toggle_button
1074  * ** toggle_panel
1075  * @end{tag}{name="horizontal_listbox"}
1076  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
1077  */
1078 
1080  : builder_styled_widget(cfg)
1081  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
1082  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
1083  , list_builder(nullptr)
1084  , list_data()
1085  , has_minimum_(cfg["has_minimum"].to_bool(true))
1086  , has_maximum_(cfg["has_maximum"].to_bool(true))
1087 {
1088  const config& l = cfg.child("list_definition");
1089 
1090  VALIDATE(l, _("No list defined."));
1091 
1092  list_builder = std::make_shared<builder_grid>(l);
1093  assert(list_builder);
1094 
1095  VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
1096 
1097  if(cfg.has_child("list_data")) {
1098  list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
1099  }
1100 }
1101 
1103 {
1104 #ifdef GUI2_EXPERIMENTAL_LISTBOX
1105  list_view* widget = new list_view(true, true, generator_base::horizontal_list, true, list_builder);
1106 
1107  // init_control(widget);
1108  if(!list_data.empty()) {
1109  widget->append_rows(list_data);
1110  }
1111 
1112  return widget;
1113 #else
1114 
1116 
1119 
1120  DBG_GUI_G << "Window builder: placed listbox '" << id << "' with definition '" << definition << "'.\n";
1121 
1122  const auto conf = widget->cast_config_to<listbox_definition>();
1123  assert(conf);
1124 
1125  widget->init_grid(conf->grid);
1126 
1127  widget->finalize(nullptr, nullptr, list_data);
1128 
1129  return widget;
1130 #endif
1131 }
1132 
1133 /*WIKI_MACRO
1134  * @begin{macro}{grid_listbox_description}
1135  *
1136  * A grid listbox is a styled_widget that holds several items of the
1137  * same type. Normally the items in a listbox are ordered in rows,
1138  * this version orders them in a grid instead.
1139  * @end{macro}
1140  */
1141 
1142 /*WIKI
1143  * @page = GUIWidgetInstanceWML
1144  * @order = 2_grid_listbox
1145  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
1146  * @begin{tag}{name="grid_listbox"}{min="0"}{max="-1"}{super="generic/widget_instance"}
1147  * == Horizontal listbox ==
1148  *
1149  * @macro = grid_listbox_description
1150  *
1151  * List with the grid listbox specific variables:
1152  * @begin{table}{config}
1153  * vertical_scrollbar_mode & scrollbar_mode & initial_auto &
1154  * Determines whether or not to show the
1155  * scrollbar. $
1156  * horizontal_scrollbar_mode & scrollbar_mode & initial_auto &
1157  * Determines whether or not to show the
1158  * scrollbar. $
1159  *
1160  * list_definition & section & & This defines how a listbox item
1161  * looks. It must contain the grid
1162  * definition for 1 column of the list. $
1163  *
1164  * list_data & section & [] & A grid alike section which stores the
1165  * initial data for the listbox. Every row
1166  * must have the same number of columns as
1167  * the 'list_definition'. $
1168  *
1169  * has_minimum & bool & true & If false, less than one cell can be selected. $
1170  *
1171  * has_maximum & bool & true & If false, more than one cell can be selected. $
1172  *
1173  * @end{table}
1174  * @begin{tag}{name="header"}{min=0}{max=1}{super="gui/window/resolution/grid"}
1175  * @end{tag}{name="header"}
1176  * @begin{tag}{name="footer"}{min=0}{max=1}{super="gui/window/resolution/grid"}
1177  * @end{tag}{name="footer"}
1178  * @begin{tag}{name="list_definition"}{min=0}{max=1}
1179  * @begin{tag}{name="row"}{min=1}{max=1}{super="generic/listbox_grid/row"}
1180  * @end{tag}{name="row"}
1181  * @end{tag}{name="list_definition"}
1182  * @begin{tag}{name="list_data"}{min=0}{max=1}{super="generic/listbox_grid"}
1183  * @end{tag}{name="list_data"}
1184  * In order to force widgets to be the same size inside a grid listbox,
1185  * the widgets need to be inside a linked_group.
1186  *
1187  * Inside the list section there are only the following widgets allowed
1188  * * grid (to nest)
1189  * * selectable widgets which are
1190  * ** toggle_button
1191  * ** toggle_panel
1192  * @end{tag}{name="grid_listbox"}
1193  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
1194  */
1195 
1197  : builder_styled_widget(cfg)
1198  , vertical_scrollbar_mode(get_scrollbar_mode(cfg["vertical_scrollbar_mode"]))
1199  , horizontal_scrollbar_mode(get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
1200  , list_builder(nullptr)
1201  , list_data()
1202  , has_minimum_(cfg["has_minimum"].to_bool(true))
1203  , has_maximum_(cfg["has_maximum"].to_bool(true))
1204 {
1205  const config& l = cfg.child("list_definition");
1206 
1207  VALIDATE(l, _("No list defined."));
1208 
1209  list_builder = std::make_shared<builder_grid>(l);
1210  assert(list_builder);
1211 
1212  VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
1213 
1214  if(cfg.has_child("list_data")) {
1215  list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
1216  }
1217 }
1218 
1220 {
1221 #ifdef GUI2_EXPERIMENTAL_LISTBOX
1222  list_view* widget = new list_view(true, true, generator_base::grid, true, list_builder);
1223 
1224  // init_control(widget);
1225  if(!list_data.empty()) {
1226  widget->append_rows(list_data);
1227  }
1228 
1229  return widget;
1230 #else
1231 
1233 
1236 
1237  DBG_GUI_G << "Window builder: placed listbox '" << id << "' with definition '" << definition << "'.\n";
1238 
1239  const auto conf = widget->cast_config_to<listbox_definition>();
1240  assert(conf);
1241 
1242  widget->init_grid(conf->grid);
1243 
1244  widget->finalize(nullptr, nullptr, list_data);
1245 
1246  return widget;
1247 #endif
1248 }
1249 
1250 } // namespace implementation
1251 
1252 // }------------ END --------------
1253 
1254 } // namespace gui2
1255 
1256 #endif
const order_pair get_active_sorting_option()
Definition: listbox.cpp:661
Define the common log macros for the gui toolkit.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)=0
Left arrow key pressed.
void show_content_rect(const SDL_Rect &rect)
Shows a certain part of the content.
Base class of a resolution, contains the common keys for a resolution.
void keyboard_capture(widget *widget)
Definition: window.cpp:1279
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)=0
Up arrow key pressed.
virtual unsigned get_item_at_ordered(unsigned index_ordered) const =0
#define DBG_GUI_P
Definition: log.hpp:68
void set_active_sorting_option(const order_pair &sort_by, const bool select_first=false)
Sorts the listbox by a pre-set sorting option.
Definition: listbox.cpp:642
Defines the exception classes for the layout algorithm.
Small abstract helper class.
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
Definition: grid.cpp:603
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:417
#define LOG_GUI_L
Definition: log.hpp:58
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
boost::dynamic_bitset get_rows_shown() const
Returns a list of visible rows.
Definition: listbox.cpp:223
Helper class to block invalidate_layout.
Definition: window.hpp:226
std::vector< state_definition > state
void set_horizontal_scrollbar_mode(const scrollbar_mode scrollbar_mode)
std::function< void(unsigned, SORT_ORDER)> callback_order_change_
Definition: listbox.hpp:373
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: listbox.cpp:451
#define DBG_GUI_L
Definition: log.hpp:57
virtual unsigned get_item_count() const =0
Returns the number of items.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)=0
Right arrow key pressed.
virtual grid & create_item(const int index, builder_grid_const_ptr list_builder, const string_map &item_data, const std::function< void(widget &)> &callback)=0
Creates a new item.
int get_y() const
Definition: widget.cpp:323
boost::dynamic_bitset get_items_shown() const
Returns the visibility of all the items as a bit set.
Definition: generator.hpp:120
void finalize_setup()
The builder needs to call us so we do our setup.
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
virtual void set_item_shown(const unsigned index, const bool show)=0
Shows or hides an item.
void mark_as_unsorted()
Deactivates all sorting toggle buttons at the top, making the list look like it's not sorted...
Definition: listbox.cpp:674
std::shared_ptr< const builder_grid > builder_grid_const_ptr
point get_origin() const
Returns the screen origin of the widget.
Definition: widget.cpp:303
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:443
bool rects_overlap(const SDL_Rect &rect1, const SDL_Rect &rect2)
Tests whether two rectangles overlap.
Definition: rect.cpp:33
virtual void place(const point &origin, const point &size) override=0
See widget::place.
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:470
const grid & get_grid() const
virtual void child_populate_dirty_list(window &caller, const std::vector< widget * > &call_stack) override
See widget::child_populate_dirty_list.
virtual void place(const point &origin, const point &size) override
See widget::place.
#define LOG_HEADER
Definition: listbox.cpp:42
virtual void set_order(const order_func &order)=0
virtual bool is_selected(const unsigned index) const =0
Returns whether the item is selected.
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:382
virtual bool has_widget(const widget &widget) const override
See widget::has_widget.
Definition: grid.cpp:666
This file contains the window object, this object is a top level container which has the event manage...
child_itors child_range(config_key_type key)
Definition: config.cpp:360
void set_vertical_scrollbar_mode(const scrollbar_mode scrollbar_mode)
unsigned get_width() const
Definition: widget.cpp:328
Base class for all widgets.
Definition: widget.hpp:48
std::function< bool(unsigned, unsigned)> order_func
Definition: generator.hpp:249
unsigned get_height() const
Definition: widget.cpp:333
void register_translatable_sorting_option(const int col, translatable_sorter_func_t f)
Registers a special sorting function specifically for translatable values.
Definition: listbox.cpp:634
virtual grid & item(const unsigned index)=0
Gets the grid of an item.
#define h
void swap_grid(grid *g, grid *content_grid, widget *widget, const std::string &id)
Swaps an item in a grid for another one.
std::unique_ptr< grid > content_grid_
The grid that holds the content.
bool row_selected(const unsigned row)
Check if a row is selected.
Definition: listbox.cpp:268
bool need_layout_
Definition: listbox.hpp:368
virtual unsigned get_selected_item_count() const =0
Returns the number of selected items.
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:502
void set_row_active(const unsigned row, const bool active)
Makes a row active or inactive.
Definition: listbox.cpp:139
std::pair< int, SORT_ORDER > order_pair
Definition: listbox.hpp:280
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:252
torder_list orders_
Definition: listbox.hpp:371
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.
virtual point calculate_best_size() const override
See widget::calculate_best_size.
int x
x coordinate.
Definition: point.hpp:44
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:262
Generic file dialog.
Definition: field-fwd.hpp:22
Sent by a widget to notify others its contents or state are modified.
Definition: handler.hpp:96
virtual point calculate_best_size() const override=0
See widget::calculate_best_size.
The listbox class.
Definition: listbox.hpp:42
unsigned get_horizontal_scrollbar_item_position() const
Returns current position of the horizontal scrollbar.
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:274
void finalize(builder_grid_const_ptr header, builder_grid_const_ptr footer, const std::vector< std::map< std::string, string_map >> &list_data)
Finishes the building initialization of the widget.
Definition: listbox.cpp:544
Base container class.
Definition: grid.hpp:30
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:493
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)
Left arrow key pressed.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
std::string definition
Parameters for the styled_widget.
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:494
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:233
Abstract base class for the generator.
Definition: generator.hpp:40
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
listbox_definition(const config &cfg)
Definition: listbox.cpp:723
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:456
This file contains the settings handling of the widget library.
virtual void set_content_size(const point &origin, const point &size) override
Inherited from scrollbar_container.
Definition: listbox.cpp:683
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:127
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:469
builder_grid_const_ptr list_builder_
Contains the builder for the new items.
Definition: listbox.hpp:366
void toggle_item(const unsigned index)
Toggles the selection state of an item.
Definition: generator.hpp:98
bool content_resize_request(const bool force_sizing=false)
Notification if the content of a child needs a resize.
void order_by_column(unsigned column, widget &widget)
Definition: listbox.cpp:587
bool update_content_size()
Request to update the size of the content after changing the content.
Definition: listbox.cpp:331
virtual void create_items(const int index, builder_grid_const_ptr list_builder, const std::vector< string_map > &data, const std::function< void(widget &)> &callback)=0
Creates one or more new item(s).
void init_grid(const std::shared_ptr< builder_grid > &grid_builder)
Initializes and builds the grid.
virtual bool get_item_shown(const unsigned index) const =0
Returns whether the item is shown.
void list_item_clicked(widget &caller)
Function to call after the user clicked on a row.
Definition: listbox.cpp:280
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: grid.cpp:479
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:410
const SDL_Rect & content_visible_area() const
void order_by(const generator_base::order_func &func)
Definition: listbox.cpp:617
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition: listbox.cpp:326
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:480
size_t size(const utf8::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
Base class for creating containers with one or two scrollbar(s).
virtual int get_selected_item() const =0
Returns the selected item.
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:530
point get_best_size() const
Gets the best size for the widget.
Definition: widget.cpp:196
#define LOG_GUI_G
Definition: log.hpp:41
unsigned int get_rows() const
Definition: grid.hpp:307
virtual void clear()=0
Deletes all items.
void set_vertical_scrollbar_item_position(const unsigned position)
Move the vertical scrollbar to a position.
mock_party p
The user set the widget invisible, that means:
window * get_window()
Get the parent window.
Definition: widget.cpp:114
static map_location::DIRECTION s
window * build(const builder_window::window_resolution *definition)
Builds a window.
unsigned get_vertical_scrollbar_item_position() const
Returns current position of the vertical scrollbar.
size_t i
Definition: function.cpp:933
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
std::array< generator_base::order_func, 2 > generator_sort_array
Definition: generator.hpp:382
Holds a 2D point.
Definition: point.hpp:23
grid & add_row(const string_map &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:68
void set_active(const bool active)
Activates all children.
Definition: grid.cpp:162
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:239
int w
virtual void set_value(unsigned value, bool fire_event=false)=0
Select the styled_widget.
scrollbar_mode get_scrollbar_mode(const std::string &scrollbar_mode)
Returns the scrollbar mode flags.
Definition: helper.cpp:120
virtual void layout_children() override
See widget::layout_children.
Definition: listbox.cpp:436
bool grid()
Definition: general.cpp:507
std::shared_ptr< const typename T::resolution > cast_config_to() const
Casts the current resolution definition config to the respective type of a derived widget...
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:504
bool get_value_bool() const
Contains the SDL_Rect helper code.
virtual void delete_item(const unsigned index)=0
Deletes an item.
#define f
static std::vector< std::map< std::string, string_map > > parse_list_data(const config &data, const unsigned int req_cols)
Definition: listbox.cpp:921
int icompare(const std::string &s1, const std::string &s2)
Case-insensitive lexicographical comparison.
SDL_Rect content_visible_area_
Cache for the visible area for the content.
unsigned int get_cols() const
Definition: grid.hpp:313
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.
visibility get_visible() const
Definition: widget.cpp:506
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:88
const bool is_horizontal_
Definition: listbox.hpp:363
#define REGISTER_WIDGET3(type, id, key)
Registers a widget.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:120
void set_column_order(unsigned col, const generator_sort_array &func)
Definition: listbox.cpp:625
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:133
virtual void set_size(const point &size)
Sets the size of the widget.
Definition: widget.cpp:230
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:803
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:488
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)
Up arrow key pressed.
point get_size() const
Returns the size of the widget.
Definition: widget.cpp:308
generator_base * generator_
Contains a pointer to the generator.
Definition: listbox.hpp:361
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
mock_char c
bool any_rows_shown() const
Definition: listbox.cpp:228
std::function< std::string(const int)> translatable_sorter_func_t
Definition: listbox.hpp:269
int y
y coordinate.
Definition: point.hpp:47
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:469
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
SDL_Rect get_rectangle() const
Gets the bounding rectangle of the widget on the screen.
Definition: widget.cpp:313
#define DBG_GUI_G
Definition: log.hpp:40
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:145
std::shared_ptr< builder_grid > builder_grid_ptr
void populate_dirty_list(window &caller, std::vector< widget * > &call_stack)
Adds a widget to the dirty list if it is dirty.
Definition: widget.cpp:420
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:516
static std::deque< std::string > call_stack
Definition: function.cpp:39
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:442
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: listbox.cpp:350
Class for a toggle button.
Contains the implementation details for lexical_cast and shouldn't be used directly.
virtual unsigned get_value() const =0
Is the styled_widget selected?
void set_horizontal_scrollbar_item_position(const unsigned position)
Move the horizontal scrollbar to a position.
virtual void child_populate_dirty_list(window &caller, const std::vector< widget * > &call_stack) override
See widget::child_populate_dirty_list.
Definition: listbox.cpp:441