* Textholder default text ComponentStackRework

Tue, 07 Jul 2020 08:02:49 +0300

author
cemkalyoncu
date
Tue, 07 Jul 2020 08:02:49 +0300
branch
ComponentStackRework
changeset 1410
56a95bb31659
parent 1409
feee05cd9da2
child 1411
da9d2f378e83

* Textholder default text
* Offset is used in size calculation
* More test cases

Source/Gorgon/Containers/Iterator.h file | annotate | diff | comparison | revisions
Source/Gorgon/Graphics/TextureTargets.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStack.cpp file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Component.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Containers/Iterator.h	Sat Jul 04 09:07:32 2020 +0300
+++ b/Source/Gorgon/Containers/Iterator.h	Tue Jul 07 08:02:49 2020 +0300
@@ -6,6 +6,7 @@
 
 #include <stdexcept>
 #include <iterator>
+#include <iostream>
 
 
 namespace Gorgon {
--- a/Source/Gorgon/Graphics/TextureTargets.h	Sat Jul 04 09:07:32 2020 +0300
+++ b/Source/Gorgon/Graphics/TextureTargets.h	Tue Jul 07 08:02:49 2020 +0300
@@ -43,6 +43,11 @@
 		}
 
 		/// Draws a textureless solid colored rectangle on the screen.
+		virtual void Draw(int x, int y, int w, int h, RGBAf color = RGBAf(1.f)) {
+			Draw({float(x), float(y), float(w), float(h)}, color);
+		}
+
+		/// Draws a textureless solid colored rectangle on the screen.
 		virtual void Draw(const Geometry::Pointf &location, const Geometry::Sizef &size, RGBAf color = RGBAf(1.f)) {
 			Draw({location, size}, color);
 		}
--- a/Source/Gorgon/UI/ComponentStack.cpp	Sat Jul 04 09:07:32 2020 +0300
+++ b/Source/Gorgon/UI/ComponentStack.cpp	Tue Jul 07 08:02:49 2020 +0300
@@ -6,7 +6,8 @@
 
 #include "math.h"
 
-//TODO: Textholder default text
+//TODO: in a relatively placed, relatively sized component, anchor/offset should effect maximum size in free direction.
+//      unless offset is also percentage based.
 
 namespace Gorgon { namespace UI {
     
@@ -2184,6 +2185,18 @@
         
         //for easy access
         auto ishor = cont.GetOrientation() == Graphics::Orientation::Horizontal;
+
+        //offsets will be stored here
+        std::map<Component *, Geometry::Point> offsets;
+
+        //reset all components
+        forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &val, int emsize) {
+            comp.location = {0, 0};
+            comp.size = {0, 0};
+            comp.innersize = {0, 0};
+            offsets[&comp] = {0, 0};
+        });
+
         
 realign:
 
@@ -2219,8 +2232,11 @@
             else {
                 yfree = true;
             }
+
+            //***** Left/top, right/bottom to center/middle alignment
             
-            //to be attached to left or right of the center reduces the effective size by half
+            //to be attached to left or right of the center reduces the effective size by half,
+            //this will work automatically with non-free direction
             if(xfree && IsCenter(temp.GetContainerAnchor()) && !IsCenter(temp.GetMyAnchor())) {
                 maxsize.Width = 
                     parent.innersize.Width/2 - 
@@ -2230,9 +2246,15 @@
                     )
                 ;
             }
+
+            //if there is an offset in the free direction, reduce it from the maximum size
+            if(xfree) {
+                maxsize.Width -= offsets[&comp].X;
+            }
             
-            //to be attached to top or bottom of the middle reduces the effective size by half
-            if(xfree && IsMiddle(temp.GetContainerAnchor()) && !IsMiddle(temp.GetMyAnchor())) {
+            //to be attached to top or bottom of the middle reduces the effective size by half,
+            //this will work automatically with non-free direction
+            if(yfree && IsMiddle(temp.GetContainerAnchor()) && !IsMiddle(temp.GetMyAnchor())) {
                 maxsize.Height = 
                     parent.innersize.Height/2 - 
                     (IsTop(temp.GetMyAnchor()) ? 
@@ -2241,6 +2263,13 @@
                     )
                 ;
             }
+
+            //if there is an offset in the free direction, reduce it from the maximum size
+            if(yfree) {
+                maxsize.Height -= offsets[&comp].Y;
+            }
+
+            //****** Max size calculation (cont.)
             
             //defined size of the component
             auto size = temp.GetSize();
@@ -2452,6 +2481,7 @@
                 }
                 
                 //automatic sizing restrictions
