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