* ComponentStack review 4/4 ComponentStackRework

Sun, 07 Jun 2020 12:05:24 +0300

author
cemkalyoncu
date
Sun, 07 Jun 2020 12:05:24 +0300
branch
ComponentStackRework
changeset 1404
2d9a7988d31f
parent 1403
a8e49fcb3d69
child 1405
ce87f9c3b7cc

* ComponentStack review 4/4
* ComponentStack rework part 1

Source/Gorgon/Graphics/Font.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/Graphics/Font.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Component.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/Dimension.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Template.h file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Graphics/Font.cpp	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/Graphics/Font.cpp	Sun Jun 07 12:05:24 2020 +0300
@@ -1048,7 +1048,7 @@
             [&](Glyph) { cur.Y += (int)std::round(renderer->GetLineGap() * vspace + pspace); if(maxx < cur.X) maxx = cur.X; cur.X = 0; }
         );
 
-        return{maxx > 0 ? maxx + 1 : 0, cur.Y + 1};
+        return{maxx > 0 ? maxx + 1 : 0, cur.Y > 0 ? (cur.Y + 1 - pspace + renderer->GetLineGap() * (1 - vspace)) : 0};
     }
     
     Geometry::Size StyledRenderer::GetSize(const std::string &text, int width) const {
@@ -1062,7 +1062,10 @@
         internal::boundedprint(
             *renderer, text.begin(), text.end(), tot,
             [&](Glyph eol, internal::markvecit begin, internal::markvecit end, int width) {            
-                y += (int)std::round(renderer->GetLineGap() * vspace + pspace);
+                y += (int)std::round(renderer->GetLineGap() * vspace);
+                if(eol != 0)
+                    y += pspace;
+                
                 if(width > maxx)
                     maxx = width;
 
@@ -1076,7 +1079,7 @@
             std::bind(&internal::dodefaulttab<int>, 0, std::placeholders::_1, tabwidth ? tabwidth : 16)
         );
 
-        return {maxx > 0 ? maxx + 1 : 0, y + 1};
+        return {maxx > 0 ? maxx + 1 : 0, y > 0 ?  y - pspace + renderer->GetLineGap() * (1 - vspace) + 1 : 0};
     }
     
     int StyledRenderer::GetCharacterIndex(const std::string &text, Geometry::Point location) const{ 
--- a/Source/Gorgon/Graphics/Font.h	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/Graphics/Font.h	Sun Jun 07 12:05:24 2020 +0300
@@ -213,6 +213,12 @@
         /// Returns the size of the EM dash
         virtual int GetEMSize() const = 0;
         
+        /// Get the distance of baseline from the top of the text
+        virtual float GetBaseLine() const = 0;
+        
+        /// Get the distance of baseline from the top of the text
+        virtual int GetHeight() const = 0;
+        
         /// Returns the size of the given text
         virtual Geometry::Size GetSize(const std::string &text) const = 0;
         
@@ -346,7 +352,15 @@
         virtual int GetEMSize() const override {
             return renderer->GetEMSize();
         }
-
+        
+        virtual float GetBaseLine() const override {
+            return renderer->GetBaseLine();
+        }
+        
+        virtual int GetHeight() const override {
+            return renderer->GetHeight();
+        }
+        
         virtual Geometry::Size GetSize(const std::string &text) const override;
         
         virtual Geometry::Size GetSize(const std::string &text, int width) const override;
@@ -719,6 +733,14 @@
             return renderer->GetEMSize();
         }
         
+        virtual float GetBaseLine() const override {
+            return renderer->GetBaseLine();
+        }
+        
+        virtual int GetHeight() const override {
+            return renderer->GetHeight();
+        }
+        
         virtual const GlyphRenderer &GetGlyphRenderer() const override {
             return *renderer;
         }
--- a/Source/Gorgon/UI/Component.h	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/UI/Component.h	Sun Jun 07 12:05:24 2020 +0300
@@ -21,16 +21,6 @@
             return *temp;
         }
         
-        static void Swap(Component &left, Component &right) {
-            using std::swap;
-            
-            swap(left.temp     , right.temp     );
-            swap(left.location , right.location );
-            swap(left.size     , right.size     );
-            swap(left.innersize, right.innersize);
-        }
-        
-
         Geometry::Point location = {0, 0};
         
         Geometry::Size size = {-1, -1};
--- a/Source/Gorgon/UI/ComponentStack.cpp	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/UI/ComponentStack.cpp	Sun Jun 07 12:05:24 2020 +0300
@@ -6,7 +6,8 @@
 
 #include "math.h"
 
-//NOTE if a transition does not exists, but it is in the stack, its completion will be counted as 100%
+//NOTE when does the condition for a 
+
 
 namespace Gorgon { namespace UI {
     
@@ -113,14 +114,22 @@
         //set our initial size
         Resize(size);
         
-        //search for emsize in textholders, use the first one found
+        //search for emsize in textholders, find the maximum ones to ensure 
+        //when the default is to be used as size, it will be able to contain
+        //any font within the stack.
         for(int i=0; i<temp.GetCount(); i++) {
             if(temp[i].GetType() == ComponentType::Textholder) {
                 const auto &th = dynamic_cast<const TextholderTemplate&>(temp[i]);
                 
                 if(th.IsReady()) {
-                    emsize = th.GetRenderer().GetEMSize();
-                    break;
+                    if(emsize < th.GetRenderer().GetEMSize())
+                        emsize = th.GetRenderer().GetEMSize();
+                    
+                    if(textheight < th.GetRenderer().GetHeight())
+                        textheight = th.GetRenderer().GetHeight();
+                    
+                    if(baseline < th.GetRenderer().GetBaseLine())
+                        baseline = th.GetRenderer().GetBaseLine();
                 }
             }
         }
@@ -1450,6 +1459,38 @@
         return emsize;
     }
 
+    int ComponentStack::getbaseline(const Component &comp) {
+        //if the component is a text holder
+        if(comp.GetTemplate().GetType() == ComponentType::Textholder) {
+            const auto &th = dynamic_cast<const TextholderTemplate&>(comp.GetTemplate());
+            
+            //and ready
+            if(th.IsReady()) {
+                //return its own em size
+                return th.GetRenderer().GetBaseLine();
+            }
+        }
+        
+        //otherwise return the global (first one found) emsize
+        return baseline;
+    }
+
+    int ComponentStack::gettextheight(const Component &comp) {
+        //if the component is a text holder
+        if(comp.GetTemplate().GetType() == ComponentType::Textholder) {
+            const auto &th = dynamic_cast<const TextholderTemplate&>(comp.GetTemplate());
+            
+            //and ready
+            if(th.IsReady()) {
+                //return its own em size
+                return th.GetRenderer().GetHeight();
+            }
+        }
+        
+        //otherwise return the global (first one found) emsize
+        return baseline;
+    }
+
     float ComponentStack::calculatevalue(const std::array<float, 4> &value, int channel, const Component &comp) const {
         //get the template
         const auto &temp = comp.GetTemplate();
@@ -1639,14 +1680,19 @@
         return nullptr;
     }
     
-    void anchortoparent(Component &comp, const ComponentTemplate &temp, 
+    ///Determines the location of the component in relation to its parent. 
+    void ComponentStack::anchortoparent(Component &comp, const ComponentTemplate &temp, 
                         Geometry::Point offset, Geometry::Margin margin, Geometry::Size maxsize) {
         
+        //anchor on the parent
         Anchor pa = temp.GetContainerAnchor();
+        //component anchor
         Anchor ca = temp.GetMyAnchor();
         
+        //parent anchor point and component anchor point
         Geometry::Point pp, cp;
         
+        //determine parent anchor point
         switch(pa) {
             default:
             case Anchor::TopLeft:
@@ -1663,8 +1709,11 @@
                 
                 
             case Anchor::MiddleLeft:
+                pp = {margin.Left, margin.Top - margin.Bottom + maxsize.Height / 2};
+                break;
+                
             case Anchor::FirstBaselineLeft:
-                pp = {margin.Left, margin.Top - margin.Bottom + maxsize.Height / 2};
+                pp = {margin.Left, -margin.Bottom + baseline};
                 break;
                 
             case Anchor::MiddleCenter:
@@ -1672,14 +1721,19 @@
                 break;
                 
             case Anchor::MiddleRight:
-            case Anchor::FirstBaselineRight:
                 pp = { -margin.Right + maxsize.Width, margin.Top - margin.Bottom + maxsize.Height / 2};
                 break;
                 
+            case Anchor::FirstBaselineRight:
+                pp = {-margin.Right + maxsize.Width, -margin.Bottom + baseline};
+                break;
                 
             case Anchor::BottomLeft:
+                pp = {margin.Left, -margin.Bottom + maxsize.Height};
+                break;
+                
             case Anchor::LastBaselineLeft:
-                pp = {margin.Left, -margin.Bottom + maxsize.Height};
+                pp = {margin.Left, -margin.Bottom + maxsize.Height - textheight + baseline};
                 break;
                 
             case Anchor::BottomCenter:
@@ -1687,44 +1741,19 @@
                 break;
                 
             case Anchor::BottomRight:
+                pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height};
+                break;
+                
             case Anchor::LastBaselineRight:
-                pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height};
+                pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height - textheight + baseline};
                 break;
                 
         }
         
