Skip to content

Commit

Permalink
feat(itemsrepeater): Brings more C++ code and begin integration with Uno
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Nov 16, 2020
1 parent 77dbf85 commit 69bd34e
Show file tree
Hide file tree
Showing 24 changed files with 1,278 additions and 333 deletions.
3 changes: 2 additions & 1 deletion src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Uno.UI.DataBinding;
using Windows.UI.Core;
using Windows.UI.Xaml.Media;
using Microsoft.UI.Xaml.Controls;

#if XAMARIN_ANDROID
using View = Android.Views.View;
Expand All @@ -21,7 +22,7 @@
namespace Windows.UI.Xaml.Controls
{
[Markup.ContentProperty(Name = "Children")]
public partial class Panel : FrameworkElement, ICustomClippingElement
public partial class Panel : FrameworkElement, ICustomClippingElement, IPanel
{
#if NET461 || NETSTANDARD2_0
private new UIElementCollection _children;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#include "pch.h"
#include "common.h"
#include "QPCTimer.h"
#include "BuildTreeScheduler.h"
#include "RepeaterTestHooks.h"

double BuildTreeScheduler.m_budgetInMs = 40.0;
thread_local QPCTimer BuildTreeScheduler.m_timer{};
thread_local std.CalculatorList<WorkInfo> BuildTreeScheduler.m_pendingWork{};
thread_local event_token BuildTreeScheduler.m_renderingToken{};

void RegisterWork(int priority, const std.function<void()>& workFunc)
{
global::System.Diagnostics.Debug.Assert(priority >= 0);
global::System.Diagnostics.Debug.Assert(workFunc != null);

QueueTick();
m_pendingWork.push_back(WorkInfo(priority, workFunc));
}

bool ShouldYield()
{
return m_timer.DurationInMilliSeconds() > m_budgetInMs;
}

void OnRendering(const IInspectable&, const IInspectable&)
{
bool budgetReached = ShouldYield();
if (!budgetReached && m_pendingWork.size() > 0)
{
// Sort in descending order of priority and work from the end of the list to avoid moving around during erase.
std.sort(m_pendingWork.begin(), m_pendingWork.end(), [](const auto& lhs, const auto& rhs) { return lhs.Priority() > rhs.Priority(); });
int currentIndex = (int)(m_pendingWork.size()) - 1;

do
{
m_pendingWork[currentIndex].InvokeWorkFunc();
m_pendingWork.erase(m_pendingWork.begin() + currentIndex);
} while (--currentIndex >= 0 && !ShouldYield());
}

if (m_pendingWork.empty())
{
// No more pending work, unhook from rendering event since being hooked up will case wux to try to
// call the event at 60 frames per second
Windows.UI.Xaml.Media.CompositionTarget.CompositionTarget.Rendering(m_renderingToken);
m_renderingToken.value = 0;
RepeaterTestHooks.NotifyBuildTreeCompleted();
}

// Reset the timer so it snaps the time just before rendering
m_timer.Reset();
}

void QueueTick()
{
if (m_renderingToken.value == 0)
{
m_renderingToken = Windows.UI.Xaml.Media.CompositionTarget.Rendering(OnRendering);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Microsoft.UI.Xaml.Controls
{
internal class ChildrenInTabFocusOrderIterable : IEnumerable<DependencyObject>
{
private readonly ItemsRepeater m_repeater;

public ChildrenInTabFocusOrderIterable(ItemsRepeater repeater)
{
m_repeater = repeater;
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public IEnumerator<DependencyObject> GetEnumerator() => new ChildrenInTabFocusOrderIterator(m_repeater);

private class ChildrenInTabFocusOrderIterator : IEnumerator<DependencyObject>
{
private readonly List<KeyValuePair<int /* index */, UIElement>> m_realizedChildren;
private int m_index = 0;

public ChildrenInTabFocusOrderIterator(ItemsRepeater repeater)
{
var children = repeater.Children;
m_realizedChildren = new List<KeyValuePair<int, UIElement>>(children.Count);

// Filter out unrealized children.
for (var i = 0; i < children.Count; ++i)
{
var element = children[i];
var virtInfo = ItemsRepeater.GetVirtualizationInfo(element);
if (virtInfo.IsRealized)
{
m_realizedChildren.Add(new KeyValuePair<int, UIElement>(virtInfo.Index, element));
}
}

// Sort children by index.
m_realizedChildren.Sort((lhs, rhs) => lhs.Key - rhs.Key);
}

object IEnumerator.Current => Current;
public DependencyObject Current
{
get
{
if (m_index < m_realizedChildren.Count)
{
return m_realizedChildren[m_index].Value;
}
else
{
throw new IndexOutOfRangeException();
}
}
}

public bool MoveNext()
{
if (m_index < m_realizedChildren.Count)
{
++m_index;
return m_index < m_realizedChildren.Count;
}
else
{
throw new IndexOutOfRangeException();
}
}

public void Reset() { }
public void Dispose() { }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private bool IsVirtualizingContext
if (m_context != null)
{
var rect = m_context.RealizationRect;
bool hasInfiniteSize = double.IsInfinity(rect.Height) || double.IsInfinity(rect.Width));
bool hasInfiniteSize = double.IsInfinity(rect.Height) || double.IsInfinity(rect.Width);
return !hasInfiniteSize;
}

Expand Down
19 changes: 19 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Primitives/Repeater/IPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Linq;
using Windows.UI.Xaml.Controls;

namespace Microsoft.UI.Xaml.Controls
{
/// <summary>
/// This interface allows use to replicate the "DeriveFromPanelHelper_base" of WinUI (cf. Remarks)
/// </summary>
/// <remarks>
/// Doc about the DeriveFromPanelHelper_base in WinUI:
/// This type exists for types that in metadata derive from FrameworkElement but internally want to derive from Panel
/// to get "protected" Children.
/// </remarks>
internal interface IPanel
{
public UIElementCollection Children { get; }
}
}
Loading

0 comments on commit 69bd34e

Please sign in to comment.