* DataEffect tests ComponentStackRework

Fri, 17 Jul 2020 16:19:15 +0300

author
cemkalyoncu
date
Fri, 17 Jul 2020 16:19:15 +0300
branch
ComponentStackRework
changeset 1416
ce292ba2937c
parent 1415
870f05e3b2e2
child 1418
2eb832eb32fe

* DataEffect tests
* Bug fix: automatic sized text
* Documentation is moved to cpp file not to cause a large recompile

Source/Gorgon/Main.cpp 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/Template.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Template.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/GraphicsHelper.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Component.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Main.cpp	Sun Jul 12 16:15:09 2020 +0300
+++ b/Source/Gorgon/Main.cpp	Fri Jul 17 16:19:15 2020 +0300
@@ -21,10 +21,23 @@
 #endif
 
 /**
- * @page GDB Pretty Printing
- * For GDB pretty printing to work with Gorgon objects
- * simply copy Resource/Gorgon-gdb.py file to the startup
- * directory of your program.
+ * @page programminghelpers Programming Utilities
+ * 
+ * Debugging Help
+ * ==============
+ * 
+ * GDB Pretty Printing
+ * -------------------
+ * 
+ * For GDB pretty printing to work with Gorgon objects simply copy `Resource/Gorgon-gdb.py`
+ * file to the startup directory of your program. You may need to allow script execution
+ * in GDB, when GDB is run, it will show you options on how to allow autoload scripts.
+ * 
+ * Adding the following to `~/.gdbinit` will allow script autoload in everywhere:
+ * 
+ * @code
+ * set auto-load safe-path /
+ * @endcode
  */
 
 #ifdef __GNUC__
--- a/Source/Gorgon/UI/ComponentStack.cpp	Sun Jul 12 16:15:09 2020 +0300
+++ b/Source/Gorgon/UI/ComponentStack.cpp	Fri Jul 17 16:19:15 2020 +0300
@@ -2250,20 +2250,23 @@
             if(yfree) {
                 maxsize.Height -= offsets[&comp].Y;
             }
-
+            
             //****** Max size calculation (cont.)
             
             //defined size of the component
             auto size = temp.GetSize();
             
