Example #1
0
        private void HandleFixedAspectRatio(LayoutNode parentNode, LayoutNode child)
        {
            if (child.Size.IsFixedAspectRatio())
            {
                // Right now both sides of FixedAspectRatio think they're streched, we need to figure out which one is actually stretched based on how much room is thinks it has
                var aspectRatioOfAvailableSpace = new AspectRatio(this.measurer.GetMeasuredSize(child.Size));
                var childAspectRatio            = child.Size.GetAspectRatio();
                var isStretchedAlong            = AspectRatio.IsStretchedAlong(childAspectRatio, aspectRatioOfAvailableSpace, parentNode.Orientation);
                var isStretchedPerpendicular    = AspectRatio.IsStretchedPerpendicular(childAspectRatio, aspectRatioOfAvailableSpace, parentNode.Orientation);
                var isStretchedBoth             = isStretchedAlong && isStretchedPerpendicular;

                var oppositeOrientation = parentNode.Orientation.Opposite();

                // If it's stretched both we do nothing because we already assume it's stretched on both sides
                if (!isStretchedBoth)
                {
                    if (isStretchedAlong)
                    {
                        var alongSize = this.measurer.MeasureEdgeOfNode(child, parentNode.Orientation);
                        this.measurer.Add(child.Size.GetValueFromOrientation(oppositeOrientation), (int)(alongSize * childAspectRatio.AlongOverPerpendicular(oppositeOrientation)));
                    }

                    if (isStretchedPerpendicular)
                    {
                        var perpendicularSize = this.measurer.MeasureEdgeOfNode(child, oppositeOrientation);
                        this.measurer.Add(child.Size.GetValueFromOrientation(parentNode.Orientation), (int)(perpendicularSize * childAspectRatio.AlongOverPerpendicular(parentNode.Orientation)));
                    }
                }
            }
        }
Example #2
0
        public BakedLayoutNode[] GetDirectChildrenOfNode(LayoutNode node)
        {
            if (!this.rawToBakedLookup.ContainsKey(node))
            {
                throw new Exception($"No node matches {node}");
            }

            if (node.Name.IsNameless)
            {
                throw new Exception($"Found node {node} but its nameless so it can't have children");
            }

            var result = new List <BakedLayoutNode>();

            foreach (var child in node.Children)
            {
                if (child.IsBakable)
                {
                    result.Add(this.rawToBakedLookup[child]);
                }
            }


            return(result.ToArray());
        }
Example #3
0
 public void AddNodeToLayout(BakedLayout inProgressLayout, Point position, LayoutNode node, int nestingLevel)
 {
     if (node.IsBakable)
     {
         inProgressLayout.Add(node, new BakedLayoutNode(position, this.measurer.GetMeasuredSize(node.Size), nestingLevel));
     }
 }
Example #4
0
        private static int GetRemainingAlongSizeFromEasyNodes(LayoutNode parentNode, Point groupSize)
        {
            var isVertical         = parentNode.Orientation == Orientation.Vertical;
            var totalAlongSize     = isVertical ? groupSize.Y : groupSize.X;
            var alongMargin        = isVertical ? parentNode.Margin.Y : parentNode.Margin.X;
            var remainingAlongSize = totalAlongSize - alongMargin * 2;
            var lastIndex          = parentNode.Children.Length - 1;
            var index = 0;

            foreach (var child in parentNode.Children)
            {
                if (child.Size.IsMeasurableAlong(parentNode.Orientation))
                {
                    remainingAlongSize -= child.Size.GetValueFromOrientation(parentNode.Orientation).ActualSize;
                }

                if (index != lastIndex)
                {
                    remainingAlongSize -= parentNode.Padding;
                }

                index++;
            }

            return(remainingAlongSize);
        }
