Gorgon Game Engine
Listbox.h
Go to the documentation of this file.
1 #pragma once
2 
3 
4 #include "Common.h"
5 #include "../UI/ComponentStackWidget.h"
6 #include "../Property.h"
7 #include "../Input/KeyRepeater.h"
8 #include "Registry.h"
9 #include "ListItem.h"
10 #include <vector>
11 #include "Scrollbar.h"
12 
13 namespace Gorgon { namespace Widgets {
14 
19  template<class T_, class W_>
20  class ListBase {
21  public:
22  virtual ~ListBase() {
23  }
24 
27  virtual T_ &operator[](long index) = 0;
28 
31  virtual const T_ &operator[](long index) const = 0;
32 
34  virtual long GetCount() const = 0;
35 
40  virtual long getindex(const W_ &widget) = 0;
41 
45  virtual void Refresh() = 0;
46 
47  protected:
48 
54  virtual W_ *getrepresentation(long index) = 0;
55 
60  virtual W_ *getrepresentation() = 0;
61 
62  };
63 
65  namespace internal {
67  template <class T_, class W_, class F_>
68  class LBTRF_blank {
69  protected:
70  LBTRF_blank() { }
71  ~LBTRF_blank() { }
72 
73  void apply(long, W_ &, const T_ &, Geometry::Point p, Geometry::Size) { }
74 
77  }
78 
79  void prepare(W_ &) { }
80  void insert(long, long) { }
81  void move(long, long) { }
82  void remove(long, long) { }
83  };
84 
86  template <class T_, class W_, class F_>
87  class LBTRF_ListItem {
88  public:
89 
91  void SetOddEven(bool value) {
92  if(oddeven == value)
93  return;
94 
95  oddeven = value;
96  dynamic_cast<F_*>(this)->Refresh();
97  }
98 
100  bool GetOddEven() const {
101  return oddeven;
102  }
103 
104  protected:
105  LBTRF_ListItem() { }
106  ~LBTRF_ListItem() { }
107 
108  void apply(long, W_ &w, const T_ &, Geometry::Point p, Geometry::Size) {
109  if(oddeven) {
110  w.SetParity(p.Y%2 ? Parity::Odd : Parity::Even);
111  }
112  else {
113  w.SetParity(Parity::None);
114  }
115  }
116 
119  }
120 
121  void prepare(W_ &) { }
122  void insert(long, long) { }
123  void move(long, long) { }
124  void remove(long, long) { }
125 
126  bool oddeven = true;
127  };
128 
129  template<class T_, class W_>
130  void SetTextUsingFrom(const T_ &val, W_ &w) {
131  w.SetText(String::From(val));
132  }
133 
134  template<class T_, class W_, class F_, F_ f>
135  void SetTextUsingFn(const T_ &val, W_ &w) {
136  w.SetText(f(val));
137  }
138 
139  template<class T_, class W_>
140  void GetTextUsingTo(W_ &w, T_ &val) {
141  val = String::To<T_>(w.GetText());
142  }
143 
144  //This class allows single selection. The selected item will
145  //follow the focus by default. If desired, this can be changed
146  template<class T_, class W_, class F_>
147  class LBSELTR_Single {
148  public:
150  bool HasSelectedItem() const {
151  return selectedindex != -1;
152  }
153 
157  const T_ &GetSelectedItem() const {
158  if(selectedindex == -1)
159  throw std::runtime_error("Nothing is selected.");
160 
161  return dynamic_cast<const F_&>(*this)[selectedindex];
162  }
163 
168  T_ &GetSelectedItem() {
169  if(selectedindex == -1)
170  throw std::runtime_error("Nothing is selected.");
171 
172  return dynamic_cast<F_&>(*this)[selectedindex];
173  }
174 
177  long GetSelectedIndex() const {
178  return selectedindex;
179  }
180 
184  void SetSelectedIndex(long index) {
185  if(index < -1 || index >= dynamic_cast<F_&>(*this).GetCount())
186  throw std::out_of_range("Selected index does not exits");
187 
188  if(index == selectedindex)
189  return;
190 
191  if(focusonly) {
192  if(index == -1) {
193  W_ *elm = dynamic_cast<F_&>(*this).getrepresentation();
194  if(elm != nullptr && elm->HasParent()) {
195  elm->GetParent().RemoveFocus();
196  }
197  }
198  else {
199  W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
200  if(elm != nullptr) {
201  elm->Focus();
202  }
203  else {
204  elm = dynamic_cast<F_&>(*this).getrepresentation();
205 
206  if(elm != nullptr && elm->HasParent()) {
207  elm->GetParent().RemoveFocus();
208  }
209  }
210  }
211 
212  focusindex = index;
213  }
214 
215  if(selected)
216  selected->SetSelected(false);
217 
218  if(index != -1) {
219  W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
220 
221  if(elm)
222  elm->SetSelected(true);
223 
224  selected = elm;
225  }
226 
227  selectedindex = index;
228  ChangedEvent(selectedindex);
229  }
230 
233  void SetFocusIndex(long value) {
234  if(focusindex == value)
235  return;
236 
237  if(focusonly) {
238  SetSelectedIndex(value);
239  return;
240  }
241 
242  if(value != -1) {
243  auto w = dynamic_cast<F_*>(this)->getrepresentation(value);
244  if(w)
245  w->Focus();
246  }
247  else {
248  auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
249  if(w)
250  w->Defocus();
251  }
252 
253  focusindex = value;
254  }
255 
258  long GetFocusIndex() const {
259  return focusindex;
260  }
261 
262  void RemoveSelection() {
263  SetSelectedIndex(-1);
264  }
265 
268  void SetSelection(T_ item) {
269  auto &me = dynamic_cast<F_&>(*this);
270 
271  for(long i=0; i<me.GetSize(); i++) {
272  if(me[i] == item) {
273  SetSelectedIndex(i);
274  return;
275  }
276  }
277 
278  SetSelectedIndex(-1);
279  }
280 
285  bool IsSelectionFollowingFocus() const {
286  return focusonly;
287  }
288 
293  void SetSelectionFollowsFocus(bool value) {
294  if(!focusonly && value) {
295  if(focusindex != -1) {
296  if(selectedindex != focusindex) {
297  selectedindex = focusindex;
298  ChangedEvent(selectedindex);
299  }
300  }
301  else {
302  focusindex = selectedindex;
303  }
304  }
305 
306  focusonly = value;
307  }
308 
309  operator T_() {
310  return GetSelectedItem();
311  }
312 
313  operator T_() const {
314  return GetSelectedItem();
315  }
316 
317  Event<LBSELTR_Single, long> ChangedEvent = Event<LBSELTR_Single, long>{this};
318 
319  protected:
320  LBSELTR_Single() {
321  }
322 
323  virtual ~LBSELTR_Single() { }
324 
325  void sel_clicked(long index, W_ &w) {
326  if(focusonly) {
327  if(selectedindex == index)
328  return;
329 
330  if(selected)
331  selected->SetSelected(false);
332 
333  w.SetSelected(true);
334 
335  if(dynamic_cast<UI::Widget*>(this)->IsFocused())
336  w.Focus();
337 
338  selected = &w;
339  selectedindex = index;
340  focusindex = index;
341 
342  ChangedEvent(index);
343  }
344  else {
345  if(focusindex == index)
346  return;
347 
348  if(dynamic_cast<UI::Widget*>(this)->IsFocused())
349  w.Focus();
350 
351  focusindex = index;
352  }
353 
354  dynamic_cast<UI::Widget*>(this)->Focus();
355  }
356 
357  void sel_toggled(long index, W_ &w) {
358  if(selectedindex == index || focusonly)
359  return;
360 
361  if(selected)
362  selected->SetSelected(false);
363 
364  w.SetSelected(true);
365  selectedindex = index;
366  selected = &w;
367 
368  if(focusonly) {
369  if(dynamic_cast<UI::Widget*>(this)->IsFocused())
370  w.Focus();
371 
372  focusindex = index;
373  }
374 
375  ChangedEvent(index);
376  }
377 
378  void sel_apply(long index, W_ &w, const T_ &) {
379  if(index == focusindex) {
380  w.Focus();
381  }
382  else if(w.IsFocused()) {
383  w.Defocus();
384  }
385 
386  if(index == selectedindex) {
387  w.SetSelected(true);
388  selected = &w;
389  }
390  else {
391  w.SetSelected(false);
392 
393  if(&w == selected)
394  selected = nullptr;
395  }
396  }
397 
398  void sel_prepare(W_ &w) {
399  w.ClickEvent.Register([&w, this] {
400  sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
401  });
402  w.ToggleEvent.Register([&w, this] {
403  sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w);
404  });
405  }
406 
407  void sel_insert(long index, long count) {
408  if(index <= focusindex)
409  focusindex += count;
410 
411  if(index <= selectedindex)
412  selectedindex += count;
413  }
414 
415  void sel_move(long index, long target) {
416  //move triggers apply to both indexes
417 
418  if(index == focusindex) {
419  focusindex = target;
420  }
421  else if(index > focusindex && target <= focusindex) {
422  focusindex++;
423  }
424  else if(index < focusindex && target > focusindex) {
425  focusindex--;
426  }
427 
428  if(index == selectedindex) {
429  selectedindex = target;
430  }
431  else if(index > selectedindex && target <= selectedindex) {
432  selectedindex++;
433  }
434  else if(index < selectedindex && target > selectedindex) {
435  selectedindex--;
436  }
437  }
438 
439  void sel_remove(long index, long count) {
440  //removed items will be repurposed using apply,
441  if(index <= focusindex) {
442  if(index+count > focusindex) {
443  focusindex = -1;
444  ChangedEvent(-1);
445  }
446  else {
447  focusindex -= count;
448  }
449  }
450 
451  if(index <= selectedindex) {
452  if(index+count > selectedindex) {
453  selectedindex = -1;
454  ChangedEvent(-1);
455  }
456  else {
457  selectedindex -= count;
458  }
459  }
460  }
461 
462  void sel_destroy(W_ &w) {
463  if(&w == selected) {
464  selected = nullptr;
465  }
466  if(w.IsFocused()) {
467  focusindex = -1;
468  w.Defocus();
469  }
470  }
471 
472  void reapplyfocus() {
473  if(focusindex != -1) {
474  auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
475  if(w)
476  w->Focus();
477  }
478  }
479 
480  bool focusonly = true;
481 
482  long focusindex = -1, selectedindex = -1;
483 
484  W_ *selected = nullptr;
485  };
486 
487  //This class allows single selection. The selected item will
488  //follow the focus by default. If desired, this can be changed
489  template<class T_, class W_, class F_>
490  class LBSELTR_Multi {
491  template <class F1_> friend class ItemIterator_;
492  friend class SelectionHelper;
493 
494  class SelectionIndexHelper {
495  public:
496  SelectionIndexHelper(const std::vector<long> &v) : v(v) {
497  }
498 
499  auto begin() {
500  return v.begin();
501  }
502 
503  auto end() {
504  return v.end();
505  }
506 
507  private:
508  const std::vector<long> &v;
509  };
510 
511  class SelectionHelper {
512  public:
513  SelectionHelper(LBSELTR_Multi &l) : l(l) {
514  }
515 
516  auto begin() {
517  auto &me = dynamic_cast<F_ &>(l);
518  return ItemIterator(me, l.selected, 0);
519  }
520 
521  auto end() {
522  auto &me = dynamic_cast<F_ &>(l);
523  return ItemIterator(me, l.selected, l.selected.size());
524  }
525 
526  auto begin() const {
527  auto &me = dynamic_cast<F_ &>(l);
528  return ConstItemIterator(me, l.selected, 0);
529  }
530 
531  auto end() const {
532  auto &me = dynamic_cast<F_ &>(l);
533  return ConstItemIterator(me, l.selected, l.selected.size());
534  }
535 
536  private:
537  LBSELTR_Multi &l;
538  };
539 
540 
541  template <class O_, class F1_>
542  class ItemIterator_ : public Containers::Iterator<ItemIterator_<O_, F1_>, O_> {
543  friend class SelectionHelper;
544  friend class ConstItemIterator;
545  friend class Containers::Iterator<ItemIterator_<O_, F1_>, O_>;
546  public:
548  ItemIterator_(): list(NULL), offset(-1) {
549  }
551  ItemIterator_(const ItemIterator_ &it): list(it.list), offset(it.offset) {
552  }
553 
554  protected:
555  ItemIterator_(F1_ &list, const std::vector<long> &inds, long offset = 0): list(&list), offset(offset), inds(&inds) {
556  }
557 
559  O_ &current() const {
560  if(!isvalid())
561  throw std::out_of_range("Iterator is not valid.");
562 
563  return (*list)[(*inds)[offset]];
564  }
565 
566  bool isvalid() const {
567  return list && inds && offset>=0 && offset<(inds->size());
568  }
569 
570  bool moveby(long amount) {
571  //sanity check
572  if(amount==0) return isvalid();
573 
574  offset += amount;
575 
576  return isvalid();
577  }
578 
579  bool compare(const ItemIterator_ &it) const {
580  if(!it.isvalid() && !isvalid()) return true;
581  return it.offset==offset;
582  }
583 
584  void set(const ItemIterator_ &it) {
585  list = it.list;
586  offset = it.offset;
587  }
588 
589  long distance(const ItemIterator_ &it) const {
590  return it.offset-offset;
591  }
592 
593  bool isbefore(const ItemIterator_ &it) const {
594  return offset<it.offset;
595  }
596 
597  F1_ *list = nullptr;
598  long offset = 0;
599  const std::vector<long> *inds = nullptr;
600  };
601  public:
603  typedef ItemIterator_<T_, F_> ItemIterator;
604 
606  class ConstItemIterator : public ItemIterator_<const T_, const F_> {
607  friend class SelectionHelper;
608  friend class Containers::Iterator<ItemIterator_<const T_, const F_>, T_>;
609 
610  public:
612  ConstItemIterator(const ItemIterator &it) {
613  this->list = it.list;
614  this->offset = it.offset;
615  }
616 
617  private:
618  ConstItemIterator(const F_ &c, const std::vector<long> &inds, long offset = 0): ItemIterator_<const T_, const F_>(c, inds, offset) {
619  }
620  };
621 
622  enum SelectionMethod {
624  Toggle,
625 
628  UseCtrl,
629  };
630 
631  enum EventMethod {
633  Once,
634 
636  ForEachItem
637  };
638 
644  void SetSelectionMethod(SelectionMethod value) {
645  method = value;
646  }
647 
649  SelectionMethod GetSelectionMethod() const {
650  return method;
651  }
652 
659  void SetEventMethod(EventMethod value) {
660  event = value;
661  }
662 
664  EventMethod GetEventMethod() const {
665  return event;
666  }
667 
670  long GetFocusIndex() const {
671  return focusindex;
672  }
673 
676  void SetFocusIndex(long value) {
677  if(focusindex == value)
678  return;
679 
680  if(value != -1) {
681  auto w = dynamic_cast<F_*>(this)->getrepresentation(value);
682  if(w)
683  w->Focus();
684  }
685  else {
686  auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
687  if(w)
688  w->Defocus();
689  }
690 
691  focusindex = value;
692  }
693 
695  void ClearSelection() {
696  if(event == Once) {
697  selected.clear();
698  ChangedEvent(-1, false);
699  }
700  else {
701  std::vector<long> old;
702  std::swap(old, selected);
703 
704  for(auto ind : old) {
705  ChangedEvent(ind, false);
706  }
707  }
708 
709  dynamic_cast<F_*>(this)->Refresh();
710  }
711 
713  void SetSelection(long ind) {
714  SetSelection(std::vector<long>{ind});
715  };
716 
718  void SetSelection(std::vector<long> indices) {
719  if(event == ForEachItem)
720  ClearSelection();
721 
722  selected = std::move(indices);
723  std::sort(selected.begin(), selected.end());
724 
725  //ensure nothing is duplicated
726  selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
727 
728  if(event == ForEachItem) {
729  for(auto ind : selected) {
730  ChangedEvent(ind, true);
731  }
732  }
733  else {
734  ChangedEvent(-1, false);
735  }
736 
737  dynamic_cast<F_*>(this)->Refresh();
738  };
739 
741  template<class ...P_>
742  void SetSelection(P_&&... elms) {
743  SetSelection({elms...});
744  }
745 
747  void AddToSelection(long ind) {
748  AddToSelection(std::vector<long>{ind});
749  };
750 
752  void AddToSelection(std::vector<long> indices) {
753  std::sort(indices.begin(), indices.end());
754 
755  selected.resize(selected.size() + indices.size());
756  auto sel = selected.rbegin();
757  auto cur = selected.rbegin() + indices.size();
758  auto ind = indices.rbegin();
759 
760  while(ind != indices.rend()) {
761  if(cur == selected.rend() || *cur < *ind) {
762  *sel = *ind;
763 
764  if(event == ForEachItem)
765  ChangedEvent(*ind, true);
766 
767  ++ind;
768  }
769  else {
770  *sel = *cur;
771  ++cur;
772  }
773  ++sel;
774  }
775 
776  //ensure nothing is duplicated
777  selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
778 
779  if(event == Once) {
780  ChangedEvent(-1, false);
781  }
782 
783  dynamic_cast<F_*>(this)->Refresh();
784  };
785 
787  template<class ...P_>
788  void AddToSelection(P_&&... elms) {
789  AddToSelection({elms...});
790  }
791 
793  bool IsSelected(long index) const {
794  return std::binary_search(selected.begin(), selected.end(), index);
795  }
796 
798  long GetSelectionCount() const {
799  return long(selected.size());
800  }
801 
803  void RemoveFromSelection(long index) {
804  auto item = std::lower_bound(selected.begin(), selected.end(), index);
805 
806  if(item != selected.end() && *item == index) {
807  selected.erase(item);
808  ChangedEvent(index, false);
809  }
810 
811  dynamic_cast<F_*>(this)->Refresh();
812  }
813 
815  void SelectAll() {
816  auto elms = dynamic_cast<F_*>(this)->GetCount();
817 
818  std::vector<long> old;
819  old.reserve(elms);
820 
821  std::swap(old, selected);
822 
823  auto sel = old.begin();
824  for(int i=0; i<elms; i++) {
825  if(sel != old.end() && *sel == i)
826  ++sel;
827  else if(event == ForEachItem)
828  ChangedEvent(i, true);
829 
830  selected.push_back(i);
831  }
832 
833  if(event == Once)
834  ChangedEvent(-1, false);
835 
836 
837  dynamic_cast<F_*>(this)->Refresh();
838  }
839 
841  void InvertSelection() {
842  std::vector<long> old;
843 
844  auto elms = dynamic_cast<F_*>(this)->GetCount();
845  old.reserve(elms-selected.size());
846 
847  std::swap(selected, old);
848 
849  auto sel = old.begin();
850  for(int i=0; i<elms; i++) {
851  if(sel != old.end() && *sel == i) {
852  ++sel;
853 
854  if(event == ForEachItem)
855  ChangedEvent(i, false);
856  }
857  else {
858  selected.push_back(i);
859 
860  if(event == ForEachItem)
861  ChangedEvent(i, true);
862  }
863  }
864 
865  if(event == Once)
866  ChangedEvent(-1, false);
867 
868  dynamic_cast<F_*>(this)->Refresh();
869  }
870 
872  SelectionIndexHelper SelectedIndices;
873 
876  SelectionHelper Selection;
877 
878  Event<LBSELTR_Multi, long, bool> ChangedEvent = Event<LBSELTR_Multi, long, bool>{this};
879 
880  protected:
881  LBSELTR_Multi() :
882  SelectedIndices(selected),
883  Selection(*this)
884  {
885  }
886 
887  virtual ~LBSELTR_Multi() { }
888 
889  void sel_clicked(long index, W_ &w) {
890  if(focusindex == index)
891  return;
892 
893  if(dynamic_cast<UI::Widget*>(this)->IsFocused())
894  w.Focus();
895 
896  focusindex = index;
897 
898  dynamic_cast<UI::Widget*>(this)->Focus();
899  }
900 
901  void sel_toggled(long index, W_ &w, bool forcetoggle = true) {
902  if(method == Toggle || forcetoggle) {
903  auto item = std::lower_bound(selected.begin(), selected.end(), index);
904 
905  if(item != selected.end() && *item == index) {
906  w.SetSelected(false);
907  selected.erase(item);
908 
909  ChangedEvent(index, false);
910  }
911  else {
912  w.SetSelected(true);
913  selected.insert(item, index);
914 
915  ChangedEvent(index, true);
916  }
917  }
918  else {
920  auto item = std::lower_bound(selected.begin(), selected.end(), index);
921 
922  if(item != selected.end() && *item == index) {
923  w.SetSelected(false);
924  selected.erase(item);
925 
926  ChangedEvent(index, false);
927  }
928  else {
929  w.SetSelected(true);
930  selected.insert(item, index);
931 
932  ChangedEvent(index, true);
933  }
934  }
935  else {
936  SetSelection(index);
937  }
938  }
939  }
940 
941  void sel_apply(long index, W_ &w, const T_ &) {
942  if(index == focusindex) {
943  w.Focus();
944  }
945  else if(w.IsFocused()) {
946  w.Defocus();
947  }
948 
949  if(std::binary_search(selected.begin(), selected.end(), index)) {
950  w.SetSelected(true);
951  }
952  else {
953  w.SetSelected(false);
954  }
955  }
956 
957  void sel_prepare(W_ &w) {
958  w.ClickEvent.Register([&w, this] {
959  sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
960  });
961  w.ToggleEvent.Register([&w, this] {
962  sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w, false);
963  });
964  }
965 
966  void sel_insert(long index, long count) {
967  if(index <= focusindex)
968  focusindex += count;
969 
970  auto item = std::lower_bound(selected.begin(), selected.end(), index);
971  for(; item != selected.end(); ++item) {
972  *item += count;
973  }
974  }
975 
976  void sel_move(long index, long target) {
977  if(index == target)
978  return;
979  //move triggers apply to both indexes
980 
981  if(index == focusindex) {
982  focusindex = target;
983  }
984  else if(index > focusindex && target <= focusindex) {
985  focusindex++;
986  }
987  else if(index < focusindex && target > focusindex) {
988  focusindex--;
989  }
990 
991  if(index < target) {
992  auto from = std::lower_bound(selected.begin(), selected.end(), index);
993  auto to = std::lower_bound(selected.begin(), selected.end(), target+1);
994 
995  auto shifted = from;
996 
997  if(*from == index)
998  ++shifted;
999 
1000  while(from < to) {
1001  *from = *shifted - 1;
1002 
1003  ++from;
1004  ++shifted;
1005  }
1006 
1007  if(shifted != from) {
1008  *shifted = target;
1009  }
1010  }
1011  else {
1012  auto from = std::lower_bound(selected.begin(), selected.end(), index-1);
1013  auto to = std::upper_bound(selected.begin(), selected.end(), target);
1014 
1015  auto shifted = from;
1016 
1017  if(*from == index)
1018  --shifted;
1019 
1020  while(from > to) {
1021  *from = *shifted + 1;
1022 
1023  --from;
1024  --shifted;
1025  }
1026 
1027  if(shifted != from) {
1028  *shifted = target;
1029  }
1030  }
1031  }
1032 
1033  void sel_remove(long index, long count) {
1034  //removed items will be repurposed using apply,
1035  if(index <= focusindex) {
1036  if(index+count > focusindex) {
1037  focusindex = -1;
1038  }
1039  else {
1040  focusindex -= count;
1041  }
1042  }
1043 
1044  //move and update items that are after the point of removal
1045  auto item = std::lower_bound(selected.begin(), selected.end(), index);
1046  auto shifted = item;
1047  while(shifted != selected.end()) {
1048  if(*item < index+count) {
1049  shifted++;
1050  }
1051 
1052  *item = *shifted - count;
1053 
1054  ++shifted;
1055  ++item;
1056  }
1057 
1058  //remove the items to be removed, they are already moved to the end
1059  if(item != selected.end())
1060  selected.erase(item, selected.end());
1061  }
1062 
1063  void sel_destroy(W_ &w) {
1064  if(w.IsFocused()) {
1065  focusindex = -1;
1066  w.Defocus();
1067  }
1068  }
1069 
1070  void reapplyfocus() {
1071  if(focusindex != -1) {
1072  auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
1073  if(w)
1074  w->Focus();
1075  }
1076  }
1077 
1078  long focusindex = -1;
1079  std::vector<long> selected; //this list will be kept sorted
1080  SelectionMethod method = Toggle;
1081  EventMethod event = ForEachItem;
1082  };
1083 
1084  template<class T_, class W_, class S_, class F_>
1085  class LBSTR_STLVector {
1086  public:
1087  using Storage = S_;
1088 
1090  void Add(T_ val) {
1091  storage.push_back(val);
1092 
1093  dynamic_cast<F_*>(this)->Refresh();
1094  }
1095 
1097  template<class... A_>
1098  void Add(T_ val, A_&& ...rest) {
1099  storage.push_back(val);
1100 
1101  Add(std::forward<A_>(rest)...);
1102  }
1103 
1107  void Insert(long before, T_ val) {
1108  if(before == -1) {
1109  Add(val);
1110  return;
1111  }
1112 
1113  storage.insert(storage.begin()+before, val);
1114 
1115  dynamic_cast<F_*>(this)->sel_insert(before, 1);
1116  dynamic_cast<F_*>(this)->Refresh();
1117  }
1118 
1122  template<class... A_>
1123  void Insert(long before, T_ val, A_&& ...rest) {
1124  if(before == -1) {
1125  Add(val, rest...);
1126  return;
1127  }
1128 
1129  //TODO optimize
1130  Insert(std::forward<A_>(rest)...);
1131 
1132  storage.insert(storage.begin()+before, val);
1133  dynamic_cast<F_*>(this)->sel_insert(before, 1);
1134  }
1135 
1137  void Remove(long index) {
1138  storage.erase(storage.begin()+index);
1139 
1140  dynamic_cast<F_*>(this)->sel_remove(index, 1);
1141  dynamic_cast<F_*>(this)->Refresh();
1142  }
1143 
1147  void MoveBefore(long index, long before) {
1148  if(index==before)
1149  return;
1150 
1151  if(before >= storage.size() || before == -1) {
1152  auto t = storage[index];
1153 
1154  for(unsigned i=index; i<storage.size()-1; i++)
1155  storage[i] = storage[i+1];
1156 
1157  storage[storage.size()-1] = t;
1158  }
1159  else if(index>before) {
1160  auto t = storage[index];
1161  for(unsigned i=index; i>before; i--)
1162  storage[i] = storage[i-1];
1163 
1164  storage[before]=t;
1165  }
1166  else {
1167  auto t = storage[index];
1168  for(unsigned i=index; i<before; i++)
1169  storage[i] = storage[i+1];
1170 
1171  storage[before] = t;
1172  }
1173 
1174  dynamic_cast<F_*>(this)->sel_move(index, before);
1175  dynamic_cast<F_*>(this)->Refresh();
1176  }
1177 
1180  long Find(const T_ item, long start = 0) {
1181  auto it = std::find(storage.begin() + start, storage.end(), item);
1182  if(it == storage.end())
1183  return -1;
1184  else
1185  return it-storage.begin();
1186  }
1187 
1189  void Reserve(long amount) {
1190  storage.reserve(amount);
1191  }
1192 
1202  auto begin() {
1203  return storage.begin();
1204  }
1205 
1206  auto begin() const {
1207  return storage.begin();
1208  }
1209 
1210  auto end() {
1211  return storage.end();
1212  }
1213 
1214  auto end() const {
1215  return storage.end();
1216  }
1217 
1219 
1220  protected:
1221  LBSTR_STLVector() {}
1222  virtual ~LBSTR_STLVector() {}
1223 
1224  long getsize() const {
1225  return storage.size();
1226  }
1227 
1228  T_ &getelm(long index) {
1229  return storage[index];
1230  }
1231 
1232  const T_ &getelm(long index) const {
1233  return storage[index];
1234  }
1235 
1236  Storage storage;
1237  };
1238 
1239  template<class T_, class W_, class F_>
1240  class LBSTR_Collection {
1241  public:
1242  using Storage = Containers::Collection<T_>;
1243 
1245  void Add(T_ &val) {
1246  storage.Push(val);
1247 
1248  dynamic_cast<F_*>(this)->Refresh();
1249  }
1250 
1251  template<class... A_>
1252  T_ &AddNew(A_&& ...args) {
1253  auto &t = storage.AddNew(args...);
1254 
1255  dynamic_cast<F_*>(this)->Refresh();
1256 
1257  return t;
1258  }
1259 
1260  template<class... A_>
1261  void Add(T_ &val, A_& ...rest) {
1262  storage.Push(val);
1263 
1264  Add(std::forward<A_>(rest)...);
1265  }
1266 
1267  void Insert(long before, T_ &val) {
1268  if(storage.Insert(before, val)) {
1269  dynamic_cast<F_*>(this)->sel_insert(before, 1);
1270  dynamic_cast<F_*>(this)->Refresh();
1271  }
1272  }
1273 
1274  void Insert(const T_ &before, T_ &val) {
1275  Insert(FindLocation(before), val);
1276  }
1277 
1278  template<class... A_>
1279  T_ &InsertNew(const T_ &before, A_&& ...args) {
1280  auto &t = storage.InsertNew(FindLocation(before), args...);
1281 
1282  dynamic_cast<F_*>(this)->sel_insert(before, 1);
1283  dynamic_cast<F_*>(this)->Refresh();
1284 
1285  return t;
1286  }
1287 
1288  void Remove(long index) {
1289  storage.Remove(index);
1290 
1291  dynamic_cast<F_*>(this)->sel_remove(index, 1);
1292  dynamic_cast<F_*>(this)->Refresh();
1293  }
1294 
1295  void Remove(const T_ &item) {
1296  long index = storage.FindLocation(item);
1297  if(index == -1)
1298  return;
1299 
1300  storage.Remove(index);
1301 
1302  dynamic_cast<F_*>(this)->sel_remove(index, 1);
1303  dynamic_cast<F_*>(this)->Refresh();
1304  }
1305 
1309  void Delete(const T_ &item) {
1310  long index = storage.FindLocation(item);
1311  if(index == -1) {
1312  delete &item;
1313 
1314  return;
1315  }
1316 
1317  storage.Delete(index);
1318 
1319  dynamic_cast<F_*>(this)->sel_remove(index, 1);
1320  dynamic_cast<F_*>(this)->Refresh();
1321  }
1322 
1324  void Delete(long index) {
1325  storage.Delete(index);
1326 
1327  dynamic_cast<F_*>(this)->sel_remove(index, 1);
1328  dynamic_cast<F_*>(this)->Refresh();
1329  }
1330 
1331  void MoveBefore(long index, long before) {
1332  if(index==before)
1333  return;
1334 
1335  storage.MoveBefore(index, before);
1336 
1337  dynamic_cast<F_*>(this)->sel_move(index, before);
1338  dynamic_cast<F_*>(this)->Refresh();
1339  }
1340 
1343  long Find(const T_ &item) {
1344  return storage.FindLocation(item);
1345  }
1346 
1348  void DeleteAll() {
1349  auto s = storage.GetSize();
1350 
1351  storage.DeleteAll();
1352 
1353  dynamic_cast<F_*>(this)->sel_remove(0, s);
1354  dynamic_cast<F_*>(this)->Refresh();
1355  }
1356 
1359  void Destroy() {
1360  auto s = storage.GetSize();
1361 
1362  storage.Destroy();
1363 
1364  dynamic_cast<F_*>(this)->sel_remove(0, s);
1365  dynamic_cast<F_*>(this)->Refresh();
1366  }
1367 
1369  void Reserve(long amount) {
1370  storage.Reserve(amount);
1371  }
1372 
1382  auto begin() {
1383  return storage.begin();
1384  }
1385 
1386  auto begin() const {
1387  return storage.begin();
1388  }
1389 
1390  auto end() {
1391  return storage.end();
1392  }
1393 
1394  auto end() const {
1395  return storage.end();
1396  }
1397 
1399 
1400  protected:
1401  LBSTR_Collection() {}
1402  virtual ~LBSTR_Collection() {}
1403 
1404  long getsize() const {
1405  return storage.GetSize();
1406  }
1407 
1408  T_ &getelm(long index) {
1409  return storage[index];
1410  }
1411 
1412  const T_ &getelm(long index) const {
1413  return storage[index];
1414  }
1415 
1416  Storage storage;
1417  };
1418  }
1420 
1516  template<
1517  class T_, class W_, class TRF_,
1518  class STR_, class SELTR_,
1519  bool useisvisible,
1520  void (*TW_)(const T_ &, W_ &)
1521  >
1522  class ListboxBase :
1523  public ListBase<T_, W_>,
1524  public TRF_,
1525  public SELTR_,
1526  public STR_
1527  {
1528  public:
1529  using SelectionType = SELTR_;
1530  using TypeTraits = TRF_;
1531  using StorageType = STR_;
1532 
1536  virtual T_ &operator[](long index) override {
1537  return this->getelm(index);
1538  }
1539 
1542  virtual const T_ &operator[](long index) const override {
1543  return this->getelm(index);
1544  }
1545 
1547  virtual long GetCount() const override {
1548  return this->STR_::getsize();
1549  }
1550 
1551 
1552 
1553  protected:
1555  { }
1556  };
1557 
1558  template<
1559  class T_, class W_, class TRF_,
1560  class STR_, class SELTR_,
1561  bool useisvisible,
1562  void (*TW_)(const T_ &, W_ &)
1563  >
1565  public UI::ComponentStackWidget,
1567  {
1568  public:
1570 
1571  virtual void Refresh() override {
1572  if(!contents.IsReady())
1573  return;
1574 
1575  auto elms = this->STR_::getsize();
1576 
1577  std::map<UI::ComponentTemplate::Tag, int> tagcounts;
1578 
1579  //TODO improve performance by rolling
1580 
1581  //remove all first
1582  for(auto &p : widgetlist) {
1583  p.second->Remove();
1584  }
1585  indexes.clear();
1586  widgetlist.clear();
1587 
1588  auto b = stack.TagBounds(UI::ComponentTemplate::ViewPortTag);
1589  if(b.Width() == 0 || b.Height() == 0)
1590  b = stack.TagBounds(UI::ComponentTemplate::ContentsTag);
1591 
1592  int y = 0;
1593  long i = int(scrolloffset), c = 0;
1594  int totalh = 0;
1595  if(i < 0)
1596  i = 0;
1597  while(y < b.Height() && i < elms) {
1598  auto &v = this->getelm(i);
1599  auto tag = this->tag(i, v, {0, (int)i}, {1, (int)elms});
1600 
1601  auto w = getwidget(tag, tagcounts[tag]++);
1602 
1603  if(w == nullptr)
1604  return;
1605 
1606  TW_(v, *w);
1607 
1608  contents.Add(*w);
1609  this->apply(i, *w, v, {0, (int)i}, {1, (int)elms});
1610  this->sel_apply(i, *w, v);
1611 
1612  if(y == 0) {
1613  y = -int(std::round(w->GetHeight() * (scrolloffset - int(scrolloffset))));
1614  }
1615 
1616  indexes.insert({w, i});
1617  widgetlist.insert({i, w});
1618 
1619  w->Move(0, y);
1620 
1621  //to be moved to resize
1622  w->SetWidth(b.Width());
1623  auto advance = w->GetHeight() + stack.GetTemplate().GetSpacing() / 2;
1624  y += advance;
1625  totalh += advance;
1626  i++;
1627  c++;
1628  }
1629 
1630  if(totalh == 0)
1631  maxdisplay = 0;
1632  else
1633  maxdisplay = b.Height() / (float(totalh) / c);
1634 
1635  if(maxdisplay < elms+overscroll && !stack.HasCondition(UI::ComponentCondition::VScroll)) {
1636  stack.AddCondition(UI::ComponentCondition::VScroll);
1637  stack.Update(true);
1638  }
1639 
1640  auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
1641  if(scroller) {
1642  scroller->SetMaximum(elms + overscroll);
1643 
1644  scroller->Range = maxdisplay;
1645  scroller->LargeChange = maxdisplay * 0.8f;
1646 
1647  if(scroller->Range >= scroller->Maximum) {
1648  stack.RemoveCondition(UI::ComponentCondition::VScroll);
1649  }
1650  }
1651 
1652  contents.Displaced();
1653  }
1654 
1658  void ScrollTo(float y) {
1659  float max = this->STR_::getsize() + overscroll - maxdisplay;
1660 
1661  if(y < 0)
1662  y = 0;
1663 
1664  if(y > max)
1665  y = max;
1666 
1667  if(target == y)
1668  return;
1669 
1670  target = y;
1671 
1672  if(scrollspeed == 0) {
1673  scrolloffset = y;
1674  Refresh();
1675  }
1676  else {
1677  if(!isscrolling) {
1678  stack.SetFrameEvent(std::bind(&ListboxWidgetBase::updatescroll, this));
1679  isscrolling = true;
1680  }
1681  }
1682 
1683  auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
1684  if(scroller)
1685  *scroller = target;
1686 
1687  Refresh();
1688  }
1689 
1691  void ScrollBy(float y) {
1692  ScrollTo(ScrollOffset() + y);
1693  }
1694 
1696  float ScrollOffset() const {
1697  return scrolloffset;
1698  }
1699 
1703  void SetOverscroll(float value) {
1704  if(overscroll == value)
1705  return;
1706 
1707  overscroll = value;
1708 
1709  auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
1710  if(scroller)
1711  scroller->SetMaximum(this->STR_::getsize() + overscroll);
1712  }
1713 
1716  float GetOverscroll() const {
1717  return overscroll;
1718  }
1719 
1722  void SetScrollDistance(int vert) {
1723  scrolldist = vert;
1724  }
1725 
1727  int GetScrollDistance() const {
1728  return scrolldist;
1729  }
1730 
1733  SetSmoothScrollSpeed(0);
1734  }
1735 
1738  void SetSmoothScrollSpeed(int value) {
1739  scrollspeed = value;
1740 
1741  auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
1742  if(scroller)
1743  scroller->SetSmoothChangeSpeed(scrollspeed);
1744 
1745  auto elms = this->STR_::getsize();
1746 
1747 
1748  stack.SetValueTransitionSpeed({elms > 0 ? float(value)/elms : 0, 0, 0, 0});
1749  }
1750 
1753  int GetSmoothScrollSpeed() const {
1754  return scrollspeed;
1755  }
1756 
1758  bool IsSmoothScrollEnabled() const {
1759  return scrollspeed != 0;
1760  }
1761 
1764  return maxdisplay;
1765  }
1766 
1772  bool FitHeight(int maxpixels) {
1773  int curh = GetInteriorSize().Height;
1774  int overhead = GetHeight() - curh;
1775  int expected = int( std::ceil( (this->GetCount()+overscroll) * (curh/maxdisplay) ) ) + overhead;
1776  bool smalldone = false;
1777 
1778  //will possibly fit
1779  if(expected < maxpixels) {
1780 
1781  do {
1782  SetHeight(expected);
1783  stack.Update(true);
1784  Refresh();
1785 
1786  auto diff = maxdisplay - (this->GetCount()+overscroll);
1787 
1788  //it fits everything, might not be tightest but that's ok. We can also eat up a bit of overscroll
1789  if(diff < 1 && diff >= -overscroll/2)
1790  return true;
1791 
1792  curh = GetInteriorSize().Height;
1793  overhead = GetHeight() - curh;
1794  int curexpected = int( std::ceil( (this->GetCount()+overscroll) * (curh/maxdisplay) ) ) + overhead;
1795 
1796  if(abs(expected - curexpected) == 0) { //no progress, exit
1797  break;
1798  }
1799  else if(abs(expected - curexpected) < 0.1 && smalldone) { //we will allow one small progress, no more
1800  break;
1801  }
1802  else if(abs(expected - curexpected) < 0.1) {
1803  smalldone = true;
1804  }
1805  expected = curexpected;
1806  } while(expected < maxpixels);
1807 
1808  }
1809 
1810  SetHeight(maxpixels);
1811  return false;
1812  }
1813 
1815  auto b = stack.TagBounds(UI::ComponentTemplate::ViewPortTag);
1816  if(b.Width() == 0 || b.Height() == 0)
1817  b = stack.TagBounds(UI::ComponentTemplate::ContentsTag);
1818 
1819  return b.GetSize();
1820  }
1821 
1823 
1825  void EnsureVisible(long index) {
1826  float targetind = float(index);
1827 
1828  auto md = maxdisplay;
1829 
1830  if(targetind >= target && targetind < floor(target + md)) {
1831  return; //already visible
1832  }
1833  else if(targetind >= floor(target + md)) {
1834  targetind -= md - 1.5; //show the next item a little bit
1835  }
1836  else {
1837  targetind -= 0.5; //show the next item a little bit
1838  }
1839 
1840  auto elms = this->GetCount();
1841 
1842  if(targetind < 0)
1843  targetind = 0;
1844  if(targetind > overscroll + elms)
1845  targetind = overscroll + elms;
1846 
1847  ScrollTo(targetind);
1848 
1849  //if max display changes, call ensure visible again
1850  if(md != maxdisplay)
1851  EnsureVisible(index);
1852  }
1853 
1854  bool KeyEvent(Input::Key key, float state) override {
1855  namespace Keycodes = Input::Keyboard::Keycodes;
1856 
1857  if(repeater.KeyEvent(key, state))
1858  return true;
1859 
1860  if(key == Keycodes::Space) {
1861  if(contents.HasFocusedWidget() && state != 0) {
1862  auto w = dynamic_cast<W_*>(&contents.GetFocus());
1863  if(w) {
1864  this->sel_toggled(indexes.count(w) ? indexes[w] : -1, *w);
1865  }
1866  }
1867 
1868  return true;
1869  }
1870 
1871  return false;
1872  }
1873 
1874  protected:
1876  ComponentStackWidget(temp, {
1881  std::bind(&ListboxWidgetBase::createvscroll, this, std::placeholders::_1)
1882  }
1883  })
1884  {
1885  stack.HandleMouse();
1886 
1887  stack.SetClickEvent([&](auto, auto, auto) {
1888  Focus();
1889  });
1890 
1891  stack.SetOtherMouseEvent([this](UI::ComponentTemplate::Tag tag, Input::Mouse::EventType type, Geometry::Point, float amount) {
1892  if(type == Input::Mouse::EventType::Scroll_Vert && stack.HasCondition(UI::ComponentCondition::VScroll)) {
1893  ScrollBy(-amount*scrolldist);
1894 
1895  return true;
1896  }
1897 
1898  return false;
1899  });
1900 
1901  contents.SetLayer(stack.GetLayerOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)));
1902  stack.AddCondition(UI::ComponentCondition::VScroll);
1903 
1904  repeater.Register(Input::Keyboard::Keycodes::Up);
1905  repeater.Register(Input::Keyboard::Keycodes::Down);
1906  repeater.Register(Input::Keyboard::Keycodes::PageUp);
1907  repeater.Register(Input::Keyboard::Keycodes::PageDown);
1908 
1909 
1910  repeater.Repeat.Register([this](Input::Key key) {
1911  namespace Keycodes = Input::Keyboard::Keycodes;
1912  using Input::Keyboard::Modifier;
1913 
1914  long org = this->GetFocusIndex();
1915  long ind = org;
1916 
1917  switch(key) {
1918  case Keycodes::Down:
1919  ind++;
1920  break;
1921 
1922  case Keycodes::Up:
1923  ind--;
1924  break;
1925 
1926  case Keycodes::PageDown:
1927  ind += long(floor(maxdisplay));
1928  break;
1929 
1930  case Keycodes::PageUp:
1931  ind -= long(floor(maxdisplay));
1932  break;
1933  }
1934 
1935  if(ind < 0)
1936  ind = 0;
1937  if(ind >= this->GetCount())
1938  ind = this->GetCount() - 1;
1939 
1940  if(ind != org) {
1941  this->SetFocusIndex(ind);
1942  EnsureVisible(ind);
1943  }
1944 
1945  });
1946  }
1947 
1949  for(auto &p : widgets) {
1950  p.second.Destroy();
1951  }
1952  }
1953 
1954  //this will return the widget with the tag and the order (not index). If the requested
1955  //widget does not exists, it will be created
1957  auto temp = stack.GetTemplate(tag);
1958 
1959  if(temp == nullptr)
1960  return nullptr;
1961 
1962  auto &ws = widgets[tag];
1963 
1964  while(ws.GetSize() <= order) {
1965  auto &w = ws.AddNew(*temp);
1966  this->TRF_::prepare(w);
1967  this->sel_prepare(w);
1968  }
1969 
1970  return &ws[order];
1971  }
1972 
1973  virtual void focused() override {
1974  ComponentStackWidget::focused();
1975  this->reapplyfocus();
1976  }
1977 
1978  virtual void focuslost() override {
1979  ComponentStackWidget::focuslost();
1980  contents.RemoveFocus();
1981  }
1982 
1984  auto vscroller = new VScroller<float>(temp);
1985  vscroller->Maximum = this->STR_::getsize();
1986  vscroller->Range = 1;
1987  *vscroller = scrolloffset;
1988  vscroller->SmallChange = scrolldist;
1989  vscroller->ValueChanged.Register(*this, &ListboxWidgetBase::ScrollTo);
1990 
1991  return vscroller;
1992  }
1993 
1994  void updatescroll() {
1995  if(!isscrolling)
1996  Utils::ASSERT_FALSE("This should not happen");
1997 
1998  auto cur = scrolloffset;
1999 
2000  float dist = (float)scrollspeed/1000 * Time::DeltaTime();
2001 
2002  bool done = false;
2003 
2004  if(target < cur) {
2005  if(cur - dist <= target) {
2006  cur = target;
2007  }
2008  else {
2009  cur -= dist;
2010  }
2011  }
2012  else if(target > cur) {
2013  if(cur + dist >= target) {
2014  cur = target;
2015  }
2016  else {
2017  cur += dist;
2018  }
2019  }
2020  else {
2021  done = true;
2022  }
2023 
2024  scrolloffset = cur;
2025 
2026  Refresh();
2027 
2028  if(done) {
2029  isscrolling = false;
2030  stack.RemoveFrameEvent();
2031  }
2032  }
2033 
2039  virtual W_ *getrepresentation(long index) override {
2040  return widgetlist.count(index) ? widgetlist[index] : nullptr;
2041  }
2042 
2047  virtual W_ *getrepresentation() override {
2048  return nullptr;
2049  }
2050 
2051  virtual long getindex(const W_ &widget) override {
2052  return indexes.count(&widget) ? indexes[&widget] : -1;
2053  }
2054 
2055  virtual void boundschanged() override {
2056  Refresh();
2057  }
2058 
2059  std::map<UI::ComponentTemplate::Tag, Containers::Collection<W_>> widgets;
2060  std::map<const W_*, long> indexes;
2061  std::map<long, W_*> widgetlist;
2063  float scrolloffset = 0.f;
2064  float target = 0.f;
2065  float overscroll = 1;
2066  int scrollspeed = 20;
2067  int scrolldist = 5;
2068  bool isscrolling = false;
2069  float maxdisplay = 0; //maximum elements that can be displayed
2070 
2072  };
2073 
2079  template<class T_, void (*TW_)(const T_ &, ListItem &) = internal::SetTextUsingFrom<T_, ListItem>>
2080  class SimpleListbox :
2081  public ListboxWidgetBase<T_, ListItem,
2082  internal::LBTRF_ListItem<T_, ListItem, SimpleListbox<T_, TW_>>,
2083  internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_, TW_>>,
2084  internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_, TW_>>,
2085  false, TW_
2086  >
2087  {
2088  using Base = ListboxWidgetBase<T_, ListItem,
2089  internal::LBTRF_ListItem<T_, ListItem, SimpleListbox<T_, TW_>>,
2090  internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_, TW_>>,
2091  internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_, TW_>>,
2092  false, TW_
2093  >;
2094 
2095  friend internal::LBTRF_ListItem<T_, ListItem, SimpleListbox<T_, TW_>>;
2096  friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_, TW_>>;
2097  friend internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_, TW_>>;
2098 
2099  public:
2101  }
2102 
2103  explicit SimpleListbox(const UI::Template &temp) : Base(temp) {
2104  }
2105 
2106  virtual bool Activate() {
2107  return false;
2108  }
2109 
2110  SimpleListbox &operator =(const T_ value) {
2111  this->SetSelection(value);
2112 
2113  return *this;
2114  }
2115 
2117  using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>::Remove;
2118  };
2119 
2130  template<class T_, void (*TW_)(const T_ &, ListItem &) = internal::SetTextUsingFrom<T_, ListItem>>
2131  class MultiListbox :
2132  public ListboxWidgetBase<T_, ListItem,
2133  internal::LBTRF_ListItem<T_, ListItem, MultiListbox<T_, TW_>>,
2134  internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_, TW_>>,
2135  internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_, TW_>>,
2136  false, TW_
2137  >
2138  {
2139  using Base = ListboxWidgetBase<T_, ListItem,
2140  internal::LBTRF_ListItem<T_, ListItem, MultiListbox<T_, TW_>>,
2141  internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_, TW_>>,
2142  internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_, TW_>>,
2143  false, TW_
2144  >;
2145 
2146  friend internal::LBTRF_ListItem<T_, ListItem, MultiListbox<T_, TW_>>;
2147  friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_, TW_>>;
2148  friend internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_, TW_>>;
2149 
2150  public:
2152  }
2153 
2154  explicit MultiListbox(const UI::Template &temp) : Base(temp) {
2155  }
2156 
2157  virtual bool Activate() {
2158  return false;
2159  }
2160 
2161  MultiListbox &operator =(const T_ value) {
2162  this->SetSelection(value);
2163 
2164  return *this;
2165  }
2166 
2168  using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>::Remove;
2169  };
2170 
2176  template<class T_, void (*TW_)(const T_ &, ListItem &) = internal::SetTextUsingFrom<T_, ListItem>>
2178  public ListboxWidgetBase<T_, ListItem,
2179  internal::LBTRF_ListItem<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2180  internal::LBSTR_Collection<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2181  internal::LBSELTR_Single<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2182  false, TW_
2183  >
2184  {
2185  using Base = ListboxWidgetBase<T_, ListItem,
2186  internal::LBTRF_ListItem<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2187  internal::LBSTR_Collection<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2188  internal::LBSELTR_Single<T_, ListItem, SimpleCollectionbox<T_, TW_>>,
2189  false, TW_
2190  >;
2191 
2192  friend internal::LBTRF_ListItem<T_, ListItem, SimpleCollectionbox<T_, TW_>>;
2193  friend internal::LBSTR_Collection<T_, ListItem, SimpleCollectionbox<T_, TW_>>;
2194  friend internal::LBSELTR_Single<T_, ListItem, SimpleCollectionbox<T_, TW_>>;
2195 
2196  public:
2198  }
2199 
2200  explicit SimpleCollectionbox(const UI::Template &temp) : Base(temp) {
2201  }
2202 
2203  virtual bool Activate() {
2204  return false;
2205  }
2206 
2207  SimpleCollectionbox &operator =(const T_ value) {
2208  this->SetSelection(value);
2209 
2210  return *this;
2211  }
2212 
2214  using internal::LBSTR_Collection<T_, ListItem, SimpleCollectionbox<T_>>::Remove;
2215  };
2216 
2227  template<class T_, void (*TW_)(const T_ &, ListItem &) = internal::SetTextUsingFrom<T_, ListItem>>
2229  public ListboxWidgetBase<T_, ListItem,
2230  internal::LBTRF_ListItem<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2231  internal::LBSTR_Collection<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2232  internal::LBSELTR_Multi<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2233  false, TW_
2234  >
2235  {
2236  using Base = ListboxWidgetBase<T_, ListItem,
2237  internal::LBTRF_ListItem<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2238  internal::LBSTR_Collection<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2239  internal::LBSELTR_Multi<T_, ListItem, MultiCollectionbox<T_, TW_>>,
2240  false, TW_
2241  >;
2242 
2243  friend internal::LBTRF_ListItem<T_, ListItem, MultiCollectionbox<T_, TW_>>;
2244  friend internal::LBSTR_Collection<T_, ListItem, MultiCollectionbox<T_, TW_>>;
2245  friend internal::LBSELTR_Multi<T_, ListItem, MultiCollectionbox<T_, TW_>>;
2246 
2247  public:
2249  }
2250 
2251  explicit MultiCollectionbox(const UI::Template &temp) : Base(temp) {
2252  }
2253 
2254  virtual bool Activate() {
2255  return false;
2256  }
2257 
2258  MultiCollectionbox &operator =(const T_ value) {
2259  this->SetSelection(value);
2260 
2261  return *this;
2262  }
2263 
2265  using internal::LBSTR_Collection<T_, ListItem, MultiCollectionbox<T_>>::Remove;
2266  };
2267 
2268 } }
2269 
Gorgon::Widgets::MultiListbox::MultiListbox
MultiListbox(Registry::TemplateType temp=Registry::Listbox_Regular)
Definition: Listbox.h:2151
Gorgon::Widgets::SimpleCollectionbox
This is a simple collectionbox.
Definition: Listbox.h:2184
Gorgon::Widgets::ListboxWidgetBase::focuslost
virtual void focuslost() override
This is called after the focus is lost.
Definition: Listbox.h:1978
Gorgon::Widgets::ListBase::~ListBase
virtual ~ListBase()
Definition: Listbox.h:22
Gorgon::swap
void swap(Event< Source_, Args_... > &l, Event< Source_, Args_... > &r)
Swaps two events.
Definition: Event.h:351
Gorgon::Widgets::Scrollbar::SetMaximum
void SetMaximum(const T_ &value)
Sets the maximum value that this slider reaches up to.
Definition: Slider.h:138
Gorgon::Containers::Remove
void Remove(const I_ &first, const I_ &end)
This function works with collection iterators.
Definition: Iterator.h:386
Gorgon::Widgets::ListboxWidgetBase::repeater
Input::KeyRepeater repeater
Definition: Listbox.h:2071
Gorgon::Widgets::MultiCollectionbox::MultiCollectionbox
MultiCollectionbox(const UI::Template &temp)
Definition: Listbox.h:2251
Gorgon::String::From
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::string >::type From(const T_ &e)
Definition: Enum.h:303
Gorgon::Widgets::ListboxBase< T_, ListItem, internal::LBTRF_ListItem< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSTR_STLVector< T_, ListItem, std::vector< T_ >, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSELTR_Single< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, useisvisible, TW_ >::StorageType
internal::LBSTR_STLVector< T_, ListItem, std::vector< T_ >, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > > StorageType
Definition: Listbox.h:1531
Gorgon::UI::ComponentTemplate::HeaderTag
@ HeaderTag
Definition: Template.h:877
Gorgon::Widgets::ListboxWidgetBase::KeyEvent
bool KeyEvent(Input::Key key, float state) override
This function should be called whenever a key is pressed or released.
Definition: Listbox.h:1854
Gorgon::Widgets::MultiListbox::Activate
virtual bool Activate()
Activates the widget.
Definition: Listbox.h:2157
Gorgon::UI::ComponentTemplate::ContentsTag
@ ContentsTag
Definition: Template.h:872
Gorgon::Widgets::ListboxWidgetBase::Refresh
virtual void Refresh() override
This function should refresh the contents of the listbox.
Definition: Listbox.h:1571
Gorgon::Widgets::ListBase::operator[]
virtual T_ & operator[](long index)=0
Returns the item at the given point.
Gorgon::Widgets::ListboxBase::operator[]
virtual T_ & operator[](long index) override
Returns the item at the given point.
Definition: Listbox.h:1536
Gorgon::Input::Keyboard::Keycodes::Space
constexpr Key Space
Definition: Keyboard.h:59
Gorgon::Widgets::Registry::Listbox_Regular
@ Listbox_Regular
Definition: Registry.h:47
Gorgon::Widgets::ListboxWidgetBase::DisableSmoothScroll
void DisableSmoothScroll()
Disables smooth scrolling of the panel.
Definition: Listbox.h:1732
Gorgon::Widgets::ListboxWidgetBase::ScrollOffset
float ScrollOffset() const
Returns the current scroll offset.
Definition: Listbox.h:1696
Gorgon::Widgets::ListboxWidgetBase::ListboxWidgetBase
ListboxWidgetBase(const UI::Template &temp)
Definition: Listbox.h:1875
Gorgon::Widgets::ListItem
This widget is designed to be used by Listbox, Table, Grid and Treeview.
Definition: ListItem.h:33
Gorgon::Widgets::ListboxWidgetBase::getwidget
W_ * getwidget(UI::ComponentTemplate::Tag tag, int order)
Definition: Listbox.h:1956
Gorgon::Widgets::ListboxWidgetBase::GetOverscroll
float GetOverscroll() const
Returns the amount of extra scrolling distance after the bottom-most widget is completely visible in ...
Definition: Listbox.h:1716
Gorgon::Input::Keyboard::CurrentModifier
Modifier CurrentModifier
Current keyboard modifier, this is a global value.
Definition: Input.cpp:7
Gorgon::UI::Template
This class stores visual information about a widget template.
Definition: Template.h:392
Common.h
Gorgon::Widgets::Scrollbar
This widget is a scrollbar.
Definition: Scrollbar.h:25
Gorgon::Widgets::ListboxBase::ListboxBase
ListboxBase()
Definition: Listbox.h:1554
Gorgon::Widgets::ListboxWidgetBase::SetScrollDistance
void SetScrollDistance(int vert)
Sets the horizontal scroll distance per click in pixels.
Definition: Listbox.h:1722
Gorgon::Widgets::MultiCollectionbox::operator=
MultiCollectionbox & operator=(const T_ value)
Definition: Listbox.h:2258
Gorgon::Widgets::ListboxBase::operator[]
virtual const T_ & operator[](long index) const override
Returns the item at the given point.
Definition: Listbox.h:1542
Gorgon::begin
std::vector< T_ >::const_iterator begin(enum_type_id< T_ >)
Definition: Enum.h:283
Gorgon::Widgets::MultiListbox::MultiListbox
MultiListbox(const UI::Template &temp)
Definition: Listbox.h:2154
Gorgon::Widgets::ListboxWidgetBase::GetSmoothScrollSpeed
int GetSmoothScrollSpeed() const
Returns the smooth scrolling speed of the panel.
Definition: Listbox.h:1753
Gorgon::UI::ComponentTemplate::SpacerTag
@ SpacerTag
Definition: Template.h:878
Gorgon::UI::Odd
@ Odd
In lists denotes the item is in odd position.
Definition: Template.h:227
Gorgon::Widgets::ListboxWidgetBase::focused
virtual void focused() override
This is called after the focus is transferred to this widget.
Definition: Listbox.h:1973
Gorgon::Widgets::ListBase::getrepresentation
virtual W_ * getrepresentation(long index)=0
For internal use.
Gorgon::Widgets::ListboxWidgetBase::SetSmoothScrollSpeed
void SetSmoothScrollSpeed(int value)
Adjusts the smooth scrolling speed of the panel.
Definition: Listbox.h:1738
Gorgon::Geometry::Size
basic_Size< int > Size
Definition: Size.h:385
Gorgon::Time::DeltaTime
unsigned long DeltaTime()
Returns the time passed since the last frame.
Definition: Time.h:258
Gorgon::Widgets::MultiCollectionbox::Activate
virtual bool Activate()
Activates the widget.
Definition: Listbox.h:2254
Gorgon::Utils::ASSERT_FALSE
void ASSERT_FALSE(const std::string &message, int skip=1, int depth=4)
Definition: Assert.h:192
Gorgon::Widgets::ListboxBase< T_, ListItem, internal::LBTRF_ListItem< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSTR_STLVector< T_, ListItem, std::vector< T_ >, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSELTR_Single< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, useisvisible, TW_ >::SelectionType
internal::LBSELTR_Single< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > > SelectionType
Definition: Listbox.h:1529
Gorgon::Widgets::Registry::TemplateType
TemplateType
This enum lists all possible template types.
Definition: Registry.h:18
ListItem.h
Gorgon::Input::Keyboard::Keycodes::PageUp
constexpr Key PageUp
Definition: Keyboard.h:44
Gorgon::Input::Key
int Key
A type to represent an input key.
Definition: Input.h:14
Gorgon::Widgets::ListBase::Refresh
virtual void Refresh()=0
This function should refresh the contents of the listbox.
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
Gorgon::Geometry::basic_Size
This class represents a 2D geometric size.
Definition: Size.h:23
Gorgon::UI::LayerAdapter
This class turns a layer into a widget container.
Definition: LayerAdapter.h:12
Gorgon::Input::Mouse::Scroll_Vert
@ Scroll_Vert
Definition: Mouse.h:24
Gorgon::Widgets::ListBase
This is the abstract base of listboxes.
Definition: Listbox.h:20
Gorgon::Input::Keyboard::Keycodes::Up
constexpr Key Up
Definition: Keyboard.h:63
Gorgon::Input::Keyboard::Modifier::Ctrl
@ Ctrl
Only control modifier is pressed.
Definition: Keyboard.h:176
Gorgon::Widgets::SimpleCollectionbox::Activate
virtual bool Activate()
Activates the widget.
Definition: Listbox.h:2203
Gorgon::UI::ComponentTemplate::ViewPortTag
@ ViewPortTag
Definition: Template.h:873
Gorgon::UI::ComponentTemplate::VScrollTag
@ VScrollTag
Definition: Template.h:857
Gorgon::UI::VScroll
@ VScroll
There is space vertically to be scrolled.
Definition: Template.h:251
Gorgon::Widgets::SimpleCollectionbox::operator=
SimpleCollectionbox & operator=(const T_ value)
Definition: Listbox.h:2207
Gorgon::Geometry::Point
basic_Point< int > Point
Definition: Point.h:598
Gorgon::Widgets::SimpleListbox
This is a simple listbox.
Definition: Listbox.h:2087
Gorgon::Widgets::ListboxWidgetBase::getrepresentation
virtual W_ * getrepresentation(long index) override
For internal use.
Definition: Listbox.h:2039
Gorgon::Widgets::ListboxBase::GetCount
virtual long GetCount() const override
Returns the number of elements in the list.
Definition: Listbox.h:1547
Gorgon::Widgets::ListboxBase
This is the base class for all listbox like widgets.
Definition: Listbox.h:1527
Gorgon::UI::Widget::Remove
bool Remove()
Removes the widget from its parent.
Definition: Widget.cpp:6
Gorgon::Widgets::SimpleCollectionbox::SimpleCollectionbox
SimpleCollectionbox(Registry::TemplateType temp=Registry::Listbox_Regular)
Definition: Listbox.h:2197
Gorgon::Widgets::ListboxWidgetBase::updatescroll
void updatescroll()
Definition: Listbox.h:1994
Gorgon::Containers::Find
I_ Find(const I_ &first, const I_ &end, const T_ &item)
This function works with collection iterators.
Definition: Iterator.h:403
Gorgon::Widgets::ListboxWidgetBase::widgetlist
std::map< long, W_ * > widgetlist
Definition: Listbox.h:2061
Gorgon::Widgets::ListboxWidgetBase::contents
UI::LayerAdapter contents
Definition: Listbox.h:2062
Gorgon::Widgets::ListboxWidgetBase::SetOverscroll
void SetOverscroll(float value)
Sets the amount of extra scrolling distance after the bottom-most widget is completely visible in pix...
Definition: Listbox.h:1703
Gorgon::Widgets::SimpleListbox::Activate
virtual bool Activate()
Activates the widget.
Definition: Listbox.h:2106
Gorgon::UI::Widget::EnsureVisible
bool EnsureVisible() const
Ensures this widget is visible in its container by scrolling it into view.
Definition: Widget.cpp:55
Gorgon::Widgets::ListboxWidgetBase::~ListboxWidgetBase
~ListboxWidgetBase()
Definition: Listbox.h:1948
Gorgon::Widgets::ListboxWidgetBase::getrepresentation
virtual W_ * getrepresentation() override
For internal use.
Definition: Listbox.h:2047
Gorgon::Widgets::ListboxWidgetBase::FitHeight
bool FitHeight(int maxpixels)
This function will try to set the height of the listbox to contain all its elements.
Definition: Listbox.h:1772
Gorgon::Widgets::ListBase::operator[]
virtual const T_ & operator[](long index) const =0
Returns the item at the given point.
Gorgon::Widgets::ListboxWidgetBase::GetInteriorSize
Geometry::Size GetInteriorSize() const
Definition: Listbox.h:1814
Gorgon::Input::Keyboard::Keycodes::Delete
constexpr Key Delete
Definition: Keyboard.h:43
Gorgon::Widgets::ListboxWidgetBase::getindex
virtual long getindex(const W_ &widget) override
For internal use.
Definition: Listbox.h:2051
Gorgon::Geometry::basic_Point
This class represents a 2D point.
Definition: Point.h:32
Gorgon::Widgets::ListboxWidgetBase
Definition: Listbox.h:1567
Gorgon::Widgets::ListBase::GetCount
virtual long GetCount() const =0
Returns the number of elements in the list.
Gorgon::Widgets::MultiCollectionbox::MultiCollectionbox
MultiCollectionbox(Registry::TemplateType temp=Registry::Listbox_Regular)
Definition: Listbox.h:2248
Registry.h
Gorgon::Widgets::ListboxWidgetBase::ScrollBy
void ScrollBy(float y)
Scrolls the contents an additional amount of items.
Definition: Listbox.h:1691
Gorgon::Widgets::SimpleListbox::operator=
SimpleListbox & operator=(const T_ value)
Definition: Listbox.h:2110
Gorgon::Input::Mouse::EventType
EventType
The type of a mouse event.
Definition: Mouse.h:14
Gorgon::UI::Active
@ Active
This is for widgets that can be activated, like a count down timer.
Definition: Template.h:245
Gorgon::Animation::Storage
basic_Storage< const Provider > Storage
Basic animation storage, can store all types of animation and can be moved around as a value.
Definition: Storage.h:170
Gorgon::Widgets::Scrollbar::SetSmoothChangeSpeed
void SetSmoothChangeSpeed(T_ value)
Adjusts the smooth change speed.
Definition: Slider.h:272
Gorgon::Widgets::ListboxWidgetBase::ScrollTo
void ScrollTo(float y)
Scrolls the contents of the listbox so that the it will start displaying items from the given locatio...
Definition: Listbox.h:1658
Gorgon::Widgets::MultiListbox
This is a simple multi select listbox.
Definition: Listbox.h:2138
Gorgon::Widgets::ListboxWidgetBase::createvscroll
UI::Widget * createvscroll(const UI::Template &temp)
Definition: Listbox.h:1983
Gorgon::Input::KeyRepeater
This class simplifies the use of repeated keystrokes when a key is pressed.
Definition: KeyRepeater.h:54
Gorgon::Widgets::SimpleListbox::SimpleListbox
SimpleListbox(Registry::TemplateType temp=Registry::Listbox_Regular)
Definition: Listbox.h:2100
Gorgon::UI::ComponentTemplate::ItemTag
@ ItemTag
Definition: Template.h:876
Gorgon::end
std::vector< T_ >::const_iterator end(enum_type_id< T_ >)
Definition: Enum.h:288
Gorgon::Widgets::MultiListbox::operator=
MultiListbox & operator=(const T_ value)
Definition: Listbox.h:2161
Gorgon::Widgets::ListBase::getrepresentation
virtual W_ * getrepresentation()=0
For internal use.
Gorgon::Widgets::ListBase::getindex
virtual long getindex(const W_ &widget)=0
For internal use.
Gorgon::Widgets::ListboxWidgetBase::IsSmoothScrollEnabled
bool IsSmoothScrollEnabled() const
Returns if the smooth scroll is enabled.
Definition: Listbox.h:1758
Gorgon::Widgets::ListboxWidgetBase::indexes
std::map< const W_ *, long > indexes
Definition: Listbox.h:2060
Gorgon::Parity::None
@ None
Gorgon::Input::Keyboard::Keycodes::PageDown
constexpr Key PageDown
Definition: Keyboard.h:45
Gorgon::Widgets::ListboxWidgetBase::GetMaximumDisplayedElements
float GetMaximumDisplayedElements() const
This may not be a perfect number.
Definition: Listbox.h:1763
Gorgon::UI::ComponentStackWidget
This class acts as a widget base that uses component stack to handle rendering, resizing and other op...
Definition: ComponentStackWidget.h:14
Scrollbar.h
Gorgon::Widgets::ListboxWidgetBase::boundschanged
virtual void boundschanged() override
Call this function when the widget bounds is changed.
Definition: Listbox.h:2055
Gorgon::Widgets::MultiCollectionbox
This is a simple multi select collectionbox.
Definition: Listbox.h:2235
Gorgon::UI::ComponentTemplate::Tag
Tag
Tags mark a component to be modified in a way meaningful to specific widgets.
Definition: Template.h:850
Gorgon::Widgets::ListboxWidgetBase::GetScrollDistance
int GetScrollDistance() const
Returns the scroll distance per click.
Definition: Listbox.h:1727
Gorgon::Widgets::SimpleListbox::SimpleListbox
SimpleListbox(const UI::Template &temp)
Definition: Listbox.h:2103
Gorgon::Input::Keyboard::Keycodes::Insert
constexpr Key Insert
Definition: Keyboard.h:42
Gorgon::Widgets::ListboxBase< T_, ListItem, internal::LBTRF_ListItem< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSTR_STLVector< T_, ListItem, std::vector< T_ >, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, internal::LBSELTR_Single< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > >, useisvisible, TW_ >::TypeTraits
internal::LBTRF_ListItem< T_, ListItem, SimpleListbox< T_, internal::SetTextUsingFrom< T_, ListItem > > > TypeTraits
Definition: Listbox.h:1530
Gorgon::Widgets::Registry
This class stores templates for elements.
Definition: Registry.h:12
Gorgon::Widgets::SimpleCollectionbox::SimpleCollectionbox
SimpleCollectionbox(const UI::Template &temp)
Definition: Listbox.h:2200
Gorgon::Widgets::ListboxWidgetBase::EnsureVisible
void EnsureVisible(long index)
Ensures the given index is completely visible on the screen.
Definition: Listbox.h:1825
Gorgon::UI::Widget
This class is the base for all widgets.
Definition: Widget.h:16
Gorgon::Input::Keyboard::Keycodes::Down
constexpr Key Down
Definition: Keyboard.h:65
Gorgon::Widgets::ListboxWidgetBase::widgets
std::map< UI::ComponentTemplate::Tag, Containers::Collection< W_ > > widgets
Definition: Listbox.h:2059