-            //ensure unused size will not cause a repass
-            if(temp.GetHorizontalSizing() == ComponentTemplate::Automatic) {
-                size.Width = 0; //will not be used, set to 0px
+            //ensure unused size will not cause a repass except for text component which requires width
+            //to calculate exact text size.
+            if(temp.GetType() != ComponentType::Textholder) {
+                if(temp.GetHorizontalSizing() == ComponentTemplate::Automatic) {
+                    size.Width = 0; //will not be used, set to 0px
+                }
+                if(temp.GetVerticalSizing() == ComponentTemplate::Automatic) {
+                    size.Height = 0; //will not be used, set to 0px
+                }
             }
-            if(temp.GetVerticalSizing() == ComponentTemplate::Automatic) {
-                size.Height = 0; //will not be used, set to 0px
-            }
-        
+            
             //if relatively positioned, then the space left will be used. Space left will not
             //be available in the first pass.
             if(!xfree) {
@@ -2431,7 +2434,7 @@
                         //if there is some text data
                         if(text != "") {
                             //if not to be wrapped
-                            if(tagnowrap.count(temp.GetTag()))
+                            if(tagnowrap.count(temp.GetTag()) || width == 0)
                                 comp.size = th.GetRenderer().GetSize(text);
                             else
                                 comp.size = th.GetRenderer().GetSize(text, width);
--- a/Source/Gorgon/UI/ComponentStack.h	Sun Jul 12 16:15:09 2020 +0300
+++ b/Source/Gorgon/UI/ComponentStack.h	Fri Jul 17 16:19:15 2020 +0300
@@ -62,6 +62,16 @@
         /// the stack for condition changes. This variant supports image based data.
         /// Ownership of the image stays with the caller.
         void SetData(ComponentTemplate::DataEffect effect, const Graphics::Drawable &image);
+        
+        /// Returns the text data. If data is not set, this will return empty string.
+        std::string GetTextData(ComponentTemplate::DataEffect effect) {
+            return stringdata.count(effect) ? stringdata[effect] : "";
+        }
+        
+        /// Returns the image data. If data is not set, this will return nullptr.
+        const Graphics::Drawable *GetImageData(ComponentTemplate::DataEffect effect) {
+            return imagedata.Exists(effect) ? &imagedata[effect] : nullptr;
+        }
 
         /// Removes the data associated with data effect. This will remove all data
         /// variants together.
@@ -98,6 +108,9 @@
 
         /// Sets the value for the stack using a color
         void SetValue(Graphics::RGBA color) { SetValue((Graphics::RGBAf)color); }
+        
+        /// Returns the value of the stack
+        std::array<float, 4> GetValue() const { return returntarget ? targetvalue : value; }
 
         /// Changes the value transition speed. A speed of 0 will disable smooth transition.
         /// The unit is values per second
@@ -105,13 +118,13 @@
             valuespeed = val;
         }
 
-        /// GetValue returns the current transitional value, this will also enable value event
+        /// Whether GetValue returns the current transitional value, this will also enable value event
         /// to be called every time transitional value is updated
         void ReturnTransitionalValue() {
             returntarget = false;
         }
 
-        /// GetValue returns the target value. This is the default mode.
+        /// Whether GetValue returns the target value. This is the default mode.
         void ReturnTargetValue() {
             returntarget = true;
         }
@@ -121,8 +134,6 @@
             value_fn = handler;
         }
 
-        /// Returns the value of the stack
-        std::array<float, 4> GetValue() const { return returntarget ? targetvalue : value; }
 
         /// Sets the function that will be used to convert a value to a string. The handler will receive the value channel, data effect
         /// that is causing the translation and the value that needs to be transformed.
--- a/Source/Gorgon/UI/Template.cpp	Sun Jul 12 16:15:09 2020 +0300
+++ b/Source/Gorgon/UI/Template.cpp	Fri Jul 17 16:19:15 2020 +0300
@@ -4,6 +4,349 @@
 
 namespace Gorgon { namespace UI {
 
+    /**
+    * @page ui User interface
+    * 
+    * The user interface in Gorgon Library is based on the components system and is highly
+    * customizable. ComponentStack manages these components within a widget. There are
+    * different component types: containers (see @ref ContainerTemplate), placeholders (see
+    * @ref PlaceholderTemplate), graphics (see @ref GraphicsTemplate), and textholder (see 
+    * @ref TextholderTemplate). All subcomponents should be created from the main Template.
+    * 
+    * Each component has an index and containers have the index of the components that resides
+    * in them. There can be multiple components with the same index. ComponentCondition system
+    * is used to decide which components will exist at a given time. 
+    * 
+    * It is possible to control the transition of the widget from state to state by giving
+    * a specific component for the transition. This is generally used to animate state changes.
+    * It is also possible to use transition value channel to have value based animations. These
+    * animations can be reversed, even at the middle. In fact, even for regular bitmap
+    * animations, this is recommended as it can time the animation perfectly, allow it to be
+    * reversed at the middle of the transition (imagine mouse over). 
+    * 
+    * Components can be modified by ValueModification system. There are 4 widget controlled
+    * value channels and a fifth controlled by the transition. Values are expected to be in
+    * range from 0 to 1. But this can be changed by modifying value ranges. The aspect of the
+    * component that the value affects can also be controlled. Channels can be reordered to
+    * fit into the necessary order. Value changes can also be asked to be applied smoothly. But
+    * this is controlled through the widget.
+    * 
+    * Component data can be obtained by DataEffect. Data can currently be a text or an image.
+    * There are various data effects that can be used by graphics and textholder templates. 
+    * There are also conditions that trigger if a data channel has any data in it.
+    * 
+    * Components can be repeated. The repeats are controlled by the widget. Containers are not
+    * fully supported to be repeating structures. Other component types can be used with this
+    * system. Each repeat can have a different set value and condition. There are different
+    * repeating systems (such as minor and major) and each of these can be adjusted separately.
+    * 
+    * Components can have tags to be accessed from the widgets. Some widgets needs specific
+    * tags to exist in the template to work. 
+    * 
+    * Components are placed according to a series of complicated but intuitive rules. For 
+    * details of this system see @ref boxmodel.
+    * 
+    *
+    * @subpage components
+    * 
+    * @subpage boxmodel
+    * 
+    * @subpage uiconditions
+    * 
+    * @subpage valuechannels
+    * 
+    * @subpage componentexample
+    * 
+    * @subpage validators
+    */
+    
+
+    /**
+    * @page components Components
+    * 
+    * Components are the building blocks of widgets. They are the visual elements
+    * that makes up most of the visual aspect of a widget. Components have templates,
+    * which they use as basis for their placement and drawing. ComponentTemplate is 
+    * the base class for all component templates. Components have component index
+    * and component condition (see ComponentCondition) to control which components
+    * will be visible at a given instance. Components have the same component indices
+    * but only one will be shown at a time. The components that have more specific
+    * condition will have precedence. For instance, if two components have index of 2
+    * and one has condition of ComponentCondition::Always and the other has condition
+    * of ComponentCondition::Focused, first component will be displayed unless the
+    * widget has received focus, in that case the second one will be shown.
+    * 
+    * 
+    * Every widget requires a container component at index 0 as the root. If this
+    * component has a non-0 size, the widget size will be fixed [this might change
+    * in the future].
+    * 
+    * 
+    * Components can be modified by the widget data. This is controlled through data
+    * effect. Various data effects exist to suit different type of widgets. See the
+    * widget documentation for specific data exported by them.
+    * 
+    * See @ref boxmodel to learn how the components are spaced out.
+    * 
+    * See @ref componentexample to learn how to create a simple button
+    * 
+    */
+    
+    /**
+    * @page componentexample Component Example
+    * 
+    * This example shows how to create a simple button. Create the following templates:
+    * 
+    * @code
+    * ContainerTemplate, index = 0, background = bg image, set size, children = 1, 2
+    * TextholderTemplate, index = 2, set font, data effect = Text
+    * @endcode
+    * 
+    * These two templates will create a very simple button that has the background and
+    * it will display the text that is set by the programmer. If you wish to change the
+    * color of the text when the user moves mouse into the button, add the following
+    * template as well:
+    * 
+    * @code
+    * TextholderTemplate index = 2, set font, data effect = Text, condition = Hover
+    * @endcode
+    * 
+    * This component will override the previous if the mouse is over the button. In order
+    * to change the background when the user clicks the button, add the following:
+    * 
+    * @code
+    * ContainerTemplate, index = 0, background = pressed, set size, condition = Down, 
+    * children = 1, 2
+    * @endcode
+    * 
+    * This will change the background when the user presses the mouse button. Both hover and
+    * down conditions can occur at the same time. If user uses mouse to press the button
+    * they will both be active at the same time, however, if the user uses space bar to
+    * press the button when it is focused, only Down condition will be satisfied. In addition
+    * to these, it is helpful to provide a visual clue when the widget is focused. This
+    * is generally done by adding a focus rectangle like the following:
+    * 
+    * @code
+    * GraphicsTemplate, index = 1, Drawable = focus rectangle, Positioning = Absolute, 
+    * Size = 100, 100, Unit::Percent, set margin, condition = Focused
+    * @endcode
+    * 
+    * This last piece will only be shown when the button is focused. There will be no errors
+    * when it is invisible even when the container lists this template as its child.
+    * 
+    */
+
+
+    /**
+    * @page boxmodel Component placement
+    * 
+    * Apart from the top level container, each component should be in container. Components
+    * arrangement in a container first depends on component positioning. If a component is 
+    * relatively positioned, then it will follow the container orientation to be stacked with 
+    * the other relatively positioned components.
+    * 
+    * Sizing
+    * ======
+    * Components have multiple sizing modes. The first set of options control how the component
+    * will be sized in case it contains an image, text, or another component stack. If the size
+    * is Fixed, the size of the contents is ignored. Automatic uses the size of the contents.
+    * GrowOnly, ShrinkOnly options allow component to grow/shrink if the contents is larger/
+    * smaller than the given size. Sizing can be adjusted separately for X and Y axis. When
+    * grow only and shrink only options are combined with relative sizing the size calculation
+    * is performed between fixed and always relative size calculation time. Mixing multiple
+    * automatic grow/shrink only, relatively sized components in the same container is not 
+    * recommended. The system will try to fit automatic grow/shrink relatively sized components
+    * as best as possible with a single pass. Ex: There are two components, both are 50% in
+    * width and one of them is shrink only, container has 100px usable size. If the shrink only
+    * component has a content of 40px, the other component will be grown to fill the remaining
+    * 60px, even though it will be more than 50%. If this is not desired, shrink only component
+    * can be placed inside a 50% sized container, and its relative size should be set 100%.
+    * 
+    * Component size can also be relative. In this case, container orientation plays an 
+    * important role. If the relatively sized axis is not in the oriented direction, then the 
+    * entire usable size of the parent is used for the calculation. However, if the axis is the
+    * oriented direction, then only the unused space is considered during the relative size
+    * calculation. For instance, in a horizontally oriented container, assume there are two
+    * components. One has a fixed width of 50px and the other is set to 100% and the container
+    * has 200px usable width. Assuming no additional spacing, second component will have 150px
+    * width. This calculation depends on how the components are anchored and margin/padding/
+    * indent/border size.
+    * 
+    * Size of the component can be influenced by the value channels. In this case, the size of
+    * component is used as additional size on top of the relative size depending on the channel
+    * value. 
+    *
+    * It is possible for widgets to specify additional size to tags. In these cases, the given
+    * size will be used as an addition to the original size. It is not recommended to use
+    * automatic sizing with tags that the widgets can use (e.g., ContentsTag).
+    * 
+    * 
+    * Spacing
+    * =======
+    * In this system 4 spacing methods are used. First method is border size. Border size is
+    * excluded from the internal area of a container. Thus (0, 0), does not include the border.
+    * In this system, borders are not drawn automatically, they are a part of the background
+    * image, therefore, border size is not calculated. It should be supplied.
+    * 
+    * The second spacing is provided by the padding of the container. Main difference of
+    * padding is that it collapses with the margin of the components as well as being counted
+    * in the container. If the padding for any edge is negative, it will not be collapsed.
+    * 
+    * Margins are spacing around the components. Unless negative, they collapse. This means if
+    * two components are anchored together, the margin between them is the maximum of the
+    * margin their touching edges. Negative margins are always added. 
+    * 
+    * Indent is the last spacing. It is additive and only used if a component is anchored to
+    * its parent. This is very useful in repeated or conditional components. For instance, if
+    * a button can have icon with text. You may want extra spacing on the text if there is no
+    * icon. This can be facilitated using Icon1IsSet condition and indent.
+    * 
+    * All spacing except for border size can be relative. For padding, the size of the
+    * component excluding the borders is used. For margin and indent, size of the parent 
+    * excluding the borders is used. 50% margin left will effectively start a component from 
+    * the center. However, anchoring should be used for this case.
+    * 
+    * 
+    * Anchoring
+    * =========
+    * All components are placed according to their anchor points. Relatively positioned 
+    * components can be anchored to another component, but absolutely positioned components
+    * are always anchored to their parent. Depending on the orientation, relative anchoring
+    * will be done to left/right or top/bottom. It is possible for anchoring to cause 
+    * artifacts, thus it should be used properly. 
+    * 
+    * Absolute anchoring is simple. It uses parent and anchor point. In this anchoring, the 
+    * component should be inside the parent. This means, if horizontal part of the anchor point
+    * is left, then parent anchor should either be left or center, so that the component will
+    * be placed in the parent. Otherwise the component will be placed outside the parent. If
+    * an absolutely positioned object is attached to left/top or right/bottom of its parent's
+    * center/middle, then the effective size of the container if only include right/bottom or
+    * left/top portion of the container. If spacing for both sides are equal, this will cut the
+    * usable size by half. This feature makes it easier to deal with center starting 
+    * components.
+    * 
+    * Relative anchoring requires previous component anchor dictated by the current component
+    * and parent anchor. These target anchor points should match. Following previous example,
+    * where anchor point was left, parent anchor should again either be left or center.
+    * Assuming orientation is horizontal, previous anchor should be right, anchoring the
+    * component to the end of the previous one. In a container, there can be two separate
+    * anchor stacks, one starting from left to right and the other starting from right to
+    * left. This also works with vertical layouts (top to bottom and bottom to top). This is
+    * controlled by the combination of the anchor and previous component anchor. If anchor is
+    * specified as right and previous anchor is left (or none and parent anchor is right),
+    * then the component will be anchored from the right. If previous anchor is none, component
+    * is always anchored to the parent. This may cause components to overlap. Components can
+    * only be anchored to their parents or other relative components.
+    * 
+    * First baseline anchor uses the baseline of the first text line. In the calculations, it
+    * is considered top aligned. Last baseline uses the baseline of the last text line. It is 
+    * considered as bottom alignment. If there is no text, first baseline is calculated from
+    * the top, last baseline is calculated from the bottom. Baseline can be specified in 
+    * template. When it is specified, that value will be used instead of calculated baseline.
+    * Last baseline alignments should only be used for textholders.
+    * 
+    * Positioning
+    * ===========
+    * The position of the component effects its place from the anchor. If anchored by left/top
+    * or center/middle x/y position is added to the anchor point. If anchored by right/bottom, 
+    * x/y position is subtracted. 
+    *
+    * In AbsoluteSliding positioning the component anchors to its parent. For relative size, 
+    * entire usable area of the parent is used. If the position is specified as percentage,
+    * remaining area after the component is placed is used. Ex: parent width: 100, component 
+    * width: 50, parent padding: 10, component x position: 50%, margin: 0. In this case,
+    * component width and padding is subtracted from parent width, 30px remains. This size is 
+    * used to calculate percentage position, which is 15px. If an component's size is 100%, 
+    * percentage base positioning will not have any effect on the position of the component.
+    * 
+    * Relative positioning is very similar to absolute positioning except the component can be
+    * anchored to other components and its percent based metrics uses remaining size of the
+    * parent in the oriented direction.
+    * 
+    * Absolute positioning is classical absolute positioning in many systems. It uses entirety 
+    * of the parent size to calculate percentage based positioning. In other aspects, it is 
+    * same with absolute sliding positioning.
+    * 
+    * PolarAbsolute changes coordinate system to polar coordinates. X axis becomes radius and
+    * Y axis becomes angle in degrees. Center is used to calculate transformation point. While
+    * calculating center point Absolute positioning is used. If radius is percentage based, the
+    * maximum size that will ensure component will stay within the parent will be used. Parent
+    * anchor is used to decide how to calculate this length. For instance, if the anchor point
+    * is TopCenter, then the max radius calculation assumes angle will change from 180-360. 
+    * This currently does not take value range into consideration. If desired, em size could 
+    * also be used for angle, which is set to 45deg. Component is then placed according to its
+    * center point. To use PolarAbsolute correctly, you should set center of parent, center of 
+    * component as well as parent anchor of the component (not self anchor) correctly. Setting
+    * parent anchor also adjusts maximum and starting angle so that the both radius 0-100% and 
+    * angle 0-100% will stay within the container. Angle always works counter clockwise. Angle 
+    * EM size is not changed by the anchor point, however, it is also affected by the starting 
+    * point. Also, when percentages or value modification is involved, it is advised to set 
+    * center point of the component so that it will be within the object. This offset will not
+    * be automatically done and will leave portions of the object outside its parent.
+    * 
+    * Position can be affected by the value modification system. In this case specified
+    * position is used as an addition with a percentage based value. 
+    * 
+    * It is possible for widgets to specify additional position for a specific tag. It is
+    * recommended to anchor such components to top left and instead of using position to place
+    * them, use spacing. Only one tag currently is used for position modification: ContentsTag.
+    * 
+    *  
+    */
+    
+    
+    /**
+     * @page uiconditions Conditions
+     * 
+     * There are many conditions that will effect the visibility/selection of each components.
+     * Using conditions, visuals of widgets can be modified. Conditions are supplied by the 
+     * widgets depending on their states. A simple example will be mouse over. 
+     * 
+     * Only one component can be present for every index. When there are multiple components 
+     * for the same index is present, the component to be shown is determined by the active
+     * conditions. If there are no conditions present, only components with Always condition
+     * will be visible. If there is a condition that matches a component, that particular
+     * component will be visible for that index. If there are multiple conditions active for 
+     * the same index, the last condition applied will take precedence. Not all conditions are
+     * supported by all widgets. For the list of conditions see @ref ComponentCondition.
+     * 
+     * Combining multiple conditions can be done by using containers. Containers could be set
+     * to obtain the size of its contents, with no spacing, it will not effect anything 
+     * visually. Having separate conditions for the container and the component will act as and
+     * operation as both conditions should be present for the component to be visible. For or
+     * operation, you can have two containers containing the same index with different 
+     * conditions. Indexes are global, therefore, if one of the containers is visible on the
+     * screen, component will be visible. A component cannot be in two separate containers at
+     * the *same* time. Thus the containers should have the same index for exclusivity.
+     * 
+     * Conditions can transition from one to another. These are also controlled by widgets. For
+     * transitions to work, it should be adjusted from the Template. First the transition 
+     * duration should be set. Then if the transition can be reversed, which is recommended, it
+     * should be set as well. Finally, there should be a component with transition from first
+     * condition to the second. This can be done by supplying two conditions to Add component
+     * functions. With reversed transition and using transition value channel to control the
+     * effect, one component can handle both conditions and the transition to both directions.
+     * 
+     * For instance, for a checkbox, an animation from unchecked to checked can be used for
+     * unchecked (Always), checked (State2), Always > State2, State2 > Always by waiting at
+     * first frame, waiting at last frame, running the animation forwards and running the 
+     * animation backwards. All of which can easily be handled by setting value source to
+     * Transition, value modification to ModifyAnimation, condition should be set to Always >
+     * State2 and finally, the durations for Always > State2 and State2 > Always transitions
+     * should be set.
+     * 
+     */
+    
+    /**
+     * @page valuechannels Value channels and modification
+     * 
+     * Value modification is an integral part of the UI mechanics. It allows widgets to specify
+     * values up to 4 channels. The components can be setup to be modified by these channels by
+     * various effects. In addition to these standard 4 channels, there is also transition
+     * channel, the value of which changes with the transition of the conditions.
+     * 
+     */
+
     PlaceholderTemplate& Template::AddPlaceholder(int index, ComponentCondition from, ComponentCondition to){ 
         auto obj = new PlaceholderTemplate();
         components.Add(obj);
--- a/Source/Gorgon/UI/Template.h	Sun Jul 12 16:15:09 2020 +0300
+++ b/Source/Gorgon/UI/Template.h	Fri Jul 17 16:19:15 2020 +0300
@@ -23,293 +23,9 @@
     /// Gorgon::Widgets namespace.
     namespace UI {
 
-    /**
-    * @page ui User interface
-    * 
-    * The user interface in Gorgon Library is based on the components system and is highly
-    * customizable. ComponentStack manages these components within a widget. There are
-    * different component types: containers (see @ref ContainerTemplate), placeholders (see
-    * @ref PlaceholderTemplate), graphics (see @ref GraphicsTemplate), and textholder (see 
-    * @ref TextholderTemplate). All subcomponents should be created from the main Template.
-    * 
-    * Each component has an index and containers have the index of the components that resides
-    * in them. There can be multiple components with the same index. ComponentCondition system
-    * is used to decide which components will exist at a given time. 
-    * 
-    * It is possible to control the transition of the widget from state to state by giving
-    * a specific component for the transition. This is generally used to animate state changes.
-    * It is also possible to use transition value channel to have value based animations. These
-    * animations can be reversed, even at the middle. In fact, even for regular bitmap
-    * animations, this is recommended as it can time the animation perfectly, allow it to be
-    * reversed at the middle of the transition (imagine mouse over). 
-    * 
-    * Components can be modified by ValueModification system. There are 4 widget controlled
-    * value channels and a fifth controlled by the transition. Values are expected to be in
-    * range from 0 to 1. But this can be changed by modifying value ranges. The aspect of the
-    * component that the value affects can also be controlled. Channels can be reordered to
-    * fit into the necessary order. Value changes can also be asked to be applied smoothly. But
-    * this is controlled through the widget.
-    * 
-    * Component data can be obtained by DataEffect. Data can currently be a text or an image.
-    * There are various data effects that can be used by graphics and textholder templates. 
-    * There are also conditions that trigger if a data channel has any data in it.
-    * 
-    * Components can be repeated. The repeats are controlled by the widget. Containers are not
-    * fully supported to be repeating structures. Other component types can be used with this
-    * system. Each repeat can have a different set value and condition. There are different
-    * repeating systems (such as minor and major) and each of these can be adjusted separately.
-    * 
-    * Components can have tags to be accessed from the widgets. Some widgets needs specific
-    * tags to exist in the template to work. 
-    * 
-    * Components are placed according to a series of complicated but intuitive rules. For 
-    * details of this system see @ref boxmodel.
-    * 
-    *
-    * @subpage components
-    * 
-    * @subpage boxmodel
-    * 
-    * @subpage validators
-    */
-    
-
-    /**
-    * @page components Components
-    * 
-    * Components are the building blocks of widgets. They are the visual elements
-    * that makes up most of the visual aspect of a widget. Components have templates,
-    * which they use as basis for their placement and drawing. ComponentTemplate is 
-    * the base class for all component templates. Components have component index
-    * and component condition (see ComponentCondition) to control which components
-    * will be visible at a given instance. Components have the same component indices
-    * but only one will be shown at a time. The components that have more specific
-    * condition will have precedence. For instance, if two components have index of 2
-    * and one has condition of ComponentCondition::Always and the other has condition
-    * of ComponentCondition::Focused, first component will be displayed unless the
-    * widget has received focus, in that case the second one will be shown.
-    * 
-    * 
-    * Every widget requires a container component at index 0 as the root. If this
-    * component has a non-0 size, the widget size will be fixed [this might change
-    * in the future].
-    * 
-    * 
-    * Components can be modified by the widget data. This is controlled through data
-    * effect. Various data effects exist to suit different type of widgets. See the
-    * widget documentation for specific data exported by them.
-    * 
-    * See @ref boxmodel to learn how the components are spaced out.
-    * 
-    * 
-    * How to create a simple button using components
-    * ==============================================
-    * Create the following templates:
-    * 
-    * @code
-    * ContainerTemplate, index = 0, background = bg image, set size, children = 1, 2
-    * TextholderTemplate, index = 2, set font, data effect = Text
-    * @endcode
-    * 
-    * These two templates will create a very simple button that has the background and
-    * it will display the text that is set by the programmer. If you wish to change the
-    * color of the text when the user moves mouse into the button, add the following
-    * template as well:
-    * 
-    * @code
-    * TextholderTemplate index = 2, set font, data effect = Text, condition = Hover
-    * @endcode
-    * 
-    * This component will override the previous if the mouse is over the button. In order
-    * to change the background when the user clicks the button, add the following:
-    * 
-    * @code
-    * ContainerTemplate, index = 0, background = pressed, set size, condition = Down, 
-    * children = 1, 2
-    * @endcode
-    * 
-    * This will change the background when the user presses the mouse button. Both hover and
-    * down conditions can occur at the same time. If user uses mouse to press the button
-    * they will both be active at the same time, however, if the user uses space bar to
-    * press the button when it is focused, only Down condition will be satisfied. In addition
-    * to these, it is helpful to provide a visual clue when the widget is focused. This
-    * is generally done by adding a focus rectangle like the following:
-    * 
-    * @code
-    * GraphicsTemplate, index = 1, Drawable = focus rectangle, Positioning = Absolute, 
-    * Size = 100, 100, Unit::Percent, set margin, condition = Focused
-    * @endcode
-    * 
-    * This last piece will only be shown when the button is focused. There will be no errors
-    * when it is invisible even when the container lists this template as its child.
-    * 
-    * 
-    * ###See also:
-    * 
-    * @ref boxmodel
-    */
-
-
-    /**
-    * @page boxmodel Component placement
-    * 
-    * Apart from the top level container, each component should be in container. Components
-    * arrangement in a container first depends on component positioning. If a component is 
-    * relatively positioned, then it will follow the container orientation to be stacked with 
-    * the other relatively positioned components.
-    * 
-    * Sizing
-    * ======
-    * Components have multiple sizing modes. The first set of options control how the component
-    * will be sized in case it contains an image, text, or another component stack. If the size
-    * is Fixed, the size of the contents is ignored. Automatic uses the size of the contents.
-    * GrowOnly, ShrinkOnly options allow component to grow/shrink if the contents is larger/
-    * smaller than the given size. Sizing can be adjusted separately for X and Y axis. When
-    * grow only and shrink only options are combined with relative sizing the size calculation
-    * is performed between fixed and always relative size calculation time. Mixing multiple
-    * automatic grow/shrink only, relatively sized components in the same container is not 
-    * recommended. The system will try to fit automatic grow/shrink relatively sized components
-    * as best as possible with a single pass. Ex: There are two components, both are 50% in
-    * width and one of them is shrink only, container has 100px usable size. If the shrink only
-    * component has a content of 40px, the other component will be grown to fill the remaining
-    * 60px, even though it will be more than 50%. If this is not desired, shrink only component
-    * can be placed inside a 50% sized container, and its relative size should be set 100%.
-    * 
-    * Component size can also be relative. In this case, container orientation plays an 
-    * important role. If the relatively sized axis is not in the oriented direction, then the 
-    * entire usable size of the parent is used for the calculation. However, if the axis is the
-    * oriented direction, then only the unused space is considered during the relative size
-    * calculation. For instance, in a horizontally oriented container, assume there are two
-    * components. One has a fixed width of 50px and the other is set to 100% and the container
-    * has 200px usable width. Assuming no additional spacing, second component will have 150px
-    * width. This calculation depends on how the components are anchored and margin/padding/
-    * indent/border size.
-    * 
-    * Size of the component can be influenced by the value channels. In this case, the size of
-    * component is used as additional size on top of the relative size depending on the channel
-    * value. 
-    *
-    * It is possible for widgets to specify additional size to tags. In these cases, the given
-    * size will be used as an addition to the original size. It is not recommended to use
-    * automatic sizing with tags that the widgets can use (e.g., ContentsTag).
-    * 
-    * 
-    * Spacing
-    * =======
-    * In this system 4 spacing methods are used. First method is border size. Border size is
-    * excluded from the internal area of a container. Thus (0, 0), does not include the border.
-    * In this system, borders are not drawn automatically, they are a part of the background
-    * image, therefore, border size is not calculated. It should be supplied.
-    * 
-    * The second spacing is provided by the padding of the container. Main difference of
-    * padding is that it collapses with the margin of the components as well as being counted
-    * in the container. If the padding for any edge is negative, it will not be collapsed.
-    * 
-    * Margins are spacing around the components. Unless negative, they collapse. This means if
-    * two components are anchored together, the margin between them is the maximum of the
-    * margin their touching edges. Negative margins are always added. 
-    * 
-    * Indent is the last spacing. It is additive and only used if a component is anchored to
-    * its parent. This is very useful in repeated or conditional components. For instance, if
-    * a button can have icon with text. You may want extra spacing on the text if there is no
-    * icon. This can be facilitated using Icon1IsSet condition and indent.
-    * 
-    * All spacing except for border size can be relative. For padding, the size of the
-    * component excluding the borders is used. For margin and indent, size of the parent 
-    * excluding the borders is used. 50% margin left will effectively start a component from 
-    * the center. However, anchoring should be used for this case.
-    * 
-    * 
-    * Anchoring
-    * =========
-    * All components are placed according to their anchor points. Relatively positioned 
-    * components can be anchored to another component, but absolutely positioned components
-    * are always anchored to their parent. Depending on the orientation, relative anchoring
-    * will be done to left/right or top/bottom. It is possible for anchoring to cause 
-    * artifacts, thus it should be used properly. 
-    * 
-    * Absolute anchoring is simple. It uses parent and anchor point. In this anchoring, the 
-    * component should be inside the parent. This means, if horizontal part of the anchor point
-    * is left, then parent anchor should either be left or center, so that the component will
-    * be placed in the parent. Otherwise the component will be placed outside the parent. If
-    * an absolutely positioned object is attached to left/top or right/bottom of its parent's
-    * center/middle, then the effective size of the container if only include right/bottom or
-    * left/top portion of the container. If spacing for both sides are equal, this will cut the
-    * usable size by half. This feature makes it easier to deal with center starting 
-    * components.
-    * 
-    * Relative anchoring requires previous component anchor dictated by the current component
-    * and parent anchor. These target anchor points should match. Following previous example,
-    * where anchor point was left, parent anchor should again either be left or center.
-    * Assuming orientation is horizontal, previous anchor should be right, anchoring the
-    * component to the end of the previous one. In a container, there can be two separate
-    * anchor stacks, one starting from left to right and the other starting from right to
-    * left. This also works with vertical layouts (top to bottom and bottom to top). This is
-    * controlled by the combination of the anchor and previous component anchor. If anchor is
-    * specified as right and previous anchor is left (or none and parent anchor is right),
-    * then the component will be anchored from the right. If previous anchor is none, component
-    * is always anchored to the parent. This may cause components to overlap. Components can
-    * only be anchored to their parents or other relative components.
-    * 
-    * First baseline anchor uses the baseline of the first text line. In the calculations, it
-    * is considered top aligned. Last baseline uses the baseline of the last text line. It is 
-    * considered as bottom alignment. If there is no text, first baseline is calculated from
-    * the top, last baseline is calculated from the bottom. Baseline can be specified in 
-    * template. When it is specified, that value will be used instead of calculated baseline.
-    * Last baseline alignments should only be used for textholders.
-    * 
-    * Positioning
-    * ===========
-    * The position of the component effects its place from the anchor. If anchored by left/top
-    * or center/middle x/y position is added to the anchor point. If anchored by right/bottom, 
-    * x/y position is subtracted. 
-    *
-    * In AbsoluteSliding positioning the component anchors to its parent. For relative size, 
-    * entire usable area of the parent is used. If the position is specified as percentage,
-    * remaining area after the component is placed is used. Ex: parent width: 100, component 
-    * width: 50, parent padding: 10, component x position: 50%, margin: 0. In this case,
-    * component width and padding is subtracted from parent width, 30px remains. This size is 
-    * used to calculate percentage position, which is 15px. If an component's size is 100%, 
-    * percentage base positioning will not have any effect on the position of the component.
-    * 
-    * Relative positioning is very similar to absolute positioning except the component can be
-    * anchored to other components and its percent based metrics uses remaining size of the
-    * parent in the oriented direction.
-    * 
-    * Absolute positioning is classical absolute positioning in many systems. It uses entirety 
-    * of the parent size to calculate percentage based positioning. In other aspects, it is 
-    * same with absolute sliding positioning.
-    * 
-    * PolarAbsolute changes coordinate system to polar coordinates. X axis becomes radius and
-    * Y axis becomes angle in degrees. Center is used to calculate transformation point. While
-    * calculating center point Absolute positioning is used. If radius is percentage based, the
-    * maximum size that will ensure component will stay within the parent will be used. Parent
-    * anchor is used to decide how to calculate this length. For instance, if the anchor point
-    * is TopCenter, then the max radius calculation assumes angle will change from 180-360. This
-    * currently does not take value range into consideration. If desired, em size could also be
-    * used for angle, which is set to 45deg. Component is then placed according to its center 
-    * point. To use PolarAbsolute correctly, you should set center of parent, center of component
-    * as well as parent anchor of the component (not self anchor) correctly. Setting parent anchor
-    * also adjusts maximum and starting angle so that the both radius 0-100% and angle 0-100%
-    * will stay within the container. Angle always works counter clockwise. Angle EM size is not
-    * changed by the anchor point, however, it is also affected by the starting point. Also, when
-    * percentages or value modification is involved, it is adviced to set center point of the 
-    * component so that it will be within the object. This offset will not be automatically done 
-    * and will leave portions of the object outside its parent.
-    * 
-    * Position can be affected by the value modification system. In this case specified
-    * position is used as an addition with a percentage based value. 
-    * 
-    * It is possible for widgets to specify additional position for a specific tag. It is
-    * recommended to anchor such components to top left and instead of using position to place
-    * them, use spacing. Only one tag currently is used for position modification: ContentsTag.
-    * 
-    *  
-    */
-
     // TextPlaceholder
     // TextPlaceholder should have its own layer (same for others?)
-    // Obtained size, position, think about animation frame
+    // Obtained size, position
     // 
 
     /// Anchor position
@@ -469,10 +185,10 @@
         /// Component is visible when the widget is readonly.
         Readonly,
 
-        
+        /// Widget has the focus
         Focused,
 
-        
+        /// Mouse is over the widget, or over a particular repeat
         Hover,
         
         /// This is activated when the mouse is pressed on the component stack. However,
@@ -480,10 +196,13 @@
         Down,
         
 
+        /// Second state of the widget, first state is Always
         State2,
 
+        /// Third state of the widget, first state is Always
         State3,
 
+        /// Fourth state of the widget, first state is Always
         State4,
 
         /// This condition is triggered when the widget is opened like a combobox
@@ -499,12 +218,16 @@
         /// for the base state.
         Closed,
         
+        /// This is for widgets that can be activated, like a count down timer
         Active,
         
+        /// There is space horizontally to be scrolled
         HScroll,
         
+        /// There is space vertically to be scrolled.
         VScroll,
         
+        /// There is space both horizontally and vertically to be scrolled.
         HVScroll,
 
         /// Channel 1 value is 0, the value will be
@@ -1606,7 +1329,7 @@
 
     /**
      * Textholder is designed to hold text data. This data is set by the widget through
-     * DataEffect.
+     * DataEffect. Alignment for this component uses baseline and it is automatically sized.
      */
     class TextholderTemplate : public ComponentTemplate {
     public:
@@ -1614,6 +1337,7 @@
             my = Anchor::FirstBaselineLeft;
             previous = Anchor::FirstBaselineRight;
             container = Anchor::FirstBaselineLeft;
+            SetSizing(Automatic);
         }
 
         /// Returns the type of the component.
--- a/Testing/Source/Manual/GraphicsHelper.h	Sun Jul 12 16:15:09 2020 +0300
+++ b/Testing/Source/Manual/GraphicsHelper.h	Fri Jul 17 16:19:15 2020 +0300
@@ -117,7 +117,7 @@
 				  , 600, 10, wind.GetWidth()-605
 		);
 
-		wind.KeyEvent.Register([this](Input::Key key, bool state) {
+		wind.KeyEvent.Register([](Input::Key key, bool state) {
 			if(!state && (key == 27 || key == 65307))
 				exit(0);
 
--- a/Testing/Source/Manual/UI_Component.cpp	Sun Jul 12 16:15:09 2020 +0300
+++ b/Testing/Source/Manual/UI_Component.cpp	Fri Jul 17 16:19:15 2020 +0300
@@ -11,18 +11,35 @@
 std::string helptext = 
     "Key list:\n"
     "d\tToggle disabled\n"
-    "left, right\tPrevious, next test\n"
+    "left\tPrevious\n"
+    "right\tNext test\n"
     "c\tCopy title of the active test\n"
     "1234\tIncrease the value of the stack\n"
     "qwer\tDecrease the value of the stack\n"
     "Shift\tSlower value change\n"
     "Ctrl\tFaster value change, snaps to nearest 20%\n"
+    "56\tChange text, title\n"
+    "78\tChange icon1, icon2\n"
     "esc\tClose\n"
 ;
 
 using namespace Gorgon::UI;
 namespace Color = Gorgon::Graphics::Color;
 
+struct TestData {
+    std::string name, description;
+    ComponentStack &stack;
+};
+
+extern std::vector<std::function<TestData(Layer &)>> tests;
+
+Application &getapp() {
+    auto help = helptext + String::Concat("\nTotal tests:\t", tests.size());
+    static Application app("uitest", "UI Component Test", help, 10, 8);
+    
+    return app;
+}
+
 //BEGIN Helpers
 
 Graphics::RectangleProvider &coloredrect(Graphics::RGBA color) {
@@ -80,7 +97,7 @@
 }
 
 Graphics::BlankImage &greenimg2x2() {
-    static auto &img = blankimage(Graphics::Color::Green, {1, 2});
+    static auto &img = blankimage(Graphics::Color::Green, {2, 2});
     
     return img;
 }
@@ -166,6 +183,22 @@
     return anim;
 }
 
+
+const std::string teststrings[] = {
+    "Hi",
+    "Hello",
+    "Hello world!",
+    "This is a very long text."
+};
+
+const Graphics::BlankImage *testimages[] = {
+    &orangeimg(),
+    &greenimg1x2(),
+    &greenimg2x1(),
+    &greenimg2x2(),
+    &redimg()
+};
+
 //END helpers
 
 
@@ -177,10 +210,48 @@
  * will live until the program ends. Create the function and
  * add it to the tests vector.
  ***********/
-struct TestData {
-    std::string name, description;
-    ComponentStack &stack;
-};
+
+TestData test_graphic(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.AddGraphics(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.Content.SetAnimation(greenimg());
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Graphic component", "10x10 green object on a 50x50 white background, should be aligned to top left.", stack};
+}
+
+TestData test_text(Layer &layer) {
+    auto &app = getapp();
+
+    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.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetText("Hello");
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Text component", "Brown Hello on 50x50 white background, should be aligned to top left.", stack};
+}
 
 TestData test_setsize(Layer &layer) {
     auto &temp = *new Template;
@@ -1657,8 +1728,179 @@
     return {"Blend", "80x80 cyan rectangle contains a 60x60 rectangle. It is an animation with 10 colors (red, orange, yellow, green, cyan, blue, magenta, white, grey, black), channel 1 can be used to control the animation frame. 0-10 should be red, orange starts from 11, yellow starts from 21 and so on.", stack};
 }
 
+TestData test_data_settext(Layer &layer) {
+    auto &app = getapp();
+
+    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.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Text);
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set text data", "Brown text obtained from text data on 50x50 white background, should be aligned to top left. Extra text should overflow.", stack};
+}
+
+TestData test_data_textwrap(Layer &layer) {
+    auto &app = getapp();
+
+    auto &temp = *new Template;
+    temp.SetSize(70, 50);
+    
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Text);
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Text wrap", "Brown text obtained from text data on 70x50 white background, should be aligned to top left. Extra text should wrap but completely visible.", stack};
+}
+
+TestData test_data_textclip(Layer &layer) {
+    auto &app = getapp();
+
+    auto &temp = *new Template;
+    temp.SetSize(70, 50);
+    
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Text);
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    cont2.SetSize(100, 100, Gorgon::UI::Dimension::Percent);
+    cont2.SetClip(true);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Text clipping", "Brown text obtained from text data on 70x50 white background, should be aligned to top left. Extra text should wrap and clipped.", stack};
+}
+
+TestData test_data_settitle(Layer &layer) {
+    auto &app = getapp();
+
+    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.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Title);
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set title data", "Brown text obtained from title data on 50x50 white background, should be aligned to top left. Extra text should overflow.", stack};
+}
+
+TestData test_data_settexttitle(Layer &layer) {
+    auto &app = getapp();
+
+    auto &temp = *new Template;
+    temp.SetSize(120, 50);
+    
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddTextholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Title);
+    cont2.SetColor(Color::Brown);
+    cont2.SetRenderer(app.fntlarge);
+    
+    auto &cont3 = temp.AddTextholder(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetDataEffect(Gorgon::UI::ComponentTemplate::Text);
+    cont3.SetColor(Color::DarkGreen);
+    cont3.SetRenderer(app.fnt);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set text data, title", "Brown text obtained from title data followed by small green text obtained from text on 120x50 white background, should be aligned to top left. Extra text should overflow. Two text components should be aligned from the baseline.", stack};
+}
+
+TestData test_data_setimage(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.AddPlaceholder(1, Gorgon::UI::ComponentCondition::Always);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Icon1);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set image data", "Selected image obtained from icon 1 data on 50x50 white background, should be aligned to top left.", stack};
+}
+
+TestData test_data_setimage2(Layer &layer) {
+    auto &temp = *new Template;
+    temp.SetSize(50, 50);
+    
+    auto &cont1 = temp.AddContainer(0, Gorgon::UI::ComponentCondition::Always);
+    cont1.AddIndex(1);
+    cont1.AddIndex(2);
+    cont1.Background.SetAnimation(whiteimg());
+    
+    auto &cont2 = temp.AddPlaceholder(1, Gorgon::UI::ComponentCondition::Icon1IsSet);
+    cont2.SetDataEffect(Gorgon::UI::ComponentTemplate::Icon1);
+    
+    auto &cont3 = temp.AddPlaceholder(2, Gorgon::UI::ComponentCondition::Always);
+    cont3.SetDataEffect(Gorgon::UI::ComponentTemplate::Icon2);
+    cont3.SetAnchor(Gorgon::UI::Anchor::BottomRight, Gorgon::UI::Anchor::BottomLeft, Gorgon::UI::Anchor::BottomLeft);
+    
+    auto &stack = *new ComponentStack(temp);
+    stack.HandleMouse();
+    
+    layer.Add(stack);
+    
+    return {"Set image data 2", "Selected image obtained from icon 1 data and icon 2 data on 50x50 white background, should be aligned to top left. Second image should be aligned to bottom right of the first one. If the first one is empty, it should anchor to the bottom left of its parent.", stack};
+}
+
 
 std::vector<std::function<TestData(Layer &)>> tests = {
+    
+    &test_graphic,
+    &test_text,
+    
     &test_setsize,
     &test_setsizepercent,
     &test_setsizepercent_percent,
@@ -1724,6 +1966,15 @@
     &test_modify_blend4,
     
     &test_modify_animation,
+    
+    &test_data_settext,
+    &test_data_textwrap,
+    &test_data_textclip,
+    &test_data_settitle,
+    &test_data_settexttitle,
+    
+    &test_data_setimage,
+    &test_data_setimage2,
 };
 
 //END tests
@@ -1734,8 +1985,7 @@
 Input::KeyRepeater repeater;
     
 int main() {
-    helptext += String::Concat("\nTotal tests:\t", tests.size());
-    Application app("uitest", "UI Component Test", helptext, 10, 8);
+    auto &app = getapp();
 
     int xs = 50, ys = 20, w = 500, h = 400;
     
@@ -1816,7 +2066,9 @@
                     "Value 1:\t", int(activestack->GetValue()[0]*100),"\n",
                     "Value 2:\t", int(activestack->GetValue()[1]*100),"\n",
                     "Value 3:\t", int(activestack->GetValue()[2]*100),"\n",
-                    "Value 4:\t", int(activestack->GetValue()[3]*100),"\n"
+                    "Value 4:\t", int(activestack->GetValue()[3]*100),"\n",
+                    "Text   :\t", activestack->GetTextData(Gorgon::UI::ComponentTemplate::Text), "\n",
+                    "Title  :\t", activestack->GetTextData(Gorgon::UI::ComponentTemplate::Title), "\n"
                 ),
                 0,0, datalayer.GetWidth(), Gorgon::Graphics::TextAlignment::Left
             );
@@ -1928,6 +2180,108 @@
                 exit(0);
                 break;
                 
+            case Keycodes::Number_5: {
+                std::string text = activestack->GetTextData(Gorgon::UI::ComponentTemplate::Text);
+                
+                switch(text.length()) {
+                case 0:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Text, teststrings[0]);
+                    break;
+                case 2:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Text, teststrings[1]);
+                    break;
+                case 5:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Text, teststrings[2]);
+                    break;
+                case 12:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Text, teststrings[3]);
+                    break;
+                default:
+                    activestack->RemoveData(Gorgon::UI::ComponentTemplate::Text);
+                    break;
+                }
+                
+                displayvalue();
+                
+                break;
+            }
+            
+            case Keycodes::Number_6: {
+                std::string text = activestack->GetTextData(Gorgon::UI::ComponentTemplate::Title);
+                
+                switch(text.length()) {
+                case 0:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Title, teststrings[0]);
+                    break;
+                case 2:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Title, teststrings[1]);
+                    break;
+                case 5:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Title, teststrings[2]);
+                    break;
+                case 12:
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Title, teststrings[3]);
+                    break;
+                default:
+                    activestack->RemoveData(Gorgon::UI::ComponentTemplate::Title);
+                    break;
+                }
+                
+                displayvalue();
+                
+                break;
+            }
+                
+            case Keycodes::Number_7: {
+                auto img = activestack->GetImageData(Gorgon::UI::ComponentTemplate::Icon1);
+                
+                if(img == testimages[4]) {
+                    activestack->RemoveData(Gorgon::UI::ComponentTemplate::Icon1);
+                }
+                else if(img == testimages[0]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon1, *testimages[1]);
+                }
+                else if(img == testimages[1]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon1, *testimages[2]);
+                }
+                else if(img == testimages[2]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon1, *testimages[3]);
+                }
+                else if(img == testimages[3]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon1, *testimages[4]);
+                }
+                else {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon1, *testimages[0]);
+                }
+                
+                break;
+            }
+            
+            case Keycodes::Number_8: {
+                auto img = activestack->GetImageData(Gorgon::UI::ComponentTemplate::Icon2);
+                
+                if(img == testimages[4]) {
+                    activestack->RemoveData(Gorgon::UI::ComponentTemplate::Icon2);
+                }
+                else if(img == testimages[0]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon2, *testimages[1]);
+                }
+                else if(img == testimages[1]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon2, *testimages[2]);
+                }
+                else if(img == testimages[2]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon2, *testimages[3]);
+                }
+                else if(img == testimages[3]) {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon2, *testimages[4]);
+                }
+                else {
+                    activestack->SetData(Gorgon::UI::ComponentTemplate::Icon2, *testimages[0]);
+                }
+                
+                break;
+            }
+            
             case Keycodes::Shift:
                 repeater.SetInitialDelay(500);
                 repeater.SetDelay(500);

mercurial