/**
  * This methods takes a attribute object and overrides styles that
  * are present and not null. All properties are null by default and
  * will only be cascaded if is present
  */
 public UIAttributes CascadeAttributes(UIAttributes cascadingAttributes)
 {
     return(new UIAttributes
     {
         TextureKey = cascadingAttributes.TextureKey ?? TextureKey,
         FontKey = cascadingAttributes.FontKey ?? FontKey,
         // ReSharper disable once CompareOfFloatsByEqualityOperator
         FontSize = cascadingAttributes.FontSize != 1f ? cascadingAttributes.FontSize : FontSize,
         X = cascadingAttributes.X != 0 ? cascadingAttributes.X : X,
         Y = cascadingAttributes.Y != 0 ? cascadingAttributes.Y : Y,
         OffsetX = cascadingAttributes.OffsetX != 0 ? cascadingAttributes.OffsetX : OffsetX,
         OffsetY = cascadingAttributes.OffsetY != 0 ? cascadingAttributes.OffsetY : OffsetY,
         Width = cascadingAttributes.Width != 0 ? cascadingAttributes.Width : Width,
         Height = cascadingAttributes.Height != 0 ? cascadingAttributes.Height : Height,
         Color = cascadingAttributes.Color != Color.Black ? cascadingAttributes.Color : Color,
         Background = cascadingAttributes.Background != Color.Transparent ? cascadingAttributes.Background : Background,
         Grow = cascadingAttributes.Grow != 1 ? cascadingAttributes.Grow : Grow,
         BorderSize = cascadingAttributes.BorderSize != 0 ? cascadingAttributes.BorderSize : BorderSize,
         BorderColor = cascadingAttributes.BorderColor != Color.Black ? cascadingAttributes.BorderColor : BorderColor,
         Position = cascadingAttributes.Position != Position.Relative ? cascadingAttributes.Position : Position,
         Sizing = cascadingAttributes.Sizing != Sizing.Proportion ? cascadingAttributes.Sizing : Sizing,
         Overflow = cascadingAttributes.Overflow != Overflow.Show ? cascadingAttributes.Overflow : Overflow,
         JustifyText = cascadingAttributes.JustifyText != JustifyText.Center ? cascadingAttributes.JustifyText : JustifyText,
         VerticalAlignText = cascadingAttributes.VerticalAlignText != VerticalAlignText.Center ? cascadingAttributes.VerticalAlignText : VerticalAlignText,
         TextWrap = cascadingAttributes.TextWrap != TextWrap.Wrap ? cascadingAttributes.TextWrap : TextWrap,
         FontScaleMode = cascadingAttributes.FontScaleMode != FontScaleMode.FontSizeScale ? cascadingAttributes.FontScaleMode : FontScaleMode,
         StackDirection = cascadingAttributes.StackDirection != StackDirection.None ? cascadingAttributes.StackDirection : StackDirection,
     });
 }
        protected UIComponent(string name, bool updateable = false)
        {
            //Component name
            Name = name;

            //Indexing for drawing children
            Index          = 0;
            NextChildIndex = 0;

            //Parent and children
            Parent   = null;
            Children = new List <UIComponent>();

            //UIConstraints and attributes
            Constraints       = new List <UIConstraint>();
            DefaultAttributes = new UIAttributes
            {
                TextureKey = "default",
                FontKey    = "default",
                Grow       = 1,
                FontSize   = 1,
                Background = Color.Transparent,
                Color      = Color.Black,
                Position   = Position.Relative
            };

            RenderAttributes = new UIAttributes();

            //Events and focus
            Focusable     = false;
            Updateable    = updateable;
            EventHandlers = new Dictionary <string, Action <UIEvent> >();
        }
        /**
         * Used to generate a UIComponent making use of all applied constraints and modifiers.
         * Modifiers and constraints are applied in the same order as they are defined
         */
        public void Build(UILayer layer)
        {
            #region Inherit/Defaults

            DefaultAttributes.X      = Parent?.DefaultAttributes.X ?? 0;
            DefaultAttributes.Y      = Parent?.DefaultAttributes.Y ?? 0;
            DefaultAttributes.Width  = Parent?.DefaultAttributes.Width ?? DefaultAttributes.Width;
            DefaultAttributes.Height = Parent?.DefaultAttributes.Height ?? DefaultAttributes.Height;

            if (DefaultAttributes.StackDirection == StackDirection.Inherit)
            {
                DefaultAttributes.StackDirection = Parent?.DefaultAttributes.StackDirection ?? StackDirection.None;
            }

            if (DefaultAttributes.Overflow == Overflow.Inherit)
            {
                DefaultAttributes.Overflow = Parent?.DefaultAttributes.Overflow ?? Overflow.Show;
            }

            if (DefaultAttributes.Sizing == Sizing.Inherit)
            {
                DefaultAttributes.Sizing = Parent?.DefaultAttributes.Sizing ?? Sizing.Proportion;
            }

            if (DefaultAttributes.Position == Position.Inherit)
            {
                DefaultAttributes.Position = Parent?.DefaultAttributes.Position ?? Position.Relative;
            }

            if (DefaultAttributes.JustifyText == JustifyText.Inherit)
            {
                DefaultAttributes.JustifyText = Parent?.DefaultAttributes.JustifyText ?? JustifyText.Start;
            }

            if (DefaultAttributes.TextWrap == TextWrap.Inherit)
            {
                DefaultAttributes.TextWrap = Parent?.DefaultAttributes.TextWrap ?? TextWrap.Wrap;
            }

            if (DefaultAttributes.FontScaleMode == FontScaleMode.Inherit)
            {
                DefaultAttributes.FontScaleMode = Parent?.DefaultAttributes.FontScaleMode ?? FontScaleMode.FontSizeScale;
            }

            if (DefaultAttributes.VerticalAlignText == VerticalAlignText.Inherit)
            {
                DefaultAttributes.VerticalAlignText = Parent?.DefaultAttributes.VerticalAlignText ?? VerticalAlignText.Start;
            }

            #endregion

            #region Apply Contraints/ Build Indexes

            if (EventHandlers.Any())
            {
                layer.AddEventComponent(this);
            }

            if (Focusable)
            {
                layer.AddTabIndexComponent(this);
            }

            if (Updateable)
            {
                layer.AddUpdateIndexComponent(this);
            }

            #endregion

            //If the parent node is null then we stop here
            if (Parent != null)
            {
                if (Parent.DefaultAttributes.Sizing == Sizing.Proportion)
                {
                    #region Proportional Container Positioning

                    int totalProportionNumber   = Parent.Children.Sum(x => x.DefaultAttributes.Grow);
                    int leadingProportionNumber = Parent.Children.TakeWhile(child => child.Index != Index).Sum(x => x.DefaultAttributes.Grow);

                    //Correctly render in the correct stack direction
                    switch (Parent.DefaultAttributes.StackDirection)
                    {
                    case StackDirection.Horizontal:

                        int oneProportionWidth = DefaultAttributes.Width / totalProportionNumber;

                        DefaultAttributes.X      += leadingProportionNumber * oneProportionWidth;
                        DefaultAttributes.OffsetX = leadingProportionNumber * oneProportionWidth;
                        DefaultAttributes.Width   = oneProportionWidth * DefaultAttributes.Grow;
                        break;

                    case StackDirection.Vertical:

                        int oneProportionHeight = DefaultAttributes.Height / totalProportionNumber;

                        DefaultAttributes.Y      += leadingProportionNumber * oneProportionHeight;
                        DefaultAttributes.OffsetY = leadingProportionNumber * oneProportionHeight;
                        DefaultAttributes.Height  = oneProportionHeight * DefaultAttributes.Grow;
                        break;
                    }

                    #endregion
                }
                else if (Parent.DefaultAttributes.Sizing == Sizing.Dimension)
                {
                    #region Dimensional Container Positioning

                    switch (Parent.DefaultAttributes.StackDirection)
                    {
                    case StackDirection.Horizontal:
                        int nextWidth = Index * Parent.Children[0].DefaultAttributes.Width;
                        DefaultAttributes.X      += nextWidth;
                        DefaultAttributes.OffsetX = nextWidth;
                        break;

                    case StackDirection.Vertical:
                        int nextHeight = Index * Parent.Children[0].DefaultAttributes.Height;
                        DefaultAttributes.Y      += nextHeight;
                        DefaultAttributes.OffsetY = nextHeight;
                        break;
                    }

                    #endregion
                }
            }

            foreach (UIConstraint uiConstraint in Constraints)
            {
                uiConstraint.Apply(this);
            }

            RenderAttributes = DefaultAttributes.CascadeAttributes(DefaultAttributes);
        }