Example #5
0
        private static RawFlowLayout OrientedFlowParent(Orientation orientation, string name, LayoutSize size, FlowLayoutStyle style, params LayoutNodeOrInstruction[] children)
        {
            var workableAreaStyle = new LayoutStyle(margin: style.Margin, alignment: style.Alignment);

            var workableArea = LayoutNode.NamelessOneOffParent(size, workableAreaStyle, LayoutNode.Leaf("workableArea", LayoutSize.StretchedBoth())).Bake().GetNode("workableArea");
            var rows         = new FlowLayoutRows(workableArea.Size, style, orientation);

            foreach (var item in children)
            {
                if (item.IsLayoutNode)
                {
                    if (!rows.CanFitItemPerpendicular(item))
                    {
                        break;
                    }

                    if (rows.CanFitItemAlongCurrentRow(item))
                    {
                        rows.AddItemToCurrentRow(item);
                    }
                    else
                    {
                        rows.CreateNextRowAndAdd(item);
                    }
                }
                else if (item.IsInstruction)
                {
                    rows.ConsumeInstruction(item);
                }
            }

            return(new RawFlowLayout(name, size, workableAreaStyle, orientation, style, rows));
        }
Example #6
0
        private void CreateActorsForChildren(LayoutNode parent, IBakedLayout layout)
        {
            if (!parent.HasChildren)
            {
                return;
            }

            var parentActor = GetActor(parent.Name.Text);

            foreach (var childNode in parent.Children)
            {
                if (childNode.Name.Exists)
                {
                    var actorName = childNode.Name.Text;
                    var actor     = parentActor.transform.AddActorAsChild(actorName);

                    new LayoutSiblingWithCachedOrientation(actor, parent.Orientation);
                    new BoundingRect(actor, layout.GetNode(actorName).Size);

                    AddActorToTable(actorName, actor);
                    SetupChildActor(actor, actorName, layout);
                    CreateActorsForChildren(childNode, layout);
                }
            }
        }
Example #7
0
        private void HandleStretchedNodes(LayoutNode parentNode, int remainingAlongSize, int perpendicularStretchSize)
        {
            int stretchAlongCount         = 0;
            int stretchPerpendicularCount = 0;

            foreach (var child in parentNode.Children)
            {
                if (child.Size.IsStretchedAlong(parentNode.Orientation))
                {
                    stretchAlongCount++;
                }

                if (child.Size.IsStretchedPerpendicular(parentNode.Orientation))
                {
                    stretchPerpendicularCount++;
                }
            }

            // Update size of along stretch elements
            if (stretchAlongCount > 0)
            {
                var alongSizeOfEachStretchedChild = remainingAlongSize / stretchAlongCount;
                var fractionalLossIncrement       = (float)remainingAlongSize / stretchAlongCount % 1;
                var fractionalLoss = 0f;

                foreach (var child in parentNode.Children)
                {
                    if (child.Size.IsStretchedAlong(parentNode.Orientation))
                    {
                        fractionalLoss += fractionalLossIncrement;
                        int extraPixelIfApplicable = 0;
                        var epsilon = 0.001f;
                        if (1 - fractionalLoss < epsilon)
                        {
                            extraPixelIfApplicable = 1;
                            fractionalLoss        -= 1;
                        }

                        this.measurer.Add(child.Size.GetValueFromOrientation(parentNode.Orientation), alongSizeOfEachStretchedChild + extraPixelIfApplicable);
                    }
                }
            }

            // Update perp elements (we can inline this in the first loop
            if (stretchPerpendicularCount > 0)
            {
                foreach (var child in parentNode.Children)
                {
                    if (child.Size.IsStretchedPerpendicular(parentNode.Orientation))
                    {
                        this.measurer.Add(child.Size.GetValueFromOrientation(parentNode.Orientation.Opposite()), perpendicularStretchSize);
                        HandleFixedAspectRatio(parentNode, child);
                    }
                }
            }
        }
Example #8
0
 public void ConsumeInstruction(FlowLayoutInstruction instruction)
 {
     if (instruction == FlowLayoutInstruction.Linebreak)
     {
         if (HasRoomForAnotherRow(LayoutNode.NamelessLeaf(LayoutSize.Pixels(0, 0))))
         {
             AddNewRow();
         }
     }
 }
Example #9
0
        public LayoutNode[] GetLayoutNodesOfEachRow()
        {
            var nodes = new LayoutNode[Content.Count];

            for (int i = 0; i < Content.Count; i++)
            {
                nodes[i] = Content[i].GetLayoutNode($"row {i}");
            }

            return(nodes);
        }
