protected internal virtual void ComputeStyleChildren(ProcessLayoutContext ctx) { var length = Children.Count; var children = Children; for (var i = 0; i < length; i++) { children[i].ComputeStyle(ctx); } }
private protected Box GetParentBlockBox(ProcessLayoutContext ctx) { var el = GetParentBlockElement(ctx); if (el == null) { return(ctx.GlobalContext !.GlobalViewPort); } return(el.ClientRect); }
internal StyleValue Normalize(ProcessLayoutContext ctx, Axis axis) { var value = this; switch (Unit) { case StyleUnit.Percentage: value.Number = (ctx.LocalViewPort.Size(axis) / 100) * Number; value.Unit = StyleUnit.Pixel; break; } return(value); }
private protected Element?GetParentBlockElement(ProcessLayoutContext ctx) { var p = Parent; while (p != null) { if (p.ResolvedStyle.Position == StylePosition.Absolute) { return(p); } p = p.Parent; } return(null); }
protected internal virtual void ComputeBoundsChildren(ProcessLayoutContext ctx) { var length = Children.Count; if (length == 0) { return; } var children = Children; for (var i = 0; i < length; i++) { var child = children[i]; child.ProcessLayoutContext.LocalViewPort = ClientRect; child.CallComputeBounds(ctx.GlobalContext !); } }
protected internal virtual void ComputeStyle(ProcessLayoutContext ctx) { var style = Style; var resolved = ResolvedStyle; if (style._BoundingChanged) { resolved._Size = style._Size.Normalize(ctx); resolved._MinSize = style._MinSize.Normalize(ctx); resolved._MaxSize = style._MaxSize.Normalize(ctx); resolved._Margin = style._Margin.Normalize(ctx); resolved._Padding = style._Padding.Normalize(ctx); resolved._BorderWidth = style._BorderWidth.Normalize(ctx); resolved._Anchors = style._Anchors.Normalize(ctx); } resolved.Position = style.Position; resolved.Display = style.Display; resolved.Visibility = style.Visibility; ComputeStyleChildren(ctx); }
internal StyleSize Normalize(ProcessLayoutContext ctx) { return(new StyleSize( Width.Normalize(ctx, Axis.X), Height.Normalize(ctx, Axis.Y))); }
protected internal virtual void ComputeBounds(ProcessLayoutContext ctx) { ComputeBoundsSelf(ctx); ComputeBoundsChildren(ctx); }
protected internal virtual void ComputeBoundsSelf(ProcessLayoutContext ctx) { if (PassThrough) { return; } //OuterRect = ctx.LocalViewPort; Box relMargin = ResolvedStyle._Margin.ToBox(); Box relBorder = ResolvedStyle._BorderWidth.ToBox(); Box relPadding = ResolvedStyle._Padding.ToBox(); Size relSize = ResolvedStyle._Size.ToSize(); Size relMinSize = ResolvedStyle._MinSize.ToSize(); Size relMaxSize = ResolvedStyle._MaxSize.ToSize(); // top | left Span <bool> normalDirection = stackalloc bool[2]; // Debug const int axisStart = 0; const int axisCount = 2; const int MIN = 0; // Left or Top const int MAX = 2; // Right or Bottom /* * Anchors: Left, Top, Right, Bottom * * position affects position (x, y) and flow of subsequent elements. * it does not affect the dimensions of the box. * * if position == static: * must ignore Anchors! * * if position == absolute: * MUST ignore Display, except Display.None * * Display affects Box-Calculation * * If Display == Inline: * MUST ignore Size, take the inner content as it is. * */ var decorationSize = new Size( relMargin.LeftRight + relBorder.LeftRight + relPadding.LeftRight, relMargin.TopBottom + relBorder.TopBottom + relPadding.TopBottom); var flow = ResolvedStyle.Position is StylePosition.Static or StylePosition.Relative; if (flow) { // in flow if (ResolvedStyle.Display != StyleDisplay.Inline) { // StyleDisplay.Inline are typically Text spans, that are converted to // one ore more TextElementFracment / StyleDisplay.InlineBlock if (Parent == null) #pragma warning disable HAA0601 // Value type to reference type conversion causing boxing allocation { throw new Exception($"Elements with Display.{ResolvedStyle.Display} must be inside of a block element."); } #pragma warning restore HAA0601 // Value type to reference type conversion causing boxing allocation var el = GetParentBlockElement(ctx); if (el != null) { Box absAnchors = el.ClientRect; var absCenter = absAnchors.Center; absAnchors.Width = relSize.Width + decorationSize.Width; absAnchors.Height = relSize.Height + decorationSize.Height; var pc = el.ProcessLayoutContext; if (absAnchors.Right + pc.RowPosition.X > el.ClientRect.Right || ResolvedStyle.Display == StyleDisplay.Block) // OuterRect.Right { pc.RowElements.Clear(); pc.RowPosition.Y += pc.RowHeight; pc.RowPosition.X = 0; pc.RowHeight = absAnchors.Height; } else if (absAnchors.Height > pc.RowHeight) { var diff = absAnchors.Height - pc.RowHeight; var prevElLength = pc.RowElements.Count; for (var i = 0; i < prevElLength; i++) { var prevEl = pc.RowElements[i]; prevEl.TranslateY(diff); } pc.RowHeight = absAnchors.Height; } absAnchors.Translate(pc.RowPosition.X, pc.RowPosition.Y + (pc.RowHeight - absAnchors.Height)); MarginRect = absAnchors; BorderRect = MarginRect.Substract(relMargin); PaddingRect = BorderRect.Substract(relBorder); ClientRect = PaddingRect.Substract(relPadding); pc.RowPosition.X += absAnchors.Width; //pc.RowHeight = absAnchors.Height; pc.RowElements.Add(this); } } } else // flow == false: { Box absAnchors = Parent != null ? Parent.ClientRect : ctx.GlobalContext !.GlobalViewPort; var absCenter = absAnchors.Center; // Because we don't have flow, both axis behave exactly the same, // so we can reduce code for (var a = axisStart; a < axisCount; a++) { normalDirection[a] = true; var ax = (Axis)a; if (ResolvedStyle._Anchors[MIN + a].HasValue() && ResolvedStyle._Anchors[MAX + a].HasValue()) { absAnchors[MIN + a] += ResolvedStyle._Anchors[MIN + a].Number; absAnchors[MAX + a] -= ResolvedStyle._Anchors[MAX + a].Number; } else { var diffHeight = relSize[a] + decorationSize[a]; if (ResolvedStyle._Margin[MIN + a].Unit == StyleUnit.Auto && ResolvedStyle._Margin[MAX + a].Unit == StyleUnit.Auto) { var size = diffHeight; var halfSize = size / 2; absAnchors[MIN + a] = absCenter[a] - halfSize; absAnchors[MAX + a] = absCenter[a] + halfSize; } else { if (ResolvedStyle._Anchors[MIN + a].HasValue()) { absAnchors[MIN + a] += ResolvedStyle._Anchors[MIN + a].Number; absAnchors[MAX + a] = absAnchors[MIN + a] + diffHeight; } else if (ResolvedStyle._Anchors[MAX + a].HasValue()) { normalDirection[a] = false; absAnchors[MAX + a] -= ResolvedStyle._Anchors[MAX + a].Number; absAnchors[MIN + a] = absAnchors[MAX + a] - diffHeight; } else { absAnchors[MAX + a] = absAnchors[MIN + a] + diffHeight; } } } } MarginRect = absAnchors; BorderRect = MarginRect.Substract(relMargin); PaddingRect = BorderRect.Substract(relBorder); ClientRect = PaddingRect.Substract(relPadding); for (var a = axisStart; a < axisCount; a++) { normalDirection[a] = true; var ax = (Axis)a; if (ResolvedStyle.MaxSize[a].HasValue() && ClientRect.Size(ax) > relMaxSize[a]) { var diff = ClientRect.Size(ax) - relMaxSize[a]; if (normalDirection[a]) { ClientRect[MAX + a] -= diff; PaddingRect[MAX + a] -= diff; BorderRect[MAX + a] -= diff; MarginRect[MAX + a] -= diff; } else { ClientRect[MIN + a] += diff; PaddingRect[MIN + a] += diff; BorderRect[MIN + a] += diff; MarginRect[MIN + a] += diff; } } if (ResolvedStyle.MinSize[a].HasValue() && ClientRect.Size(ax) < relMinSize[a]) { var diff = relMinSize[a] - ClientRect.Size(ax); if (normalDirection[a]) { ClientRect[MAX + a] += diff; PaddingRect[MAX + a] += diff; BorderRect[MAX + a] += diff; MarginRect[MAX + a] += diff; } else { ClientRect[MIN + a] -= diff; PaddingRect[MIN + a] -= diff; BorderRect[MIN + a] -= diff; MarginRect[MIN + a] -= diff; } } } } // flow }
protected internal virtual void ComputeChildBoundsOffers(ProcessLayoutContext ctx) { }