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