Example #10
0
 internal RawFlowLayout(string name, LayoutSize size, LayoutStyle workableAreaStyle, Orientation orientation, FlowLayoutStyle style, FlowLayoutRows rows) : base(
         LayoutNode.OneOffParent(name, size, workableAreaStyle,
                                 LayoutNode.OrientedParent(orientation.Opposite(), "rows", LayoutSize.Pixels(rows.UsedSize), new LayoutStyle(padding: style.PaddingBetweenRows),
                                                           rows.GetLayoutNodesOfEachRow()
                                                           )
                                 ))
 {
     this.orientation  = orientation;
     this.rowNodes     = rows.GetLayoutNodesOfEachRow();
     this.rowUsedSpace = rows.GetUsedSpaceOfEachRow();
 }
Example #11
0
        public bool CanFitItemPerpendicular(LayoutNode item)
        {
            if (Style.OverflowRule.HasInfiniteRows)
            {
                return(true);
            }
            var usedPerpendicular = PerpendicularSizeOfAllRowsExceptCurrent;
            var itemPerpendicular = item.Size.GetValueFromOrientation(Orientation.Opposite()).ActualSize;

            return(AvailablePerpendicularSize >= usedPerpendicular + itemPerpendicular);
        }
Example #12
0
        private bool HasRoomForAnotherRow(LayoutNode itemToAdd)
        {
            if (Style.OverflowRule.HasInfiniteRows)
            {
                return(true);
            }

            var possibleNewRow = new FlowLayoutRow(AvailableAlongSize, Style, Orientation);

            possibleNewRow.AddItem(itemToAdd);
            var totalSizeAfterAddingRow = UsedSize.OppositeAxisValue(Orientation.ToAxis()) + possibleNewRow.UsedPerpendicularSize;

            return(totalSizeAfterAddingRow <= AvailablePerpendicularSize);
        }
Example #13
0
        private void BakeGroup(BakedLayout inProgressLayout, LayoutNode parentNode, Point parentNodeLocation, int parentNestingLevel)
        {
            var isVertical = parentNode.Orientation == Orientation.Vertical;
            var groupSize  = this.measurer.GetMeasuredSize(parentNode.Size);

            int remainingAlongSize = GetRemainingAlongSizeFromEasyNodes(parentNode, groupSize);

            var perpendicularStretchSize = isVertical ? groupSize.X - parentNode.Margin.X * 2 : groupSize.Y - parentNode.Margin.Y * 2;

            HandleStretchedNodes(parentNode, remainingAlongSize, perpendicularStretchSize);

            // Place elements
            PlaceAndBakeMeasuredElements(inProgressLayout, parentNode, parentNodeLocation, parentNestingLevel + 1);
        }
Example #14
0
 public void CreateNextRowAndAdd(LayoutNode itemToAdd)
 {
     if (CurrentRow.Content.Count == 0)
     {
         AddItemToCurrentRow(itemToAdd);
     }
     else if (!HasRoomForAnotherRow(itemToAdd))
     {
         AddItemToCurrentRow(itemToAdd);
     }
     else
     {
         AddNewRow();
         AddItemToCurrentRow(itemToAdd);
     }
 }
Example #15
0
        private Point CalculateTotalUsedSpace(LayoutNode parentNode)
        {
            var totalUsedAlongSpace         = 0;
            var totalUsedPerpendicularSpace = 0;

            foreach (var child in parentNode.Children)
            {
                totalUsedAlongSpace        += this.measurer.MeasureEdgeOfNode(child, parentNode.Orientation);
                totalUsedAlongSpace        += parentNode.Padding;
                totalUsedPerpendicularSpace = Math.Max(totalUsedPerpendicularSpace, this.measurer.MeasureEdgeOfNode(child, parentNode.Orientation.Opposite()));
            }

            // subtract 1 padding since the previous loop adds an extra (thanks foreach)
            totalUsedAlongSpace -= parentNode.Padding;

            return(parentNode.Orientation.GetPointFromAlongPerpendicular(totalUsedAlongSpace, totalUsedPerpendicularSpace));
        }
