internal override bool UpdateSubTree()
        {
            if (!base.UpdateSubTree())
            {
                return(false);
            }

            if (!autoSize.EnsureValid())
            {
                autoSize.Refresh(delegate
                {
                    Vector2 b = DrawQuadForBounds.BottomRight;

                    InternalSize = new Vector2((RelativeSizeAxes & Axes.X) > 0 ? InternalSize.X : b.X, (RelativeSizeAxes & Axes.Y) > 0 ? InternalSize.Y : b.Y);
                    Invalidate(Invalidation.Position);

                    //note that this is called before autoSize becomes valid. may be something to consider down the line.
                    //might work better to add an OnRefresh event in Cached<> and invoke there.
                    OnAutoSize?.Invoke();

                    return(b);
                });
            }

            return(true);
        }
        private void updateAutoSize()
        {
            isComputingAutosize = true;
            try
            {
                if (autoSize.EnsureValid())
                {
                    return;
                }

                autoSize.Refresh(delegate
                {
                    Vector2 b = computeAutoSize() + Padding.Total;

                    if ((RelativeSizeAxes & Axes.X) == 0)
                    {
                        base.Width = b.X;
                    }
                    if ((RelativeSizeAxes & Axes.Y) == 0)
                    {
                        base.Height = b.Y;
                    }

                    //note that this is called before autoSize becomes valid. may be something to consider down the line.
                    //might work better to add an OnRefresh event in Cached<> and invoke there.
                    OnAutoSize?.Invoke();
                });
            }
            finally
            {
                isComputingAutosize = false;
            }
        }
Beispiel #3
0
        protected override void UpdateLayout()
        {
            base.UpdateLayout();

            if (!activeMode.EnsureValid())
            {
                activeMode.Refresh(() => modeButtonLine.MoveToX(activeButton.DrawPosition.X, 200, EasingTypes.OutQuint));
            }
        }
Beispiel #4
0
        protected override void UpdateAfterChildren()
        {
            base.UpdateAfterChildren();

            if (!layout.EnsureValid())
            {
                layout.Refresh(delegate
                {
                    OnLayout?.Invoke();

                    if (!Children.Any())
                    {
                        return;
                    }

                    var positions = ComputeLayoutPositions().ToArray();

                    int i = 0;
                    foreach (var d in FlowingChildren)
                    {
                        if (i > positions.Length)
                        {
                            throw new InvalidOperationException(
                                $"{GetType().FullName}.{nameof(ComputeLayoutPositions)} returned a total of {positions.Length} positions for {i} children. {nameof(ComputeLayoutPositions)} must return 1 position per child.");
                        }

                        if ((d.RelativeSizeAxes & AutoSizeAxes) != 0)
                        {
                            throw new InvalidOperationException(
                                "Drawables inside a flow container may not have a relative size axis that the flow container is auto sizing for." +
                                $"The flow container is set to autosize in {AutoSizeAxes} axes and the child is set to relative size in {d.RelativeSizeAxes} axes.");
                        }

                        if (d.RelativePositionAxes != Axes.None)
                        {
                            throw new InvalidOperationException($"A flow container cannot contain a child with relative positioning (it is {d.RelativePositionAxes}).");
                        }

                        var finalPos = positions[i];
                        if (d.Position != finalPos)
                        {
                            d.MoveTo(finalPos, LayoutDuration, LayoutEasing);
                        }

                        ++i;
                    }

                    if (i != positions.Length)
                    {
                        throw new InvalidOperationException(
                            $"{GetType().FullName}.{nameof(ComputeLayoutPositions)} returned a total of {positions.Length} positions for {i} children. {nameof(ComputeLayoutPositions)} must return 1 position per child.");
                    }
                });
            }
        }
Beispiel #5
0
        /// <summary>
        /// Apply this drawable to the draw node
        /// </summary>
        /// <param name="node">The node to apply properties to</param>
        protected virtual void ApplyDrawNode(DrawNode3D node)
        {
            node.WorldMatrix = WorldMatrix;

            node.ColourInfo = ColourInfo;
            if (node.ColourInfo.HasSingleColour)
            {
                node.ColourInfo = node.ColourInfo.MultiplyAlpha(Alpha);
            }
            node.Blending = blendingInfo.EnsureValid() ? blendingInfo.Value : blendingInfo.Refresh(() => new BlendingInfo(blendingMode));
        }
