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