* ComponentStack autosize support 4.x-dev

Fri, 04 Dec 2020 12:40:22 +0200

author
cemkalyoncu
date
Fri, 04 Dec 2020 12:40:22 +0200
branch
4.x-dev
changeset 1506
c24aade1ec31
parent 1505
3c56a4a7f14f
child 1507
16116186d94c

* ComponentStack autosize support

Source/Gorgon/Containers/Collection.h file | annotate | diff | comparison | revisions
Source/Gorgon/Graphics/FreeType.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/Layer.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStack.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStack.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Organizers/Flow.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Template.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Template.h file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Generator.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Listbox.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Component.cpp file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Generate.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Containers/Collection.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/Containers/Collection.h	Fri Dec 04 12:40:22 2020 +0200
@@ -379,7 +379,7 @@
 			/// this method moves the given object in the collection in front of the reference
 			void MoveBefore(long index, long before) {
                 if(before == -1)
-                    before = list.size();
+                    before = (long)list.size();
 				if(index>=list.size())
 					throw std::out_of_range("Invalid location");
 				if(before>list.size())
--- a/Source/Gorgon/Graphics/FreeType.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/Graphics/FreeType.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -526,7 +526,7 @@
 	}
 	
 	bool FreeType::Exists(Glyph g) const {
-        int c = glyphmap.count(g);
+        int c = (int)glyphmap.count(g);
         return c != 0;
     }
     
@@ -1098,7 +1098,7 @@
             loadglyphs('f', true);
             loadglyphs('j', true);
 
-            if(glyphmap.count(0xc2)) {
+            if(glyphmap.count(0xc2)) { 
                 c[0] = 0xc2;
             }
             else
@@ -1126,6 +1126,6 @@
                 maxy = g.offset.Y + g.images.regular->GetHeight();
         }
 
-        return {miny + baseline, maxy - miny};
+        return {miny + (int)baseline, maxy - miny};
     }
 } }
--- a/Source/Gorgon/Layer.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/Layer.h	Fri Dec 04 12:40:22 2020 +0200
@@ -354,13 +354,13 @@
 		}
 
 		/// Sets the boundaries of this layer.
-		void SetBounds(const Geometry::Bounds &bounds) {
+		virtual void SetBounds(const Geometry::Bounds &bounds) {
 			this->bounds=bounds;
 		}
 		
 		/// Returns the size of the layer
 		Geometry::Size GetSize() const {
-            return bounds.GetSize();
+            return GetBounds().GetSize();
         }
         
         /// Returns the size of the layer. If any dimension size is
@@ -391,31 +391,31 @@
         
 		/// Returns the width of the layer
 		int GetWidth() const {
-			return bounds.Width();
+			return GetBounds().Width();
 		}
 
 		/// Returns the height of the layer
 		int GetHeight() const {
-			return bounds.Height();
+			return GetBounds().Height();
 		}
 
 		/// Returns the current location of the layer
 		Geometry::Point GetLocation() const {
-			return bounds.TopLeft();
+			return GetBounds().TopLeft();
 		}
 
 		/// Returns the current location of the layer
 		int GetLeft() const {
-			return bounds.Left;
+			return GetBounds().Left;
 		}
 
 		/// Returns the current location of the layer
 		int GetTop() const {
-			return bounds.Top;
+			return GetBounds().Top;
 		}
 		
 		/// Returns the boundaries of the layer
-		Geometry::Bounds GetBounds() const {
+		virtual Geometry::Bounds GetBounds() const {
 			return bounds;
 		}
 
--- a/Source/Gorgon/UI/ComponentStack.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/UI/ComponentStack.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -2138,6 +2138,12 @@
         if(stacksizes[0]) {
             //initial states
             get(0).size = size;
+            
+            if(autosize.first)
+                get(0).size.Width = 0;
+            if(autosize.second)
+                get(0).size.Height = 0;
+            
             get(0).location = {0,0};
             get(0).parent = -1;
             
@@ -2172,7 +2178,25 @@
             }
             
             //start the update from the root
-            update(get(0), value, -1);
+            update(get(0), value, -1, autosize.first ? size.Width : -1, autosize.first || autosize.second);
+            
+            if(autosize.first || autosize.second) {
+                auto sz = size;
+                
+                if(autosize.first && get(0).size.Width >= 0)
+                    sz.Width = get(0).size.Width;
+                
+                if(autosize.second && get(0).size.Height >= 0)
+                    sz.Height = get(0).size.Height;
+                
+                
+                //second run to get everything into proper size
+                update(get(0), value, -1);
+                
+                Layer::Resize(sz);
+                mouse.Resize(sz);
+            }
+
         }
         
         //update is complete
@@ -2198,7 +2222,7 @@
     }
     
     //location depends on the container location