Beispiel #6
0
        private void refreshLayout()
        {
            if (internalSize.EnsureValid())
            {
                return;
            }

            internalSize.Refresh(delegate
            {
                if (FixedWidth && !constantWidth.HasValue)
                {
                    constantWidth = CreateCharacterDrawable('D').DrawWidth;
                }

                //keep sprites which haven't changed since last layout.
                List <Drawable> keepDrawables = new List <Drawable>();

                bool allowKeepingExistingDrawables = true;

                //adjust shadow alpha based on highest component intensity to avoid muddy display of darker text.
                //squared result for quadratic fall-off seems to give the best result.
                var avgColour     = (Color4)DrawInfo.Colour.AverageColour;
                float shadowAlpha = (float)Math.Pow(Math.Max(Math.Max(avgColour.R, avgColour.G), avgColour.B), 2);

                //we can't keep existing drawabled if our shadow has changed, as the shadow is applied in the add-loop.
                //this could potentially be optimised if necessary.
                allowKeepingExistingDrawables &= shadowAlpha == lastShadowAlpha && font == lastFont;

                lastShadowAlpha = shadowAlpha;
                lastFont        = font;

                if (allowKeepingExistingDrawables)
                {
                    int length = Math.Min(lastText?.Length ?? 0, text.Length);
                    keepDrawables.AddRange(Children.TakeWhile((n, i) => i < length && lastText[i] == text[i]));
                    Remove(keepDrawables); //doesn't dispose
                }

                Clear();

                if (text.Length == 0)
                {
                    return(Vector2.Zero);
                }

                foreach (var k in keepDrawables)
                {
                    Add(k);
                }

                for (int index = keepDrawables.Count; index < text.Length; index++)
                {
                    char c = text[index];

                    bool fixedWidth = FixedWidth && !FixedWidthExceptionCharacters.Contains(c);

                    Drawable d;

                    if (char.IsWhiteSpace(c))
                    {
                        float width = fixedWidth ? constantWidth.GetValueOrDefault() : spaceWidth;

                        switch ((int)c)
                        {
                        case 0x3000:     //double-width space
                            width *= 2;
                            break;
                        }

                        d = new Container
                        {
                            Size   = new Vector2(width),
                            Scale  = new Vector2(TextSize),
                            Colour = Color4.Transparent,
                        };
                    }
                    else
                    {
                        d = CreateCharacterDrawable(c);

                        if (fixedWidth)
                        {
                            d.Anchor = Anchor.TopCentre;
                            d.Origin = Anchor.TopCentre;
                        }

                        var ctn = new Container
                        {
                            Size     = new Vector2(fixedWidth ? constantWidth.GetValueOrDefault() : d.DrawSize.X, UseFullGlyphHeight ? 1 : d.DrawSize.Y),
                            Scale    = new Vector2(TextSize),
                            Children = new[] { d }
                        };

                        if (shadow && shadowAlpha > 0)
                        {
                            Drawable shadowDrawable = CreateCharacterDrawable(c);
                            shadowDrawable.Position = new Vector2(0, 0.06f);
                            shadowDrawable.Anchor   = d.Anchor;
                            shadowDrawable.Origin   = d.Origin;
                            shadowDrawable.Alpha    = shadowAlpha;
                            shadowDrawable.Colour   = shadowColour;
                            shadowDrawable.Depth    = float.MaxValue;
                            ctn.Add(shadowDrawable);
                        }

                        d = ctn;
                    }

                    Add(d);
                }

                lastText = text;
                return(Vector2.Zero);
            });
        }
Beispiel #7
0
        private void refreshLayout()
        {
            if (internalSize.EnsureValid())
            {
                return;
            }

            internalSize.Refresh(delegate
            {
                if (FixedWidth && !constantWidth.HasValue)
                {
                    constantWidth = CreateCharacterDrawable('D').DrawWidth;
                }

                //keep sprites which haven't changed since last layout.
                List <Drawable> keepDrawables = new List <Drawable>();
                int length = Math.Min(lastText?.Length ?? 0, text?.Length ?? 0);

                keepDrawables.AddRange(Children.TakeWhile((n, i) => i < length && lastText[i] == text[i]));
                Remove(keepDrawables);
                Clear();

                foreach (var k in keepDrawables)
                {
                    Add(k);
                }

                for (int index = keepDrawables.Count; index < text.Length; index++)
                {
                    char c = text[index];

                    Drawable d;

                    if (char.IsWhiteSpace(c))
                    {
                        float width = FixedWidth ? constantWidth.GetValueOrDefault() : spaceWidth;

                        switch ((int)c)
                        {
                        case 0x3000:     //double-width space
                            width *= 2;
                            break;
                        }

                        d = new Container
                        {
                            Size   = new Vector2(width),
                            Scale  = new Vector2(TextSize),
                            Colour = Color4.Transparent,
                        };
                    }
                    else
                    {
                        d = CreateCharacterDrawable(c);

                        if (FixedWidth)
                        {
                            d.Anchor = Anchor.TopCentre;
                            d.Origin = Anchor.TopCentre;
                        }

                        var ctn = new Container
                        {
                            Size     = new Vector2(FixedWidth ? constantWidth.GetValueOrDefault() : d.DrawSize.X, UseFullGlyphHeight ? 1 : d.DrawSize.Y),
                            Scale    = new Vector2(TextSize),
                            Children = new[] { d }
                        };

                        if (shadow)
                        {
                            Drawable shadowDrawable = CreateCharacterDrawable(c);
                            shadowDrawable.Position = new Vector2(0, 0.06f);
                            shadowDrawable.Colour   = shadowColour;
                            shadowDrawable.Depth    = float.MaxValue;
                            ctn.Add(shadowDrawable);
                        }

                        d = ctn;
                    }

                    Add(d);
                }

                lastText = text;
                return(Vector2.Zero);
            });
        }
