From 3bfc847498531a7b9e7dbc633ac41088279d1bd5 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 19 Mar 2021 15:20:35 -0400 Subject: [PATCH] feat(swipecontrol): Implement the core of the SwipeControl --- .../Windows.UI.Xaml.Controls/SwipeControl.cs | 22 +- src/Uno.UI/Helpers/WinUI/DownlevelHelper.cs | 5 + src/Uno.UI/Helpers/WinUI/SharedHelpers.cs | 1 + .../Controls/SwipeControl/SwipeControl.Uno.cs | 30 + .../Controls/SwipeControl/SwipeControl.cs | 3499 +++++++++-------- .../Controls/SwipeControl/SwipeControl.h.cs | 502 +-- .../SwipeControl/SwipeControl.properties.cs | 335 +- .../SwipeControl/SwipeControl.properties.h.cs | 66 +- .../Xaml/Controls/SwipeControl/SwipeItem.cs | 7 +- .../Xaml/Controls/SwipeControl/SwipeItems.cs | 2 +- 10 files changed, 2319 insertions(+), 2150 deletions(-) create mode 100644 src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.Uno.cs diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/SwipeControl.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/SwipeControl.cs index f1e80b248e12..a1c964207ca6 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/SwipeControl.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/SwipeControl.cs @@ -2,12 +2,12 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented] #endif public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentControl { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public global::Windows.UI.Xaml.Controls.SwipeItems TopItems { @@ -21,7 +21,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public global::Windows.UI.Xaml.Controls.SwipeItems RightItems { @@ -35,7 +35,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public global::Windows.UI.Xaml.Controls.SwipeItems LeftItems { @@ -49,7 +49,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public global::Windows.UI.Xaml.Controls.SwipeItems BottomItems { @@ -63,7 +63,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public static global::Windows.UI.Xaml.DependencyProperty BottomItemsProperty { get; } = Windows.UI.Xaml.DependencyProperty.Register( @@ -71,7 +71,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon typeof(global::Windows.UI.Xaml.Controls.SwipeControl), new FrameworkPropertyMetadata(default(global::Windows.UI.Xaml.Controls.SwipeItems))); #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public static global::Windows.UI.Xaml.DependencyProperty LeftItemsProperty { get; } = Windows.UI.Xaml.DependencyProperty.Register( @@ -79,7 +79,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon typeof(global::Windows.UI.Xaml.Controls.SwipeControl), new FrameworkPropertyMetadata(default(global::Windows.UI.Xaml.Controls.SwipeItems))); #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public static global::Windows.UI.Xaml.DependencyProperty RightItemsProperty { get; } = Windows.UI.Xaml.DependencyProperty.Register( @@ -87,7 +87,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon typeof(global::Windows.UI.Xaml.Controls.SwipeControl), new FrameworkPropertyMetadata(default(global::Windows.UI.Xaml.Controls.SwipeItems))); #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public static global::Windows.UI.Xaml.DependencyProperty TopItemsProperty { get; } = Windows.UI.Xaml.DependencyProperty.Register( @@ -95,7 +95,7 @@ public partial class SwipeControl : global::Windows.UI.Xaml.Controls.ContentCon typeof(global::Windows.UI.Xaml.Controls.SwipeControl), new FrameworkPropertyMetadata(default(global::Windows.UI.Xaml.Controls.SwipeItems))); #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public SwipeControl() : base() { @@ -111,7 +111,7 @@ public SwipeControl() : base() // Forced skipping of method Windows.UI.Xaml.Controls.SwipeControl.TopItems.set // Forced skipping of method Windows.UI.Xaml.Controls.SwipeControl.BottomItems.get // Forced skipping of method Windows.UI.Xaml.Controls.SwipeControl.BottomItems.set - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public void Close() { diff --git a/src/Uno.UI/Helpers/WinUI/DownlevelHelper.cs b/src/Uno.UI/Helpers/WinUI/DownlevelHelper.cs index b95cda0e07d0..cae76759833b 100644 --- a/src/Uno.UI/Helpers/WinUI/DownlevelHelper.cs +++ b/src/Uno.UI/Helpers/WinUI/DownlevelHelper.cs @@ -9,5 +9,10 @@ public static bool ToDisplayNameExists() { return false; } + + public static bool SetIsTranslationEnabledExists() + { + return false; + } } } diff --git a/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs b/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs index 8d05492f6ea7..88b0ff81f686 100644 --- a/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs +++ b/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs @@ -840,6 +840,7 @@ public static object FindResource(string resource, ResourceDictionary resources, return resources.HasKey(boxedResource) ? resources.Lookup(boxedResource) : defaultValue; } + public static object FindInApplicationResources(string resource) => FindInApplicationResources(resource, default); public static object FindInApplicationResources(string resource, object defaultValue) { return FindResource(resource, Application.Current.Resources, defaultValue); diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.Uno.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.Uno.cs new file mode 100644 index 000000000000..f5ab948842ce --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.Uno.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Windows.UI.Xaml.Controls +{ + public partial class SwipeControl + { + [Conditional("DEBUG")] + private static void SWIPECONTROL_TRACE_INFO(SwipeControl that, [CallerLineNumber] int TRACE_MSG_METH = -1, [CallerMemberName] string METH_NAME = null, SwipeControl _ = null) + { + + } + + [Conditional("DEBUG")] + private static void SWIPECONTROL_TRACE_VERBOSE(SwipeControl that, [CallerLineNumber] int TRACE_MSG_METH = -1, [CallerMemberName] string METH_NAME = null, SwipeControl _ = null) + { + + } + + // TODO Uno - Interactions + private void InitializeInteractionTracker() { } + + private void ConfigurePositionInertiaRestingValues() { } + + private void IdleStateEntered(object @null, object @also_null) { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.cs index 9a07511af5dd..918cf47d3ccf 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.cs @@ -1,1721 +1,1796 @@ // 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.Numerics; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Composition; +using Windows.UI.Core; +using Windows.UI.Xaml.Hosting; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Uno.Disposables; +using Uno.UI.Helpers.WinUI; + namespace Windows.UI.Xaml.Controls { - public partial class SwipeControl + public partial class SwipeControl : ContentControl { // Change to 'true' to turn on debugging outputs in Output window - bool SwipeControlTrace.s_IsDebugOutputEnabled{ false }; -bool SwipeControlTrace.s_IsVerboseDebugOutputEnabled{ false }; - -static double c_epsilon = 0.0001; -static float c_ThresholdValue = 100.0; -static float c_MinimumCloseVelocity = 31.0; - -static thread_local winrt.weak_ref s_lastInteractedWithSwipeControl = null; - -SwipeControl() -{ - __RP_Marker_ClassById(RuntimeProfiler.ProfId_SwipeControl); - SetDefaultStyleKey(this); -} - -SwipeControl.~SwipeControl() -{ - DetachEventHandlers(); - - if (var lastInteractedWithSwipeControl = s_lastInteractedWithSwipeControl.get()) - { - if (lastInteractedWithSwipeControl.get() == this) - { - s_lastInteractedWithSwipeControl = null; - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyLastInteractedWithSwipeControlChanged(); - } - } - } -} - -#pragma region ISwipeControl - -void Close() -{ - CheckThread(); - - if (m_isOpen && !m_lastActionWasClosing && !m_isInteracting) - { - m_lastActionWasClosing = true; - if (!m_isIdle) - { - winrt.float3 initialPosition{ 0.0f }; - switch (m_createdContent) - { - case CreatedContent.Left: - initialPosition.x = (float)(-m_swipeContentStackPanel.get().ActualWidth()); - break; - case CreatedContent.Top: - initialPosition.y = (float)(-m_swipeContentStackPanel.get().ActualHeight()); - break; - case CreatedContent.Right: - initialPosition.x = (float)(m_swipeContentStackPanel.get().ActualWidth()); - break; - case CreatedContent.Bottom: - initialPosition.y = (float)(m_swipeContentStackPanel.get().ActualHeight()); - break; - case CreatedContent.None: - break; - default: - assert(false); - } - m_interactionTracker.get().TryUpdatePosition(initialPosition); - } - - winrt.float3 addedVelocity{ 0.0f }; - switch (m_createdContent) - { - case CreatedContent.Left: - addedVelocity.x = c_MinimumCloseVelocity; - break; - case CreatedContent.Top: - addedVelocity.y = c_MinimumCloseVelocity; - break; - case CreatedContent.Right: - addedVelocity.x = -c_MinimumCloseVelocity; - break; - case CreatedContent.Bottom: - addedVelocity.y = -c_MinimumCloseVelocity; - break; - case CreatedContent.None: - break; - default: - assert(false); - } - m_interactionTracker.get().TryUpdatePositionWithAdditionalVelocity(addedVelocity); - } -} -#pragma endregion - -#pragma region FrameworkElementOverrides -void OnApplyTemplate() -{ - ThrowIfHasVerticalAndHorizontalContent(/setIsHorizontal/ true); - - DetachEventHandlers(); - GetTemplateParts(); - EnsureClip(); - AttachEventHandlers(); -} - -void OnPropertyChanged( winrt.DependencyPropertyChangedEventArgs& args) -{ - winrt.IDependencyProperty property = args.Property(); - if (property == s_LeftItemsProperty) - { - OnLeftItemsCollectionChanged(args); - } - if (property == s_RightItemsProperty) - { - OnRightItemsCollectionChanged(args); - } - if (property == s_TopItemsProperty) - { - OnTopItemsCollectionChanged(args); - } - if (property == s_BottomItemsProperty) - { - OnBottomItemsCollectionChanged(args); - } -} - -//Swipe control is usually placed in a list view item. When this is the case the swipe item needs to be the same size as the list view item. -//This is to ensure that swiping from anywhere on the list view item causes pointer pressed events in the SwipeControl. Without this measure -//override it is usually not the case that swipe control will fill the available space. This is because list view item is a content control -//and those by convension only provide it's children space for at most their desired size. However list view item itself will take up a different -//ammount of space. In the past we solved this issue by requiring the list view item to have the HorizontalContentAlignment and VerticalContentAlignment -//set to stretch. This property changes the measure cycle to give as much space as possible to the list view items children. Instead we can -//just do this ourselves in this measure override and prevent the confusing need for properties set on the parent of swipe control to use it at all. -winrt.Size MeasureOverride(winrt.Size & availableSize) -{ - m_rootGrid.get().Measure(availableSize); - winrt.Size contentDesiredSize = m_rootGrid.get().DesiredSize(); - if (availableSize.Width != std.numeric_limits.infinity()) - { - contentDesiredSize.Width = availableSize.Width; - } - if (availableSize.Height != std.numeric_limits.infinity()) - { - contentDesiredSize.Height = availableSize.Height; - } - return contentDesiredSize; -} -#pragma endregion - -#pragma region IInteractionTrackerOwner -void CustomAnimationStateEntered( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerCustomAnimationStateEnteredArgs & /args/) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - m_isInteracting = true; - - if (m_isIdle) - { - m_isIdle = false; - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyIdleStatusChanged(this); - } - } -} - -void RequestIgnored( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerRequestIgnoredArgs & /args/) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); -} - -void IdleStateEntered( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerIdleStateEnteredArgs & /args/) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - m_isInteracting = false; - UpdateIsOpen(m_interactionTracker.get().Position() != winrt.float3.zero()); - - if (m_isOpen) - { - if (m_currentItems && m_currentItems.get().Mode() == winrt.SwipeMode.Execute && m_currentItems.get().Size() > 0) - { - var swipeItem = (winrt.SwipeItem)(m_currentItems.get().GetAt(0)); - winrt.get_self(swipeItem).InvokeSwipe(this); - } - } - else - { - if (var swipeContentStackPanel = m_swipeContentStackPanel.get()) - { - swipeContentStackPanel.Background(null); - if (var swipeContentStackPanelChildren = swipeContentStackPanel.Children()) - { - swipeContentStackPanelChildren.Clear(); - } - } - if (var swipeContentRoot = m_swipeContentRoot.get()) - { - swipeContentRoot.Background(null); - } - - m_currentItems.set(null); - m_createdContent = CreatedContent.None; - } - - if (!m_isIdle) - { - m_isIdle = true; - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyIdleStatusChanged(this); - } - } -} - -void InteractingStateEntered( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerInteractingStateEnteredArgs & /args/) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_isIdle) - { - m_isIdle = false; - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyIdleStatusChanged(this); - } - } - - m_lastActionWasClosing = false; - m_lastActionWasOpening = false; - m_isInteracting = true; - - //Once the user has started interacting with a SwipeControl in the closed state we are free to unblock contents. - //Contents of items opposite the currently opened ones will not be created. - if (!m_isOpen) - { - m_blockNearContent = false; - m_blockFarContent = false; - m_interactionTracker.get().Properties().InsertBoolean(s_blockNearContentPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_blockFarContentPropertyName, false); - } -} - -void InertiaStateEntered( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerInertiaStateEnteredArgs & args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - m_isInteracting = false; - - if (m_isIdle) - { - m_isIdle = false; - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyIdleStatusChanged(this); - } - } - - //It is possible that the user has flicked from a negative position to a position that would result in the interaction - //tracker coming to rest at the positive open position (or vise versa). The != zero check does not account for this. - //Instead we check to ensure that the current position and the ModifiedRestingPosition have the same sign (multiply to a positive number) - //If they do not then we are in this situation and want the end result of the interaction to be the closed state, so close without any animation and return - //to prevent further processing of this inertia state. - var flickToOppositeSideCheck = m_interactionTracker.get().Position() * args.ModifiedRestingPosition().Value(); - if (m_isHorizontal ? flickToOppositeSideCheck.x < 0 : flickToOppositeSideCheck.y < 0) - { - CloseWithoutAnimation(); - return; - } - - UpdateIsOpen(args.ModifiedRestingPosition().Value() != winrt.float3.zero()); - // If the user has panned the interaction tracker past 0 in the opposite direction of the previously - // opened swipe items then when we set m_isOpen to true the animations will snap to that value. - // To avoid this we block that side of the animation until the interacting state is entered. - if (m_isOpen) - { - switch (m_createdContent) - { - case CreatedContent.Bottom: - case CreatedContent.Right: - m_blockNearContent = true; - m_blockFarContent = false; - m_interactionTracker.get().Properties().InsertBoolean(s_blockNearContentPropertyName, true); - m_interactionTracker.get().Properties().InsertBoolean(s_blockFarContentPropertyName, false); - break; - case CreatedContent.Top: - case CreatedContent.Left: - m_blockNearContent = false; - m_blockFarContent = true; - m_interactionTracker.get().Properties().InsertBoolean(s_blockNearContentPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_blockFarContentPropertyName, true); - break; - case CreatedContent.None: - m_blockNearContent = false; - m_blockFarContent = false; - m_interactionTracker.get().Properties().InsertBoolean(s_blockNearContentPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_blockFarContentPropertyName, false); - break; - default: - assert(false); - } - } -} - -void ValuesChanged( - winrt.InteractionTracker & /sender/, - winrt.InteractionTrackerValuesChangedArgs & args) -{ - SWIPECONTROL_TRACE_VERBOSE(this, TRACE_MSG_METH, METH_NAME, this); - - var lastInteractedWithSwipeControl = s_lastInteractedWithSwipeControl.get(); - if (m_isInteracting && (!lastInteractedWithSwipeControl || lastInteractedWithSwipeControl.get() != this)) - { - if (lastInteractedWithSwipeControl) - { - lastInteractedWithSwipeControl.CloseIfNotRemainOpenExecuteItem(); - } - s_lastInteractedWithSwipeControl = get_weak(); - - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyLastInteractedWithSwipeControlChanged(); - } - } - - float value = 0.0f; - - if (m_isHorizontal) - { - value = args.Position().x; - if (!m_blockNearContent && m_createdContent != CreatedContent.Left && value < -c_epsilon) - { - CreateLeftContent(); - } - else if (!m_blockFarContent && m_createdContent != CreatedContent.Right && value > c_epsilon) - { - CreateRightContent(); - } - } - else - { - value = args.Position().y; - if (!m_blockNearContent && m_createdContent != CreatedContent.Top && value < -c_epsilon) - { - CreateTopContent(); - } - else if (!m_blockFarContent && m_createdContent != CreatedContent.Bottom && value > c_epsilon) - { - CreateBottomContent(); - } - } - UpdateThresholdReached(value); -} -#pragma endregion - -#pragma region TestHookHelpers -winrt.SwipeControl GetLastInteractedWithSwipeControl() -{ - if (var lastInteractedWithSwipeControl = s_lastInteractedWithSwipeControl.get()) - { - return lastInteractedWithSwipeControl; - } - return null; -} - -bool GetIsOpen() -{ - return m_isOpen; -} - -bool GetIsIdle() -{ - return m_isIdle; -} -#pragma endregion - -void OnLeftItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_leftItemsChangedToken.value != 0) - { - var observableVector = args.OldValue().try_as>(); - observableVector.VectorChanged(m_leftItemsChangedToken); - m_leftItemsChangedToken.value = 0; - } - - if (args.NewValue()) - { - ThrowIfHasVerticalAndHorizontalContent(); - var observableVector = args.NewValue().try_as>(); - m_leftItemsChangedToken = observableVector.VectorChanged({ this, &SwipeControl.OnLeftItemsChanged }); - } - - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasLeftContentPropertyName, args.NewValue() && args.NewValue().try_as>().Size() > 0); - } - - if (m_createdContent == CreatedContent.Left) - { - CreateLeftContent(); - } -} - -void OnRightItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_rightItemsChangedToken.value != 0) - { - var observableVector = args.OldValue().try_as>(); - observableVector.VectorChanged(m_rightItemsChangedToken); - m_rightItemsChangedToken.value = 0; - } - - if (args.NewValue()) - { - ThrowIfHasVerticalAndHorizontalContent(); - var observableVector = args.NewValue().try_as>(); - m_rightItemsChangedToken = observableVector.VectorChanged({ this, &SwipeControl.OnRightItemsChanged }); - } - - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasRightContentPropertyName, args.NewValue() && args.NewValue().try_as>().Size() > 0); - } - - if (m_createdContent == CreatedContent.Right) - { - CreateRightContent(); - } -} - -void OnTopItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_topItemsChangedToken.value != 0) - { - var observableVector = args.OldValue().try_as>(); - observableVector.VectorChanged(m_topItemsChangedToken); - m_topItemsChangedToken.value = 0; - } - - if (args.NewValue()) - { - ThrowIfHasVerticalAndHorizontalContent(); - var observableVector = args.NewValue().try_as>(); - m_topItemsChangedToken = observableVector.VectorChanged({ this, &SwipeControl.OnTopItemsChanged }); - } - - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasTopContentPropertyName, args.NewValue() && args.NewValue().try_as>().Size() > 0); - } - - if (m_createdContent == CreatedContent.Top) - { - CreateTopContent(); - } -} - -void OnBottomItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_bottomItemsChangedToken.value != 0) - { - var observableVector = args.OldValue().try_as>(); - observableVector.VectorChanged(m_bottomItemsChangedToken); - m_bottomItemsChangedToken.value = 0; - } - - if (args.NewValue()) - { - ThrowIfHasVerticalAndHorizontalContent(); - var observableVector = args.NewValue().try_as>(); - m_bottomItemsChangedToken = observableVector.VectorChanged({ this, &SwipeControl.OnBottomItemsChanged }); - } - - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasBottomContentPropertyName, args.NewValue() && args.NewValue().try_as>().Size() > 0); - } - - if (m_createdContent == CreatedContent.Bottom) - { - CreateBottomContent(); - } -} - -void OnLoaded( winrt.DependencyObject& /sender/, winrt.RoutedEventArgs& /args/) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (!m_hasInitialLoadedEventFired) - { - m_hasInitialLoadedEventFired = true; - InitializeInteractionTracker(); - TryGetSwipeVisuals(); - } - //If the swipe control has been added to the tree for a subsequent time, for instance when a list view item has been recycled, - //Ensure that we are in the closed interaction tracker state. - CloseWithoutAnimation(); -} - -void AttachEventHandlers() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - global::System.Diagnostics.Debug.Assert(m_loadedToken.value == 0); - m_loadedToken = Loaded({ this, &SwipeControl.OnLoaded }); - m_hasInitialLoadedEventFired = false; - - global::System.Diagnostics.Debug.Assert(m_onSizeChangedToken.value == 0); - m_onSizeChangedToken = SizeChanged({ this, &SwipeControl.OnSizeChanged }); - - global::System.Diagnostics.Debug.Assert(m_onSwipeContentStackPanelSizeChangedToken.value == 0); - m_onSwipeContentStackPanelSizeChangedToken = m_swipeContentStackPanel.get().SizeChanged({ this, &SwipeControl.OnSwipeContentStackPanelSizeChanged }); - - // also get any action from any inside button, or a clickable/tappable control - if (!m_onPointerPressedEventHandler) - { - m_onPointerPressedEventHandler.set(winrt.box_value({ this, &SwipeControl.OnPointerPressedEvent })); - AddHandler(winrt.UIElement.PointerPressedEvent(), m_onPointerPressedEventHandler.get(), true); - } - - global::System.Diagnostics.Debug.Assert(m_inputEaterTappedToken.value == 0); - m_inputEaterTappedToken = m_inputEater.get().Tapped({ this, &SwipeControl.InputEaterGridTapped }); -} - -void DetachEventHandlers() -{ - SWIPECONTROL_TRACE_INFO(null, TRACE_MSG_METH, METH_NAME, this); - - if (m_loadedToken.value != 0) - { - Loaded(m_loadedToken); - m_loadedToken.value = 0; - } - - if (m_onSizeChangedToken.value != 0) - { - SizeChanged(m_onSizeChangedToken); - m_onSizeChangedToken.value = 0; - } - - if (m_onSwipeContentStackPanelSizeChangedToken.value != 0) - { - m_swipeContentStackPanel.get().SizeChanged(m_onSwipeContentStackPanelSizeChangedToken); - m_onSwipeContentStackPanelSizeChangedToken.value = 0; - } - - if (m_onPointerPressedEventHandler) - { - RemoveHandler(winrt.UIElement.PointerPressedEvent(), m_onPointerPressedEventHandler.get()); - m_onPointerPressedEventHandler.set(null); - } - - if (m_inputEater.safe_get() && m_inputEaterTappedToken.value != 0) - { - m_inputEater.safe_get().Tapped(m_inputEaterTappedToken); - m_inputEaterTappedToken.value = 0; - } - - DetachDismissingHandlers(); -} - -void OnSizeChanged( winrt.DependencyObject& /sender/, winrt.SizeChangedEventArgs& /args/) -{ - EnsureClip(); - for (winrt.UIElement uiElement : m_swipeContentStackPanel.get().Children()) - { - winrt.AppBarButton appBarButton = uiElement.try_as(); - if (appBarButton) - { - if (m_isHorizontal) - { - appBarButton.Height(ActualHeight()); - if (m_currentItems && m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - appBarButton.Width(ActualWidth()); - } - } - else - { - appBarButton.Width(ActualWidth()); - if (m_currentItems && m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - appBarButton.Height(ActualHeight()); - } - } - } - } -} - -void OnSwipeContentStackPanelSizeChanged( winrt.DependencyObject& sender, winrt.SizeChangedEventArgs& args) -{ - if (m_interactionTracker) - { - m_interactionTracker.get().MinPosition({ -args.NewSize().Width, -args.NewSize().Height, 0.0f }); - m_interactionTracker.get().MaxPosition({ args.NewSize().Width, args.NewSize().Height, 0.0f }); - ConfigurePositionInertiaRestingValues(); - } -} - -void OnPointerPressedEvent( - winrt.DependencyObject& sender, - winrt.PointerRoutedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (args.Pointer().PointerDeviceType() == winrt.Devices.Input.PointerDeviceType.Touch && m_visualInteractionSource) - { - if (m_currentItems && - m_currentItems.get().Mode() == winrt.SwipeMode.Execute && - m_currentItems.get().Size() > 0 && - m_currentItems.get().GetAt(0).BehaviorOnInvoked() == winrt.SwipeBehaviorOnInvoked.RemainOpen && - m_isOpen) - { - //If the swipe control is currently open on an Execute item's who's behaviorOnInvoked property is set to RemainOpen - //we don't want to allow the user interaction to effect the swipe control anymore, so don't redirect the manipulation - //to the interaction tracker. - return; - } - try - { - m_visualInteractionSource.get().TryRedirectForManipulation(args.GetCurrentPoint(this)); - } - catch ( winrt.hresult_error& e) - { - // Swallowing Access Denied error because of InteractionTracker bug 17434718 which has been - // causing crashes at least in RS3, RS4 and RS5. - if (e.to_abi() != E_ACCESSDENIED) - { - throw; - } - } - } -} - -void InputEaterGridTapped( winrt.DependencyObject& /sender/, winrt.TappedRoutedEventArgs& args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_isOpen) - { - CloseIfNotRemainOpenExecuteItem(); - args.Handled(true); - } -} - -void AttachDismissingHandlers() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - DetachDismissingHandlers(); - - if (winrt.UIElement10 uiElement10 = this) - { - if ( var xamlRoot = uiElement10.XamlRoot()) - { - if ( var xamlRootContent = xamlRoot.Content()) - { - m_xamlRootPointerPressedEventRevoker = AddRoutedEventHandler( - xamlRootContent, - [this](var &, var & args) - { - DismissSwipeOnAnExternalTap(args.GetCurrentPoint(null).Position()); - }, - true /handledEventsToo/); - - m_xamlRootKeyDownEventRevoker = AddRoutedEventHandler( - xamlRootContent, - [this](var &, var & args) - { - CloseIfNotRemainOpenExecuteItem(); - }, - true /handledEventsToo/); - } - - m_xamlRootChangedRevoker = xamlRoot.Changed(winrt.auto_revoke, { this, &SwipeControl.CurrentXamlRootChanged }); - } - } - else - { - if (var currentWindow = winrt.Window.Current()) - { - if (var coreWindow = currentWindow.CoreWindow()) - { - m_coreWindowPointerPressedRevoker = coreWindow.PointerPressed(winrt.auto_revoke, { this, &SwipeControl.DismissSwipeOnAnExternalCoreWindowTap }); - m_coreWindowKeyDownRevoker = coreWindow.KeyDown(winrt.auto_revoke, { this, &SwipeControl.DismissSwipeOnCoreWindowKeyDown }); - m_windowMinimizeRevoker = coreWindow.VisibilityChanged(winrt.auto_revoke, { this, &SwipeControl.CurrentWindowVisibilityChanged }); - m_windowSizeChangedRevoker = currentWindow.SizeChanged(winrt.auto_revoke, { this, &SwipeControl.CurrentWindowSizeChanged }); - } - } - } - - if (var coreWindow = winrt.CoreWindow.GetForCurrentThread()) - { - if (var dispatcher = coreWindow.Dispatcher()) - { - m_acceleratorKeyActivatedRevoker = dispatcher.AcceleratorKeyActivated(winrt.auto_revoke, { this, &SwipeControl.DismissSwipeOnAcceleratorKeyActivator }); - } - } -} - -void DetachDismissingHandlers() -{ - SWIPECONTROL_TRACE_INFO(null, TRACE_MSG_METH, METH_NAME, this); - - m_xamlRootPointerPressedEventRevoker.revoke(); - m_xamlRootKeyDownEventRevoker.revoke(); - m_xamlRootChangedRevoker.revoke(); - - m_acceleratorKeyActivatedRevoker.revoke(); - m_coreWindowPointerPressedRevoker.revoke(); - m_coreWindowKeyDownRevoker.revoke(); - m_windowMinimizeRevoker.revoke(); - m_windowSizeChangedRevoker.revoke(); -} - -void DismissSwipeOnAcceleratorKeyActivator( winrt.Windows.UI.Core.CoreDispatcher& sender, winrt.AcceleratorKeyEventArgs& args) -{ - CloseIfNotRemainOpenExecuteItem(); -} - -void CurrentXamlRootChanged( winrt.XamlRoot & /sender/, winrt.XamlRootChangedEventArgs &/args/) -{ - CloseIfNotRemainOpenExecuteItem(); -} - -void DismissSwipeOnCoreWindowKeyDown( winrt.CoreWindow& sender, winrt.KeyEventArgs& args) -{ - CloseIfNotRemainOpenExecuteItem(); -} - -void CurrentWindowSizeChanged( winrt.DependencyObject & /sender/, winrt.WindowSizeChangedEventArgs &/args/) -{ - CloseIfNotRemainOpenExecuteItem(); -} - -void CurrentWindowVisibilityChanged( winrt.CoreWindow & /sender/, winrt.VisibilityChangedEventArgs /args/) -{ - CloseIfNotRemainOpenExecuteItem(); -} - -void DismissSwipeOnAnExternalCoreWindowTap( winrt.CoreWindow& sender, winrt.PointerEventArgs& args) -{ - DismissSwipeOnAnExternalTap(args.CurrentPoint().RawPosition()); -} - -void DismissSwipeOnAnExternalTap(winrt.Point & tapPoint) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - winrt.GeneralTransform transform = TransformToVisual(null); - winrt.Point p(0, 0); - - // start of the swipe control - var transformedElementOrigin = transform.TransformPoint(p); - - // If point is not within the item's bounds, close it. - if (this && tapPoint.X < transformedElementOrigin.X || tapPoint.Y < transformedElementOrigin.Y || - (tapPoint.X - transformedElementOrigin.X) > ActualWidth() || - (tapPoint.Y - transformedElementOrigin.Y) > ActualHeight()) - { - CloseIfNotRemainOpenExecuteItem(); - } -} - -void GetTemplateParts() -{ - winrt.IControlProtected thisAsControlProtected = this; - m_rootGrid.set(GetTemplateChildT(s_rootGridName, thisAsControlProtected)); - m_inputEater.set(GetTemplateChildT(s_inputEaterName, thisAsControlProtected)); - m_content.set(GetTemplateChildT(s_ContentRootName, thisAsControlProtected)); - m_swipeContentRoot.set(GetTemplateChildT(s_swipeContentRootName, thisAsControlProtected)); - m_swipeContentStackPanel.set(GetTemplateChildT(s_swipeContentStackPanelName, thisAsControlProtected)); - - //Before RS5 these elements were not in the template but were instead created in code behind when the swipe content was created. - //Post RS5 the code behind expects these elements to always be in the tree. - if (!m_swipeContentRoot) - { - winrt.Grid swipeContentRoot; - swipeContentRoot.Name("SwipeContentRoot"); - m_swipeContentRoot.set(swipeContentRoot); - m_rootGrid.get().Children().InsertAt(0, swipeContentRoot); - } - if (!m_swipeContentStackPanel) - { - winrt.StackPanel swipeContentStackPanel; - swipeContentStackPanel.Name("SwipeContentStackPanel"); - m_swipeContentStackPanel.set(swipeContentStackPanel); - m_swipeContentRoot.get().Children().Append(swipeContentStackPanel); - } - m_swipeContentStackPanel.get().Orientation(m_isHorizontal ? winrt.Orientation.Horizontal : winrt.Orientation.Vertical); - - if (var lookedUpStyle = SharedHelpers.FindInApplicationResources(s_swipeItemStyleName)) - { - m_swipeItemStyle.set(lookedUpStyle.try_as()); - } -} - -void InitializeInteractionTracker() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - winrt.IInteractionTrackerOwner interactionTrackerOwner = this; - - if (!m_compositor) - { - m_compositor.set(winrt.ElementCompositionPreview.GetElementVisual(m_rootGrid.get()).Compositor()); - } - - m_visualInteractionSource.set(winrt.VisualInteractionSource.Create(FindVisualInteractionSourceVisual())); - m_visualInteractionSource.get().IsPositionXRailsEnabled(m_isHorizontal); - m_visualInteractionSource.get().IsPositionYRailsEnabled(!m_isHorizontal); - m_visualInteractionSource.get().ManipulationRedirectionMode(winrt.VisualInteractionSourceRedirectionMode.CapableTouchpadOnly); - m_visualInteractionSource.get().PositionXSourceMode(m_isHorizontal ? winrt.InteractionSourceMode.EnabledWithInertia : winrt.InteractionSourceMode.Disabled); - m_visualInteractionSource.get().PositionYSourceMode(!m_isHorizontal ? winrt.InteractionSourceMode.EnabledWithInertia : winrt.InteractionSourceMode.Disabled); - if (m_isHorizontal) - { - m_visualInteractionSource.get().PositionXChainingMode(winrt.InteractionChainingMode.Never); - } - else - { - m_visualInteractionSource.get().PositionYChainingMode(winrt.InteractionChainingMode.Never); - } - - m_interactionTracker.set(winrt.InteractionTracker.CreateWithOwner(m_compositor.get(), interactionTrackerOwner)); - m_interactionTracker.get().InteractionSources().Add(m_visualInteractionSource.get()); - m_interactionTracker.get().Properties().InsertBoolean(s_isFarOpenPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_isNearOpenPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_blockNearContentPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_blockFarContentPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_hasLeftContentPropertyName, LeftItems() && LeftItems().Size() > 0); - m_interactionTracker.get().Properties().InsertBoolean(s_hasRightContentPropertyName, RightItems() && RightItems().Size() > 0); - m_interactionTracker.get().Properties().InsertBoolean(s_hasTopContentPropertyName, TopItems() && TopItems().Size() > 0); - m_interactionTracker.get().Properties().InsertBoolean(s_hasBottomContentPropertyName, BottomItems() && BottomItems().Size() > 0); - m_interactionTracker.get().MaxPosition({ std.numeric_limits.infinity(), std.numeric_limits.infinity(), 0.0f }); - m_interactionTracker.get().MinPosition({ -1.0f * std.numeric_limits.infinity(), -1.0f * std.numeric_limits.infinity(), 0.0f }); - - // Create and initialize the Swipe animations: - // If the swipe control is already opened it should not be possible to open the opposite side's items, without first closing the swipe control. - // This prevents the user from flicking the swipe control closed and accidently opening the other due to inertia. - // To acheive this we insert the isFarOpen and isNearOpen boolean properties on the interaction tracker and alter the expression output based on these. - // The opened state is maintained in the interaction trackers IdleStateEntered handler, this means we need to ensure this state is entered each time the swipe control - // is opened or closed. - - // A more readable version of the expression: - - /m_swipeAnimation.set(m_compositor.get().CreateExpressionAnimation("isHorizontal ?" - "Vector3(tracker.isFarOpen || tracker.blockNearContent ? Clamp(-tracker.Position.X, -this.Target.Size.X, 0) :" - "tracker.isNearOpen || tracker.blockFarContent ? Clamp(-tracker.Position.X, 0, this.Target.Size.X) :" - "Clamp(-tracker.Position.X, (tracker.hasRightContent ? -10000 : 0), (tracker.hasLeftContent ? 10000 : 0)), 0, 0) :" - "Vector3(0, tracker.isFarOpen || tracker.blockNearContent ? Clamp(-tracker.Position.Y, -this.Target.Size.Y, 0) :" - "tracker.isNearOpen || tracker.blockFarContent ? Clamp(-tracker.Position.Y, 0, this.Target.Size.Y) :" - "Clamp(-tracker.Position.Y, (tracker.hasBottomContent ? -10000 : 0), (tracker.hasTopContent ? 10000 : 0)), 0)"));*/ - - m_swipeAnimation.set(m_compositor.get().CreateExpressionAnimation(isHorizontalPropertyName() + " ?" - "Vector3(" + trackerPropertyName() + "." + isFarOpenPropertyName() + " || " + trackerPropertyName() + "." + blockNearContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.X, -this.Target.Size.X, 0) :" - + trackerPropertyName() + "." + isNearOpenPropertyName() + " || " + trackerPropertyName() + "." + blockFarContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.X, 0, this.Target.Size.X) :" - "Clamp(-" + trackerPropertyName() + ".Position.X, (" + trackerPropertyName() + "." + hasRightContentPropertyName() + " ? -10000 : 0), (" + trackerPropertyName() + "." + hasLeftContentPropertyName() + " ? 10000 : 0)), 0, 0) :" - "Vector3(0, " + trackerPropertyName() + "." + isFarOpenPropertyName() + " || " + trackerPropertyName() + "." + blockNearContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.Y, -this.Target.Size.Y, 0) :" - + trackerPropertyName() + "." + isNearOpenPropertyName() + " || " + trackerPropertyName() + "." + blockFarContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.Y, 0, this.Target.Size.Y) :" - "Clamp(-" + trackerPropertyName() + ".Position.Y, (" + trackerPropertyName() + "." + hasBottomContentPropertyName() + " ? -10000 : 0), (" + trackerPropertyName() + "." + hasTopContentPropertyName() + " ? 10000 : 0)), 0)")); - - m_swipeAnimation.get().SetReferenceParameter(s_trackerPropertyName, m_interactionTracker.get()); - m_swipeAnimation.get().SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); - if (IsTranslationFacadeAvailableForSwipeControl(m_content.get())) - { - m_swipeAnimation.get().Target(s_translationPropertyName); - } - - //A more readable version of the expression: - - /m_executeExpressionAnimation.set(m_compositor.get().CreateExpressionAnimation("(foregroundVisual." + GetAnimationTarget() + " * 0.5) + (isHorizontal ?" - "Vector3((isNearContent ? -0.5, 0.5) * this.Target.Size.X, 0, 0) : " - "Vector3(0, (isNearContent ? -0.5, 0.5) * this.Target.Size.Y, 0))"));*/ - - m_executeExpressionAnimation.set(m_compositor.get().CreateExpressionAnimation("(" + foregroundVisualPropertyName() + "." + GetAnimationTarget(m_swipeContentStackPanel.get()) + " * 0.5) + (" + isHorizontalPropertyName() + " ? " - "Vector3((" + isNearContentPropertyName() + " ? -0.5 : 0.5) * this.Target.Size.X, 0, 0) : " - "Vector3(0, (" + isNearContentPropertyName() + " ? -0.5 : 0.5) * this.Target.Size.Y, 0))")); - - m_executeExpressionAnimation.get().SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); - if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel.get())) - { - m_executeExpressionAnimation.get().Target(s_translationPropertyName); - } - - //A more readable version of the expression: - - /m_clipExpressionAnimation.set(m_compositor.get().CreateExpressionAnimation(L"isHorizontal ? - Max(swipeRootVisual.Size.X + (isNearContent ? tracker.Position.X : -tracker.Position.X) , 0) : - Max(swipeRootVisual.Size.Y + (isNearContent ? tracker.Position.Y : -tracker.Position.Y) , 0)"));*/ - - m_clipExpressionAnimation.set(m_compositor.get().CreateExpressionAnimation(isHorizontalPropertyName() + " ? " - "Max(" + swipeRootVisualPropertyName() + ".Size.X + (" + isNearContentPropertyName() + " ? " + trackerPropertyName() + ".Position.X : -" + trackerPropertyName() + ".Position.X) , 0) : " - "Max(" + swipeRootVisualPropertyName() + ".Size.Y + (" + isNearContentPropertyName() + " ? " + trackerPropertyName() + ".Position.Y : -" + trackerPropertyName() + ".Position.Y) , 0)")); - - m_clipExpressionAnimation.get().SetReferenceParameter(s_trackerPropertyName, m_interactionTracker.get()); - m_clipExpressionAnimation.get().SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); -} - -void ConfigurePositionInertiaRestingValues() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_isHorizontal) - { - winrt.IVector xModifiers = winrt.new Vector(); - - winrt.ExpressionAnimation leftCondition = m_compositor.get().CreateExpressionAnimation("this.Target." + hasLeftContentPropertyName() + " && !this.Target." + isFarOpenPropertyName() + " && this.Target.NaturalRestingPosition.x <= -1 * (this.Target." + isNearOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); - leftCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualWidth())); - leftCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); - winrt.ExpressionAnimation leftRestingPoint = m_compositor.get().CreateExpressionAnimation("-" + swipeContentSizeParameterName()); - leftRestingPoint.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualWidth())); - winrt.InteractionTrackerInertiaRestingValue leftOpen = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - leftOpen.Condition(leftCondition); - leftOpen.RestingValue(leftRestingPoint); - xModifiers.Append(leftOpen); - - winrt.ExpressionAnimation rightCondition = m_compositor.get().CreateExpressionAnimation("this.Target." + hasRightContentPropertyName() + " && !this.Target." + isNearOpenPropertyName() + " && this.Target.NaturalRestingPosition.x >= (this.Target." + isFarOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); - rightCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualWidth())); - rightCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); - winrt.ExpressionAnimation rightRestingValue = m_compositor.get().CreateExpressionAnimation(s_swipeContentSizeParameterName); - rightRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualWidth())); - winrt.InteractionTrackerInertiaRestingValue rightOpen = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - rightOpen.Condition(rightCondition); - rightOpen.RestingValue(rightRestingValue); - xModifiers.Append(rightOpen); - - winrt.ExpressionAnimation condition = m_compositor.get().CreateExpressionAnimation("true"); - winrt.ExpressionAnimation restingValue = m_compositor.get().CreateExpressionAnimation("0"); - winrt.InteractionTrackerInertiaRestingValue neutralX = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - neutralX.Condition(condition); - neutralX.RestingValue(restingValue); - xModifiers.Append(neutralX); - - m_interactionTracker.get().ConfigurePositionXInertiaModifiers(xModifiers); - } - else - { - winrt.IVector yModifiers = winrt.new Vector(); - - winrt.ExpressionAnimation topCondition = m_compositor.get().CreateExpressionAnimation("this.Target." + hasTopContentPropertyName() + " && !this.Target." + isFarOpenPropertyName() + " && this.Target.NaturalRestingPosition.y <= -1 * (this.Target." + isNearOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); - topCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualHeight())); - topCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); - winrt.ExpressionAnimation topRestingValue = m_compositor.get().CreateExpressionAnimation("-" + swipeContentSizeParameterName()); - topRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualHeight())); - winrt.InteractionTrackerInertiaRestingValue topOpen = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - topOpen.Condition(topCondition); - topOpen.RestingValue(topRestingValue); - yModifiers.Append(topOpen); - - winrt.ExpressionAnimation bottomCondition = m_compositor.get().CreateExpressionAnimation("this.Target." + hasBottomContentPropertyName() + " && !this.Target." + isNearOpenPropertyName() + " && this.Target.NaturalRestingPosition.y >= (this.Target." + isFarOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); - bottomCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualHeight())); - bottomCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); - winrt.ExpressionAnimation bottomRestingValue = m_compositor.get().CreateExpressionAnimation(s_swipeContentSizeParameterName); - bottomRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.get().ActualHeight())); - winrt.InteractionTrackerInertiaRestingValue bottomOpen = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - bottomOpen.Condition(bottomCondition); - bottomOpen.RestingValue(bottomRestingValue); - yModifiers.Append(bottomOpen); - - winrt.ExpressionAnimation condition = m_compositor.get().CreateExpressionAnimation("true"); - winrt.ExpressionAnimation restingValue = m_compositor.get().CreateExpressionAnimation("0"); - winrt.InteractionTrackerInertiaRestingValue neutralY = winrt.InteractionTrackerInertiaRestingValue.Create(m_compositor.get()); - neutralY.Condition(condition); - neutralY.RestingValue(restingValue); - yModifiers.Append(neutralY); - - m_interactionTracker.get().ConfigurePositionYInertiaModifiers(yModifiers); - } -} - -winrt.Visual FindVisualInteractionSourceVisual() -{ - winrt.Visual visualInteractionSource = null; - - // Don't walk up the tree too far largely as an optimization for when SwipeControl isn't used - // with a list. The general-case when using swipe with a ListView will probably have the - // LVIP as the visual parent of the SwipeControl but enabling checking for a few more - // levels above that could enable more complex list item templates where SwipeControl - // isn't the root element. - int maxSteps = 5; - int steps = 0; - var current = winrt.VisualTreeHelper.GetParent(this); - while (current && steps < maxSteps) - { - if (var lvip = current.try_as()) - { - visualInteractionSource = winrt.ElementCompositionPreview.GetElementVisual(lvip); - break; - } - - current = winrt.VisualTreeHelper.GetParent(current); - ++steps; - } - - if (!visualInteractionSource) - { - visualInteractionSource = winrt.ElementCompositionPreview.GetElementVisual(this); - } - - return visualInteractionSource; -} - -void EnsureClip() -{ - float width = (float)(ActualWidth()); - float height = (float)(ActualHeight()); - winrt.Rect rect = { 0.0f, 0.0f, width, height }; - winrt.Windows.UI.Xaml.Media.RectangleGeometry rectangleGeometry; - rectangleGeometry.Rect(rect); - Clip(rectangleGeometry); -} - -void CloseWithoutAnimation() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - bool wasIdle = m_isIdle; - m_interactionTracker.get().TryUpdatePosition({ 0.0f, 0.0f, 0.0f }); - if (wasIdle) - { - IdleStateEntered(null, null); - } -} - -void CloseIfNotRemainOpenExecuteItem() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_currentItems && - m_currentItems.get().Mode() == winrt.SwipeMode.Execute && - m_currentItems.get().Size() > 0 && - m_currentItems.get().GetAt(0).BehaviorOnInvoked() == winrt.SwipeBehaviorOnInvoked.RemainOpen && - m_isOpen) - { - //If we have a Mode set to Execute, and an item with BehaviorOnInvoked set to RemainOpen, we do not want to close, so no-op - return; - } - Close(); -} - -void CreateLeftContent() -{ - if (var items = LeftItems()) - { - m_createdContent = CreatedContent.Left; - CreateContent(items); - } -} - -void CreateRightContent() -{ - if (var items = RightItems()) - { - m_createdContent = CreatedContent.Right; - CreateContent(items); - } -} - -void CreateBottomContent() -{ - if (var items = BottomItems()) - { - m_createdContent = CreatedContent.Bottom; - CreateContent(items); - } -} - -void CreateTopContent() -{ - if (var items = TopItems()) - { - m_createdContent = CreatedContent.Top; - CreateContent(items); - } -} - -void CreateContent( winrt.SwipeItems& items) -{ - if (m_swipeContentStackPanel && m_swipeContentStackPanel.get().Children()) - { - m_swipeContentStackPanel.get().Children().Clear(); - } - - m_currentItems.set(items); - if (m_currentItems) - { - AlignStackPanel(); - PopulateContentItems(); - SetupExecuteExpressionAnimation(); - SetupClipAnimation(); - UpdateColors(); - } -} - -void AlignStackPanel() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_currentItems.get().Size() > 0) - { - switch (m_currentItems.get().Mode()) - { - case winrt.SwipeMode.Execute: - { - if (m_isHorizontal) - { - m_swipeContentStackPanel.get().HorizontalAlignment(winrt.HorizontalAlignment.Stretch); - m_swipeContentStackPanel.get().VerticalAlignment(winrt.VerticalAlignment.Center); - } - else - { - m_swipeContentStackPanel.get().HorizontalAlignment(winrt.HorizontalAlignment.Center); - m_swipeContentStackPanel.get().VerticalAlignment(winrt.VerticalAlignment.Stretch); - } - break; - } - case winrt.SwipeMode.Reveal: - { - if (m_isHorizontal) - { - var swipeContentStackPanelHorizontalAlignment = m_createdContent == CreatedContent.Left ? winrt.HorizontalAlignment.Left : - m_createdContent == CreatedContent.Right ? winrt.HorizontalAlignment.Right : - winrt.HorizontalAlignment.Stretch; - - m_swipeContentStackPanel.get().HorizontalAlignment(swipeContentStackPanelHorizontalAlignment); - m_swipeContentStackPanel.get().VerticalAlignment(winrt.VerticalAlignment.Center); - } - else - { - var swipeContentStackPanelVerticalAlignment = m_createdContent == CreatedContent.Top ? winrt.VerticalAlignment.Top : - m_createdContent == CreatedContent.Bottom ? winrt.VerticalAlignment.Bottom : - winrt.VerticalAlignment.Stretch; - - m_swipeContentStackPanel.get().HorizontalAlignment(winrt.HorizontalAlignment.Center); - m_swipeContentStackPanel.get().VerticalAlignment(swipeContentStackPanelVerticalAlignment); - } - break; - } - default: - assert(false); - break; - } - } -} - -void PopulateContentItems() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - for (winrt.SwipeItem swipeItem : m_currentItems.get()) - { - m_swipeContentStackPanel.get().Children().Append(GetSwipeItemButton(swipeItem)); - } - - TryGetSwipeVisuals(); -} - -void SetupExecuteExpressionAnimation() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel.get())) - { - m_swipeContentStackPanel.get().StopAnimation(m_executeExpressionAnimation.get()); - m_swipeContentStackPanel.get().Translation({ 0.0f, 0.0f, 0.0f }); - } - else if (m_swipeContentVisual) - { - m_swipeContentVisual.get().StopAnimation(GetAnimationTarget(m_swipeContentStackPanel.get())); - m_swipeContentVisual.get().Properties().InsertVector3(GetAnimationTarget(m_swipeContentStackPanel.get()), { 0.0f, 0.0f, 0.0f }); - } - - if (m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - assert(m_createdContent != CreatedContent.None); - m_executeExpressionAnimation.get().SetBooleanParameter(s_isNearContentPropertyName, m_createdContent == CreatedContent.Left || m_createdContent == CreatedContent.Top); - if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel.get())) - { - m_swipeContentStackPanel.get().StartAnimation(m_executeExpressionAnimation.get()); - } - if (m_swipeContentVisual) - { - m_swipeContentVisual.get().StartAnimation(GetAnimationTarget(m_swipeContentStackPanel.get()), m_executeExpressionAnimation.get()); - } - } -} - -void SetupClipAnimation() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (!m_insetClip) - { - m_insetClip.set(m_compositor.get().CreateInsetClip()); - m_swipeContentRootVisual.get().Clip(m_insetClip.get()); - } - else - { - m_insetClip.get().StopAnimation(s_leftInsetTargetName); - m_insetClip.get().StopAnimation(s_rightInsetTargetName); - m_insetClip.get().StopAnimation(s_topInsetTargetName); - m_insetClip.get().StopAnimation(s_bottomInsetTargetName); - m_insetClip.get().LeftInset(0.0f); - m_insetClip.get().RightInset(0.0f); - m_insetClip.get().TopInset(0.0f); - m_insetClip.get().BottomInset(0.0f); - } - - m_clipExpressionAnimation.get().SetBooleanParameter(s_isNearContentPropertyName, m_createdContent == CreatedContent.Left || m_createdContent == CreatedContent.Top); - - if (m_createdContent == CreatedContent.None) - { - //If we have no created content then we don't need to start the clip animation yet. - return; - } - - m_insetClip.get().StartAnimation(DirectionToInset(m_createdContent), m_clipExpressionAnimation.get()); -} - -void UpdateColors() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - UpdateColorsIfExecuteItem(); - } - else - { - UpdateColorsIfRevealItems(); - } -} - -winrt.AppBarButton GetSwipeItemButton( winrt.SwipeItem& swipeItem) -{ - winrt.AppBarButton itemAsButton; - winrt.get_self(swipeItem).GenerateControl(itemAsButton, m_swipeItemStyle.get()); - - if (!swipeItem.Background()) - { - if (var lookedUpBrush = SharedHelpers.FindInApplicationResources(m_currentItems.get().Mode() == winrt.SwipeMode.Reveal ? s_swipeItemBackgroundResourceName : m_thresholdReached ? s_executeSwipeItemPostThresholdBackgroundResourceName : s_executeSwipeItemPreThresholdBackgroundResourceName)) - { - itemAsButton.Background(lookedUpBrush.try_as()); - } - } - - if (!swipeItem.Foreground()) - { - if (var lookedUpBrush = SharedHelpers.FindInApplicationResources(m_currentItems.get().Mode() == winrt.SwipeMode.Reveal ? s_swipeItemForegroundResourceName : m_thresholdReached ? s_executeSwipeItemPostThresholdForegroundResourceName : s_executeSwipeItemPreThresholdForegroundResourceName)) - { - itemAsButton.Foreground(lookedUpBrush.try_as()); - } - } - - if (m_isHorizontal) - { - itemAsButton.Height(ActualHeight()); - if (m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - itemAsButton.Width(ActualWidth()); - } - } - else - { - itemAsButton.Width(ActualWidth()); - if (m_currentItems.get().Mode() == winrt.SwipeMode.Execute) - { - itemAsButton.Height(ActualHeight()); - } - } - return itemAsButton; -} - -void UpdateColorsIfExecuteItem() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (!m_currentItems || m_currentItems.get().Mode() != winrt.SwipeMode.Execute) - { - return; - } - - winrt.SwipeItem swipeItem = null; - if (m_currentItems.get().Size() > 0) - { - swipeItem = m_currentItems.get().GetAt(0); - } - UpdateExecuteBackgroundColor(swipeItem); - UpdateExecuteForegroundColor(swipeItem); -} - -void UpdateExecuteBackgroundColor( winrt.SwipeItem& swipeItem) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - winrt.Brush background = null; - - if (!m_thresholdReached) - { - if (var lookedUpBackgroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPreThresholdBackgroundResourceName)) - { - background = lookedUpBackgroundBrush.try_as(); - } - } - else - { - if (var lookedUpBackgroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPostThresholdBackgroundResourceName)) - { - background = lookedUpBackgroundBrush.try_as(); - } - } - - if (swipeItem && swipeItem.Background()) - { - background = swipeItem.Background(); - } - - m_swipeContentStackPanel.get().Background(background); - m_swipeContentRoot.get().Background(null); -} - -void UpdateExecuteForegroundColor( winrt.SwipeItem& swipeItem) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_swipeContentStackPanel.get().Children().Size() > 0) - { - if (var appBarButton = m_swipeContentStackPanel.get().Children().GetAt(0).as()) - { - winrt.Brush foreground = null; - - if (!m_thresholdReached) - { - if (var lookedUpForegroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPreThresholdForegroundResourceName)) - { - foreground = lookedUpForegroundBrush.try_as(); - } - } - else - { - if (var lookedUpForegroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPostThresholdForegroundResourceName)) - { - foreground = lookedUpForegroundBrush.try_as(); - } - } - - if (swipeItem && swipeItem.Foreground()) - { - foreground = swipeItem.Foreground(); - } - - appBarButton.Foreground(foreground); - appBarButton.Background(winrt.SolidColorBrush(winrt.Colors.Transparent())); - } - } -} - -void UpdateColorsIfRevealItems() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (m_currentItems.get().Mode() != winrt.SwipeMode.Reveal) - { - return; - } - - winrt.Brush rootGridBackground = null; - - if (var lookedUpBrush = SharedHelpers.FindInApplicationResources(s_swipeItemBackgroundResourceName)) - { - rootGridBackground = lookedUpBrush.try_as(); - } - if (m_currentItems.get().Size() > 0) - { - switch (m_createdContent) - { - case CreatedContent.Left: - case CreatedContent.Top: - { - var itemBackground = m_currentItems.get().GetAt(m_swipeContentStackPanel.get().Children().Size() - 1).Background(); - if (itemBackground != null) - { - rootGridBackground = itemBackground; - } - break; - } - case CreatedContent.Right: - case CreatedContent.Bottom: - { - var itemBackground = m_currentItems.get().GetAt(0).Background(); - if (itemBackground != null) - { - rootGridBackground = itemBackground; - } - break; - } - case CreatedContent.None: - { - break; - } - default: - assert(false); - break; - } - } - - m_swipeContentRoot.get().Background(rootGridBackground); - m_swipeContentStackPanel.get().Background(null); -} - -void OnLeftItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - ThrowIfHasVerticalAndHorizontalContent(); - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasLeftContentPropertyName, sender.Size() > 0); - } - - if (m_createdContent == CreatedContent.Left) - { - CreateLeftContent(); - } -} - -void OnRightItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - ThrowIfHasVerticalAndHorizontalContent(); - - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasRightContentPropertyName, sender.Size() > 0); - } - - if (m_createdContent == CreatedContent.Right) - { - CreateRightContent(); - } -} - -void OnTopItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - ThrowIfHasVerticalAndHorizontalContent(); - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasTopContentPropertyName, sender.Size() > 0); - } - - if (m_createdContent == CreatedContent.Top) - { - CreateTopContent(); - } -} - -void OnBottomItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - ThrowIfHasVerticalAndHorizontalContent(); - if (m_interactionTracker) - { - m_interactionTracker.get().Properties().InsertBoolean(s_hasBottomContentPropertyName, sender.Size() > 0); - } - - if (m_createdContent == CreatedContent.Bottom) - { - CreateBottomContent(); - } -} - -void TryGetSwipeVisuals() -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (IsTranslationFacadeAvailableForSwipeControl(m_content.get())) - { - m_swipeAnimation.get().Target(GetAnimationTarget(m_content.get())); - m_content.get().StartAnimation(m_swipeAnimation.get()); - } - else - { - var mainContentVisual = winrt.ElementCompositionPreview.GetElementVisual(m_content.get()); - if (mainContentVisual && m_mainContentVisual.get() != mainContentVisual) - { - m_mainContentVisual.set(mainContentVisual); - - if (DownlevelHelper.SetIsTranslationEnabledExists()) - { - winrt.ElementCompositionPreview.SetIsTranslationEnabled(m_content.get(), true); - mainContentVisual.Properties().InsertVector3(s_translationPropertyName, { 0.0f, 0.0f, 0.0f }); - } - mainContentVisual.StartAnimation(GetAnimationTarget(m_content.get()), m_swipeAnimation.get()); - - m_executeExpressionAnimation.get().SetReferenceParameter(s_foregroundVisualPropertyName, mainContentVisual); - } - } - - if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel.get())) - { - m_swipeAnimation.get().Target(GetAnimationTarget(m_swipeContentStackPanel.get())); - } - else - { - var swipeContentVisual = winrt.ElementCompositionPreview.GetElementVisual(m_swipeContentStackPanel.get()); - if (swipeContentVisual && m_swipeContentVisual.get() != swipeContentVisual) - { - m_swipeContentVisual.set(swipeContentVisual); - - if (DownlevelHelper.SetIsTranslationEnabledExists()) - { - winrt.ElementCompositionPreview.SetIsTranslationEnabled(m_swipeContentStackPanel.get(), true); - swipeContentVisual.Properties().InsertVector3(s_translationPropertyName, { 0.0f, 0.0f, 0.0f }); - } - - ConfigurePositionInertiaRestingValues(); - } - } - - var swipeContentRootVisual = winrt.ElementCompositionPreview.GetElementVisual(m_swipeContentRoot.get()); - if (swipeContentRootVisual && m_swipeContentRootVisual.get() != swipeContentRootVisual) - { - m_swipeContentRootVisual.set(swipeContentRootVisual); - m_clipExpressionAnimation.get().SetReferenceParameter(s_swipeRootVisualPropertyName, swipeContentRootVisual); - if (m_insetClip) - { - swipeContentRootVisual.Clip(m_insetClip.get()); - } - } -} - -void UpdateIsOpen(bool isOpen) -{ - SWIPECONTROL_TRACE_INFO(this, TRACE_MSG_METH, METH_NAME, this); - - if (isOpen) - { - if (!m_isOpen) - { - m_isOpen = true; - m_lastActionWasOpening = true; - switch (m_createdContent) - { - case CreatedContent.Right: - case CreatedContent.Bottom: - m_interactionTracker.get().Properties().InsertBoolean(s_isFarOpenPropertyName, true); - m_interactionTracker.get().Properties().InsertBoolean(s_isNearOpenPropertyName, false); - break; - case CreatedContent.Left: - case CreatedContent.Top: - m_interactionTracker.get().Properties().InsertBoolean(s_isFarOpenPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_isNearOpenPropertyName, true); - break; - case CreatedContent.None: - m_interactionTracker.get().Properties().InsertBoolean(s_isFarOpenPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_isNearOpenPropertyName, false); - break; - default: - assert(false); - } - - if (m_currentItems.get().Mode() != winrt.SwipeMode.Execute) - { - AttachDismissingHandlers(); - } - - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyOpenedStatusChanged(this); - } - } - } - else - { - if (m_isOpen) - { - m_isOpen = false; - m_lastActionWasClosing = true; - DetachDismissingHandlers(); - m_interactionTracker.get().Properties().InsertBoolean(s_isFarOpenPropertyName, false); - m_interactionTracker.get().Properties().InsertBoolean(s_isNearOpenPropertyName, false); - - if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) - { - globalTestHooks.NotifyOpenedStatusChanged(this); - } - } - } -} - -void UpdateThresholdReached(float value) -{ - SWIPECONTROL_TRACE_VERBOSE(this, TRACE_MSG_METH, METH_NAME, this); - - bool oldValue = m_thresholdReached; - float effectiveStackPanelSize = (float)((m_isHorizontal ? m_swipeContentStackPanel.get().ActualWidth() : m_swipeContentStackPanel.get().ActualHeight()) - 1); - if (!m_isOpen || m_lastActionWasOpening) - { - //If we are opening new swipe items then we need to scroll open c_ThresholdValue - m_thresholdReached = abs(value) > std.min(effectiveStackPanelSize, c_ThresholdValue); - } - else - { - //If we already have an open swipe item then swiping it closed by any amount will close it. - m_thresholdReached = abs(value) < effectiveStackPanelSize; - } - if (m_thresholdReached != oldValue) - { - UpdateColorsIfExecuteItem(); - } -} - -void ThrowIfHasVerticalAndHorizontalContent(bool setIsHorizontal) -{ - bool hasLeftContent = LeftItems() && LeftItems().Size() > 0; - bool hasRightContent = RightItems() && RightItems().Size() > 0; - bool hasTopContent = TopItems() && TopItems().Size() > 0; - bool hasBottomContent = BottomItems() && BottomItems().Size() > 0; - if (setIsHorizontal) - { - m_isHorizontal = hasLeftContent || hasRightContent || !(hasTopContent || hasBottomContent); - } - - if (this.Template()) - { - if (m_isHorizontal && (hasTopContent || hasBottomContent)) - { - throw winrt.hresult_invalid_argument("This SwipeControl is horizontal and can not have vertical items."); - } - if (!m_isHorizontal && (hasLeftContent || hasRightContent)) - { - throw winrt.hresult_invalid_argument("This SwipeControl is vertical and can not have horizontal items."); - } - } - else - { - if ((hasLeftContent || hasRightContent) && (hasTopContent || hasBottomContent)) - { - throw winrt.hresult_invalid_argument("SwipeControl can't have both horizontal items and vertical items set at the same time."); - } - } -} - -std.string GetAnimationTarget(winrt.UIElement child) -{ - if (DownlevelHelper.SetIsTranslationEnabledExists() || SharedHelpers.IsTranslationFacadeAvailable(child)) - { - return s_translationPropertyName.data(); - } - else - { - return s_offsetPropertyName.data(); - } -} - -winrt.SwipeControl GetThis() -{ - return this; -} - -bool IsTranslationFacadeAvailableForSwipeControl( winrt.UIElement& element) -{ - //For now Facade's are causing more issues than they are worth for swipe control. Revist this - //when we have a little more time. - - //There are concerns about swipe consumers having taken a dependency on the ElementCompositionPreview - //Api's that this is exclusive with and also the target property of the swipe expression animations - //is not resolving with the use of Facade's - return false; - //return SharedHelpers.IsTranslationFacadeAvailable(element); -} - -wstring_view DirectionToInset( CreatedContent& createdContent) -{ - switch (createdContent) - { - case CreatedContent.Right: - return s_leftInsetTargetName; - case CreatedContent.Left: - return s_rightInsetTargetName; - case CreatedContent.Bottom: - return s_topInsetTargetName; - case CreatedContent.Top: - return s_bottomInsetTargetName; - case CreatedContent.None: - return ""; - default: - assert(false); - return ""; - } -} -} + //bool SwipeControlTrace.s_IsDebugOutputEnabled = false; + //bool SwipeControlTrace.s_IsVerboseDebugOutputEnabled = false; + + private const double c_epsilon = 0.0001; + private const float c_ThresholdValue = 100.0f; + private const float c_MinimumCloseVelocity = 31.0f; + + [ThreadStatic] + static WeakReference s_lastInteractedWithSwipeControl = null; + + public SwipeControl() + { + s_lastInteractedWithSwipeControl ??= new WeakReference(null); + + //__RP_Marker_ClassById(RuntimeProfiler.ProfId_SwipeControl); + SetDefaultStyleKey(this); + } + + ~SwipeControl() + { + DetachEventHandlers(); + + if (s_lastInteractedWithSwipeControl.TryGetTarget(out var lastInteractedWithSwipeControl)) + { + if (lastInteractedWithSwipeControl == this) + { + s_lastInteractedWithSwipeControl.SetTarget(null); + var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks(); + if (globalTestHooks is {}) + { + globalTestHooks.NotifyLastInteractedWithSwipeControlChanged(); + } + } + } + } + + #region ISwipeControl + public void Close() + { + //CheckThread(); + + if (m_isOpen && !m_lastActionWasClosing && !m_isInteracting) + { + m_lastActionWasClosing = true; + if (!m_isIdle) + { + Vector3 initialPosition = default; + switch (m_createdContent) + { + case CreatedContent.Left: + initialPosition.X = (float)(-m_swipeContentStackPanel.ActualWidth); + break; + case CreatedContent.Top: + initialPosition.Y = (float)(-m_swipeContentStackPanel.ActualHeight); + break; + case CreatedContent.Right: + initialPosition.X = (float)(m_swipeContentStackPanel.ActualWidth); + break; + case CreatedContent.Bottom: + initialPosition.Y = (float)(m_swipeContentStackPanel.ActualHeight); + break; + case CreatedContent.None: + break; + default: + global::System.Diagnostics.Debug.Assert(false); + break; + } + + m_interactionTracker.TryUpdatePosition(initialPosition); + } + + Vector3 addedVelocity = default; + switch (m_createdContent) + { + case CreatedContent.Left: + addedVelocity.X = c_MinimumCloseVelocity; + break; + case CreatedContent.Top: + addedVelocity.Y = c_MinimumCloseVelocity; + break; + case CreatedContent.Right: + addedVelocity.X = -c_MinimumCloseVelocity; + break; + case CreatedContent.Bottom: + addedVelocity.Y = -c_MinimumCloseVelocity; + break; + case CreatedContent.None: + break; + default: + global::System.Diagnostics.Debug.Assert(false); + break; + } + + m_interactionTracker.TryUpdatePositionWithAdditionalVelocity(addedVelocity); + } + } +#endregion + + #region FrameworkElementOverrides + protected override void OnApplyTemplate() + { + ThrowIfHasVerticalAndHorizontalContent(setIsHorizontal: true); + + DetachEventHandlers(); + GetTemplateParts(); + EnsureClip(); + AttachEventHandlers(); + } + + private void OnPropertyChanged(DependencyPropertyChangedEventArgs args) + { + DependencyProperty property = args.Property; + if (property == LeftItemsProperty) + { + OnLeftItemsCollectionChanged(args); + } + + if (property == RightItemsProperty) + { + OnRightItemsCollectionChanged(args); + } + + if (property == TopItemsProperty) + { + OnTopItemsCollectionChanged(args); + } + + if (property == BottomItemsProperty) + { + OnBottomItemsCollectionChanged(args); + } + } + + //Swipe control is usually placed in a list view item. When this is the case the swipe item needs to be the same size as the list view item. + //This is to ensure that swiping from anywhere on the list view item causes pointer pressed events in the SwipeControl. Without this measure + //override it is usually not the case that swipe control will fill the available space. This is because list view item is a content control + //and those by convension only provide it's children space for at most their desired size. However list view item itself will take up a different + //ammount of space. In the past we solved this issue by requiring the list view item to have the HorizontalContentAlignment and VerticalContentAlignment + //set to stretch. This property changes the measure cycle to give as much space as possible to the list view items children. Instead we can + //just do this ourselves in this measure override and prevent the confusing need for properties set on the parent of swipe control to use it at all. + protected override Size MeasureOverride(Size availableSize) + { + m_rootGrid.Measure(availableSize); + Size contentDesiredSize = m_rootGrid.DesiredSize; + if (!double.IsInfinity(availableSize.Width)) + { + contentDesiredSize.Width = availableSize.Width; + } + + if (!double.IsInfinity(availableSize.Height)) + { + contentDesiredSize.Height = availableSize.Height; + } + + return contentDesiredSize; + } + #endregion + + #region IInteractionTrackerOwner + // Uno workaround: Interaction tracker is not supported yet, use Manipulation events instead + + //void CustomAnimationStateEntered( + // InteractionTracker sender, + // InteractionTrackerCustomAnimationStateEnteredArgs args) + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // m_isInteracting = true; + + // if (m_isIdle) + // { + // m_isIdle = false; + // if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) + // { + // globalTestHooks.NotifyIdleStatusChanged(this); + // } + // } + //} + + //void RequestIgnored( + // InteractionTracker sender, + + //InteractionTrackerRequestIgnoredArgs args) + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + //} + + //void IdleStateEntered( + // InteractionTracker sender, + + //InteractionTrackerIdleStateEnteredArgs args) + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // m_isInteracting = false; + // UpdateIsOpen(m_interactionTracker.Position() != float3.zero()); + + // if (m_isOpen) + // { + // if (m_currentItems && m_currentItems.Mode == SwipeMode.Execute && m_currentItems.Size() > 0) + // { + // var swipeItem = (SwipeItem)(m_currentItems.GetAt(0)); + // get_self(swipeItem).InvokeSwipe(this); + // } + // } + // else + // { + // if (var swipeContentStackPanel = m_swipeContentStackPanel) + // { + // swipeContentStackPanel.Background(null); + // if (var swipeContentStackPanelChildren = swipeContentStackPanel.Children) + // { + // swipeContentStackPanelChildren.Clear(); + // } + // } + // if (var swipeContentRoot = m_swipeContentRoot) + // { + // swipeContentRoot.Background(null); + // } + + // m_currentItems.set(null); + // m_createdContent = CreatedContent.None; + // } + + // if (!m_isIdle) + // { + // m_isIdle = true; + // if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) + // { + // globalTestHooks.NotifyIdleStatusChanged(this); + // } + // } + //} + + //void InteractingStateEntered( + // InteractionTracker sender, + + //InteractionTrackerInteractingStateEnteredArgs args) + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // if (m_isIdle) + // { + // m_isIdle = false; + // if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) + // { + // globalTestHooks.NotifyIdleStatusChanged(this); + // } + // } + + // m_lastActionWasClosing = false; + // m_lastActionWasOpening = false; + // m_isInteracting = true; + + // //Once the user has started interacting with a SwipeControl in the closed state we are free to unblock contents. + // //Contents of items opposite the currently opened ones will not be created. + // if (!m_isOpen) + // { + // m_blockNearContent = false; + // m_blockFarContent = false; + // m_interactionTracker.Properties.InsertBoolean(s_blockNearContentPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_blockFarContentPropertyName, false); + // } + //} + + //void InertiaStateEntered( + // InteractionTracker sender, + + //InteractionTrackerInertiaStateEnteredArgs & args) + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // m_isInteracting = false; + + // if (m_isIdle) + // { + // m_isIdle = false; + // if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) + // { + // globalTestHooks.NotifyIdleStatusChanged(this); + // } + // } + + // //It is possible that the user has flicked from a negative position to a position that would result in the interaction + // //tracker coming to rest at the positive open position (or vise versa). The != zero check does not account for this. + // //Instead we check to ensure that the current position and the ModifiedRestingPosition have the same sign (multiply to a positive number) + // //If they do not then we are in this situation and want the end result of the interaction to be the closed state, so close without any animation and return + // //to prevent further processing of this inertia state. + // var flickToOppositeSideCheck = m_interactionTracker.Position() * args.ModifiedRestingPosition().Value(); + // if (m_isHorizontal ? flickToOppositeSideCheck.x < 0 : flickToOppositeSideCheck.y < 0) + // { + // CloseWithoutAnimation(); + // return; + // } + + // UpdateIsOpen(args.ModifiedRestingPosition().Value() != float3.zero()); + // // If the user has panned the interaction tracker past 0 in the opposite direction of the previously + // // opened swipe items then when we set m_isOpen to true the animations will snap to that value. + // // To avoid this we block that side of the animation until the interacting state is entered. + // if (m_isOpen) + // { + // switch (m_createdContent) + // { + // case CreatedContent.Bottom: + // case CreatedContent.Right: + // m_blockNearContent = true; + // m_blockFarContent = false; + // m_interactionTracker.Properties.InsertBoolean(s_blockNearContentPropertyName, true); + // m_interactionTracker.Properties.InsertBoolean(s_blockFarContentPropertyName, false); + // break; + // case CreatedContent.Top: + // case CreatedContent.Left: + // m_blockNearContent = false; + // m_blockFarContent = true; + // m_interactionTracker.Properties.InsertBoolean(s_blockNearContentPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_blockFarContentPropertyName, true); + // break; + // case CreatedContent.None: + // m_blockNearContent = false; + // m_blockFarContent = false; + // m_interactionTracker.Properties.InsertBoolean(s_blockNearContentPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_blockFarContentPropertyName, false); + // break; + // default: + // assert(false); + // } + // } + //} + + //void ValuesChanged( + // InteractionTracker sender, + + //InteractionTrackerValuesChangedArgs & args) + //{ + // SWIPECONTROL_TRACE_VERBOSE(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // var lastInteractedWithSwipeControl = s_lastInteractedWithSwipeControl; + // if (m_isInteracting && (!lastInteractedWithSwipeControl || lastInteractedWithSwipeControl != this)) + // { + // if (lastInteractedWithSwipeControl) + // { + // lastInteractedWithSwipeControl.CloseIfNotRemainOpenExecuteItem(); + // } + + // s_lastInteractedWithSwipeControl = get_weak(); + + // if (var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks()) + // { + // globalTestHooks.NotifyLastInteractedWithSwipeControlChanged(); + // } + // } + + // float value = 0.0f; + + // if (m_isHorizontal) + // { + // value = args.Position().x; + // if (!m_blockNearContent && m_createdContent != CreatedContent.Left && value < -c_epsilon) + // { + // CreateLeftContent(); + // } + // else if (!m_blockFarContent && m_createdContent != CreatedContent.Right && value > c_epsilon) + // { + // CreateRightContent(); + // } + // } + // else + // { + // value = args.Position().y; + // if (!m_blockNearContent && m_createdContent != CreatedContent.Top && value < -c_epsilon) + // { + // CreateTopContent(); + // } + // else if (!m_blockFarContent && m_createdContent != CreatedContent.Bottom && value > c_epsilon) + // { + // CreateBottomContent(); + // } + // } + + // UpdateThresholdReached(value); + //} + #endregion + + #region TestHookHelpers + internal static SwipeControl GetLastInteractedWithSwipeControl() + { + if (s_lastInteractedWithSwipeControl.TryGetTarget(out var lastInteractedWithSwipeControl)) + { + return lastInteractedWithSwipeControl; + } + return null; + } + + internal bool GetIsOpen() + { + return m_isOpen; + } + + internal bool GetIsIdle() + { + return m_isIdle; + } + #endregion + + private void OnLeftItemsCollectionChanged(DependencyPropertyChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (args.OldValue is { }) + { + var observableVector = args.NewValue as IObservableVector; + observableVector.VectorChanged -= OnLeftItemsChanged; + } + + if (args.NewValue is {}) + { + ThrowIfHasVerticalAndHorizontalContent(); + var observableVector = args.NewValue as IObservableVector; + observableVector.VectorChanged += OnLeftItemsChanged; + } + + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasLeftContentPropertyName, args.NewValue is {} && (args.NewValue as IObservableVector).Count > 0); + } + + if (m_createdContent == CreatedContent.Left) + { + CreateLeftContent(); + } + } + + private void OnRightItemsCollectionChanged(DependencyPropertyChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (args.OldValue is {}) + { + var observableVector = args.OldValue as IObservableVector; + observableVector.VectorChanged -= OnRightItemsChanged; + } + + if (args.NewValue is {}) + { + ThrowIfHasVerticalAndHorizontalContent(); + var observableVector = args.NewValue as IObservableVector; + observableVector.VectorChanged += OnRightItemsChanged; + } + + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasRightContentPropertyName, args.NewValue is {} && (args.NewValue as IObservableVector).Count > 0); + } + + if (m_createdContent == CreatedContent.Right) + { + CreateRightContent(); + } + } + + private void OnTopItemsCollectionChanged(DependencyPropertyChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (args.OldValue is {}) + { + var observableVector = args.OldValue as IObservableVector; + observableVector.VectorChanged -= OnTopItemsChanged; + } + + if (args.NewValue is {}) + { + ThrowIfHasVerticalAndHorizontalContent(); + var observableVector = args.NewValue as IObservableVector; + observableVector.VectorChanged += OnTopItemsChanged; + } + + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasTopContentPropertyName, args.NewValue is {} && (args.NewValue as IObservableVector).Count > 0); + } + + if (m_createdContent == CreatedContent.Top) + { + CreateTopContent(); + } + } + + private void OnBottomItemsCollectionChanged(DependencyPropertyChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (args.OldValue is {}) + { + var observableVector = args.OldValue as IObservableVector; + observableVector.VectorChanged -= OnBottomItemsChanged; + } + + if (args.NewValue is {}) + { + ThrowIfHasVerticalAndHorizontalContent(); + var observableVector = args.NewValue as IObservableVector; + observableVector.VectorChanged += OnBottomItemsChanged; + } + + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasBottomContentPropertyName, args.NewValue is {} && (args.NewValue as IObservableVector).Count > 0); + } + + if (m_createdContent == CreatedContent.Bottom) + { + CreateBottomContent(); + } + } + + private void OnLoaded(object sender, RoutedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (!m_hasInitialLoadedEventFired) + { + m_hasInitialLoadedEventFired = true; + InitializeInteractionTracker(); + TryGetSwipeVisuals(); + } + + //If the swipe control has been added to the tree for a subsequent time, for instance when a list view item has been recycled, + //Ensure that we are in the closed interaction tracker state. + CloseWithoutAnimation(); + } + + private void AttachEventHandlers() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + //global::System.Diagnostics.Debug.Assert(m_loadedToken.value == 0); + Loaded += OnLoaded; + m_hasInitialLoadedEventFired = false; + + //global::System.Diagnostics.Debug.Assert(m_onSizeChangedToken.value == 0); + SizeChanged += OnSizeChanged; + + //global::System.Diagnostics.Debug.Assert(m_onSwipeContentStackPanelSizeChangedToken.value == 0); + m_swipeContentStackPanel.SizeChanged += OnSwipeContentStackPanelSizeChanged; + + // also get any action from any inside button, or a clickable/tappable control + if (m_onPointerPressedEventHandler is null) + { + m_onPointerPressedEventHandler = OnPointerPressedEvent; + AddHandler(UIElement.PointerPressedEvent, m_onPointerPressedEventHandler, true); + } + + //global::System.Diagnostics.Debug.Assert(m_inputEaterTappedToken.value == 0); + m_inputEater.Tapped += InputEaterGridTapped; + } + + private void DetachEventHandlers() + { + SWIPECONTROL_TRACE_INFO(null/*, TRACE_MSG_METH, METH_NAME, this*/); + + Loaded -= OnLoaded; + + SizeChanged -= OnSizeChanged; + + m_swipeContentStackPanel.SizeChanged -= OnSwipeContentStackPanelSizeChanged; + + if (m_onPointerPressedEventHandler is {}) + { + RemoveHandler(UIElement.PointerPressedEvent, m_onPointerPressedEventHandler); + m_onPointerPressedEventHandler = null; + } + + if (m_inputEater is {}) + { + m_inputEater.Tapped -= InputEaterGridTapped; + } + + DetachDismissingHandlers(); + } + + private void OnSizeChanged(object sender, SizeChangedEventArgs args) + { + EnsureClip(); + foreach (var uiElement in m_swipeContentStackPanel.GetChildren()) + { + AppBarButton appBarButton = uiElement as AppBarButton; + if (appBarButton is {}) + { + if (m_isHorizontal) + { + appBarButton.Height = ActualHeight; + if (m_currentItems is {} && m_currentItems.Mode == SwipeMode.Execute) + { + appBarButton.Width = ActualWidth; + } + } + else + { + appBarButton.Width = ActualWidth; + if (m_currentItems is {} && m_currentItems.Mode == SwipeMode.Execute) + { + appBarButton.Height = ActualHeight; + } + } + } + } + } + + private void OnSwipeContentStackPanelSizeChanged(object sender, SizeChangedEventArgs args) + { + if (m_interactionTracker is {}) + { + m_interactionTracker.MinPosition = new Vector3( + (float)-args.NewSize.Width, (float)-args.NewSize.Height, 0.0f + ); + m_interactionTracker.MaxPosition = new Vector3( + (float)args.NewSize.Width, (float)args.NewSize.Height, 0.0f + ); + ConfigurePositionInertiaRestingValues(); + } + } + + private void OnPointerPressedEvent( + object sender, + PointerRoutedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (args.Pointer.PointerDeviceType == Devices.Input.PointerDeviceType.Touch && m_visualInteractionSource is {}) + { + if (m_currentItems is {} && + m_currentItems.Mode == SwipeMode.Execute && + m_currentItems.Size > 0 && + m_currentItems.GetAt(0).BehaviorOnInvoked == SwipeBehaviorOnInvoked.RemainOpen && + m_isOpen) + { + //If the swipe control is currently open on an Execute item's who's behaviorOnInvoked property is set to RemainOpen + //we don't want to allow the user interaction to effect the swipe control anymore, so don't redirect the manipulation + //to the interaction tracker. + return; + } + + //try + { + m_visualInteractionSource.TryRedirectForManipulation(args.GetCurrentPoint(this)); + } + //catch (Exception e) + //{ + // // Swallowing Access Denied error because of InteractionTracker bug 17434718 which has been + // // causing crashes at least in RS3, RS4 and RS5. + // if (e.to_abi() != E_ACCESSDENIED) + // { + // throw; + // } + //} + } + } + + private void InputEaterGridTapped(object sender, TappedRoutedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_isOpen) + { + CloseIfNotRemainOpenExecuteItem(); + args.Handled = true; + } + } + + private void AttachDismissingHandlers() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + DetachDismissingHandlers(); + + //if (UIElement10 uiElement10 = this) + //{ + var xamlRoot = this.XamlRoot; + if (xamlRoot is {}) + { + if (xamlRoot.Content is {} xamlRootContent) + { + var handler = new PointerEventHandler((_, args) => + { + DismissSwipeOnAnExternalTap(args.GetCurrentPoint(null).Position); + }); + xamlRootContent.AddHandler(PointerPressedEvent, handler, true); + m_xamlRootPointerPressedEventRevoker = Disposable.Create(() => xamlRootContent.RemoveHandler(PointerPressedEvent, handler)); + + var keyHandler = new KeyEventHandler((_, arg) => + { + CloseIfNotRemainOpenExecuteItem(); + }); + xamlRootContent.AddHandler(KeyDownEvent, handler, true); + m_xamlRootKeyDownEventRevoker = Disposable.Create(() => xamlRootContent.RemoveHandler(PointerPressedEvent, handler)); + } + + xamlRoot.Changed += CurrentXamlRootChanged; + m_xamlRootChangedRevoker = Disposable.Create(() => xamlRoot.Changed -= CurrentXamlRootChanged); + } + //} + //else + //{ + // if (var currentWindow = Window.Current()) + // { + // if (var coreWindow = currentWindow.CoreWindow()) + // { + // m_coreWindowPointerPressedRevoker = coreWindow.PointerPressed(auto_revoke, { + // this, DismissSwipeOnAnExternalCoreWindowTap + // }); + // m_coreWindowKeyDownRevoker = coreWindow.KeyDown(auto_revoke, { + // this, DismissSwipeOnCoreWindowKeyDown + // }); + // m_windowMinimizeRevoker = coreWindow.VisibilityChanged(auto_revoke, { + // this, CurrentWindowVisibilityChanged + // }); + // m_windowSizeChangedRevoker = currentWindow.SizeChanged(auto_revoke, { + // this, CurrentWindowSizeChanged + // }); + // } + // } + //} + + if (CoreWindow.GetForCurrentThread() is {} coreWindow) + { + if (coreWindow.Dispatcher is {} dispatcher) + { + dispatcher.AcceleratorKeyActivated += DismissSwipeOnAcceleratorKeyActivator; + m_acceleratorKeyActivatedRevoker = Disposable.Create(() => dispatcher.AcceleratorKeyActivated -= DismissSwipeOnAcceleratorKeyActivator); + } + } + } + + private void DetachDismissingHandlers() + { + SWIPECONTROL_TRACE_INFO(null/*, TRACE_MSG_METH, METH_NAME, this*/); + + m_xamlRootPointerPressedEventRevoker?.Dispose(); + m_xamlRootKeyDownEventRevoker?.Dispose(); + m_xamlRootChangedRevoker?.Dispose(); + + m_acceleratorKeyActivatedRevoker?.Dispose(); + m_coreWindowPointerPressedRevoker?.Dispose(); + m_coreWindowKeyDownRevoker?.Dispose(); + m_windowMinimizeRevoker?.Dispose(); + m_windowSizeChangedRevoker?.Dispose(); + } + + private void DismissSwipeOnAcceleratorKeyActivator(Windows.UI.Core.CoreDispatcher sender, AcceleratorKeyEventArgs args) + { + CloseIfNotRemainOpenExecuteItem(); + } + + private void CurrentXamlRootChanged(XamlRoot sender, XamlRootChangedEventArgs args) + { + CloseIfNotRemainOpenExecuteItem(); + } + + private void DismissSwipeOnCoreWindowKeyDown(CoreWindow sender, KeyEventArgs args) + { + CloseIfNotRemainOpenExecuteItem(); + } + + private void CurrentWindowSizeChanged(DependencyObject sender, WindowSizeChangedEventArgs args) + { + CloseIfNotRemainOpenExecuteItem(); + } + + private void CurrentWindowVisibilityChanged(CoreWindow sender, VisibilityChangedEventArgs args) + { + CloseIfNotRemainOpenExecuteItem(); + } + + private void DismissSwipeOnAnExternalCoreWindowTap(CoreWindow sender, PointerEventArgs args) + { + DismissSwipeOnAnExternalTap(args.CurrentPoint.RawPosition); + } + + private void DismissSwipeOnAnExternalTap(Point tapPoint) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + GeneralTransform transform = TransformToVisual(null); + Point p = Point.Zero; + + // start of the swipe control + var transformedElementOrigin = transform.TransformPoint(p); + + // If point is not within the item's bounds, close it. + if (tapPoint.X < transformedElementOrigin.X || tapPoint.Y < transformedElementOrigin.Y || + (tapPoint.X - transformedElementOrigin.X) > ActualWidth || + (tapPoint.Y - transformedElementOrigin.Y) > ActualHeight) + { + CloseIfNotRemainOpenExecuteItem(); + } + } + + private void GetTemplateParts() + { + m_rootGrid = GetTemplateChild(s_rootGridName); + m_inputEater = GetTemplateChild(s_inputEaterName); + m_content = GetTemplateChild(s_ContentRootName); + m_swipeContentRoot = GetTemplateChild(s_swipeContentRootName); + m_swipeContentStackPanel = GetTemplateChild(s_swipeContentStackPanelName); + + //Before RS5 these elements were not in the template but were instead created in code behind when the swipe content was created. + //Post RS5 the code behind expects these elements to always be in the tree. + if (m_swipeContentRoot is null) + { + Grid swipeContentRoot = new Grid(); + swipeContentRoot.Name = "SwipeContentRoot"; + m_swipeContentRoot = swipeContentRoot; + m_rootGrid.Children.Insert(0, swipeContentRoot); + } + + if (m_swipeContentStackPanel is null) + { + StackPanel swipeContentStackPanel = new StackPanel(); + swipeContentStackPanel.Name("SwipeContentStackPanel"); + m_swipeContentStackPanel = swipeContentStackPanel; + m_swipeContentRoot.Children.Add(swipeContentStackPanel); + } + + m_swipeContentStackPanel.Orientation(m_isHorizontal ? Orientation.Horizontal : Orientation.Vertical); + + var lookedUpStyle = SharedHelpers.FindInApplicationResources(s_swipeItemStyleName, null); + if (lookedUpStyle is {}) + { + m_swipeItemStyle = lookedUpStyle as UI.Xaml.Style; + } + } + + //* Uno workaround: Animation are not yet supported by composition API, we are using XAML animation instead. + //void InitializeInteractionTracker() + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // IInteractionTrackerOwner interactionTrackerOwner = this; + + // if (!m_compositor) + // { + // m_compositor.set(ElementCompositionPreview.GetElementVisual(m_rootGrid).Compositor()); + // } + + // m_visualInteractionSource.set(VisualInteractionSource.Create(FindVisualInteractionSourceVisual())); + // m_visualInteractionSource.IsPositionXRailsEnabled(m_isHorizontal); + // m_visualInteractionSource.IsPositionYRailsEnabled(!m_isHorizontal); + // m_visualInteractionSource.ManipulationRedirectionMode(VisualInteractionSourceRedirectionMode.CapableTouchpadOnly); + // m_visualInteractionSource.PositionXSourceMode(m_isHorizontal ? InteractionSourceMode.EnabledWithInertia : InteractionSourceMode.Disabled); + // m_visualInteractionSource.PositionYSourceMode(!m_isHorizontal ? InteractionSourceMode.EnabledWithInertia : InteractionSourceMode.Disabled); + // if (m_isHorizontal) + // { + // m_visualInteractionSource.PositionXChainingMode(InteractionChainingMode.Never); + // } + // else + // { + // m_visualInteractionSource.PositionYChainingMode(InteractionChainingMode.Never); + // } + + // m_interactionTracker.set(InteractionTracker.CreateWithOwner(m_compositor, interactionTrackerOwner)); + // m_interactionTracker.InteractionSources().Add(m_visualInteractionSource); + // m_interactionTracker.Properties.InsertBoolean(s_isFarOpenPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_isNearOpenPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_blockNearContentPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_blockFarContentPropertyName, false); + // m_interactionTracker.Properties.InsertBoolean(s_hasLeftContentPropertyName, LeftItems() && LeftItems().Size() > 0); + // m_interactionTracker.Properties.InsertBoolean(s_hasRightContentPropertyName, RightItems() && RightItems().Size() > 0); + // m_interactionTracker.Properties.InsertBoolean(s_hasTopContentPropertyName, TopItems() && TopItems().Size() > 0); + // m_interactionTracker.Properties.InsertBoolean(s_hasBottomContentPropertyName, BottomItems() && BottomItems().Size() > 0); + // m_interactionTracker.MaxPosition({ + // std.numeric_limits.infinity(), std.numeric_limits.infinity(), 0.0f + // }); + // m_interactionTracker.MinPosition({ + // -1.0f * std.numeric_limits.infinity(), -1.0f * std.numeric_limits.infinity(), 0.0f + // }); + + // // Create and initialize the Swipe animations: + // // If the swipe control is already opened it should not be possible to open the opposite side's items, without first closing the swipe control. + // // This prevents the user from flicking the swipe control closed and accidently opening the other due to inertia. + // // To acheive this we insert the isFarOpen and isNearOpen boolean properties on the interaction tracker and alter the expression output based on these. + // // The opened state is maintained in the interaction trackers IdleStateEntered handler, this means we need to ensure this state is entered each time the swipe control + // // is opened or closed. + + // // A more readable version of the expression: + + // /m_swipeAnimation.set(m_compositor.CreateExpressionAnimation("isHorizontal ?" + // "Vector3(tracker.isFarOpen || tracker.blockNearContent ? Clamp(-tracker.Position.X, -this.Target.Size.X, 0) :" + // "tracker.isNearOpen || tracker.blockFarContent ? Clamp(-tracker.Position.X, 0, this.Target.Size.X) :" + // "Clamp(-tracker.Position.X, (tracker.hasRightContent ? -10000 : 0), (tracker.hasLeftContent ? 10000 : 0)), 0, 0) :" + // "Vector3(0, tracker.isFarOpen || tracker.blockNearContent ? Clamp(-tracker.Position.Y, -this.Target.Size.Y, 0) :" + // "tracker.isNearOpen || tracker.blockFarContent ? Clamp(-tracker.Position.Y, 0, this.Target.Size.Y) :" + // "Clamp(-tracker.Position.Y, (tracker.hasBottomContent ? -10000 : 0), (tracker.hasTopContent ? 10000 : 0)), 0)")); + // */ + + // m_swipeAnimation.set(m_compositor.CreateExpressionAnimation(isHorizontalPropertyName() + " ?" + // "Vector3(" + trackerPropertyName() + "." + isFarOpenPropertyName() + " || " + trackerPropertyName() + "." + blockNearContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.X, -this.Target.Size.X, 0) :" + // + trackerPropertyName() + "." + isNearOpenPropertyName() + " || " + trackerPropertyName() + "." + blockFarContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.X, 0, this.Target.Size.X) :" + // "Clamp(-" + trackerPropertyName() + ".Position.X, (" + trackerPropertyName() + "." + hasRightContentPropertyName() + " ? -10000 : 0), (" + trackerPropertyName() + "." + hasLeftContentPropertyName() + " ? 10000 : 0)), 0, 0) :" + // "Vector3(0, " + trackerPropertyName() + "." + isFarOpenPropertyName() + " || " + trackerPropertyName() + "." + blockNearContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.Y, -this.Target.Size.Y, 0) :" + // + trackerPropertyName() + "." + isNearOpenPropertyName() + " || " + trackerPropertyName() + "." + blockFarContentPropertyName() + " ? Clamp(-" + trackerPropertyName() + ".Position.Y, 0, this.Target.Size.Y) :" + // "Clamp(-" + trackerPropertyName() + ".Position.Y, (" + trackerPropertyName() + "." + hasBottomContentPropertyName() + " ? -10000 : 0), (" + trackerPropertyName() + "." + hasTopContentPropertyName() + " ? 10000 : 0)), 0)")); + + // m_swipeAnimation.SetReferenceParameter(s_trackerPropertyName, m_interactionTracker); + // m_swipeAnimation.SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); + // if (IsTranslationFacadeAvailableForSwipeControl(m_content)) + // { + // m_swipeAnimation.Target(s_translationPropertyName); + // } + + // //A more readable version of the expression: + + // /m_executeExpressionAnimation.set(m_compositor.CreateExpressionAnimation("(foregroundVisual." + GetAnimationTarget() + " * 0.5) + (isHorizontal ?" + // "Vector3((isNearContent ? -0.5, 0.5) * this.Target.Size.X, 0, 0) : " + // "Vector3(0, (isNearContent ? -0.5, 0.5) * this.Target.Size.Y, 0))")); + // */ + + // m_executeExpressionAnimation.set(m_compositor.CreateExpressionAnimation("(" + foregroundVisualPropertyName() + "." + GetAnimationTarget(m_swipeContentStackPanel) + " * 0.5) + (" + isHorizontalPropertyName() + " ? " + // "Vector3((" + isNearContentPropertyName() + " ? -0.5 : 0.5) * this.Target.Size.X, 0, 0) : " + // "Vector3(0, (" + isNearContentPropertyName() + " ? -0.5 : 0.5) * this.Target.Size.Y, 0))")); + + // m_executeExpressionAnimation.SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); + // if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel)) + // { + // m_executeExpressionAnimation.Target(s_translationPropertyName); + // } + + // //A more readable version of the expression: + + // /m_clipExpressionAnimation.set(m_compositor.CreateExpressionAnimation(L"isHorizontal ? + // Max(swipeRootVisual.Size.X + (isNearContent ? tracker.Position.X : -tracker.Position.X), 0) : + // Max(swipeRootVisual.Size.Y + (isNearContent ? tracker.Position.Y : -tracker.Position.Y), 0)"));*/ + + // m_clipExpressionAnimation.set(m_compositor.CreateExpressionAnimation(isHorizontalPropertyName() + " ? " + // "Max(" + swipeRootVisualPropertyName() + ".Size.X + (" + isNearContentPropertyName() + " ? " + trackerPropertyName() + ".Position.X : -" + trackerPropertyName() + ".Position.X) , 0) : " + // "Max(" + swipeRootVisualPropertyName() + ".Size.Y + (" + isNearContentPropertyName() + " ? " + trackerPropertyName() + ".Position.Y : -" + trackerPropertyName() + ".Position.Y) , 0)")); + + // m_clipExpressionAnimation.SetReferenceParameter(s_trackerPropertyName, m_interactionTracker); + // m_clipExpressionAnimation.SetBooleanParameter(s_isHorizontalPropertyName, m_isHorizontal); + //} + + //void ConfigurePositionInertiaRestingValues() + //{ + // SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + // if (m_isHorizontal) + // { + // IVector xModifiers = new Vector(); + + // ExpressionAnimation leftCondition = m_compositor.CreateExpressionAnimation("this.Target." + hasLeftContentPropertyName() + " && !this.Target." + isFarOpenPropertyName() + " && this.Target.NaturalRestingPosition.x <= -1 * (this.Target." + isNearOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); + // leftCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualWidth)); + // leftCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); + // ExpressionAnimation leftRestingPoint = m_compositor.CreateExpressionAnimation("-" + swipeContentSizeParameterName()); + // leftRestingPoint.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualWidth)); + // InteractionTrackerInertiaRestingValue leftOpen = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // leftOpen.Condition(leftCondition); + // leftOpen.RestingValue(leftRestingPoint); + // xModifiers.Append(leftOpen); + + // ExpressionAnimation rightCondition = m_compositor.CreateExpressionAnimation("this.Target." + hasRightContentPropertyName() + " && !this.Target." + isNearOpenPropertyName() + " && this.Target.NaturalRestingPosition.x >= (this.Target." + isFarOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); + // rightCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualWidth)); + // rightCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); + // ExpressionAnimation rightRestingValue = m_compositor.CreateExpressionAnimation(s_swipeContentSizeParameterName); + // rightRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualWidth)); + // InteractionTrackerInertiaRestingValue rightOpen = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // rightOpen.Condition(rightCondition); + // rightOpen.RestingValue(rightRestingValue); + // xModifiers.Append(rightOpen); + + // ExpressionAnimation condition = m_compositor.CreateExpressionAnimation("true"); + // ExpressionAnimation restingValue = m_compositor.CreateExpressionAnimation("0"); + // InteractionTrackerInertiaRestingValue neutralX = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // neutralX.Condition(condition); + // neutralX.RestingValue(restingValue); + // xModifiers.Append(neutralX); + + // m_interactionTracker.ConfigurePositionXInertiaModifiers(xModifiers); + // } + // else + // { + // IVector yModifiers = new Vector(); + + // ExpressionAnimation topCondition = m_compositor.CreateExpressionAnimation("this.Target." + hasTopContentPropertyName() + " && !this.Target." + isFarOpenPropertyName() + " && this.Target.NaturalRestingPosition.y <= -1 * (this.Target." + isNearOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); + // topCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualHeight)); + // topCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); + // ExpressionAnimation topRestingValue = m_compositor.CreateExpressionAnimation("-" + swipeContentSizeParameterName()); + // topRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualHeight)); + // InteractionTrackerInertiaRestingValue topOpen = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // topOpen.Condition(topCondition); + // topOpen.RestingValue(topRestingValue); + // yModifiers.Append(topOpen); + + // ExpressionAnimation bottomCondition = m_compositor.CreateExpressionAnimation("this.Target." + hasBottomContentPropertyName() + " && !this.Target." + isNearOpenPropertyName() + " && this.Target.NaturalRestingPosition.y >= (this.Target." + isFarOpenPropertyName() + " ? " + swipeContentSizeParameterName() + " : min(" + swipeContentSizeParameterName() + ", " + maxThresholdPropertyName() + "))"); + // bottomCondition.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualHeight)); + // bottomCondition.SetScalarParameter(s_maxThresholdPropertyName, c_ThresholdValue); + // ExpressionAnimation bottomRestingValue = m_compositor.CreateExpressionAnimation(s_swipeContentSizeParameterName); + // bottomRestingValue.SetScalarParameter(s_swipeContentSizeParameterName, (float)(m_swipeContentStackPanel.ActualHeight)); + // InteractionTrackerInertiaRestingValue bottomOpen = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // bottomOpen.Condition(bottomCondition); + // bottomOpen.RestingValue(bottomRestingValue); + // yModifiers.Append(bottomOpen); + + // ExpressionAnimation condition = m_compositor.CreateExpressionAnimation("true"); + // ExpressionAnimation restingValue = m_compositor.CreateExpressionAnimation("0"); + // InteractionTrackerInertiaRestingValue neutralY = InteractionTrackerInertiaRestingValue.Create(m_compositor); + // neutralY.Condition(condition); + // neutralY.RestingValue(restingValue); + // yModifiers.Append(neutralY); + + // m_interactionTracker.ConfigurePositionYInertiaModifiers(yModifiers); + // } + //} + + //Visual FindVisualInteractionSourceVisual() + //{ + // Visual visualInteractionSource = null; + + // // Don't walk up the tree too far largely as an optimization for when SwipeControl isn't used + // // with a list. The general-case when using swipe with a ListView will probably have the + // // LVIP as the visual parent of the SwipeControl but enabling checking for a few more + // // levels above that could enable more complex list item templates where SwipeControl + // // isn't the root element. + // int maxSteps = 5; + // int steps = 0; + // var current = VisualTreeHelper.GetParent(this); + // while (current && steps < maxSteps) + // { + // if (var lvip = current.try_as()) + // { + // visualInteractionSource = ElementCompositionPreview.GetElementVisual(lvip); + // break; + // } + + // current = VisualTreeHelper.GetParent(current); + // ++steps; + // } + + // if (!visualInteractionSource) + // { + // visualInteractionSource = ElementCompositionPreview.GetElementVisual(this); + // } + + // return visualInteractionSource; + //} + + private void EnsureClip() + { + float width = (float)(ActualWidth); + float height = (float)(ActualHeight); + Rect rect = new Rect(0.0f, 0.0f, width, height); + Windows.UI.Xaml.Media.RectangleGeometry rectangleGeometry = new RectangleGeometry(); + rectangleGeometry.Rect = rect; + Clip = rectangleGeometry; + } + + private void CloseWithoutAnimation() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + bool wasIdle = m_isIdle; + m_interactionTracker.TryUpdatePosition(new Vector3( + 0.0f, 0.0f, 0.0f + )); + if (wasIdle) + { + IdleStateEntered(null, null); + } + } + + private void CloseIfNotRemainOpenExecuteItem() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_currentItems is {} && + m_currentItems.Mode == SwipeMode.Execute && + m_currentItems.Size > 0 && + m_currentItems.GetAt(0).BehaviorOnInvoked == SwipeBehaviorOnInvoked.RemainOpen && + m_isOpen) + { + //If we have a Mode set to Execute, and an item with BehaviorOnInvoked set to RemainOpen, we do not want to close, so no-op + return; + } + + Close(); + } + + private void CreateLeftContent() + { + var items = LeftItems; + if (items is {}) + { + m_createdContent = CreatedContent.Left; + CreateContent(items); + } + } + + private void CreateRightContent() + { + var items = RightItems; + if (items is {}) + { + m_createdContent = CreatedContent.Right; + CreateContent(items); + } + } + + private void CreateBottomContent() + { + var items = BottomItems; + if (items is { }) + { + m_createdContent = CreatedContent.Bottom; + CreateContent(items); + } + } + + private void CreateTopContent() + { + var items = TopItems; + if (items is { }) + { + m_createdContent = CreatedContent.Top; + CreateContent(items); + } + } + + private void CreateContent(SwipeItems items) + { + if (m_swipeContentStackPanel is {} && m_swipeContentStackPanel.Children is {}) + { + m_swipeContentStackPanel.Children.Clear(); + } + + m_currentItems = items; + if (m_currentItems is {}) + { + AlignStackPanel(); + PopulateContentItems(); + SetupExecuteExpressionAnimation(); + SetupClipAnimation(); + UpdateColors(); + } + } + + private void AlignStackPanel() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_currentItems.Size > 0) + { + switch (m_currentItems.Mode) + { + case SwipeMode.Execute: + { + if (m_isHorizontal) + { + m_swipeContentStackPanel.HorizontalAlignment = HorizontalAlignment.Stretch; + m_swipeContentStackPanel.VerticalAlignment = VerticalAlignment.Center; + } + else + { + m_swipeContentStackPanel.HorizontalAlignment = HorizontalAlignment.Center; + m_swipeContentStackPanel.VerticalAlignment = VerticalAlignment.Stretch; + } + + break; + } + case SwipeMode.Reveal: + { + if (m_isHorizontal) + { + var swipeContentStackPanelHorizontalAlignment = m_createdContent == CreatedContent.Left ? HorizontalAlignment.Left : + m_createdContent == CreatedContent.Right ? HorizontalAlignment.Right : + HorizontalAlignment.Stretch; + + m_swipeContentStackPanel.HorizontalAlignment = swipeContentStackPanelHorizontalAlignment; + m_swipeContentStackPanel.VerticalAlignment = VerticalAlignment.Center; + } + else + { + var swipeContentStackPanelVerticalAlignment = m_createdContent == CreatedContent.Top ? VerticalAlignment.Top : + m_createdContent == CreatedContent.Bottom ? VerticalAlignment.Bottom : + VerticalAlignment.Stretch; + + m_swipeContentStackPanel.HorizontalAlignment = HorizontalAlignment.Center; + m_swipeContentStackPanel.VerticalAlignment = swipeContentStackPanelVerticalAlignment; + } + + break; + } + default: + global::System.Diagnostics.Debug.Assert(false); + break; + } + } + } + + private void PopulateContentItems() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + foreach (var swipeItem in m_currentItems) + { + m_swipeContentStackPanel.Children.Add(GetSwipeItemButton(swipeItem)); + } + + TryGetSwipeVisuals(); + } + + private void SetupExecuteExpressionAnimation() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel)) + { + m_swipeContentStackPanel.StopAnimation(m_executeExpressionAnimation); + m_swipeContentStackPanel.Translation = new Vector3( + 0.0f, 0.0f, 0.0f + ); + } + else if (m_swipeContentVisual is { }) + { + m_swipeContentVisual.StopAnimation(GetAnimationTarget(m_swipeContentStackPanel)); + m_swipeContentVisual.Properties.InsertVector3(GetAnimationTarget(m_swipeContentStackPanel), new Vector3( + 0.0f, 0.0f, 0.0f + )); + } + + if (m_currentItems.Mode == SwipeMode.Execute) + { + global::System.Diagnostics.Debug.Assert((m_createdContent != CreatedContent.None)); + m_executeExpressionAnimation.SetBooleanParameter(s_isNearContentPropertyName, m_createdContent == CreatedContent.Left || m_createdContent == CreatedContent.Top); + if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel)) + { + m_swipeContentStackPanel.StartAnimation(m_executeExpressionAnimation); + } + + if (m_swipeContentVisual is {}) + { + m_swipeContentVisual.StartAnimation(GetAnimationTarget(m_swipeContentStackPanel), m_executeExpressionAnimation); + } + } + } + + private void SetupClipAnimation() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_insetClip is null) + { + m_insetClip = m_compositor.CreateInsetClip(); + m_swipeContentRootVisual.Clip = m_insetClip; + } + else + { + m_insetClip.StopAnimation(s_leftInsetTargetName); + m_insetClip.StopAnimation(s_rightInsetTargetName); + m_insetClip.StopAnimation(s_topInsetTargetName); + m_insetClip.StopAnimation(s_bottomInsetTargetName); + m_insetClip.LeftInset = 0.0f; + m_insetClip.RightInset = 0.0f; + m_insetClip.TopInset = 0.0f; + m_insetClip.BottomInset = 0.0f; + } + + m_clipExpressionAnimation.SetBooleanParameter(s_isNearContentPropertyName, m_createdContent == CreatedContent.Left || m_createdContent == CreatedContent.Top); + + if (m_createdContent == CreatedContent.None) + { + //If we have no created content then we don't need to start the clip animation yet. + return; + } + + m_insetClip.StartAnimation(DirectionToInset(m_createdContent), m_clipExpressionAnimation); + } + + private void UpdateColors() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_currentItems.Mode == SwipeMode.Execute) + { + UpdateColorsIfExecuteItem(); + } + else + { + UpdateColorsIfRevealItems(); + } + } + + AppBarButton GetSwipeItemButton(SwipeItem swipeItem) + { + AppBarButton itemAsButton = new AppBarButton(); + swipeItem.GenerateControl(itemAsButton, m_swipeItemStyle); + + if (swipeItem.Background is null) + { + var lookedUpBrush = SharedHelpers.FindInApplicationResources(m_currentItems.Mode == SwipeMode.Reveal ? s_swipeItemBackgroundResourceName : m_thresholdReached ? s_executeSwipeItemPostThresholdBackgroundResourceName : s_executeSwipeItemPreThresholdBackgroundResourceName); + if (lookedUpBrush is {}) + { + itemAsButton.Background = lookedUpBrush as Brush; + } + } + + if (swipeItem.Foreground is null) + { + var lookedUpBrush = SharedHelpers.FindInApplicationResources(m_currentItems.Mode == SwipeMode.Reveal ? s_swipeItemForegroundResourceName : m_thresholdReached ? s_executeSwipeItemPostThresholdForegroundResourceName : s_executeSwipeItemPreThresholdForegroundResourceName); + if (lookedUpBrush is {}) + { + itemAsButton.Foreground = lookedUpBrush as Brush; + } + } + + if (m_isHorizontal) + { + itemAsButton.Height = ActualHeight; + if (m_currentItems.Mode == SwipeMode.Execute) + { + itemAsButton.Width = ActualWidth; + } + } + else + { + itemAsButton.Width = (ActualWidth); + if (m_currentItems.Mode == SwipeMode.Execute) + { + itemAsButton.Height = (ActualHeight); + } + } + + return itemAsButton; + } + + private void UpdateColorsIfExecuteItem() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_currentItems is null || m_currentItems.Mode != SwipeMode.Execute) + { + return; + } + + SwipeItem swipeItem = null; + if (m_currentItems.Size > 0) + { + swipeItem = m_currentItems.GetAt(0); + } + + UpdateExecuteBackgroundColor(swipeItem); + UpdateExecuteForegroundColor(swipeItem); + } + + private void UpdateExecuteBackgroundColor(SwipeItem swipeItem) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + Brush background = null; + + if (!m_thresholdReached) + { + var lookedUpBackgroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPreThresholdBackgroundResourceName); + if (lookedUpBackgroundBrush is {}) + { + background = lookedUpBackgroundBrush as Brush; + } + } + else + { + var lookedUpBackgroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPostThresholdBackgroundResourceName); + if (lookedUpBackgroundBrush is { }) + { + background = lookedUpBackgroundBrush as Brush; + } + } + + if (swipeItem is {} && swipeItem.Background is {}) + { + background = swipeItem.Background; + } + + m_swipeContentStackPanel.Background = background; + m_swipeContentRoot.Background = null; + } + + private void UpdateExecuteForegroundColor(SwipeItem swipeItem) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_swipeContentStackPanel.Children.Count > 0) + { + if (m_swipeContentStackPanel.Children[0] is AppBarButton appBarButton) + { + Brush foreground = null; + + if (!m_thresholdReached) + { + var lookedUpForegroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPreThresholdForegroundResourceName); + if (lookedUpForegroundBrush is {}) + { + foreground = lookedUpForegroundBrush as Brush; + } + } + else + { + var lookedUpForegroundBrush = SharedHelpers.FindInApplicationResources(s_executeSwipeItemPostThresholdForegroundResourceName); + if (lookedUpForegroundBrush is { }) + { + foreground = lookedUpForegroundBrush as Brush; + } + } + + if (swipeItem is {} && swipeItem.Foreground is {}) + { + foreground = swipeItem.Foreground; + } + + appBarButton.Foreground = foreground; + appBarButton.Background = new SolidColorBrush(Colors.Transparent); + } + } + } + + private void UpdateColorsIfRevealItems() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (m_currentItems.Mode != SwipeMode.Reveal) + { + return; + } + + Brush rootGridBackground = null; + + var lookedUpBrush = SharedHelpers.FindInApplicationResources(s_swipeItemBackgroundResourceName); + if (lookedUpBrush is {}) + { + rootGridBackground = lookedUpBrush as Brush; + } + if (m_currentItems.Size > 0) + { + switch (m_createdContent) + { + case CreatedContent.Left: + case CreatedContent.Top: + { + var itemBackground = m_currentItems.GetAt((uint)m_swipeContentStackPanel.Children.Count - 1).Background; + if (itemBackground != null) + { + rootGridBackground = itemBackground; + } + + break; + } + case CreatedContent.Right: + case CreatedContent.Bottom: + { + var itemBackground = m_currentItems.GetAt(0).Background; + if (itemBackground != null) + { + rootGridBackground = itemBackground; + } + + break; + } + case CreatedContent.None: + { + break; + } + default: + global::System.Diagnostics.Debug.Assert(false); + break; + } + } + + m_swipeContentRoot.Background = rootGridBackground; + m_swipeContentStackPanel.Background = null; + } + + private void OnLeftItemsChanged(IObservableVector sender, IVectorChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + ThrowIfHasVerticalAndHorizontalContent(); + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasLeftContentPropertyName, sender.Count > 0); + } + + if (m_createdContent == CreatedContent.Left) + { + CreateLeftContent(); + } + } + + private void OnRightItemsChanged(IObservableVector sender, IVectorChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + ThrowIfHasVerticalAndHorizontalContent(); + + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasRightContentPropertyName, sender.Count > 0); + } + + if (m_createdContent == CreatedContent.Right) + { + CreateRightContent(); + } + } + + private void OnTopItemsChanged(IObservableVector sender, IVectorChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + ThrowIfHasVerticalAndHorizontalContent(); + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasTopContentPropertyName, sender.Count > 0); + } + + if (m_createdContent == CreatedContent.Top) + { + CreateTopContent(); + } + } + + private void OnBottomItemsChanged(IObservableVector sender, IVectorChangedEventArgs args) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + ThrowIfHasVerticalAndHorizontalContent(); + if (m_interactionTracker is {}) + { + m_interactionTracker.Properties.InsertBoolean(s_hasBottomContentPropertyName, sender.Count > 0); + } + + if (m_createdContent == CreatedContent.Bottom) + { + CreateBottomContent(); + } + } + + private void TryGetSwipeVisuals() + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (IsTranslationFacadeAvailableForSwipeControl(m_content)) + { + m_swipeAnimation.Target = GetAnimationTarget(m_content); + m_content.StartAnimation(m_swipeAnimation); + } + else + { + var mainContentVisual = ElementCompositionPreview.GetElementVisual(m_content); + if (mainContentVisual is {} && m_mainContentVisual != mainContentVisual) + { + m_mainContentVisual = mainContentVisual; + + if (DownlevelHelper.SetIsTranslationEnabledExists()) + { + ElementCompositionPreview.SetIsTranslationEnabled(m_content, true); + mainContentVisual.Properties.InsertVector3(s_translationPropertyName, new Vector3( + 0.0f, 0.0f, 0.0f + )); + } + + mainContentVisual.StartAnimation(GetAnimationTarget(m_content), m_swipeAnimation); + + m_executeExpressionAnimation.SetReferenceParameter(s_foregroundVisualPropertyName, mainContentVisual); + } + } + + if (IsTranslationFacadeAvailableForSwipeControl(m_swipeContentStackPanel)) + { + m_swipeAnimation.Target = GetAnimationTarget(m_swipeContentStackPanel); + } + else + { + var swipeContentVisual = ElementCompositionPreview.GetElementVisual(m_swipeContentStackPanel); + if (swipeContentVisual is {} && m_swipeContentVisual != swipeContentVisual) + { + m_swipeContentVisual = swipeContentVisual; + + if (DownlevelHelper.SetIsTranslationEnabledExists()) + { + ElementCompositionPreview.SetIsTranslationEnabled(m_swipeContentStackPanel, true); + swipeContentVisual.Properties.InsertVector3(s_translationPropertyName, new Vector3( + 0.0f, 0.0f, 0.0f + )); + } + + ConfigurePositionInertiaRestingValues(); + } + } + + var swipeContentRootVisual = ElementCompositionPreview.GetElementVisual(m_swipeContentRoot); + if (swipeContentRootVisual is {} && m_swipeContentRootVisual != swipeContentRootVisual) + { + m_swipeContentRootVisual = swipeContentRootVisual; + m_clipExpressionAnimation.SetReferenceParameter(s_swipeRootVisualPropertyName, swipeContentRootVisual); + if (m_insetClip is {}) + { + swipeContentRootVisual.Clip = m_insetClip; + } + } + } + + private void UpdateIsOpen(bool isOpen) + { + SWIPECONTROL_TRACE_INFO(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + if (isOpen) + { + if (!m_isOpen) + { + m_isOpen = true; + m_lastActionWasOpening = true; + switch (m_createdContent) + { + case CreatedContent.Right: + case CreatedContent.Bottom: + m_interactionTracker.Properties.InsertBoolean(s_isFarOpenPropertyName, true); + m_interactionTracker.Properties.InsertBoolean(s_isNearOpenPropertyName, false); + break; + case CreatedContent.Left: + case CreatedContent.Top: + m_interactionTracker.Properties.InsertBoolean(s_isFarOpenPropertyName, false); + m_interactionTracker.Properties.InsertBoolean(s_isNearOpenPropertyName, true); + break; + case CreatedContent.None: + m_interactionTracker.Properties.InsertBoolean(s_isFarOpenPropertyName, false); + m_interactionTracker.Properties.InsertBoolean(s_isNearOpenPropertyName, false); + break; + default: + global::System.Diagnostics.Debug.Assert(false); + break; + } + + if (m_currentItems.Mode != SwipeMode.Execute) + { + AttachDismissingHandlers(); + } + + var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks(); + if (globalTestHooks is {}) + { + globalTestHooks.NotifyOpenedStatusChanged(this); + } + } + } + else + { + if (m_isOpen) + { + m_isOpen = false; + m_lastActionWasClosing = true; + DetachDismissingHandlers(); + m_interactionTracker.Properties.InsertBoolean(s_isFarOpenPropertyName, false); + m_interactionTracker.Properties.InsertBoolean(s_isNearOpenPropertyName, false); + + var globalTestHooks = SwipeTestHooks.GetGlobalTestHooks(); + if (globalTestHooks is { }) + { + globalTestHooks.NotifyOpenedStatusChanged(this); + } + } + } + } + + private void UpdateThresholdReached(float value) + { + SWIPECONTROL_TRACE_VERBOSE(this/*, TRACE_MSG_METH, METH_NAME, this*/); + + bool oldValue = m_thresholdReached; + float effectiveStackPanelSize = (float)((m_isHorizontal ? m_swipeContentStackPanel.ActualWidth : m_swipeContentStackPanel.ActualHeight) - 1); + if (!m_isOpen || m_lastActionWasOpening) + { + //If we are opening new swipe items then we need to scroll open c_ThresholdValue + m_thresholdReached = Math.Abs(value) > Math.Min(effectiveStackPanelSize, c_ThresholdValue); + } + else + { + //If we already have an open swipe item then swiping it closed by any amount will close it. + m_thresholdReached = Math.Abs(value) < effectiveStackPanelSize; + } + + if (m_thresholdReached != oldValue) + { + UpdateColorsIfExecuteItem(); + } + } + + private void ThrowIfHasVerticalAndHorizontalContent(bool setIsHorizontal = false) + { + bool hasLeftContent = LeftItems is {} && LeftItems.Size > 0; + bool hasRightContent = RightItems is { } && RightItems.Size > 0; + bool hasTopContent = TopItems is { } && TopItems.Size > 0; + bool hasBottomContent = BottomItems is { } && BottomItems.Size > 0; + if (setIsHorizontal) + { + m_isHorizontal = hasLeftContent || hasRightContent || !(hasTopContent || hasBottomContent); + } + + if (this.Template is {}) + { + if (m_isHorizontal && (hasTopContent || hasBottomContent)) + { + throw new ArgumentException("This SwipeControl is horizontal and can not have vertical items."); + } + + if (!m_isHorizontal && (hasLeftContent || hasRightContent)) + { + throw new ArgumentException("This SwipeControl is vertical and can not have horizontal items."); + } + } + else + { + if ((hasLeftContent || hasRightContent) && (hasTopContent || hasBottomContent)) + { + throw new ArgumentException("SwipeControl can't have both horizontal items and vertical items set at the same time."); + } + } + } + + private string GetAnimationTarget(UIElement child) + { + if (DownlevelHelper.SetIsTranslationEnabledExists() || SharedHelpers.IsTranslationFacadeAvailable(child)) + { + return s_translationPropertyName; + } + else + { + return s_offsetPropertyName; + } + } + + private SwipeControl GetThis() + { + return this; + } + + private bool IsTranslationFacadeAvailableForSwipeControl(UIElement element) + { + //For now Facade's are causing more issues than they are worth for swipe control. Revist this + //when we have a little more time. + + //There are concerns about swipe consumers having taken a dependency on the ElementCompositionPreview + //Api's that this is exclusive with and also the target property of the swipe expression animations + //is not resolving with the use of Facade's + return false; + //return SharedHelpers.IsTranslationFacadeAvailable(element); + } + + private string DirectionToInset(CreatedContent createdContent) + { + switch (createdContent) + { + case CreatedContent.Right: + return s_leftInsetTargetName; + case CreatedContent.Left: + return s_rightInsetTargetName; + case CreatedContent.Bottom: + return s_topInsetTargetName; + case CreatedContent.Top: + return s_bottomInsetTargetName; + case CreatedContent.None: + return ""; + default: + global::System.Diagnostics.Debug.Assert(false); + return ""; + } + } } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.h.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.h.cs index 6f9a71448e86..b7ea77b7adbe 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.h.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.h.cs @@ -1,272 +1,292 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. +using System; +using Windows.UI.Composition; +using Windows.UI.Composition.Interactions; +using Windows.UI.Xaml.Input; + #pragma once namespace Windows.UI.Xaml.Controls { public partial class SwipeControl { + private enum CreatedContent { Left, Top, Bottom, Right, None }; - enum class CreatedContent { Left, Top, Bottom, Right, None }; + //class SwipeControl : + // public ReferenceTracker>, + // public SwipeControlProperties + //{ + //public: + // SwipeControl(); + // virtual ~SwipeControl(); -class SwipeControl : - public ReferenceTracker>, - public SwipeControlProperties -{ -public: - SwipeControl(); - virtual ~SwipeControl(); + //#pragma region ISwipeControl + + + // void Close(); + + //#pragma endregion + + //#pragma region FrameworkElementOverrides + // void OnApplyTemplate(); + + // void OnPropertyChanged( winrt.DependencyPropertyChangedEventArgs& args); + // winrt.Size MeasureOverride(winrt.Size & availableSize); + //#pragma endregion + + //#pragma region IInteractionTrackerOwner + // void CustomAnimationStateEntered( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerCustomAnimationStateEnteredArgs & args); + + // void RequestIgnored( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerRequestIgnoredArgs & args); + + // void IdleStateEntered( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerIdleStateEnteredArgs & args); + + // void InteractingStateEntered( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerInteractingStateEnteredArgs & args); + + // void InertiaStateEntered( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerInertiaStateEnteredArgs & args); + + // void ValuesChanged( + // winrt.InteractionTracker & sender, + // winrt.InteractionTrackerValuesChangedArgs & args); + //#pragma endregion + + // winrt.SwipeItems GetCurrentItems() { return m_currentItems.get(); } + + //#pragma region TestHookHelpers + // static winrt.SwipeControl GetLastInteractedWithSwipeControl(); + // bool GetIsOpen(); + // bool GetIsIdle(); + //#pragma endregion + + //private: + // void OnLeftItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); + // void OnRightItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); + // void OnBottomItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); + // void OnTopItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); + // void OnLoaded( winrt.DependencyObject& /sender/, winrt.RoutedEventArgs& /args/); + + // void AttachEventHandlers(); + // void DetachEventHandlers(); + // void OnSizeChanged( winrt.DependencyObject& sender, winrt.SizeChangedEventArgs& args); + // void OnSwipeContentStackPanelSizeChanged( winrt.DependencyObject& sender, winrt.SizeChangedEventArgs& args); + // void OnPointerPressedEvent( winrt.DependencyObject& sender, winrt.PointerRoutedEventArgs& args); + // void InputEaterGridTapped( winrt.DependencyObject& /sender/, winrt.TappedRoutedEventArgs& args); + + // void AttachDismissingHandlers(); + // void DetachDismissingHandlers(); + // void DismissSwipeOnAcceleratorKeyActivator( winrt.Windows.UI.Core.CoreDispatcher & sender, winrt.AcceleratorKeyEventArgs & args); + + // // Used on platforms where we have XamlRoot. + // void CurrentXamlRootChanged( winrt.XamlRoot & sender, winrt.XamlRootChangedEventArgs & args); + + + // // Used on platforms where we don't have XamlRoot. + // void DismissSwipeOnCoreWindowKeyDown( winrt.CoreWindow & sender, winrt.KeyEventArgs & args); + // void CurrentWindowSizeChanged( winrt.DependencyObject & sender, winrt.WindowSizeChangedEventArgs& args); + // void CurrentWindowVisibilityChanged( winrt.CoreWindow & sender, winrt.VisibilityChangedEventArgs args); + // void DismissSwipeOnAnExternalCoreWindowTap( winrt.CoreWindow& sender, winrt.PointerEventArgs& args); + + // void DismissSwipeOnAnExternalTap(winrt.Point & tapPoint); + + // void GetTemplateParts(); + + // void InitializeInteractionTracker(); + // void ConfigurePositionInertiaRestingValues(); + + // winrt.Visual FindVisualInteractionSourceVisual(); + // void EnsureClip(); + + // void CloseWithoutAnimation(); + // void CloseIfNotRemainOpenExecuteItem(); + + // void CreateLeftContent(); + // void CreateRightContent(); + // void CreateTopContent(); + // void CreateBottomContent(); + // void CreateContent( winrt.SwipeItems& items); + + // void AlignStackPanel(); + // void PopulateContentItems(); + // void SetupExecuteExpressionAnimation(); + // void SetupClipAnimation(); + // void UpdateColors(); + + // winrt.AppBarButton GetSwipeItemButton( winrt.SwipeItem& swipeItem); + // void UpdateColorsIfExecuteItem(); + // void UpdateColorsIfRevealItems(); + // void UpdateExecuteForegroundColor( winrt.SwipeItem& swipeItem); + // void UpdateExecuteBackgroundColor( winrt.SwipeItem& swipeItem); + + // void OnLeftItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); + // void OnRightItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); + // void OnTopItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); + // void OnBottomItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); + + // void TryGetSwipeVisuals(); + // void UpdateIsOpen(bool isOpen); + // void UpdateThresholdReached(float value); + + // void ThrowIfHasVerticalAndHorizontalContent(bool IsHorizontal = false); + + // std.string GetAnimationTarget(winrt.UIElement child); + + // winrt.SwipeControl GetThis(); + + private Grid m_rootGrid; + private Grid m_content; + private Grid m_inputEater; + private Grid m_swipeContentRoot; + private StackPanel m_swipeContentStackPanel; + + private InteractionTracker m_interactionTracker; + private VisualInteractionSource m_visualInteractionSource; + private Compositor m_compositor; + + private Visual m_mainContentVisual; + private Visual m_swipeContentRootVisual; + private Visual m_swipeContentVisual; + private InsetClip m_insetClip; + + private ExpressionAnimation m_swipeAnimation; + private ExpressionAnimation m_executeExpressionAnimation; + private ExpressionAnimation m_clipExpressionAnimation; + private ExpressionAnimation m_maxPositionExpressionAnimation; + private ExpressionAnimation m_minPositionExpressionAnimation; + + private Style m_swipeItemStyle; + + // Cache the current content object to minimize work if there are multiple swipes in the same direction. + private SwipeItems m_currentItems; + + //private IDisposable m_loadedToken; + + //private IDisposable m_leftItemsChangedToken; + //private IDisposable m_rightItemsChangedToken; + //private IDisposable m_topItemsChangedToken; + //private IDisposable m_bottomItemsChangedToken; + //private IDisposable m_onSizeChangedToken; + private IDisposable m_onSwipeContentStackPanelSizeChangedToken; + //private IDisposable m_inputEaterTappedToken; + private PointerEventHandler m_onPointerPressedEventHandler; + + // Used on platforms where we have XamlRoot. + private IDisposable m_xamlRootPointerPressedEventRevoker; + private IDisposable m_xamlRootKeyDownEventRevoker; + private IDisposable m_xamlRootChangedRevoker; + + + // Used on platforms where we don't have XamlRoot. + private IDisposable m_coreWindowPointerPressedRevoker; + private IDisposable m_coreWindowKeyDownRevoker; + private IDisposable m_windowMinimizeRevoker; + private IDisposable m_windowSizeChangedRevoker; + + private IDisposable m_acceleratorKeyActivatedRevoker; + + private bool m_hasInitialLoadedEventFired = false; + + private bool m_lastActionWasClosing = false; + private bool m_lastActionWasOpening = false; + private bool m_isInteracting = false; + private bool m_isIdle = true; + private bool m_isOpen = false; + + private bool m_thresholdReached = false; + + //Near content = left or top + //Far content = right or bottom + private bool m_blockNearContent = false; + private bool m_blockFarContent = false; + private bool m_isHorizontal = true; + private CreatedContent m_createdContent = CreatedContent.None; + + //static bool IsTranslationFacadeAvailableForSwipeControl(winrt.UIElement& element); + //static string DirectionToInset(CreatedContent& createdContent); + + private const string s_isNearOpenPropertyName = "isNearOpen"; + private static string isNearOpenPropertyName() { return s_isNearOpenPropertyName; } + + private const string s_isFarOpenPropertyName = "isFarOpen"; + private static string isFarOpenPropertyName() { return s_isFarOpenPropertyName; } -#pragma region ISwipeControl + private const string s_isNearContentPropertyName = "isNearContent"; + private static string isNearContentPropertyName() { return s_isNearContentPropertyName; } + private const string s_blockNearContentPropertyName = "blockNearContent"; + private static string blockNearContentPropertyName() { return s_blockNearContentPropertyName; } - void Close(); + private const string s_blockFarContentPropertyName = "blockFarContent"; + private static string blockFarContentPropertyName() { return s_blockFarContentPropertyName; } -#pragma endregion + private const string s_hasLeftContentPropertyName = "hasLeftContent"; + private static string hasLeftContentPropertyName() { return s_hasLeftContentPropertyName; } -#pragma region FrameworkElementOverrides - void OnApplyTemplate(); + private const string s_hasRightContentPropertyName = "hasRightContent"; + private static string hasRightContentPropertyName() { return s_hasRightContentPropertyName; } - void OnPropertyChanged( winrt.DependencyPropertyChangedEventArgs& args); - winrt.Size MeasureOverride(winrt.Size & availableSize); -#pragma endregion + private const string s_hasTopContentPropertyName = "hasTopContent"; + private static string hasTopContentPropertyName() { return s_hasTopContentPropertyName; } -#pragma region IInteractionTrackerOwner - void CustomAnimationStateEntered( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerCustomAnimationStateEnteredArgs & args); + private const string s_hasBottomContentPropertyName = "hasBottomContent"; + private static string hasBottomContentPropertyName() { return s_hasBottomContentPropertyName; } - void RequestIgnored( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerRequestIgnoredArgs & args); + private const string s_isHorizontalPropertyName = "isHorizontal"; + private static string isHorizontalPropertyName() { return s_isHorizontalPropertyName; } - void IdleStateEntered( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerIdleStateEnteredArgs & args); + private const string s_trackerPropertyName = "tracker"; + private static string trackerPropertyName() { return s_trackerPropertyName; } - void InteractingStateEntered( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerInteractingStateEnteredArgs & args); + private const string s_foregroundVisualPropertyName = "foregroundVisual"; + private static string foregroundVisualPropertyName() { return s_foregroundVisualPropertyName; } - void InertiaStateEntered( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerInertiaStateEnteredArgs & args); + private const string s_swipeContentVisualPropertyName = "swipeContentVisual"; + private static string swipeContentVisualPropertyName() { return s_swipeContentVisualPropertyName; } - void ValuesChanged( - winrt.InteractionTracker & sender, - winrt.InteractionTrackerValuesChangedArgs & args); -#pragma endregion + private const string s_swipeContentSizeParameterName = "swipeContentVisual"; + private static string swipeContentSizeParameterName() { return s_swipeContentSizeParameterName; } - winrt.SwipeItems GetCurrentItems() { return m_currentItems.get(); } + private const string s_swipeRootVisualPropertyName = "swipeRootVisual"; + private static string swipeRootVisualPropertyName() { return s_swipeRootVisualPropertyName; } -#pragma region TestHookHelpers - static winrt.SwipeControl GetLastInteractedWithSwipeControl(); - bool GetIsOpen(); - bool GetIsIdle(); -#pragma endregion + private const string s_maxThresholdPropertyName = "maxThreshold"; + private static string maxThresholdPropertyName() { return s_maxThresholdPropertyName; } -private: - void OnLeftItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); - void OnRightItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); - void OnBottomItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); - void OnTopItemsCollectionChanged( winrt.DependencyPropertyChangedEventArgs& /args/); - void OnLoaded( winrt.DependencyObject& /sender/, winrt.RoutedEventArgs& /args/); + private const string s_minPositionPropertyName = "minPosition"; + private const string s_maxPositionPropertyName = "maxPosition"; - void AttachEventHandlers(); - void DetachEventHandlers(); - void OnSizeChanged( winrt.DependencyObject& sender, winrt.SizeChangedEventArgs& args); - void OnSwipeContentStackPanelSizeChanged( winrt.DependencyObject& sender, winrt.SizeChangedEventArgs& args); - void OnPointerPressedEvent( winrt.DependencyObject& sender, winrt.PointerRoutedEventArgs& args); - void InputEaterGridTapped( winrt.DependencyObject& /sender/, winrt.TappedRoutedEventArgs& args); - - void AttachDismissingHandlers(); - void DetachDismissingHandlers(); - void DismissSwipeOnAcceleratorKeyActivator( winrt.Windows.UI.Core.CoreDispatcher & sender, winrt.AcceleratorKeyEventArgs & args); + private const string s_leftInsetTargetName = "LeftInset"; + private const string s_rightInsetTargetName = "RightInset"; + private const string s_topInsetTargetName = "TopInset"; + private const string s_bottomInsetTargetName = "BottomInset"; - // Used on platforms where we have XamlRoot. - void CurrentXamlRootChanged( winrt.XamlRoot & sender, winrt.XamlRootChangedEventArgs & args); - + private const string s_translationPropertyName = "Translation"; + private const string s_offsetPropertyName = "Offset"; - // Used on platforms where we don't have XamlRoot. - void DismissSwipeOnCoreWindowKeyDown( winrt.CoreWindow & sender, winrt.KeyEventArgs & args); - void CurrentWindowSizeChanged( winrt.DependencyObject & sender, winrt.WindowSizeChangedEventArgs& args); - void CurrentWindowVisibilityChanged( winrt.CoreWindow & sender, winrt.VisibilityChangedEventArgs args); - void DismissSwipeOnAnExternalCoreWindowTap( winrt.CoreWindow& sender, winrt.PointerEventArgs& args); + private const string s_rootGridName = "RootGrid"; + private const string s_inputEaterName = "InputEater"; + private const string s_ContentRootName = "ContentRoot"; + private const string s_swipeContentRootName = "SwipeContentRoot"; + private const string s_swipeContentStackPanelName = "SwipeContentStackPanel"; + private const string s_swipeItemStyleName = "SwipeItemStyle"; - void DismissSwipeOnAnExternalTap(winrt.Point & tapPoint); - void GetTemplateParts(); - - void InitializeInteractionTracker(); - void ConfigurePositionInertiaRestingValues(); - - winrt.Visual FindVisualInteractionSourceVisual(); - void EnsureClip(); - - void CloseWithoutAnimation(); - void CloseIfNotRemainOpenExecuteItem(); - - void CreateLeftContent(); - void CreateRightContent(); - void CreateTopContent(); - void CreateBottomContent(); - void CreateContent( winrt.SwipeItems& items); - - void AlignStackPanel(); - void PopulateContentItems(); - void SetupExecuteExpressionAnimation(); - void SetupClipAnimation(); - void UpdateColors(); - - winrt.AppBarButton GetSwipeItemButton( winrt.SwipeItem& swipeItem); - void UpdateColorsIfExecuteItem(); - void UpdateColorsIfRevealItems(); - void UpdateExecuteForegroundColor( winrt.SwipeItem& swipeItem); - void UpdateExecuteBackgroundColor( winrt.SwipeItem& swipeItem); - - void OnLeftItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); - void OnRightItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); - void OnTopItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); - void OnBottomItemsChanged( winrt.IObservableVector& sender, winrt.IVectorChangedEventArgs args); - - void TryGetSwipeVisuals(); - void UpdateIsOpen(bool isOpen); - void UpdateThresholdReached(float value); - - void ThrowIfHasVerticalAndHorizontalContent(bool IsHorizontal = false); - - std.string GetAnimationTarget(winrt.UIElement child); - - winrt.SwipeControl GetThis(); - - tracker_ref m_rootGrid{ this }; - tracker_ref m_content{ this }; - tracker_ref m_inputEater{ this }; - tracker_ref m_swipeContentRoot{ this }; - tracker_ref m_swipeContentStackPanel{ this }; - - tracker_ref m_interactionTracker{ this }; - tracker_ref m_visualInteractionSource{ this }; - tracker_ref m_compositor{ this }; - - tracker_ref m_mainContentVisual{ this }; - tracker_ref m_swipeContentRootVisual{ this }; - tracker_ref m_swipeContentVisual{ this }; - tracker_ref m_insetClip{ this }; - - tracker_ref m_swipeAnimation{ this }; - tracker_ref m_executeExpressionAnimation{ this }; - tracker_ref m_clipExpressionAnimation{ this }; - tracker_ref m_maxPositionExpressionAnimation{ this }; - tracker_ref m_minPositionExpressionAnimation{ this }; - - tracker_ref m_swipeItemStyle{ this }; - - // Cache the current content object to minimize work if there are multiple swipes in the same direction. - tracker_ref m_currentItems{ this }; - - winrt.event_token m_loadedToken{}; - winrt.event_token m_leftItemsChangedToken{}; - winrt.event_token m_rightItemsChangedToken{}; - winrt.event_token m_topItemsChangedToken{}; - winrt.event_token m_bottomItemsChangedToken{}; - winrt.event_token m_onSizeChangedToken{}; - winrt.event_token m_onSwipeContentStackPanelSizeChangedToken{}; - winrt.event_token m_inputEaterTappedToken{}; - tracker_ref m_onPointerPressedEventHandler{ this }; - - // Used on platforms where we have XamlRoot. - RoutedEventHandler_revoker m_xamlRootPointerPressedEventRevoker{}; - RoutedEventHandler_revoker m_xamlRootKeyDownEventRevoker{}; - winrt.IXamlRoot.Changed_revoker m_xamlRootChangedRevoker{}; - - - // Used on platforms where we don't have XamlRoot. - winrt.ICoreWindow.PointerPressed_revoker m_coreWindowPointerPressedRevoker; - winrt.ICoreWindow.KeyDown_revoker m_coreWindowKeyDownRevoker; - winrt.ICoreWindow.VisibilityChanged_revoker m_windowMinimizeRevoker; - winrt.IWindow.SizeChanged_revoker m_windowSizeChangedRevoker; - - winrt.CoreAcceleratorKeys.AcceleratorKeyActivated_revoker m_acceleratorKeyActivatedRevoker; - - bool m_hasInitialLoadedEventFired{ false }; - - bool m_lastActionWasClosing{ false }; - bool m_lastActionWasOpening{ false }; - bool m_isInteracting{ false }; - bool m_isIdle{ true }; - bool m_isOpen{ false }; - bool m_thresholdReached{ false }; - //Near content = left or top - //Far content = right or bottom - bool m_blockNearContent{ false }; - bool m_blockFarContent{ false }; - bool m_isHorizontal{ true }; - CreatedContent m_createdContent{ CreatedContent.None }; - - static bool IsTranslationFacadeAvailableForSwipeControl( winrt.UIElement& element); - static wstring_view DirectionToInset( CreatedContent& createdContent); - - static wstring_view s_isNearOpenPropertyName{ "isNearOpen"sv }; - static inline std.string isNearOpenPropertyName() { return s_isNearOpenPropertyName.data(); } - static wstring_view s_isFarOpenPropertyName{ "isFarOpen"sv }; - static inline std.string isFarOpenPropertyName() { return s_isFarOpenPropertyName.data(); } - static wstring_view s_isNearContentPropertyName{ "isNearContent"sv }; - static inline std.string isNearContentPropertyName() { return s_isNearContentPropertyName.data(); } - static wstring_view s_blockNearContentPropertyName{ "blockNearContent"sv }; - static inline std.string blockNearContentPropertyName() { return s_blockNearContentPropertyName.data(); } - static wstring_view s_blockFarContentPropertyName{ "blockFarContent"sv }; - static inline std.string blockFarContentPropertyName() { return s_blockFarContentPropertyName.data(); } - - static wstring_view s_hasLeftContentPropertyName{ "hasLeftContent"sv }; - static inline std.string hasLeftContentPropertyName() { return s_hasLeftContentPropertyName.data(); } - static wstring_view s_hasRightContentPropertyName{ "hasRightContent"sv }; - static inline std.string hasRightContentPropertyName() { return s_hasRightContentPropertyName.data(); } - static wstring_view s_hasTopContentPropertyName{ "hasTopContent"sv }; - static inline std.string hasTopContentPropertyName() { return s_hasTopContentPropertyName.data(); } - static wstring_view s_hasBottomContentPropertyName{ "hasBottomContent"sv }; - static inline std.string hasBottomContentPropertyName() { return s_hasBottomContentPropertyName.data(); } - static wstring_view s_isHorizontalPropertyName{ "isHorizontal"sv }; - static inline std.string isHorizontalPropertyName() { return s_isHorizontalPropertyName.data(); } - - static wstring_view s_trackerPropertyName{ "tracker"sv }; - static inline std.string trackerPropertyName() { return s_trackerPropertyName.data(); } - static wstring_view s_foregroundVisualPropertyName{ "foregroundVisual"sv }; - static inline std.string foregroundVisualPropertyName() { return s_foregroundVisualPropertyName.data(); } - static wstring_view s_swipeContentVisualPropertyName{ "swipeContentVisual"sv }; - static inline std.string swipeContentVisualPropertyName() { return s_swipeContentVisualPropertyName.data(); } - static wstring_view s_swipeContentSizeParameterName{ "swipeContentVisual"sv }; - static inline std.string swipeContentSizeParameterName() { return s_swipeContentSizeParameterName.data(); } - static wstring_view s_swipeRootVisualPropertyName{ "swipeRootVisual"sv }; - static inline std.string swipeRootVisualPropertyName() { return s_swipeRootVisualPropertyName.data(); } - static wstring_view s_maxThresholdPropertyName{ "maxThreshold"sv }; - static inline std.string maxThresholdPropertyName() { return s_maxThresholdPropertyName.data(); } - - static wstring_view s_minPositionPropertyName{ "minPosition"sv }; - static wstring_view s_maxPositionPropertyName{ "maxPosition"sv }; - - static wstring_view s_leftInsetTargetName{ "LeftInset"sv }; - static wstring_view s_rightInsetTargetName{ "RightInset"sv }; - static wstring_view s_topInsetTargetName{ "TopInset"sv }; - static wstring_view s_bottomInsetTargetName{ "BottomInset"sv }; - - static wstring_view s_translationPropertyName{ "Translation"sv }; - static wstring_view s_offsetPropertyName{ "Offset"sv }; - - static wstring_view s_rootGridName{ "RootGrid"sv }; - static wstring_view s_inputEaterName{ "InputEater"sv }; - static wstring_view s_ContentRootName{ "ContentRoot"sv }; - static wstring_view s_swipeContentRootName{ "SwipeContentRoot"sv }; - static wstring_view s_swipeContentStackPanelName{ "SwipeContentStackPanel"sv }; - static wstring_view s_swipeItemStyleName{ "SwipeItemStyle"sv }; - - - static wstring_view s_swipeItemBackgroundResourceName{ "SwipeItemBackground"sv }; - static wstring_view s_swipeItemForegroundResourceName{ "SwipeItemForeground"sv }; - static wstring_view s_executeSwipeItemPreThresholdBackgroundResourceName{ "SwipeItemPreThresholdExecuteBackground"sv }; - static wstring_view s_executeSwipeItemPostThresholdBackgroundResourceName{ "SwipeItemPostThresholdExecuteBackground"sv }; - static wstring_view s_executeSwipeItemPreThresholdForegroundResourceName{ "SwipeItemPreThresholdExecuteForeground"sv }; - static wstring_view s_executeSwipeItemPostThresholdForegroundResourceName{ "SwipeItemPostThresholdExecuteForeground"sv }; -}; -}} + private const string s_swipeItemBackgroundResourceName = "SwipeItemBackground"; + private const string s_swipeItemForegroundResourceName = "SwipeItemForeground"; + private const string s_executeSwipeItemPreThresholdBackgroundResourceName = "SwipeItemPreThresholdExecuteBackground"; + private const string s_executeSwipeItemPostThresholdBackgroundResourceName = "SwipeItemPostThresholdExecuteBackground"; + private const string s_executeSwipeItemPreThresholdForegroundResourceName = "SwipeItemPreThresholdExecuteForeground"; + private const string s_executeSwipeItemPostThresholdForegroundResourceName = "SwipeItemPostThresholdExecuteForeground"; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.cs index 3a767ddf386a..111eada2b2bb 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.cs @@ -8,153 +8,190 @@ namespace Windows.UI.Xaml.Controls public partial class SwipeControl { - GlobalDependencyProperty SwipeControlProperties.s_BottomItemsProperty{ null }; -GlobalDependencyProperty SwipeControlProperties.s_LeftItemsProperty{ null }; -GlobalDependencyProperty SwipeControlProperties.s_RightItemsProperty{ null }; -GlobalDependencyProperty SwipeControlProperties.s_TopItemsProperty{ null }; - -SwipeControlProperties.SwipeControlProperties() -{ - EnsureProperties(); -} - -void SwipeControlProperties.EnsureProperties() -{ - if (!s_BottomItemsProperty) - { - s_BottomItemsProperty = - InitializeDependencyProperty( - "BottomItems", - winrt.name_of(), - winrt.name_of(), - false /* isAttached */, - ValueHelper.BoxedDefaultValue(), - winrt.PropertyChangedCallback(&OnBottomItemsPropertyChanged)); - } - if (!s_LeftItemsProperty) - { - s_LeftItemsProperty = - InitializeDependencyProperty( - "LeftItems", - winrt.name_of(), - winrt.name_of(), - false /* isAttached */, - ValueHelper.BoxedDefaultValue(), - winrt.PropertyChangedCallback(&OnLeftItemsPropertyChanged)); - } - if (!s_RightItemsProperty) - { - s_RightItemsProperty = - InitializeDependencyProperty( - "RightItems", - winrt.name_of(), - winrt.name_of(), - false /* isAttached */, - ValueHelper.BoxedDefaultValue(), - winrt.PropertyChangedCallback(&OnRightItemsPropertyChanged)); - } - if (!s_TopItemsProperty) - { - s_TopItemsProperty = - InitializeDependencyProperty( - "TopItems", - winrt.name_of(), - winrt.name_of(), - false /* isAttached */, - ValueHelper.BoxedDefaultValue(), - winrt.PropertyChangedCallback(&OnTopItemsPropertyChanged)); - } -} - -void SwipeControlProperties.ClearProperties() -{ - s_BottomItemsProperty = null; - s_LeftItemsProperty = null; - s_RightItemsProperty = null; - s_TopItemsProperty = null; -} - -void SwipeControlProperties.OnBottomItemsPropertyChanged( - winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args) -{ - var owner = sender.as(); - winrt.get_self(owner).OnPropertyChanged(args); -} - -void SwipeControlProperties.OnLeftItemsPropertyChanged( - winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args) -{ - var owner = sender.as(); - winrt.get_self(owner).OnPropertyChanged(args); -} - -void SwipeControlProperties.OnRightItemsPropertyChanged( - winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args) -{ - var owner = sender.as(); - winrt.get_self(owner).OnPropertyChanged(args); -} - -void SwipeControlProperties.OnTopItemsPropertyChanged( - winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args) -{ - var owner = sender.as(); - winrt.get_self(owner).OnPropertyChanged(args); -} - -void SwipeControlProperties.BottomItems(winrt.SwipeItems & value) -{ - [[gsl.suppress(con)]] - { - (SwipeControl)(this).SetValue(s_BottomItemsProperty, ValueHelper.BoxValueIfNecessary(value)); - } -} - -winrt.SwipeItems SwipeControlProperties.BottomItems() -{ - return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_BottomItemsProperty)); -} - -void SwipeControlProperties.LeftItems(winrt.SwipeItems & value) -{ - [[gsl.suppress(con)]] - { - (SwipeControl)(this).SetValue(s_LeftItemsProperty, ValueHelper.BoxValueIfNecessary(value)); - } -} - -winrt.SwipeItems SwipeControlProperties.LeftItems() -{ - return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_LeftItemsProperty)); -} - -void SwipeControlProperties.RightItems(winrt.SwipeItems & value) -{ - [[gsl.suppress(con)]] - { - (SwipeControl)(this).SetValue(s_RightItemsProperty, ValueHelper.BoxValueIfNecessary(value)); - } -} - -winrt.SwipeItems SwipeControlProperties.RightItems() -{ - return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_RightItemsProperty)); -} - -void SwipeControlProperties.TopItems(winrt.SwipeItems & value) -{ - [[gsl.suppress(con)]] - { - (SwipeControl)(this).SetValue(s_TopItemsProperty, ValueHelper.BoxValueIfNecessary(value)); - } -} - -winrt.SwipeItems SwipeControlProperties.TopItems() -{ - return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_TopItemsProperty)); -} + //GlobalDependencyProperty s_BottomItemsProperty{ null }; + //GlobalDependencyProperty s_LeftItemsProperty{ null }; + //GlobalDependencyProperty s_RightItemsProperty{ null }; + //GlobalDependencyProperty s_TopItemsProperty{ null }; + + //SwipeControlProperties() + //{ + // EnsureProperties(); + //} + + //void EnsureProperties() + //{ + // if (!s_BottomItemsProperty) + // { + // s_BottomItemsProperty = + // InitializeDependencyProperty( + // "BottomItems", + // name_of(), + // name_of(), + // false /* isAttached */, + // ValueHelper.BoxedDefaultValue(), + // PropertyChangedCallback(&OnBottomItemsPropertyChanged)); + // } + // if (!s_LeftItemsProperty) + // { + // s_LeftItemsProperty = + // InitializeDependencyProperty( + // "LeftItems", + // name_of(), + // name_of(), + // false /* isAttached */, + // ValueHelper.BoxedDefaultValue(), + // PropertyChangedCallback(&OnLeftItemsPropertyChanged)); + // } + // if (!s_RightItemsProperty) + // { + // s_RightItemsProperty = + // InitializeDependencyProperty( + // "RightItems", + // name_of(), + // name_of(), + // false /* isAttached */, + // ValueHelper.BoxedDefaultValue(), + // PropertyChangedCallback(&OnRightItemsPropertyChanged)); + // } + // if (!s_TopItemsProperty) + // { + // s_TopItemsProperty = + // InitializeDependencyProperty( + // "TopItems", + // name_of(), + // name_of(), + // false /* isAttached */, + // ValueHelper.BoxedDefaultValue(), + // PropertyChangedCallback(&OnTopItemsPropertyChanged)); + // } + //} + + //void ClearProperties() + //{ + // s_BottomItemsProperty = null; + // s_LeftItemsProperty = null; + // s_RightItemsProperty = null; + // s_TopItemsProperty = null; + //} + + private static void OnBottomItemsPropertyChanged( + DependencyObject sender, + DependencyPropertyChangedEventArgs args) + { + var owner = (SwipeControl)sender; + owner.OnPropertyChanged(args); + } + + private static void OnLeftItemsPropertyChanged( + DependencyObject sender, + DependencyPropertyChangedEventArgs args) + { + var owner = (SwipeControl)sender; + owner.OnPropertyChanged(args); + } + + private static void OnRightItemsPropertyChanged( + DependencyObject sender, + DependencyPropertyChangedEventArgs args) + { + var owner = (SwipeControl)sender; + owner.OnPropertyChanged(args); + } + + private static void OnTopItemsPropertyChanged( + DependencyObject sender, + DependencyPropertyChangedEventArgs args) + { + var owner = (SwipeControl)sender; + owner.OnPropertyChanged(args); + } + + + public static readonly DependencyProperty BottomItemsProperty = DependencyProperty.Register( + "BottomItems", typeof(SwipeItems), typeof(SwipeControl), new PropertyMetadata(default(SwipeItems), OnBottomItemsPropertyChanged)); + + public SwipeItems BottomItems + { + get { return (SwipeItems)GetValue(BottomItemsProperty); } + set { SetValue(BottomItemsProperty, value); } + } + //void BottomItems(SwipeItems & value) + //{ + // [[gsl.suppress(con)]] + // { + // (SwipeControl)(this).SetValue(s_BottomItemsProperty, ValueHelper.BoxValueIfNecessary(value)); + // } + //} + + //SwipeItems BottomItems() + //{ + // return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_BottomItemsProperty)); + //} + + + public static readonly DependencyProperty LeftItemsProperty = DependencyProperty.Register( + "LeftItems", typeof(SwipeItems), typeof(SwipeControl), new PropertyMetadata(default(SwipeItems), OnLeftItemsPropertyChanged)); + + public SwipeItems LeftItems + { + get { return (SwipeItems)GetValue(LeftItemsProperty); } + set { SetValue(LeftItemsProperty, value); } + } + + //void LeftItems(SwipeItems & value) + //{ + // [[gsl.suppress(con)]] + // { + // (SwipeControl)(this).SetValue(s_LeftItemsProperty, ValueHelper.BoxValueIfNecessary(value)); + // } + //} + + //SwipeItems LeftItems() + //{ + // return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_LeftItemsProperty)); + //} + + public static readonly DependencyProperty RightItemsProperty = DependencyProperty.Register( + "RightItems", typeof(SwipeItems), typeof(SwipeControl), new PropertyMetadata(default(SwipeItems), OnRightItemsPropertyChanged)); + + public SwipeItems RightItems + { + get { return (SwipeItems)GetValue(RightItemsProperty); } + set { SetValue(RightItemsProperty, value); } + } + + //void RightItems(SwipeItems & value) + //{ + // [[gsl.suppress(con)]] + // { + // (SwipeControl)(this).SetValue(s_RightItemsProperty, ValueHelper.BoxValueIfNecessary(value)); + // } + //} + + //SwipeItems RightItems() + //{ + // return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_RightItemsProperty)); + //} + + public static readonly DependencyProperty TopItemsProperty = DependencyProperty.Register( + "TopItems", typeof(SwipeItems), typeof(SwipeControl), new PropertyMetadata(default(SwipeItems), OnTopItemsPropertyChanged)); + + public SwipeItems TopItems + { + get { return (SwipeItems)GetValue(TopItemsProperty); } + set { SetValue(TopItemsProperty, value); } + } + + //void TopItems(SwipeItems & value) + //{ + // [[gsl.suppress(con)]] + // { + // (SwipeControl)(this).SetValue(s_TopItemsProperty, ValueHelper.BoxValueIfNecessary(value)); + // } + //} + + //SwipeItems TopItems() + //{ + // return ValueHelper.CastOrUnbox((SwipeControl)(this).GetValue(s_TopItemsProperty)); + //} }} diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.h.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.h.cs index faae801c8739..994b5013573a 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.h.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.properties.h.cs @@ -8,61 +8,61 @@ namespace Windows.UI.Xaml.Controls { public partial class SwipeControl { - public: + //public: - SwipeControlProperties(); + //SwipeControlProperties(); - void BottomItems(winrt.SwipeItems & value); + //void BottomItems(winrt.SwipeItems & value); - winrt.SwipeItems BottomItems(); + //winrt.SwipeItems BottomItems(); - void LeftItems(winrt.SwipeItems & value); + //void LeftItems(winrt.SwipeItems & value); - winrt.SwipeItems LeftItems(); + //winrt.SwipeItems LeftItems(); - void RightItems(winrt.SwipeItems & value); + //void RightItems(winrt.SwipeItems & value); - winrt.SwipeItems RightItems(); + //winrt.SwipeItems RightItems(); - void TopItems(winrt.SwipeItems & value); + //void TopItems(winrt.SwipeItems & value); - winrt.SwipeItems TopItems(); + //winrt.SwipeItems TopItems(); - static winrt.DependencyProperty BottomItemsProperty() { return s_BottomItemsProperty; } + //static winrt.DependencyProperty BottomItemsProperty() { return s_BottomItemsProperty; } - static winrt.DependencyProperty LeftItemsProperty() { return s_LeftItemsProperty; } + //static winrt.DependencyProperty LeftItemsProperty() { return s_LeftItemsProperty; } - static winrt.DependencyProperty RightItemsProperty() { return s_RightItemsProperty; } + //static winrt.DependencyProperty RightItemsProperty() { return s_RightItemsProperty; } - static winrt.DependencyProperty TopItemsProperty() { return s_TopItemsProperty; } + //static winrt.DependencyProperty TopItemsProperty() { return s_TopItemsProperty; } - static GlobalDependencyProperty s_BottomItemsProperty; - static GlobalDependencyProperty s_LeftItemsProperty; - static GlobalDependencyProperty s_RightItemsProperty; - static GlobalDependencyProperty s_TopItemsProperty; + //static GlobalDependencyProperty s_BottomItemsProperty; + //static GlobalDependencyProperty s_LeftItemsProperty; + //static GlobalDependencyProperty s_RightItemsProperty; + //static GlobalDependencyProperty s_TopItemsProperty; - static void EnsureProperties(); + //static void EnsureProperties(); - static void ClearProperties(); + //static void ClearProperties(); - static void OnBottomItemsPropertyChanged( - winrt.DependencyObject & sender, + //static void OnBottomItemsPropertyChanged( + // winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args); + //winrt.DependencyPropertyChangedEventArgs & args); - static void OnLeftItemsPropertyChanged( - winrt.DependencyObject & sender, + //static void OnLeftItemsPropertyChanged( + // winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args); + //winrt.DependencyPropertyChangedEventArgs & args); - static void OnRightItemsPropertyChanged( - winrt.DependencyObject & sender, + //static void OnRightItemsPropertyChanged( + // winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args); + //winrt.DependencyPropertyChangedEventArgs & args); - static void OnTopItemsPropertyChanged( - winrt.DependencyObject & sender, + //static void OnTopItemsPropertyChanged( + // winrt.DependencyObject & sender, - winrt.DependencyPropertyChangedEventArgs & args); - }; + //winrt.DependencyPropertyChangedEventArgs & args); + } } diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItem.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItem.cs index 9ba81cae0041..367c0ad7a071 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItem.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItem.cs @@ -11,7 +11,7 @@ namespace Windows.UI.Xaml.Controls { - public partial class SwipeItem : DependencyObject + public partial class SwipeItem : FrameworkElement { static double s_swipeItemWidth = 68.0; static double s_swipeItemHeight = 60.0; @@ -62,7 +62,7 @@ private void OnCommandChanged(ICommand oldCommand, ICommand newCommand) } } - void GenerateControl(AppBarButton appBarButton, Style swipeItemStyle) + internal void GenerateControl(AppBarButton appBarButton, Style swipeItemStyle) { appBarButton.Style(swipeItemStyle); if (Background is {}) @@ -77,7 +77,8 @@ void GenerateControl(AppBarButton appBarButton, Style swipeItemStyle) if (IconSource is {}) { - appBarButton.Icon = IconSource.CreateIconElement(); + // TODO Uno + //appBarButton.Icon = IconSource.CreateIconElement(); } appBarButton.Label = Text; diff --git a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItems.cs b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItems.cs index 38f74e26326a..d66871c5ec41 100644 --- a/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItems.cs +++ b/src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeItems.cs @@ -10,7 +10,7 @@ namespace Windows.UI.Xaml.Controls { public partial class SwipeItems : DependencyObject, IEnumerable, IList, IObservableVector { - public void SwipeItems() + public SwipeItems() { // create the Collection var collection = new ObservableCollection();