+                //TODO: if relative size turns to content size, this should adjust maximum usable width
                 if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) {
                     if(comp.size.Width < orgsize.Width)
                         comp.size.Width = orgsize.Width;
@@ -2719,7 +2749,7 @@
                     } (maxsize.Width - (sliding ? offset.X + comp.size.Width : 0), emsize);
                 }
 
-                //this will convert y to piyels
+                //this will convert y to pixels
                 if(ych == -1) { //value channel is not in effect
                     offset.Y = pos.Y(
                         maxsize.Height - (sliding ? tagpos.Y + comp.size.Height : 0), emsize
@@ -2737,7 +2767,16 @@
                             int(calculatevalue(val, ych, comp)*10000), Dimension::BasisPoint
                     } (maxsize.Height - (sliding ? offset.Y + comp.size.Height : 0), emsize);
                 }
+
+                offsets[&comp] = offset;
         
+                //if there is an offset in a relatively sized sub-component, final pass might be necessary.
+                if(
+                    (offset.X != 0 && temp.GetSize().Width.IsRelative()) ||
+                    (offset.Y != 0 && temp.GetSize().Height.IsRelative())
+                    )
+                    finalpass = true;
+
                 if(anch) {
                     anchortoother(comp, temp, offset, margin, *anch, cont.GetOrientation());
                 }
@@ -2751,18 +2790,18 @@
             if(temp.GetPositioning() == temp.Relative) {
                 if(cont.GetOrientation() == Graphics::Orientation::Horizontal) {
                     if(IsRight(temp.GetMyAnchor())) {
-                        startanch = &comp;
+                        endanch = &comp;
                     }
                     else {
-                        endanch = &comp;
+                        startanch = &comp;
                     }
                 }
                 else {
                     if(IsBottom(temp.GetMyAnchor())) {
-                        startanch = &comp;
+                        endanch = &comp;
                     }
                     else {
-                        endanch = &comp;
+                        startanch = &comp;
                     }
                 }
             }
--- a/Testing/Source/Manual/UI_Component.cpp	Sat Jul 04 09:07:32 2020 +0300
+++ b/Testing/Source/Manual/UI_Component.cpp	Tue Jul 07 08:02:49 2020 +0300
@@ -12,6 +12,7 @@
     "Key list:\n"
     "d\tToggle disabled\n"
     "left, right\tPrevious, next test\n"
+    "c\tCopy title of the active test\n"
     "1-8\tModify value of the stack [not active yet]\n"
     "esc\tClose\n"
 ;
@@ -21,7 +22,7 @@
 
 Graphics::RectangleProvider &coloredrect(Graphics::RGBA color) {
     //this will not leak
-    auto &img = *new Graphics::BlankImage(10, 10, {color, 0.5});
+    auto &img = *new Graphics::BlankImage(10, 10, {color, 0.6});
     
     //as long as rectangle is destroyed
     auto &ret = *new Graphics::RectangleProvider(img);
@@ -49,7 +50,7 @@
 }
 
 Graphics::BlankImage &blankimage(Graphics::RGBA color) {
-    auto &img = *new Graphics::BlankImage(10, 10, {color, 0.5});
+    auto &img = *new Graphics::BlankImage(10, 10, {color, 0.6});
     
     return img;
 }
@@ -129,6 +130,140 @@
     ComponentStack &stack;
 };
 