Beispiel #8
0
        private void refreshLayout()
        {
            if (internalSize.EnsureValid())
            {
                return;
            }

            internalSize.Refresh(delegate
            {
                if (FixedWidth && !constantWidth.HasValue)
                {
                    constantWidth = getSprite('D').DrawWidth;
                }

                //keep sprites which haven't changed since last layout.
                List <Drawable> keepDrawables = new List <Drawable>();
                int length = Math.Min(lastText?.Length ?? 0, text?.Length ?? 0);

                keepDrawables.AddRange(Children.TakeWhile((n, i) => i < length && lastText[i] == text[i]));
                Remove(keepDrawables);
                Clear();

                foreach (var k in keepDrawables)
                {
                    Add(k);
                }

                for (int index = keepDrawables.Count; index < text.Length; index++)
                {
                    char c = text[index];

                    Drawable s;

                    if (char.IsWhiteSpace(c))
                    {
                        float width = FixedWidth ? constantWidth.GetValueOrDefault() : spaceWidth;

                        switch ((int)c)
                        {
                        case 0x3000:     //double-width space
                            width *= 2;
                            break;
                        }

                        s = new Container
                        {
                            Size   = new Vector2(width),
                            Colour = Color4.Transparent,
                        };
                    }
                    else
                    {
                        s = getSprite(c);

                        if (FixedWidth)
                        {
                            s.Anchor = Anchor.TopCentre;
                            s.Origin = Anchor.TopCentre;
                        }

                        var ctn = new Container
                        {
                            Size     = new Vector2(FixedWidth ? constantWidth.GetValueOrDefault() : s.DrawSize.X, 1f),
                            Children = new[] { s }
                        };

                        s = ctn;
                    }

                    Add(s);
                }

                lastText = text;
                return(Vector2.Zero);
            });
        }
Beispiel #9
0
        protected override void UpdateLayout()
        {
            base.UpdateLayout();

            if (!layout.EnsureValid())
            {
                layout.Refresh(delegate
                {
                    OnLayout?.Invoke();

                    if (Children.FirstOrDefault() == null)
                    {
                        return(Vector2.Zero);
                    }

                    Vector2 current = new Vector2(Math.Max(0, Padding.X), Math.Max(0, Padding.Y));

                    Vector2 max = maximumSize;
                    if (direction == FlowDirection.Full && maximumSize == Vector2.Zero)
                    {
                        var s = Size;

                        //If we are autosize and haven't specified a maximum size, we should allow infinite expansion.
                        //If we are inheriting then we need to use the parent size (our ActualSize).
                        max.X = (RelativeSizeAxes & Axes.X) == 0 ? float.MaxValue : s.X;
                        max.Y = (RelativeSizeAxes & Axes.Y) == 0 ? float.MaxValue : s.Y;
                    }

                    float rowMaxHeight = 0;
                    foreach (Drawable d in Children)
                    {
                        if (((int)direction & (int)d.RelativeSizeAxes) > 0)
                        {
                            //if the inheriting mode of the drawable shares the same directional value as our flow direction, we have to ignore it.
                            continue;
                        }

                        Vector2 size = Vector2.Zero;

                        if (d.IsVisible)
                        {
                            size = d.Size * d.Scale * ChildrenScale;

                            if (Direction != FlowDirection.HorizontalOnly && current.X + size.X > max.X)
                            {
                                current.X  = Math.Max(0, Padding.X);
                                current.Y += rowMaxHeight;

                                rowMaxHeight = 0;
                            }

                            //todo: check this is correct
                            if (size.X > 0)
                            {
                                size.X = Math.Max(0, size.X + Padding.X);
                            }
                            if (size.Y > 0)
                            {
                                size.Y = Math.Max(0, size.Y + Padding.Y);
                            }

                            if (size.Y > rowMaxHeight)
                            {
                                rowMaxHeight = size.Y;
                            }
                        }

                        if (current != d.Position)
                        {
                            d.MoveTo(current, LayoutDuration, LayoutEasing);
                        }

                        current.X += size.X;
                    }

                    return(current);
                });
            }
        }