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