diff --git a/dev/AnimatedIcon/AnimatedIcon.cpp b/dev/AnimatedIcon/AnimatedIcon.cpp index caa7f92b7f..da768984f4 100644 --- a/dev/AnimatedIcon/AnimatedIcon.cpp +++ b/dev/AnimatedIcon/AnimatedIcon.cpp @@ -22,6 +22,7 @@ AnimatedIcon::AnimatedIcon() Loaded({ this, &AnimatedIcon::OnLoaded }); RegisterPropertyChangedCallback(winrt::IconElement::ForegroundProperty(), { this, &AnimatedIcon::OnForegroundPropertyChanged}); + RegisterPropertyChangedCallback(winrt::FrameworkElement::FlowDirectionProperty(), { this, &AnimatedIcon::OnFlowDirectionPropertyChanged }); } void AnimatedIcon::OnApplyTemplate() @@ -96,6 +97,7 @@ void AnimatedIcon::OnLoaded(winrt::IInspectable const&, winrt::RoutedEventArgs c OnFallbackIconSourcePropertyChanged(nullptr); } + winrt::Size AnimatedIcon::MeasureOverride(winrt::Size const& availableSize) { if (auto const visual = m_animatedVisual.get()) @@ -444,6 +446,33 @@ void AnimatedIcon::OnSourcePropertyChanged(const winrt::DependencyPropertyChange } } +void AnimatedIcon::UpdateMirrorTransform() +{ + auto const scaleTransform = [this]() + { + if (!m_scaleTransform) + { + // Initialize the scale transform that will be used for mirroring and the + // render transform origin as center in order to have the icon mirrored in place. + winrt::Windows::UI::Xaml::Media::ScaleTransform scaleTransform; + + RenderTransform(scaleTransform); + RenderTransformOrigin({ 0.5, 0.5 }); + m_scaleTransform.set(scaleTransform); + return scaleTransform; + } + return m_scaleTransform.get(); + }(); + + + scaleTransform.ScaleX(FlowDirection() == winrt::FlowDirection::RightToLeft && !MirroredWhenRightToLeft() && m_canDisplayPrimaryContent ? -1.0f : 1.0f); +} + +void AnimatedIcon::OnMirroredWhenRightToLeftPropertyChanged(const winrt::DependencyPropertyChangedEventArgs&) +{ + UpdateMirrorTransform(); +} + bool AnimatedIcon::ConstructAndInsertVisual() { auto const visual = [this]() @@ -497,6 +526,8 @@ bool AnimatedIcon::ConstructAndInsertVisual() m_canDisplayPrimaryContent = false; return false; } + + UpdateMirrorTransform(); } void AnimatedIcon::OnFallbackIconSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs&) @@ -535,6 +566,11 @@ void AnimatedIcon::OnForegroundPropertyChanged(const winrt::DependencyObject& se } } +void AnimatedIcon::OnFlowDirectionPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args) +{ + UpdateMirrorTransform(); +} + void AnimatedIcon::OnForegroundBrushColorPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args) { TrySetForegroundProperty(sender.GetValue(args).as()); diff --git a/dev/AnimatedIcon/AnimatedIcon.h b/dev/AnimatedIcon/AnimatedIcon.h index 57c98fb850..f9081a5b1b 100644 --- a/dev/AnimatedIcon/AnimatedIcon.h +++ b/dev/AnimatedIcon/AnimatedIcon.h @@ -27,8 +27,9 @@ class AnimatedIcon : winrt::Size MeasureOverride(winrt::Size const& availableSize); winrt::Size ArrangeOverride(winrt::Size const& finalSize); - void OnSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args); - void OnFallbackIconSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs& args); + void OnSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs&); + void OnFallbackIconSourcePropertyChanged(const winrt::DependencyPropertyChangedEventArgs&); + void OnMirroredWhenRightToLeftPropertyChanged(const winrt::DependencyPropertyChangedEventArgs&); static void OnAnimatedIconStatePropertyChanged( const winrt::DependencyObject& sender, const winrt::DependencyPropertyChangedEventArgs& args); @@ -55,11 +56,14 @@ class AnimatedIcon : void TrySetForegroundProperty(winrt::IAnimatedVisualSource2 const& source = nullptr); void OnAnimationCompleted(winrt::IInspectable const&, winrt::CompositionBatchCompletedEventArgs const&); void OnForegroundPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args); + void OnFlowDirectionPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args); void OnForegroundBrushColorPropertyChanged(const winrt::DependencyObject& sender, const winrt::DependencyProperty& args); void SetRootPanelChildToFallbackIcon(); + void UpdateMirrorTransform(); tracker_ref m_animatedVisual{ this }; tracker_ref m_rootPanel{ this }; + tracker_ref m_scaleTransform{ this }; winrt::hstring m_currentState{ L"" }; winrt::hstring m_previousState{ L"" }; diff --git a/dev/AnimatedIcon/AnimatedIcon.idl b/dev/AnimatedIcon/AnimatedIcon.idl index 76763406f4..563f88215a 100644 --- a/dev/AnimatedIcon/AnimatedIcon.idl +++ b/dev/AnimatedIcon/AnimatedIcon.idl @@ -22,6 +22,9 @@ unsealed runtimeclass AnimatedIcon : Windows.UI.Xaml.Controls.IconElement [MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] IconSource FallbackIconSource{ get; set; }; + [MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] + Boolean MirroredWhenRightToLeft{ get; set; }; + [MUX_PROPERTY_CHANGED_CALLBACK_METHODNAME("OnAnimatedIconStatePropertyChanged")] static Windows.UI.Xaml.DependencyProperty StateProperty{ get; }; static void SetState(Windows.UI.Xaml.DependencyObject object, String value); @@ -29,6 +32,7 @@ unsealed runtimeclass AnimatedIcon : Windows.UI.Xaml.Controls.IconElement static Windows.UI.Xaml.DependencyProperty SourceProperty{ get; }; static Windows.UI.Xaml.DependencyProperty FallbackIconSourceProperty{ get; }; + static Windows.UI.Xaml.DependencyProperty MirroredWhenRightToLeftProperty{ get; }; } } diff --git a/dev/AnimatedIcon/TestUI/AnimatedIconHost.cs b/dev/AnimatedIcon/TestUI/AnimatedIconHost.cs index 2cdc0ca2ae..30125fc409 100644 --- a/dev/AnimatedIcon/TestUI/AnimatedIconHost.cs +++ b/dev/AnimatedIcon/TestUI/AnimatedIconHost.cs @@ -96,21 +96,7 @@ private void IconSourceChanged() { if (m_iconPresenter != null) { - AnimatedIcon animatedIcon = new AnimatedIcon(); - AnimatedIconSource source = (AnimatedIconSource)IconSource; - if (source.Source != null) - { - animatedIcon.Source = source.Source; - } - if (source.FallbackIconSource != null) - { - animatedIcon.FallbackIconSource = source.FallbackIconSource; - } - if (source.Foreground != null) - { - animatedIcon.Foreground = source.Foreground; - } - m_iconPresenter.Child = animatedIcon; + m_iconPresenter.Child = IconSource.CreateIconElement(); } } } diff --git a/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml b/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml index 2b8747b696..ffc48a1d3a 100644 --- a/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml +++ b/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml @@ -149,6 +149,7 @@ + @@ -168,7 +169,8 @@ - + + @@ -441,7 +443,7 @@ - + @@ -458,7 +460,7 @@ - + @@ -475,7 +477,7 @@ - + @@ -590,6 +592,13 @@ + + + + + + + diff --git a/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml.cs b/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml.cs index b1f612aaa9..5ada5b8c87 100644 --- a/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml.cs +++ b/dev/AnimatedIcon/TestUI/AnimatedIconPage.xaml.cs @@ -270,6 +270,16 @@ private void SpeedUpSlider_ValueChanged(object sender, RangeBaseValueChangedEven } } + public void IsLeftToRightChecked(object sender, RoutedEventArgs args) + { + this.FlowDirection = FlowDirection.LeftToRight; + } + + public void IsLeftToRightUnchecked(object sender, RoutedEventArgs args) + { + this.FlowDirection = FlowDirection.RightToLeft; + } + private void ChangeFallbackGlyphButton_Click(object sender, RoutedEventArgs e) { boundFallback.FallbackGlyph = "\uE9AE"; diff --git a/dev/Generated/AnimatedIcon.properties.cpp b/dev/Generated/AnimatedIcon.properties.cpp index b93ea1762b..4b53b1b82b 100644 --- a/dev/Generated/AnimatedIcon.properties.cpp +++ b/dev/Generated/AnimatedIcon.properties.cpp @@ -14,6 +14,7 @@ namespace winrt::Microsoft::UI::Xaml::Controls #include "AnimatedIcon.g.cpp" GlobalDependencyProperty AnimatedIconProperties::s_FallbackIconSourceProperty{ nullptr }; +GlobalDependencyProperty AnimatedIconProperties::s_MirroredWhenRightToLeftProperty{ nullptr }; GlobalDependencyProperty AnimatedIconProperties::s_SourceProperty{ nullptr }; GlobalDependencyProperty AnimatedIconProperties::s_StateProperty{ nullptr }; @@ -35,6 +36,17 @@ void AnimatedIconProperties::EnsureProperties() ValueHelper::BoxedDefaultValue(), winrt::PropertyChangedCallback(&OnFallbackIconSourcePropertyChanged)); } + if (!s_MirroredWhenRightToLeftProperty) + { + s_MirroredWhenRightToLeftProperty = + InitializeDependencyProperty( + L"MirroredWhenRightToLeft", + winrt::name_of(), + winrt::name_of(), + false /* isAttached */, + ValueHelper::BoxedDefaultValue(), + winrt::PropertyChangedCallback(&OnMirroredWhenRightToLeftPropertyChanged)); + } if (!s_SourceProperty) { s_SourceProperty = @@ -62,6 +74,7 @@ void AnimatedIconProperties::EnsureProperties() void AnimatedIconProperties::ClearProperties() { s_FallbackIconSourceProperty = nullptr; + s_MirroredWhenRightToLeftProperty = nullptr; s_SourceProperty = nullptr; s_StateProperty = nullptr; } @@ -74,6 +87,14 @@ void AnimatedIconProperties::OnFallbackIconSourcePropertyChanged( winrt::get_self(owner)->OnFallbackIconSourcePropertyChanged(args); } +void AnimatedIconProperties::OnMirroredWhenRightToLeftPropertyChanged( + winrt::DependencyObject const& sender, + winrt::DependencyPropertyChangedEventArgs const& args) +{ + auto owner = sender.as(); + winrt::get_self(owner)->OnMirroredWhenRightToLeftPropertyChanged(args); +} + void AnimatedIconProperties::OnSourcePropertyChanged( winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args) @@ -95,6 +116,19 @@ winrt::IconSource AnimatedIconProperties::FallbackIconSource() return ValueHelper::CastOrUnbox(static_cast(this)->GetValue(s_FallbackIconSourceProperty)); } +void AnimatedIconProperties::MirroredWhenRightToLeft(bool value) +{ + [[gsl::suppress(con)]] + { + static_cast(this)->SetValue(s_MirroredWhenRightToLeftProperty, ValueHelper::BoxValueIfNecessary(value)); + } +} + +bool AnimatedIconProperties::MirroredWhenRightToLeft() +{ + return ValueHelper::CastOrUnbox(static_cast(this)->GetValue(s_MirroredWhenRightToLeftProperty)); +} + void AnimatedIconProperties::Source(winrt::IAnimatedVisualSource2 const& value) { [[gsl::suppress(con)]] diff --git a/dev/Generated/AnimatedIcon.properties.h b/dev/Generated/AnimatedIcon.properties.h index e911183b34..741b4611c7 100644 --- a/dev/Generated/AnimatedIcon.properties.h +++ b/dev/Generated/AnimatedIcon.properties.h @@ -12,6 +12,9 @@ class AnimatedIconProperties void FallbackIconSource(winrt::IconSource const& value); winrt::IconSource FallbackIconSource(); + void MirroredWhenRightToLeft(bool value); + bool MirroredWhenRightToLeft(); + void Source(winrt::IAnimatedVisualSource2 const& value); winrt::IAnimatedVisualSource2 Source(); @@ -19,10 +22,12 @@ class AnimatedIconProperties static winrt::hstring GetState(winrt::DependencyObject const& target); static winrt::DependencyProperty FallbackIconSourceProperty() { return s_FallbackIconSourceProperty; } + static winrt::DependencyProperty MirroredWhenRightToLeftProperty() { return s_MirroredWhenRightToLeftProperty; } static winrt::DependencyProperty SourceProperty() { return s_SourceProperty; } static winrt::DependencyProperty StateProperty() { return s_StateProperty; } static GlobalDependencyProperty s_FallbackIconSourceProperty; + static GlobalDependencyProperty s_MirroredWhenRightToLeftProperty; static GlobalDependencyProperty s_SourceProperty; static GlobalDependencyProperty s_StateProperty; @@ -33,6 +38,10 @@ class AnimatedIconProperties winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args); + static void OnMirroredWhenRightToLeftPropertyChanged( + winrt::DependencyObject const& sender, + winrt::DependencyPropertyChangedEventArgs const& args); + static void OnSourcePropertyChanged( winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args); diff --git a/dev/Generated/AnimatedIconSource.properties.cpp b/dev/Generated/AnimatedIconSource.properties.cpp index 372ff2db3d..f9ec53d3a2 100644 --- a/dev/Generated/AnimatedIconSource.properties.cpp +++ b/dev/Generated/AnimatedIconSource.properties.cpp @@ -14,6 +14,7 @@ namespace winrt::Microsoft::UI::Xaml::Controls #include "AnimatedIconSource.g.cpp" GlobalDependencyProperty AnimatedIconSourceProperties::s_FallbackIconSourceProperty{ nullptr }; +GlobalDependencyProperty AnimatedIconSourceProperties::s_MirroredWhenRightToLeftProperty{ nullptr }; GlobalDependencyProperty AnimatedIconSourceProperties::s_SourceProperty{ nullptr }; AnimatedIconSourceProperties::AnimatedIconSourceProperties() @@ -35,6 +36,17 @@ void AnimatedIconSourceProperties::EnsureProperties() ValueHelper::BoxedDefaultValue(), winrt::PropertyChangedCallback(&OnFallbackIconSourcePropertyChanged)); } + if (!s_MirroredWhenRightToLeftProperty) + { + s_MirroredWhenRightToLeftProperty = + InitializeDependencyProperty( + L"MirroredWhenRightToLeft", + winrt::name_of(), + winrt::name_of(), + false /* isAttached */, + ValueHelper::BoxedDefaultValue(), + winrt::PropertyChangedCallback(&OnMirroredWhenRightToLeftPropertyChanged)); + } if (!s_SourceProperty) { s_SourceProperty = @@ -51,6 +63,7 @@ void AnimatedIconSourceProperties::EnsureProperties() void AnimatedIconSourceProperties::ClearProperties() { s_FallbackIconSourceProperty = nullptr; + s_MirroredWhenRightToLeftProperty = nullptr; s_SourceProperty = nullptr; IconSource::ClearProperties(); } @@ -63,6 +76,14 @@ void AnimatedIconSourceProperties::OnFallbackIconSourcePropertyChanged( winrt::get_self(owner)->OnPropertyChanged(args); } +void AnimatedIconSourceProperties::OnMirroredWhenRightToLeftPropertyChanged( + winrt::DependencyObject const& sender, + winrt::DependencyPropertyChangedEventArgs const& args) +{ + auto owner = sender.as(); + winrt::get_self(owner)->OnPropertyChanged(args); +} + void AnimatedIconSourceProperties::OnSourcePropertyChanged( winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args) @@ -84,6 +105,19 @@ winrt::IconSource AnimatedIconSourceProperties::FallbackIconSource() return ValueHelper::CastOrUnbox(static_cast(this)->GetValue(s_FallbackIconSourceProperty)); } +void AnimatedIconSourceProperties::MirroredWhenRightToLeft(bool value) +{ + [[gsl::suppress(con)]] + { + static_cast(this)->SetValue(s_MirroredWhenRightToLeftProperty, ValueHelper::BoxValueIfNecessary(value)); + } +} + +bool AnimatedIconSourceProperties::MirroredWhenRightToLeft() +{ + return ValueHelper::CastOrUnbox(static_cast(this)->GetValue(s_MirroredWhenRightToLeftProperty)); +} + void AnimatedIconSourceProperties::Source(winrt::IAnimatedVisualSource2 const& value) { [[gsl::suppress(con)]] diff --git a/dev/Generated/AnimatedIconSource.properties.h b/dev/Generated/AnimatedIconSource.properties.h index 5aaa3b8bf0..e1c08bef74 100644 --- a/dev/Generated/AnimatedIconSource.properties.h +++ b/dev/Generated/AnimatedIconSource.properties.h @@ -12,13 +12,18 @@ class AnimatedIconSourceProperties void FallbackIconSource(winrt::IconSource const& value); winrt::IconSource FallbackIconSource(); + void MirroredWhenRightToLeft(bool value); + bool MirroredWhenRightToLeft(); + void Source(winrt::IAnimatedVisualSource2 const& value); winrt::IAnimatedVisualSource2 Source(); static winrt::DependencyProperty FallbackIconSourceProperty() { return s_FallbackIconSourceProperty; } + static winrt::DependencyProperty MirroredWhenRightToLeftProperty() { return s_MirroredWhenRightToLeftProperty; } static winrt::DependencyProperty SourceProperty() { return s_SourceProperty; } static GlobalDependencyProperty s_FallbackIconSourceProperty; + static GlobalDependencyProperty s_MirroredWhenRightToLeftProperty; static GlobalDependencyProperty s_SourceProperty; static void EnsureProperties(); @@ -28,6 +33,10 @@ class AnimatedIconSourceProperties winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args); + static void OnMirroredWhenRightToLeftPropertyChanged( + winrt::DependencyObject const& sender, + winrt::DependencyPropertyChangedEventArgs const& args); + static void OnSourcePropertyChanged( winrt::DependencyObject const& sender, winrt::DependencyPropertyChangedEventArgs const& args); diff --git a/dev/IconSource/APITests/IconSourceApiTests.cs b/dev/IconSource/APITests/IconSourceApiTests.cs index f76bb8f809..0a0f4b262a 100644 --- a/dev/IconSource/APITests/IconSourceApiTests.cs +++ b/dev/IconSource/APITests/IconSourceApiTests.cs @@ -252,17 +252,21 @@ public void AnimatedIconSourceTest() // the parent to work. Verify.AreEqual(iconSource.Foreground, null); //Verify.AreEqual(animatedIcon.Foreground, null); + Verify.AreEqual(iconSource.MirroredWhenRightToLeft, false); + Verify.AreEqual(animatedIcon.MirroredWhenRightToLeft, false); Log.Comment("Validate the defaults match BitmapIcon."); var icon = new AnimatedIcon(); Verify.AreEqual(icon.Source, iconSource.Source); Verify.AreEqual(animatedIcon.Source, iconSource.Source); + Verify.AreEqual(icon.MirroredWhenRightToLeft, iconSource.MirroredWhenRightToLeft); Log.Comment("Validate that you can change the properties."); iconSource.Foreground = new SolidColorBrush(Windows.UI.Colors.Red); iconSource.Source = source; + iconSource.MirroredWhenRightToLeft = true; }); IdleSynchronizer.Wait(); @@ -274,6 +278,8 @@ public void AnimatedIconSourceTest() Verify.AreEqual(Windows.UI.Colors.Red, (animatedIcon.Foreground as SolidColorBrush).Color); Verify.AreEqual(source, iconSource.Source); Verify.AreEqual(source, animatedIcon.Source); + Verify.IsTrue(iconSource.MirroredWhenRightToLeft); + Verify.IsTrue(animatedIcon.MirroredWhenRightToLeft); }); } diff --git a/dev/IconSource/AnimatedIconSource.cpp b/dev/IconSource/AnimatedIconSource.cpp index e06e744ff6..10dfc031ac 100644 --- a/dev/IconSource/AnimatedIconSource.cpp +++ b/dev/IconSource/AnimatedIconSource.cpp @@ -22,6 +22,8 @@ winrt::IconElement AnimatedIconSource::CreateIconElementCore() { animatedIcon.Foreground(newForeground); } + animatedIcon.MirroredWhenRightToLeft(MirroredWhenRightToLeft()); + return animatedIcon; } @@ -35,6 +37,10 @@ winrt::DependencyProperty AnimatedIconSource::GetIconElementPropertyCore(winrt:: { return winrt::AnimatedIcon::FallbackIconSourceProperty(); } + else if (sourceProperty == s_MirroredWhenRightToLeftProperty) + { + return winrt::AnimatedIcon::MirroredWhenRightToLeftProperty(); + } return __super::GetIconElementPropertyCore(sourceProperty); } diff --git a/dev/IconSource/IconSource.idl b/dev/IconSource/IconSource.idl index b77c443290..8e8e8cc6dc 100644 --- a/dev/IconSource/IconSource.idl +++ b/dev/IconSource/IconSource.idl @@ -125,9 +125,12 @@ unsealed runtimeclass AnimatedIconSource : IconSource IAnimatedVisualSource2 Source{ get; set; }; [MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] IconSource FallbackIconSource{ get; set; }; + [MUX_PROPERTY_CHANGED_CALLBACK(TRUE)] + Boolean MirroredWhenRightToLeft{ get; set; }; static Windows.UI.Xaml.DependencyProperty SourceProperty { get; }; static Windows.UI.Xaml.DependencyProperty FallbackIconSourceProperty { get; }; + static Windows.UI.Xaml.DependencyProperty MirroredWhenRightToLeftProperty{ get; }; } } diff --git a/dev/NavigationView/NavigationBackButton.xaml b/dev/NavigationView/NavigationBackButton.xaml index 78f8eb83fc..8077abe0c4 100644 --- a/dev/NavigationView/NavigationBackButton.xaml +++ b/dev/NavigationView/NavigationBackButton.xaml @@ -76,7 +76,8 @@ diff --git a/dev/NavigationView/TestUI/Common/NavigationViewPage.xaml b/dev/NavigationView/TestUI/Common/NavigationViewPage.xaml index bcf5b5a0e2..54dd232171 100644 --- a/dev/NavigationView/TestUI/Common/NavigationViewPage.xaml +++ b/dev/NavigationView/TestUI/Common/NavigationViewPage.xaml @@ -207,6 +207,7 @@