From cd4c24c8a05c8564d99f1bed81ab92087c8eddbb Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Fri, 2 Aug 2024 17:12:41 +0200 Subject: [PATCH] chore: Additional required dependencies --- src/Uno.UI/DirectUI/ElevationHelper.cs | 58 ++++ .../Controls/ComboBox/ComboBox.Properties.cs | 10 +- .../Xaml/Controls/ComboBox/ComboBox.custom.cs | 2 + .../ComboBox/ComboBox.partial.h.mux.cs | 19 +- .../Controls/ComboBox/ComboBox.partial.mux.cs | 293 +++++++++--------- 5 files changed, 236 insertions(+), 146 deletions(-) create mode 100644 src/Uno.UI/DirectUI/ElevationHelper.cs diff --git a/src/Uno.UI/DirectUI/ElevationHelper.cs b/src/Uno.UI/DirectUI/ElevationHelper.cs new file mode 100644 index 000000000000..6dad374409dd --- /dev/null +++ b/src/Uno.UI/DirectUI/ElevationHelper.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +// MUX Reference dxaml\phone\lib\ElevationHelper.cpp, tag winui3/release/1.5.4, commit 98a60c8 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; + +namespace DirectUI; + +internal static class ElevationHelper +{ + //// The initial Z offset applied to all elevated controls + //private const float s_elevationBaseDepth = 32.0f; + //// This additional Z offset will be applied for each tier of logically parented controls + //private const float s_elevationIterativeDepth = 8.0f; + + //internal static void ApplyThemeShadow(UIElement target) + //{ + // var themeShadow = new ThemeShadow(); + // target.Shadow = themeShadow; + //} + + //internal static void ApplyElevationEffect(UIElement target, int depth) + //{ + // // Calculate the Z offset based on the depth of the shadow + // var calculatedZDepth = s_elevationBaseDepth + (depth * s_elevationIterativeDepth); + + // var endTranslation = new Vector3(0.0f, 0.0f, calculatedZDepth); + + // // Apply a translation facade value + // target.Translation = endTranslation; + + // // Apply a shadow to the element + // ApplyThemeShadow(target); + //} + + // Move the control forward in Z and apply a shadow effect to it. + // If the control is part of a tier of elevated controls (for example a MenuFlyoutSubItem), + // you may provide an additional "depth" value that provides an additional Z offset. + internal static void ApplyElevationEffect(UIElement target, int depth = 0, int? baseElevation = null) + { + } + + // Remove any shadow applied with ApplyElevationEffect + internal static void ClearElevationEffect(UIElement target) + { + } + + // Checks if the "IsDefaultShadowEnabled" resource is defined as True or not, determining + // if a control should enable a shadow by default. + internal static bool IsDefaultShadowEnabled(FrameworkElement resourceTarget) => false; +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs index d6826020cde6..962769faaa31 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.Properties.cs @@ -208,11 +208,6 @@ public Style TextBoxStyle typeof(ComboBox), new FrameworkPropertyMetadata(null)); - /// - /// Occurs when the user submits some text that does not correspond to an item in the ComboBox dropdown list. - /// - public event TypedEventHandler TextSubmitted; - /// /// Occurs when the drop-down portion of the ComboBox closes. /// @@ -222,4 +217,9 @@ public Style TextBoxStyle /// Occurs when the drop-down portion of the ComboBox opens. /// public event EventHandler DropDownOpened; + + /// + /// Occurs when the user submits some text that does not correspond to an item in the ComboBox dropdown list. + /// + public event TypedEventHandler TextSubmitted; } diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs index ed510ce04b7c..972ec4db2cc8 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.custom.cs @@ -863,6 +863,8 @@ Point getChildLocation() #endif child.Arrange(frame); + + combo.m_bPopupHasBeenArrangedOnce = true; } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs index f6ae88846714..cebba3e7d777 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.h.mux.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Media.Animation; using Uno.Disposables; using Uno.UI.Xaml.Input; using Windows.Foundation; @@ -12,10 +13,18 @@ namespace Microsoft.UI.Xaml.Controls; partial class ComboBox { +#pragma warning disable CS0067 // Unused only in reference API. +#pragma warning disable CS0649 // Unused only in reference API. +#pragma warning disable CS0169 // Unused only in reference API. +#pragma warning disable CS0168 // Unused only in reference API. +#pragma warning disable CS0414 // Unused only in reference API. internal bool IsSearchResultIndexSet() => m_searchResultIndexSet; internal int GetSearchResultIndex() => m_searchResultIndex; + private bool m_bIsPopupPannable; + private bool m_bShouldCarousel; + private bool m_bShouldCenterSelectedItem; private bool m_handledGamepadOrRemoteKeyDown; private bool m_ignoreCancelKeyDowns; private bool m_isEditModeConfigured; @@ -44,12 +53,18 @@ partial class ComboBox // Editable ComboBox is designed to set the focus on TextBox when ComboBox is focused, there are some cases when we don't want // this behavior eg(Shift+Tab). private bool m_shouldMoveFocusToTextBox; - private bool m_isClosingDueToCancel; + private bool m_isExpanded; + private bool m_isOverlayVisible; private bool m_restoreIndexSet; + private bool m_isClosingDueToCancel; private bool m_IsPointerOverDropDownOverlay; private InputDeviceType m_inputDeviceTypeUsedToOpen; + private InputDeviceType m_previousInputDeviceTypeUsedToOpen; + + private FrameworkElement m_tpElementPopupChild; + private FrameworkElement m_tpElementPopupContent; private readonly SerialDisposable m_spEditableTextPointerPressedEventHandler = new(); private readonly SerialDisposable m_spEditableTextTappedEventHandler = new(); @@ -65,6 +80,7 @@ partial class ComboBox private TextBlock m_tpEditableContentPresenterTextBlock; private ComboBoxItem m_tpSwappedOutComboBoxItem; + private Storyboard m_tpClosedStoryboard; private DependencyObject m_tpGeneratedContainerForContentPresenter; private int m_iLastGeneratedItemIndexforFaceplate; private object m_customValueRef; @@ -78,6 +94,7 @@ partial class ComboBox private bool IsFullMode => IsSmallFormFactor && m_itemCount > s_itemCountThreshold; + private IAsyncInfo m_tpAsyncSelectionInfo; private int m_itemCount; private int m_indexToRestoreOnCancel = -1; diff --git a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs index 9af623800c74..f986b26cb032 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ComboBox/ComboBox.partial.mux.cs @@ -13,6 +13,7 @@ using Uno.UI.Xaml.Input; using Windows.Foundation; using Windows.System; +using static DirectUI.ElevationHelper; namespace Microsoft.UI.Xaml.Controls; @@ -279,162 +280,162 @@ private protected override void ChangeVisualState(bool useTransitions) private void SetContentPresenter(int index, bool forceSelectionBoxToNull = false) { - bool bGeneratedComboBoxItem = false; - DependencyObject spContainer; - DependencyObject spGeneratedComboBoxItemAsDO; - ComboBoxItem? spComboBoxItem; - object? spContent; - DataTemplate spDataTemplate; - DataTemplateSelector spDataTemplateSelector; - GeneratorPosition generatorPosition; + UpdateContentPresenter(); // TODO MZ: This should not happen + return; // TODO MZ: This should not happen - Debug.Assert(!IsInline, "ContentPresenter is not used in inline mode."); + //bool bGeneratedComboBoxItem = false; + //DependencyObject spContainer; + //DependencyObject spGeneratedComboBoxItemAsDO; + //ComboBoxItem? spComboBoxItem; + //object? spContent; + //DataTemplate spDataTemplate; + //DataTemplateSelector spDataTemplateSelector; + //GeneratorPosition generatorPosition; - UpdateContentPresenter(); - return; + //Debug.Assert(!IsInline, "ContentPresenter is not used in inline mode."); - // Avoid reentrancy. - if (m_preparingContentPresentersElement) - { - return; - } + //// Avoid reentrancy. + //if (m_preparingContentPresentersElement) + //{ + // return; + //} - if (m_tpSwappedOutComboBoxItem is not null) - { - if (m_tpContentPresenterPart is not null) - { - spContent = m_tpContentPresenterPart.Content; - { - m_tpContentPresenterPart.Content = null; - m_tpSwappedOutComboBoxItem.Content = spContent; - m_tpSwappedOutComboBoxItem = null; - } - } - } + //if (m_tpSwappedOutComboBoxItem is not null) + //{ + // if (m_tpContentPresenterPart is not null) + // { + // spContent = m_tpContentPresenterPart.Content; + // { + // m_tpContentPresenterPart.Content = null; + // m_tpSwappedOutComboBoxItem.Content = spContent; + // m_tpSwappedOutComboBoxItem = null; + // } + // } + //} - ItemContainerGenerator? spGenerator = null; // TODO Uno: Support for ItemContainerGenerator #17808 (Should reference this.ItemContainerGenerator property) - ItemContainerGenerator? pItemContainerGenerator = spGenerator; - if (m_iLastGeneratedItemIndexforFaceplate > 0 && pItemContainerGenerator is not null) - { - // This container was generated just for the purpose of extracting Content and ContentTemplate. - // This is the case where we generated an item which was its own container (e.g. defined in XAML or code behind). - // We keep this until the next item is being put on faceplate or popup is opened so that ItemContainerGenerator.ContainerFromIndex returns the - // correct container for this item which a developer would expect. - // We need to remove this item once popup opens (or another item takes its place on faceplate) - // so that virtualizing panel underneath does not get items out of order. - // We want to remove instead of recycle because we do not want to change the collection order by reusing containers for different data. - generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(m_iLastGeneratedItemIndexforFaceplate); - if (generatorPosition.Offset == 0 && generatorPosition.Index >= 0) - { - // Only remove if the position returned by Generator is correct - pItemContainerGenerator.Remove(generatorPosition, 1); - } + //ItemContainerGenerator? spGenerator = null; // TODO Uno: Support for ItemContainerGenerator #17808 (Should reference this.ItemContainerGenerator property) + //ItemContainerGenerator? pItemContainerGenerator = spGenerator; + //if (m_iLastGeneratedItemIndexforFaceplate > 0 && pItemContainerGenerator is not null) + //{ + // // This container was generated just for the purpose of extracting Content and ContentTemplate. + // // This is the case where we generated an item which was its own container (e.g. defined in XAML or code behind). + // // We keep this until the next item is being put on faceplate or popup is opened so that ItemContainerGenerator.ContainerFromIndex returns the + // // correct container for this item which a developer would expect. + // // We need to remove this item once popup opens (or another item takes its place on faceplate) + // // so that virtualizing panel underneath does not get items out of order. + // // We want to remove instead of recycle because we do not want to change the collection order by reusing containers for different data. + // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(m_iLastGeneratedItemIndexforFaceplate); + // if (generatorPosition.Offset == 0 && generatorPosition.Index >= 0) + // { + // // Only remove if the position returned by Generator is correct + // pItemContainerGenerator.Remove(generatorPosition, 1); + // } - m_iLastGeneratedItemIndexforFaceplate = -1; - } + // m_iLastGeneratedItemIndexforFaceplate = -1; + //} - if (index == -1) - { - if (m_tpContentPresenterPart is not null) - { - m_tpContentPresenterPart.ContentTemplateSelector = null; - m_tpContentPresenterPart.ContentTemplate = null; - m_tpContentPresenterPart.Content = m_tpEmptyContent; - } + //if (index == -1) + //{ + // if (m_tpContentPresenterPart is not null) + // { + // m_tpContentPresenterPart.ContentTemplateSelector = null; + // m_tpContentPresenterPart.ContentTemplate = null; + // m_tpContentPresenterPart.Content = m_tpEmptyContent; + // } - // Only reset the SelectionBoxItem if a custom value is not selected. - if (forceSelectionBoxToNull || !IsEditable || m_customValueRef is null) - { - SelectionBoxItem = null; - } + // // Only reset the SelectionBoxItem if a custom value is not selected. + // if (forceSelectionBoxToNull || !IsEditable || m_customValueRef is null) + // { + // SelectionBoxItem = null; + // } - SelectionBoxItemTemplate = null; - return; - } + // SelectionBoxItemTemplate = null; + // return; + //} - if (m_tpContentPresenterPart is not null) - { - m_tpContentPresenterPart.Content = null; - } + //if (m_tpContentPresenterPart is not null) + //{ + // m_tpContentPresenterPart.Content = null; + //} - spContainer = ContainerFromIndex(index); - spComboBoxItem = spContainer as ComboBoxItem; + //spContainer = ContainerFromIndex(index); + //spComboBoxItem = spContainer as ComboBoxItem; - if (spComboBoxItem is null && pItemContainerGenerator is not null) - { - bool isNewlyRealized = false; - generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index); - pItemContainerGenerator.StartAt(generatorPosition, GeneratorDirection.Forward, true); - spGeneratedComboBoxItemAsDO = pItemContainerGenerator.GenerateNext(out isNewlyRealized); - pItemContainerGenerator.Stop(); - m_preparingContentPresentersElement = true; - m_tpGeneratedContainerForContentPresenter = spGeneratedComboBoxItemAsDO; - try - { - pItemContainerGenerator.PrepareItemContainer(spGeneratedComboBoxItemAsDO); - } - finally - { - m_tpGeneratedContainerForContentPresenter = null; - m_preparingContentPresentersElement = false; - } - spComboBoxItem = (ComboBoxItem)spGeneratedComboBoxItemAsDO; - // We dont want to remove the comboBoxItem if it was created explicitly in XAML and exists in Items collection - // TODO Uno: Missing implementation for ItemContainerGenerator #17808 - //spItem = null; spComboBoxItem.ReadLocalValue(ItemContainerGenerator.ItemForItemContainerProperty); - //bGeneratedComboBoxItem = IsItemItsOwnContainer(spItem); - //bGeneratedComboBoxItem = !bGeneratedComboBoxItem; - m_iLastGeneratedItemIndexforFaceplate = index; - } + //if (spComboBoxItem is null && pItemContainerGenerator is not null) + //{ + // bool isNewlyRealized = false; + // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index); + // pItemContainerGenerator.StartAt(generatorPosition, GeneratorDirection.Forward, true); + // spGeneratedComboBoxItemAsDO = pItemContainerGenerator.GenerateNext(out isNewlyRealized); + // pItemContainerGenerator.Stop(); + // m_preparingContentPresentersElement = true; + // m_tpGeneratedContainerForContentPresenter = spGeneratedComboBoxItemAsDO; + // try + // { + // pItemContainerGenerator.PrepareItemContainer(spGeneratedComboBoxItemAsDO); + // } + // finally + // { + // m_tpGeneratedContainerForContentPresenter = null; + // m_preparingContentPresentersElement = false; + // } + // spComboBoxItem = (ComboBoxItem)spGeneratedComboBoxItemAsDO; + // // We dont want to remove the comboBoxItem if it was created explicitly in XAML and exists in Items collection + // // TODO Uno: Missing implementation for ItemContainerGenerator #17808 + // //spItem = null; spComboBoxItem.ReadLocalValue(ItemContainerGenerator.ItemForItemContainerProperty); + // //bGeneratedComboBoxItem = IsItemItsOwnContainer(spItem); + // //bGeneratedComboBoxItem = !bGeneratedComboBoxItem; + // m_iLastGeneratedItemIndexforFaceplate = index; + //} - if (spComboBoxItem is null) - { - return; - } + //if (spComboBoxItem is null) + //{ + // return; + //} - spContent = spComboBoxItem.Content; - { - // Because we can't keep UIElement in 2 different place - // we need to reset ComboBoxItem.Content property. And we need to do it for UIElement only - if (spContent is UIElement) - { - spComboBoxItem.Content = null; - if (!bGeneratedComboBoxItem) - { - m_tpSwappedOutComboBoxItem = spComboBoxItem; - } - } + //spContent = spComboBoxItem.Content; + //{ + // // Because we can't keep UIElement in 2 different place + // // we need to reset ComboBoxItem.Content property. And we need to do it for UIElement only + // if (spContent is UIElement) + // { + // spComboBoxItem.Content = null; + // if (!bGeneratedComboBoxItem) + // { + // m_tpSwappedOutComboBoxItem = spComboBoxItem; + // } + // } - spComboBoxItem.IsPointerOver = false; - spComboBoxItem.ChangeVisualStateInternal(true); + // spComboBoxItem.IsPointerOver = false; + // spComboBoxItem.ChangeVisualStateInternal(true); - // We want the item displayed in the 'selected item' ContentPresenter to have the same visual representation as the - // items in the Popup's StackPanel, to do that we copy the DataTemplate of the ComboBoxItem. - spDataTemplate = spComboBoxItem.ContentTemplate; - spDataTemplateSelector = spComboBoxItem.ContentTemplateSelector; - if (m_tpContentPresenterPart is not null) - { - m_tpContentPresenterPart.Content = spContent; - m_tpContentPresenterPart.ContentTemplate = spDataTemplate; - m_tpContentPresenterPart.ContentTemplateSelector = spDataTemplateSelector; - if (spDataTemplate is null) - { - spDataTemplate = m_tpContentPresenterPart.SelectedContentTemplate; - } - } + // // We want the item displayed in the 'selected item' ContentPresenter to have the same visual representation as the + // // items in the Popup's StackPanel, to do that we copy the DataTemplate of the ComboBoxItem. + // spDataTemplate = spComboBoxItem.ContentTemplate; + // spDataTemplateSelector = spComboBoxItem.ContentTemplateSelector; + // if (m_tpContentPresenterPart is not null) + // { + // m_tpContentPresenterPart.Content = spContent; + // m_tpContentPresenterPart.ContentTemplate = spDataTemplate; + // m_tpContentPresenterPart.ContentTemplateSelector = spDataTemplateSelector; + // if (spDataTemplate is null) + // { + // spDataTemplate = m_tpContentPresenterPart.SelectedContentTemplate; + // } + // } - SelectionBoxItem = spContent; - SelectionBoxItemTemplate = spDataTemplate; - } + // SelectionBoxItem = spContent; + // SelectionBoxItemTemplate = spDataTemplate; + //} - if (bGeneratedComboBoxItem && pItemContainerGenerator is not null) - { - // This container was generated just for the purpose of extracting Content and ContentTemplate - // It is not connected to the visual tree which might have unintended consequences, so remove it - generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index); - pItemContainerGenerator.Recycle(generatorPosition, 1); - m_iLastGeneratedItemIndexforFaceplate = -1; - } + //if (bGeneratedComboBoxItem && pItemContainerGenerator is not null) + //{ + // // This container was generated just for the purpose of extracting Content and ContentTemplate + // // It is not connected to the visual tree which might have unintended consequences, so remove it + // generatorPosition = pItemContainerGenerator.GeneratorPositionFromIndex(index); + // pItemContainerGenerator.Recycle(generatorPosition, 1); + // m_iLastGeneratedItemIndexforFaceplate = -1; + //} } internal void UpdateSelectionBoxItemProperties(int index) @@ -763,7 +764,7 @@ private void OnOpen() { m_tpPopupPart.IsOpen = true; - bool isDefaultShadowEnabled = IsDefaultShadowEnabled; + bool isDefaultShadowEnabled = IsDefaultShadowEnabled(this); // Cast a shadow if (isDefaultShadowEnabled) @@ -827,7 +828,7 @@ private void OnOpen() // give focus to or select the first item to ensure that keyboarding can function normally. if (selectedItemIndex >= 0) { - SetFocusedItem(selectedItemIndex, m_bShouldCenterSelectedItem /*shouldScrollIntoView*/, true /*forceFocus*/, FocusState.Programmatic); + SetFocusedItem(selectedItemIndex, m_bShouldCenterSelectedItem /*shouldScrollIntoView*/, true /*forceFocus*/, FocusState.Programmatic, false); } else { @@ -2325,5 +2326,17 @@ private void EnsurePresenterReadyForFullMode() { } private void EnsurePresenterReadyForInlineMode() { } private void ForceApplyInlineLayoutUpdate() { } + + private void SetIsPopupPannable() { } + + private void SetClosingAnimationDirection() { } + + private void ResetCarouselPanelState() { } + + private void PlayOverlayClosingAnimation() { } + + private void PlayOverlayOpeningAnimation() { } + + private void ClearStateFlagsOnItems() { } #endif }