mirror of
https://github.com/ZuneDev/MicrosoftIris.git
synced 2026-07-27 13:13:29 -07:00
416 lines
18 KiB
C#
416 lines
18 KiB
C#
// Decompiled with JetBrains decompiler
|
|||
|
|
// Type: Microsoft.Iris.Layouts.AnchorLayout
|
||
|
|
// Assembly: UIX, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
|
||
|
|
// MVID: A56C6C9D-B7F6-46A9-8BDE-B3D9B8D60B11
|
||
|
|
// Assembly location: C:\Program Files\Zune\UIX.dll
|
||
|
|
|
||
|
|
using Microsoft.Iris.Layout;
|
||
|
|
using Microsoft.Iris.Library;
|
||
|
|
using Microsoft.Iris.Render;
|
||
|
|
using Microsoft.Iris.Session;
|
||
|
|
using Microsoft.Iris.UI;
|
||
|
|
using System;
|
||
|
|
|
||
|
|
namespace Microsoft.Iris.Layouts
|
||
|
|
{
|
||
|
|
internal class AnchorLayout : ILayout
|
||
|
|
{
|
||
|
|
private bool _sizeToHorizontalChildrenFlag = true;
|
||
|
|
private bool _sizeToVerticalChildrenFlag = true;
|
||
|
|
private ItemAlignment _defaultChildAlignment;
|
||
|
|
private static readonly DataCookie s_dataProperty = DataCookie.ReserveSlot();
|
||
|
|
private static AnchorEdge s_anchorParent0 = new AnchorEdge("Parent", 0.0f);
|
||
|
|
private static AnchorEdge s_anchorParent1 = new AnchorEdge("Parent", 1f);
|
||
|
|
private static AnchorEdge s_anchorParentActual0 = new AnchorEdge("ParentActual", 0.0f);
|
||
|
|
private static AnchorEdge s_anchorParentActual1 = new AnchorEdge("ParentActual", 1f);
|
||
|
|
|
||
|
|
public bool SizeToHorizontalChildren
|
||
|
|
{
|
||
|
|
get => _sizeToHorizontalChildrenFlag;
|
||
|
|
set => _sizeToHorizontalChildrenFlag = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool SizeToVerticalChildren
|
||
|
|
{
|
||
|
|
get => _sizeToVerticalChildrenFlag;
|
||
|
|
set => _sizeToVerticalChildrenFlag = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
public ItemAlignment DefaultChildAlignment
|
||
|
|
{
|
||
|
|
get => _defaultChildAlignment;
|
||
|
|
set => _defaultChildAlignment = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
Size ILayout.Measure(ILayoutNode layoutNode, Size constraint)
|
||
|
|
{
|
||
|
|
if (!(layoutNode.MeasureData is AnchorLayout.Packet packet))
|
||
|
|
{
|
||
|
|
packet = new AnchorLayout.Packet();
|
||
|
|
layoutNode.MeasureData = packet;
|
||
|
|
packet.ParentRecord = new AnchorLayout.Record("Parent", new Rectangle(Point.Zero, constraint), LayoutPhase.Done);
|
||
|
|
packet.ParentActualRecord = new AnchorLayout.Record("ParentActual", Rectangle.Zero, LayoutPhase.Arrange);
|
||
|
|
packet.AreaOfInterestRecord = new AnchorLayout.Record("Focus", Rectangle.Zero, LayoutPhase.Arrange);
|
||
|
|
packet.Records = new Vector<AnchorLayout.Record>(layoutNode.LayoutChildrenCount);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
packet.ParentRecord.Bounds = new Rectangle(Point.Zero, constraint);
|
||
|
|
packet.CircularitiesDetected = false;
|
||
|
|
packet.CircularityBreakerRecord = null;
|
||
|
|
}
|
||
|
|
packet.Subject = layoutNode;
|
||
|
|
packet.Constraint = constraint;
|
||
|
|
packet.TotalBounds = new Rectangle(int.MaxValue, int.MaxValue, int.MinValue, int.MinValue);
|
||
|
|
Size zero = Size.Zero;
|
||
|
|
if (layoutNode.LayoutChildrenCount == 0)
|
||
|
|
{
|
||
|
|
packet.Records.Clear();
|
||
|
|
if (!_sizeToHorizontalChildrenFlag)
|
||
|
|
zero.Width = constraint.Width;
|
||
|
|
if (!_sizeToVerticalChildrenFlag)
|
||
|
|
zero.Height = constraint.Height;
|
||
|
|
layoutNode.RequestMoreChildren(int.MaxValue);
|
||
|
|
return zero;
|
||
|
|
}
|
||
|
|
int index = 0;
|
||
|
|
foreach (ILayoutNode layoutChild in layoutNode.LayoutChildren)
|
||
|
|
{
|
||
|
|
if (index < packet.Records.Count)
|
||
|
|
{
|
||
|
|
packet.Records[index].Initialize(layoutChild);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
AnchorLayout.Record record = new AnchorLayout.Record(layoutChild);
|
||
|
|
packet.Records.Add(record);
|
||
|
|
}
|
||
|
|
++index;
|
||
|
|
}
|
||
|
|
packet.Records.RemoveRange(index, packet.Records.Count - index);
|
||
|
|
foreach (AnchorLayout.Record record in packet.Records)
|
||
|
|
{
|
||
|
|
if (record.Phase == LayoutPhase.Untouched)
|
||
|
|
{
|
||
|
|
packet.CircularityBreakerRecord = null;
|
||
|
|
MeasureChild(packet, record);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (packet.CircularitiesDetected)
|
||
|
|
{
|
||
|
|
foreach (AnchorLayout.Record record in packet.Records)
|
||
|
|
{
|
||
|
|
if (record.Phase == LayoutPhase.Circular)
|
||
|
|
record.Phase = LayoutPhase.Untouched;
|
||
|
|
}
|
||
|
|
packet.CircularitiesDetected = false;
|
||
|
|
foreach (AnchorLayout.Record record in packet.Records)
|
||
|
|
{
|
||
|
|
if (record.Phase == LayoutPhase.Untouched)
|
||
|
|
MeasureChild(packet, record);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Size size = constraint;
|
||
|
|
if (_sizeToHorizontalChildrenFlag || _sizeToVerticalChildrenFlag)
|
||
|
|
{
|
||
|
|
if (_sizeToHorizontalChildrenFlag)
|
||
|
|
size.Width = packet.TotalBounds.Width;
|
||
|
|
if (_sizeToVerticalChildrenFlag)
|
||
|
|
size.Height = packet.TotalBounds.Height;
|
||
|
|
foreach (AnchorLayout.Record record in packet.Records)
|
||
|
|
{
|
||
|
|
Rectangle bounds = record.Bounds;
|
||
|
|
if (_sizeToHorizontalChildrenFlag)
|
||
|
|
bounds.X -= packet.TotalBounds.X;
|
||
|
|
if (_sizeToVerticalChildrenFlag)
|
||
|
|
bounds.Y -= packet.TotalBounds.Y;
|
||
|
|
record.Bounds = bounds;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
layoutNode.RequestMoreChildren(int.MaxValue);
|
||
|
|
return size;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void MeasureChild(AnchorLayout.Packet packet, AnchorLayout.Record record)
|
||
|
|
{
|
||
|
|
AnchorLayoutInput input = record.Input;
|
||
|
|
record.Phase = LayoutPhase.InProgress;
|
||
|
|
bool allArrangePhase = true;
|
||
|
|
bool anyArrangePhase = false;
|
||
|
|
int edge1 = ComputeEdge(packet, "Left", input.Left, s_anchorParent0, Orientation.Horizontal, record, out AnchorLayout.Record _, ref allArrangePhase, ref anyArrangePhase);
|
||
|
|
int edge2 = ComputeEdge(packet, "Top", input.Top, s_anchorParent0, Orientation.Vertical, record, out AnchorLayout.Record _, ref allArrangePhase, ref anyArrangePhase);
|
||
|
|
int edge3 = ComputeEdge(packet, "Right", input.Right, s_anchorParent1, Orientation.Horizontal, record, out AnchorLayout.Record _, ref allArrangePhase, ref anyArrangePhase);
|
||
|
|
int edge4 = ComputeEdge(packet, "Bottom", input.Bottom, s_anchorParent1, Orientation.Vertical, record, out AnchorLayout.Record _, ref allArrangePhase, ref anyArrangePhase);
|
||
|
|
if (anyArrangePhase)
|
||
|
|
{
|
||
|
|
if (!allArrangePhase)
|
||
|
|
{
|
||
|
|
ErrorManager.ReportError("All AnchorEdges must refer to actual positions on AnchorLayoutInput {0}.", record.Input);
|
||
|
|
record.Invalid = true;
|
||
|
|
}
|
||
|
|
if (record.Input.ContributesToHeight || record.Input.ContributesToWidth)
|
||
|
|
{
|
||
|
|
ErrorManager.ReportError("AnchorLayoutInput {0} cannot contribute to width or height.", record.Input);
|
||
|
|
record.Invalid = true;
|
||
|
|
}
|
||
|
|
record.Phase = LayoutPhase.Arrange;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Normalize(ref edge1, ref edge3);
|
||
|
|
Normalize(ref edge2, ref edge4);
|
||
|
|
int constraintMaxValue1;
|
||
|
|
ComputeConstraint(edge1, edge3, out constraintMaxValue1);
|
||
|
|
int constraintMaxValue2;
|
||
|
|
ComputeConstraint(edge2, edge4, out constraintMaxValue2);
|
||
|
|
Size constraint = new Size(constraintMaxValue1, constraintMaxValue2);
|
||
|
|
record.LayoutNode.Measure(constraint);
|
||
|
|
int size1;
|
||
|
|
int x = LocationFromEdges(input.Left, input.Right, edge1, edge3, record.LayoutNode.DesiredSize.Width, record.LayoutNode.AlignedSize.Width, record.LayoutNode.AlignmentOffset.X, out size1);
|
||
|
|
int size2;
|
||
|
|
int y = LocationFromEdges(input.Top, input.Bottom, edge2, edge4, record.LayoutNode.DesiredSize.Height, record.LayoutNode.AlignedSize.Height, record.LayoutNode.AlignmentOffset.Y, out size2);
|
||
|
|
record.Bounds = new Rectangle(x, y, size1, size2);
|
||
|
|
bool flag = packet.CircularityBreakerRecord == record;
|
||
|
|
if (record.Phase != LayoutPhase.InProgress && !flag)
|
||
|
|
return;
|
||
|
|
record.Phase = LayoutPhase.Done;
|
||
|
|
Rectangle bounds = record.Bounds;
|
||
|
|
if (!input.ContributesToWidth)
|
||
|
|
{
|
||
|
|
bounds.X = int.MaxValue;
|
||
|
|
bounds.Width = int.MinValue;
|
||
|
|
}
|
||
|
|
if (!input.ContributesToHeight)
|
||
|
|
{
|
||
|
|
bounds.Y = int.MaxValue;
|
||
|
|
bounds.Height = int.MinValue;
|
||
|
|
}
|
||
|
|
packet.TotalBounds = Rectangle.Union(packet.TotalBounds, bounds);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private int ComputeEdge(
|
||
|
|
AnchorLayout.Packet packet,
|
||
|
|
string edgeName,
|
||
|
|
AnchorEdge anchor,
|
||
|
|
AnchorEdge fallback,
|
||
|
|
Orientation orientation,
|
||
|
|
AnchorLayout.Record record,
|
||
|
|
out AnchorLayout.Record recordRef,
|
||
|
|
ref bool allArrangePhase,
|
||
|
|
ref bool anyArrangePhase)
|
||
|
|
{
|
||
|
|
anchor = anchor != null ? anchor : fallback;
|
||
|
|
recordRef = GetReferenceRecord(packet, anchor.Id);
|
||
|
|
if (recordRef == null)
|
||
|
|
{
|
||
|
|
allArrangePhase = false;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
bool flag = recordRef.Phase == LayoutPhase.Arrange;
|
||
|
|
allArrangePhase &= flag;
|
||
|
|
anyArrangePhase |= flag;
|
||
|
|
record.Visible &= recordRef.Visible;
|
||
|
|
Rectangle bounds = recordRef.Bounds;
|
||
|
|
if (recordRef.Phase != LayoutPhase.Done && recordRef.Phase != LayoutPhase.Arrange)
|
||
|
|
{
|
||
|
|
record.Phase = LayoutPhase.Circular;
|
||
|
|
bounds = packet.ParentRecord.Bounds;
|
||
|
|
if (recordRef.Phase == LayoutPhase.InProgress && packet.CircularityBreakerRecord == null)
|
||
|
|
{
|
||
|
|
packet.CircularityBreakerRecord = recordRef;
|
||
|
|
packet.CircularitiesDetected = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
int val1 = Weigh(orientation == Orientation.Horizontal ? bounds.Width : bounds.Height, anchor.Percent) + (orientation == Orientation.Horizontal ? bounds.X : bounds.Y) + anchor.Offset;
|
||
|
|
int num = orientation == Orientation.Horizontal ? packet.ParentRecord.Bounds.Width : packet.ParentRecord.Bounds.Height;
|
||
|
|
if (anchor.MaximumSet)
|
||
|
|
{
|
||
|
|
int val2 = Weigh(num, anchor.MaximumPercent) + anchor.MaximumOffset;
|
||
|
|
val1 = Math.Min(val1, val2);
|
||
|
|
}
|
||
|
|
if (anchor.MinimumSet)
|
||
|
|
{
|
||
|
|
int val2 = Weigh(num, anchor.MinimumPercent) + anchor.MinimumOffset;
|
||
|
|
val1 = Math.Max(val1, val2);
|
||
|
|
}
|
||
|
|
return val1;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void ComputeConstraint(int nearValue, int farValue, out int constraintMaxValue) => constraintMaxValue = farValue - nearValue;
|
||
|
|
|
||
|
|
private static int LocationFromEdges(
|
||
|
|
AnchorEdge near,
|
||
|
|
AnchorEdge far,
|
||
|
|
int nearValue,
|
||
|
|
int farValue,
|
||
|
|
int desiredSize,
|
||
|
|
int alignedSize,
|
||
|
|
int alignmentOffset,
|
||
|
|
out int size)
|
||
|
|
{
|
||
|
|
size = desiredSize;
|
||
|
|
int num;
|
||
|
|
if (near == null && far == null)
|
||
|
|
num = (nearValue + farValue - desiredSize) / 2;
|
||
|
|
else if (near != null && far == null)
|
||
|
|
num = nearValue;
|
||
|
|
else if (near == null && far != null)
|
||
|
|
{
|
||
|
|
num = farValue - desiredSize;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
num = nearValue + alignmentOffset;
|
||
|
|
size = alignedSize;
|
||
|
|
}
|
||
|
|
return num;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void Normalize(ref int nearValue, ref int farValue)
|
||
|
|
{
|
||
|
|
if (farValue >= nearValue)
|
||
|
|
return;
|
||
|
|
farValue = nearValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int Weigh(int value, float percentValue) => (int)(value * (double)percentValue);
|
||
|
|
|
||
|
|
void ILayout.Arrange(ILayoutNode layoutNode, LayoutSlot slot)
|
||
|
|
{
|
||
|
|
AnchorLayout.Packet measureData = (AnchorLayout.Packet)layoutNode.MeasureData;
|
||
|
|
if (measureData.Records == null)
|
||
|
|
return;
|
||
|
|
measureData.ParentActualRecord.Bounds = new Rectangle(Point.Zero, slot.Bounds);
|
||
|
|
measureData.AreaOfInterestRecord.Bounds = Rectangle.Zero;
|
||
|
|
Vector<AnchorLayout.Record> vector = null;
|
||
|
|
AnchorLayout.Record record1 = null;
|
||
|
|
foreach (AnchorLayout.Record record2 in measureData.Records)
|
||
|
|
{
|
||
|
|
if (record2.Phase != LayoutPhase.Arrange)
|
||
|
|
{
|
||
|
|
record2.LayoutNode.Arrange(slot, record2.Bounds);
|
||
|
|
if (record1 == null && (record2.LayoutNode.ContainsAreaOfInterest(AreaOfInterestID.FocusOverride) || record2.LayoutNode.ContainsAreaOfInterest(AreaOfInterestID.Focus)))
|
||
|
|
record1 = record2;
|
||
|
|
}
|
||
|
|
else if (!record2.Invalid)
|
||
|
|
{
|
||
|
|
if (vector == null)
|
||
|
|
vector = new Vector<AnchorLayout.Record>();
|
||
|
|
vector.Add(record2);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
record2.LayoutNode.MarkHidden();
|
||
|
|
}
|
||
|
|
if (vector == null)
|
||
|
|
return;
|
||
|
|
if (record1 != null)
|
||
|
|
{
|
||
|
|
AreaOfInterest area;
|
||
|
|
if (!record1.LayoutNode.TryGetAreaOfInterest(AreaOfInterestID.FocusOverride, out area))
|
||
|
|
record1.LayoutNode.TryGetAreaOfInterest(AreaOfInterestID.Focus, out area);
|
||
|
|
measureData.AreaOfInterestRecord.Bounds = Rectangle.Offset(area.DisplayRectangle, record1.Bounds.Location);
|
||
|
|
}
|
||
|
|
foreach (AnchorLayout.Record record2 in vector)
|
||
|
|
{
|
||
|
|
AnchorLayoutInput input = record2.Input;
|
||
|
|
bool flag = false;
|
||
|
|
AnchorLayout.Record recordRef;
|
||
|
|
int edge1 = ComputeEdge(measureData, "Left", input.Left, null, Orientation.Horizontal, record2, out recordRef, ref flag, ref flag);
|
||
|
|
int edge2 = ComputeEdge(measureData, "Top", input.Top, null, Orientation.Vertical, record2, out recordRef, ref flag, ref flag);
|
||
|
|
int edge3 = ComputeEdge(measureData, "Right", input.Right, null, Orientation.Horizontal, record2, out recordRef, ref flag, ref flag);
|
||
|
|
int edge4 = ComputeEdge(measureData, "Bottom", input.Bottom, null, Orientation.Vertical, record2, out recordRef, ref flag, ref flag);
|
||
|
|
int width = edge3 - edge1;
|
||
|
|
int height = edge4 - edge2;
|
||
|
|
record2.LayoutNode.Measure(new Size(width, height));
|
||
|
|
record2.LayoutNode.Arrange(slot, new Rectangle(edge1, edge2, width, height));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private AnchorLayout.Record GetReferenceRecord(
|
||
|
|
AnchorLayout.Packet packet,
|
||
|
|
string id)
|
||
|
|
{
|
||
|
|
if (id == "Parent")
|
||
|
|
return packet.ParentRecord;
|
||
|
|
if (id == "ParentActual")
|
||
|
|
return packet.ParentActualRecord;
|
||
|
|
if (id == "Focus")
|
||
|
|
return packet.AreaOfInterestRecord;
|
||
|
|
foreach (AnchorLayout.Record record in packet.Records)
|
||
|
|
{
|
||
|
|
if (record.ID == id)
|
||
|
|
{
|
||
|
|
if (record.Phase == LayoutPhase.Untouched)
|
||
|
|
MeasureChild(packet, record);
|
||
|
|
return record;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ErrorManager.ReportError("Anchor layout: {0} cannot find the '{1}' child", GetType().Name, id);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal static DataCookie InputData => s_dataProperty;
|
||
|
|
|
||
|
|
internal enum LayoutPhase
|
||
|
|
{
|
||
|
|
Untouched,
|
||
|
|
InProgress,
|
||
|
|
Circular,
|
||
|
|
Done,
|
||
|
|
Arrange,
|
||
|
|
}
|
||
|
|
|
||
|
|
internal class Record
|
||
|
|
{
|
||
|
|
public ILayoutNode LayoutNode;
|
||
|
|
public string ID;
|
||
|
|
public AnchorLayoutInput Input;
|
||
|
|
public Rectangle Bounds;
|
||
|
|
public AnchorLayout.LayoutPhase Phase;
|
||
|
|
public bool Visible = true;
|
||
|
|
public bool Invalid;
|
||
|
|
private static AnchorLayoutInput s_defaultInput = new AnchorLayoutInput();
|
||
|
|
|
||
|
|
public Record(ILayoutNode layoutNode) => Initialize(layoutNode);
|
||
|
|
|
||
|
|
public void Initialize(ILayoutNode layoutNode)
|
||
|
|
{
|
||
|
|
LayoutNode = layoutNode;
|
||
|
|
Input = layoutNode.GetLayoutInput(InputData) as AnchorLayoutInput;
|
||
|
|
if (Input == null)
|
||
|
|
Input = s_defaultInput;
|
||
|
|
ID = ((ViewItem)layoutNode).Name;
|
||
|
|
Bounds = Rectangle.Zero;
|
||
|
|
Phase = LayoutPhase.Untouched;
|
||
|
|
Visible = true;
|
||
|
|
Invalid = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public Record(string idName, Rectangle bounds, AnchorLayout.LayoutPhase phaseOverride)
|
||
|
|
{
|
||
|
|
ID = idName;
|
||
|
|
Bounds = bounds;
|
||
|
|
Phase = phaseOverride;
|
||
|
|
}
|
||
|
|
|
||
|
|
public override string ToString() => string.Format("AnchorLayout.Record({0}, Phase={1})", ID, Phase);
|
||
|
|
}
|
||
|
|
|
||
|
|
private class Packet
|
||
|
|
{
|
||
|
|
public ILayoutNode Subject;
|
||
|
|
public Vector<AnchorLayout.Record> Records;
|
||
|
|
public AnchorLayout.Record ParentRecord;
|
||
|
|
public AnchorLayout.Record ParentActualRecord;
|
||
|
|
public AnchorLayout.Record AreaOfInterestRecord;
|
||
|
|
public Size Constraint;
|
||
|
|
public Rectangle TotalBounds;
|
||
|
|
public bool CircularitiesDetected;
|
||
|
|
public AnchorLayout.Record CircularityBreakerRecord;
|
||
|
|
|
||
|
|
public override string ToString() => string.Format("AnchorLayout.Packet({0})", Subject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|