Example #16
0
        public void AddItemToCurrentRow(LayoutNode itemToAdd)
        {
            if (StopAddingNewItems)
            {
                return;
            }

            CurrentRow.AddItem(itemToAdd);

            var overflowedAlong         = CurrentRow.UsedAlongSize > AvailableAlongSize;
            var overflowedPerpendicular = UsedSize.OppositeAxisValue(Orientation.ToAxis()) > AvailablePerpendicularSize;
            var failed = overflowedPerpendicular || overflowedAlong;

            if (failed)
            {
            }
        }
Example #17
0
        private void PlaceAndBakeMeasuredElements(BakedLayout inProgressLayout, LayoutNode parentNode, Point parentNodeLocation, int currentNestingLevel)
        {
            var parentSize   = this.measurer.GetMeasuredSize(parentNode.Size);
            var nextPosition = parentNodeLocation
                               + parentNode.Alignment.GetRelativePositionOfElement(parentSize, CalculateTotalUsedSpace(parentNode))
                               + parentNode.Alignment.AddPostionDeltaFromMargin(parentNode.Margin)
            ;

            foreach (var child in parentNode.Children)
            {
                var alignmentOffset = parentNode.Alignment.GetRelativePositionOfElement(CalculateTotalUsedSpace(parentNode), this.measurer.GetMeasuredSize(child.Size)).WithJustAxisValue(parentNode.Orientation.Opposite().ToAxis());
                var childPosition   = nextPosition + alignmentOffset;
                AddNodeToLayout(inProgressLayout, childPosition, child, currentNestingLevel);

                nextPosition += parentNode.Orientation.GetPointForAlongAxis(this.measurer.MeasureEdgeOfNode(child, parentNode.Orientation) + parentNode.Padding);

                if (child.HasChildren)
                {
                    BakeGroup(inProgressLayout, child, childPosition, currentNestingLevel);
                }
            }
        }
Example #18
0
        public LayoutNode GetLayoutNode(string rowNodeName)
        {
            var size = Orientation.GetPointFromAlongPerpendicular(AvailableAlongSize, UsedPerpendicularSize);

            return(LayoutNode.OrientedParent(Orientation, rowNodeName, LayoutSize.Pixels(size), RowStyle, Content.ToArray()));
        }
Example #19
0
 public void AddItem(LayoutNode child)
 {
     Content.Add(child);
     UpdateEstimatedSize();
 }
Example #20
0
 public BakedLayoutNode GetNode(LayoutNode unbakedNode)
 {
     return(this.rawToBakedLookup[unbakedNode]);
 }
Example #21
0
 public void Add(LayoutNode key, BakedLayoutNode value)
 {
     this.rawToBakedLookup[key] = value;
 }
Example #22
0
 public bool CanFitItemAlongCurrentRow(LayoutNode item)
 {
     return(RemainingAlongSizeInCurrentRow >= item.Size.GetValueFromOrientation(Orientation).ActualSize);
 }
Example #23
0
 public static RawLayout HorizontalFlexParent(string name, FlexLayoutStyle style, params LayoutNode[] children)
 {
     return(LayoutNode.HorizontalParent(name, FlexParentSize(Orientation.Horizontal, style, children), style.InnerStyle, children));
 }
Example #24
0
 public LayoutBaker(LayoutNode rootNode)
 {
     this.rootNode = rootNode;
     this.measurer = new LayoutMeasurer();
 }
Example #25
0
 public LayoutNodeOrInstruction(LayoutNode layoutNode)
 {
     InternalLayoutNode = layoutNode;
 }
Example #26
0
 public static RawLayout OneOffParent(string name, LayoutSize size, LayoutStyle style, LayoutNode child)
 {
     // Horizontal/Vertical does not matter here
     return(HorizontalParent(name, size, style, child));
 }
Example #27
0
 public static RawLayout NamelessOneOffParent(LayoutSize size, LayoutStyle style, LayoutNode child)
 {
     // Horizontal/Vertical does not matter here
     return(HorizontalParent("root", size, style, child));
 }
Example #28
0
 public BakedLayout(LayoutNode originalRoot)
 {
     OriginalRoot = originalRoot;
 }
Example #29
0
 public RawLayout(LayoutNode rootNode) : base(rootNode)
 {
 }
Example #30
0
 public int MeasureEdgeOfNode(LayoutNode node, Orientation orientation)
 {
     return(MeasureEdge(node.Size.GetValueFromOrientation(orientation)));
 }