+        //component size
         auto csize = comp.size;
         
-        if(temp.GetType() == ComponentType::Textholder && 
-            (ca == Anchor::FirstBaselineLeft || ca == Anchor::FirstBaselineRight || ca == Anchor::LastBaselineLeft || ca == Anchor::LastBaselineRight)
-        ) {
-            const auto &th = dynamic_cast<const TextholderTemplate&>(temp);
-            
-            if(th.IsReady()) {
-                
-                switch(ca) {
-                    case Anchor::FirstBaselineLeft:
-                        cp = {-offset.X, int(-offset.Y-th.GetRenderer().GetGlyphRenderer().GetBaseLine())};
-                        break;
-                        
-                    case Anchor::FirstBaselineRight:
-                        cp = {-offset.X + csize.Width, int(-offset.Y-th.GetRenderer().GetGlyphRenderer().GetBaseLine())};
-                        break;
-                        
-                    case Anchor::LastBaselineLeft:
-                        cp = {-offset.X, int(offset.Y+th.GetRenderer().GetGlyphRenderer().GetBaseLine()-th.GetRenderer().GetGlyphRenderer().GetHeight()-csize.Height)};
-                        break;
-                        
-                    case Anchor::LastBaselineRight:
-                        cp = {-offset.X + csize.Width, int(offset.Y+th.GetRenderer().GetGlyphRenderer().GetBaseLine()-th.GetRenderer().GetGlyphRenderer().GetHeight()-csize.Height)};
-                        break;
-                    default: ;//to silence warnings
-                }
-                
-                ca = Anchor::None;
-            }
-        }
-        
+        //determine where the anchor point is on the component
         switch(ca) {
             default:
             case Anchor::TopLeft:
@@ -1741,8 +1770,11 @@
                 
                 
             case Anchor::MiddleLeft:
+                cp = {-offset.X, csize.Height / 2 - offset.Y};
+                break;
+                
             case Anchor::FirstBaselineLeft:
-                cp = {-offset.X, csize.Height / 2 - offset.Y};
+                cp = {-offset.X, getbaseline(comp) - offset.Y};
                 break;
                 
             case Anchor::MiddleCenter:
@@ -1750,31 +1782,41 @@
                 break;
                 
             case Anchor::MiddleRight:
+                cp = { offset.X + csize.Width, csize.Height / 2 - offset.Y};
+                break;
+
             case Anchor::FirstBaselineRight:
-                cp = { offset.X + csize.Width, csize.Height / 2 - offset.Y};
+                cp = {offset.X + csize.Width, getbaseline(comp) - offset.Y};
                 break;
                 
                 
             case Anchor::BottomLeft:
-            case Anchor::LastBaselineLeft:
                 cp = {-offset.X, csize.Height + offset.Y};
                 break;
-                
+
+            case Anchor::LastBaselineLeft:
+                cp = {-offset.X, csize.Height - gettextheight(comp) + getbaseline(comp) + offset.Y};
+                break;
+
             case Anchor::BottomCenter:
                 cp = {-offset.X + csize.Width / 2, csize.Height + offset.Y};
                 break;
                 
             case Anchor::BottomRight:
+                cp = { offset.X + csize.Width, csize.Height + offset.Y};
+                break;
+                
             case Anchor::LastBaselineRight:
-                cp = { offset.X + csize.Width, csize.Height + offset.Y};
+                cp = {offset.X + csize.Width, csize.Height - gettextheight(comp) + getbaseline(comp) + offset.Y};
                 break;
                 
         }
         
+        //calculate the final offset
         comp.location = pp - cp;
     }
 
