public UIDrawCall Render(int RenderedWidth, int RenderedHeight, int RenderedX, int RenderedY) { // Let the renderer know this component was seen uiRendererInstance.MarkElementAsSeen(key); // Insert own draw call List <UIDrawCall> childDrawCalls = new List <UIDrawCall>(); // Find out how much space the fixed elements need, and what the total sum of relative sizes are int fixedSpaceNeeds = 0; int restSpaceSums = 0; int restSpaceMinimumNeeds = 0; int maxCrossDirectionSize = 0; int cursorX = RenderedX; int cursorY = RenderedY - GetScroll(); int runBeginIndex = 0; for (int i = 0; i < children.Length;) { IUIElement child = children[i]; if (child.GetPositioning() == UIEnums.Positioning.Absolute) { childDrawCalls.Add( child.Render( child.GetWidth().Sizing == UIEnums.Sizing.Fixed ? child.GetWidth().Size : (int)(RenderedWidth * (child.GetWidth().Size / 100f)), child.GetHeight().Sizing == UIEnums.Sizing.Fixed ? child.GetHeight().Size : (int)(RenderedHeight * (child.GetHeight().Size / 100f)), RenderedX + child.GetX(), RenderedY + child.GetY() ) ); i++; continue; } else if (child.GetPositioning() == UIEnums.Positioning.Fixed) { childDrawCalls.Add( child.Render( child.GetWidth().Sizing == UIEnums.Sizing.Fixed ? child.GetWidth().Size : (int)(RenderedWidth * (child.GetWidth().Size / 100f)), child.GetHeight().Sizing == UIEnums.Sizing.Fixed ? child.GetHeight().Size : (int)(RenderedHeight * (child.GetHeight().Size / 100f)), child.GetX(), child.GetY() ) ); i++; continue; } // We don't want to commit these values until we know we haven't reached capacity int tempFixedSpaceNeeds = fixedSpaceNeeds; int tempRestSpaceSums = restSpaceSums; int tempRestSpaceMinimumNeeds = restSpaceMinimumNeeds; int tempMaxCrossDirectionSize = maxCrossDirectionSize; bool isLastChild = i == children.Length - 1; if (!isLastChild && child.GetPositioning() == UIEnums.Positioning.Relative) { bool didFindRelative = false; for (int j = i + 1; j < children.Length && !isLastChild; j++) { if (children[j].GetPositioning() == UIEnums.Positioning.Relative) { didFindRelative = true; break; } } if (!didFindRelative) { isLastChild = true; } } if (childOrdering == UIEnums.ChildOrdering.Row) { if (child.GetWidth().Sizing == UIEnums.Sizing.Fixed) { tempFixedSpaceNeeds += child.GetWidth().Size; } else if (child.GetWidth().Sizing == UIEnums.Sizing.Relative) { tempFixedSpaceNeeds += (int)(child.GetWidth().Size / 100f * RenderedWidth) - child.GetWidth().FullMargin; } else if (child.GetWidth().Sizing == UIEnums.Sizing.Rest) { tempRestSpaceSums += child.GetWidth().Size; tempRestSpaceMinimumNeeds += child.GetWidth().Minimum; } tempFixedSpaceNeeds += child.GetWidth().FullMargin; if (child.GetHeight().Sizing == UIEnums.Sizing.Fixed) { tempMaxCrossDirectionSize = Math.Max(tempMaxCrossDirectionSize, child.GetHeight().Size); } else if (child.GetHeight().Sizing == UIEnums.Sizing.Relative) { tempMaxCrossDirectionSize += Math.Max(tempMaxCrossDirectionSize, (int)(child.GetHeight().Size / 100f * RenderedHeight)); } else { throw new Exception("Rest sizing is not allowed in a child's cross direction"); } tempMaxCrossDirectionSize += child.GetHeight().FullMargin; // Check if we're over capacity bool wasCapacityReached = !isScrollingEnabled && (tempFixedSpaceNeeds + tempRestSpaceMinimumNeeds > RenderedWidth); if (wasCapacityReached || isLastChild) { if (!wasCapacityReached && isLastChild) { fixedSpaceNeeds = tempFixedSpaceNeeds; restSpaceSums = tempRestSpaceSums; restSpaceMinimumNeeds = tempRestSpaceMinimumNeeds; maxCrossDirectionSize = tempMaxCrossDirectionSize; } int realCursorX = cursorX; for (int j = runBeginIndex; j <= i; j++) { if (wasCapacityReached && j == i) { continue; } IUIElement renderedChild = children[j]; if (renderedChild.GetPositioning() != UIEnums.Positioning.Relative) { continue; } int childWidth, childHeight; switch (renderedChild.GetWidth().Sizing) { case UIEnums.Sizing.Fixed: childWidth = renderedChild.GetWidth().Size; break; case UIEnums.Sizing.Relative: childWidth = (int)(renderedChild.GetWidth().Size / 100f * RenderedWidth); break; case UIEnums.Sizing.Rest: childWidth = Math.Max( (int)((float)renderedChild.GetWidth().Size / restSpaceSums * (RenderedWidth - fixedSpaceNeeds - (restSpaceMinimumNeeds - renderedChild.GetWidth().Minimum))), renderedChild.GetWidth().Minimum ); break; default: throw new Exception("Unsupported width sizing"); } switch (renderedChild.GetHeight().Sizing) { case UIEnums.Sizing.Fixed: childHeight = renderedChild.GetHeight().Size; break; case UIEnums.Sizing.Relative: childHeight = (int)(renderedChild.GetHeight().Size / 100f * RenderedHeight); break; default: throw new Exception("Unsupported height sizing on cross direction"); } childDrawCalls.Add( renderedChild.Render( childWidth - renderedChild.GetWidth().FullPadding, childHeight - renderedChild.GetHeight().FullPadding, realCursorX + renderedChild.GetWidth().MarginStart + renderedChild.GetWidth().PaddingStart, cursorY + renderedChild.GetHeight().MarginStart + renderedChild.GetHeight().PaddingStart ) ); realCursorX += childWidth + renderedChild.GetWidth().FullMargin; } if (!wasCapacityReached && isLastChild) { i++; continue; } cursorX = RenderedX; cursorY += maxCrossDirectionSize; fixedSpaceNeeds = 0; restSpaceSums = 0; restSpaceMinimumNeeds = 0; maxCrossDirectionSize = 0; runBeginIndex = i; continue; } } else if (childOrdering == UIEnums.ChildOrdering.Column) { if (child.GetHeight().Sizing == UIEnums.Sizing.Fixed) { tempFixedSpaceNeeds += child.GetHeight().Size; } else if (child.GetHeight().Sizing == UIEnums.Sizing.Relative) { tempFixedSpaceNeeds += (int)(child.GetHeight().Size / 100f * RenderedHeight) - child.GetHeight().FullMargin; } else if (child.GetHeight().Sizing == UIEnums.Sizing.Rest) { tempRestSpaceSums += child.GetHeight().Size; tempRestSpaceMinimumNeeds += child.GetHeight().Minimum; } tempFixedSpaceNeeds += child.GetHeight().FullMargin; if (child.GetWidth().Sizing == UIEnums.Sizing.Fixed) { tempMaxCrossDirectionSize = Math.Max(tempMaxCrossDirectionSize, child.GetWidth().Size); } else if (child.GetWidth().Sizing == UIEnums.Sizing.Relative) { tempMaxCrossDirectionSize = Math.Max(tempMaxCrossDirectionSize, (int)(child.GetWidth().Size / 100f * RenderedWidth)); } else { throw new System.Exception("Rest sizing is not allowed in a child's cross direction"); } tempMaxCrossDirectionSize += child.GetWidth().FullMargin; // Check if we're over capacity bool wasCapacityReached = !isScrollingEnabled && (tempFixedSpaceNeeds + tempRestSpaceMinimumNeeds > RenderedHeight); if (wasCapacityReached || isLastChild) { if (!wasCapacityReached && isLastChild) { fixedSpaceNeeds = tempFixedSpaceNeeds; restSpaceSums = tempRestSpaceSums; restSpaceMinimumNeeds = tempRestSpaceMinimumNeeds; maxCrossDirectionSize = tempMaxCrossDirectionSize; } int realCursorY = cursorY; for (int j = runBeginIndex; j <= i; j++) { if (wasCapacityReached && j == i) { continue; } IUIElement renderedChild = children[j]; if (renderedChild.GetPositioning() != UIEnums.Positioning.Relative) { continue; } int childWidth, childHeight; switch (renderedChild.GetWidth().Sizing) { case UIEnums.Sizing.Fixed: childWidth = renderedChild.GetWidth().Size; break; case UIEnums.Sizing.Relative: childWidth = (int)(renderedChild.GetWidth().Size / 100f * RenderedWidth); break; default: throw new Exception("Unsupported width sizing on cross direction"); } switch (renderedChild.GetHeight().Sizing) { case UIEnums.Sizing.Fixed: childHeight = renderedChild.GetHeight().Size; break; case UIEnums.Sizing.Relative: childHeight = (int)(renderedChild.GetHeight().Size / 100f * RenderedHeight); break; case UIEnums.Sizing.Rest: childHeight = Math.Max( (int)((float)renderedChild.GetHeight().Size / restSpaceSums * (RenderedHeight - fixedSpaceNeeds - (restSpaceMinimumNeeds - renderedChild.GetHeight().Minimum))), renderedChild.GetHeight().Minimum ); break; default: throw new Exception("Unsupported height sizing"); } childDrawCalls.Add( renderedChild.Render( childWidth - renderedChild.GetWidth().FullPadding, childHeight - renderedChild.GetHeight().FullPadding, cursorX + renderedChild.GetWidth().MarginStart + renderedChild.GetWidth().PaddingStart, realCursorY + renderedChild.GetHeight().MarginStart + renderedChild.GetHeight().PaddingStart ) ); realCursorY += childHeight + renderedChild.GetHeight().FullMargin; } if (!wasCapacityReached && isLastChild) { i++; continue; } cursorX += maxCrossDirectionSize; cursorY = RenderedY - GetScroll(); fixedSpaceNeeds = 0; restSpaceSums = 0; restSpaceMinimumNeeds = 0; maxCrossDirectionSize = 0; runBeginIndex = i; continue; } } fixedSpaceNeeds = tempFixedSpaceNeeds; restSpaceSums = tempRestSpaceSums; restSpaceMinimumNeeds = tempRestSpaceMinimumNeeds; maxCrossDirectionSize = tempMaxCrossDirectionSize; i++; } return(new UIDrawCall(childDrawCalls.ToArray(), this, RenderedWidth, RenderedHeight, RenderedX, RenderedY, isScrollingEnabled)); }