The Battle for Wesnoth  1.17.0-dev
generator_private.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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 #pragma once
16 
18 
19 #include "gui/widgets/grid.hpp"
23 #include "gui/widgets/window.hpp" // For widget::visibility
24 #include "wml_exception.hpp"
25 
26 #include <cassert>
27 
28 namespace gui2
29 {
30 /**
31  * Contains the policies for the generator class.
32  */
33 namespace policy
34 {
35 /***** ***** ***** ***** Minimum selection ***** ***** ***** *****/
36 
37 /** Contains the policy for the minimum number of selected items. */
38 namespace minimum_selection
39 {
40 /** Must select at least one item. */
41 struct one_item : public virtual generator_base
42 {
43  /**
44  * Called when an item is shown or hidden.
45  *
46  * @param index The item to show or hide.
47  * @param show If true shows the item, else hides it.
48  */
49  void set_item_shown(const unsigned index, const bool show);
50 
51  /**
52  * Called when an item is created.
53  *
54  * @param index The index of the new item.
55  */
56  void create_item(const unsigned index);
57 
58  /* Also make the overload from the generator_ visible. */
60 
61  /**
62  * Called when the users wants to deselect an item.
63  *
64  * If the item can be deselected this function should call
65  * do_deselect_item() to make the deselection happen. If not allowed no
66  * action needs to be taken.
67  *
68  * @param index The index of the item to deselect.
69  *
70  * @returns Whether the item was deselected, some
71  * actions might happen automatically upon
72  * deselecting, so if this function returns
73  * false the caller should make sure the
74  * select state is restored.
75  */
76  bool deselect_item(const unsigned index);
77 
78  /**
79  * Called just before an item is deleted.
80  *
81  * This function can if needed select another items to try to obey the
82  * policy.
83  *
84  * @param index The index of the item to be deleted.
85  */
86  void delete_item(const unsigned index);
87 };
88 
89 /** No minimum selection. */
90 struct no_item : public virtual generator_base
91 {
92  /** See @ref minimum_selection::one_item::set_item_shown(). */
93  void set_item_shown(const unsigned index, const bool show);
94 
95  /** See @ref minimum_selection::one_item::create_item() */
96  void create_item(const unsigned /*index*/)
97  {
98  }
99 
100  /* Also make the overload from the generator_ visible. */
102 
103  /** See @ref minimum_selection::one_item::deselect_item() */
104  bool deselect_item(const unsigned index)
105  {
106  do_deselect_item(index);
107  return true;
108  }
109 
110  /** See @ref minimum_selection::one_item::delete_item() */
111  void delete_item(const unsigned index)
112  {
113  if(is_selected(index)) {
114  do_deselect_item(index);
115  }
116  }
117 };
118 
119 } // namespace minimum_selection
120 
121 /***** ***** ***** ***** Maximum selection ***** ***** ***** *****/
122 
123 /** Contains the policy for the maximum number of selected items. */
124 namespace maximum_selection
125 {
126 /** May select only one item. */
127 struct one_item : public virtual generator_base
128 {
129  /**
130  * Called when an item is selected.
131  *
132  * This function can deselect other items to obey the policy. This
133  * function should always call do_select_item() so the new item does get
134  * selected.
135  *
136  * Since this function controls the maximum selection count it should only
137  * be used to select items, not to deselect them.
138  *
139  * @pre @p select == @c true
140  *
141  * @param index The item to select.
142  * @param select Should always be true.
143  */
144  void select_item(const unsigned index, const bool select) override
145  {
146  assert(select);
147 
148  if(get_selected_item_count() == 1) {
149  // deselect current.
151  }
152 
153  // select new.
154  do_select_item(index);
155  }
156 };
157 
158 /** No maximum amount of items to select. */
159 struct many_items : public virtual generator_base
160 {
161  /** See one_item::select_item(). */
162  void select_item(const unsigned index, const bool select) override
163  {
164  assert(select);
165 
166  do_select_item(index);
167  }
168 };
169 
170 } // namespace maximum_selection
171 
172 /***** ***** ***** ***** Placement ***** ***** ***** *****/
173 
174 /** Controls how new items are placed. */
175 namespace placement
176 {
177 /** Places the items in a horizontal row. */
178 struct horizontal_list : public virtual generator_base
179 {
180  horizontal_list();
181 
182  /**
183  * Called when an item is created.
184  *
185  * This function should place the new item.
186  *
187  * @param index The index of the new item.
188  */
189  void create_item(const unsigned index);
190 
191  /* Also make the overload from the generator_ visible. */
193 
194  /** See @ref widget::request_reduce_width. */
195  virtual void request_reduce_width(const unsigned /*maximum_width*/) override
196  {
197  /* DO NOTHING */
198  }
199 
200  /** See @ref widget::request_reduce_height. */
201  virtual void request_reduce_height(const unsigned /*maximum_height*/) override
202  {
203  /* DO NOTHING */
204  }
205 
206  /** See @ref widget::calculate_best_size. */
207  virtual point calculate_best_size() const override;
208 
209  /** See @ref widget::place. */
210  virtual void place(const point& origin, const point& size) override;
211 
212  /** See @ref widget::set_origin. */
213  virtual void set_origin(const point& origin) override;
214 
215  /**
216  * Sets the visible rectangle of the generator.
217  *
218  * @param rectangle The visible rectangle.
219  */
220  void set_visible_rectangle(const SDL_Rect& rectangle) override;
221 
222  /** See @ref widget::find_at. */
223  virtual widget* find_at(const point& coordinate, const bool must_be_active) override;
224 
225  /** See @ref widget::find_at. */
226  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override;
227 
228  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
229 
230  /** Inherited from generator_base. */
231  void handle_key_up_arrow(SDL_Keymod /*modifier*/, bool& /*handled*/) override
232  {
233  /* DO NOTHING */
234  }
235 
236  /** Inherited from generator_base. */
237  void handle_key_down_arrow(SDL_Keymod /*modifier*/, bool& /*handled*/) override
238  {
239  /* DO NOTHING */
240  }
241 
242  /** Inherited from generator_base. */
243  void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) override;
244 
245  /** Inherited from generator_base. */
246  void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) override;
247 
248 private:
249  /**
250  * Has the grid already been placed?
251  *
252  * If the grid is placed it's no problem set the location of the new
253  * item,it hasn't been placed, there's no information about its location
254  * so do nothing.
255  */
256  bool placed_;
257 };
258 
259 /** Places the items in a vertical column. */
260 struct vertical_list : public virtual generator_base
261 {
262  vertical_list();
263 
264  /** See horizontal_list::create_item(). */
265  void create_item(const unsigned index);
266 
267  /* Also make the overload from the generator_ visible. */
269 
270  /** See @ref widget::request_reduce_width. */
271  virtual void request_reduce_width(const unsigned /*maximum_width*/) override
272  {
273  /* DO NOTHING */
274  }
275 
276  /** See @ref widget::request_reduce_height. */
277  virtual void request_reduce_height(const unsigned /*maximum_height*/) override
278  {
279  /* DO NOTHING */
280  }
281 
282  /** See @ref widget::calculate_best_size. */
283  virtual point calculate_best_size() const override;
284 
285  /** See @ref widget::place. */
286  virtual void place(const point& origin, const point& size) override;
287 
288  /** See @ref widget::set_origin. */
289  virtual void set_origin(const point& origin) override;
290 
291  /** See @ref horizontal_list::set_visible_rectangle(). */
292  void set_visible_rectangle(const SDL_Rect& rectangle) override;
293 
294  /** See @ref widget::find_at. */
295  virtual widget* find_at(const point& coordinate, const bool must_be_active) override;
296 
297  /** See @ref widget::find_at. */
298  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override;
299 
300  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
301 
302  /** Inherited from generator_base. */
303  void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) override;
304 
305  /** Inherited from generator_base. */
306  void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) override;
307 
308  /** Inherited from generator_base. */
309  void handle_key_left_arrow(SDL_Keymod /*modifier*/, bool& /*handled*/) override
310  {
311  /* DO NOTHING */
312  }
313 
314  /** Inherited from generator_base. */
315  void handle_key_right_arrow(SDL_Keymod /*modifier*/, bool& /*handled*/) override
316  {
317  /* DO NOTHING */
318  }
319 
320  // FIXME we need a delete handler as well,
321  // when deleting the last item we need to remove the placed flag.
322 
323  // FIXME we also need a clear function, called when
324  // clear is called.
325 private:
326  /**
327  * Has the grid already been placed?
328  *
329  * If the grid is placed it's no problem set the location of the new
330  * item,it hasn't been placed, there's no information about its location
331  * so do nothing.
332  */
333  bool placed_;
334 };
335 
336 /**
337  * Places the items in a grid.
338  *
339  * The items will be placed in rows and columns. It has to be determined
340  * whether the number of columns will be fixed or variable.
341  *
342  * @todo Implement.
343  */
344 struct table : public virtual generator_base
345 {
346  table();
347 
348  /** See horizontal_list::create_item(). */
349  void create_item(const unsigned /*index*/);
350 
351  /* Also make the overload from the generator_ visible. */
353 
354  /** See @ref widget::request_reduce_width. */
355  virtual void request_reduce_width(const unsigned /*maximum_width*/) override
356  {
357  /* DO NOTHING */
358  }
359 
360  /** See @ref widget::request_reduce_height. */
361  virtual void request_reduce_height(const unsigned /*maximum_height*/) override
362  {
363  /* DO NOTHING */
364  }
365 
366  /** See @ref widget::calculate_best_size. */
367  virtual point calculate_best_size() const override;
368 
369  /** See @ref widget::place. */
370  virtual void place(const point& /*origin*/, const point& /*size*/) override;
371 
372  /** See @ref widget::set_origin. */
373  virtual void set_origin(const point& /*origin*/) override;
374 
375  /** See @ref horizontal_list::set_visible_rectangle(). */
376  void set_visible_rectangle(const SDL_Rect& /*rectangle*/) override;
377 
378  /** See @ref widget::find_at. */
379  virtual widget* find_at(const point& /*coordinate*/
380  ,
381  const bool /*must_be_active*/) override;
382 
383  /** See @ref widget::find_at. */
384  virtual const widget* find_at(const point& /*coordinate*/
385  ,
386  const bool /*must_be_active*/) const override;
387 
388  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
389 
390  /** Inherited from generator_base. */
391  void handle_key_up_arrow(SDL_Keymod, bool&) override;
392 
393  /** Inherited from generator_base. */
394  void handle_key_down_arrow(SDL_Keymod, bool&) override;
395 
396  /** Inherited from generator_base. */
397  void handle_key_left_arrow(SDL_Keymod, bool&) override;
398 
399  /** Inherited from generator_base. */
400  void handle_key_right_arrow(SDL_Keymod, bool&) override;
401 
402 private:
403  /**
404  * Has the grid already been placed?
405  *
406  * If the grid is placed it's no problem set the location of the new
407  * item,it hasn't been placed, there's no information about its location
408  * so do nothing.
409  */
410  bool placed_;
411 };
412 
413 /**
414  * Places the items independent of each other.
415  *
416  * This is mainly meant for when only one item is shown at the same time.
417  *
418  * @todo Implement.
419  */
420 struct independent : public virtual generator_base
421 {
422  /** See horizontal_list::create_item(). */
423  void create_item(const unsigned /*index*/)
424  {
425  /* DO NOTHING */
426  }
427 
428  /* Also make the overload from the generator_ visible. */
430 
431  /** See @ref widget::request_reduce_width. */
432  virtual void request_reduce_width(const unsigned maximum_width) override;
433 
434  /** See horizontal_list::request_reduce_height. */
435  virtual void request_reduce_height(const unsigned maximum_height) override;
436 
437  /** See @ref widget::calculate_best_size. */
438  virtual point calculate_best_size() const override;
439 
440  /** See @ref widget::place. */
441  virtual void place(const point& origin, const point& size) override;
442 
443  /** See @ref widget::set_origin. */
444  virtual void set_origin(const point& origin) override;
445 
446  /** See @ref horizontal_list::set_visible_rectangle(). */
447  void set_visible_rectangle(const SDL_Rect& rectangle) override;
448 
449  /** See @ref widget::find_at. */
450  virtual widget* find_at(const point& coordinate, const bool must_be_active) override;
451 
452  /** See @ref widget::find_at. */
453  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override;
454 
455  /** See @ref widget::find. */
456  widget* find(const std::string& id, const bool must_be_active) override;
457 
458  /** See @ref widget::find. */
459  const widget* find(const std::string& id, const bool must_be_active) const override;
460 
461  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
462 
463  /** Inherited from generator_base. */
464  void handle_key_up_arrow(SDL_Keymod, bool&) override
465  {
466  /* DO NOTHING */
467  }
468 
469  /** Inherited from generator_base. */
470  void handle_key_down_arrow(SDL_Keymod, bool&) override
471  {
472  /* DO NOTHING */
473  }
474 
475  /** Inherited from generator_base. */
476  void handle_key_left_arrow(SDL_Keymod, bool&) override
477  {
478  /* DO NOTHING */
479  }
480 
481  /** Inherited from generator_base. */
482  void handle_key_right_arrow(SDL_Keymod, bool&) override
483  {
484  /* DO NOTHING */
485  }
486 };
487 
488 } // namespace placement
489 
490 /***** ***** ***** ***** Select action ***** ***** ***** *****/
491 
492 /**
493  * Contains the policy for which action to take when an item is selected or
494  * deselected.
495  */
496 namespace select_action
497 {
498 /** Select the item, this requires the grid to contain a selectable_item. */
499 struct selection : public virtual generator_base
500 {
501  void select(grid& grid, const bool select);
502 
503  /**
504  * Helper function to initialize a grid.
505  *
506  * @param grid The grid to initialize.
507  * @param data The data to initialize the parameters of
508  * the new item.
509  * @param callback The callback function to call when an item
510  * in the grid is (de)selected.
511  */
512  void init(grid* grid,
513  const std::map<std::string /* widget id */, string_map>& data,
514  const std::function<void(widget&)>& callback);
515 };
516 
517 /** Show the item. */
518 struct show : public virtual generator_base
519 {
520  void select(grid& grid, const bool show)
521  {
523  }
524 
525  /**
526  * Helper function to initialize a grid.
527  *
528  * @param grid The grid to initialize.
529  * @param data The data to initialize the parameters of
530  * the new item. No widgets with id == "" are
531  * allowed.
532  * @param callback The callback function is not used and
533  * should be nullptr.
534  */
535  void init(grid* grid,
536  const std::map<std::string /* widget id */, string_map>& data,
537  const std::function<void(widget&)>& callback);
538 };
539 
540 } // namespace select_action
541 
542 } // namespace policy
543 
544 /***** ***** ***** ***** generator ***** ***** ***** *****/
545 
546 /**
547  * Basic template class to generate new items.
548  *
549  * The class is policy based so the behavior can be selected.
550  */
551 template<class minimum_selection,
552  class maximum_selection,
553  class my_placement,
554  class select_action>
555 class generator : public minimum_selection,
556  public maximum_selection,
557  public my_placement,
558  public select_action
559 {
560 public:
562  : minimum_selection()
563  , maximum_selection()
564  , my_placement()
565  , select_action()
566  , selected_item_count_(0)
567  , last_selected_item_(-1)
568  , items_()
569  , order_()
570  , order_dirty_(true)
571  , order_func_()
572  {
573  }
574 
576  {
577  clear();
578  }
579 
580  /***** ***** ***** inherited ***** ****** *****/
581 
582  /** Inherited from generator_base. */
583  void delete_item(const unsigned index) override
584  {
585  assert(index < items_.size());
586 
587  // Might be other parts of the engine want to know about the
588  // deselection, if minimum fails it gets another chance later on,
589  // since it deletes the item.
590  if(is_selected(index)) {
591  select_item(index, false);
592  }
593 
594  minimum_selection::delete_item(index);
595 
596  items_.erase(items_.begin() + index);
597  order_dirty_ = true;
598  }
599 
600  /** Inherited from generator_base. */
601  void clear() override
602  {
603  items_.clear();
604  order_dirty_ = true;
605  selected_item_count_ = 0;
606  }
607 
608  /** Inherited from generator_base. */
609  void select_item(const unsigned index, const bool select = true) override
610  {
611  assert(index < items_.size());
612 
613  if(select && !is_selected(index)) {
614  maximum_selection::select_item(index, true);
615  last_selected_item_ = index;
616  } else if(is_selected(index)) {
617  if(!minimum_selection::deselect_item(index)) {
618  // Some items might have deselected themselves so
619  // make sure they do get selected again.
620  select_action::select(item(index), true);
621  }
622  }
623  }
624 
625  /** Inherited from generator_base. */
626  bool is_selected(const unsigned index) const override
627  {
628  assert(index < items_.size());
629  return (*items_[index]).selected;
630  }
631 
632  /** Inherited from generator_base. */
633  void set_item_shown(const unsigned index, const bool show) override
634  {
635  assert(index < items_.size());
636  if(items_[index]->shown != show) {
637  /*** Set the proper visible state. ***/
638  items_[index]->shown = show;
639  items_[index]->child_grid.set_visible(show ? widget::visibility::visible : widget::visibility::invisible);
640 
641  /*** Update the selection. ***/
642  minimum_selection::set_item_shown(index, show);
643  }
644  }
645 
646  /** Inherited from generator_base. */
647  virtual bool get_item_shown(const unsigned index) const override
648  {
649  assert(index < items_.size());
650  return items_[index]->shown && items_[index]->child_grid.get_visible() != widget::visibility::invisible;
651  }
652 
653  /** Inherited from generator_base. */
654  unsigned get_item_count() const override
655  {
656  return items_.size();
657  }
658 
659  /** Inherited from generator_base. */
660  unsigned get_selected_item_count() const override
661  {
662  return selected_item_count_;
663  }
664 
665  /** Inherited from generator_base. */
666  int get_selected_item() const override
667  {
668  if(selected_item_count_ == 0) {
669  return -1;
670  } else if(last_selected_item_ != -1 && last_selected_item_ < static_cast<int>(items_.size())
671  && (*items_[last_selected_item_]).selected)
672  {
673  return last_selected_item_;
674  } else {
675  for(std::size_t i = 0; i < items_.size(); ++i) {
676  if((*items_[i]).selected) {
677  return i;
678  }
679  }
680 
682  "No item selected.", "selected_item_count_ was non-zero, yet no selected item was found.");
683  }
684  }
685 
686  /** Inherited from generator_base. */
687  grid& item(const unsigned index) override
688  {
689  assert(index < items_.size());
690  return items_[index]->child_grid;
691  }
692 
693  /** Inherited from generator_base. */
694  const grid& item(const unsigned index) const override
695  {
696  assert(index < items_.size());
697  return items_[index]->child_grid;
698  }
699 
700  /** Inherited from generator_base. */
701  grid& item_ordered(const unsigned index) override
702  {
703  calculate_order();
704  assert(index < items_.size());
705  return items_[order_[index]]->child_grid;
706  }
707 
708  /** Inherited from generator_base. */
709  const grid& item_ordered(const unsigned index) const override
710  {
711  calculate_order();
712  assert(index < items_.size());
713  return items_[order_[index]]->child_grid;
714  }
715 
716  /** Inherited from generator_base. */
717  grid& create_item(const int index,
718  const builder_grid& list_builder,
719  const string_map& item_data,
720  const std::function<void(widget&)>& callback) override
721  {
722  std::map<std::string, string_map> data;
723 
724  data.emplace("", item_data);
725  return create_item(index, list_builder, data, callback);
726  }
727 
728  /** Inherited from generator_base. */
729  grid& create_item(const int index,
730  const builder_grid& list_builder,
731  const std::map<std::string /* widget id */, string_map>& item_data,
732  const std::function<void(widget&)>& callback) override
733  {
734  assert(index == -1 || static_cast<unsigned>(index) <= items_.size());
735 
736  child* item = new child;
737  list_builder.build(&item->child_grid);
738 
739  init(&item->child_grid, item_data, callback);
740 
741  const unsigned item_index = index == -1 ? items_.size() : index;
742 
743  items_.emplace(items_.begin() + item_index, item);
744 
745  order_dirty_ = true;
746 
747  minimum_selection::create_item(item_index);
748 
749  my_placement::create_item(item_index);
750 
751  if(!is_selected(item_index)) {
752  select_action::select(item->child_grid, false);
753  }
754 
755  return item->child_grid;
756  }
757 
758  /** Inherited from generator_base. */
759  virtual void create_items(const int index,
760  const builder_grid& list_builder,
761  const std::vector<std::map<std::string /*widget id*/, string_map>>& data,
762  const std::function<void(widget&)>& callback) override
763  {
764  impl_create_items(index, list_builder, data, callback);
765  }
766 
767  /** Inherited from generator_base. */
768  virtual void create_items(const int index,
769  const builder_grid& list_builder,
770  const std::vector<string_map>& data,
771  const std::function<void(widget&)>& callback) override
772  {
773  impl_create_items(index, list_builder, data, callback);
774  }
775 
776  /** See @ref widget::layout_initialize. */
777  virtual void layout_initialize(const bool full_initialization) override
778  {
779  for(auto& item : items_) {
780  if(item->child_grid.get_visible() != widget::visibility::invisible && item->shown) {
781  item->child_grid.layout_initialize(full_initialization);
782  }
783  }
784  }
785 
786  /** See @ref widget::request_reduce_width. */
787  virtual void request_reduce_width(const unsigned maximum_width) override
788  {
789  my_placement::request_reduce_width(maximum_width);
790  }
791 
792  /** See @ref widget::request_reduce_height. */
793  virtual void request_reduce_height(const unsigned maximum_height) override
794  {
795  my_placement::request_reduce_height(maximum_height);
796  }
797 
798  /** See @ref widget::calculate_best_size. */
799  virtual point calculate_best_size() const override
800  {
801  return my_placement::calculate_best_size();
802  }
803 
804  /** See @ref widget::place. */
805  virtual void place(const point& origin, const point& size) override
806  {
807  // Inherited, so we get useful debug info.
808  widget::place(origin, size);
809 
810  my_placement::place(origin, size);
811  }
812 
813  /** See @ref widget::set_origin. */
814  virtual void set_origin(const point& origin) override
815  {
816  // Inherited.
817  widget::set_origin(origin);
818 
819  my_placement::set_origin(origin);
820  }
821 
822  /** See @ref widget::set_visible_rectangle. */
823  virtual void set_visible_rectangle(const SDL_Rect& rectangle) override
824  {
825  my_placement::set_visible_rectangle(rectangle);
826  }
827 
828  /** See @ref widget::impl_draw_children. */
829  virtual void impl_draw_children(surface& frame_buffer, int x_offset, int y_offset) override
830  {
831  assert(this->get_visible() == widget::visibility::visible);
832 
833  calculate_order();
834 
835  for(auto index : order_) {
836  child* item = items_[index].get();
837 
838  if(item->child_grid.get_visible() == widget::visibility::visible && item->shown) {
839  item->child_grid.draw_children(frame_buffer, x_offset, y_offset);
840  }
841  }
842  }
843 
844  /** See @ref widget::child_populate_dirty_list. */
845  virtual void child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack) override
846  {
847  for(auto& item : items_) {
848  std::vector<widget*> child_call_stack = call_stack;
849  item->child_grid.populate_dirty_list(caller, child_call_stack);
850  }
851  }
852 
853  /** See @ref widget::find_at. */
854  virtual widget* find_at(const point& coordinate, const bool must_be_active) override
855  {
856  return my_placement::find_at(coordinate, must_be_active);
857  }
858 
859  /** See @ref widget::find_at. */
860  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override
861  {
862  return my_placement::find_at(coordinate, must_be_active);
863  }
864 
865  /** See @ref widget::disable_click_dismiss. */
866  bool disable_click_dismiss() const override
867  {
868  for(auto& item : items_) {
869  if(item->child_grid.disable_click_dismiss()) {
870  return true;
871  }
872  }
873 
874  return false;
875  }
876 
877  /**
878  * See @ref widget::create_walker.
879  *
880  * @todo Implement properly.
881  */
883  {
884  return nullptr;
885  }
886 
887  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
888 
889  /** Inherited from generator_base. */
890  void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) override
891  {
892  my_placement::handle_key_up_arrow(modifier, handled);
893  }
894 
895  /** Inherited from generator_base. */
896  void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) override
897  {
898  my_placement::handle_key_down_arrow(modifier, handled);
899  }
900 
901  /** Inherited from generator_base. */
902  void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) override
903  {
904  my_placement::handle_key_left_arrow(modifier, handled);
905  }
906 
907  /** Inherited from generator_base. */
908  void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) override
909  {
910  my_placement::handle_key_right_arrow(modifier, handled);
911  }
912 
913 protected:
914  /** Inherited from generator_base. */
915  void do_select_item(const unsigned index) override
916  {
917  assert(index < items_.size());
918 
919  ++selected_item_count_;
920  set_item_selected(index, true);
921  }
922 
923  /** Inherited from generator_base. */
924  void do_deselect_item(const unsigned index) override
925  {
926  assert(index < items_.size());
927 
928  --selected_item_count_;
929  set_item_selected(index, false);
930  }
931 
932 private:
933  /** Definition of an item. */
934  struct child
935  {
937  : child_grid()
938  , selected(false)
939  , shown(true)
940  , ordered_index(0)
941  {
942  }
943 
944  /** The grid containing the widgets. */
946 
947  /** Is the item selected or not. */
948  bool selected;
949 
950  /**
951  * Is the row shown or not.
952  *
953  * This flag is used the help to set the visible flag, it's preferred to
954  * test this flag for external functions.
955  *
956  * @todo functions now test for visible and shown, that can use some
957  * polishing.
958  */
959  bool shown;
960 
961  std::size_t ordered_index;
962  };
963 
964  /** The number of selected items. */
966 
967  /** The last item selected. */
969 
970  /** The items in the generator. */
971  typedef std::vector<std::unique_ptr<child>> child_list;
972  child_list items_;
973 
974  /** the elements of order_ are indexes to items_ */
975  mutable std::vector<std::size_t> order_;
976  /** whether need to recalculate order_dirty_ */
977  mutable bool order_dirty_;
978 
979  typedef std::function<bool(unsigned, unsigned)> order_func;
980  order_func order_func_;
981 
982  virtual void set_order(const order_func& order) override
983  {
984  order_func_ = order;
985  order_dirty_ = true;
986  this->set_is_dirty(true);
987  }
988 
990  {
991  const order_func& order_func_;
992  const child_list& items_;
993 
994  calculate_order_helper(const order_func& order_func, const child_list& items)
995  : order_func_(order_func)
996  , items_(items)
997  {
998  }
999 
1000  bool operator()(std::size_t a, std::size_t b)
1001  {
1002  return order_func_(a, b);
1003  }
1004  };
1005 
1006  virtual unsigned get_ordered_index(unsigned index) const override
1007  {
1008  assert(index < items_.size());
1009  calculate_order();
1010  return items_[index]->ordered_index;
1011  }
1012 
1013  virtual unsigned get_item_at_ordered(unsigned index_ordered) const override
1014  {
1015  assert(index_ordered < items_.size());
1016  calculate_order();
1017  return order_[index_ordered];
1018  }
1019 
1020  void calculate_order() const
1021  {
1022  if(order_dirty_) {
1023  if(order_.size() != items_.size()) {
1024  order_.resize(items_.size());
1025 
1026  for(std::size_t i = 0; i < items_.size(); ++i) {
1027  order_[i] = i;
1028  }
1029  }
1030 
1031  if(order_func_) {
1032  std::stable_sort(order_.begin(), order_.end(), calculate_order_helper(order_func_, items_));
1033  }
1034 
1035  for(std::size_t i = 0; i < order_.size(); ++i) {
1036  items_[order_[i]]->ordered_index = i;
1037  }
1038 
1039  order_dirty_ = false;
1040  } else {
1041  assert(order_.size() == items_.size());
1042  }
1043  }
1044  /**
1045  * Sets the selected state of an item.
1046  *
1047  * @param index The item to modify.
1048  * @param selected Select or deselect.
1049  */
1050  void set_item_selected(const unsigned index, const bool selected)
1051  {
1052  assert(index < items_.size());
1053 
1054  (*items_[index]).selected = selected;
1055  select_action::select((*items_[index]).child_grid, selected);
1056  }
1057 
1058  /**
1059  * Helper function for create_items().
1060  *
1061  * @tparam T Type of the data, this should be one of the
1062  * valid parameters for create_item().
1063  *
1064  * @param index The item before which to add the new item,
1065  * 0 == begin, -1 == end.
1066  * @param list_builder A grid builder that's will build the
1067  * contents of the new item.
1068  * @param data The data to initialize the parameters of
1069  * the new item.
1070  * @param callback The callback function to call when an item
1071  * in the grid is (de)selected.
1072  */
1073  template<class T>
1074  void impl_create_items(const int index,
1075  const builder_grid& list_builder,
1076  const std::vector<T>& data,
1077  const std::function<void(widget&)>& callback)
1078  {
1079  int i = index;
1080 
1081  for(const auto& item_data : data) {
1082  create_item(i, list_builder, item_data, callback);
1083  if(i != -1) {
1084  ++i;
1085  }
1086  }
1087  }
1088 
1089  /**
1090  * Helper function to initialize a grid.
1091  *
1092  * The actual part is implemented in select_action, see those
1093  * implementations for more information.
1094  *
1095  * @param grid The grid to initialize.
1096  * @param data The data to initialize the parameters of
1097  * the new item.
1098  * @param callback The callback function to call when an item
1099  * in the grid is (de)selected.
1100  */
1101  void init(grid* grid,
1102  const std::map<std::string /* widget id */, string_map>& data,
1103  const std::function<void(widget&)>& callback)
1104  {
1105  assert(grid);
1106  grid->set_parent(this);
1107 
1108  select_action::init(grid, data, callback);
1109  }
1110 };
1111 
1112 } // namespace gui2
bool shown
Is the row shown or not.
virtual void handle_key_left_arrow(SDL_Keymod modifier, bool &handled)=0
Left arrow key pressed.
void create_item(const unsigned)
See minimum_selection::one_item::create_item()
unsigned get_selected_item_count() const override
Inherited from generator_base.
virtual void handle_key_up_arrow(SDL_Keymod modifier, bool &handled)=0
Up arrow key pressed.
virtual void request_reduce_width(const unsigned maximum_width) override=0
See widget::request_reduce_width.
void impl_create_items(const int index, const builder_grid &list_builder, const std::vector< T > &data, const std::function< void(widget &)> &callback)
Helper function for create_items().
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override
See widget::set_visible_rectangle.
virtual grid * build() const override
void handle_key_left_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
void set_parent(widget *parent)
Definition: widget.cpp:154
virtual widget * find_at(const point &coordinate, const bool must_be_active) override=0
See widget::find_at.
const grid & item(const unsigned index) const override
Inherited from generator_base.
virtual void request_reduce_height(const unsigned maximum_height) override
See widget::request_reduce_height.
virtual void handle_key_right_arrow(SDL_Keymod modifier, bool &handled)=0
Right arrow key pressed.
virtual const widget * find_at(const point &coordinate, const bool must_be_active) const override
See widget::find_at.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
virtual widget * find(const std::string &id, const bool must_be_active)
Returns a widget with the wanted id.
Definition: widget.cpp:583
void handle_key_right_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from generator_base.
No maximum amount of items to select.
bool deselect_item(const unsigned index)
See minimum_selection::one_item::deselect_item()
bool placed_
Has the grid already been placed?
virtual void place(const point &origin, const point &size) override=0
See widget::place.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: grid.cpp:681
Add a special kind of assert to validate whether the input from WML doesn&#39;t contain any problems that...
visibility get_visible() const
Definition: widget.cpp:502
bool order_dirty_
whether need to recalculate order_dirty_
void set_item_shown(const unsigned index, const bool show)
Called when an item is shown or hidden.
Definition: generator.cpp:33
#define a
grid & item_ordered(const unsigned index) override
Inherited from generator_base.
int get_selected_item() const override
Inherited from generator_base.
void do_deselect_item(const unsigned index) override
Inherited from generator_base.
virtual bool is_selected(const unsigned index) const =0
Returns whether the item is selected.
void delete_item(const unsigned index)
See minimum_selection::one_item::delete_item()
grid & create_item(const int index, const builder_grid &list_builder, const string_map &item_data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
virtual void do_select_item(const unsigned index)=0
Selects a not selected item.
This file contains the window object, this object is a top level container which has the event manage...
Places the items in a grid.
virtual void request_reduce_height(const unsigned) override
See widget::request_reduce_height.
Base class for all widgets.
Definition: widget.hpp:48
grid & create_item(const int index, const builder_grid &list_builder, const std::map< std::string, string_map > &item_data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
void calculate_order() const
bool operator()(std::size_t a, std::size_t b)
virtual grid & item(const unsigned index)=0
Gets the grid of an item.
void select_item(const unsigned index, const bool select) override
Called when an item is selected.
virtual void child_populate_dirty_list(window &caller, const std::vector< widget *> &call_stack) override
See widget::child_populate_dirty_list.
virtual void request_reduce_width(const unsigned) override
See widget::request_reduce_width.
const std::vector< std::string > items
virtual unsigned get_selected_item_count() const =0
Returns the number of selected items.
void handle_key_left_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
virtual iteration::walker_base * create_walker() override
See widget::create_walker.
void create_item(const unsigned index)
Called when an item is created.
Definition: generator.cpp:67
void set_item_selected(const unsigned index, const bool selected)
Sets the selected state of an item.
void delete_item(const unsigned index)
Called just before an item is deleted.
Definition: generator.cpp:84
void handle_key_right_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
const grid & item_ordered(const unsigned index) const override
Inherited from generator_base.
std::vector< std::size_t > order_
the elements of order_ are indexes to items_
Generic file dialog.
Definition: field-fwd.hpp:22
virtual point calculate_best_size() const override=0
See widget::calculate_best_size.
#define b
virtual void impl_draw_children(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_children.
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: grid.cpp:185
Base container class.
Definition: grid.hpp:30
virtual void request_reduce_height(const unsigned maximum_height) override=0
See widget::request_reduce_height.
void handle_key_down_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from generator_base.
virtual void set_order(const order_func &order) override
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
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:84
void select_item(const unsigned index, const bool select) override
See one_item::select_item().
struct utils::detail::formula_initer init
void clear() override
Inherited from generator_base.
virtual void request_reduce_width(const unsigned) override
See widget::request_reduce_width.
Abstract base class for the generator.
Definition: generator.hpp:37
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:237
void set_visible(const visibility visible)
Definition: widget.cpp:475
virtual bool get_item_shown(const unsigned index) const override
Inherited from generator_base.
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:465
grid & item(const unsigned index) override
Inherited from generator_base.
virtual void set_origin(const point &origin)
Sets the origin of the widget.
Definition: widget.cpp:220
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:35
std::string selected
The walker abstract base class.
Definition: walker.hpp:26
Places the items independent of each other.
std::function< bool(unsigned, unsigned)> order_func
static thread_local std::deque< std::string > call_stack
For printing error messages when WFL parsing or evaluation fails, this contains the names of the WFL ...
Definition: function.cpp:46
virtual void place(const point &origin, const point &size) override
See widget::place.
placement
Determines how the items are placed.
Definition: generator.hpp:47
bool deselect_item(const unsigned index)
Called when the users wants to deselect an item.
Definition: generator.cpp:74
void delete_item(const unsigned index) override
Inherited from generator_base.
int last_selected_item_
The last item selected.
Basic template class to generate new items.
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
void handle_key_down_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
void set_item_shown(const unsigned index, const bool show) override
Inherited from generator_base.
void select(grid &grid, const bool show)
#define FAIL_WITH_DEV_MESSAGE(message, dev_message)
std::vector< std::unique_ptr< child > > child_list
The items in the generator.
Places the items in a horizontal row.
Definition of an item.
virtual int get_selected_item() const =0
Returns the selected item.
std::size_t i
Definition: function.cpp:940
void handle_key_left_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from generator_base.
virtual void set_visible_rectangle(const SDL_Rect &rectangle) override=0
See widget::set_visible_rectangle.
virtual void clear()=0
Deletes all items.
void handle_key_up_arrow(SDL_Keymod modifier, bool &handled) override
Inherited from generator_base.
bool is_selected(const unsigned index) const override
Inherited from generator_base.
void init(grid *grid, const std::map< std::string, string_map > &data, const std::function< void(widget &)> &callback)
Helper function to initialize a grid.
virtual grid & create_item(const int index, const builder_grid &list_builder, const string_map &item_data, const std::function< void(widget &)> &callback)=0
Creates a new item.
The user set the widget invisible, that means:
bool placed_
Has the grid already been placed?
unsigned selected_item_count_
The number of selected items.
virtual unsigned get_item_at_ordered(unsigned index_ordered) const override
std::map< std::string, t_string > string_map
Definition: widget.hpp:25
Holds a 2D point.
Definition: point.hpp:23
virtual unsigned get_ordered_index(unsigned index) const override
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:69
virtual void create_items(const int index, const builder_grid &list_builder, const std::vector< string_map > &data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
void handle_key_down_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
The user sets the widget visible, that means:
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
void handle_key_up_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
The user sets the widget hidden, that means:
virtual void request_reduce_height(const unsigned) override
See widget::request_reduce_height.
bool selected
Is the item selected or not.
calculate_order_helper(const order_func &order_func, const child_list &items)
virtual void handle_key_down_arrow(SDL_Keymod modifier, bool &handled)=0
Down arrow key pressed.
bool placed_
Has the grid already been placed?
virtual void select_item(const unsigned index, const bool select)=0
(De)selects an item.
Select the item, this requires the grid to contain a selectable_item.
grid child_grid
The grid containing the widgets.
Places the items in a vertical column.
void handle_key_right_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
void draw_children(surface &frame_buffer, int x_offset, int y_offset)
Draws the children of a widget.
Definition: widget.cpp:386
unsigned get_item_count() const override
Inherited from generator_base.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
virtual void set_origin(const point &origin) override=0
See widget::set_origin.
virtual void create_items(const int index, const builder_grid &list_builder, const std::vector< std::map< std::string, string_map >> &data, const std::function< void(widget &)> &callback) override
Inherited from generator_base.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
void create_item(const unsigned)
See horizontal_list::create_item().
virtual void do_deselect_item(const unsigned index)=0
Deselects a selected item.
void do_select_item(const unsigned index) override
Inherited from generator_base.
virtual point calculate_best_size() const override
See widget::calculate_best_size.
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
virtual void request_reduce_height(const unsigned) override
See widget::request_reduce_height.
virtual void request_reduce_width(const unsigned) override
See widget::request_reduce_width.
virtual void set_origin(const point &origin) override
See widget::set_origin.
void select_item(const unsigned index, const bool select=true) override
Inherited from generator_base.
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:139
void handle_key_up_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.