-    void anchortoother(Component &comp, const ComponentTemplate &temp, 
+    void ComponentStack::anchortoother(Component &comp, const ComponentTemplate &temp, 
                         Geometry::Point offset, Geometry::Margin margin, Component &other, Graphics::Orientation orientation) {
         
         Anchor pa = temp.GetPreviousAnchor();
@@ -1957,543 +1999,614 @@
     }
     
     void ComponentStack::update() {
-        if(!stacksizes[0]) return;
-        
+        //honor before update notification
         if(beforeupdate_fn)
             beforeupdate_fn();
-        
-        get(0).size = size;
-        get(0).location = {0,0};
-        get(0).parent = -1;
-        
-        //update repeat counts
-        for(auto &r : repeated) {
-            if(repeats.count(r.first->GetRepeatMode()))
-                r.second.resize(repeats[r.first->GetRepeatMode()].size(), Component(*r.first));
+
+        //clear everything
+        base.Clear();
+        for(auto &s : storage) {
+            if(s.second->layer)
+                s.second->layer->Hide();
         }
         
-        //calculate common emsize        
-        for(int i=0; i<indices; i++) {
-            if(stacksizes[i] > 0) {
-                if(get(i).GetTemplate().GetType() == ComponentType::Textholder) {
-                    const auto &th = dynamic_cast<const TextholderTemplate&>(get(i).GetTemplate());
-                    
-                    if(th.IsReady()) {
-                        emsize = th.GetRenderer().GetEMSize();
-                        break;
+        //update is no more required, set beforehand so that
+        //if necessary can be set again during update to
+        //run update next frame
+        updaterequired = false;
+
+        //if root has something to be displayed
+        if(stacksizes[0]) {
+            //initial states
+            get(0).size = size;
+            get(0).location = {0,0};
+            get(0).parent = -1;
+            
+            //update the component storage for repeated components
+            for(auto &r : repeated) {
+                r.second.resize(
+                    repeats[r.first->GetRepeatMode()].size(), //size will be number of repeats
+                    Component(*r.first) //the components will be instantiated from the repeat template
+                );
+            }
+            
+            //search for emsize in textholders, find the maximum ones to ensure 
+            //when the default is to be used as size, it will be able to contain
+            //any font within the stack.
+            for(int i=0; i<indices; i++) {
+                if(stacksizes[i] > 0) {
+                    if(get(i).GetTemplate().GetType() == ComponentType::Textholder) {
+                        const auto &th = dynamic_cast<const TextholderTemplate&>(get(i).GetTemplate());
+                        
+                        if(th.IsReady()) {
+                            if(emsize < th.GetRenderer().GetEMSize())
+                                emsize = th.GetRenderer().GetEMSize();
+                            
+                            if(textheight < th.GetRenderer().GetHeight())
+                                textheight = th.GetRenderer().GetHeight();
+                            
+                            if(baseline < th.GetRenderer().GetBaseLine())
+                                baseline = th.GetRenderer().GetBaseLine();
+                        }
                     }
                 }
             }
+            
+            //start the update from the root
+            update(get(0));
         }
         
-        update(get(0));
-        
-        updaterequired = false;
+        //update is complete
+        if(update_fn)
+            update_fn();
         
-        base.Clear();
-        for(auto &s : storage) 
-            if(s.second->layer)
-                s.second->layer->Hide();
-            
-            if(update_fn)
-                update_fn();
-            
+        //if root has something to be displayed
+        if(stacksizes[0]) {
             //draw everything
             render(get(0), base, {0,0});
+        }
         
+        //this is called after the render
         if(render_fn)
             render_fn();
     }
     
+    int calculatemargin(int l, int r) {
+        if(l<0 || r<0)
+            return l+r;
+        else
+            return std::max(l, r);
+    }
+    
     //location depends on the container location
     void ComponentStack::update(Component &parent) {
+        //get the template
         const ComponentTemplate &ctemp = parent.GetTemplate();
 
-        if(ctemp.GetType() != ComponentType::Container) return;
+        //just in case
+        ASSERT(ctemp.GetType() == ComponentType::Container, "Only containers are needed to be updated") ;
 
+        //get the container
         const ContainerTemplate &cont = dynamic_cast<const ContainerTemplate&>(ctemp);
         
+        //we need the innersize to arrange components
         parent.innersize = parent.size - cont.GetBorderSize();
         
-        if(cont.GetHorizontalSizing() == cont.Fixed && parent.innersize.Width <= 0) return;
-        if(cont.GetVerticalSizing() == cont.Fixed && parent.innersize.Height <= 0) return;
+        //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) 
+            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) 
+            return;
+
+        //this function will loop through all components, including the repeats and calls the given
+        //function for each component
+        auto forallcomponents = [&](auto fn) {
+            for(int i=0; i<cont.GetCount(); i++) {
+                
+                //get the component index
+                int ci = cont[i];
+
+                //just in case
+                if(ci >= indices) continue;
+                
+                //if empty, this index is not currently available
+                //this is not an edge case
+                if(!stacksizes[ci]) continue;
+
+                //original component, used to distinguish from repeats
+                auto &comporg = get(cont[i]);
 
+                //original template
+                const auto &temporg = comporg.GetTemplate();
+                
+                
+                for(int j = 0; 
+                    temporg.GetRepeatMode() == temporg.NoRepeat ? //if not repeating
+                        j == 0 : //only do this once
+                        repeats.count(temporg.GetRepeatMode()) && j < repeats[temporg.GetRepeatMode()].size(); //if not, repeat for every repeat
+                    j++) 
+                {
+                    Component *compptr;
+                    const ComponentTemplate *tempptr;
+                    
+                    //stores the reference value for this component
+                    const std::array<float, 4> *val;
+
+                    //if not to be repeated
+                    if(temporg.GetRepeatMode() == temporg.NoRepeat) {
+                        //use originals
+                        compptr = &comporg;
+                        tempptr = &temporg;
+                        val     = &value;
+                    }
+                    else {
+                        //get the repeated component
+                        compptr = &repeated[&temporg][j];
+                        
+                        //determine condition of the repeat, default is always
+                        ComponentCondition rc = ComponentCondition::Always;
+
+                        //if condition is set
+                        if(repeatconditions[temporg.GetRepeatMode()].count(j))
+                            rc = repeatconditions[temporg.GetRepeatMode()][j]; //use it
+
+                        //get the template depending on the condition
+                        tempptr = &get(ci, rc).GetTemplate();
+                        val     = &repeats[temporg.GetRepeatMode()][j];
+                    }
+                    
+                    //call the function
+                    fn(*compptr, *tempptr, *val, getemsize(*compptr));
+                }
+            }
+        };
+        
+        //whether there is something requires a second pass
         bool requiresrepass = false;
+        
+        //when repass is done, it will be repeated
         bool repassdone = false;
         
+        //space left after the absolutely sized components are placed, will be used for percentage based
+        //components
         int spaceleft = 0;
-
+        
+        //for easy access
+        auto ishor = cont.GetOrientation() == Graphics::Orientation::Horizontal;
+        
 realign:
-        // first pass for size, second pass will cover the sizes that are percent based.
-        for(int i=0; i<cont.GetCount(); i++) {
-            
-            int ci = cont[i];
-
-            if(ci >= indices) continue;
-            if(!stacksizes[ci]) continue;
-
-
-            auto &compparent = get(cont[i]);
-
-            const auto &tempparent = compparent.GetTemplate();
-            
-            
-            for(int j = 0; tempparent.GetRepeatMode() == tempparent.NoRepeat ? j == 0 : repeats.count(tempparent.GetRepeatMode()) && j < repeats[tempparent.GetRepeatMode()].size(); j++) {
-                Component *compptr;
-                const ComponentTemplate *tempptr;
-
-                const std::array<float, 4> *val;
-
-                if(tempparent.GetRepeatMode() == tempparent.NoRepeat) {
-                    compptr = &compparent;
-                    tempptr = &tempparent;
-                    val     = &value;
+        // first operation is for size. Second pass will cover the sizes that are percent based.
+        forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &val, int emsize) {
+            //set the index to be accessed later
+            comp.parent = cont.GetIndex();
+    
+            //******************************** very dubious max size depends on where the component is anchored to
+            auto parentmargin = Convert(
+                temp.GetMargin(), parent.innersize, emsize
+                ).CombinePadding(
+                    Convert(cont.GetPadding(), parent.size, emsize)
+                ) + 
+                Convert(temp.GetIndent(), parent.innersize, emsize);
+        
+            auto maxsize = parent.innersize - parentmargin;
+        
+            if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) {
+                if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
+                    maxsize.Width = spaceleft - parentmargin.TotalX();
+                    if(maxsize.Width < 0) 
+                        maxsize.Width = 0;
                 }
                 else {
-                    compptr = &repeated[&tempparent][j];
-                    ComponentCondition rc = ComponentCondition::Always;
-
-                    if(repeatconditions[tempparent.GetRepeatMode()].count(j))
-                        rc = repeatconditions[tempparent.GetRepeatMode()][j];
-
-                    tempptr = &get(ci, rc).GetTemplate();
-                    val     = &repeats[tempparent.GetRepeatMode()][j];
+                    maxsize.Height = spaceleft - parentmargin.TotalY();
+                    if(maxsize.Height < 0) 
+                        maxsize.Height = 0;
                 }
-
-                auto &comp = *compptr;
-                const auto &temp = *tempptr;
-
-                comp.parent = cont.GetIndex();
-
-                //check if textholder and if so use emsize from the font
-                int emsize = getemsize(comp);
+            }
+            //**************************************
+            
         
-                auto parentmargin = Convert(
-                        temp.GetMargin(), parent.innersize, emsize
-                    ).CombinePadding(
-                        Convert(cont.GetPadding(), parent.size, emsize)
-                    ) + 
-                    Convert(temp.GetIndent(), parent.innersize, emsize);
+            auto size = temp.GetSize();
             
-                auto maxsize = parent.innersize - parentmargin;
-            
-                if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) {
+            //********** simplify this.
+            if(temp.GetValueModification() == temp.ModifySize) {
+                if(NumberOfSetBits(temp.GetValueSource()) == 1) {
                     if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                        maxsize.Width = spaceleft - parentmargin.TotalX();
-                        if(maxsize.Width < 0) 
-                            maxsize.Width = 0;
+                        size = {
+                            {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, 
+                            size.Height
+                        };
                     }
                     else {
-                        maxsize.Height = spaceleft - parentmargin.TotalY();
-                        if(maxsize.Height < 0) 
-                            maxsize.Height = 0;
-                    }
-                }
-            
-                auto size = temp.GetSize();
-            
-            
-                if(temp.GetValueModification() == temp.ModifySize) {
-                    if(NumberOfSetBits(temp.GetValueSource()) == 1) {
-                        if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                            size = {
-                                {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, 
-                                size.Height
-                            };
-                        }
-                        else {
-                            size = {
-                                size.Width, 
-                                {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}
-                            };
-                        }
-                    }
-                    else {
-                        size ={
-                            {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, 
-                            {int(calculatevalue(*val, 1, comp)*10000), Dimension::BasisPoint}
+                        size = {
+                            size.Width, 
+                            {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}
                         };
                     }
                 }
-                else if(temp.GetValueModification() == temp.ModifyWidth) {
-                    size ={{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, size.Height};
-                }
-                else if(temp.GetValueModification() == temp.ModifyHeight) {
-                    size ={size.Width, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}};
-                }
-                
-                if(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) {
-                    auto minimum = Convert(temp.GetSize(), maxsize, emsize);
-                    
-                    comp.size = Convert(size, maxsize - minimum, emsize) + minimum;
-                }
-                else if(temp.GetValueModification() == temp.ModifyWidth || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Horizontal)) {
-                    auto minimum = Convert(temp.GetSize(), maxsize, emsize);
-                                        
-                    comp.size = Convert(size, {maxsize.Width - minimum.Width, maxsize.Height}, emsize) + Geometry::Size(minimum.Width, 0);
-                }
-                else if(temp.GetValueModification() == temp.ModifyHeight || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Vertical)) {
-                    auto minimum = Convert(temp.GetSize(), maxsize, emsize);
-                                        
-                    comp.size = Convert(size, {maxsize.Width, maxsize.Height - minimum.Height}, emsize) + Geometry::Size(0, minimum.Height);
-                }
-                else if(tagsizes.count(temp.GetTag())) {
-                    comp.size = tagsizes[temp.GetTag()];
-                }
                 else {
-                    comp.size = Convert(size, maxsize, emsize);
-                }
-                
-                if(
-                    (temp.GetPositioning() == temp.Relative || temp.GetPositioning() == temp.AbsoluteSliding) && 
-                    (
-                        (cont.GetOrientation() == Graphics::Orientation::Horizontal && 
-                            (size.Width.GetUnit() == Dimension::Percent || size.Width.GetUnit() == Dimension::BasisPoint)) ||
-                        (cont.GetOrientation() == Graphics::Orientation::Vertical && 
-                            (size.Height.GetUnit() == Dimension::Percent || size.Height.GetUnit() == Dimension::BasisPoint))
-                    )
-                )
-                    requiresrepass = true;
-                
-                if(!(tagsizes.count(temp.GetTag())) && 
-                    (temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed) &&
-                   !(temp.GetValueModification() == temp.ModifySize &&  NumberOfSetBits(temp.GetValueSource()) > 1)
-                ) {
-                    auto &st = *storage[&temp];
-
-                    auto orgsize = comp.size;
-
-                    if(temp.GetType() == ComponentType::Container) {
-                        comp.size = {0, 0};
-                        update(comp);
-                    }
-                    else if(temp.GetType() == ComponentType::Graphics) {
-                        if(st.primary) {
-                            auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary);
-                            if(rectangular)
-                                comp.size = rectangular->GetSize() + dynamic_cast<const GraphicsTemplate&>(temp).GetPadding();
-                        }
-                        else {
-                            comp.size = dynamic_cast<const GraphicsTemplate&>(temp).GetPadding().Total();
-                        }
-                    }
-                    else if(temp.GetType() == ComponentType::Textholder) {
-                        const auto &th = dynamic_cast<const TextholderTemplate&>(temp);
-
-                        if(th.IsReady() && stringdata[temp.GetDataEffect()] != "") {
-                            auto s = size.Width(maxsize.Width, emsize);
-                            
-                            if(tagnowrap.count(temp.GetTag()))
-                                s = 0;
-
-                            if(s > 0)
-                                comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()], s);
-                            else
-                                comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()]);
-
-                        }
-                    }
-                    else if(temp.GetType() == ComponentType::Placeholder) {
-                        const auto &ph = dynamic_cast<const PlaceholderTemplate&>(temp);
-
-                        if(imagedata.Exists(ph.GetDataEffect())) {
-                            auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(&imagedata[ph.GetDataEffect()]);
-                            if(rectangular) {
-                                comp.size = rectangular->GetSize();
-                            }
-                        }
-                        else {
-                            comp.size = {0, 0};
-                        }
-                    }
-
-                    if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) {
-                        if(comp.size.Width < orgsize.Width)
-                            comp.size.Width = orgsize.Width;
-                    }
-                    else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) {
-                        if(comp.size.Width > orgsize.Width)
-                            comp.size.Width = orgsize.Width;
-                    }
-
-                    if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) {
-                        if(comp.size.Height < orgsize.Height)
-                            comp.size.Height = orgsize.Height;
-                    }
-                    else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) {
-                        if(comp.size.Height > orgsize.Height)
-                            comp.size.Height = orgsize.Height;
-                    }
-
-                    if(temp.GetValueModification() == temp.ModifySize) {
-                        if(cont.GetOrientation() == Graphics::Orientation::Horizontal)
-                            comp.size.Width = orgsize.Width;
-                        else
-                            comp.size.Height = orgsize.Height;
-                    }
-                    else if(temp.GetValueModification() == temp.ModifyWidth) {
-                        comp.size.Width = orgsize.Width;
-                    }
-                    else if(temp.GetValueModification() == temp.ModifyHeight) {
-                        comp.size.Height = orgsize.Height;
-                    }
-
-                    if(
-                        (cont.GetOrientation() == Graphics::Orientation::Horizontal &&
-                        (size.Width.GetUnit() == Dimension::Percent || size.Width.GetUnit() == Dimension::BasisPoint)) ||
-                        (cont.GetOrientation() == Graphics::Orientation::Vertical &&
-                        (size.Height.GetUnit() == Dimension::Percent || size.Height.GetUnit() == Dimension::BasisPoint))
-                        )
-                    {
-                        if(maxsize.Width == 0)
-                            comp.size.Width = 0;
-                        if(maxsize.Height == 0)
-                            comp.size.Height = 0;
-                    }
-
-                    if(comp.size.Width < 0)
-                        comp.size.Width = 0;
-                    if(comp.size.Height < 0)
-                        comp.size.Height = 0;
+                    size ={
+                        {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, 
+                        {int(calculatevalue(val, 1, comp)*10000), Dimension::BasisPoint}
+                    };
                 }
             }