-    void ComponentStack::update(Component &parent, const std::array<float, 4> &value, int ind, int textwidth) {
+    void ComponentStack::update(Component &parent, const std::array<float, 4> &value, int ind, int textwidth, bool autosize) {
         //get the template
         const ComponentTemplate &ctemp = parent.GetTemplate();
 
@@ -2212,11 +2236,11 @@
         parent.innersize = parent.size - cont.GetBorderSize();
         
         //if sizing is fixed and the size is 0 and clipping is on, nothing can be displayed
-        if(cont.GetClip() && cont.GetHorizontalSizing() == cont.Fixed && parent.innersize.Width <= 0) 
+        if(cont.GetClip() && cont.GetHorizontalSizing() == cont.Fixed && parent.innersize.Width <= 0 && !autosize) 
             return;
         
         //if sizing is fixed and the size is 0 and clipping is on, nothing can be displayed
-        if(cont.GetClip() && cont.GetVerticalSizing() == cont.Fixed && parent.innersize.Height <= 0) 
+        if(cont.GetClip() && cont.GetVerticalSizing() == cont.Fixed && parent.innersize.Height <= 0 && !autosize)
             return;
 
         //this function will loop through all components, including the repeats and calls the given
@@ -2587,7 +2611,10 @@
             
             
             //**** Automatic sizing
-            if((temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed)
+            if(
+                (temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed) ||
+                (parent.size.Width == 0 && autosize && temp.GetType() == ComponentType::Container && temp.GetSize().Width.IsRelative()) ||
+                (parent.size.Height == 0 && autosize && temp.GetType() == ComponentType::Container && temp.GetSize().Height.IsRelative())
             ) {
                 auto &st = *storage[&temp];
 
@@ -2600,19 +2627,19 @@
                         finalpass = true;
 
                     if(!size.Width.IsRelative() || stage==final) {
-                        int textwidth = -1;
+                        int tw = -1;
                         
                         //set the dimensions that are not fixed to 0.
-                        if(temp.GetHorizontalSizing() != ComponentTemplate::Fixed) {
-                            textwidth = comp.size.Width;
+                        if(parent.size.Width == 0 || temp.GetHorizontalSizing() != ComponentTemplate::Fixed) {
+                            tw = comp.size.Width ? comp.size.Width : textwidth;
                             comp.size.Width = 0;
                         }
                         
-                        if(temp.GetVerticalSizing() != ComponentTemplate::Fixed)
+                        if(parent.size.Height == 0 || temp.GetVerticalSizing() != ComponentTemplate::Fixed)
                             comp.size.Height = 0;
                         
                         //do an update
-                        update(comp, val, index, textwidth);
+                        update(comp, val, index, tw, true);
                     }
                 }
                 else if(temp.GetType() == ComponentType::Graphics) {
@@ -3261,7 +3288,9 @@
                 ;
                 
                 r += m.Right;
-                
+                if(comp.anchtoparent && IsCenter(comp.GetTemplate().GetMyAnchor()))
+                    r += m.Left;
+
                 if(w < r)
                     w = r;
             });
@@ -3285,6 +3314,8 @@
                 ;
                 
                 b += m.Bottom;
+                if(comp.anchtoparent && IsMiddle(comp.GetTemplate().GetMyAnchor()))
+                    b += m.Top;
                 
                 if(h < b) {
                     h = b;
--- a/Source/Gorgon/UI/ComponentStack.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/UI/ComponentStack.h	Fri Dec 04 12:40:22 2020 +0200
@@ -252,6 +252,20 @@
             }
         }
         
+        virtual void SetBounds(const Geometry::Bounds &bounds) override {
+            Resize(bounds.GetSize());
+            
+            Layer::Move(bounds.TopLeft());
+        }
+        
+        virtual Geometry::Bounds GetBounds() const override {
+            if(updaterequired) {
+                const_cast<ComponentStack*>(this)->update();
+            }
+            
+            return Layer::GetBounds();
+        }
+        
         /// Returns the template used by this stack
         const Template &GetTemplate() const {
             return temp;
@@ -400,18 +414,35 @@
         /// Removes the fixed size for a set tagged component
         void RemoveTagSize(ComponentTemplate::Tag tag) {
             tagsizes.erase(tag);
+            Update();
         }
         
         /// Enables text wrapping on a specific tag, default is enabled.
         void EnableTagWrap(ComponentTemplate::Tag tag) {
             tagnowrap.erase(tag);
+            Update();
         }
         
         /// Disables text wrapping on a specific tag, default is enabled.
         void DisableTagWrap(ComponentTemplate::Tag tag) {
             tagnowrap.insert(tag);
         }
+        
+        /// Sets whether the ComponentStack should be autosized. Autosize
+        /// uses the set size for text width.
+        void SetAutoSize(bool horizontal, bool vertical) {
+            if(autosize == std::make_pair(horizontal, vertical))
+                return;
+                
+            autosize = {horizontal, vertical};
+            Update();
+        }
 
+        /** @name Events
+         * These are events that can be handled
+         * 
+         * @{
+         */
 
         /// Sets a function to be called before update check
         void SetFrameEvent(std::function<void()> handler) {
@@ -453,6 +484,8 @@
             render_fn = std::function<void()>();
         }
         
+        /// @}
+        
         /** @name Mouse Events
         * These function will allow handling mouse events. If the mouse event is originating from a
         * substack, it will have a tag other than NoTag. If the tag for the substack is set NoTag,
@@ -553,7 +586,7 @@
         
         /// @}
 
-        
+        /// This event is fired when condition is changed.
         Event<ComponentStack> ConditionChanged;
         
         
@@ -588,7 +621,7 @@
         void update();
 
         ///updates a specific container component
-        void update(Component &parent, const std::array<float, 4> &value, int ind, int textwidth = -1);
+        void update(Component &parent, const std::array<float, 4> &value, int ind, int textwidth = -1, bool autosize = false);
 
         ///renders the given component, rendering will use parent layer if the component does not have its own layer. Index is for
         ///repeated components, it is the index of the repeat to be rendered. Unlike Layer::Render function, this function does not
@@ -676,7 +709,7 @@
         ///Dictates the speed which values reach to the target value. valuespeed = 0 disables animation
         std::array<float, 4> valuespeed = {{0.f, 0.f, 0.f, 0.f}};
         
-        ///??
+        ///Get value returns the target value if set the to true
         bool returntarget = false;
 
         ///Number of elements in each stack
@@ -690,6 +723,9 @@
         
         ///Whether component stack will be handling the mouse events
         bool handlingmouse = false;
+        
+        ///When set, component stack will resize itself to fit components.
+        std::pair<bool, bool> autosize = {false, false};
 
         ///Size of the component stack
         Geometry::Size size;
--- a/Source/Gorgon/UI/Organizers/Flow.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/UI/Organizers/Flow.h	Fri Dec 04 12:40:22 2020 +0200
@@ -103,7 +103,7 @@
         
         /// Returns the number of breaks at the given index.
         int BreakCount(int index) const {
-            return breaks.count(index);
+            return (int)breaks.count(index);
         }
         
         /// Removes all breaks in the organizer
--- a/Source/Gorgon/UI/Template.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/UI/Template.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -349,7 +349,37 @@
      * 
      */
 
-    PlaceholderTemplate& Template::AddPlaceholder(int index, ComponentCondition from, ComponentCondition to){ 
+
+
+
+    Template::Template(Template &&other) :
+        ChangedEvent(std::move(other.ChangedEvent)),
+        Name(std::move(other.Name)),
+        components(std::move(other.components)),
+        tokens(std::move(other.tokens)),
+        durations(std::move(other.durations)),
+        xsizing(std::move(other.xsizing)),
+        ysizing(std::move(other.ysizing)),
+        size(std::move(other.size)),
+        additional(std::move(other.additional)),
+        spacing(std::move(other.spacing)),
+        unitwidth(std::move(other.unitwidth)),
+        resizehandlesize(std::move(other.resizehandlesize))
+    {
+        auto token = tokens.begin();
+        for(auto &c : components) {
+            c.ChangedEvent.Unregister(*token);
+            token++;
+        }
+        tokens.clear();
+        for(auto &c : components) {
+            tokens.push_back(
+                c.ChangedEvent.Register(ChangedEvent, &Event<Template>::operator ())
+            );
+        }
+    }
+
+    PlaceholderTemplate& Template::AddPlaceholder(int index, ComponentCondition from, ComponentCondition to){
         auto obj = new PlaceholderTemplate();
         components.Add(obj);
         
--- a/Source/Gorgon/UI/Template.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/UI/Template.h	Fri Dec 04 12:40:22 2020 +0200
@@ -411,9 +411,10 @@
         Template() {
         }
 
-        Template(Template &&) = default;
+        //Move constructor. Moving is only allowed on construction
+        Template(Template &&other);
         
-        Template &operator =(Template &&) = default;
+        Template &operator =(Template &&) = delete;
 
         /// Destructor
         ~Template() {
@@ -632,6 +633,8 @@
         int spacing = 4;
         int unitwidth = 25;
         int resizehandlesize = -1;
+
+        //Do not forget to update move constructor!
     };
 
     /// Defines an object according to the Box Model.
--- a/Source/Gorgon/Widgets/Generator.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/Widgets/Generator.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -163,12 +163,17 @@
     
     void SimpleGenerator::UpdateBorders(bool smooth) {
         Border.Width  = (int)std::max(std::round(regularrenderer->GetLineThickness()*2.6f), 1.f);
-        ShapeBorder   = std::max(regularrenderer->GetLineThickness()*2.6f, 1.f);
+        ShapeBorder   = std::max((regularrenderer->GetLineThickness()+ObjectHeight/18.f)*1.3f, 1.f);
 
         //limit the thickness after 2.
         if(Border.Width > 2) {
             Border.Width = (int)std::max(std::round(regularrenderer->GetLineThickness()*2.4f), 1.f);
-            ShapeBorder  = std::max(regularrenderer->GetLineThickness()*2.4f, 1.f);
+        }
+        if(ShapeBorder > 2.f) {
+            ShapeBorder = std::max((regularrenderer->GetLineThickness()+ObjectHeight/18.f)*1.2f, 1.f);
+
+            if(ShapeBorder < 2.f)
+                ShapeBorder = 2.f;
         }
 
         ObjectBorder  = Border.Width;
@@ -594,7 +599,6 @@
         auto setupborder = [&](auto &anim, UI::ComponentCondition condition) {
             auto &bg = temp.AddContainer(1, condition);
             bg.Background.SetAnimation(anim);
-            bg.SetSize(100, 100, UI::Dimension::Percent);
             bg.SetPositioning(UI::ComponentTemplate::Absolute);
         };
 
@@ -607,7 +611,6 @@
             .AddIndex(3) //clip
             .AddIndex(4) //focus
         ;
-        boxed.SetSize(100, 100, UI::Dimension::Percent);
         boxed.SetBorderSize(Border.Width);
         boxed.SetPadding(std::max(Border.Radius / 2, Focus.Spacing));
         boxed.SetPositioning(UI::ComponentTemplate::Absolute);
@@ -617,18 +620,15 @@
         ;
         clip.SetClip(true);
         clip.SetPadding(Focus.Spacing + Focus.Width);
-        clip.SetSize(100, 100, UI::Dimension::Percent);
         
         //Contents
         auto &content = temp.AddContainer(5, UI::ComponentCondition::Always)
             .AddIndex(6) //icon
             .AddIndex(7) //text
         ;
-        content.SetSize(100, 100, UI::Dimension::Percent);
-        content.SetSize(100, 100, UI::Dimension::Percent);
-        content.SetSizing(UI::ComponentTemplate::Automatic);
         content.SetPositioning(UI::ComponentTemplate::Absolute);
         content.SetAnchor(UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter);
+        content.SetSizing(UI::ComponentTemplate::Automatic);
         
         //Icon container
         auto &iconcont = temp.AddContainer(6, UI::ComponentCondition::Icon1IsSet)
@@ -655,7 +655,6 @@
             txt.SetColor(color);
             txt.SetAnchor(UI::Anchor::MiddleRight, UI::Anchor::MiddleLeft, UI::Anchor::MiddleLeft);
             txt.SetDataEffect(UI::ComponentTemplate::Text);
-            txt.SetSize(100, 100, UI::Dimension::Percent);
             txt.SetSizing(UI::ComponentTemplate::ShrinkOnly);
         };
         
@@ -842,12 +841,12 @@
             //these coordinates are designed to look good across many different
             //sizes covering a wide range
             Geometry::PointList<Geometry::Pointf> tick ={
-                {ShapeBorder*2.4f, ObjectHeight/2.f},
-                {ObjectHeight*0.45f, ObjectHeight-ShapeBorder*2.4f},
-                {ObjectHeight-ShapeBorder*2.4f, ShapeBorder*2.4f}
+                {ShapeBorder*2.2f, ObjectHeight/2.f},
+                {ObjectHeight*0.45f, ObjectHeight-ShapeBorder*2.2f},
+                {ObjectHeight-ShapeBorder*2.4f, ShapeBorder*2.2f}
             };
             
-            if(ObjectHeight - ShapeBorder*4.8f < 3) {
+            if(ObjectHeight - ShapeBorder*4.6f < 3) {
                 CGI::Polyfill(*icon, Geometry::PointList<Geometry::Pointf>{
                     {ObjectBorder*2.f, ObjectBorder*2.f},
                     {ObjectHeight - ObjectBorder*2.f, ObjectBorder*2.f},
@@ -1020,7 +1019,7 @@
         state2.SetPositioning(UI::ComponentTemplate::Absolute);
         state2.SetAnchor(UI::Anchor::None, UI::Anchor::MiddleLeft, UI::Anchor::MiddleLeft);
         
-        float outer_r = ObjectHeight / 2.f - 0.5;
+        float outer_r = ObjectHeight / 2.f - 0.5f;
         int borderstart_r = int(ceil(outer_r - ObjectBorder));
         float inner_r = std::max(outer_r - ObjectBorder - std::max(Spacing / 2.f, 1.5f), 1.5f);
         
@@ -1753,8 +1752,8 @@
             
             Geometry::PointList<Geometry::Pointf> border;
             float off = 0;
-            float w = icon->GetWidth();
-            float h = icon->GetHeight()-off;
+            float w = (float)icon->GetWidth();
+            float h = (float)icon->GetHeight()-off;
             
             if(upwards) {   
                 border = {
@@ -1953,7 +1952,7 @@
             
             icon->Clear();
             
-            float off = ObjectBorder;
+            float off = (float)ObjectBorder;
             float s = float(bs);
             float mid = s/2.f;
             
--- a/Source/Gorgon/Widgets/Listbox.h	Sun Nov 29 16:21:07 2020 +0200
+++ b/Source/Gorgon/Widgets/Listbox.h	Fri Dec 04 12:40:22 2020 +0200
@@ -520,7 +520,7 @@
 
                 auto end() {
                     auto &me = dynamic_cast<F_ &>(l);
-                    return ItemIterator(me, l.selected, l.selected.size());
+                    return ItemIterator(me, l.selected, (long)l.selected.size());
                 }
 
                 auto begin() const {
@@ -530,7 +530,7 @@
 
                 auto end() const {
                     auto &me = dynamic_cast<F_ &>(l);
-                    return ConstItemIterator(me, l.selected, l.selected.size());
+                    return ConstItemIterator(me, l.selected, (long)l.selected.size());
                 }
 
             private:
@@ -1222,7 +1222,7 @@
             virtual ~LBSTR_STLVector() {}
             
             long getsize() const {
-                return storage.size();
+                return (long)storage.size();
             }
             
             T_ &getelm(long index) {
--- a/Testing/Source/Manual/UI_Component.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Testing/Source/Manual/UI_Component.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -1260,7 +1260,7 @@
     cont2.SetAnchor(Gorgon::UI::Anchor::None, Gorgon::UI::Anchor::TopLeft, Gorgon::UI::Anchor::TopLeft);
     cont2.SetPosition(0, 0, Gorgon::UI::Dimension::Percent);
     cont2.SetValueModification(Gorgon::UI::ComponentTemplate::ModifyPosition);
-    cont2.SetValueRange(0, 0.2, 0.8);
+    cont2.SetValueRange(0, 0.2f, 0.8f);
     
     
     
@@ -1369,7 +1369,7 @@
     cont2.SetPosition(0, 0, Gorgon::UI::Dimension::Percent);
     cont2.SetValueModification(Gorgon::UI::ComponentTemplate::ModifyPosition);
     cont2.SetValueOrdering(3, 0, 0, 0);
-    cont2.SetValueRange(0, 0.2, 0.8);
+    cont2.SetValueRange(0, 0.2f, 0.8f);
     
     auto &stack = *new ComponentStack(temp);
     
@@ -2198,7 +2198,7 @@
     
     layer.Add(stack);
     
-    stack.SetValue(0.2, 0.5);
+    stack.SetValue(0.2f, 0.5f);
     
     auto b = stack.TagBounds(Gorgon::UI::ComponentTemplate::LeftTag);
     
@@ -2229,7 +2229,7 @@
     
     layer.Add(stack);
     
-    stack.SetValue(0.2, 0.5);
+    stack.SetValue(0.2f, 0.5f);
     
     auto b = stack.TagBounds(Gorgon::UI::ComponentTemplate::LeftTag);
     
@@ -2777,6 +2777,7 @@
     , stack};
 }
 
+
 TestData test_anchacc(Layer &layer) {
     auto &temp = *new Template;
     temp.SetSize(60, 60);
@@ -2809,7 +2810,6 @@
     return {"Anchoring accuracy", "Size 10x20, 10x19 and 10x20 objects on a 60x60 white background, second could be 0 or 1px from the top, first and third should be touching to the top.", stack};
 }
 
-
 TestData test_ignored(Layer &layer) {
     auto &temp = *new Template;
     temp.SetSize(60, 60);
@@ -2846,6 +2846,434 @@
 }
 
 
+TestData test_autosizedstack(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetClip(true);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack simple", String::Concat((s.operator ==({20, 20}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 20x20 white background."), stack};
+}
+
+TestData test_autosizedstack_double(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(1)
+        .AddIndex(2)
+    ;
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetSize(20, 20);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetAnchor(Gorgon::UI::Anchor::BottomRight, Gorgon::UI::Anchor::TopLeft, Gorgon::UI::Anchor::TopLeft);
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont3.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    
+    auto s = stack.GetSize();
+
+    return {"Autosized stack double", String::Concat((s.operator ==({40, 40}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 40x40 white background with 20x20 green at top left, red at bottom right."), stack};
+}
+
+TestData test_autosizedstack_padding(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(20, 20);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(1)
+        .AddIndex(2)
+    ;
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetSize(20, 20);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetAnchor(Gorgon::UI::Anchor::BottomRight, Gorgon::UI::Anchor::TopLeft, Gorgon::UI::Anchor::TopLeft);
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont3.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    cont3.SetPosition(10, 10);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    
+    auto s = stack.GetSize();
+
+    return {"Autosized stack padding", String::Concat((s.operator ==({70, 70}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 70x70 white background with 20x20 green at top left, red at bottom right. green and red should not touch"), stack};
+}
+
+TestData test_autosizedstack_border(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(20, 20);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(1)
+        .AddIndex(2)
+    ;
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetBorderSize(10);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetSize(20, 20);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetAnchor(Gorgon::UI::Anchor::BottomRight, Gorgon::UI::Anchor::TopLeft, Gorgon::UI::Anchor::TopLeft);
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont3.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    cont3.SetPosition(10, 10);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    
+    auto s = stack.GetSize();
+
+    return {"Autosized stack border", String::Concat((s.operator ==({70, 70}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 70x70 white background with 20x20 green at top left, red at bottom right. green and red should not touch"), stack};
+}
+
+TestData test_autosizedstack_nested(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(10, 10);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(3)
+    ;
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetSize(20, 20);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetAnchor(Gorgon::UI::Anchor::BottomRight, Gorgon::UI::Anchor::TopLeft, Gorgon::UI::Anchor::TopLeft);
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont3.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+
+    auto &cont4 = temp.AddContainer(3, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(1)
+        .AddIndex(2)
+    ;
+    cont4.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    cont4.Background.SetAnimation(yellowimg());
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    
+    auto s = stack.GetSize();
+    
+    return {"Autosized stack nested", String::Concat((s.operator ==({60, 60}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 60x60 white background with 20x20 green at top left, red at bottom right, yellow at other corners."), stack};
+}
+
+TestData test_autosizedstack_text(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(100, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10);
+    
+    static Graphics::BitmapFont fnt;
+    fnt.SetGlyphSpacing(10);
+    fnt.AddGlyph('1', greenimg1x2());
+    fnt.AddGlyph('2', greenimg2x2());
+    fnt.SetLineGap(25);
+    fnt.SetBaseline(20);
+    fnt.SetHeight(20);
+    
+    auto &cont2 = temp.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetRenderer(fnt);
+    cont2.SetText("12");
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack text", String::Concat((s.operator ==({70, 45}) ? "Passed" : "Failed"), ". Size = ", s, ". Two green rectangles on 70x45 white background."), stack};
+}
+
+TestData test_autosizedstack_textnested(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(100, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.AddIndex(2);
+    
+    static Graphics::BitmapFont fnt;
+    fnt.SetGlyphSpacing(10);
+    fnt.AddGlyph('1', greenimg1x2());
+    fnt.AddGlyph('2', greenimg2x2());
+    fnt.SetLineGap(25);
+    fnt.SetBaseline(20);
+    fnt.SetHeight(20);
+    
+    auto &cont3 = temp.AddTextholder(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetRenderer(fnt);
+    cont3.SetText("12");
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack nested text", String::Concat((s.operator ==({70, 45}) ? "Passed" : "Failed"), ". Size = ", s, ". Two green rectangles on 70x45 white background."), stack};
+}
+
+TestData test_autosizedstack_textnested_sister(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(100, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(3);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.AddIndex(2);
+    
+    static Graphics::BitmapFont fnt;
+    fnt.SetGlyphSpacing(10);
+    fnt.AddGlyph('1', greenimg1x2());
+    fnt.AddGlyph('2', greenimg2x2());
+    fnt.SetLineGap(25);
+    fnt.SetBaseline(20);
+    fnt.SetHeight(20);
+    
+    auto &cont3 = temp.AddTextholder(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetRenderer(fnt);
+    cont3.SetText("12");
+    cont3.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+    
+    auto &cont4 = temp.AddContainer(3, Gorgon::UI::ComponentCondition::Always);
+    cont4.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
+    cont4.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    cont4.Background.SetAnimation(yellowimg());
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack nested text with a sister", String::Concat((s.operator ==({70, 45}) ? "Passed" : "Failed"), ". Size = ", s, ". Two green rectangles on 70x45 white background overlayed by a 50x25 yellow rectangle."), stack};
+}
+
+TestData test_autosizedstack_textdoublenested(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(100, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(5);
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.AddIndex(2);
+    cont2.SetPadding(5);
+    
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.AddIndex(3);
+    cont3.SetPadding(5);
+    
+    static Graphics::BitmapFont fnt;
+    fnt.SetGlyphSpacing(10);
+    fnt.AddGlyph('1', greenimg1x2());
+    fnt.AddGlyph('2', greenimg2x2());
+    fnt.SetLineGap(25);
+    fnt.SetBaseline(20);
+    fnt.SetHeight(20);
+    
+    auto &text = temp.AddTextholder(3, Gorgon::UI::ComponentCondition::Always);
+    text.SetRenderer(fnt);
+    text.SetText("12");
+    text.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack double nested text", String::Concat((s.operator ==({80, 55}) ? "Passed" : "Failed"), ". Size = ", s, ". Two green rectangles on 80x55 white background."), stack};
+}
+
+TestData test_autosizedstack_clip(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetClip(true);
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 20);
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack clipping", String::Concat((s.operator ==({20, 20}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 20x20 white background."), stack};
+}
+
+TestData test_autosizedstack_complex(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(100, 60);
+
+    auto &cont0 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont0.AddIndex(1);
+    cont0.AddIndex(2);
+    cont0.Background.SetAnimation(whiteimg());
+    
+    auto &cont1 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont1.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    
+    auto &cont2 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont2.AddIndex(3);
+    cont2.AddIndex(4);
+    cont2.SetPadding(3);
+    cont2.SetBorderSize(2);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    
+    auto &cont3 = temp.AddContainer(3, Gorgon::UI::ComponentCondition::Always);
+    cont3.AddIndex(5);
+    cont3.SetPadding(5);
+    cont3.SetClip(true);
+    
+    auto &cont5 = temp.AddContainer(5, Gorgon::UI::ComponentCondition::Always);
+    cont5.AddIndex(6);
+    cont5.AddIndex(7);
+    cont5.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+    cont5.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    cont5.SetAnchor(UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter);
+
+    auto &cont6 = temp.AddContainer(6, Gorgon::UI::ComponentCondition::Icon1IsSet);
+    
+    static Graphics::BitmapFont fnt;
+    fnt.SetGlyphSpacing(10);
+    fnt.AddGlyph('1', greenimg1x2());
+    fnt.AddGlyph('2', greenimg2x2());
+    fnt.SetLineGap(25);
+    fnt.SetBaseline(20);
+    fnt.SetHeight(20);
+    
+    auto &text = temp.AddTextholder(7, Gorgon::UI::ComponentCondition::Always);
+    text.SetRenderer(fnt);
+    text.SetText("12");
+    //text.SetSizing(Gorgon::UI::ComponentTemplate::Automatic);
+    
+    auto &cont4 = temp.AddContainer(4, Gorgon::UI::ComponentCondition::Always);
+    cont4.SetPadding(5);
+    cont4.SetPositioning(Gorgon::UI::ComponentTemplate::Absolute);
+    
+
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+    auto s = stack.GetSize();
+
+    return {"Autosized stack complex", String::Concat((s.operator ==({70, 45}) ? "Passed" : "Failed"), ". Size = ", s, ". Two green rectangles on 70x45 white background."), stack};
+}
+
+TestData test_autosizedstack_center(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(30, 30);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always)
+        .AddIndex(1)
+        .AddIndex(2)
+    ;
+    cont1.Background.SetAnimation(whiteimg());
+    cont1.SetPadding(10, 20);
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetSize(20, 30);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSizing(Gorgon::UI::ComponentTemplate::Fixed);
+    cont2.SetPositioning(Gorgon::UI::ComponentTemplate::Relative);
+    cont2.SetAnchor(UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter, UI::Anchor::MiddleCenter);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.SetAutoSize(true, true);
+
+    layer.Add(stack);
+
+    auto s = stack.GetSize();
+
+    return {"Autosized stack center aligned", String::Concat((s.operator ==({40, 70}) ? "Passed" : "Failed"), ". Size = ", s, ". Size 40x70 white background with 20x30 green at center"), stack};
+}
 
 std::vector<std::function<TestData(Layer &)>> tests = {
     //BEGIN layout
@@ -2974,9 +3402,26 @@
     &test_autosize_cont_text,
     //END
     
+    //BEGIN Autosized stack
+    &test_autosizedstack,
+    &test_autosizedstack_double,
+    &test_autosizedstack_padding,
+    &test_autosizedstack_border,
+    &test_autosizedstack_nested,
+    &test_autosizedstack_text,
+    &test_autosizedstack_textnested,
+    &test_autosizedstack_textnested_sister,
+    &test_autosizedstack_textdoublenested,
+    &test_autosizedstack_clip,
+    &test_autosizedstack_complex,
+    &test_autosizedstack_center,
+    //END
+    /*
+    //BEGIN Extra
     &test_anchacc,
     &test_ignored,
-    
+    //END
+    */
 };
 
 //END tests
--- a/Testing/Source/Manual/UI_Generate.cpp	Sun Nov 29 16:21:07 2020 +0200
+++ b/Testing/Source/Manual/UI_Generate.cpp	Fri Dec 04 12:40:22 2020 +0200
@@ -93,7 +93,7 @@
     ///Blank Panel & elements with Registry & Regulars
     /*Widgets::SimpleGenerator generator;
     generator.Density = 5;
-    generator.Init(9);
+    generator.Init(16, "freesans");
     generator.UpdateBorders();
     generator.Border.Width = 2;
     generator.Border.Radius = 4;

mercurial