+TestData test_setsize(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(50, 50);
+    
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(20, 30);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set size", "20x30 green object on a 50x50 white background, should be aligned to top left.", stack};
+}
+
+TestData test_setsizepercent(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());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(5000, 3333, Gorgon::UI::Dimension::BasisPoint);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set size percent", "30x20 green object on a 60x60 white background, should be aligned to top left.", stack};
+}
+
+TestData test_setsizepercent_percent(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(3333, 3333, Gorgon::UI::Dimension::BasisPoint);
+
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetSize(50, 50, Gorgon::UI::Dimension::Percent);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set size percent x2", "Size 20x20 and 30x30 objects on a 60x60 white background, should be aligned to top left. Objects are green and red and should be touching.", stack};
+}
+
+TestData test_setsizepercent_rel(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+    cont2.SetPosition(0, 0);
+
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetSize(50, 50, Gorgon::UI::Dimension::Percent);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set size percent relative", "Size 20x20 and 20x30 objects on a 60x60 white background, should be aligned to top left. Objects are green and red and should be touching.", stack};
+}
+
+TestData test_sizepercent_center(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(80, 80);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(50, 50, Gorgon::UI::Dimension::Percent);
+    cont2.SetAnchor(UI::Anchor::None, UI::Anchor::MiddleCenter, UI::Anchor::TopLeft);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set size percent from center", "20x20 green object on a 80x80 white background, should be aligned to center from its top left.", stack};
+}
+
+TestData test_sizepercent_centerabs(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(80, 80);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(50, 50, Gorgon::UI::Dimension::Percent);
+    cont2.SetAnchor(UI::Anchor::None, UI::Anchor::MiddleCenter, UI::Anchor::TopLeft);
+    cont2.SetPositioning(cont2.Absolute);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set size percent from center absolute", "20x20 green object on a 80x80 white background, should be aligned to center from its top left.", stack};
+}
+
 TestData test_setborder(Layer &layer) {
     auto &temp = *new Template;
     temp.SetSize(50, 50);
@@ -141,7 +276,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(greenrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -151,7 +285,6 @@
     return {"Set border", "White background (50x50) and a green border (starting from 10,10, size of 30x30). Result should be concentric squares, 10px size difference, white, green, white.", stack};
 }
 
-
 TestData test_setborder2(Layer &layer) {
     auto &temp = *new Template;
     temp.SetSize(70, 70);
@@ -164,7 +297,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(greenrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -187,7 +319,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -209,7 +340,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -231,7 +361,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redimg());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -254,7 +383,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     
     auto &stack = *new ComponentStack(temp);
     stack.HandleMouse();
@@ -275,7 +403,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetMargin(10);
     
     auto &stack = *new ComponentStack(temp);
@@ -297,7 +424,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetMargin(20, Gorgon::UI::Dimension::Percent);
     
     auto &stack = *new ComponentStack(temp);
@@ -320,7 +446,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetMargin(10);
     
     auto &stack = *new ComponentStack(temp);
@@ -342,7 +467,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetIndent(10);
     
     auto &stack = *new ComponentStack(temp);
@@ -365,7 +489,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetIndent(10);
     
     auto &stack = *new ComponentStack(temp);
@@ -388,7 +511,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetMargin(10);
     
     auto &stack = *new ComponentStack(temp);
@@ -411,7 +533,6 @@
     auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
     cont2.Background.SetAnimation(redrect());
     cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
-    cont2.SetPosition(0,0);
     cont2.SetMargin(-10, 0, -10, 0);
     
     auto &stack = *new ComponentStack(temp);
@@ -419,7 +540,36 @@
     
     layer.Add(stack);
     
-    return {"Set margin negative", "Two empty squares inside each other. Cyan on the outside, red inside. There should be 10x20 empty square at the middle. Borders should be 10px in size and should touch each other apart from left and right which they should be on top of each other.", stack};
+    return {"Set margin negative", "Two empty squares inside each other. Cyan on the outside, red inside. There should be 30x10 empty square at the middle. Borders should be 10px in size and should touch each other apart from left and right which they should be on top of each other.", stack};
+}
+
+TestData test_border_padding_margin_size(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(120, 120);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(cyanrect());
+    cont1.SetBorderSize(10);
+    cont1.SetPadding(20, 10, 10, 40, Gorgon::UI::Dimension::Percent);
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(redimg());
+    cont2.SetSize({50, Gorgon::UI::Dimension::Percent}, 40);
+    cont2.SetMargin(10, 20, 30, -10, Gorgon::UI::Dimension::Pixel);
+
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.Background.SetAnimation(greenimg());
+    cont3.SetSize(20, 60, Gorgon::UI::Dimension::Pixel);
+    cont3.SetMargin(30, -10, 0, 0, Gorgon::UI::Dimension::Pixel);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Set border, padding, margin and check relative sizing", "This has a cyan border around a 10x40 red object and 20x60 green object. There should be 30px between object. Red object should be 20px from top border, green object should be aligned to the red object from top.", stack};
 }
 
 TestData test_absanch_samepoint(Layer &layer) {
@@ -523,7 +673,132 @@
     return {"Absolute anchoring center to anchor", "9 components will be anchored in a cyan rectangle. Colors at top from left: red, yellow, orange; middle: blue, purple, brown; bottom: green, gray, white. Apart from the center component, all component should overlap cyan border. No component should touch (not even corner to corner) each other (10px space around all).", stack};
 }
 
+TestData test_absanchoff(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());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(blueimg());
+    cont2.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+    cont2.SetPosition(10, 20);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Absolute anchoring from top-left", "Blue object of size 20x20 on white background with 10, 20 pixel from top.", stack};
+}
+
+TestData test_absanchoffsize(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(cyanrect());
+    cont1.SetBorderSize(10);
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
+    cont2.SetPositioning(UI::ComponentTemplate::Absolute);
+    cont2.SetPosition(10, 20);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Absolute anchoring from top-left", "Green object in a cyan rectangle with 10, 20 pixel from border. It should fill the rest of the space.", stack};
+}
+
+TestData test_absanchoffrev(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());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(blueimg());
+    cont2.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+    cont2.SetAnchor(UI::Anchor::None, UI::Anchor::BottomRight, UI::Anchor::BottomRight);
+    cont2.SetPositioning(UI::ComponentTemplate::Absolute);
+    cont2.SetPosition(10, 20);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Absolute anchoring from bottom-right", "Blue object of size 20x20 on white background with 10, 20 pixel from bottom right.", stack};
+}
+
+TestData test_relanch(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Relative anchoring", "Size 20x20 and 20x20 objects on a 60x60 white background, should be aligned to top left. Objects are green and red and should be touching.", stack};
+}
+
+TestData test_relanch2(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(60, 60);
+
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+
+    auto &cont2 = temp.AddContainer(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Background.SetAnimation(greenimg());
+    cont2.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+
+    auto &cont3 = temp.AddContainer(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.Background.SetAnimation(redimg());
+    cont3.SetSize(20, 20, Gorgon::UI::Dimension::Pixel);
+    cont3.SetAnchor(UI::Anchor::BottomRight, UI::Anchor::BottomLeft, UI::Anchor::TopLeft);
+
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+
+    layer.Add(stack);
+
+    return {"Relative anchoring", "Size 20x20 and 20x20 objects on a 60x60 white background, first should be aligned to top left. Objects are green and red and should be touching from the corners.", stack};
+}
+
 std::vector<std::function<TestData(Layer &)>> tests = {
+    &test_setsize,
+    &test_setsizepercent,
+    &test_setsizepercent_percent,
+    &test_setsizepercent_rel,
+    &test_sizepercent_center,
+    &test_sizepercent_centerabs,
+
     &test_setborder,
     &test_setborder2,
     &test_setpadding,
@@ -537,9 +812,17 @@
     &test_indent_padding,
     &test_setpadding_negative,
     &test_setmargin_negative,
+    &test_border_padding_margin_size,
+
     &test_absanch_samepoint,
     &test_paranch_samepoint,
     &test_absanch_centertopoint,
+    &test_absanchoff,
+    &test_absanchoffsize,
+    &test_absanchoffrev,
+    
+    &test_relanch,
+    &test_relanch2
 };
 
 
@@ -655,6 +938,10 @@
                 }
                 break;
                 
+            case Keycodes::C:
+                WindowManager::SetClipboardText(info[ind].first);
+                break;
+
             case Keycodes::Escape:
                 exit(0);
                 break;

mercurial