-        }
-
-        Component *prev = nullptr, *next = nullptr;
-
-        //second pass will align everything
-        for(int i=0; i<cont.GetCount(); i++) {
-            
-            int ci = cont[i];
-
-            if(ci >= indices) continue;
-            if(!stacksizes[ci]) continue;
-
-
-            auto &compparent = get(cont[i]);
-            
-            const auto &temp = compparent.GetTemplate();
-
-            for(int j = 0; temp.GetRepeatMode() == temp.NoRepeat ? j == 0 : repeats.count(temp.GetRepeatMode()) && j < repeats[temp.GetRepeatMode()].size(); j++) {
-                Component *compptr;
-                const std::array<float, 4> *val;
-
-                if(temp.GetRepeatMode() == temp.NoRepeat) {
-                    compptr = &compparent;
-                    val     = &value;
-                }
-                else {
-                    compptr = &repeated[&temp][j];
-                    val     = &repeats[temp.GetRepeatMode()][j];
-                }
-
-                auto &comp = *compptr;
-
-                //check if textholder and if so use emsize from the font
-                int emsize = getemsize(comp);
-            
-                //check anchor object by observing temp.GetPreviousAnchor and direction
-                Component *anch = nullptr;
+            else if(temp.GetValueModification() == temp.ModifyWidth) {
+                size ={{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, size.Height};
+            }
+            else if(temp.GetValueModification() == temp.ModifyHeight) {
+                size ={size.Width, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}};
+            }
             
             
-                //if absolute, nothing to anchor to but to parent
-                if(temp.GetPositioning() == temp.Relative && temp.GetPreviousAnchor() != Anchor::None) {
-                    if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                        if((IsLeft(temp.GetPreviousAnchor()) && IsRight(temp.GetMyAnchor())) || 
-                            (temp.GetPreviousAnchor() == Anchor::None && IsRight(temp.GetContainerAnchor()))) 
-                        {
-                            anch = prev;
-                            comp.anchorotherside = true;
-                        }
-                        else {
-                            anch = next;
+            //****** combine with above
+            if(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) {
+                auto minimum = Convert(temp.GetSize(), maxsize, emsize);
+                
+                comp.size = Convert(size, maxsize - minimum, emsize) + minimum;
+            }
+            else if(temp.GetValueModification() == temp.ModifyWidth || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Horizontal)) {
+                auto minimum = Convert(temp.GetSize(), maxsize, emsize);
+                                    
+                comp.size = Convert(size, {maxsize.Width - minimum.Width, maxsize.Height}, emsize) + Geometry::Size(minimum.Width, 0);
+            }
+            else if(temp.GetValueModification() == temp.ModifyHeight || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Vertical)) {
+                auto minimum = Convert(temp.GetSize(), maxsize, emsize);
+                                    
+                comp.size = Convert(size, {maxsize.Width, maxsize.Height - minimum.Height}, emsize) + Geometry::Size(0, minimum.Height);
+            }
+            else if(tagsizes.count(temp.GetTag())) {
+                comp.size = tagsizes[temp.GetTag()]; //********* this should be combined with regular size + modified size
+            }
+            else {
+                comp.size = Convert(size, maxsize, emsize);
+            }
+            
+            if( //if positioning is not free form
+                (temp.GetPositioning() == temp.Relative || temp.GetPositioning() == temp.AbsoluteSliding) && 
+                ( //and size along the orientation depends on the remaining size
+                    (cont.GetOrientation() == Graphics::Orientation::Horizontal && size.Width.IsRelative() ) ||
+                    (cont.GetOrientation() == Graphics::Orientation::Vertical   && size.Height.IsRelative())
+                )
+            )  //this component requires a repass
+                requiresrepass = true;
+            
+            if(!(tagsizes.count(temp.GetTag())) && 
+                (temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed) &&
+                !(temp.GetValueModification() == temp.ModifySize &&  NumberOfSetBits(temp.GetValueSource()) > 1)
+            ) {
+                auto &st = *storage[&temp];
+
+                auto orgsize = comp.size;
+
+                if(temp.GetType() == ComponentType::Container) {
+                    comp.size = {0, 0};
+                    update(comp);
+                }
+                else if(temp.GetType() == ComponentType::Graphics) {
+                    if(st.primary) {
+                        auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary);
+                        if(rectangular)
+                            comp.size = rectangular->GetSize() + dynamic_cast<const GraphicsTemplate&>(temp).GetPadding();
+                    }
+                    else {
+                        comp.size = dynamic_cast<const GraphicsTemplate&>(temp).GetPadding().Total();
+                    }
+                }
+                else if(temp.GetType() == ComponentType::Textholder) {
+                    const auto &th = dynamic_cast<const TextholderTemplate&>(temp);
+
+                    if(th.IsReady() && stringdata[temp.GetDataEffect()] != "") {
+                        auto s = size.Width(maxsize.Width, emsize);
+                        
+                        if(tagnowrap.count(temp.GetTag()))
+                            s = 0;
+
+                        if(s > 0)
+                            comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()], s);
+                        else
+                            comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()]);
+
+                    }
+                }
+                else if(temp.GetType() == ComponentType::Placeholder) {
+                    const auto &ph = dynamic_cast<const PlaceholderTemplate&>(temp);
+
+                    if(imagedata.Exists(ph.GetDataEffect())) {
+                        auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(&imagedata[ph.GetDataEffect()]);
+                        if(rectangular) {
+                            comp.size = rectangular->GetSize();
                         }
                     }
                     else {
-                        if((IsTop(temp.GetPreviousAnchor()) && IsBottom(temp.GetMyAnchor())) || 
-                            (temp.GetPreviousAnchor() == Anchor::None && IsBottom(temp.GetContainerAnchor()))) 
-                        {
-                            anch = prev;
-                            comp.anchorotherside = true;
-                        }
-                        else {
-                            anch = next;
-                        }
-                    }
-                }
-            
-                auto parentmargin = Convert(temp.GetMargin(), parent.innersize, emsize).CombinePadding(Convert(cont.GetPadding(), parent.size, emsize)) + Convert(temp.GetIndent(), parent.innersize, emsize);
-            
-                Geometry::Margin margin;
-            
-                if(anch) {
-                    margin = Convert(temp.GetMargin(), parent.innersize, emsize).CombineMargins(Convert(anch->GetTemplate().GetMargin(), parent.innersize, emsize));
-                }
-                else {
-                    margin = parentmargin;
-                }
-            
-                auto maxsize = parent.innersize - parentmargin;
-            
-                auto pos = temp.GetPosition();
-            
-                if(temp.GetValueModification() == temp.ModifyPosition) {
-                    if(NumberOfSetBits(temp.GetValueSource()) == 1) {
-                        if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                            pos = {{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y};
-                        }
-                        else {
-                            pos = {pos.X, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}};
-                        }
-                    }
-                    else {
-                        pos ={{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, {int(calculatevalue(*val, 1, comp)*10000), Dimension::BasisPoint}};
-                    }
-                }
-                else if(temp.GetValueModification() == temp.ModifyX) {
-                    pos = {{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y};
-                }
-                else if(temp.GetValueModification() == temp.ModifyY) {
-                    pos = {pos.X, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}};
-                }
-                else if(taglocations.count(temp.GetTag())) {
-                    pos = {taglocations[temp.GetTag()]};
-                }
-                
-                if(temp.GetPositioning() == temp.PolarAbsolute) {
-                    auto pcenter = Geometry::Pointf(cont.GetCenter().X.CalculateFloat((float)maxsize.Width, (float)emsize), cont.GetCenter().Y.CalculateFloat((float)maxsize.Height, (float)emsize));
-                    auto center  = Geometry::Pointf(temp.GetCenter().X.CalculateFloat((float)comp.size.Width, (float)emsize), temp.GetCenter().Y.CalculateFloat((float)comp.size.Height, (float)emsize));
-
-                    pcenter += parentmargin.TopLeft();
-
-                    auto r = pos.X.CalculateFloat(Geometry::Point(maxsize).Distance()/(float)sqrt(2), (float)emsize);
-
-                    auto a = pos.Y.CalculateFloat(360, PI);
-
-                    a *= PI / 180.0f;
-
-                    comp.location = {int(std::round(r * cos(a) + pcenter.X - center.X)), int(std::round(r * sin(a) + pcenter.Y - center.Y))};
-                }
-                else {
-                    auto offset = Convert(pos, (temp.GetPositioning() == temp.AbsoluteSliding ?  maxsize - comp.size : comp.size), emsize);
-            
-                    if(anch) {
-                        anchortoother(comp, temp, offset, margin, *anch, cont.GetOrientation());
-                    }
-                    else {
-                        anchortoparent(comp, temp, offset, margin, parent.innersize);
+                        comp.size = {0, 0};
                     }
                 }
 
