From 6aad691f7b4e47a46e2fbabe93821ad52f44f2c5 Mon Sep 17 00:00:00 2001 From: Dongle <29563098+dongle-the-gadget@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:16:12 +0700 Subject: [PATCH] Make UI more compliant with Windows 11 design (#26) * Make UI more compliant with Windows 11 design. * Fix to 2-space indent. --- NanaBox/App.xaml | 3 + NanaBox/NanaBox.vcxproj | 11 +++ NanaBox/NanaBox.vcxproj.filters | 3 + NanaBox/NewVirtualHardDiskPage.xaml | 4 +- NanaBox/ProgressRing.cpp | 114 +++++++++++++++++++++++++ NanaBox/ProgressRing.h | 37 ++++++++ NanaBox/ProgressRing.idl | 9 ++ NanaBox/ResizeVirtualHardDiskPage.xaml | 4 +- NanaBox/Utils.cpp | 4 +- 9 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 NanaBox/ProgressRing.cpp create mode 100644 NanaBox/ProgressRing.h create mode 100644 NanaBox/ProgressRing.idl diff --git a/NanaBox/App.xaml b/NanaBox/App.xaml index 7ff467c..a158005 100644 --- a/NanaBox/App.xaml +++ b/NanaBox/App.xaml @@ -8,6 +8,9 @@ + diff --git a/NanaBox/NanaBox.vcxproj b/NanaBox/NanaBox.vcxproj index 8d08168..899e51c 100644 --- a/NanaBox/NanaBox.vcxproj +++ b/NanaBox/NanaBox.vcxproj @@ -68,6 +68,10 @@ NewVirtualHardDiskPage.xaml Code + + ProgressRing.idl + Code + QuickStartPage.xaml Code @@ -128,6 +132,9 @@ NewVirtualHardDiskPage.xaml Code + + Code + QuickStartPage.xaml Code @@ -175,6 +182,10 @@ Code + + ProgressRing.idl + Code + QuickStartPage.xaml Code diff --git a/NanaBox/NanaBox.vcxproj.filters b/NanaBox/NanaBox.vcxproj.filters index c1bfa2f..60b6c46 100644 --- a/NanaBox/NanaBox.vcxproj.filters +++ b/NanaBox/NanaBox.vcxproj.filters @@ -160,4 +160,7 @@ Strings\zh-Hans + + + \ No newline at end of file diff --git a/NanaBox/NewVirtualHardDiskPage.xaml b/NanaBox/NewVirtualHardDiskPage.xaml index dd86c5f..2bcd6e2 100644 --- a/NanaBox/NewVirtualHardDiskPage.xaml +++ b/NanaBox/NewVirtualHardDiskPage.xaml @@ -24,7 +24,7 @@ x:Uid="/NewVirtualHardDiskPage/ContentTextBlock" Text="[You can create a VHD (up to 2040 GiB) or VHDX (up to 64 TiB, but not supported before Windows 8) dynamically expanding virtual hard disk with this dialog.]" TextWrapping="Wrap" /> - + @@ -45,7 +45,7 @@ x:Uid="/NewVirtualHardDiskPage/SizeTextBlock" Padding="0,2" Text="Size (at least 3 MiB and must be a multiple of 512 bytes)" /> - + diff --git a/NanaBox/ProgressRing.cpp b/NanaBox/ProgressRing.cpp new file mode 100644 index 0000000..af38940 --- /dev/null +++ b/NanaBox/ProgressRing.cpp @@ -0,0 +1,114 @@ +#include "pch.h" +#include "ProgressRing.h" +#if __has_include("ProgressRing.g.cpp") +#include "ProgressRing.g.cpp" +#endif + +namespace winrt::NanaBox::implementation +{ + ProgressRing::ProgressRing() + { + m_compositor = Windows::UI::Xaml::Hosting::ElementCompositionPreview::GetElementVisual(*this).Compositor(); + + auto ellipse = m_compositor.CreateEllipseGeometry(); + ellipse.Radius({ 7, 7 }); + + m_shape = m_compositor.CreateSpriteShape(ellipse); + m_shape.StrokeDashCap(Windows::UI::Composition::CompositionStrokeCap::Round); + m_shape.StrokeStartCap(Windows::UI::Composition::CompositionStrokeCap::Round); + m_shape.StrokeEndCap(Windows::UI::Composition::CompositionStrokeCap::Round); + m_shape.StrokeThickness(m_strokeThickness); + m_shape.TransformMatrix({ 5.0f, 0.0f, 0.0f, 5.0f, 40.0f, 40.0f }); + + m_visual = m_compositor.CreateShapeVisual(); + m_visual.Size({ m_defaultProgressRingSize, m_defaultProgressRingSize }); + m_visual.Shapes().Append(m_shape); + + Windows::UI::Xaml::Hosting::ElementCompositionPreview::SetElementChildVisual(*this, m_visual); + + auto holdThenStepEasing = m_compositor.CreateStepEasingFunction(); + holdThenStepEasing.IsFinalStepSingleFrame(true); + + auto cubicBezierEasing = m_compositor.CreateCubicBezierEasingFunction({ 0.166999996f, 0.166999996f }, { 0.833000004f, 0.833000004f }); + + auto rotationAnimation = m_compositor.CreateScalarKeyFrameAnimation(); + rotationAnimation.InsertKeyFrame(0.0f, 0.0f, holdThenStepEasing); + rotationAnimation.InsertKeyFrame(0.5f, 450.0f, cubicBezierEasing); + rotationAnimation.InsertKeyFrame(1.0f, 1080.0f, cubicBezierEasing); + rotationAnimation.Duration(Windows::Foundation::TimeSpan{ std::chrono::seconds(2) }); + rotationAnimation.IterationBehavior(Windows::UI::Composition::AnimationIterationBehavior::Forever); + + auto sizeAnimation = m_compositor.CreateScalarKeyFrameAnimation(); + sizeAnimation.InsertKeyFrame(0.0f, 0.0f, holdThenStepEasing); + sizeAnimation.InsertKeyFrame(0.5f, 0.5f, cubicBezierEasing); + sizeAnimation.InsertKeyFrame(1.0f, 0.0f, cubicBezierEasing); + sizeAnimation.Duration(Windows::Foundation::TimeSpan{ std::chrono::seconds(2) }); + sizeAnimation.IterationBehavior(Windows::UI::Composition::AnimationIterationBehavior::Forever); + + m_shape.StartAnimation(L"RotationAngleInDegrees", rotationAnimation); + ellipse.StartAnimation(L"TrimEnd", sizeAnimation); + } + + Windows::Foundation::Size ProgressRing::MeasureOverride(Windows::Foundation::Size const& availableSize) + { + auto size = availableSize.Width > availableSize.Height ? availableSize.Height : availableSize.Width; + if (size == INFINITY) + { + size = m_defaultProgressRingSize; + } + + return { size, size }; + } + + Windows::Foundation::Size ProgressRing::ArrangeOverride(Windows::Foundation::Size const& finalSize) + { + auto size = finalSize.Width > finalSize.Height ? finalSize.Height : finalSize.Width; + + float scale = size / m_defaultProgressRingSize; + m_visual.Scale({ scale, scale, scale }); + + float widthOffset = (finalSize.Width - size) / 2; + float heightOffset = (finalSize.Height - size) / 2; + m_visual.Offset({ widthOffset, heightOffset, 0.0f }); + + return finalSize; + } + + Windows::UI::Xaml::DependencyProperty ProgressRing::m_foregroundProperty = + Windows::UI::Xaml::DependencyProperty::Register( + L"Foreground", + winrt::xaml_typename(), + winrt::xaml_typename(), + Windows::UI::Xaml::PropertyMetadata{ nullptr, &OnForegroundChanged } + ); + + void ProgressRing::OnForegroundChanged(Windows::UI::Xaml::DependencyObject d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs args) + { + auto progressRing = d.as(); + auto progressRingImpl = winrt::get_self(progressRing); + + auto oldBrush = progressRingImpl->m_shape.StrokeBrush(); + auto newBrush = progressRingImpl->m_compositor.CreateColorBrush(args.NewValue().as().Color()); + progressRingImpl->m_shape.StrokeBrush(newBrush); + + if (oldBrush) + { + oldBrush.Close(); + } + } + + Windows::UI::Xaml::DependencyProperty ProgressRing::ForegroundProperty() + { + return m_foregroundProperty; + } + + Windows::UI::Xaml::Media::SolidColorBrush ProgressRing::Foreground() + { + return winrt::unbox_value(GetValue(m_foregroundProperty)); + } + + void ProgressRing::Foreground(Windows::UI::Xaml::Media::SolidColorBrush const& value) + { + SetValue(m_foregroundProperty, value); + } +} diff --git a/NanaBox/ProgressRing.h b/NanaBox/ProgressRing.h new file mode 100644 index 0000000..3262602 --- /dev/null +++ b/NanaBox/ProgressRing.h @@ -0,0 +1,37 @@ +#pragma once + +#include "ProgressRing.g.h" +#include + +namespace winrt::NanaBox::implementation +{ + struct ProgressRing : ProgressRingT + { + ProgressRing(); + + static Windows::UI::Xaml::DependencyProperty ForegroundProperty(); + Windows::UI::Xaml::Media::SolidColorBrush Foreground(); + void Foreground(Windows::UI::Xaml::Media::SolidColorBrush const& value); + + Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size const& availableSize); + Windows::Foundation::Size ArrangeOverride(Windows::Foundation::Size const& finalSize); + + private: + static void OnForegroundChanged(Windows::UI::Xaml::DependencyObject d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs args); + + Windows::UI::Composition::Compositor m_compositor{ nullptr }; + Windows::UI::Composition::CompositionSpriteShape m_shape{ nullptr }; + Windows::UI::Composition::ShapeVisual m_visual{ nullptr }; + + static Windows::UI::Xaml::DependencyProperty m_foregroundProperty; + const float m_defaultProgressRingSize = 80.0f; + const float m_strokeThickness = 1.5f; + }; +} + +namespace winrt::NanaBox::factory_implementation +{ + struct ProgressRing : ProgressRingT + { + }; +} diff --git a/NanaBox/ProgressRing.idl b/NanaBox/ProgressRing.idl new file mode 100644 index 0000000..3647a57 --- /dev/null +++ b/NanaBox/ProgressRing.idl @@ -0,0 +1,9 @@ +namespace NanaBox +{ + runtimeclass ProgressRing : Windows.UI.Xaml.FrameworkElement + { + ProgressRing(); + static Windows.UI.Xaml.DependencyProperty ForegroundProperty { get; }; + Windows.UI.Xaml.Media.SolidColorBrush Foreground; + } +} diff --git a/NanaBox/ResizeVirtualHardDiskPage.xaml b/NanaBox/ResizeVirtualHardDiskPage.xaml index 6ddea65..a031ec8 100644 --- a/NanaBox/ResizeVirtualHardDiskPage.xaml +++ b/NanaBox/ResizeVirtualHardDiskPage.xaml @@ -24,7 +24,7 @@ x:Uid="/ResizeVirtualHardDiskPage/ContentTextBlock" Text="[Specify the new size for the virtual hard disk.]" TextWrapping="Wrap" /> - + @@ -45,7 +45,7 @@ x:Uid="/ResizeVirtualHardDiskPage/SizeTextBlock" Padding="0,2" Text="[Size (at least 3 MiB and must be a multiple of 512 bytes)]" /> - + diff --git a/NanaBox/Utils.cpp b/NanaBox/Utils.cpp index 4c05ddb..780cad8 100644 --- a/NanaBox/Utils.cpp +++ b/NanaBox/Utils.cpp @@ -29,7 +29,7 @@ namespace winrt using Windows::UI::Xaml::HorizontalAlignment; using Windows::UI::Xaml::ThicknessHelper; using Windows::UI::Xaml::VerticalAlignment; - using Windows::UI::Xaml::Controls::ProgressRing; + using NanaBox::ProgressRing; } void SplitCommandLineEx( @@ -937,7 +937,7 @@ HWND ShowOperationWaitingWindow( Content.Margin(winrt::ThicknessHelper::FromUniformLength(12)); Content.HorizontalAlignment(winrt::HorizontalAlignment::Stretch); Content.VerticalAlignment(winrt::VerticalAlignment::Stretch); - Content.IsActive(true); + // Content.IsActive(true); ::ShowXamlDialog( WindowHandle,