The Battle for Wesnoth  1.17.4+dev
generator_private.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
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  {
108  do_deselect_item(index);
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)) {
116  do_deselect_item(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.
156  do_select_item(index);
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 
168  do_select_item(index);
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 std::map<std::string /* widget id */, string_map>& 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 std::map<std::string /* widget id */, string_map>& 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()
568  , selected_item_count_(0)
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;
607  selected_item_count_ = 0;
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);
617  last_selected_item_ = index;
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;
641  items_[index]->child_grid.set_visible(show ? widget::visibility::visible : widget::visibility::invisible);
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 string_map& item_data,
722  const std::function<void(widget&)>& callback) override
723  {
724  std::map<std::string, string_map> data;
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 std::map<std::string /* widget id */, string_map>& 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<std::map<std::string /*widget id*/, string_map>>& 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<string_map>& 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(int x_offset, int y_offset) 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(x_offset, y_offset);
842  }
843  }
844  }
845 
846  /** See @ref widget::child_populate_dirty_list. */
847  virtual void child_populate_dirty_list(window& caller, const std::vector<widget*>& call_stack) override
848  {
849  for(auto& item : items_) {
850  std::vector<widget*> child_call_stack = call_stack;
851  item->child_grid.populate_dirty_list(caller, child_call_stack);
852  }
853  }
854 
855  /** See @ref widget::find_at. */
856  virtual widget* find_at(const point& coordinate, const bool must_be_active) override
857  {
858  return my_placement::find_at(coordinate, must_be_active);
859  }
860 
861  /** See @ref widget::find_at. */
862  virtual const widget* find_at(const point& coordinate, const bool must_be_active) const override
863  {
864  return my_placement::find_at(coordinate, must_be_active);
865  }
866 
867  /** See @ref widget::disable_click_dismiss. */
868  bool disable_click_dismiss() const override
869  {
870  for(auto& item : items_) {
871  if(item->child_grid.disable_click_dismiss()) {
872  return true;
873  }
874  }
875 
876  return false;
877  }
878 
879  /**
880  * See @ref widget::create_walker.
881  *
882  * @todo Implement properly.
883  */
885  {
886  return nullptr;
887  }
888 
889  /***** ***** ***** ***** keyboard functions ***** ***** ***** *****/
890 
891  /** Inherited from generator_base. */
892  void handle_key_up_arrow(SDL_Keymod modifier, bool& handled) override
893  {
894  my_placement::handle_key_up_arrow(modifier, handled);
895  }
896 
897  /** Inherited from generator_base. */
898  void handle_key_down_arrow(SDL_Keymod modifier, bool& handled) override
899  {
900  my_placement::handle_key_down_arrow(modifier, handled);
901  }
902 
903  /** Inherited from generator_base. */
904  void handle_key_left_arrow(SDL_Keymod modifier, bool& handled) override
905  {
906  my_placement::handle_key_left_arrow(modifier, handled);
907  }
908 
909  /** Inherited from generator_base. */
910  void handle_key_right_arrow(SDL_Keymod modifier, bool& handled) override
911  {
912  my_placement::handle_key_right_arrow(modifier, handled);
913  }
914 
915 protected:
916  /** Inherited from generator_base. */
917  void do_select_item(const unsigned index) override
918  {
919  assert(index < items_.size());
920 
921  ++selected_item_count_;
922  set_item_selected(index, true);
923  }
924 
925  /** Inherited from generator_base. */
926  void do_deselect_item(const unsigned index) override
927  {
928  assert(index < items_.size());
929 
930  --selected_item_count_;
931  set_item_selected(index, false);
932  }
933 
934 private:
935  /** Definition of an item. */
936  struct child
937  {
939  : child_grid()
940  , selected(false)
941  , shown(true)
942  , ordered_index(0)
943  {
944  }
945 
946  /** The grid containing the widgets. */
948 
949  /** Is the item selected or not. */
950  bool selected;
951 
952  /**
953  * Is the row shown or not.
954  *
955  * This flag is used the help to set the visible flag, it's preferred to
956  * test this flag for external functions.
957  *
958  * @todo functions now test for visible and shown, that can use some
959  * polishing.
960  */
961  bool shown;
962 
963  std::size_t ordered_index;
964  };
965 
966  /** The number of selected items. */
968 
969  /** The last item selected. */
971 
972  /** The items in the generator. */
973  typedef std::vector<std::unique_ptr<child>> child_list;
974  child_list items_;
975 
976  /** the elements of order_ are indexes to items_ */
977  mutable std::vector<std::size_t> order_;
978  /** whether need to recalculate order_dirty_ */
979  mutable bool order_dirty_;
980 
981  typedef std::function<bool(unsigned, unsigned)> order_func;
982  order_func order_func_;
983 
984  virtual void set_order(const order_func& order) override
985  {
986  order_func_ = order;
987  order_dirty_ = true;
988  this->set_is_dirty(true);
989  }
990 
992  {
993  const order_func& order_func_;
994  const child_list& items_;
995 
996  calculate_order_helper(const order_func& order_func, const child_list& items)
997  : order_func_(order_func)
998  , items_(items)
999  {
1000  }
1001 
1002  bool operator()(std::size_t a, std::size_t b)
1003  {
1004  return order_func_(a, b);
1005  }
1006  };
1007 
1008  virtual unsigned get_ordered_index(unsigned index) const override
1009  {
1010  assert(index < items_.size());
1011  calculate_order();
1012  return items_[index]->ordered_index;
1013  }
1014 
1015  virtual unsigned get_item_at_ordered(unsigned index_ordered) const override
1016  {
1017  assert(index_ordered < items_.size());
1018  calculate_order();
1019  return order_[index_ordered];
1020  }
1021 
1022  void calculate_order() const
1023  {
1024  if(order_dirty_) {
1025  if(order_.size() != items_.size()) {
1026  order_.resize(items_.size());
1027 
1028  for(std::size_t i = 0; i < items_.size(); ++i) {
1029  order_[i] = i;
1030  }
1031  }
1032 
1033  if(order_func_) {
1034  std::stable_sort(order_.begin(), order_.end(), calculate_order_helper(order_func_, items_));
1035  }
1036 
1037  for(std::size_t i = 0; i < order_.size(); ++i) {
1038  items_[order_[i]]->ordered_index = i;
1039  }
1040 
1041  order_dirty_ = false;
1042  } else {
1043  assert(order_.size() == items_.size());
1044  }
1045  }
1046  /**
1047  * Sets the selected state of an item.
1048  *
1049  * @param index The item to modify.
1050  * @param selected Select or deselect.
1051  */
1052  void set_item_selected(const unsigned index, const bool selected)
1053  {
1054  assert(index < items_.size());
1055 
1056  (*items_[index]).selected = selected;
1057  select_action::select((*items_[index]).child_grid, selected);
1058  }
1059 
1060  /**
1061  * Helper function for create_items().
1062  *
1063  * @tparam T Type of the data, this should be one of the
1064  * valid parameters for create_item().
1065  *
1066  * @param index The item before which to add the new item,
1067  * 0 == begin, -1 == end.
1068  * @param list_builder A grid builder that's will build the
1069  * contents of the new item.
1070  * @param data The data to initialize the parameters of
1071  * the new item.
1072  * @param callback The callback function to call when an item
1073  * in the grid is (de)selected.
1074  */
1075  template<class T>
1076  void impl_create_items(const int index,
1077  const builder_grid& list_builder,
1078  const std::vector<T>& data,
1079  const std::function<void(widget&)>& callback)
1080  {
1081  int i = index;
1082 
1083  for(const auto& item_data : data) {
1084  create_item(i, list_builder, item_data, callback);
1085  if(i != -1) {
1086  ++i;
1087  }
1088  }
1089  }
1090 
1091  /**
1092  * Helper function to initialize a grid.
1093  *
1094  * The actual part is implemented in select_action, see those
1095  * implementations for more information.
1096  *
1097  * @param grid The grid to initialize.
1098  * @param data The data to initialize the parameters of
1099  * the new item.
1100  * @param callback The callback function to call when an item
1101  * in the grid is (de)selected.
1102  */
1103  void init(grid* grid,
1104  const std::map<std::string /* widget id */, string_map>& data,
1105  const std::function<void(widget&)>& callback)
1106  {
1107  assert(grid);
1108  grid->set_parent(this);
1109 
1110  select_action::init(grid, data, callback);
1111  }
1112 };
1113 
1114 } // 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.
void handle_key_left_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:39
void set_parent(widget *parent)
Definition: widget.cpp:156
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 void impl_draw_children(int x_offset, int y_offset) override
See widget::impl_draw_children.
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:582
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:686
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:501
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:34
#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:49
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)
const std::vector< std::string > items
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.
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.
void create_item(const unsigned index)
Called when an item is created.
Definition: generator.cpp:68
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:85
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:23
virtual point calculate_best_size() const override=0
See widget::calculate_best_size.
#define b
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
Definition: grid.cpp:190
Base container class.
Definition: grid.hpp:31
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:415
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
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:39
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
virtual void place(const point &origin, const point &size)
Places the widget.
Definition: widget.cpp:239
void draw_children(int x_offset, int y_offset)
Draws the children of a widget.
Definition: widget.cpp:387
void set_visible(const visibility visible)
Definition: widget.cpp:474
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:464
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:222
void init()
Initializes the GUI subsystems.
Definition: gui.cpp:36
std::string selected
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:47
virtual void place(const point &origin, const point &size) override
See widget::place.
placement
Determines how the items are placed.
Definition: generator.hpp:49
bool deselect_item(const unsigned index)
Called when the users wants to deselect an item.
Definition: generator.cpp:75
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)
virtual std::unique_ptr< widget > build() const override
Inherited from builder_widget.
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:967
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:26
Holds a 2D point.
Definition: point.hpp:24
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:72
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.
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:66
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:140
void handle_key_up_arrow(SDL_Keymod, bool &) override
Inherited from generator_base.