-                //Which anchor side is to be changed
-                if(temp.GetPositioning() == temp.Relative) {
+                if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) {
+                    if(comp.size.Width < orgsize.Width)
+                        comp.size.Width = orgsize.Width;
+                }
+                else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) {
+                    if(comp.size.Width > orgsize.Width)
+                        comp.size.Width = orgsize.Width;
+                }
+
+                if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) {
+                    if(comp.size.Height < orgsize.Height)
+                        comp.size.Height = orgsize.Height;
+                }
+                else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) {
+                    if(comp.size.Height > orgsize.Height)
+                        comp.size.Height = orgsize.Height;
+                }
+
+                if(temp.GetValueModification() == temp.ModifySize) {
+                    if(cont.GetOrientation() == Graphics::Orientation::Horizontal)
+                        comp.size.Width = orgsize.Width;
+                    else
+                        comp.size.Height = orgsize.Height;
+                }
+                else if(temp.GetValueModification() == temp.ModifyWidth) {
+                    comp.size.Width = orgsize.Width;
+                }
+                else if(temp.GetValueModification() == temp.ModifyHeight) {
+                    comp.size.Height = orgsize.Height;
+                }
+
+                if(
+                    (cont.GetOrientation() == Graphics::Orientation::Horizontal && size.Width.IsRelative()) ||
+                    (cont.GetOrientation() == Graphics::Orientation::Vertical && size.Height.IsRelative() )
+                    )
+                {
+                    if(maxsize.Width == 0)
+                        comp.size.Width = 0;
+                    if(maxsize.Height == 0)
+                        comp.size.Height = 0;
+                }
+
+                if(comp.size.Width < 0)
+                    comp.size.Width = 0;
+                if(comp.size.Height < 0)
+                    comp.size.Height = 0;
+            }
+        }); //for size
+
+        Component *startanch = nullptr, *endanch = nullptr;
+
+        //Positioning stage, second pass will align everything.
+        forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &val, int emsize) {
+            //check anchor object by observing temp.GetPreviousAnchor and direction
+            Component *anch = nullptr;
+            
+            //if absolute, nothing to anchor to but to parent
+            if(temp.GetPositioning() == temp.Relative && temp.GetPreviousAnchor() != Anchor::None) {
+                if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
+                    if((IsLeft(temp.GetPreviousAnchor()) && IsRight(temp.GetMyAnchor())) || 
+                        (temp.GetPreviousAnchor() == Anchor::None && IsRight(temp.GetContainerAnchor()))) 
+                    {
+                        anch = startanch;
+                        comp.anchorotherside = true;
+                    }
+                    else {
+                        anch = endanch;
+                    }
+                }
+                else {
+                    if((IsTop(temp.GetPreviousAnchor()) && IsBottom(temp.GetMyAnchor())) || 
+                        (temp.GetPreviousAnchor() == Anchor::None && IsBottom(temp.GetContainerAnchor()))) 
+                    {
+                        anch = startanch;
+                        comp.anchorotherside = true;
+                    }
+                    else {
+                        anch = endanch;
+                    }
+                }
+            }
+        
+            auto parentmargin = Convert(temp.GetMargin(), parent.innersize, emsize).CombinePadding(Convert(cont.GetPadding(), parent.size, emsize)) + Convert(temp.GetIndent(), parent.innersize, emsize);
+        
+            Geometry::Margin margin;
+        
+            if(anch) {
+                margin = Convert(temp.GetMargin(), parent.innersize, emsize).CombineMargins(Convert(anch->GetTemplate().GetMargin(), parent.innersize, emsize));
+            }
+            else {
+                margin = parentmargin;
+            }
+        
+            auto maxsize = parent.innersize - parentmargin;
+        
+            auto pos = temp.GetPosition();
+        
+            if(temp.GetValueModification() == temp.ModifyPosition) {
+                if(NumberOfSetBits(temp.GetValueSource()) == 1) {
                     if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                        if(IsRight(temp.GetMyAnchor())) {
-                            prev = &comp;
+                        pos = {{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y};
+                    }
+                    else {
+                        pos = {pos.X, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}};
+                    }
+                }
+                else {
+                    pos ={{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, {int(calculatevalue(val, 1, comp)*10000), Dimension::BasisPoint}};
+                }
+            }
+            else if(temp.GetValueModification() == temp.ModifyX) {
+                pos = {{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y};
+            }
+            else if(temp.GetValueModification() == temp.ModifyY) {
+                pos = {pos.X, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}};
+            }
+            else if(taglocations.count(temp.GetTag())) {
+                pos = {taglocations[temp.GetTag()]};
+            }
+            
+            if(temp.GetPositioning() == temp.PolarAbsolute) {
+                auto pcenter = Geometry::Pointf(cont.GetCenter().X.CalculateFloat((float)maxsize.Width, (float)emsize), cont.GetCenter().Y.CalculateFloat((float)maxsize.Height, (float)emsize));
+                auto center  = Geometry::Pointf(temp.GetCenter().X.CalculateFloat((float)comp.size.Width, (float)emsize), temp.GetCenter().Y.CalculateFloat((float)comp.size.Height, (float)emsize));
+
+                pcenter += parentmargin.TopLeft();
+
+                auto r = pos.X.CalculateFloat(Geometry::Point(maxsize).Distance()/(float)sqrt(2), (float)emsize);
+
+                auto a = pos.Y.CalculateFloat(360, PI);
+
+                a *= PI / 180.0f;
+
+                comp.location = {int(std::round(r * cos(a) + pcenter.X - center.X)), int(std::round(r * sin(a) + pcenter.Y - center.Y))};
+            }
+            else {
+                auto offset = Convert(pos, (temp.GetPositioning() == temp.AbsoluteSliding ?  maxsize - comp.size : comp.size), emsize);
+        
+                if(anch) {
+                    anchortoother(comp, temp, offset, margin, *anch, cont.GetOrientation());
+                }
+                else {
+                    anchortoparent(comp, temp, offset, margin, parent.innersize);
+                }
+            }
+
+            //Which anchor side is to be changed
+            if(temp.GetPositioning() == temp.Relative) {
+                if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
+                    if(IsRight(temp.GetMyAnchor())) {
+                        startanch = &comp;
+                    }
+                    else {
+                        endanch = &comp;
+                    }
+                }
+                else {
+                    if(IsBottom(temp.GetMyAnchor())) {
+                        startanch = &comp;
+                    }
+                    else {
+                        endanch = &comp;
+                    }
+                }
+            }
+        }); //position pass
+        
+        if(requiresrepass && !repassdone) {
+            int startused = 0, endused = 0;
+            
+            Component *startmost = nullptr, *endmost = nullptr;
+            
+            //go through the components to see where they end
+            forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &, int) {
+                //only relatively sided components take up space
+                if(temp.GetPositioning() == temp.Relative) {
+                    //the values will be overwritten successively to find the last ones
+                    if(ishor) {
+                        if(comp.anchorotherside) { //anchored to right
+                            startmost = &comp;
                         }
-                        else {
-                            next = &comp;
+                        else { //to left
+                            startmost = &comp;
                         }
                     }
                     else {
-                        if(IsBottom(temp.GetMyAnchor())) {
-                            prev = &comp;
+                        if(comp.anchorotherside) { //to bottom
+                            endmost = &comp;
                         }
-                        else {
-                            next = &comp;
+                        else { //to top
+                            startmost = &comp;
                         }
                     }
                 }
-            }
-        }//for indices
-        
-        if(requiresrepass && !repassdone) {
-            if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
-                int rightused = 0, leftused = 0;
-                
-                for(int i=0; i<cont.GetCount(); i++) {
+            });
+            
+            //this will calculate the necessary spacing between the last item(s)
+            int lastspacing = 0;
+            
+            if(ishor) {
+                if(startmost) {
+                    //calculate the used space on the left
+                    startused = startmost->location.X + startmost->size.Width;
                     
-                    int ci = cont[i];
-
-                    if(ci >= indices) continue;
-                    if(!stacksizes[ci]) continue;
-
-                    auto &compparent = get(cont[i]);
-                    const auto &temp = compparent.GetTemplate();
-
-                    for(int j = 0; temp.GetRepeatMode() == temp.NoRepeat ? j == 0 : repeats.count(temp.GetRepeatMode()) && j < repeats[temp.GetRepeatMode()].size(); j++) {
-                        Component *compptr;
-                        const std::array<float, 4> *val;
-
-                        if(temp.GetRepeatMode() == temp.NoRepeat) {
-                            compptr = &compparent;
-                            val     = &value;
-                        }
-                        else {
-                            compptr = &repeated[&temp][j];
-                            val     = &repeats[temp.GetRepeatMode()][j];
-                        }
-
-                        auto &comp = *compptr;
-
-                        //check if textholder and if so use emsize from the font
-                        int emsize = getemsize(comp);
-
-                        if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) {
-                            if(comp.anchorotherside) {
-                                rightused = parent.innersize.Width - comp.location.X;
-                            }
-                            else if(comp.size.Width > 0) {
-                                leftused = (   
-                                    comp.location.X + comp.size.Width + 
-                                    std::max(temp.GetMargin().Right(parent.innersize.Width, emsize), cont.GetPadding().Right(parent.size.Width, emsize))
-                                
-                                );
-                            }
-                        }
+                    //both sides exist, so we will be using the margins between them
+                    if(endmost) {
+                        //calculate the used space on the right
+                        endused = parent.innersize.Width - endmost->location.X;
+                        
+                        //calculate margin
+                        auto s = startmost->GetTemplate().GetMargin().Right(0, getemsize(*startmost));
+                        auto e = endmost->GetTemplate().GetMargin().Left(0, getemsize(*startmost));
+                        
+                        //add indent
+                        lastspacing = calculatemargin(s, e);
+                    }
+                    else { //only start side is there
+                        //calculate margin
+                        auto s = startmost->GetTemplate().GetMargin().Right(0, getemsize(*startmost));
+                        auto e = cont.GetPadding().Right(parent.innersize.Width, getemsize(*startmost));
+                        
+                        //add indent
+                        lastspacing = calculatemargin(s, e) + startmost->GetTemplate().GetIndent().Right(0, getemsize(*startmost));
                     }
                 }
-                
-                spaceleft = parent.innersize.Width - rightused - leftused;
+                else if(endmost) { //only end side is there
+                    //calculate the used space on the right
+                    endused = parent.innersize.Width - endmost->location.X;
+                    
+                    //calculate margin
+                    auto s = cont.GetPadding().Left(parent.innersize.Width, getemsize(*startmost));
+                    auto e = endmost->GetTemplate().GetMargin().Left(0, getemsize(*startmost));
+                    
+                    //add indent
+                    lastspacing = calculatemargin(s, e) + endmost->GetTemplate().GetIndent().Left(0, getemsize(*startmost));
+                }
             }
             else {
-                int bottomused = 0, topused = 0;
-                
-                for(int i=0; i<cont.GetCount(); i++) {
-                    
-                    int ci = cont[i];
-
-                    if(ci >= indices) continue;
-                    if(!stacksizes[ci]) continue;
-
-                    auto &comp = get(cont[i]);
-                    const auto &temp = comp.GetTemplate();
+                if(startmost) {
+                    //calculate the space used on the top side
+                    startused = startmost->location.Y + startmost->size.Height;
                     
-                    //check if textholder and if so use emsize from the font
-                    int emsize = getemsize(comp);
-
-                    if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) {
-                        if(comp.anchorotherside) {
-                            bottomused = parent.innersize.Height - comp.location.X;
-                        }
-                        else if(comp.size.Height) {
-                            topused = (   
-                                comp.location.X + comp.size.Height + 
-                                std::max(temp.GetMargin().Right(parent.innersize.Height, emsize), cont.GetPadding().Right(parent.size.Height, emsize))
-                                
-                            );
-                        }
+                    //both sides exist, so we will be using the margins between them
+                    if(endmost) {
+                        //calculate the space used on the bottom side
+                        endused = parent.innersize.Height - endmost->location.Y;
+                        
+                        //calculate margin
+                        auto s = startmost->GetTemplate().GetMargin().Bottom(0, getemsize(*startmost));
+                        auto e = endmost->GetTemplate().GetMargin().Top(0, getemsize(*startmost));
+                        
+                        lastspacing = calculatemargin(s, e);
+                    }
+                    else { //only start side is there
+                        //calculate margin
+                        auto s = startmost->GetTemplate().GetMargin().Bottom(0, getemsize(*startmost));
+                        auto e = cont.GetPadding().Bottom(parent.innersize.Width, getemsize(*startmost));
+                        
+                        //add indent
+                        lastspacing = calculatemargin(s, e) + startmost->GetTemplate().GetIndent().Bottom(0, getemsize(*startmost));
                     }
                 }
-                
-                spaceleft = parent.innersize.Height - bottomused - topused;
+                else if(endmost) { //only end side is there
+                    //calculate the space used on the bottom side
+                    endused = parent.innersize.Height - endmost->location.Y;
+                    
+                    //calculate margin
+                    auto s = cont.GetPadding().Top(parent.innersize.Width, getemsize(*startmost));
+                    auto e = endmost->GetTemplate().GetMargin().Top(0, getemsize(*startmost));
+                    
+                    //add indent
+                    lastspacing = calculatemargin(s, e) + endmost->GetTemplate().GetIndent().Top(0, getemsize(*startmost));
+                }
             }
+            
+            //calculate remaining space for percent based components
+            spaceleft = parent.innersize.Width - startused - endused - lastspacing;
 
             repassdone = true;
             goto realign;
         }
 
 
+        //update the containers
         for(int i=0; i<cont.GetCount(); i++) {
 
             int ci = cont[i];
@@ -2512,7 +2625,7 @@
         }
     }
 
-        
+    
     void ComponentStack::render(Component &comp, Graphics::Layer &parent, Geometry::Point offset, Graphics::RGBAf color, int ind) {
         const ComponentTemplate &tempp = comp.GetTemplate();
         auto tempptr = &tempp;
@@ -2569,17 +2682,18 @@
         if(temp.GetType() == ComponentType::Container) {
             const auto &cont = dynamic_cast<const ContainerTemplate&>(temp);
             
-            offset += cont.GetBorderSize().TopLeft();
             offset += comp.location;
 
             if(st.primary && target) {
                 auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary);
                 if(rectangular)
-                    rectangular->DrawIn(*target, offset-cont.GetBorderSize().TopLeft(), comp.size, color);
+                    rectangular->DrawIn(*target, offset, comp.size, color);
                 else
-                    st.primary->Draw(*target, offset-cont.GetBorderSize().TopLeft(), color);
+                    st.primary->Draw(*target, offset, color);
             }
             
+            offset += cont.GetBorderSize().TopLeft();
+            
             for(int i=0; i<cont.GetCount(); i++) {
                 if(cont[i] >= indices) continue;
                 if(stacksizes[cont[i]]) {
@@ -2596,6 +2710,8 @@
                 }
             }
             
+            offset -= cont.GetBorderSize().TopLeft();
+            
             if(st.secondary && target) {
                 auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.secondary);
                 if(rectangular)
@@ -2603,8 +2719,6 @@
                 else
                     st.secondary->Draw(*target, offset-cont.GetBorderSize().TopLeft()+cont.GetOverlayExtent().TopLeft(), color);
             }
-            
-            offset -= cont.GetBorderSize().TopLeft();
         }
         else if(temp.GetType() == ComponentType::Graphics) {
             if(st.primary && target) {
--- a/Source/Gorgon/UI/ComponentStack.h	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/UI/ComponentStack.h	Sun Jun 07 12:05:24 2020 +0300
@@ -517,8 +517,18 @@
 
         ///Return the component at the given index with the requested condition. Returns top of stack if condition does not exist.
         Component &get(int ind, ComponentCondition condition) const;
-
-        ///starts update chain
+        
+        ///Calculates the position results from the anchoring the given component to the area determined by the
+        ///given size and margin. Offset is used to move away from the anchor and may result reversing of direction.
+        void anchortoparent(Component &comp, const ComponentTemplate &temp, 
+                                Geometry::Point offset, Geometry::Margin margin, Geometry::Size maxsize);
+        
+        
+        ///Calculates the position results from the anchoring the given component to another component
+        void anchortoother(Component &comp, const ComponentTemplate &temp, 
+                        Geometry::Point offset, Geometry::Margin margin, Component &other, Graphics::Orientation orientation);
+        
+        ///starts the update chain
         void update();
 
         ///updates a specific container component
@@ -534,6 +544,12 @@
         
         ///returns the size of the emdash
         int getemsize(const Component &comp);
+        
+        ///returns the baseline point of the component
+        int getbaseline(const Component &comp);
+        
+        ///returns the height of the component
+        int gettextheight(const Component &comp);
 
         ///Calculates the value of the given channel for the given component. Uses stored value
         float calculatevalue(int channel, const Component &comp) const { return calculatevalue(value, channel, comp); }
@@ -556,7 +572,13 @@
         Component *gettag(ComponentTemplate::Tag tag) const;
 
         ///ComponentStack wide emsize
-        int emsize = 10;
+        int emsize = 0;
+        
+        ///ComponentStack wide baseline
+        int baseline = 0;
+        
+        ///ComponentStack wide baseline
+        int textheight = 0;
         
         ///This vector contains data for components. This piece of memory will be managed by the stack
         Component *data = nullptr;
--- a/Source/Gorgon/UI/Dimension.h	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/UI/Dimension.h	Sun Jun 07 12:05:24 2020 +0300
@@ -79,6 +79,11 @@
                     return (float)value;
             }
         }
