#139: EnsureVisible 4.x-dev

Fri, 30 Oct 2020 20:44:22 +0200

author
cemkalyoncu
date
Fri, 30 Oct 2020 20:44:22 +0200
branch
4.x-dev
changeset 1475
e829b6db7a5d
parent 1474
5ed81f9f7516
child 1476
e9317f02166d

#139: EnsureVisible

Source/Gorgon/Widgets/Listbox.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Generate.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Widgets/Listbox.h	Fri Oct 30 13:43:20 2020 +0200
+++ b/Source/Gorgon/Widgets/Listbox.h	Fri Oct 30 20:44:22 2020 +0200
@@ -1,466 +1,466 @@
-#pragma once
-
-
-#include "Common.h"
-#include "../UI/ComponentStackWidget.h"
-#include "../Property.h"
-#include "Registry.h"
-#include "ListItem.h"
-#include <vector>
-#include "Scrollbar.h"
-
-namespace Gorgon { namespace Widgets {
-    
-    /**
-     * This is the abstract base of listboxes. It is mainly used to allow list
-     * mixins to access list items.
-     */
-    template<class T_, class W_>
-    class ListBase {
-    public:
-        virtual ~ListBase() {
-        }
-        
-        /// Returns the item at the given point. This operator will not perform
-        /// bounds checking.
-        virtual T_ &operator[](long index) = 0;
-
-        /// Returns the item at the given point. This operator will not perform
-        /// bounds checking.
-        virtual const T_ &operator[](long index) const = 0;
-        
-        /// Returns the number of elements in the list.
-        virtual long GetCount() const = 0;
-        
-        /// For internal use.
-        /// Returns the first widget used to represent any item at within the 
-        /// listbox. This function will return nullptr if there are no items in the
-        /// list.
-        virtual long getindex(const W_ &widget) = 0;
-        
-        /// This function should refresh the contents of the listbox. Normally, 
-        /// calling this function is not necessary as it is handled internally.
-        /// This function may defer refresh to next frame.
-        virtual void Refresh() = 0;
-        
-    protected:
-
-        /// For internal use.
-        /// Returns the widget used to represent the item at the given index. This
-        /// function will return nullptr if the index does not currently have a
-        /// visual representation. This is not an edge case, any item that is not
-        /// in view will most likely not have a representation.
-        virtual W_ *getrepresentation(long index) = 0;
-        
-        /// For internal use.
-        /// Returns the first widget used to represent any item at within the 
-        /// listbox. This function will return nullptr if there are no items in the
-        /// list.
-        virtual W_ *getrepresentation() = 0;
-        
-    };
-    
-    /// @cond internal
-    namespace internal {
-        // blank traits has no data associated with the items.
-        // It is good for very long lists. Should be used with
-        // useisvisible = false.
-        template<class T_, class W_>
-        class LBTR_blank {
-        public:
-            void Apply(W_ &, const T_ &, Geometry::Point, Geometry::Size) { }
-            
-            UI::ComponentTemplate::Tag Tag(const T_ &, Geometry::Point, Geometry::Size) {
-                return UI::ComponentTemplate::ItemTag;
-            }
-        };
-        
-        template <class T_, class W_, class F_>
-        class LBTRF_blank {
-            using TR_ = LBTR_blank<T_, W_>;
-        protected:
-            LBTRF_blank() { }
-            ~LBTRF_blank() { }
-            
-            TR_ access(long) {
-                return TR_();
-            }
-            
-            void prepare(W_ &) { }
-            void insert(long, long) { }
-            void move(long, long) { }
-            void remove(long, long) { }
-        };
-        
-        template<class T_, class W_>
-        void SetTextUsingFrom(const T_ &val, W_ &w) {
-            w.SetText(String::From(val));
-        }
-        
-        template<class T_, class W_>
-        void GetTextUsingTo(W_ &w, T_ &val) {
-            val = String::To<T_>(w.GetText());
-        }
-        
-        //This class allows single selection. The selected item will
-        //follow the focus by default. If desired, this can be changed
-        template<class T_, class W_, class F_>
-        class LBSELTR_Single {
-        public:
-            /// Returns true if this listbox has a selected item.
-            bool HasSelectedItem() const {
-                return selectedindex != -1;
-            }
-            
-            /// Returns the selected item. If nothing is selected this function
-            /// will throw. You may check if there is a selection using 
-            /// HasSelectedItem function.
-            T_ GetSelectedItem() const {
-                if(selectedindex == -1)
-                    throw std::runtime_error("Nothing is selected.");
-                
-                return dynamic_cast<const F_&>(*this)[selectedindex];
-            }
-            
-            /// Returns the index of the selected item. -1 will be returned if 
-            /// nothing is selected.
-            long GetSelectedIndex() const {
-                return selectedindex;
-            }
-            
-            /// Sets the selection to the given index. If index in not within the
-            /// bounds this function will throw std::out_of_range exception. -1
-            /// can be used to remove selected item.
-            void SetSelectedIndex(long index) {
-                if(index < -1 || index >= dynamic_cast<F_&>(*this).GetCount())
-                    throw std::out_of_range("Selected index does not exits");
-                
-                if(index == selectedindex)
-                    return;
-                
-                if(focusonly) {
-                    if(index == -1) {
-                        W_ *elm = dynamic_cast<F_&>(*this).getrepresentation();
-                        if(elm != nullptr && elm->HasParent()) {
-                            elm->GetParent().RemoveFocus();
-                        }
-                    }
-                    else {
-                        W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
-                        if(elm != nullptr) {
-                            elm->Focus();
-                        }
-                        else {
-                            elm = dynamic_cast<F_&>(*this).getrepresentation();
-                            
-                            if(elm != nullptr && elm->HasParent()) {
-                                elm->GetParent().RemoveFocus();
-                            }
-                        }
-                    }
-                    
-                    focusindex = index;
-                }
-                
-                if(selected)
-                    selected->SetSelected(false);
-                
-                if(index != -1) {
-                    W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
-                    
-                    if(elm)
-                        elm->SetSelected(true);
-                }
-                
-                selectedindex = index;
-                ChangedEvent(selectedindex);
-            }
-            
-            void RemoveSelection() {
-                SetSelectedIndex(-1);
-            }
-            
-            /// Selects the first item that has the given value. If item does
-            /// not exists, this function will remove the selection
-            void SetSelection(T_ item) {
-                auto &me = dynamic_cast<F_&>(*this);
-                
-                for(long i=0; i<me.GetSize(); i++) {
-                    if(me[i] == item) {
-                        SetSelectedIndex(i);
-                        return;
-                    }
-                }
-                
-                SetSelectedIndex(-1);
-            }
-            
-            /// Returns true if the selected item is the focused item. Default
-            /// is true. When set to false, an item can be focused without being
-            /// selected. A listbox with radio buttons should have this value
-            /// set to false.
-            bool IsSelectionFollowingFocus() const {
-                return focusonly;
-            }
-            
-            /// Sets whether the selected item is the focused item. Default
-            /// is true. When set to false, an item can be focused without being
-            /// selected. A listbox with radio buttons should have this value
-            /// set to false.
-            void SetSelectionFollowsFocus(bool value) {
-                if(!focusonly && value) {
-                    if(focusindex != -1) {
-                        if(selectedindex != focusindex) {
-                            selectedindex = focusindex;
-                            ChangedEvent(selectedindex);
-                        }
-                    }
-                    else {
-                        focusindex = selectedindex;
-                    }
-                }
-                
-                focusonly = value;
-            }
-            
-            operator T_() {
-                return GetSelectedItem();
-            }
-            
-            operator T_() const {
-                return GetSelectedItem();
-            }
-            
-            Event<LBSELTR_Single, long> ChangedEvent = Event<LBSELTR_Single, long>{this};
-            
-        protected:
-            LBSELTR_Single() {
-            }
-            
-            virtual ~LBSELTR_Single() { }
-            
-            void sel_clicked(long index, W_ &w) {
-                if(focusonly) {
-                    if(selectedindex == index)
-                        return;
-                    
-                    if(selected)
-                        selected->SetSelected(false);
-                    
-                    w.SetSelected(true);
-                    
-                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
-                        w.Focus();
-                    
-                    selected = &w;
-                    selectedindex = index;
-                    focusindex    = index;
-                    
-                    ChangedEvent(index);
-                }
-                else {
-                    if(focusindex == index)
-                        return;
-                    
-                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
-                        w.Focus();
-                    
-                    focusindex = index;
-                }
-                
-                dynamic_cast<UI::Widget*>(this)->Focus();
-            }
-            
-            void sel_toggled(long index, W_ &w) {
-                if(selectedindex == index || focusonly)
-                    return;
-                
-                if(selected)
-                    selected->SetSelected(false);
-                
-                w.SetSelected(true);
-                selectedindex = index;
-                selected = &w;
-                
-                if(focusonly) {
-                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
-                        w.Focus();
-                    
-                    focusindex = index;
-                }
-                
-                ChangedEvent(index);
-            }
-            
-            void sel_apply(long index, W_ &w, const T_ &) {
-                if(index == focusindex) {
-                    w.Focus();
-                }
-                else if(w.IsFocused()) {
-                    w.Defocus();
-                }
-                
-                if(index == selectedindex) {
-                    w.SetSelected(true);
-                    selected = &w;
-                }
-                else {
-                    w.SetSelected(false);
-                    
-                    if(&w == selected)
-                        selected = nullptr;
-                }
-            }
-            
-            void sel_prepare(W_ &w) {
-                w.ClickEvent.Register([&w, this] {
-                    sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
-                });
-                w.ToggleEvent.Register([&w, this] {
-                    sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w);
-                });
-            }
-            
-            void sel_insert(long index, long count) { 
-                if(index <= focusindex)
-                    focusindex += count;
-                
-                if(index <= selectedindex)
-                    selectedindex += count;
-            }
-            
-            void sel_move(long index, long target) { 
-                //move triggers apply to both indexes
-                
-                if(index == focusindex) {
-                    focusindex = target;
-                }
-                else if(index > focusindex && target <= focusindex) {
-                    focusindex++;
-                }
-                else if(index < focusindex && target > focusindex) {
-                    focusindex--;
-                }
-                
-                if(index == selectedindex) {
-                    selectedindex = target;
-                }
-                else if(index > selectedindex && target <= selectedindex) {
-                    selectedindex++;
-                }
-                else if(index < selectedindex && target > selectedindex) {
-                    selectedindex--;
-                }
-            }
-            
-            void sel_remove(long index, long count) { 
-                //removed items will be repurposed using apply,
-                if(index <= focusindex) {
-                    if(index+count > focusindex) {
-                        focusindex = -1;
-                        ChangedEvent(-1);
-                    }
-                    else {
-                        focusindex -= count;
-                    }
-                }
-                
-                if(index <= selectedindex) {
-                    if(index+count > selectedindex) {
-                        selectedindex = -1;
-                        ChangedEvent(-1);
-                    }
-                    else {
-                        selectedindex -= count;
-                    }
-                }
-            }
-            
-            void sel_destroy(W_ &w) {
-                if(&w == selected) {
-                    selected = nullptr;
-                }
-                if(w.IsFocused()) {
-                    focusindex = -1;
-                    w.Defocus();
-                }
-            }
-            
-            void reapplyfocus() {
-                if(focusindex != -1) {
-                    auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
-                    if(w)
-                        w->Focus();
-                }
-            }
-            
-            bool focusonly = true;
-            
-            long focusindex = -1, selectedindex = -1;
-            
-            W_ *selected = nullptr;
-        };
-        
-        //This class allows single selection. The selected item will
-        //follow the focus by default. If desired, this can be changed
-        template<class T_, class W_, class F_>
-        class LBSELTR_Multi {
-            template <class F1_> friend class ItemIterator_;
-            friend class SelectionHelper;
-
-            class SelectionIndexHelper {
-            public:
-                SelectionIndexHelper(const std::vector<long> &v) : v(v) {
-                }
-                
-                auto begin() {
-                    return v.begin();
-                }
-                
-                auto end() {
-                    return v.end();
-                }
-                
-            private:
-                const std::vector<long> &v;
-            };
-
-            class SelectionHelper {
-            public:
-                SelectionHelper(LBSELTR_Multi &l) : l(l) {
-                }
-
-                auto begin() {
-                    auto &me = dynamic_cast<F_ &>(l);
-                    return ItemIterator(me, l.selected, 0);
-                }
-
-                auto end() {
-                    auto &me = dynamic_cast<F_ &>(l);
-                    return ItemIterator(me, l.selected, l.selected.size());
-                }
-
-                auto begin() const {
-                    auto &me = dynamic_cast<F_ &>(l);
-                    return ConstItemIterator(me, l.selected, 0);
-                }
-
-                auto end() const {
-                    auto &me = dynamic_cast<F_ &>(l);
-                    return ConstItemIterator(me, l.selected, l.selected.size());
-                }
-
-            private:
-                LBSELTR_Multi &l;
-            };
-
-
-            template <class O_, class F1_>
-            class ItemIterator_ : public Containers::Iterator<ItemIterator_<O_, F1_>, O_> {
-                friend class SelectionHelper;
-                friend class ConstItemIterator;
-                friend class Containers::Iterator<ItemIterator_<O_, F1_>, O_>;
-            public:
+#pragma once
+
+
+#include "Common.h"
+#include "../UI/ComponentStackWidget.h"
+#include "../Property.h"
+#include "Registry.h"
+#include "ListItem.h"
+#include <vector>
+#include "Scrollbar.h"
+
+namespace Gorgon { namespace Widgets {
+    
+    /**
+     * This is the abstract base of listboxes. It is mainly used to allow list
+     * mixins to access list items.
+     */
+    template<class T_, class W_>
+    class ListBase {
+    public:
+        virtual ~ListBase() {
+        }
+        
+        /// Returns the item at the given point. This operator will not perform
+        /// bounds checking.
+        virtual T_ &operator[](long index) = 0;
+
+        /// Returns the item at the given point. This operator will not perform
+        /// bounds checking.
+        virtual const T_ &operator[](long index) const = 0;
+        
+        /// Returns the number of elements in the list.
+        virtual long GetCount() const = 0;
+        
+        /// For internal use.
+        /// Returns the first widget used to represent any item at within the 
+        /// listbox. This function will return nullptr if there are no items in the
+        /// list.
+        virtual long getindex(const W_ &widget) = 0;
+        
+        /// This function should refresh the contents of the listbox. Normally, 
+        /// calling this function is not necessary as it is handled internally.
+        /// This function may defer refresh to next frame.
+        virtual void Refresh() = 0;
+        
+    protected:
+
+        /// For internal use.
+        /// Returns the widget used to represent the item at the given index. This
+        /// function will return nullptr if the index does not currently have a
+        /// visual representation. This is not an edge case, any item that is not
+        /// in view will most likely not have a representation.
+        virtual W_ *getrepresentation(long index) = 0;
+        
+        /// For internal use.
+        /// Returns the first widget used to represent any item at within the 
+        /// listbox. This function will return nullptr if there are no items in the
+        /// list.
+        virtual W_ *getrepresentation() = 0;
+        
+    };
+    
+    /// @cond internal
+    namespace internal {
+        // blank traits has no data associated with the items.
+        // It is good for very long lists. Should be used with
+        // useisvisible = false.
+        template<class T_, class W_>
+        class LBTR_blank {
+        public:
+            void Apply(W_ &, const T_ &, Geometry::Point, Geometry::Size) { }
+            
+            UI::ComponentTemplate::Tag Tag(const T_ &, Geometry::Point, Geometry::Size) {
+                return UI::ComponentTemplate::ItemTag;
+            }
+        };
+        
+        template <class T_, class W_, class F_>
+        class LBTRF_blank {
+            using TR_ = LBTR_blank<T_, W_>;
+        protected:
+            LBTRF_blank() { }
+            ~LBTRF_blank() { }
+            
+            TR_ access(long) {
+                return TR_();
+            }
+            
+            void prepare(W_ &) { }
+            void insert(long, long) { }
+            void move(long, long) { }
+            void remove(long, long) { }
+        };
+        
+        template<class T_, class W_>
+        void SetTextUsingFrom(const T_ &val, W_ &w) {
+            w.SetText(String::From(val));
+        }
+        
+        template<class T_, class W_>
+        void GetTextUsingTo(W_ &w, T_ &val) {
+            val = String::To<T_>(w.GetText());
+        }
+        
+        //This class allows single selection. The selected item will
+        //follow the focus by default. If desired, this can be changed
+        template<class T_, class W_, class F_>
+        class LBSELTR_Single {
+        public:
+            /// Returns true if this listbox has a selected item.
+            bool HasSelectedItem() const {
+                return selectedindex != -1;
+            }
+            
+            /// Returns the selected item. If nothing is selected this function
+            /// will throw. You may check if there is a selection using 
+            /// HasSelectedItem function.
+            T_ GetSelectedItem() const {
+                if(selectedindex == -1)
+                    throw std::runtime_error("Nothing is selected.");
+                
+                return dynamic_cast<const F_&>(*this)[selectedindex];
+            }
+            
+            /// Returns the index of the selected item. -1 will be returned if 
+            /// nothing is selected.
+            long GetSelectedIndex() const {
+                return selectedindex;
+            }
+            
+            /// Sets the selection to the given index. If index in not within the
+            /// bounds this function will throw std::out_of_range exception. -1
+            /// can be used to remove selected item.
+            void SetSelectedIndex(long index) {
+                if(index < -1 || index >= dynamic_cast<F_&>(*this).GetCount())
+                    throw std::out_of_range("Selected index does not exits");
+                
+                if(index == selectedindex)
+                    return;
+                
+                if(focusonly) {
+                    if(index == -1) {
+                        W_ *elm = dynamic_cast<F_&>(*this).getrepresentation();
+                        if(elm != nullptr && elm->HasParent()) {
+                            elm->GetParent().RemoveFocus();
+                        }
+                    }
+                    else {
+                        W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
+                        if(elm != nullptr) {
+                            elm->Focus();
+                        }
+                        else {
+                            elm = dynamic_cast<F_&>(*this).getrepresentation();
+                            
+                            if(elm != nullptr && elm->HasParent()) {
+                                elm->GetParent().RemoveFocus();
+                            }
+                        }
+                    }
+                    
+                    focusindex = index;
+                }
+                
+                if(selected)
+                    selected->SetSelected(false);
+                
+                if(index != -1) {
+                    W_ *elm = dynamic_cast<F_&>(*this).getrepresentation(index);
+                    
+                    if(elm)
+                        elm->SetSelected(true);
+                }
+                
+                selectedindex = index;
+                ChangedEvent(selectedindex);
+            }
+            
+            void RemoveSelection() {
+                SetSelectedIndex(-1);
+            }
+            
+            /// Selects the first item that has the given value. If item does
+            /// not exists, this function will remove the selection
+            void SetSelection(T_ item) {
+                auto &me = dynamic_cast<F_&>(*this);
+                
+                for(long i=0; i<me.GetSize(); i++) {
+                    if(me[i] == item) {
+                        SetSelectedIndex(i);
+                        return;
+                    }
+                }
+                
+                SetSelectedIndex(-1);
+            }
+            
+            /// Returns true if the selected item is the focused item. Default
+            /// is true. When set to false, an item can be focused without being
+            /// selected. A listbox with radio buttons should have this value
+            /// set to false.
+            bool IsSelectionFollowingFocus() const {
+                return focusonly;
+            }
+            
+            /// Sets whether the selected item is the focused item. Default
+            /// is true. When set to false, an item can be focused without being
+            /// selected. A listbox with radio buttons should have this value
+            /// set to false.
+            void SetSelectionFollowsFocus(bool value) {
+                if(!focusonly && value) {
+                    if(focusindex != -1) {
+                        if(selectedindex != focusindex) {
+                            selectedindex = focusindex;
+                            ChangedEvent(selectedindex);
+                        }
+                    }
+                    else {
+                        focusindex = selectedindex;
+                    }
+                }
+                
+                focusonly = value;
+            }
+            
+            operator T_() {
+                return GetSelectedItem();
+            }
+            
+            operator T_() const {
+                return GetSelectedItem();
+            }
+            
+            Event<LBSELTR_Single, long> ChangedEvent = Event<LBSELTR_Single, long>{this};
+            
+        protected:
+            LBSELTR_Single() {
+            }
+            
+            virtual ~LBSELTR_Single() { }
+            
+            void sel_clicked(long index, W_ &w) {
+                if(focusonly) {
+                    if(selectedindex == index)
+                        return;
+                    
+                    if(selected)
+                        selected->SetSelected(false);
+                    
+                    w.SetSelected(true);
+                    
+                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
+                        w.Focus();
+                    
+                    selected = &w;
+                    selectedindex = index;
+                    focusindex    = index;
+                    
+                    ChangedEvent(index);
+                }
+                else {
+                    if(focusindex == index)
+                        return;
+                    
+                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
+                        w.Focus();
+                    
+                    focusindex = index;
+                }
+                
+                dynamic_cast<UI::Widget*>(this)->Focus();
+            }
+            
+            void sel_toggled(long index, W_ &w) {
+                if(selectedindex == index || focusonly)
+                    return;
+                
+                if(selected)
+                    selected->SetSelected(false);
+                
+                w.SetSelected(true);
+                selectedindex = index;
+                selected = &w;
+                
+                if(focusonly) {
+                    if(dynamic_cast<UI::Widget*>(this)->IsFocused())
+                        w.Focus();
+                    
+                    focusindex = index;
+                }
+                
+                ChangedEvent(index);
+            }
+            
+            void sel_apply(long index, W_ &w, const T_ &) {
+                if(index == focusindex) {
+                    w.Focus();
+                }
+                else if(w.IsFocused()) {
+                    w.Defocus();
+                }
+                
+                if(index == selectedindex) {
+                    w.SetSelected(true);
+                    selected = &w;
+                }
+                else {
+                    w.SetSelected(false);
+                    
+                    if(&w == selected)
+                        selected = nullptr;
+                }
+            }
+            
+            void sel_prepare(W_ &w) {
+                w.ClickEvent.Register([&w, this] {
+                    sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
+                });
+                w.ToggleEvent.Register([&w, this] {
+                    sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w);
+                });
+            }
+            
+            void sel_insert(long index, long count) { 
+                if(index <= focusindex)
+                    focusindex += count;
+                
+                if(index <= selectedindex)
+                    selectedindex += count;
+            }
+            
+            void sel_move(long index, long target) { 
+                //move triggers apply to both indexes
+                
+                if(index == focusindex) {
+                    focusindex = target;
+                }
+                else if(index > focusindex && target <= focusindex) {
+                    focusindex++;
+                }
+                else if(index < focusindex && target > focusindex) {
+                    focusindex--;
+                }
+                
+                if(index == selectedindex) {
+                    selectedindex = target;
+                }
+                else if(index > selectedindex && target <= selectedindex) {
+                    selectedindex++;
+                }
+                else if(index < selectedindex && target > selectedindex) {
+                    selectedindex--;
+                }
+            }
+            
+            void sel_remove(long index, long count) { 
+                //removed items will be repurposed using apply,
+                if(index <= focusindex) {
+                    if(index+count > focusindex) {
+                        focusindex = -1;
+                        ChangedEvent(-1);
+                    }
+                    else {
+                        focusindex -= count;
+                    }
+                }
+                
+                if(index <= selectedindex) {
+                    if(index+count > selectedindex) {
+                        selectedindex = -1;
+                        ChangedEvent(-1);
+                    }
+                    else {
+                        selectedindex -= count;
+                    }
+                }
+            }
+            
+            void sel_destroy(W_ &w) {
+                if(&w == selected) {
+                    selected = nullptr;
+                }
+                if(w.IsFocused()) {
+                    focusindex = -1;
+                    w.Defocus();
+                }
+            }
+            
+            void reapplyfocus() {
+                if(focusindex != -1) {
+                    auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
+                    if(w)
+                        w->Focus();
+                }
+            }
+            
+            bool focusonly = true;
+            
+            long focusindex = -1, selectedindex = -1;
+            
+            W_ *selected = nullptr;
+        };
+        
+        //This class allows single selection. The selected item will
+        //follow the focus by default. If desired, this can be changed
+        template<class T_, class W_, class F_>
+        class LBSELTR_Multi {
+            template <class F1_> friend class ItemIterator_;
+            friend class SelectionHelper;
+
+            class SelectionIndexHelper {
+            public:
+                SelectionIndexHelper(const std::vector<long> &v) : v(v) {
+                }
+                
+                auto begin() {
+                    return v.begin();
+                }
+                
+                auto end() {
+                    return v.end();
+                }
+                
+            private:
+                const std::vector<long> &v;
+            };
+
+            class SelectionHelper {
+            public:
+                SelectionHelper(LBSELTR_Multi &l) : l(l) {
+                }
+
+                auto begin() {
+                    auto &me = dynamic_cast<F_ &>(l);
+                    return ItemIterator(me, l.selected, 0);
+                }
+
+                auto end() {
+                    auto &me = dynamic_cast<F_ &>(l);
+                    return ItemIterator(me, l.selected, l.selected.size());
+                }
+
+                auto begin() const {
+                    auto &me = dynamic_cast<F_ &>(l);
+                    return ConstItemIterator(me, l.selected, 0);
+                }
+
+                auto end() const {
+                    auto &me = dynamic_cast<F_ &>(l);
+                    return ConstItemIterator(me, l.selected, l.selected.size());
+                }
+
+            private:
+                LBSELTR_Multi &l;
+            };
+
+
+            template <class O_, class F1_>
+            class ItemIterator_ : public Containers::Iterator<ItemIterator_<O_, F1_>, O_> {
+                friend class SelectionHelper;
+                friend class ConstItemIterator;
+                friend class Containers::Iterator<ItemIterator_<O_, F1_>, O_>;
+            public:
                 /// Default constructor, creates an iterator pointing to invalid location
                 ItemIterator_(): list(NULL), offset(-1) {
                 }
@@ -470,8 +470,8 @@
 
             protected:
                 ItemIterator_(F1_ &list, const std::vector<long> &inds, long offset = 0): list(&list), inds(&inds), offset(offset) {
-                }
-
+                }
+
                 /// Satisfies the needs of Iterator
                 O_ &current() const {
                     if(!isvalid())
@@ -510,19 +510,19 @@
                 bool isbefore(const ItemIterator_ &it) const {
                     return offset<it.offset;
                 }
-
-                F1_ *list = nullptr;
-                long offset = 0;
-                const std::vector<long> *inds = nullptr;
-            };
-        public:
+
+                F1_ *list = nullptr;
+                long offset = 0;
+                const std::vector<long> *inds = nullptr;
+            };
+        public:
             /// Regular iterator. @see Container::Iterator
             typedef ItemIterator_<T_, F_> ItemIterator;
 
             /// Const iterator allows iteration of const collections
             class ConstItemIterator : public ItemIterator_<const T_, const F_> {
                 friend class SelectionHelper;
-                friend class Containers::Iterator<ItemIterator_<const T_, const F_>, T_>;
+                friend class Containers::Iterator<ItemIterator_<const T_, const F_>, T_>;
 
             public:
                 ///Regular iterators can be converted to const iterators
@@ -535,1122 +535,1157 @@
                 ConstItemIterator(const F_ &c, const std::vector<long> &inds, long offset = 0): ItemIterator_<const T_, const F_>(c, inds, offset) {
                 }
             };
-
-            enum SelectionMethod {
-                /// Clicking on the item will toggle its selected state
-                Toggle,
-
+
+            enum SelectionMethod {
+                /// Clicking on the item will toggle its selected state
+                Toggle,
+
                 /// Clicking on the item will set the selection to be
-                /// that item only. Ctrl clicking toggles
-                UseCtrl,
-            };
-            
-            enum EventMethod {
-                /// Event will be fired only once per action
-                Once,
-                
-                /// Even will be fired per changed item
-                ForEachItem
-            };
-            
-            /// Changes selection method. Default method is toggle. In toggle
-            /// method, clicking on an item will toggle its state without
-            /// effecting other items. In UseCtrl method, if an item is clicked
-            /// with Ctrl key pressed, it will be toggled. If Ctrl is not pressed,
-            /// it will become the only selected item. 
-            void SetSelectionMethod(SelectionMethod value) {
-                method = value;
-            }
-            
-            /// Returns the selection method.
-            SelectionMethod GetSelectionMethod() const {
-                return method;
-            }
-            
-            /// Changes event method. Default method is ForEachItem. In ForEachItem
-            /// method, ChangedEvent will be fired for each item that is affected.
-            /// index and status parameters will be set. If event method is set to
-            /// Once, ChangedEvent will be fired once per action. index and status
-            /// parameter will be set only if one item is affected. Otherwise,
-            /// index will be set to -1 and status is set to false.
-            void SetEventMethod(EventMethod value) {
-                event = value;
-            }
-            
-            /// Returns the event method.
-            EventMethod GetEventMethod() const {
-                return event;
-            }
-            
-            /// Removes all items from the selection
-            void ClearSelection() {
-                if(event == Once) {
-                    selected.clear();
-                    ChangedEvent(-1, false);
-                }
-                else {
-                    std::vector<long> old;
-                    std::swap(old, selected);
-                    
-                    for(auto ind : old) {
-                        ChangedEvent(ind, false);
-                    }
-                }
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            /// Replaces the selection by the given index
-            void SetSelection(long ind) {
-                SetSelection(std::vector<long>{ind});
-            };
-            
-            /// Replaces the selection by the given indices
-            void SetSelection(std::vector<long> indices) {
-                if(event == ForEachItem)
-                    ClearSelection();
-                
-                selected = std::move(indices);
-                std::sort(selected.begin(), selected.end());
-                
-                //ensure nothing is duplicated
-                selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
-                
-                if(event == ForEachItem) {
-                    for(auto ind : selected) {
-                        ChangedEvent(ind, true);
-                    }
-                }
-                else {
-                    ChangedEvent(-1, false);
-                }
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            };
-            
-            /// Replaces the selection by the given indices
-            template<class ...P_>
-            void SetSelection(P_&&... elms) {
-                SetSelection({elms...});
-            }
-            
-            /// Adds the given index to the selection
-            void AddToSelection(long ind) {
-                AddToSelection(std::vector<long>{ind});
-            };
-            
-            /// Adds the given indices to the selection
-            void AddToSelection(std::vector<long> indices) {
-                std::sort(indices.begin(), indices.end());
-                
-                selected.resize(selected.size() + indices.size());
-                auto sel = selected.rbegin();
-                auto cur = selected.rbegin() + indices.size();
-                auto ind = indices.rbegin();
-                
-                while(ind != indices.rend()) {
-                    if(cur == selected.rend() || *cur < *ind) {
-                        *sel = *ind;
-                        
-                        if(event == ForEachItem)
-                            ChangedEvent(*ind, true);
-                        
-                        ++ind;
-                    }
-                    else {
-                        *sel = *cur;
-                        ++cur;
-                    }
-                    ++sel;
-                }
-                
-                //ensure nothing is duplicated
-                selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
-                
-                if(event == Once) {
-                    ChangedEvent(-1, false);
-                }
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            };
-            
-            /// Adds the given indices to the selection
-            template<class ...P_>
-            void AddToSelection(P_&&... elms) {
-                AddToSelection({elms...});
-            }
-            
-            /// Returns if the item in the given index is selected.
-            bool IsSelected(long index) const {
-                return std::binary_search(selected.begin(), selected.end(), index);
-            }
-            
-            /// Returns how many items are selected
-            long GetSelectionCount() const {
-                return long(selected.size());
-            }
-            
-            /// Removes the given index from the selection
-            void RemoveFromSelection(long index) {
-                auto item = std::lower_bound(selected.begin(), selected.end(), index);
-                
-                if(item != selected.end() && *item == index) {
-                    selected.erase(item);
-                    ChangedEvent(index, false);
-                }
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            /// Selects all items
-            void SelectAll() {
-                auto elms = dynamic_cast<F_*>(this)->GetCount();
-                
-                std::vector<long> old;
-                old.reserve(elms);
-                
-                std::swap(old, selected);
-                
-                auto sel = old.begin();
-                for(int i=0; i<elms; i++) {
-                    if(sel != old.end() && *sel == i)
-                        ++sel;
-                    else if(event == ForEachItem)
-                        ChangedEvent(i, true);
-                        
-                    selected.push_back(i);
-                }
-                
-                if(event == Once)
-                    ChangedEvent(-1, false);
-                
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            /// Inverts the selection.
-            void InvertSelection() {
-                std::vector<long> old;
-                
-                auto elms = dynamic_cast<F_*>(this)->GetCount();
-                old.reserve(elms-selected.size());
-                
-                std::swap(selected, old);
-                
-                auto sel = old.begin();
-                for(int i=0; i<elms; i++) {
-                    if(sel != old.end() && *sel == i) {
-                        ++sel;
-                        
-                        if(event == ForEachItem)
-                            ChangedEvent(i, false);
-                    }
-                    else {
-                        selected.push_back(i);
-                        
-                        if(event == ForEachItem)
-                            ChangedEvent(i, true);
-                    }
-                }
-                
-                if(event == Once)
-                    ChangedEvent(-1, false);
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            /*
-            Selection -> subclass allows for(auto item : list.Selection)
-            */
-            SelectionIndexHelper SelectedIndices;
-            SelectionHelper Selection;
-            
-            Event<LBSELTR_Multi, long, bool> ChangedEvent = Event<LBSELTR_Multi, long, bool>{this};
-            
-        protected:
-            LBSELTR_Multi() : 
-                SelectedIndices(selected),
-                Selection(*this)
-            {
-            }
-            
-            virtual ~LBSELTR_Multi() { }
-            
-            void sel_clicked(long index, W_ &w) {
-                if(focusindex == index)
-                    return;
-                
-                if(dynamic_cast<UI::Widget*>(this)->IsFocused())
-                    w.Focus();
-                
-                focusindex = index;
-                
-                dynamic_cast<UI::Widget*>(this)->Focus();
-            }
-            
-            void sel_toggled(long index, W_ &w) {
-                if(method == Toggle) {
-                    auto item = std::lower_bound(selected.begin(), selected.end(), index);
-                    
-                    if(item != selected.end() && *item == index) {
-                        w.SetSelected(false);
-                        selected.erase(item);
-                        
-                        ChangedEvent(index, false);
-                    }
-                    else {
-                        w.SetSelected(true);
-                        selected.insert(item, index);
-                        
-                        ChangedEvent(index, true);
-                    }
-                }
-                else {
-                    if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::Ctrl) {
-                        auto item = std::lower_bound(selected.begin(), selected.end(), index);
-                        
-                        if(item != selected.end() && *item == index) {
-                            w.SetSelected(false);
-                            selected.erase(item);
-                            
-                            ChangedEvent(index, false);
-                        }
-                        else {
-                            w.SetSelected(true);
-                            selected.insert(item, index);
-                            
-                            ChangedEvent(index, true);
-                        }
-                    }
-                    else {
-                        SetSelection(index);
-                    }
-                }
-            }
-            
-            void sel_apply(long index, W_ &w, const T_ &) {
-                if(index == focusindex) {
-                    w.Focus();
-                }
-                else if(w.IsFocused()) {
-                    w.Defocus();
-                }
-                
-                if(std::binary_search(selected.begin(), selected.end(), index)) {
-                    w.SetSelected(true);
-                }
-                else {
-                    w.SetSelected(false);
-                }
-            }
-            
-            void sel_prepare(W_ &w) {
-                w.ClickEvent.Register([&w, this] {
-                    sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
-                });
-                w.ToggleEvent.Register([&w, this] {
-                    sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w);
-                });
-            }
-            
-            void sel_insert(long index, long count) { 
-                if(index <= focusindex)
-                    focusindex += count;
-                
-                auto item = std::lower_bound(selected.begin(), selected.end(), index);
-                for(; item != selected.end(); ++item) {
-                    *item += count;
-                }
-            }
-            
-            void sel_move(long index, long target) { 
-                if(index == target) 
-                    return;
-                //move triggers apply to both indexes
-                
-                if(index == focusindex) {
-                    focusindex = target;
-                }
-                else if(index > focusindex && target <= focusindex) {
-                    focusindex++;
-                }
-                else if(index < focusindex && target > focusindex) {
-                    focusindex--;
-                }
-                
-                if(index < target) {
-                    auto from = std::lower_bound(selected.begin(), selected.end(), index);
-                    auto to = std::lower_bound(selected.begin(), selected.end(), target+1);
-                
-                    auto shifted = from;
-                    
-                    if(*from == index)
-                        ++shifted;
-                    
-                    while(from < to) {
-                        *from = *shifted - 1;
-                        
-                        ++from;
-                        ++shifted;
-                    }
-                    
-                    if(shifted != from) {
-                        *shifted = target;
-                    }
-                }
-                else {
-                    auto from = std::lower_bound(selected.begin(), selected.end(), index-1);
-                    auto to = std::upper_bound(selected.begin(), selected.end(), target);
-                
-                    auto shifted = from;
-                    
-                    if(*from == index)
-                        --shifted;
-                    
-                    while(from > to) {
-                        *from = *shifted + 1;
-                        
-                        --from;
-                        --shifted;
-                    }
-                    
-                    if(shifted != from) {
-                        *shifted = target;
-                    }
-                }
-            }
-            
-            void sel_remove(long index, long count) { 
-                //removed items will be repurposed using apply,
-                if(index <= focusindex) {
-                    if(index+count > focusindex) {
-                        focusindex = -1;
-                    }
-                    else {
-                        focusindex -= count;
-                    }
-                }
-                
-                //move and update items that are after the point of removal
-                auto item = std::lower_bound(selected.begin(), selected.end(), index);
-                auto shifted = item;
-                while(shifted != selected.end()) {
-                    if(*item < index+count) {
-                        shifted++;
-                    }
-                    
-                    *item = *shifted - count;
-                    
-                    ++shifted;
-                    ++item;
-                }
-                
-                //remove the items to be removed, they are already moved to the end
-                if(item != selected.end())
-                    selected.erase(item, selected.end());
-            }
-            
-            void sel_destroy(W_ &w) {
-                if(w.IsFocused()) {
-                    focusindex = -1;
-                    w.Defocus();
-                }
-            }
-            
-            void reapplyfocus() {
-                if(focusindex != -1) {
-                    auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
-                    if(w)
-                        w->Focus();
-                }
-            }
-            
-            long focusindex = -1;
-            std::vector<long> selected; //this list will be kept sorted
-            SelectionMethod method = Toggle;
-            EventMethod event      = ForEachItem;
-        };
-        
-        template<class T_, class W_, class S_, class F_>
-        class LBSTR_STLVector {
-        public:
-            using Storage = S_;
-            
-            void Add(T_ val) {
-                storage.push_back(val);
-                
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            template<class... A_>
-            void Add(T_ val, A_&& ...rest) {
-                storage.push_back(val);
-                
-                Add(std::forward<A_>(rest)...);
-            }
-            
-            void Insert(long before, T_ val) {
-                storage.insert(storage.begin()+before, val);
-                
-                dynamic_cast<F_*>(this)->sel_insert(before, 1);
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            template<class... A_>
-            void Insert(long before, T_ val, A_&& ...rest) {
-                //TODO optimize
-                Insert(std::forward<A_>(rest)...);
-                
-                storage.insert(storage.begin()+before, val);
-                dynamic_cast<F_*>(this)->sel_insert(before, 1);
-            }
-            
-            void Remove(long index) {
-                storage.erase(storage.begin()+index);
-                
-                dynamic_cast<F_*>(this)->sel_remove(index, 1);
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            void MoveBefore(long index, long before) {
-                if(index==before)
-                    return;
-
-                if(index>before) {
-                    auto t = storage[index];
-                    for(unsigned i=index; i>before; i--)
-                        storage[i] = storage[i-1];
-
-                    storage[before]=t;
-                }
-                else if(before==storage.size()) {
-                    auto t = storage[index];
-
-                    for(unsigned i=index; i<storage.size()-1; i++)
-                        storage[i] = storage[i+1];
-
-                    storage[storage.size()-1] = t;
-                }
-                else {
-                    auto t = storage[index];
-                    for(unsigned i=index; i<before; i++)
-                        storage[i] = storage[i+1];
-
-                    storage[before] = t;
-                }
-                
-                dynamic_cast<F_*>(this)->sel_move(index, before);
-                dynamic_cast<F_*>(this)->Refresh();
-            }
-            
-            /// Return the index of the first item that has the given value.
-            /// Returns -1 if item not found.
-            long Find(const T_ item, long start = 0) {
-                auto it = std::find(storage.begin() + start, storage.end(), item);
-                if(it == storage.end())
-                    return -1;
-                else
-                    return it-storage.begin();
-            }
-            
-            /**
-             * @name Iteration 
-             * 
-             * These functions allow iteration of the listbox. If 
-             * the contents are changed through these functions, 
-             * you must call Refresh manually.
-             * 
-             * @{
-             */
-            auto begin() {
-                return storage.begin();
-            }
-            
-            auto begin() const {
-                return storage.begin();
-            }
-            
-            auto end() {
-                return storage.end();
-            }
-            
-            auto end() const {
-                return storage.end();
-            }
-            
-            /// @}
-        
-        protected:
-            LBSTR_STLVector() {}
-            virtual ~LBSTR_STLVector() {}
-            
-            long getsize() const {
-                return storage.size();
-            }
-            
-            T_ &getelm(long index) {
-                return storage[index];
-            }
-            
-            const T_ &getelm(long index) const {
-                return storage[index];
-            }
-            
-            Storage storage;
-        };
-    }
-    /// @endcond
-    
-    /**
-     * This is the base class for all listbox like widgets. It is not intended
-     * to be used directly but you may use it to create your own listboxes. The
-     * solid listboxes should be derived from this object and should make 
-     * desired functionality public.
-     * 
-     * Listbox will maintain the necessary number widgets to fill its area. It
-     * does not create widgets for elements falling outside the range. If traits
-     * can return different tags, the widgets to cover its area will be created
-     * separately for these tags. 
-     * 
-     * Listbox has multi-column functionality. However, this is not to be used
-     * for tables. Table systems should insert rows as listbox items, which then
-     * should have cells.
-     * 
-     * *Template parameters*
-     * 
-     * T_ is the stored data type. 
-     * 
-     * W_ is the widget that will be used to represent items.
-     * 
-     * TR_ is widget traits class that allows additional properties for each
-     * element. They should contain minimal number of data members. There should
-     * be a function Apply taking `W_ &`, `const T_ &`, Point index, Size total
-     * as parameters applying traits to W_. Additionally, TR_ should have Tag
-     * function that has `const T_ &`, Point index, Size total as parameters and
-     * should return UI::ComponentTemplate::Tag to determine the template for
-     * the widget. The tags should match with the listbox template. If the given
-     * tag is not found, ItemTag will be used.
-     * 
-     * TRF_ is the trait functions that will return/set the traits of items. 
-     * TRF_ should contain access function that should take the index of an item
-     * to return TR_ associated with it.
-     * It should contain `insert(before, count)` to add count elements before
-     * the given index. These elements must be default initialized to a normal
-     * state. 
-     * `move(index, before)` should move the indexed item before the given 
-     * index. 
-     * `remove(index, count)` should remove count number of items 
-     * starting from the given index. 
-     * `prepare(W_ &)` function should prepare the given widget for the first
-     * usage. This is only called once on a newly created widget.
-     * `destroy(W_ &)` function is called when a widget is about to be 
-     * destroyed.
-     * Index parameters should be long int. These functions should be protected
-     * as ListboxBase will be derived from TRF_. Finally, TRF_ should have a 
-     * protected constructor/destructor.
-     * 
-     * STR_ is the storage traits for T_. This class should contain typedef
-     * Storage which is the storage. It should have functions that allows it
-     * to handle Add/Remove/Insert/Move/getsize/getelm functions. Only 
-     * getsize and getelm functions are mandatory. getelm should take a long
-     * index and should return the stored value. GetSize should return long.
-     * Additionally, this function should have a protected storage member
-     * named storage. After every modifying operation, this function should
-     * call Refresh. Ideally, this class should contain 
-     * 
-     * useisvisible controls if elements can be hidden. If this is true, TR_
-     * should have IsVisible function returning bool. This parameter will
-     * slowdown listbox considerably when many items are stored as each item
-     * will be checked whether they are visible until to the point of display.
-     * This will not affect the performance on short lists.
-     * 
-     * SELTR_ is the class that will control selection traits of the Listbox.
-     * Defult traits allow single select. It is possible to construct list of 
-     * particular widgets that has no concept of selection if selection traits
-     * is set to internal::LBSELTR_None.
-     * This class should support sel_click and sel_toggle functions both taking
-     * long index, const T_ & value, W_ &widget. Click function will be called 
-     * when the user uses arrow keys to select an item. It is this classes 
-     * responsibility to handle actual click and toggle functions.
-     * apply function should apply selection related traits to the widget taking
-     * long index, W_ &widget, const T_ & value. Any item that is benched will
-     * be applied to as well with an index of -1.
-     * This class should contain `insert(before, count)` to add count elements
-     * before the given index. These elements must be default initialized to a
-     * non-selected normal state. 
-     * `sel_move(index, before)` should move the indexed item before the given 
-     * index. 
-     * `sel_remove(index, count)` should remove count number of items 
-     * starting from the given index. 
-     * `sel_prepare(W_ &)` function should prepare the given widget for the first
-     * usage. This is only called once on a newly created widget.
-     * `sel_destroy(W_ &)` function is called when a widget is about to be 
-     * destroyed.
-     * Index parameters should be long int. These functions should be protected
-     * as ListboxBase will be derived from SELTR_. Finally, SELTR_ should have a 
-     * protected constructor/destructor.
-     * reapplyfocus function should apply the focus to the focused element. This
-     * function is called after listbox receives focus.
-     * 
-     * TW_ function should take a T_ and set this to its W_ representation. 
-     * 
-     * WT_ should read the data from W_ and set it to T_.
-     */
-    template<
-        class T_, class W_, class TR_, class TRF_, 
-        class STR_, class SELTR_, 
-        bool useisvisible = false,
-        void (*TW_)(const T_ &, W_ &) = internal::SetTextUsingFrom<T_, W_>,
-        void (*WT_)(W_ &, T_ &)       = internal::GetTextUsingTo  <T_, W_>
-    >
-    class ListboxBase : public UI::ComponentStackWidget, 
-                        public ListBase<T_, W_>, 
-                        public TRF_, 
-                        public SELTR_, public STR_ 
-    {
-    public:
-        
-        /// Returns the item at the given point. This operator will not perform
-        /// bounds checking.
-        virtual T_ &operator[](long index) override {
-            return this->getelm(index);
-        }
-
-        /// Returns the item at the given point. This operator will not perform
-        /// bounds checking.
-        virtual const T_ &operator[](long index) const override {
-            return this->getelm(index);
-        }
-        
-        /// Returns the number of elements in the list.
-        virtual long GetCount() const override {
-            return this->STR_::getsize();
-        }
-        
-        virtual void Refresh() override {
-            if(!contents.IsReady())
-                return;
-
-            auto elms = this->STR_::getsize();
-            
-            std::map<UI::ComponentTemplate::Tag, int> tagcounts;
-            
-            //TODO improve performance by rolling
-            
-            //remove all first
-            for(auto &p : widgetlist) {
-                p.second->Remove();
-            }
-            indexes.clear();
-            widgetlist.clear();
-            
-            auto b = stack.TagBounds(UI::ComponentTemplate::ViewPortTag);
-            if(b.Width() == 0 || b.Height() == 0)
-                b = stack.TagBounds(UI::ComponentTemplate::ContentsTag);
-            
-            int y = 0;
-            long i = int(scrolloffset), c = 0;
-            int totalh = 0;
-            if(i < 0)
-                i = 0;
-            while(y < b.Height() && i < elms) {
-                auto &v   = this->getelm(i);
-                auto  tr  = this->access(i);
-                auto  tag = tr.Tag(v, {0, (int)i}, {1, (int)elms});
-                
-                auto w = getwidget(tag, tagcounts[tag]++);
-                
-                if(w == nullptr)
-                    return;
-
-                TW_(v, *w);
-                
-                contents.Add(*w);
-                tr.Apply(*w, v, {0, (int)i}, {1, (int)elms});
-                this->sel_apply(i, *w, v);
-                
-                if(y == 0) {
-                    y = -int(std::round(w->GetHeight() * (scrolloffset - int(scrolloffset))));
-                }
-                
-                indexes.insert({w, i});
-                widgetlist.insert({i, w});
-                
-                w->Move(0, y);
-                
-                //to be moved to resize
-                w->SetWidth(b.Width());
-                auto advance = w->GetHeight() + stack.GetTemplate().GetSpacing() / 2;
-                y += advance;
-                totalh += advance;
-                i++;
-                c++;
-            }
-            
-            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
-            if(scroller) {
-                scroller->SetMaximum(elms + overscroll);
-                
-                if(totalh == 0)
-                    maxdisplay = 0;
-                else
-                    maxdisplay = b.Height() / (float(totalh) / c);
-                
-                scroller->Range = maxdisplay;
-            }
-        }
-        
-        /// Scrolls the contents of the listbox so that the it will start displaying
-        /// items from the given location in list items. This function takes columns
-        /// into account.
-        void ScrollTo(float y) { 
-            float max = this->STR_::getsize() + overscroll - maxdisplay;
-            
-            if(y < 0)
-                y = 0;
-            
-            if(y > max)
-                y = max;
-            
-            if(target == y)
-                return;
-            
-            target = y;
-            
-            if(scrollspeed == 0) {
-                scrolloffset = y;
-                Refresh();
-            }
-            else {
-                if(!isscrolling) {
-                    stack.SetFrameEvent(std::bind(&ListboxBase::updatescroll, this));
-                    isscrolling = true;
-                }
-            }
-            
-            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
-            if(scroller)
-                *scroller = target;
-            
-            Refresh();
-        }
-        
-        /// Scrolls the contents an additional amount of items.
-        void ScrollBy(float y) {
-            ScrollTo(ScrollOffset() + y);
-        }
-        
-        /// Returns the current scroll offset.
-        float ScrollOffset() const {
-            return scrolloffset;
-        }
-        
-        /// Sets the amount of extra scrolling distance after the bottom-most
-        /// widget is completely visible in pixels. Default is 0. Does not
-        /// apply if everything is visible.
-        void SetOverscroll(int value) {
-            if(overscroll == value)
-                return;
-            
-            overscroll = value;
-            
-            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
-            if(scroller)
-                scroller->SetMaximum(this->STR_::getsize() + overscroll);
-        }
-        
-        /// Returns the amount of extra scrolling distance after the bottom-most
-        /// widget is completely visible in pixels.
-        int GetOverscroll() const {
-            return overscroll;
-        }
-        
-        /// Sets the horizontal scroll distance per click in pixels. Default depends
-        /// on the default size of the panel.
-        void SetScrollDistance(int vert) {
-            scrolldist = vert;
-        }
-        
-        /// Returns the scroll distance per click
-        int GetScrollDistance() const {
-            return scrolldist;
-        }
-        
-        /// Disables smooth scrolling of the panel
-        void DisableSmoothScroll() {
-            SetSmoothScrollSpeed(0);
-        }
-        
-        /// Adjusts the smooth scrolling speed of the panel. Given value is
-        /// in items per second, default value is 20.
-        void SetSmoothScrollSpeed(int value) {
-            scrollspeed = value;
-            
-            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
-            if(scroller)
-                scroller->SetSmoothChangeSpeed(scrollspeed);
-            
-            auto elms = this->STR_::getsize();
-            
-            
-            stack.SetValueTransitionSpeed({elms > 0 ? float(value)/elms : 0, 0, 0, 0});
-        }
-        
-        /// Returns the smooth scrolling speed of the panel. If smooth scroll
-        /// is disabled, this value will be 0.
-        int GetSmoothScrollSpeed() const {
-            return scrollspeed;
-        }
-        
-        /// Returns if the smooth scroll is enabled.
-        bool IsSmoothScrollEnabled() const {
-            return scrollspeed != 0;
-        }
-        
-        
-    protected:
-        ListboxBase(const UI::Template &temp) : 
-            ComponentStackWidget(temp, { 
-                { UI::ComponentTemplate::ItemTag   , {}},
-                { UI::ComponentTemplate::HeaderTag , {}},
-                { UI::ComponentTemplate::SpacerTag , {}},
-                { UI::ComponentTemplate::VScrollTag, 
-                    std::bind(&ListboxBase::createvscroll, this, std::placeholders::_1)
-                },
-            } )
-        {
-            stack.HandleMouse();
-            
-            stack.SetClickEvent([&](auto, auto, auto) {
-                Focus();
-            });
-            
-            stack.SetOtherMouseEvent([this](UI::ComponentTemplate::Tag tag, Input::Mouse::EventType type, Geometry::Point, float amount) {
-                if(type == Input::Mouse::EventType::Scroll_Vert) {
-                    ScrollBy(-amount*scrolldist);
-                    
-                    return true;
-                }
-                
-                return false;
-            });
-            
-            contents.SetLayer(stack.GetLayerOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)));
-            stack.AddCondition(UI::ComponentCondition::VScroll);
-        }
-        
-        ~ListboxBase() {
-            for(auto &p : widgets) {
-                p.second.Destroy();
-            }
-        }
-        
-        //this will return the widget with the tag and the order (not index). If the requested
-        //widget does not exists, it will be created
-        W_ *getwidget(UI::ComponentTemplate::Tag tag, int order) {
-            auto temp = stack.GetTemplate(tag);
-            
-            if(temp == nullptr)
-                return nullptr;
-            
-            auto &ws = widgets[tag];
-            
-            while(ws.GetSize() <= order) {
-                auto &w = ws.AddNew(*temp);
-                this->TRF_::prepare(w);
-                this->sel_prepare(w);
-            }
-            
-            return &ws[order];
-        }
-        
-        virtual void focused() override {
-            ComponentStackWidget::focused();
-            this->reapplyfocus();
-        }
-
-        virtual void focuslost() override {
-            ComponentStackWidget::focuslost();
-            contents.RemoveFocus();
-        }
-        
-        UI::Widget *createvscroll(const UI::Template &temp) {
-            auto vscroller = new VScroller<float>(temp);
-            vscroller->Maximum      = this->STR_::getsize();
-            vscroller->Range        = 1;
-            *vscroller              = scrolloffset;
-            vscroller->SmallChange  = scrolldist;
-            vscroller->ValueChanged.Register(*this, &ListboxBase::ScrollTo);
-            
-            return vscroller;
-        }
-        
-        void updatescroll() {
-            if(!isscrolling)
-                Utils::ASSERT_FALSE("This should not happen");
-            
-            auto cur = scrolloffset;
-            
-            float dist = (float)scrollspeed/1000 * Time::DeltaTime();
-            
-            bool done = false;
-            
-            if(target < cur) {
-                if(cur - dist <= target) {
-                    cur = target;
-                }
-                else {
-                    cur -= dist;
-                }
-            }
-            else if(target > cur) {
-                if(cur + dist >= target) {
-                    cur = target;
-                }
-                else {
-                    cur += dist;
-                }
-            }
-            else {
-                done = true;
-            }                
-            
-            scrolloffset = cur;
-            
-            Refresh();
-            
-            if(done) {
-                isscrolling = false;
-                stack.RemoveFrameEvent();
-            }
-        }
-        
-        /// For internal use.
-        /// Returns the widget used to represent the item at the given index. This
-        /// function will return nullptr if the index does not currently have a
-        /// visual representation. This is not an edge case, any item that is not
-        /// in view will most likely not have a representation.
-        virtual W_ *getrepresentation(long index) override {
-            return widgetlist.count(index) ? widgetlist[index] : nullptr;
-        }
-        
-        /// For internal use.
-        /// Returns the first widget used to represent any item at within the 
-        /// listbox. This function will return nullptr if there are no items in the
-        /// list.
-        virtual W_ *getrepresentation() override {
-            return nullptr;
-        }
-        
-        virtual long getindex(const W_ &widget) override {
-            return indexes.count(&widget) ? indexes[&widget] : -1;
-        }
-        
-        std::map<UI::ComponentTemplate::Tag, Containers::Collection<W_>> widgets;
-        std::map<const W_*, long> indexes;
-        std::map<long, W_*> widgetlist;
-        UI::LayerAdapter contents;
-        float scrolloffset = 0.f;
-        float target = 0.f;
-        int overscroll = 1;
-        int scrollspeed = 20;
-        int scrolldist  = 5;
-        bool isscrolling = false;
-        int maxdisplay = 0; //maximum elements that can be displayed
-    };
-    
-    /**
-     * This is a simple listbox. It does not store any additional information
-     * about each item, therefore, can store large amounts of items. Items are
-     * stored in an std::vector. Only one element can be selected at a time.
-     */
-    template<class T_>
-    class SimpleListbox : 
-        public ListboxBase<T_, ListItem, 
-            internal::LBTR_blank <T_, ListItem>,
-            internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>,
-            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>,
-            internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>
-        >
-    {
-        using Base = ListboxBase<T_, ListItem, 
-            internal::LBTR_blank <T_, ListItem>,
-            internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>,
-            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>,
-            internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>
-        >;
-        
-        friend internal::LBTR_blank <T_, ListItem>;
-        friend internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>;
-        friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>;
-        friend internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>;
-        
-    public:
-        explicit SimpleListbox(Registry::TemplateType temp = Registry::Listbox_Regular) : Base(Registry::Active()[temp]) {
-        }
-        
-        virtual bool Activate() {
-            return false;
-        }
-        
-        SimpleListbox &operator =(const T_ value) {
-            this->SetSelection(value);
-            
-            return *this;
-        }
-        
-        using Base::ComponentStackWidget::Widget::Remove;
-        using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>::Remove;
-    };
-    
-    /**
-     * This is a simple multi select listbox. It does not store any additional 
-     * information about each item, therefore, can store large amounts of items.
-     * However, default event strategy is triggering the event for every selected
-     * and unselected item. This might cause problems if the list is too long. 
-     * When the event method is set to single, only one event will be called for
+                /// that item only. Ctrl clicking toggles
+                UseCtrl,
+            };
+            
+            enum EventMethod {
+                /// Event will be fired only once per action
+                Once,
+                
+                /// Even will be fired per changed item
+                ForEachItem
+            };
+            
+            /// Changes selection method. Default method is toggle. In toggle
+            /// method, clicking on an item will toggle its state without
+            /// effecting other items. In UseCtrl method, if an item is clicked
+            /// with Ctrl key pressed, it will be toggled. If Ctrl is not pressed,
+            /// it will become the only selected item. 
+            void SetSelectionMethod(SelectionMethod value) {
+                method = value;
+            }
+            
+            /// Returns the selection method.
+            SelectionMethod GetSelectionMethod() const {
+                return method;
+            }
+            
+            /// Changes event method. Default method is ForEachItem. In ForEachItem
+            /// method, ChangedEvent will be fired for each item that is affected.
+            /// index and status parameters will be set. If event method is set to
+            /// Once, ChangedEvent will be fired once per action. index and status
+            /// parameter will be set only if one item is affected. Otherwise,
+            /// index will be set to -1 and status is set to false.
+            void SetEventMethod(EventMethod value) {
+                event = value;
+            }
+            
+            /// Returns the event method.
+            EventMethod GetEventMethod() const {
+                return event;
+            }
+            
+            /// Removes all items from the selection
+            void ClearSelection() {
+                if(event == Once) {
+                    selected.clear();
+                    ChangedEvent(-1, false);
+                }
+                else {
+                    std::vector<long> old;
+                    std::swap(old, selected);
+                    
+                    for(auto ind : old) {
+                        ChangedEvent(ind, false);
+                    }
+                }
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            /// Replaces the selection by the given index
+            void SetSelection(long ind) {
+                SetSelection(std::vector<long>{ind});
+            };
+            
+            /// Replaces the selection by the given indices
+            void SetSelection(std::vector<long> indices) {
+                if(event == ForEachItem)
+                    ClearSelection();
+                
+                selected = std::move(indices);
+                std::sort(selected.begin(), selected.end());
+                
+                //ensure nothing is duplicated
+                selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
+                
+                if(event == ForEachItem) {
+                    for(auto ind : selected) {
+                        ChangedEvent(ind, true);
+                    }
+                }
+                else {
+                    ChangedEvent(-1, false);
+                }
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            };
+            
+            /// Replaces the selection by the given indices
+            template<class ...P_>
+            void SetSelection(P_&&... elms) {
+                SetSelection({elms...});
+            }
+            
+            /// Adds the given index to the selection
+            void AddToSelection(long ind) {
+                AddToSelection(std::vector<long>{ind});
+            };
+            
+            /// Adds the given indices to the selection
+            void AddToSelection(std::vector<long> indices) {
+                std::sort(indices.begin(), indices.end());
+                
+                selected.resize(selected.size() + indices.size());
+                auto sel = selected.rbegin();
+                auto cur = selected.rbegin() + indices.size();
+                auto ind = indices.rbegin();
+                
+                while(ind != indices.rend()) {
+                    if(cur == selected.rend() || *cur < *ind) {
+                        *sel = *ind;
+                        
+                        if(event == ForEachItem)
+                            ChangedEvent(*ind, true);
+                        
+                        ++ind;
+                    }
+                    else {
+                        *sel = *cur;
+                        ++cur;
+                    }
+                    ++sel;
+                }
+                
+                //ensure nothing is duplicated
+                selected.erase(std::unique(selected.begin(), selected.end()), selected.end());
+                
+                if(event == Once) {
+                    ChangedEvent(-1, false);
+                }
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            };
+            
+            /// Adds the given indices to the selection
+            template<class ...P_>
+            void AddToSelection(P_&&... elms) {
+                AddToSelection({elms...});
+            }
+            
+            /// Returns if the item in the given index is selected.
+            bool IsSelected(long index) const {
+                return std::binary_search(selected.begin(), selected.end(), index);
+            }
+            
+            /// Returns how many items are selected
+            long GetSelectionCount() const {
+                return long(selected.size());
+            }
+            
+            /// Removes the given index from the selection
+            void RemoveFromSelection(long index) {
+                auto item = std::lower_bound(selected.begin(), selected.end(), index);
+                
+                if(item != selected.end() && *item == index) {
+                    selected.erase(item);
+                    ChangedEvent(index, false);
+                }
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            /// Selects all items
+            void SelectAll() {
+                auto elms = dynamic_cast<F_*>(this)->GetCount();
+                
+                std::vector<long> old;
+                old.reserve(elms);
+                
+                std::swap(old, selected);
+                
+                auto sel = old.begin();
+                for(int i=0; i<elms; i++) {
+                    if(sel != old.end() && *sel == i)
+                        ++sel;
+                    else if(event == ForEachItem)
+                        ChangedEvent(i, true);
+                        
+                    selected.push_back(i);
+                }
+                
+                if(event == Once)
+                    ChangedEvent(-1, false);
+                
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            /// Inverts the selection.
+            void InvertSelection() {
+                std::vector<long> old;
+                
+                auto elms = dynamic_cast<F_*>(this)->GetCount();
+                old.reserve(elms-selected.size());
+                
+                std::swap(selected, old);
+                
+                auto sel = old.begin();
+                for(int i=0; i<elms; i++) {
+                    if(sel != old.end() && *sel == i) {
+                        ++sel;
+                        
+                        if(event == ForEachItem)
+                            ChangedEvent(i, false);
+                    }
+                    else {
+                        selected.push_back(i);
+                        
+                        if(event == ForEachItem)
+                            ChangedEvent(i, true);
+                    }
+                }
+                
+                if(event == Once)
+                    ChangedEvent(-1, false);
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            /*
+            Selection -> subclass allows for(auto item : list.Selection)
+            */
+            SelectionIndexHelper SelectedIndices;
+            SelectionHelper Selection;
+            
+            Event<LBSELTR_Multi, long, bool> ChangedEvent = Event<LBSELTR_Multi, long, bool>{this};
+            
+        protected:
+            LBSELTR_Multi() : 
+                SelectedIndices(selected),
+                Selection(*this)
+            {
+            }
+            
+            virtual ~LBSELTR_Multi() { }
+            
+            void sel_clicked(long index, W_ &w) {
+                if(focusindex == index)
+                    return;
+                
+                if(dynamic_cast<UI::Widget*>(this)->IsFocused())
+                    w.Focus();
+                
+                focusindex = index;
+                
+                dynamic_cast<UI::Widget*>(this)->Focus();
+            }
+            
+            void sel_toggled(long index, W_ &w) {
+                if(method == Toggle) {
+                    auto item = std::lower_bound(selected.begin(), selected.end(), index);
+                    
+                    if(item != selected.end() && *item == index) {
+                        w.SetSelected(false);
+                        selected.erase(item);
+                        
+                        ChangedEvent(index, false);
+                    }
+                    else {
+                        w.SetSelected(true);
+                        selected.insert(item, index);
+                        
+                        ChangedEvent(index, true);
+                    }
+                }
+                else {
+                    if(Input::Keyboard::CurrentModifier == Input::Keyboard::Modifier::Ctrl) {
+                        auto item = std::lower_bound(selected.begin(), selected.end(), index);
+                        
+                        if(item != selected.end() && *item == index) {
+                            w.SetSelected(false);
+                            selected.erase(item);
+                            
+                            ChangedEvent(index, false);
+                        }
+                        else {
+                            w.SetSelected(true);
+                            selected.insert(item, index);
+                            
+                            ChangedEvent(index, true);
+                        }
+                    }
+                    else {
+                        SetSelection(index);
+                    }
+                }
+            }
+            
+            void sel_apply(long index, W_ &w, const T_ &) {
+                if(index == focusindex) {
+                    w.Focus();
+                }
+                else if(w.IsFocused()) {
+                    w.Defocus();
+                }
+                
+                if(std::binary_search(selected.begin(), selected.end(), index)) {
+                    w.SetSelected(true);
+                }
+                else {
+                    w.SetSelected(false);
+                }
+            }
+            
+            void sel_prepare(W_ &w) {
+                w.ClickEvent.Register([&w, this] {
+                    sel_clicked(dynamic_cast<F_*>(this)->getindex(w), w);
+                });
+                w.ToggleEvent.Register([&w, this] {
+                    sel_toggled(dynamic_cast<F_*>(this)->getindex(w), w);
+                });
+            }
+            
+            void sel_insert(long index, long count) { 
+                if(index <= focusindex)
+                    focusindex += count;
+                
+                auto item = std::lower_bound(selected.begin(), selected.end(), index);
+                for(; item != selected.end(); ++item) {
+                    *item += count;
+                }
+            }
+            
+            void sel_move(long index, long target) { 
+                if(index == target) 
+                    return;
+                //move triggers apply to both indexes
+                
+                if(index == focusindex) {
+                    focusindex = target;
+                }
+                else if(index > focusindex && target <= focusindex) {
+                    focusindex++;
+                }
+                else if(index < focusindex && target > focusindex) {
+                    focusindex--;
+                }
+                
+                if(index < target) {
+                    auto from = std::lower_bound(selected.begin(), selected.end(), index);
+                    auto to = std::lower_bound(selected.begin(), selected.end(), target+1);
+                
+                    auto shifted = from;
+                    
+                    if(*from == index)
+                        ++shifted;
+                    
+                    while(from < to) {
+                        *from = *shifted - 1;
+                        
+                        ++from;
+                        ++shifted;
+                    }
+                    
+                    if(shifted != from) {
+                        *shifted = target;
+                    }
+                }
+                else {
+                    auto from = std::lower_bound(selected.begin(), selected.end(), index-1);
+                    auto to = std::upper_bound(selected.begin(), selected.end(), target);
+                
+                    auto shifted = from;
+                    
+                    if(*from == index)
+                        --shifted;
+                    
+                    while(from > to) {
+                        *from = *shifted + 1;
+                        
+                        --from;
+                        --shifted;
+                    }
+                    
+                    if(shifted != from) {
+                        *shifted = target;
+                    }
+                }
+            }
+            
+            void sel_remove(long index, long count) { 
+                //removed items will be repurposed using apply,
+                if(index <= focusindex) {
+                    if(index+count > focusindex) {
+                        focusindex = -1;
+                    }
+                    else {
+                        focusindex -= count;
+                    }
+                }
+                
+                //move and update items that are after the point of removal
+                auto item = std::lower_bound(selected.begin(), selected.end(), index);
+                auto shifted = item;
+                while(shifted != selected.end()) {
+                    if(*item < index+count) {
+                        shifted++;
+                    }
+                    
+                    *item = *shifted - count;
+                    
+                    ++shifted;
+                    ++item;
+                }
+                
+                //remove the items to be removed, they are already moved to the end
+                if(item != selected.end())
+                    selected.erase(item, selected.end());
+            }
+            
+            void sel_destroy(W_ &w) {
+                if(w.IsFocused()) {
+                    focusindex = -1;
+                    w.Defocus();
+                }
+            }
+            
+            void reapplyfocus() {
+                if(focusindex != -1) {
+                    auto w = dynamic_cast<F_*>(this)->getrepresentation(focusindex);
+                    if(w)
+                        w->Focus();
+                }
+            }
+            
+            long focusindex = -1;
+            std::vector<long> selected; //this list will be kept sorted
+            SelectionMethod method = Toggle;
+            EventMethod event      = ForEachItem;
+        };
+        
+        template<class T_, class W_, class S_, class F_>
+        class LBSTR_STLVector {
+        public:
+            using Storage = S_;
+            
+            void Add(T_ val) {
+                storage.push_back(val);
+                
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            template<class... A_>
+            void Add(T_ val, A_&& ...rest) {
+                storage.push_back(val);
+                
+                Add(std::forward<A_>(rest)...);
+            }
+            
+            void Insert(long before, T_ val) {
+                storage.insert(storage.begin()+before, val);
+                
+                dynamic_cast<F_*>(this)->sel_insert(before, 1);
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            template<class... A_>
+            void Insert(long before, T_ val, A_&& ...rest) {
+                //TODO optimize
+                Insert(std::forward<A_>(rest)...);
+                
+                storage.insert(storage.begin()+before, val);
+                dynamic_cast<F_*>(this)->sel_insert(before, 1);
+            }
+            
+            void Remove(long index) {
+                storage.erase(storage.begin()+index);
+                
+                dynamic_cast<F_*>(this)->sel_remove(index, 1);
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            void MoveBefore(long index, long before) {
+                if(index==before)
+                    return;
+
+                if(index>before) {
+                    auto t = storage[index];
+                    for(unsigned i=index; i>before; i--)
+                        storage[i] = storage[i-1];
+
+                    storage[before]=t;
+                }
+                else if(before==storage.size()) {
+                    auto t = storage[index];
+
+                    for(unsigned i=index; i<storage.size()-1; i++)
+                        storage[i] = storage[i+1];
+
+                    storage[storage.size()-1] = t;
+                }
+                else {
+                    auto t = storage[index];
+                    for(unsigned i=index; i<before; i++)
+                        storage[i] = storage[i+1];
+
+                    storage[before] = t;
+                }
+                
+                dynamic_cast<F_*>(this)->sel_move(index, before);
+                dynamic_cast<F_*>(this)->Refresh();
+            }
+            
+            /// Return the index of the first item that has the given value.
+            /// Returns -1 if item not found.
+            long Find(const T_ item, long start = 0) {
+                auto it = std::find(storage.begin() + start, storage.end(), item);
+                if(it == storage.end())
+                    return -1;
+                else
+                    return it-storage.begin();
+            }
+            
+            /**
+             * @name Iteration 
+             * 
+             * These functions allow iteration of the listbox. If 
+             * the contents are changed through these functions, 
+             * you must call Refresh manually.
+             * 
+             * @{
+             */
+            auto begin() {
+                return storage.begin();
+            }
+            
+            auto begin() const {
+                return storage.begin();
+            }
+            
+            auto end() {
+                return storage.end();
+            }
+            
+            auto end() const {
+                return storage.end();
+            }
+            
+            /// @}
+        
+        protected:
+            LBSTR_STLVector() {}
+            virtual ~LBSTR_STLVector() {}
+            
+            long getsize() const {
+                return storage.size();
+            }
+            
+            T_ &getelm(long index) {
+                return storage[index];
+            }
+            
+            const T_ &getelm(long index) const {
+                return storage[index];
+            }
+            
+            Storage storage;
+        };
+    }
+    /// @endcond
+    
+    /**
+     * This is the base class for all listbox like widgets. It is not intended
+     * to be used directly but you may use it to create your own listboxes. The
+     * solid listboxes should be derived from this object and should make 
+     * desired functionality public.
+     * 
+     * Listbox will maintain the necessary number widgets to fill its area. It
+     * does not create widgets for elements falling outside the range. If traits
+     * can return different tags, the widgets to cover its area will be created
+     * separately for these tags. 
+     * 
+     * Listbox has multi-column functionality. However, this is not to be used
+     * for tables. Table systems should insert rows as listbox items, which then
+     * should have cells.
+     * 
+     * *Template parameters*
+     * 
+     * T_ is the stored data type. 
+     * 
+     * W_ is the widget that will be used to represent items.
+     * 
+     * TR_ is widget traits class that allows additional properties for each
+     * element. They should contain minimal number of data members. There should
+     * be a function Apply taking `W_ &`, `const T_ &`, Point index, Size total
+     * as parameters applying traits to W_. Additionally, TR_ should have Tag
+     * function that has `const T_ &`, Point index, Size total as parameters and
+     * should return UI::ComponentTemplate::Tag to determine the template for
+     * the widget. The tags should match with the listbox template. If the given
+     * tag is not found, ItemTag will be used.
+     * 
+     * TRF_ is the trait functions that will return/set the traits of items. 
+     * TRF_ should contain access function that should take the index of an item
+     * to return TR_ associated with it.
+     * It should contain `insert(before, count)` to add count elements before
+     * the given index. These elements must be default initialized to a normal
+     * state. 
+     * `move(index, before)` should move the indexed item before the given 
+     * index. 
+     * `remove(index, count)` should remove count number of items 
+     * starting from the given index. 
+     * `prepare(W_ &)` function should prepare the given widget for the first
+     * usage. This is only called once on a newly created widget.
+     * `destroy(W_ &)` function is called when a widget is about to be 
+     * destroyed.
+     * Index parameters should be long int. These functions should be protected
+     * as ListboxBase will be derived from TRF_. Finally, TRF_ should have a 
+     * protected constructor/destructor.
+     * 
+     * STR_ is the storage traits for T_. This class should contain typedef
+     * Storage which is the storage. It should have functions that allows it
+     * to handle Add/Remove/Insert/Move/getsize/getelm functions. Only 
+     * getsize and getelm functions are mandatory. getelm should take a long
+     * index and should return the stored value. GetSize should return long.
+     * Additionally, this function should have a protected storage member
+     * named storage. After every modifying operation, this function should
+     * call Refresh. Ideally, this class should contain 
+     * 
+     * useisvisible controls if elements can be hidden. If this is true, TR_
+     * should have IsVisible function returning bool. This parameter will
+     * slowdown listbox considerably when many items are stored as each item
+     * will be checked whether they are visible until to the point of display.
+     * This will not affect the performance on short lists.
+     * 
+     * SELTR_ is the class that will control selection traits of the Listbox.
+     * Defult traits allow single select. It is possible to construct list of 
+     * particular widgets that has no concept of selection if selection traits
+     * is set to internal::LBSELTR_None.
+     * This class should support sel_click and sel_toggle functions both taking
+     * long index, const T_ & value, W_ &widget. Click function will be called 
+     * when the user uses arrow keys to select an item. It is this classes 
+     * responsibility to handle actual click and toggle functions.
+     * apply function should apply selection related traits to the widget taking
+     * long index, W_ &widget, const T_ & value. Any item that is benched will
+     * be applied to as well with an index of -1.
+     * This class should contain `insert(before, count)` to add count elements
+     * before the given index. These elements must be default initialized to a
+     * non-selected normal state. 
+     * `sel_move(index, before)` should move the indexed item before the given 
+     * index. 
+     * `sel_remove(index, count)` should remove count number of items 
+     * starting from the given index. 
+     * `sel_prepare(W_ &)` function should prepare the given widget for the first
+     * usage. This is only called once on a newly created widget.
+     * `sel_destroy(W_ &)` function is called when a widget is about to be 
+     * destroyed.
+     * Index parameters should be long int. These functions should be protected
+     * as ListboxBase will be derived from SELTR_. Finally, SELTR_ should have a 
+     * protected constructor/destructor.
+     * reapplyfocus function should apply the focus to the focused element. This
+     * function is called after listbox receives focus.
+     * 
+     * TW_ function should take a T_ and set this to its W_ representation. 
+     * 
+     * WT_ should read the data from W_ and set it to T_.
+     */
+    template<
+        class T_, class W_, class TR_, class TRF_, 
+        class STR_, class SELTR_, 
+        bool useisvisible = false,
+        void (*TW_)(const T_ &, W_ &) = internal::SetTextUsingFrom<T_, W_>,
+        void (*WT_)(W_ &, T_ &)       = internal::GetTextUsingTo  <T_, W_>
+    >
+    class ListboxBase : public UI::ComponentStackWidget, 
+                        public ListBase<T_, W_>, 
+                        public TRF_, 
+                        public SELTR_, public STR_ 
+    {
+    public:
+        
+        /// Returns the item at the given point. This operator will not perform
+        /// bounds checking.
+        virtual T_ &operator[](long index) override {
+            return this->getelm(index);
+        }
+
+        /// Returns the item at the given point. This operator will not perform
+        /// bounds checking.
+        virtual const T_ &operator[](long index) const override {
+            return this->getelm(index);
+        }
+        
+        /// Returns the number of elements in the list.
+        virtual long GetCount() const override {
+            return this->STR_::getsize();
+        }
+        
+        virtual void Refresh() override {
+            if(!contents.IsReady())
+                return;
+
+            auto elms = this->STR_::getsize();
+            
+            std::map<UI::ComponentTemplate::Tag, int> tagcounts;
+            
+            //TODO improve performance by rolling
+            
+            //remove all first
+            for(auto &p : widgetlist) {
+                p.second->Remove();
+            }
+            indexes.clear();
+            widgetlist.clear();
+            
+            auto b = stack.TagBounds(UI::ComponentTemplate::ViewPortTag);
+            if(b.Width() == 0 || b.Height() == 0)
+                b = stack.TagBounds(UI::ComponentTemplate::ContentsTag);
+            
+            int y = 0;
+            long i = int(scrolloffset), c = 0;
+            int totalh = 0;
+            if(i < 0)
+                i = 0;
+            while(y < b.Height() && i < elms) {
+                auto &v   = this->getelm(i);
+                auto  tr  = this->access(i);
+                auto  tag = tr.Tag(v, {0, (int)i}, {1, (int)elms});
+                
+                auto w = getwidget(tag, tagcounts[tag]++);
+                
+                if(w == nullptr)
+                    return;
+
+                TW_(v, *w);
+                
+                contents.Add(*w);
+                tr.Apply(*w, v, {0, (int)i}, {1, (int)elms});
+                this->sel_apply(i, *w, v);
+                
+                if(y == 0) {
+                    y = -int(std::round(w->GetHeight() * (scrolloffset - int(scrolloffset))));
+                }
+                
+                indexes.insert({w, i});
+                widgetlist.insert({i, w});
+                
+                w->Move(0, y);
+                
+                //to be moved to resize
+                w->SetWidth(b.Width());
+                auto advance = w->GetHeight() + stack.GetTemplate().GetSpacing() / 2;
+                y += advance;
+                totalh += advance;
+                i++;
+                c++;
+            }
+            
+            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
+            if(scroller) {
+                scroller->SetMaximum(elms + overscroll);
+                
+                if(totalh == 0)
+                    maxdisplay = 0;
+                else
+                    maxdisplay = b.Height() / (float(totalh) / c);
+                
+                scroller->Range = maxdisplay;
+            }
+        }
+        
+        /// Scrolls the contents of the listbox so that the it will start displaying
+        /// items from the given location in list items. This function takes columns
+        /// into account.
+        void ScrollTo(float y) { 
+            float max = this->STR_::getsize() + overscroll - maxdisplay;
+            
+            if(y < 0)
+                y = 0;
+            
+            if(y > max)
+                y = max;
+            
+            if(target == y)
+                return;
+            
+            target = y;
+            
+            if(scrollspeed == 0) {
+                scrolloffset = y;
+                Refresh();
+            }
+            else {
+                if(!isscrolling) {
+                    stack.SetFrameEvent(std::bind(&ListboxBase::updatescroll, this));
+                    isscrolling = true;
+                }
+            }
+            
+            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
+            if(scroller)
+                *scroller = target;
+            
+            Refresh();
+        }
+        
+        /// Scrolls the contents an additional amount of items.
+        void ScrollBy(float y) {
+            ScrollTo(ScrollOffset() + y);
+        }
+        
+        /// Returns the current scroll offset.
+        float ScrollOffset() const {
+            return scrolloffset;
+        }
+        
+        /// Sets the amount of extra scrolling distance after the bottom-most
+        /// widget is completely visible in pixels. Default is 0. Does not
+        /// apply if everything is visible.
+        void SetOverscroll(int value) {
+            if(overscroll == value)
+                return;
+            
+            overscroll = value;
+            
+            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
+            if(scroller)
+                scroller->SetMaximum(this->STR_::getsize() + overscroll);
+        }
+        
+        /// Returns the amount of extra scrolling distance after the bottom-most
+        /// widget is completely visible in pixels.
+        int GetOverscroll() const {
+            return overscroll;
+        }
+        
+        /// Sets the horizontal scroll distance per click in pixels. Default depends
+        /// on the default size of the panel.
+        void SetScrollDistance(int vert) {
+            scrolldist = vert;
+        }
+        
+        /// Returns the scroll distance per click
+        int GetScrollDistance() const {
+            return scrolldist;
+        }
+        
+        /// Disables smooth scrolling of the panel
+        void DisableSmoothScroll() {
+            SetSmoothScrollSpeed(0);
+        }
+        
+        /// Adjusts the smooth scrolling speed of the panel. Given value is
+        /// in items per second, default value is 20.
+        void SetSmoothScrollSpeed(int value) {
+            scrollspeed = value;
+            
+            auto scroller = dynamic_cast<VScroller<float>*>(stack.GetWidget(UI::ComponentTemplate::VScrollTag));
+            if(scroller)
+                scroller->SetSmoothChangeSpeed(scrollspeed);
+            
+            auto elms = this->STR_::getsize();
+            
+            
+            stack.SetValueTransitionSpeed({elms > 0 ? float(value)/elms : 0, 0, 0, 0});
+        }
+        
+        /// Returns the smooth scrolling speed of the panel. If smooth scroll
+        /// is disabled, this value will be 0.
+        int GetSmoothScrollSpeed() const {
+            return scrollspeed;
+        }
+        
+        /// Returns if the smooth scroll is enabled.
+        bool IsSmoothScrollEnabled() const {
+            return scrollspeed != 0;
+        }
+        
+        using UI::Widget::EnsureVisible;
+        
+        /// Ensures the given index is completely visible on the screen.
+        void EnsureVisible(long index) {
+            float targetind = float(index);
+            
+            auto md = maxdisplay;
+            
+            if(targetind >= target && targetind < floor(target + md)) {
+                return; //already visible
+            }
+            else if(targetind >= floor(target + md)) {
+                targetind -= md - 1.5; //show the next item a little bit
+            }
+            else {
+                targetind -= 0.5; //show the next item a little bit
+            }
+            
+            auto elms = this->GetCount();
+            
+            if(targetind < 0)
+                targetind = 0;
+            if(targetind > overscroll + elms)
+                targetind = overscroll + elms;
+            
+            ScrollTo(targetind);
+            
+            //if max display changes, call ensure visible again
+            if(md != maxdisplay)
+                EnsureVisible(index);
+        }
+        
+        bool KeyEvent(Input::Key key, float amout) override {
+            return false;
+        }
+        
+    protected:
+        ListboxBase(const UI::Template &temp) : 
+            ComponentStackWidget(temp, { 
+                { UI::ComponentTemplate::ItemTag   , {}},
+                { UI::ComponentTemplate::HeaderTag , {}},
+                { UI::ComponentTemplate::SpacerTag , {}},
+                { UI::ComponentTemplate::VScrollTag, 
+                    std::bind(&ListboxBase::createvscroll, this, std::placeholders::_1)
+                },
+            } )
+        {
+            stack.HandleMouse();
+            
+            stack.SetClickEvent([&](auto, auto, auto) {
+                Focus();
+            });
+            
+            stack.SetOtherMouseEvent([this](UI::ComponentTemplate::Tag tag, Input::Mouse::EventType type, Geometry::Point, float amount) {
+                if(type == Input::Mouse::EventType::Scroll_Vert) {
+                    ScrollBy(-amount*scrolldist);
+                    
+                    return true;
+                }
+                
+                return false;
+            });
+            
+            contents.SetLayer(stack.GetLayerOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)));
+            stack.AddCondition(UI::ComponentCondition::VScroll);
+        }
+        
+        ~ListboxBase() {
+            for(auto &p : widgets) {
+                p.second.Destroy();
+            }
+        }
+        
+        //this will return the widget with the tag and the order (not index). If the requested
+        //widget does not exists, it will be created
+        W_ *getwidget(UI::ComponentTemplate::Tag tag, int order) {
+            auto temp = stack.GetTemplate(tag);
+            
+            if(temp == nullptr)
+                return nullptr;
+            
+            auto &ws = widgets[tag];
+            
+            while(ws.GetSize() <= order) {
+                auto &w = ws.AddNew(*temp);
+                this->TRF_::prepare(w);
+                this->sel_prepare(w);
+            }
+            
+            return &ws[order];
+        }
+        
+        virtual void focused() override {
+            ComponentStackWidget::focused();
+            this->reapplyfocus();
+        }
+
+        virtual void focuslost() override {
+            ComponentStackWidget::focuslost();
+            contents.RemoveFocus();
+        }
+        
+        UI::Widget *createvscroll(const UI::Template &temp) {
+            auto vscroller = new VScroller<float>(temp);
+            vscroller->Maximum      = this->STR_::getsize();
+            vscroller->Range        = 1;
+            *vscroller              = scrolloffset;
+            vscroller->SmallChange  = scrolldist;
+            vscroller->ValueChanged.Register(*this, &ListboxBase::ScrollTo);
+            
+            return vscroller;
+        }
+        
+        void updatescroll() {
+            if(!isscrolling)
+                Utils::ASSERT_FALSE("This should not happen");
+            
+            auto cur = scrolloffset;
+            
+            float dist = (float)scrollspeed/1000 * Time::DeltaTime();
+            
+            bool done = false;
+            
+            if(target < cur) {
+                if(cur - dist <= target) {
+                    cur = target;
+                }
+                else {
+                    cur -= dist;
+                }
+            }
+            else if(target > cur) {
+                if(cur + dist >= target) {
+                    cur = target;
+                }
+                else {
+                    cur += dist;
+                }
+            }
+            else {
+                done = true;
+            }                
+            
+            scrolloffset = cur;
+            
+            Refresh();
+            
+            if(done) {
+                isscrolling = false;
+                stack.RemoveFrameEvent();
+            }
+        }
+        
+        /// For internal use.
+        /// Returns the widget used to represent the item at the given index. This
+        /// function will return nullptr if the index does not currently have a
+        /// visual representation. This is not an edge case, any item that is not
+        /// in view will most likely not have a representation.
+        virtual W_ *getrepresentation(long index) override {
+            return widgetlist.count(index) ? widgetlist[index] : nullptr;
+        }
+        
+        /// For internal use.
+        /// Returns the first widget used to represent any item at within the 
+        /// listbox. This function will return nullptr if there are no items in the
+        /// list.
+        virtual W_ *getrepresentation() override {
+            return nullptr;
+        }
+        
+        virtual long getindex(const W_ &widget) override {
+            return indexes.count(&widget) ? indexes[&widget] : -1;
+        }
+        
+        std::map<UI::ComponentTemplate::Tag, Containers::Collection<W_>> widgets;
+        std::map<const W_*, long> indexes;
+        std::map<long, W_*> widgetlist;
+        UI::LayerAdapter contents;
+        float scrolloffset = 0.f;
+        float target = 0.f;
+        int overscroll = 1;
+        int scrollspeed = 20;
+        int scrolldist  = 5;
+        bool isscrolling = false;
+        float maxdisplay = 0; //maximum elements that can be displayed
+    };
+    
+    /**
+     * This is a simple listbox. It does not store any additional information
+     * about each item, therefore, can store large amounts of items. Items are
+     * stored in an std::vector. Only one element can be selected at a time.
+     */
+    template<class T_>
+    class SimpleListbox : 
+        public ListboxBase<T_, ListItem, 
+            internal::LBTR_blank <T_, ListItem>,
+            internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>,
+            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>,
+            internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>
+        >
+    {
+        using Base = ListboxBase<T_, ListItem, 
+            internal::LBTR_blank <T_, ListItem>,
+            internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>,
+            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>,
+            internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>
+        >;
+        
+        friend internal::LBTR_blank <T_, ListItem>;
+        friend internal::LBTRF_blank<T_, ListItem, SimpleListbox<T_>>;
+        friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>;
+        friend internal::LBSELTR_Single<T_, ListItem, SimpleListbox<T_>>;
+        
+    public:
+        explicit SimpleListbox(Registry::TemplateType temp = Registry::Listbox_Regular) : Base(Registry::Active()[temp]) {
+        }
+        
+        virtual bool Activate() {
+            return false;
+        }
+        
+        SimpleListbox &operator =(const T_ value) {
+            this->SetSelection(value);
+            
+            return *this;
+        }
+        
+        using Base::ComponentStackWidget::Widget::Remove;
+        using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, SimpleListbox<T_>>::Remove;
+    };
+    
+    /**
+     * This is a simple multi select listbox. It does not store any additional 
+     * information about each item, therefore, can store large amounts of items.
+     * However, default event strategy is triggering the event for every selected
+     * and unselected item. This might cause problems if the list is too long. 
+     * When the event method is set to single, only one event will be called for
      * single action. Items are stored in an std::vector. You may use Selection
      * and SelectedIndices to iterate selected elements. In both members, selection
-     * is always sorted by the position in the listbox.
-     */
-    template<class T_>
-    class MultiListbox : 
-        public ListboxBase<T_, ListItem, 
-            internal::LBTR_blank <T_, ListItem>,
-            internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>,
-            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>,
-            internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>
-        >
-    {
-        using Base = ListboxBase<T_, ListItem, 
-            internal::LBTR_blank <T_, ListItem>,
-            internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>,
-            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>,
-            internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>
-        >;
-        
-        friend internal::LBTR_blank <T_, ListItem>;
-        friend internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>;
-        friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>;
-        friend internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>;
-        
-    public:
-        explicit MultiListbox(Registry::TemplateType temp = Registry::Listbox_Regular) : Base(Registry::Active()[temp]) {
-        }
-        
-        virtual bool Activate() {
-            return false;
-        }
-        
-        MultiListbox &operator =(const T_ value) {
-            this->SetSelection(value);
-            
-            return *this;
-        }
-        
-        using Base::ComponentStackWidget::Widget::Remove;
-        using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>::Remove;
-    };
-    
-} }
-
+     * is always sorted by the position in the listbox.
+     */
+    template<class T_>
+    class MultiListbox : 
+        public ListboxBase<T_, ListItem, 
+            internal::LBTR_blank <T_, ListItem>,
+            internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>,
+            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>,
+            internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>
+        >
+    {
+        using Base = ListboxBase<T_, ListItem, 
+            internal::LBTR_blank <T_, ListItem>,
+            internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>,
+            internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>,
+            internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>
+        >;
+        
+        friend internal::LBTR_blank <T_, ListItem>;
+        friend internal::LBTRF_blank<T_, ListItem, MultiListbox<T_>>;
+        friend internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>;
+        friend internal::LBSELTR_Multi<T_, ListItem, MultiListbox<T_>>;
+        
+    public:
+        explicit MultiListbox(Registry::TemplateType temp = Registry::Listbox_Regular) : Base(Registry::Active()[temp]) {
+        }
+        
+        virtual bool Activate() {
+            return false;
+        }
+        
+        MultiListbox &operator =(const T_ value) {
+            this->SetSelection(value);
+            
+            return *this;
+        }
+        
+        using Base::ComponentStackWidget::Widget::Remove;
+        using internal::LBSTR_STLVector<T_, ListItem, std::vector<T_>, MultiListbox<T_>>::Remove;
+    };
+    
+} }
+
--- a/Testing/Source/Manual/UI_Generate.cpp	Fri Oct 30 13:43:20 2020 +0200
+++ b/Testing/Source/Manual/UI_Generate.cpp	Fri Oct 30 20:44:22 2020 +0200
@@ -186,6 +186,8 @@
 
         std::cout<<index<<": "<<(state ? "true" : "false")<<std::endl;
     });
+    list.EnsureVisible(11);
+    list.EnsureVisible(1);
     
     app.wind.Add(blank);
     addme(blank, btn);

mercurial