Files
MicrosoftIris/UIX/Microsoft/Iris/UI/UIZone.cs
T

593 lines
22 KiB
C#
Raw Normal View History

2022-03-03 08:14:05 -06:00
// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.UI.UIZone
// 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.Debug;
using Microsoft.Iris.Input;
using Microsoft.Iris.Layout;
using Microsoft.Iris.Layouts;
using Microsoft.Iris.Library;
using Microsoft.Iris.Render;
using Microsoft.Iris.RenderAPI.Drawing;
using Microsoft.Iris.Session;
using Microsoft.Iris.ViewItems;
using System;
namespace Microsoft.Iris.UI
{
2022-10-07 10:29:09 -05:00
public class UIZone : DisposableObject
2022-03-03 08:14:05 -06:00
{
private SessionInputHandler sessionInputEvent;
private UISession _parentSession;
private UIForm _form;
private uint _tasksRequestedValue;
private bool _physicalVisible;
private Size _containerSize;
private Vector3 _scale;
private Microsoft.Iris.UI.RootUI _rootUI;
private RootViewItem _rootViewItem;
private bool _needScaleNotificationsFlag;
private bool _needFullyEnabledNotificationsFlag;
private UIClass[] _mouseFocusRouteList;
private UIClass[] _keyFocusRouteList;
private UIZone.InputDeliveryData _cachedInputDeliveryData;
private UIClass[][] _cachedUIClassStorage;
private int _cachedUIClassStorageIndex;
private bool _previousZonePhysicalVisibleFlag;
private int _uncommittedLayouts;
public UIZone(UIForm form)
{
_parentSession = form.Session;
_form = form;
_scale = Vector3.UnitVector;
_rootUI = new Microsoft.Iris.UI.RootUI(this);
_rootViewItem = new RootViewItem(this, _rootUI, form);
_rootUI.SetRootItem(_rootViewItem);
_cachedInputDeliveryData = new UIZone.InputDeliveryData();
_cachedUIClassStorage = new UIClass[4][];
_cachedUIClassStorageIndex = _cachedUIClassStorage.Length - 1;
}
protected override void OnDispose()
{
base.OnDispose();
_rootUI.Dispose(this);
_rootUI = null;
}
public UISession Session => _parentSession;
public UIForm Form => _form;
public RootViewItem RootViewItem => _rootViewItem;
public UIClass RootUI => _rootUI;
public bool ZonePhysicalVisible => _physicalVisible;
public Size RootContainerSize => _containerSize;
public Vector3 HostDisplayScale => _scale;
public bool InfiniteLayoutLoopDetected => _uncommittedLayouts > 153;
public ICookedInputSite MapInput(
IRawInputSite rawSource,
ICookedInputSite targetRelative)
{
UIClass uiClass = null;
if (targetRelative != null)
uiClass = targetRelative as UIClass;
else if (rawSource != null && rawSource.OwnerData is ViewItem ownerData)
{
UIClass ui = ownerData.UI;
if (ui != null)
uiClass = ui;
}
if (uiClass != null && !uiClass.IsMouseFocusable())
uiClass = null;
return uiClass;
}
public object PrepareInputForDelivery(
ITreeNode endpoint,
ICookedInputSite finalTarget,
InputInfo info)
{
UIZone.InputDeliveryData inputDeliveryData = GetInputDeliveryData();
inputDeliveryData.target = finalTarget as UIClass;
inputDeliveryData.sourceInputInfo = info;
inputDeliveryData.eventRoute = ComputeEventRoute((UIClass)endpoint, out inputDeliveryData.routingLength);
if (inputDeliveryData.eventRoute != null)
--inputDeliveryData.routingLength;
return inputDeliveryData;
}
public void UpdateInputFocusStates(
InputDeviceType focusType,
bool deepFocusFlag,
ITreeNode directFocusChild,
object param)
{
switch (focusType)
{
case InputDeviceType.Keyboard:
DoDeepFocusUpdates(ref _keyFocusRouteList, deepFocusFlag, directFocusChild, param, UIClass.GetFocusUpdateProc(InputDeviceType.Keyboard));
break;
case InputDeviceType.Mouse:
DoDeepFocusUpdates(ref _mouseFocusRouteList, deepFocusFlag, directFocusChild, param, UIClass.GetFocusUpdateProc(InputDeviceType.Mouse));
break;
}
}
public InputDeliveryStatus DeliverInput(object param, EventRouteStages stage)
{
UIZone.InputDeliveryData data = (UIZone.InputDeliveryData)param;
bool routeTruncated = data.routeTruncated;
switch (stage)
{
case EventRouteStages.Direct:
DeliverInputDirectWorker(data, false);
break;
case EventRouteStages.Bubbled:
DeliverInputIndirectWorker(data, false);
break;
case EventRouteStages.Routed:
DeliverInputIndirectWorker(data, true);
break;
case EventRouteStages.Unhandled:
DeliverInputDirectWorker(data, true);
break;
}
return data.routeTruncated && !routeTruncated ? InputDeliveryStatus.Truncated : InputDeliveryStatus.Normal;
}
public void UpdateCursor(UIClass changedUI)
{
if (_form == null)
return;
UIClass uiClass = Session.InputManager.Queue.CurrentMouseFocus as UIClass;
if (changedUI != null && !IsChildADescendant(changedUI, uiClass))
return;
CursorID cursorId = CursorID.NotSpecified;
if (uiClass != null && uiClass.Zone == this)
{
do
{
cursorId = uiClass.EffectiveCursor;
uiClass = uiClass.Parent;
}
while (cursorId == CursorID.NotSpecified && uiClass != null);
}
if (cursorId == CursorID.NotSpecified)
cursorId = CursorID.Arrow;
_form.Cursor = cursorId;
}
public bool IsChildADescendant(ITreeNode potentialParent, ITreeNode potentialChild) => potentialParent is Microsoft.Iris.Library.TreeNode treeNode && treeNode.HasDescendant(potentialChild as Microsoft.Iris.Library.TreeNode);
public bool IsChildKeyFocusable(ITreeNode child) => ((UIClass)child).IsKeyFocusable();
public bool IsChildRooted(ITreeNode child) => IsChildRooted((Microsoft.Iris.Library.TreeNode)child);
public bool IsChildRooted(Microsoft.Iris.Library.TreeNode child) => child.Zone == this;
public int RootAccessibilityID => 0;
protected void ResendPaintedContent() => _rootViewItem?.ResendExistingContentTree();
protected void OnContainerChange()
{
RootViewItem rootViewItem = _rootViewItem;
if (rootViewItem == null || rootViewItem.IsDisposed)
return;
rootViewItem.MarkLayoutInvalid();
bool zonePhysicalVisible = ZonePhysicalVisible;
if (zonePhysicalVisible)
return;
rootViewItem.ApplyLayoutOutputs(true);
_previousZonePhysicalVisibleFlag = zonePhysicalVisible;
}
protected void OnHostDisplayScaleChange() => _rootViewItem?.NotifyEffectiveScaleChange(true);
internal void ScheduleScaleChangeNotifications()
{
if (_needScaleNotificationsFlag)
return;
ScheduleUiTask(UiTask.Initialization);
_needScaleNotificationsFlag = true;
}
internal void ScheduleFullyEnabledChangeNotifications()
{
if (_needFullyEnabledNotificationsFlag)
return;
ScheduleUiTask(UiTask.Initialization);
_needFullyEnabledNotificationsFlag = true;
}
public void OnRenderDeviceReset() => ResendPaintedContent();
public void SetPhysicalVisible(bool visible)
{
if (_physicalVisible == visible)
return;
_physicalVisible = visible;
OnContainerChange();
}
public void ResizeRootContainer(Size size)
{
if (!(_containerSize != size))
return;
_containerSize = size;
OnContainerChange();
}
public void SetHostDisplayScale(Vector3 scale)
{
if (!(_scale != scale))
return;
_scale = scale;
OnHostDisplayScaleChange();
}
public bool OnInboundKeyNavigation(
Direction searchDirection,
RectangleF startRectangleF,
bool defaultFlag)
{
UIClass rootUi = _rootUI;
return rootUi != null && rootUi.InboundKeyNavigation(searchDirection, startRectangleF, defaultFlag);
}
public event SessionInputHandler SessionInput
{
add
{
if (sessionInputEvent == null)
Session.InputManager.PreviewInput += new InputNotificationHandler(OnSessionInput);
sessionInputEvent += value;
}
remove
{
sessionInputEvent -= value;
if (sessionInputEvent != null)
return;
Session.InputManager.PreviewInput -= new InputNotificationHandler(OnSessionInput);
}
}
private void OnSessionInput(object sender, InputNotificationEventArgs args) => sessionInputEvent(args.InputInfo, args.HandledStage);
protected void ImplementUiTask(UiTask task, object param)
{
switch (task)
{
case UiTask.Initialization:
DeliverInitializations();
break;
case UiTask.LayoutComputation:
ILayoutNode rootViewItem1 = _rootViewItem;
if (rootViewItem1 == null)
break;
ScrollingLayout.ResetScrollFocusIntoView();
if (ZonePhysicalVisible)
{
Size rootContainerSize = RootContainerSize;
rootViewItem1.Measure(rootContainerSize);
rootViewItem1.Arrange(new LayoutSlot(rootContainerSize));
++_uncommittedLayouts;
ScheduleUiTask(UiTask.Painting);
}
else
rootViewItem1.MarkHidden();
rootViewItem1.Commit();
_rootViewItem.ResetLayoutInvalid();
break;
case UiTask.LayoutApplication:
ViewItem rootViewItem2 = _rootViewItem;
if (rootViewItem2 == null)
break;
bool zonePhysicalVisible = ZonePhysicalVisible;
rootViewItem2.ApplyLayoutOutputs(_previousZonePhysicalVisibleFlag != zonePhysicalVisible);
_previousZonePhysicalVisibleFlag = zonePhysicalVisible;
break;
case UiTask.Painting:
if (_rootViewItem != null)
{
_rootViewItem.UISession.Dispatcher.RequestBatchFlush();
_rootViewItem.PaintTree(true);
}
_uncommittedLayouts = 0;
break;
}
}
private void DeliverInputIndirectWorker(UIZone.InputDeliveryData data, bool downFlag)
{
UIClass[] eventRoute = data.eventRoute;
InputInfo sourceInputInfo = data.sourceInputInfo;
byte traceLevelForEvent = Trace.GetTraceLevelForEvent(sourceInputInfo);
if (eventRoute == null)
return;
if (downFlag)
{
for (int index = 0; index < data.routingLength; ++index)
{
UIClass target = eventRoute[index];
bool handled = sourceInputInfo.Handled;
target.DeliverInput(sourceInputInfo, EventRouteStages.Routed);
if (sourceInputInfo.Handled != handled)
TraceHandled(traceLevelForEvent, sourceInputInfo, target);
if (sourceInputInfo.RouteTruncated && !data.routeTruncated)
{
data.routeTruncated = true;
data.routingLength = index + 1;
break;
}
}
}
else
{
for (int index = data.routingLength - 1; index >= 0; --index)
{
UIClass target = eventRoute[index];
bool handled = sourceInputInfo.Handled;
target.DeliverInput(sourceInputInfo, EventRouteStages.Bubbled);
if (sourceInputInfo.Handled != handled)
TraceHandled(traceLevelForEvent, sourceInputInfo, target);
if (sourceInputInfo.RouteTruncated && !data.routeTruncated)
{
data.routeTruncated = true;
data.routingLength = index + 1;
}
}
}
}
private void DeliverInputDirectWorker(UIZone.InputDeliveryData data, bool lastChance)
{
if (data.routeTruncated)
return;
UIClass target = data.target;
InputInfo sourceInputInfo = data.sourceInputInfo;
byte traceLevelForEvent = Trace.GetTraceLevelForEvent(sourceInputInfo);
EventRouteStages stage = EventRouteStages.Direct;
if (lastChance)
stage = EventRouteStages.Unhandled;
bool handled = sourceInputInfo.Handled;
target.DeliverInput(sourceInputInfo, stage);
if (sourceInputInfo.Handled == handled)
return;
TraceHandled(traceLevelForEvent, sourceInputInfo, target);
}
private void TraceHandled(byte traceLevel, InputInfo info, UIClass target)
{
}
private UIZone.InputDeliveryData GetInputDeliveryData()
{
UIZone.InputDeliveryData inputDeliveryData = _cachedInputDeliveryData;
_cachedInputDeliveryData = null;
if (inputDeliveryData == null)
inputDeliveryData = new UIZone.InputDeliveryData();
return inputDeliveryData;
}
public void RecycleInputDeliveryData(object param)
{
if (param == null)
return;
UIZone.InputDeliveryData inputDeliveryData = (UIZone.InputDeliveryData)param;
inputDeliveryData.target = null;
inputDeliveryData.sourceInputInfo = null;
if (!inputDeliveryData.eventRouteCached)
RecycleUIClassArray(inputDeliveryData.eventRoute);
else
inputDeliveryData.eventRouteCached = false;
inputDeliveryData.eventRoute = null;
inputDeliveryData.routingLength = 0;
inputDeliveryData.routeTruncated = false;
_cachedInputDeliveryData = inputDeliveryData;
}
private UIClass[] GetUIClassArray(int requiredLength)
{
UIClass[] uiClassArray = null;
if (_cachedUIClassStorageIndex >= 0)
{
uiClassArray = _cachedUIClassStorage[_cachedUIClassStorageIndex];
_cachedUIClassStorage[_cachedUIClassStorageIndex] = null;
--_cachedUIClassStorageIndex;
}
if (uiClassArray == null || uiClassArray.Length < requiredLength)
uiClassArray = new UIClass[requiredLength];
return uiClassArray;
}
private void RecycleUIClassArray(UIClass[] storage)
{
if (storage == null || _cachedUIClassStorageIndex >= _cachedUIClassStorage.Length - 1)
return;
++_cachedUIClassStorageIndex;
Array.Clear(storage, 0, storage.Length);
_cachedUIClassStorage[_cachedUIClassStorageIndex] = storage;
}
private UIClass[] ComputeEventRoute(UIClass endpoint, out int entriesCount)
{
entriesCount = 0;
if (endpoint == null)
return null;
for (UIClass uiClass = endpoint; uiClass != null; uiClass = uiClass.Parent)
++entriesCount;
UIClass[] uiClassArray = GetUIClassArray(entriesCount);
UIClass uiClass1 = endpoint;
int num = entriesCount;
for (; uiClass1 != null; uiClass1 = uiClass1.Parent)
uiClassArray[--num] = uiClass1;
return uiClassArray;
}
private void DoDeepFocusUpdates(
ref UIClass[] refCurrentFocusRouteList,
bool deepFocusFlag,
ITreeNode directFocusChild,
object param,
FocusStateHandler updateProc)
{
if (updateProc == null)
return;
UIClass[] uiClassArray1 = refCurrentFocusRouteList;
UIClass[] uiClassArray2 = null;
UIZone.InputDeliveryData inputDeliveryData = (UIZone.InputDeliveryData)param;
if (inputDeliveryData != null)
uiClassArray2 = inputDeliveryData.eventRoute;
if (uiClassArray1 == null && uiClassArray2 == null)
return;
refCurrentFocusRouteList = uiClassArray2;
if (inputDeliveryData != null)
inputDeliveryData.eventRouteCached = true;
UIClass[] removedFromRoute = FindControlsRemovedFromRoute(uiClassArray1, uiClassArray2);
if (removedFromRoute != null)
UpdateControlFocusStates(removedFromRoute, false, null, updateProc);
RecycleUIClassArray(uiClassArray1);
if (removedFromRoute != uiClassArray1)
RecycleUIClassArray(removedFromRoute);
if (uiClassArray2 == null)
return;
UpdateControlFocusStates(uiClassArray2, true, directFocusChild, updateProc);
}
private UIClass[] FindControlsRemovedFromRoute(
UIClass[] oldRouteList,
UIClass[] newRouteList)
{
UIClass[] uiClassArray = null;
if (oldRouteList != null)
{
if (newRouteList != null && newRouteList.Length > 0)
{
bool flag = false;
if (oldRouteList.Length == newRouteList.Length)
{
flag = true;
for (int index = 0; index < newRouteList.Length; ++index)
{
if (oldRouteList[index] != newRouteList[index])
{
flag = false;
break;
}
}
}
if (!flag)
{
int num = 0;
for (int index = 0; index < oldRouteList.Length; ++index)
{
UIClass oldRoute = oldRouteList[index];
if (Array.IndexOf<UIClass>(newRouteList, oldRoute) < 0)
{
if (uiClassArray == null)
uiClassArray = GetUIClassArray(oldRouteList.Length - index);
uiClassArray[num++] = oldRoute;
}
}
}
}
else
uiClassArray = oldRouteList;
}
return uiClassArray;
}
private static void UpdateControlFocusStates(
UIClass[] focusRouteList,
bool deepFocusFlag,
ITreeNode actualFocus,
FocusStateHandler updateProc)
{
UIClass uiClass = actualFocus as UIClass;
for (int index = 0; index < focusRouteList.Length; ++index)
{
UIClass focusRoute = focusRouteList[index];
if (focusRoute == null)
break;
if (focusRoute.IsValid)
{
bool directFocusFlag = false;
if (deepFocusFlag)
directFocusFlag = focusRoute == uiClass;
updateProc(focusRoute, deepFocusFlag, directFocusFlag);
}
}
}
private void DeliverInitializations()
{
while (true)
{
while (_needFullyEnabledNotificationsFlag)
{
_needFullyEnabledNotificationsFlag = false;
UIClass rootUi = _rootUI;
if (rootUi != null)
rootUi.DeliverFullyEnabled(true);
else
break;
}
if (_needScaleNotificationsFlag)
{
_needScaleNotificationsFlag = false;
ViewItem rootViewItem = _rootViewItem;
if (rootViewItem != null)
rootViewItem.DeliverEffectiveScaleChange(false);
else
goto label_7;
}
else
break;
}
return;
label_7:;
}
public void ScheduleUiTask(UiTask task)
{
uint num = (uint)(task & (UiTask)~(int)_tasksRequestedValue);
if (num == 0U)
return;
_tasksRequestedValue |= num;
_parentSession.ScheduleUiTask(task);
}
public void ProcessUiTask(UiTask task, object param)
{
uint num = (uint)task;
if (((int)_tasksRequestedValue & (int)num) == 0)
return;
_tasksRequestedValue &= ~num;
ImplementUiTask(task, param);
}
public override string ToString() => GetType().Name + "[" + _form + "]";
private class InputDeliveryData
{
public UIClass target;
public InputInfo sourceInputInfo;
public UIClass[] eventRoute;
public int routingLength;
public bool routeTruncated;
public bool eventRouteCached;
}
}
}