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