+        
+        /// Returns if the dimension is relative to the parentwidth
+        bool IsRelative() const {
+            return unit == Percent || unit == BasisPoint;
+        }
 
         /// Returns the value of the dimension, should not be considered as
         /// pixels
--- a/Source/Gorgon/UI/Template.h	Fri Jun 05 09:41:00 2020 +0300
+++ b/Source/Gorgon/UI/Template.h	Sun Jun 07 12:05:24 2020 +0300
@@ -149,7 +149,8 @@
         /// This anchor position should is only used to denote object will
         /// not be anchored to a previous object, only to its parent. If
         /// used as parent anchor it will be ignored and default anchor
-        /// will be used instead.
+        /// will be used instead. This should be paired with absolute 
+        /// positioning.
         None = 0,
         
         /// Top left
@@ -175,23 +176,19 @@
         BottomRight,
         
         /// Baseline left, for text, this aligns to the baseline of
-        /// the last line; if there is no text related data, this will
-        /// align to the middle left.
+        /// the first line
         FirstBaselineLeft,
         /// Baseline right, for text, this aligns to the baseline of
-        /// the last line; if there is no text related data, this will
-        /// align to the middle right.
+        /// the first line
         FirstBaselineRight,
         
         /// Baseline left, for text, this aligns to the baseline of
-        /// the last line; if there is no text related data, this will
-        /// align to the bottom left. This mode only works properly if
+        /// the last line. This mode only works properly if
         /// Sizing is set to automatic.
         LastBaselineLeft,
         
         /// Baseline right, for text, this aligns to the baseline of
-        /// the last line; if there is no text related data, this will
-        /// align to the bottom right. This mode only works properly if
+        /// the last line. This mode only works properly if
         /// Sizing is set to automatic.
         LastBaselineRight,
     };

mercurial