The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
listbox.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #ifndef GUI2_EXPERIMENTAL_LISTBOX
18 
21 
24 
25 #include <boost/dynamic_bitset.hpp>
26 #include <functional>
27 
28 namespace gui2
29 {
30 // ------------ WIDGET -----------{
31 
32 class selectable_item;
33 namespace implementation
34 {
35 struct builder_listbox;
36 struct builder_horizontal_listbox;
37 struct builder_grid_listbox;
38 struct builder_styled_widget;
39 }
40 
41 /** The listbox class. */
43 {
47  friend class debug_layout_graph;
48 
49 public:
50  /**
51  * Constructor.
52  *
53  * @param builder The builder for the appropriate listbox variant.
54  * @param placement How are the items placed.
55  * @param list_builder Grid builder for the listbox definition grid.
56  * @param has_minimum Does the listbox need to have one item selected.
57  * @param has_maximum Can the listbox only have one item selected.
58  * @param select Select an item when selected. If false it changes
59  * the visible state instead. Default true.
60  */
62  const generator_base::placement placement,
63  builder_grid_ptr list_builder,
64  const bool has_minimum,
65  const bool has_maximum,
66  const bool select = true);
67 
68  /***** ***** ***** ***** Row handling. ***** ***** ****** *****/
69  /**
70  * When an item in the list is selected by the user we need to
71  * update the state. We installed a callback handler which
72  * calls us.
73  *
74  * @param item The data send to the set_members of the
75  * widgets.
76  * @param index The item before which to add the new item,
77  * 0 == begin, -1 == end.
78  */
79  grid& add_row(const string_map& item, const int index = -1);
80 
81  /**
82  * Adds single row to the grid.
83  *
84  * This function expect a row to have multiple widgets (either multiple
85  * columns or one column with multiple widgets).
86  *
87  *
88  * @param data The data to send to the set_members of the
89  * widgets. If the member id is not an empty
90  * string it is only send to the widget that has
91  * the wanted id (if any). If the member id is an
92  * empty string, it is send to all members.
93  * Having both empty and non-empty id's gives
94  * undefined behavior.
95  * @param index The item before which to add the new item,
96  * 0 == begin, -1 == end.
97  */
98  grid& add_row(const std::map<std::string /* widget id */, string_map>& data, const int index = -1);
99 
100  /**
101  * Removes a row in the listbox.
102  *
103  * @param row The row to remove, when not in
104  * range the function is ignored.
105  * @param count The number of rows to remove, 0 means all
106  * rows (starting from row).
107  */
108  void remove_row(const unsigned row, unsigned count = 1);
109 
110  /** Removes all the rows in the listbox, clearing it. */
111  void clear();
112 
113  /** Returns the number of items in the listbox. */
114  unsigned get_item_count() const;
115 
116  /**
117  * Makes a row active or inactive.
118  *
119  * NOTE this doesn't change the select status of the row.
120  *
121  * @param row The row to (de)activate.
122  * @param active true activate, false deactivate.
123  */
124  void set_row_active(const unsigned row, const bool active);
125 
126  /**
127  * Makes a row visible or invisible.
128  *
129  * @param row The row to show or hide.
130  * @param shown true visible, false invisible.
131  */
132  void set_row_shown(const unsigned row, const bool shown);
133 
134  /**
135  * Makes a row visible or invisible.
136  *
137  * Use this version if you want to show hide multiple items since it's
138  * optimized for that purpose, for one it calls the selection changed
139  * callback only once instead of several times.
140  *
141  * @param shown A vector with the show hide status for every
142  * row. The number of items in the vector must
143  * be equal to the number of items in the
144  * listbox.
145  */
146  void set_row_shown(const boost::dynamic_bitset<>& shown);
147 
148  /**
149  * Returns a list of visible rows
150  *
151  * @returns A mask indicating which rows are visible
152  */
153  boost::dynamic_bitset<> get_rows_shown() const;
154 
155  bool any_rows_shown() const;
156 
157  /**
158  * Returns the grid of the wanted row.
159  *
160  * There's only a const version since allowing callers to modify the grid
161  * behind our backs might give problems. We return a pointer instead of a
162  * reference since dynamic casting of pointers is easier (no try catch
163  * needed).
164  *
165  * @param row The row to get the grid from, the caller has
166  * to make sure the row is a valid row.
167  * @returns The grid of the wanted row.
168  */
169  const grid* get_row_grid(const unsigned row) const;
170 
171  /**
172  * The possibly-giving-problems nonconst version of get_row_grid
173  *
174  * @param row The row to get the grid from, the caller has
175  * to make sure the row is a valid row.
176  * @returns The grid of the wanted row.
177  */
178  grid* get_row_grid(const unsigned row);
179 
180  /**
181  * Selects a row.
182  *
183  * @param row The row to select.
184  * @param select Select or deselect the row.
185  * @returns True if the operation succeeded.
186  */
187  bool select_row(const unsigned row, const bool select = true);
188 
189  /**
190  * Selects a row at the given position, regardless of sorting order.
191  *
192  * When using @ref select_row the relevant row is located by index regardless
193  * of its actual position in the list, which could differ if the list had been
194  * sorted. In that case, `select_row(0)` would not select the list's first row
195  * as displayed.
196  *
197  * This function allows row selection based on position. `select_row_at(0)` will
198  * always select the list's first row, regardless of sorting order.
199  *
200  * @param row The row to select.
201  * @param select Select or deselect the row.
202  *
203  * @returns True if the operation succeeded.
204  */
205  bool select_row_at(const unsigned row, const bool select = true);
206 
207  /**
208  * Check if a row is selected
209  * @param row The row to test
210  * @returns True if it is selected.
211  */
212  bool row_selected(const unsigned row);
213 
214  /**
215  * Returns the first selected row
216  *
217  * @returns The first selected row, or -1 if no row is selected.
218  */
219  int get_selected_row() const;
220 
221  /** Function to call after the user clicked on a row. */
222  void list_item_clicked(widget& caller);
223 
224  /** See @ref container_base::set_self_active. */
225  virtual void set_self_active(const bool active) override;
226 
227  /**
228  * Request to update the size of the content after changing the content.
229  *
230  * When a resize is required the container first can try to handle it
231  * itself. If it can't honor the request the function will call @ref
232  * window::invalidate_layout().
233  *
234  * @note Calling this function on a widget with size == (0, 0) results
235  * false but doesn't call invalidate_layout, the engine expects to be in
236  * build up phase with the layout already invalidated.
237  *
238  * @returns True if the resizing succeeded, false
239  * otherwise.
240  */
241  bool update_content_size();
242 
243  /***** ***** ***** ***** inherited ***** ***** ****** *****/
244 
245  /** See @ref widget::place. */
246  virtual void place(const point& origin, const point& size) override;
247 
248  /** See @ref widget::layout_children. */
249  virtual void layout_children() override;
250 
251  /** See @ref widget::child_populate_dirty_list. */
252  virtual void child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack) override;
253 
254  /***** ***** ***** setters / getters for members ***** ****** *****/
255 
256  void order_by(const generator_base::order_func& func);
257 
258  void set_column_order(unsigned col, const generator_sort_array& func);
259 
260  template<typename Func>
261  void register_sorting_option(const int col, const Func& f)
262  {
263  set_column_order(col, {{
264  [f](int lhs, int rhs) { return f(lhs) < f(rhs); },
265  [f](int lhs, int rhs) { return f(lhs) > f(rhs); }
266  }});
267  }
268 
269  using translatable_sorter_func_t = std::function<std::string(const int)>;
270 
271  /** Registers a special sorting function specifically for translatable values. */
273 
274  enum SORT_ORDER {
278  };
279 
280  using order_pair = std::pair<int, SORT_ORDER>;
281 
282  /**
283  * Sorts the listbox by a pre-set sorting option. The corresponding header widget will also be toggled.
284  * The sorting option should already have been registered by @ref listbox::register_sorting_option().
285  *
286  * @param sort_by Pair of column index and sort direction. The column (first arguemnt)
287  * argument will be sorted in the specified direction (second argument)
288  *
289  * @param select_first If true, the first row post-sort will be selected. If false (default),
290  * the selected row will be maintained post-sort as per standard sorting
291  * functionality.
292  */
293  void set_active_sorting_option(const order_pair& sort_by, const bool select_first = false);
294 
296 
297  /** Deactivates all sorting toggle buttons at the top, making the list look like it's not sorted. */
298  void mark_as_unsorted();
299 
300  /** Registers a callback to be called when the active sorting option changes. */
301  void set_callback_order_change(std::function<void(unsigned, SORT_ORDER)> callback)
302  {
303  callback_order_change_ = callback;
304  }
305 
306 protected:
307  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
308 
309  /** Inherited from scrollbar_container. */
310  void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) override;
311 
312  /** Inherited from scrollbar_container. */
313  void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) override;
314 
315  /** Inherited from scrollbar_container. */
316  void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) override;
317 
318  /** Inherited from scrollbar_container. */
319  void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) override;
320 
321 private:
322  /** See @ref widget::calculate_best_size. */
323  virtual point calculate_best_size() const override;
324 
326 
327  /** Helper to update visible area after a key event. */
329 
330  /**
331  * @todo A listbox must have the following config parameters in the
332  * instantiation:
333  * - fixed row height?
334  * - fixed column width?
335  * and if so the following ways to set them
336  * - fixed depending on header ids
337  * - fixed depending on footer ids
338  * - fixed depending on first row ids
339  * - fixed depending on list (the user has to enter a list of ids)
340  *
341  * For now it's always fixed width depending on the first row.
342  */
343 
344  /**
345  * Finishes the building initialization of the widget.
346  *
347  * @param header Builder for the header.
348  * @param footer Builder for the footer.
349  * @param list_data The initial data to fill the listbox with.
350  */
351  void finalize(builder_grid_const_ptr header,
352  builder_grid_const_ptr footer,
353  const std::vector<std::map<std::string, string_map>>& list_data);
354  /**
355  * Contains a pointer to the generator.
356  *
357  * The pointer is not owned by this class, it's stored in the content_grid_
358  * of the scrollbar_container super class and freed when it's grid is
359  * freed.
360  */
362 
363  const bool is_horizontal_;
364 
365  /** Contains the builder for the new items. */
367 
369 
370  typedef std::vector<std::pair<selectable_item*, generator_sort_array>> torder_list;
371  torder_list orders_;
372 
373  std::function<void(unsigned, SORT_ORDER)> callback_order_change_;
374 
375  /**
376  * Resizes the content.
377  *
378  * The resize either happens due to resizing the content or invalidate the
379  * layout of the window.
380  *
381  * @param width_modification The wanted modification to the width:
382  * * negative values reduce width.
383  * * zero leave width as is.
384  * * positive values increase width.
385  * @param height_modification The wanted modification to the height:
386  * * negative values reduce height.
387  * * zero leave height as is.
388  * * positive values increase height.
389  */
390  void resize_content(const int width_modification,
391  const int height_modification,
392  const int width__modification_pos = -1,
393  const int height_modification_pos = -1);
394 
395  /**
396  * Resizes the content.
397  *
398  * The resize happens when a new row is added to the contents.
399  *
400  * @param row The new row added to the listbox.
401  */
402  void resize_content(const widget& row);
403 
404  /** Layouts the children if needed. */
405  void layout_children(const bool force);
406 
407  /** Inherited from scrollbar_container. */
408  virtual void set_content_size(const point& origin, const point& size) override;
409 
410  /** Inherited from styled_widget, implemented by REGISTER_WIDGET. */
411  virtual const std::string& get_control_type() const override;
412 
413  void order_by_column(unsigned column, widget& widget);
414 };
415 
416 // }---------- DEFINITION ---------{
417 
419 {
420  explicit listbox_definition(const config& cfg);
421 
423  {
424  explicit resolution(const config& cfg);
425 
427  };
428 };
429 
430 // }---------- BUILDER -----------{
431 
432 namespace implementation
433 {
435 {
436  explicit builder_listbox(const config& cfg);
437 
439 
440  widget* build() const;
441 
444 
447 
449 
450  /**
451  * Listbox data.
452  *
453  * Contains a vector with the data to set in every cell, it's used to
454  * serialize the data in the config, so the config is no longer required.
455  */
456  std::vector<std::map<std::string, string_map>> list_data;
457 
459 };
460 
462 {
463  explicit builder_horizontal_listbox(const config& cfg);
464 
466 
467  widget* build() const;
468 
471 
473 
474  /**
475  * Listbox data.
476  *
477  * Contains a vector with the data to set in every cell, it's used to
478  * serialize the data in the config, so the config is no longer required.
479  */
480  std::vector<std::map<std::string, string_map>> list_data;
481 
483 };
484 
486 {
487  explicit builder_grid_listbox(const config& cfg);
488 
490 
491  widget* build() const;
492 
495 
497 
498  /**
499  * Listbox data.
500  *
501  * Contains a vector with the data to set in every cell, it's used to
502  * serialize the data in the config, so the config is no longer required.
503  */
504  std::vector<std::map<std::string, string_map>> list_data;
505 
507 };
508 
509 } // namespace implementation
510 
511 // }------------ END --------------
512 
513 } // namespace gui2
514 
515 #endif
const order_pair get_active_sorting_option()
Definition: listbox.cpp:661
Base class of a resolution, contains the common keys for a resolution.
void set_active_sorting_option(const order_pair &sort_by, const bool select_first=false)
Sorts the listbox by a pre-set sorting option.
Definition: listbox.cpp:642
virtual widget * build() const =0
std::vector< char_t > string
size_t index(const utf8::string &str, const size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
boost::dynamic_bitset get_rows_shown() const
Returns a list of visible rows.
Definition: listbox.cpp:223
virtual point calculate_best_size() const override
See widget::calculate_best_size.
Definition: listbox.cpp:451
std::function< void(unsigned, SORT_ORDER)> callback_order_change_
Definition: listbox.hpp:373
void update_visible_area_on_key_event(const KEY_SCROLL_DIRECTION direction)
Helper to update visible area after a key event.
Definition: listbox.cpp:467
void mark_as_unsorted()
Deactivates all sorting toggle buttons at the top, making the list look like it's not sorted...
Definition: listbox.cpp:674
std::shared_ptr< const builder_grid > builder_grid_const_ptr
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:443
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:470
void resize_content(const int width_modification, const int height_modification, const int width__modification_pos=-1, const int height_modification_pos=-1)
Resizes the content.
Definition: listbox.cpp:382
builder_listbox(const config &cfg)
Definition: listbox.cpp:952
Base class for all widgets.
Definition: widget.hpp:48
std::function< bool(unsigned, unsigned)> order_func
Definition: generator.hpp:249
void register_translatable_sorting_option(const int col, translatable_sorter_func_t f)
Registers a special sorting function specifically for translatable values.
Definition: listbox.cpp:634
bool row_selected(const unsigned row)
Check if a row is selected.
Definition: listbox.cpp:268
bool need_layout_
Definition: listbox.hpp:368
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:502
void set_row_active(const unsigned row, const bool active)
Makes a row active or inactive.
Definition: listbox.cpp:139
std::pair< int, SORT_ORDER > order_pair
Definition: listbox.hpp:280
bool select_row(const unsigned row, const bool select=true)
Selects a row.
Definition: listbox.cpp:252
torder_list orders_
Definition: listbox.hpp:371
void set_callback_order_change(std::function< void(unsigned, SORT_ORDER)> callback)
Registers a callback to be called when the active sorting option changes.
Definition: listbox.hpp:301
bool select_row_at(const unsigned row, const bool select=true)
Selects a row at the given position, regardless of sorting order.
Definition: listbox.cpp:262
Generic file dialog.
Definition: field-fwd.hpp:22
The listbox class.
Definition: listbox.hpp:42
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:274
void finalize(builder_grid_const_ptr header, builder_grid_const_ptr footer, const std::vector< std::map< std::string, string_map >> &list_data)
Finishes the building initialization of the widget.
Definition: listbox.cpp:544
Base container class.
Definition: grid.hpp:30
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:493
scrollbar_container::scrollbar_mode horizontal_scrollbar_mode
Definition: listbox.hpp:494
Abstract base class for the generator.
Definition: generator.hpp:40
std::vector< std::pair< selectable_item *, generator_sort_array > > torder_list
Definition: listbox.hpp:370
listbox_definition(const config &cfg)
Definition: listbox.cpp:723
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:456
listbox(const implementation::builder_styled_widget &builder, const generator_base::placement placement, builder_grid_ptr list_builder, const bool has_minimum, const bool has_maximum, const bool select=true)
Constructor.
Definition: listbox.cpp:52
virtual void set_content_size(const point &origin, const point &size) override
Inherited from scrollbar_container.
Definition: listbox.cpp:683
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:127
builder_grid_const_ptr list_builder_
Contains the builder for the new items.
Definition: listbox.hpp:366
placement
Determines how the items are placed.
Definition: generator.hpp:50
void order_by_column(unsigned column, widget &widget)
Definition: listbox.cpp:587
bool update_content_size()
Request to update the size of the content after changing the content.
Definition: listbox.cpp:331
void list_item_clicked(widget &caller)
Function to call after the user clicked on a row.
Definition: listbox.cpp:280
void order_by(const generator_base::order_func &func)
Definition: listbox.cpp:617
virtual void set_self_active(const bool active) override
See container_base::set_self_active.
Definition: listbox.cpp:326
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:480
size_t size(const utf8::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
Base class for creating containers with one or two scrollbar(s).
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:530
virtual const std::string & get_control_type() const override
Inherited from styled_widget, implemented by REGISTER_WIDGET.
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
std::array< generator_base::order_func, 2 > generator_sort_array
Definition: generator.hpp:382
Holds a 2D point.
Definition: point.hpp:23
grid & add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:68
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:239
virtual void layout_children() override
See widget::layout_children.
Definition: listbox.cpp:436
scrollbar_mode
The way to handle the showing or hiding of the scrollbar.
std::vector< std::map< std::string, string_map > > list_data
Listbox data.
Definition: listbox.hpp:504
#define f
friend class debug_layout_graph
Definition: listbox.hpp:47
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:88
const bool is_horizontal_
Definition: listbox.hpp:363
void set_column_order(unsigned col, const generator_sort_array &func)
Definition: listbox.cpp:625
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:133
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:488
generator_base * generator_
Contains a pointer to the generator.
Definition: listbox.hpp:361
void register_sorting_option(const int col, const Func &f)
Definition: listbox.hpp:261
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
bool any_rows_shown() const
Definition: listbox.cpp:228
std::function< std::string(const int)> translatable_sorter_func_t
Definition: listbox.hpp:269
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:469
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:145
std::shared_ptr< builder_grid > builder_grid_ptr
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from scrollbar_container.
Definition: listbox.cpp:516
static std::deque< std::string > call_stack
Definition: function.cpp:39
scrollbar_container::scrollbar_mode vertical_scrollbar_mode
Definition: listbox.hpp:442
virtual void place(const point &origin, const point &size) override
See widget::place.
Definition: listbox.cpp:350
Contains the implementation details for lexical_cast and shouldn't be used directly.
virtual void child_populate_dirty_list(window &caller, const std::vector< widget * > &call_stack) override
See widget::child_populate_dirty_list.
Definition: listbox.cpp:441