diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index a43e81d077..064e9ec94b 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1527,6 +1527,7 @@ randi RAquadrant rasterization Rasterize +rasterizing RAWINPUTDEVICE RAWINPUTHEADER RAWMODE diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs index 72bca70715..2fad25cec3 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs @@ -16,12 +16,12 @@ namespace Microsoft.CmdPal.UI.Controls; /// public partial class IconBox : ContentControl { + private const double DefaultIconFontSize = 16.0; + private double _lastScale; private ElementTheme _lastTheme; private double _lastFontSize; - private const double DefaultIconFontSize = 16.0; - /// /// Gets or sets the to display within the . Overwritten, if is used instead. /// @@ -62,6 +62,12 @@ public partial class IconBox : ContentControl { Refresh(); } +#if DEBUG + if (_sourceRequested?.GetInvocationList().Length > 1) + { + Logger.LogWarning("There shouldn't be more than one handler for IconBox.SourceRequested"); + } +#endif } remove => _sourceRequested -= value; } @@ -102,9 +108,12 @@ public partial class IconBox : ContentControl if (Source is FontIconSource fontIcon) { fontIcon.FontSize = _lastFontSize; + UpdatePaddingForFontIcon(); } } + private void UpdatePaddingForFontIcon() => Padding = new Thickness(Math.Round(_lastFontSize * -0.2)); + private void OnActualThemeChanged(FrameworkElement sender, object args) { if (_lastTheme == ActualTheme) @@ -150,10 +159,7 @@ public partial class IconBox : ContentControl private void Refresh() { - if (SourceKey is not null) - { - UpdateSourceKey(this, SourceKey); - } + UpdateSourceKey(this, SourceKey); } private static void OnSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -170,8 +176,10 @@ public partial class IconBox : ContentControl self.Padding = default; break; case FontIconSource fontIcon: + self.UpdateLastFontSize(); if (self.Content is IconSourceElement iconSourceElement) { + fontIcon.FontSize = self._lastFontSize; iconSourceElement.IconSource = fontIcon; } else @@ -190,7 +198,7 @@ public partial class IconBox : ContentControl self.Content = elem; } - self.Padding = new Thickness(Math.Round(self._lastFontSize * -0.2)); + self.UpdatePaddingForFontIcon(); break; case BitmapIconSource bitmapIcon: @@ -206,10 +214,12 @@ public partial class IconBox : ContentControl self.Padding = default; break; + case IconSource source: self.Content = source.CreateIconElement(); self.Padding = default; break; + default: throw new InvalidOperationException($"New value of {e.NewValue} is not of type IconSource."); } @@ -233,10 +243,10 @@ public partial class IconBox : ContentControl return; } - Callback(iconBox, sourceKey); + RequestIconFromSource(iconBox, sourceKey); } - private static async void Callback(IconBox iconBox, object? sourceKey) + private static async void RequestIconFromSource(IconBox iconBox, object? sourceKey) { try { @@ -256,17 +266,12 @@ public partial class IconBox : ContentControl // list virtualization situation, it's very possible we // may have already been set to a new icon before we // even got back from the await. - if (eventArgs.Key != sourceKey) + if (!ReferenceEquals(sourceKey, iconBox.SourceKey)) { // If the requested icon has changed, then just bail return; } - if (eventArgs.Value == iconBox.Source) - { - return; - } - iconBox.Source = eventArgs.Value; } catch (Exception ex) diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Helpers/Icons/IconLoaderService.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Helpers/Icons/IconLoaderService.cs index ef93ccb040..6935802b50 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Helpers/Icons/IconLoaderService.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Helpers/Icons/IconLoaderService.cs @@ -219,6 +219,6 @@ internal sealed partial class IconLoaderService : IIconLoaderService iconSize = DefaultIconSize; } - return IconPathConverter.IconSourceMUX(iconString, false, fontFamily, iconSize); + return IconPathConverter.IconSourceMUX(iconString, fontFamily, iconSize); } } diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp index c9ab37e3fc..a1dee068e8 100644 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp +++ b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.cpp @@ -94,40 +94,49 @@ namespace winrt::Microsoft::Terminal::UI::implementation // - : The type of IconSource (MUX, WUX) to generate. // Arguments: // - path: the full, expanded path to the icon. + // - targetSize: the target size for decoding/rasterizing the icon. // Return Value: // - An IconElement with its IconSource set, if possible. template - TIconSource _getColoredBitmapIcon(const winrt::hstring& path, bool monochrome) + TIconSource _getColoredBitmapIcon(const winrt::hstring& path, int targetSize) { // FontIcon uses glyphs in the private use area, whereas valid URIs only contain ASCII characters. // To skip throwing on Uri construction, we can quickly check if the first character is ASCII. - if (!path.empty() && path.front() < 128) + if (path.empty() || path.front() >= 128) { - try - { - winrt::Windows::Foundation::Uri iconUri{ path }; - - if (til::equals_insensitive_ascii(iconUri.Extension(), L".svg")) - { - typename ImageIconSource::type iconSource; - winrt::Microsoft::UI::Xaml::Media::Imaging::SvgImageSource source{ iconUri }; - iconSource.ImageSource(source); - return iconSource; - } - else - { - typename BitmapIconSource::type iconSource; - // Make sure to set this to false, so we keep the RGB data of the - // image. Otherwise, the icon will be white for all the - // non-transparent pixels in the image. - iconSource.ShowAsMonochrome(monochrome); - iconSource.UriSource(iconUri); - return iconSource; - } - } - CATCH_LOG(); + return nullptr; } + try + { + winrt::Windows::Foundation::Uri iconUri{ path }; + + if (til::equals_insensitive_ascii(iconUri.Extension(), L".svg")) + { + typename ImageIconSource::type iconSource; + winrt::Microsoft::UI::Xaml::Media::Imaging::SvgImageSource source{ iconUri }; + source.RasterizePixelWidth(static_cast(targetSize)); + // Set only single dimension here; the image might not be square and + // this will preserve the aspect ratio (for the price of keeping height unbound). + // source.RasterizePixelHeight(static_cast(targetSize)); + iconSource.ImageSource(source); + return iconSource; + } + else + { + typename ImageIconSource::type iconSource; + winrt::Microsoft::UI::Xaml::Media::Imaging::BitmapImage bitmapImage; + bitmapImage.DecodePixelWidth(targetSize); + // Set only single dimension here; the image might not be square and + // this will preserve the aspect ratio (for the price of keeping height unbound). + // bitmapImage.DecodePixelHeight(targetSize); + bitmapImage.UriSource(iconUri); + iconSource.ImageSource(bitmapImage); + return iconSource; + } + } + CATCH_LOG(); + return nullptr; } @@ -158,14 +167,14 @@ namespace winrt::Microsoft::Terminal::UI::implementation // Return Value: // - An IconElement with its IconSource set, if possible. template - TIconSource _getIconSource(const winrt::hstring& iconPath, bool monochrome, const winrt::hstring& fontFamily, const int targetSize) + TIconSource _getIconSource(const winrt::hstring& iconPath, const winrt::hstring& fontFamily, const int targetSize) { TIconSource iconSource{ nullptr }; if (iconPath.size() != 0) { const auto expandedIconPath{ _expandIconPath(iconPath) }; - iconSource = _getColoredBitmapIcon(expandedIconPath, monochrome); + iconSource = _getColoredBitmapIcon(expandedIconPath, targetSize); // If we fail to set the icon source using the "icon" as a path, // let's try it as a symbol/emoji. @@ -235,9 +244,9 @@ namespace winrt::Microsoft::Terminal::UI::implementation // return _getIconSource(path, false); // } - static Microsoft::UI::Xaml::Controls::IconSource _IconSourceMUX(const hstring& path, bool monochrome, const winrt::hstring& fontFamily, const int targetSize) + static Microsoft::UI::Xaml::Controls::IconSource _IconSourceMUX(const hstring& path, const winrt::hstring& fontFamily, const int targetSize) { - return _getIconSource(path, monochrome, fontFamily, targetSize); + return _getIconSource(path, fontFamily, targetSize); } static SoftwareBitmap _convertToSoftwareBitmap(HICON hicon, @@ -352,7 +361,6 @@ namespace winrt::Microsoft::Terminal::UI::implementation } MUX::Controls::IconSource IconPathConverter::IconSourceMUX(const winrt::hstring& iconPath, - const bool monochrome, const winrt::hstring& fontFamily, const int targetSize) { @@ -360,7 +368,7 @@ namespace winrt::Microsoft::Terminal::UI::implementation const auto indexOpt = _getIconIndex(iconPath, iconPathWithoutIndex); if (!indexOpt.has_value()) { - return _IconSourceMUX(iconPath, monochrome, fontFamily, targetSize); + return _IconSourceMUX(iconPath, fontFamily, targetSize); } const auto bitmapSource = _getImageIconSourceForBinary(iconPathWithoutIndex, indexOpt.value(), targetSize); @@ -374,13 +382,14 @@ namespace winrt::Microsoft::Terminal::UI::implementation Microsoft::UI::Xaml::Controls::IconElement IconPathConverter::IconMUX(const winrt::hstring& iconPath) { return IconMUX(iconPath, 24); } + Microsoft::UI::Xaml::Controls::IconElement IconPathConverter::IconMUX(const winrt::hstring& iconPath, const int targetSize) { std::wstring_view iconPathWithoutIndex; const auto indexOpt = _getIconIndex(iconPath, iconPathWithoutIndex); if (!indexOpt.has_value()) { - auto source = IconSourceMUX(iconPath, false, L"", targetSize); + auto source = IconSourceMUX(iconPath, L"", targetSize); Microsoft::UI::Xaml::Controls::IconSourceElement icon; icon.IconSource(source); return icon; diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h index 8f504eb8c7..de3698a923 100644 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h +++ b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.h @@ -10,7 +10,7 @@ namespace winrt::Microsoft::Terminal::UI::implementation //static Windows::UI::Xaml::Controls::IconElement IconWUX(const winrt::hstring& iconPath); //static Windows::UI::Xaml::Controls::IconSource IconSourceWUX(const winrt::hstring& iconPath); - static Microsoft::UI::Xaml::Controls::IconSource IconSourceMUX(const winrt::hstring& iconPath, bool convertToGrayscale, const winrt::hstring& fontFamily, const int targetSize=24); + static Microsoft::UI::Xaml::Controls::IconSource IconSourceMUX(const winrt::hstring& iconPath, const winrt::hstring& fontFamily, const int targetSize=24); static Microsoft::UI::Xaml::Controls::IconElement IconMUX(const winrt::hstring& iconPath); static Microsoft::UI::Xaml::Controls::IconElement IconMUX(const winrt::hstring& iconPath, const int targetSize); diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.idl b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.idl index 38aabcf822..41bde322b9 100644 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.idl +++ b/src/modules/cmdpal/Microsoft.Terminal.UI/IconPathConverter.idl @@ -7,7 +7,7 @@ namespace Microsoft.Terminal.UI { // static Windows.UI.Xaml.Controls.IconElement IconWUX(String path); // static Windows.UI.Xaml.Controls.IconSource IconSourceWUX(String path); - static Microsoft.UI.Xaml.Controls.IconSource IconSourceMUX(String path, Boolean convertToGrayscale, String fontFamily, Int32 targetSize); + static Microsoft.UI.Xaml.Controls.IconSource IconSourceMUX(String path, String fontFamily, Int32 targetSize); static Microsoft.UI.Xaml.Controls.IconElement IconMUX(String path); static Microsoft.UI.Xaml.Controls.IconElement IconMUX(String path, Int32 targetSize); };