Add an Appearances xaml object and AppearanceViewModel to TSE (#10066)

Implements an `Appearances` xaml object and an `AppearanceViewModel` in the SettingsEditor project. Updates `Profiles` to use these new objects for its default appearance. 

This is the first step towards getting `UnfocusedAppearance` into the SUI.
This commit is contained in:
PankajBhojwani 2021-07-09 13:43:58 -07:00 committed by GitHub
parent a89746a869
commit c18e0f5008
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 1118 additions and 858 deletions

View file

@ -0,0 +1,360 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Appearances.h"
#include "Appearances.g.cpp"
#include "EnumEntry.h"
#include <LibraryResources.h>
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Data;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) :
_appearance{ appearance }
{
// Add a property changed handler to our own property changed event.
// This propagates changes from the settings model to anybody listening to our
// unique view model members.
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
const auto viewModelProperty{ args.PropertyName() };
if (viewModelProperty == L"BackgroundImagePath")
{
// notify listener that all background image related values might have changed
//
// We need to do this so if someone manually types "desktopWallpaper"
// into the path TextBox, we properly update the checkbox and stored
// _lastBgImagePath. Without this, then we'll permanently hide the text
// box, prevent it from ever being changed again.
_NotifyChanges(L"UseDesktopBGImage", L"BackgroundImageSettingsVisible");
}
});
// Cache the original BG image path. If the user clicks "Use desktop
// wallpaper", then un-checks it, this is the string we'll restore to
// them.
if (BackgroundImagePath() != L"desktopWallpaper")
{
_lastBgImagePath = BackgroundImagePath();
}
}
bool AppearanceViewModel::UseDesktopBGImage()
{
return BackgroundImagePath() == L"desktopWallpaper";
}
void AppearanceViewModel::UseDesktopBGImage(const bool useDesktop)
{
if (useDesktop)
{
// Stash the current value of BackgroundImagePath. If the user
// checks and un-checks the "Use desktop wallpaper" button, we want
// the path that we display in the text box to remain unchanged.
//
// Only stash this value if it's not the special "desktopWallpaper"
// value.
if (BackgroundImagePath() != L"desktopWallpaper")
{
_lastBgImagePath = BackgroundImagePath();
}
BackgroundImagePath(L"desktopWallpaper");
}
else
{
// Restore the path we had previously cached. This might be the
// empty string.
BackgroundImagePath(_lastBgImagePath);
}
}
bool AppearanceViewModel::BackgroundImageSettingsVisible()
{
return BackgroundImagePath() != L"";
}
DependencyProperty Appearances::_AppearanceProperty{ nullptr };
Appearances::Appearances() :
_ShowAllFonts{ false },
_ColorSchemeList{ single_threaded_observable_vector<ColorScheme>() }
{
InitializeComponent();
INITIALIZE_BINDABLE_ENUM_SETTING(CursorShape, CursorStyle, winrt::Microsoft::Terminal::Core::CursorStyle, L"Profile_CursorShape", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(BackgroundImageStretchMode, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch, L"Profile_BackgroundImageStretchMode", L"Content");
// manually add Custom FontWeight option. Don't add it to the Map
INITIALIZE_BINDABLE_ENUM_SETTING(FontWeight, FontWeight, uint16_t, L"Profile_FontWeight", L"Content");
_CustomFontWeight = winrt::make<EnumEntry>(RS_(L"Profile_FontWeightCustom/Content"), winrt::box_value<uint16_t>(0u));
_FontWeightList.Append(_CustomFontWeight);
if (!_AppearanceProperty)
{
_AppearanceProperty =
DependencyProperty::Register(
L"Appearance",
xaml_typename<Editor::AppearanceViewModel>(),
xaml_typename<Editor::Appearances>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &Appearances::_ViewModelChanged } });
}
// manually keep track of all the Background Image Alignment buttons
_BIAlignmentButtons.at(0) = BIAlign_TopLeft();
_BIAlignmentButtons.at(1) = BIAlign_Top();
_BIAlignmentButtons.at(2) = BIAlign_TopRight();
_BIAlignmentButtons.at(3) = BIAlign_Left();
_BIAlignmentButtons.at(4) = BIAlign_Center();
_BIAlignmentButtons.at(5) = BIAlign_Right();
_BIAlignmentButtons.at(6) = BIAlign_BottomLeft();
_BIAlignmentButtons.at(7) = BIAlign_Bottom();
_BIAlignmentButtons.at(8) = BIAlign_BottomRight();
// apply automation properties to more complex setting controls
for (const auto& biButton : _BIAlignmentButtons)
{
const auto tooltip{ ToolTipService::GetToolTip(biButton) };
Automation::AutomationProperties::SetName(biButton, unbox_value<hstring>(tooltip));
}
const auto showAllFontsCheckboxTooltip{ ToolTipService::GetToolTip(ShowAllFontsCheckbox()) };
Automation::AutomationProperties::SetFullDescription(ShowAllFontsCheckbox(), unbox_value<hstring>(showAllFontsCheckboxTooltip));
const auto backgroundImgCheckboxTooltip{ ToolTipService::GetToolTip(UseDesktopImageCheckBox()) };
Automation::AutomationProperties::SetFullDescription(UseDesktopImageCheckBox(), unbox_value<hstring>(backgroundImgCheckboxTooltip));
}
// Method Description:
// - Searches through our list of monospace fonts to determine if the settings model's current font face is a monospace font
bool Appearances::UsingMonospaceFont() const noexcept
{
bool result{ false };
const auto currentFont{ Appearance().FontFace() };
for (const auto& font : SourceProfile().MonospaceFontList())
{
if (font.LocalizedName() == currentFont)
{
result = true;
}
}
return result;
}
// Method Description:
// - Determines whether we should show the list of all the fonts, or we should just show monospace fonts
bool Appearances::ShowAllFonts() const noexcept
{
// - _ShowAllFonts is directly bound to the checkbox. So this is the user set value.
// - If we are not using a monospace font, show all of the fonts so that the ComboBox is still properly bound
return _ShowAllFonts || !UsingMonospaceFont();
}
void Appearances::ShowAllFonts(const bool& value)
{
if (_ShowAllFonts != value)
{
_ShowAllFonts = value;
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
}
}
IInspectable Appearances::CurrentFontFace() const
{
// look for the current font in our shown list of fonts
const auto& appearanceVM{ Appearance() };
const auto appearanceFontFace{ appearanceVM.FontFace() };
const auto& currentFontList{ ShowAllFonts() ? SourceProfile().CompleteFontList() : SourceProfile().MonospaceFontList() };
IInspectable fallbackFont;
for (const auto& font : currentFontList)
{
if (font.LocalizedName() == appearanceFontFace)
{
return box_value(font);
}
else if (font.LocalizedName() == L"Cascadia Mono")
{
fallbackFont = box_value(font);
}
}
// we couldn't find the desired font, set to "Cascadia Mono" since that ships by default
return fallbackFont;
}
void Appearances::FontFace_SelectionChanged(IInspectable const& /*sender*/, SelectionChangedEventArgs const& e)
{
// NOTE: We need to hook up a selection changed event handler here instead of directly binding to the appearance view model.
// A two way binding to the view model causes an infinite loop because both combo boxes keep fighting over which one's right.
const auto selectedItem{ e.AddedItems().GetAt(0) };
const auto newFontFace{ unbox_value<Editor::Font>(selectedItem) };
Appearance().FontFace(newFontFace.LocalizedName());
}
void Appearances::_ViewModelChanged(DependencyObject const& d, DependencyPropertyChangedEventArgs const& /*args*/)
{
const auto& obj{ d.as<Editor::Appearances>() };
get_self<Appearances>(obj)->_UpdateWithNewViewModel();
}
void Appearances::_UpdateWithNewViewModel()
{
if (Appearance())
{
const auto& colorSchemeMap{ Appearance().Schemes() };
for (const auto& pair : colorSchemeMap)
{
_ColorSchemeList.Append(pair.Value());
}
const auto& biAlignmentVal{ static_cast<int32_t>(Appearance().BackgroundImageAlignment()) };
for (const auto& biButton : _BIAlignmentButtons)
{
biButton.IsChecked(biButton.Tag().as<int32_t>() == biAlignmentVal);
}
_ViewModelChangedRevoker = Appearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
const auto settingName{ args.PropertyName() };
if (settingName == L"CursorShape")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCursorShape" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsVintageCursor" });
}
else if (settingName == L"ColorSchemeName")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentColorScheme" });
}
else if (settingName == L"BackgroundImageStretchMode")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentBackgroundImageStretchMode" });
}
else if (settingName == L"BackgroundImageAlignment")
{
_UpdateBIAlignmentControl(static_cast<int32_t>(Appearance().BackgroundImageAlignment()));
}
else if (settingName == L"FontWeight")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontWeight" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
}
else if (settingName == L"FontFace" || settingName == L"CurrentFontList")
{
// notify listener that all font face related values might have changed
if (!UsingMonospaceFont())
{
_ShowAllFonts = true;
}
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontFace" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"ShowAllFonts" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"UsingMonospaceFont" });
}
});
}
}
fire_and_forget Appearances::BackgroundImage_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(Appearance().WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
Appearance().BackgroundImagePath(file);
}
}
void Appearances::BIAlignment_Click(IInspectable const& sender, RoutedEventArgs const& /*e*/)
{
if (const auto& button{ sender.try_as<Primitives::ToggleButton>() })
{
if (const auto& tag{ button.Tag().try_as<int32_t>() })
{
// Update the Appearance's value and the control
Appearance().BackgroundImageAlignment(static_cast<ConvergedAlignment>(*tag));
_UpdateBIAlignmentControl(*tag);
}
}
}
// Method Description:
// - Resets all of the buttons to unchecked, and checks the one with the provided tag
// Arguments:
// - val - the background image alignment (ConvergedAlignment) that we want to represent in the control
void Appearances::_UpdateBIAlignmentControl(const int32_t val)
{
for (const auto& biButton : _BIAlignmentButtons)
{
if (const auto& biButtonAlignment{ biButton.Tag().try_as<int32_t>() })
{
biButton.IsChecked(biButtonAlignment == val);
}
}
}
ColorScheme Appearances::CurrentColorScheme()
{
const auto schemeName{ Appearance().ColorSchemeName() };
if (const auto scheme{ Appearance().Schemes().TryLookup(schemeName) })
{
return scheme;
}
else
{
// This Appearance points to a color scheme that was renamed or deleted.
// Fallback to Campbell.
return Appearance().Schemes().TryLookup(L"Campbell");
}
}
void Appearances::CurrentColorScheme(const ColorScheme& val)
{
Appearance().ColorSchemeName(val.Name());
}
bool Appearances::IsVintageCursor() const
{
return Appearance().CursorShape() == Core::CursorStyle::Vintage;
}
IInspectable Appearances::CurrentFontWeight() const
{
// if no value was found, we have a custom value
const auto maybeEnumEntry{ _FontWeightMap.TryLookup(Appearance().FontWeight().Weight) };
return maybeEnumEntry ? maybeEnumEntry : _CustomFontWeight;
}
void Appearances::CurrentFontWeight(const IInspectable& enumEntry)
{
if (auto ee = enumEntry.try_as<Editor::EnumEntry>())
{
if (ee != _CustomFontWeight)
{
const auto weight{ winrt::unbox_value<uint16_t>(ee.EnumValue()) };
const Windows::UI::Text::FontWeight setting{ weight };
Appearance().FontWeight(setting);
// Appearance does not have observable properties
// So the TwoWay binding doesn't update on the State --> Slider direction
FontWeightSlider().Value(weight);
}
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
}
}
bool Appearances::IsCustomFontWeight()
{
// Use SelectedItem instead of CurrentFontWeight.
// CurrentFontWeight converts the Appearance's value to the appropriate enum entry,
// whereas SelectedItem identifies which one was selected by the user.
return FontWeightComboBox().SelectedItem() == _CustomFontWeight;
}
}

View file

@ -0,0 +1,142 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Appearances
Abstract:
- The classes defined in this module are responsible for encapsulating the appearance settings
of profiles and presenting them in the settings UI
Author(s):
- Pankaj Bhojwani - May 2021
--*/
#pragma once
#include "Font.g.h"
#include "Appearances.g.h"
#include "AppearanceViewModel.g.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
#include "SettingContainer.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct FontComparator
{
bool operator()(const Font& lhs, const Font& rhs) const
{
return lhs.LocalizedName() < rhs.LocalizedName();
}
};
struct Font : FontT<Font>
{
public:
Font(std::wstring name, std::wstring localizedName) :
_Name{ name },
_LocalizedName{ localizedName } {};
hstring ToString() { return _LocalizedName; }
WINRT_PROPERTY(hstring, Name);
WINRT_PROPERTY(hstring, LocalizedName);
};
struct AppearanceViewModel : AppearanceViewModelT<AppearanceViewModel>, ViewModelHelper<AppearanceViewModel>
{
public:
AppearanceViewModel(const Model::AppearanceConfig& appearance);
// background image
bool UseDesktopBGImage();
void UseDesktopBGImage(const bool useDesktop);
bool BackgroundImageSettingsVisible();
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> Schemes() { return _Schemes; }
void Schemes(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& val) { _Schemes = val; }
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
// These settings are not defined in AppearanceConfig, so we grab them
// from the source profile itself. The reason we still want them in the
// AppearanceViewModel is so we can continue to have the 'Text' grouping
// we currently have in xaml, since that grouping has some settings that
// are defined in AppearanceConfig and some that are not.
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontFace);
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontSize);
OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontWeight);
OBSERVABLE_PROJECTED_SETTING(_appearance, RetroTerminalEffect);
OBSERVABLE_PROJECTED_SETTING(_appearance, CursorShape);
OBSERVABLE_PROJECTED_SETTING(_appearance, CursorHeight);
OBSERVABLE_PROJECTED_SETTING(_appearance, ColorSchemeName);
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImagePath);
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageOpacity);
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_SETTING(_appearance, BackgroundImageAlignment);
private:
Model::AppearanceConfig _appearance;
winrt::hstring _lastBgImagePath;
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
};
struct Appearances : AppearancesT<Appearances>
{
public:
Appearances();
// font face
Windows::Foundation::IInspectable CurrentFontFace() const;
// CursorShape visibility logic
bool IsVintageCursor() const;
Model::ColorScheme CurrentColorScheme();
void CurrentColorScheme(const Model::ColorScheme& val);
bool UsingMonospaceFont() const noexcept;
bool ShowAllFonts() const noexcept;
void ShowAllFonts(const bool& value);
fire_and_forget BackgroundImage_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void BIAlignment_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void FontFace_SelectionChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& e);
// manually bind FontWeight
Windows::Foundation::IInspectable CurrentFontWeight() const;
void CurrentFontWeight(const Windows::Foundation::IInspectable& enumEntry);
bool IsCustomFontWeight();
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Microsoft::Terminal::Settings::Editor::EnumEntry>, FontWeightList);
GETSET_BINDABLE_ENUM_SETTING(CursorShape, Microsoft::Terminal::Core::CursorStyle, Appearance, CursorShape);
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Model::ColorScheme>, ColorSchemeList, nullptr);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
DEPENDENCY_PROPERTY(Editor::AppearanceViewModel, Appearance);
WINRT_PROPERTY(Editor::ProfileViewModel, SourceProfile, nullptr);
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance, BackgroundImageStretchMode);
private:
bool _ShowAllFonts;
void _UpdateBIAlignmentControl(const int32_t val);
std::array<Windows::UI::Xaml::Controls::Primitives::ToggleButton, 9> _BIAlignmentButtons;
Windows::Foundation::Collections::IMap<uint16_t, Microsoft::Terminal::Settings::Editor::EnumEntry> _FontWeightMap;
Editor::EnumEntry _CustomFontWeight{ nullptr };
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
static void _ViewModelChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e);
void _UpdateWithNewViewModel();
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Appearances);
}

View file

@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "EnumEntry.idl";
import "MainPage.idl";
import "Profiles.idl";
#include "ViewModelHelpers.idl.h"
#define OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Type, Name) \
OBSERVABLE_PROJECTED_SETTING(Type, Name); \
Object Name##OverrideSource { get; }
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass Font : Windows.Foundation.IStringable
{
String Name { get; };
String LocalizedName { get; };
}
runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Boolean UseDesktopBGImage;
Boolean BackgroundImageSettingsVisible { get; };
Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes;
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Int32, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, ColorSchemeName);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, RetroTerminalEffect);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Core.CursorStyle, CursorShape);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(UInt32, CursorHeight);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, BackgroundImagePath);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, BackgroundImageOpacity);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
}
[default_interface] runtimeclass Appearances : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Appearances();
AppearanceViewModel Appearance;
ProfileViewModel SourceProfile;
static Windows.UI.Xaml.DependencyProperty AppearanceProperty { get; };
Boolean UsingMonospaceFont { get; };
Boolean ShowAllFonts;
IInspectable CurrentCursorShape;
Boolean IsVintageCursor { get; };
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CursorShapeList { get; };
Microsoft.Terminal.Settings.Model.ColorScheme CurrentColorScheme;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Model.ColorScheme> ColorSchemeList { get; };
IInspectable CurrentBackgroundImageStretchMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> BackgroundImageStretchModeList { get; };
IInspectable CurrentFontWeight;
Boolean IsCustomFontWeight { get; };
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> FontWeightList { get; };
IInspectable CurrentFontFace { get; };
}
}

View file

@ -0,0 +1,439 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<UserControl x:Class="Microsoft.Terminal.Settings.Editor.Appearances"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Microsoft.Terminal.Settings.Model"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
IsTabStop="False"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="EnumRadioButtonTemplate"
x:DataType="local:EnumEntry">
<RadioButton Content="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="EnumComboBoxItemTemplate"
x:DataType="local:EnumEntry">
<TextBlock Text="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="FontFaceComboBoxItemTemplate"
x:DataType="local:Font">
<TextBlock FontFamily="{x:Bind Name}"
Text="{x:Bind LocalizedName}" />
</DataTemplate>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:PercentageConverter x:Key="PercentageConverter" />
<local:PercentageSignConverter x:Key="PercentageSignConverter" />
<local:FontWeightConverter x:Key="FontWeightConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<local:StringIsEmptyConverter x:Key="StringIsEmptyConverter" />
<local:PaddingConverter x:Key="PaddingConverter" />
<local:StringIsNotDesktopConverter x:Key="StringIsNotDesktopConverter" />
<local:DesktopWallpaperToEmptyStringConverter x:Key="DesktopWallpaperToEmptyStringConverter" />
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Grouping: Text -->
<TextBlock x:Uid="Profile_TextHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Color Scheme -->
<local:SettingContainer x:Uid="Profile_ColorScheme"
Margin="0"
ClearSettingValue="{x:Bind Appearance.ClearColorSchemeName}"
HasSettingValue="{x:Bind Appearance.HasColorSchemeName, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.ColorSchemeNameOverrideSource, Mode=OneWay}">
<ComboBox ItemsSource="{x:Bind ColorSchemeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentColorScheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:ColorScheme">
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Font Face -->
<local:SettingContainer x:Uid="Profile_FontFace"
ClearSettingValue="{x:Bind Appearance.ClearFontFace}"
HasSettingValue="{x:Bind Appearance.HasFontFace, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontFaceOverrideSource, Mode=OneWay}">
<StackPanel>
<!--
Binding the ItemsSource to a separate variable that switches between the
two font lists causes a crash within the ComboBox code.
As a workaround, introduce two ComboBox controls and only display one at a time.
-->
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind SourceProfile.MonospaceFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind ShowAllFonts, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind SourceProfile.CompleteFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind ShowAllFonts, Mode=OneWay}" />
<CheckBox x:Name="ShowAllFontsCheckbox"
x:Uid="Profile_FontFaceShowAllFonts"
IsChecked="{x:Bind ShowAllFonts, Mode=TwoWay}"
IsEnabled="{x:Bind UsingMonospaceFont, Mode=OneWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Font Size -->
<local:SettingContainer x:Uid="Profile_FontSize"
ClearSettingValue="{x:Bind Appearance.ClearFontSize}"
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox AcceptsExpression="False"
LargeChange="10"
Maximum="128"
Minimum="1"
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind Appearance.FontSize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Font Weight -->
<local:SettingContainer x:Name="FontWeightContainer"
x:Uid="Profile_FontWeight"
ClearSettingValue="{x:Bind Appearance.ClearFontWeight}"
HasSettingValue="{x:Bind Appearance.HasFontWeight, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontWeightOverrideSource, Mode=OneWay}">
<StackPanel>
<ComboBox x:Name="FontWeightComboBox"
ItemTemplate="{StaticResource EnumComboBoxItemTemplate}"
ItemsSource="{x:Bind FontWeightList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontWeight, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<!-- Custom Font Weight Control -->
<Grid Margin="0,10,0,0"
Style="{StaticResource CustomSliderControlGridStyle}"
Visibility="{x:Bind IsCustomFontWeight, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="FontWeightSlider"
Grid.Column="0"
Maximum="1000"
Minimum="0"
TickFrequency="50"
TickPlacement="Outside"
Value="{x:Bind Appearance.FontWeight, Converter={StaticResource FontWeightConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Margin="10,0,0,0"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=FontWeightSlider, Path=Value, Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Retro Terminal Effect -->
<local:SettingContainer x:Uid="Profile_RetroTerminalEffect"
ClearSettingValue="{x:Bind Appearance.ClearRetroTerminalEffect}"
HasSettingValue="{x:Bind Appearance.HasRetroTerminalEffect, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Appearance.RetroTerminalEffect, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Cursor -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_CursorHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Cursor Shape -->
<local:SettingContainer x:Uid="Profile_CursorShape"
Margin="0"
ClearSettingValue="{x:Bind Appearance.ClearCursorShape}"
HasSettingValue="{x:Bind Appearance.HasCursorShape, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.CursorShapeOverrideSource, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind CursorShapeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentCursorShape, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Cursor Height -->
<local:SettingContainer x:Uid="Profile_CursorHeight"
ClearSettingValue="{x:Bind Appearance.ClearCursorHeight}"
HasSettingValue="{x:Bind Appearance.HasCursorHeight, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.CursorHeightOverrideSource, Mode=OneWay}"
Visibility="{x:Bind IsVintageCursor, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="CursorHeightSlider"
Grid.Column="0"
Maximum="100"
Minimum="1"
Value="{x:Bind Appearance.CursorHeight, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=CursorHeightSlider, Path=Value, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Background -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_BackgroundHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Background Image -->
<local:SettingContainer x:Name="BackgroundImageContainer"
x:Uid="Profile_BackgroundImage"
Margin="0"
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImagePath}"
HasSettingValue="{x:Bind Appearance.HasBackgroundImagePath, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundImagePathOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Appearance.BackgroundImagePath, Mode=TwoWay, Converter={StaticResource DesktopWallpaperToEmptyStringConverter}}" />
<Button x:Uid="Profile_BackgroundImageBrowse"
Click="BackgroundImage_Click"
IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="UseDesktopImageCheckBox"
x:Uid="Profile_UseDesktopImage"
IsChecked="{x:Bind Appearance.UseDesktopBGImage, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Background Image Stretch Mode -->
<local:SettingContainer x:Uid="Profile_BackgroundImageStretchMode"
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageStretchMode}"
HasSettingValue="{x:Bind Appearance.HasBackgroundImageStretchMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundImageStretchModeOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind BackgroundImageStretchModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentBackgroundImageStretchMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Background Image Alignment -->
<local:SettingContainer x:Uid="Profile_BackgroundImageAlignment"
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageAlignment}"
HasSettingValue="{x:Bind Appearance.HasBackgroundImageAlignment, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundImageAlignmentOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
<Grid HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style BasedOn="{StaticResource DefaultToggleButtonStyle}"
TargetType="ToggleButton">
<Setter Property="Margin" Value="2" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="40" />
<Setter Property="ToolTipService.Placement" Value="Mouse" />
</Style>
</Grid.Resources>
<!-- Top Row -->
<ToggleButton x:Name="BIAlign_TopLeft"
x:Uid="Profile_BackgroundImageAlignmentTopLeft"
Grid.Row="0"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Left (0x01) -->
<x:Int32>17</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE744;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="90" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Top"
x:Uid="Profile_BackgroundImageAlignmentTop"
Grid.Row="0"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Center (0x00) -->
<x:Int32>16</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE745;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="180" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_TopRight"
x:Uid="Profile_BackgroundImageAlignmentTopRight"
Grid.Row="0"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Right (0x02) -->
<x:Int32>18</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA5F;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="270" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<!-- Middle Row -->
<ToggleButton x:Name="BIAlign_Left"
x:Uid="Profile_BackgroundImageAlignmentLeft"
Grid.Row="1"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Left (0x01) -->
<x:Int32>1</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE746;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Center"
x:Uid="Profile_BackgroundImageAlignmentCenter"
Grid.Row="1"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Center (0x00) -->
<x:Int32>0</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xF16E;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Right"
x:Uid="Profile_BackgroundImageAlignmentRight"
Grid.Row="1"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Right (0x02) -->
<x:Int32>2</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA61;" />
</ToggleButton.Content>
</ToggleButton>
<!-- Bottom Row -->
<ToggleButton x:Name="BIAlign_BottomLeft"
x:Uid="Profile_BackgroundImageAlignmentBottomLeft"
Grid.Row="2"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Left (0x01) -->
<x:Int32>33</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE744;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Bottom"
x:Uid="Profile_BackgroundImageAlignmentBottom"
Grid.Row="2"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Center (0x00) -->
<x:Int32>32</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE745;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_BottomRight"
x:Uid="Profile_BackgroundImageAlignmentBottomRight"
Grid.Row="2"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x20) | Horizontal_Right (0x02) -->
<x:Int32>34</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA5F;" />
</ToggleButton.Content>
</ToggleButton>
</Grid>
</local:SettingContainer>
<!-- Background Image Opacity -->
<local:SettingContainer x:Name="BackgroundImageOpacityContainer"
x:Uid="Profile_BackgroundImageOpacity"
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageOpacity}"
HasSettingValue="{x:Bind Appearance.HasBackgroundImageOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundImageOpacityOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.BackgroundImageSettingsVisible, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="BIOpacitySlider"
Grid.Column="0"
Value="{x:Bind Appearance.BackgroundImageOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=BIOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
</Grid>
</local:SettingContainer>
</StackPanel>
</StackPanel>
</UserControl>

View file

@ -99,6 +99,10 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Appearances.h">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="ReadOnlyActions.h">
<DependentUpon>ReadOnlyActions.xaml</DependentUpon>
</ClInclude>
@ -143,6 +147,9 @@
<Page Include="ReadOnlyActions.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Appearances.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Rendering.xaml">
<SubType>Designer</SubType>
</Page>
@ -215,6 +222,10 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Appearances.cpp">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="ReadOnlyActions.cpp">
<DependentUpon>ReadOnlyActions.xaml</DependentUpon>
</ClCompile>
@ -272,6 +283,10 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Appearances.idl">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="SettingContainer.idl">
<SubType>Code</SubType>
</Midl>

View file

@ -40,6 +40,7 @@
<Page Include="Launch.xaml" />
<Page Include="MainPage.xaml" />
<Page Include="Profiles.xaml" />
<Page Include="Appearances.xaml" />
<Page Include="Rendering.xaml" />
<Page Include="Actions.xaml" />
<Page Include="SettingContainerStyle.xaml" />

View file

@ -23,64 +23,6 @@ static const std::array<winrt::guid, 2> InBoxProfileGuids{
winrt::guid{ 0x0caa0dad, 0x35be, 0x5f56, { 0xa8, 0xff, 0xaf, 0xce, 0xee, 0xaa, 0x61, 0x01 } } // Command Prompt
};
// Function Description:
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
// Parameters:
// - customize: A lambda that receives an IFileDialog* to customize.
// Return value:
// (async) path to the selected item.
template<typename TLambda>
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
{
auto fileDialog{ winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
DWORD flags{};
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
customize(fileDialog.get());
auto hr{ fileDialog->Show(parentHwnd) };
if (!SUCCEEDED(hr))
{
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
co_return winrt::hstring{};
}
THROW_HR(hr);
}
winrt::com_ptr<IShellItem> result;
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
wil::unique_cotaskmem_string filePath;
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
co_return winrt::hstring{ filePath.get() };
}
// Function Description:
// - Helper that opens a file picker pre-seeded with image file types.
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
{
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
{ L"All Files (*.*)", L"*.*" }
};
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
try
{
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(pictureFolderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
});
}
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
@ -88,8 +30,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings) :
_profile{ profile },
_defaultAppearanceViewModel{ winrt::make<implementation::AppearanceViewModel>(profile.DefaultAppearance().try_as<AppearanceConfig>()) },
_originalProfileGuid{ profile.Guid() },
_ShowAllFonts{ false },
_appSettings{ appSettings }
{
// Add a property changed handler to our own property changed event.
@ -97,17 +39,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// unique view model members.
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
const auto viewModelProperty{ args.PropertyName() };
if (viewModelProperty == L"BackgroundImagePath")
{
// notify listener that all background image related values might have changed
//
// We need to do this so if someone manually types "desktopWallpaper"
// into the path TextBox, we properly update the checkbox and stored
// _lastBgImagePath. Without this, then we'll permanently hide the text
// box, prevent it from ever being changed again.
_NotifyChanges(L"UseDesktopBGImage", L"BackgroundImageSettingsVisible");
}
else if (viewModelProperty == L"IsBaseLayer")
if (viewModelProperty == L"IsBaseLayer")
{
// we _always_ want to show the background image settings in base layer
_NotifyChanges(L"BackgroundImageSettingsVisible");
@ -118,25 +50,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// NOTE: this is similar to what is done with BackgroundImagePath above
_NotifyChanges(L"UseParentProcessDirectory", L"UseCustomStartingDirectory");
}
else if (viewModelProperty == L"FontFace")
{
// notify listener that all font face related values might have changed
if (!UsingMonospaceFont())
{
_ShowAllFonts = true;
}
_NotifyChanges(L"ShowAllFonts", L"UsingMonospaceFont");
}
});
// Cache the original BG image path. If the user clicks "Use desktop
// wallpaper", then un-checks it, this is the string we'll restore to
// them.
if (BackgroundImagePath() != L"desktopWallpaper")
{
_lastBgImagePath = BackgroundImagePath();
}
// Do the same for the starting directory
if (!StartingDirectory().empty())
{
@ -291,41 +206,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _MonospaceFontList;
}
// Method Description:
// - Searches through our list of monospace fonts to determine if the settings model's current font face is a monospace font
// - NOTE: This is information stored from DWrite in _UpdateFontList()
bool ProfileViewModel::UsingMonospaceFont() const noexcept
{
bool result{ false };
const auto currentFont{ FontFace() };
for (const auto& font : _MonospaceFontList)
{
if (font.LocalizedName() == currentFont)
{
result = true;
}
}
return result;
}
// Method Description:
// - Determines whether we should show the list of all the fonts, or we should just show monospace fonts
bool ProfileViewModel::ShowAllFonts() const noexcept
{
// - _ShowAllFonts is directly bound to the checkbox. So this is the user set value.
// - If we are not using a monospace font, show all of the fonts so that the ComboBox is still properly bound
return _ShowAllFonts || !UsingMonospaceFont();
}
void ProfileViewModel::ShowAllFonts(const bool& value)
{
if (_ShowAllFonts != value)
{
_ShowAllFonts = value;
_NotifyChanges(L"ShowAllFonts");
}
}
winrt::guid ProfileViewModel::OriginalProfileGuid() const noexcept
{
return _originalProfileGuid;
@ -354,33 +234,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
bool ProfileViewModel::UseDesktopBGImage()
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance()
{
return BackgroundImagePath() == L"desktopWallpaper";
}
void ProfileViewModel::UseDesktopBGImage(const bool useDesktop)
{
if (useDesktop)
{
// Stash the current value of BackgroundImagePath. If the user
// checks and un-checks the "Use desktop wallpaper" button, we want
// the path that we display in the text box to remain unchanged.
//
// Only stash this value if it's not the special "desktopWallpaper"
// value.
if (BackgroundImagePath() != L"desktopWallpaper")
{
_lastBgImagePath = BackgroundImagePath();
}
BackgroundImagePath(L"desktopWallpaper");
}
else
{
// Restore the path we had previously cached. This might be the
// empty string.
BackgroundImagePath(_lastBgImagePath);
}
return _defaultAppearanceViewModel;
}
bool ProfileViewModel::UseParentProcessDirectory()
@ -429,11 +285,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
bool ProfileViewModel::BackgroundImageSettingsVisible()
{
return IsBaseLayer() || BackgroundImagePath() != L"";
}
void ProfilePageNavigationState::DeleteProfile()
{
auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(_Profile.Guid()) };
@ -441,49 +292,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
Profiles::Profiles() :
_ColorSchemeList{ single_threaded_observable_vector<ColorScheme>() },
_previewControl{ Control::TermControl(Model::TerminalSettings{}, make<PreviewConnection>()) }
{
InitializeComponent();
INITIALIZE_BINDABLE_ENUM_SETTING(CursorShape, CursorStyle, winrt::Microsoft::Terminal::Core::CursorStyle, L"Profile_CursorShape", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(BackgroundImageStretchMode, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch, L"Profile_BackgroundImageStretchMode", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(AntiAliasingMode, TextAntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode, L"Profile_AntialiasingMode", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(CloseOnExitMode, CloseOnExitMode, winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode, L"Profile_CloseOnExit", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(ScrollState, ScrollbarState, winrt::Microsoft::Terminal::Control::ScrollbarState, L"Profile_ScrollbarVisibility", L"Content");
// manually add Custom FontWeight option. Don't add it to the Map
INITIALIZE_BINDABLE_ENUM_SETTING(FontWeight, FontWeight, uint16_t, L"Profile_FontWeight", L"Content");
_CustomFontWeight = winrt::make<EnumEntry>(RS_(L"Profile_FontWeightCustom/Content"), winrt::box_value<uint16_t>(0u));
_FontWeightList.Append(_CustomFontWeight);
// manually keep track of all the Background Image Alignment buttons
_BIAlignmentButtons.at(0) = BIAlign_TopLeft();
_BIAlignmentButtons.at(1) = BIAlign_Top();
_BIAlignmentButtons.at(2) = BIAlign_TopRight();
_BIAlignmentButtons.at(3) = BIAlign_Left();
_BIAlignmentButtons.at(4) = BIAlign_Center();
_BIAlignmentButtons.at(5) = BIAlign_Right();
_BIAlignmentButtons.at(6) = BIAlign_BottomLeft();
_BIAlignmentButtons.at(7) = BIAlign_Bottom();
_BIAlignmentButtons.at(8) = BIAlign_BottomRight();
// apply automation properties to more complex setting controls
for (const auto& biButton : _BIAlignmentButtons)
{
const auto tooltip{ ToolTipService::GetToolTip(biButton) };
Automation::AutomationProperties::SetName(biButton, unbox_value<hstring>(tooltip));
}
const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
const auto backgroundImgCheckboxTooltip{ ToolTipService::GetToolTip(UseDesktopImageCheckBox()) };
Automation::AutomationProperties::SetFullDescription(UseDesktopImageCheckBox(), unbox_value<hstring>(backgroundImgCheckboxTooltip));
const auto showAllFontsCheckboxTooltip{ ToolTipService::GetToolTip(ShowAllFontsCheckbox()) };
Automation::AutomationProperties::SetFullDescription(ShowAllFontsCheckbox(), unbox_value<hstring>(showAllFontsCheckboxTooltip));
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
_previewControl.IsEnabled(false);
@ -491,38 +310,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
ControlPreview().Child(_previewControl);
}
IInspectable Profiles::CurrentFontFace() const
{
// look for the current font in our shown list of fonts
const auto& profileVM{ State().Profile() };
const auto profileFontFace{ profileVM.FontFace() };
const auto& currentFontList{ profileVM.ShowAllFonts() ? profileVM.CompleteFontList() : profileVM.MonospaceFontList() };
IInspectable fallbackFont;
for (const auto& font : currentFontList)
{
if (font.LocalizedName() == profileFontFace)
{
return box_value(font);
}
else if (font.LocalizedName() == L"Cascadia Mono")
{
fallbackFont = box_value(font);
}
}
// we couldn't find the desired font, set to "Cascadia Mono" since that ships by default
return fallbackFont;
}
void Profiles::FontFace_SelectionChanged(IInspectable const& /*sender*/, SelectionChangedEventArgs const& e)
{
// NOTE: We need to hook up a selection changed event handler here instead of directly binding to the profile view model.
// A two way binding to the view model causes an infinite loop because both combo boxes keep fighting over which one's right.
const auto selectedItem{ e.AddedItems().GetAt(0) };
const auto newFontFace{ unbox_value<Editor::Font>(selectedItem) };
State().Profile().FontFace(newFontFace.LocalizedName());
}
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
{
_State = e.Parameter().as<Editor::ProfilePageNavigationState>();
@ -533,18 +320,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
ProfileViewModel::UpdateFontList();
}
const auto& colorSchemeMap{ _State.Schemes() };
for (const auto& pair : colorSchemeMap)
{
_ColorSchemeList.Append(pair.Value());
}
const auto& biAlignmentVal{ static_cast<int32_t>(_State.Profile().BackgroundImageAlignment()) };
for (const auto& biButton : _BIAlignmentButtons)
{
biButton.IsChecked(biButton.Tag().as<int32_t>() == biAlignmentVal);
}
// Set the text disclaimer for the text box
hstring disclaimer{};
const auto guid{ _State.Profile().Guid() };
@ -571,16 +346,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// and propagate those changes to the UI
_ViewModelChangedRevoker = _State.Profile().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
const auto settingName{ args.PropertyName() };
if (settingName == L"CursorShape")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCursorShape" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsVintageCursor" });
}
else if (settingName == L"BackgroundImageStretchMode")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentBackgroundImageStretchMode" });
}
else if (settingName == L"AntialiasingMode")
if (settingName == L"AntialiasingMode")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentAntiAliasingMode" });
}
@ -596,23 +362,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentScrollState" });
}
else if (settingName == L"FontWeight")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontWeight" });
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
}
else if (settingName == L"ColorSchemeName")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentColorScheme" });
}
else if (settingName == L"FontFace" || settingName == L"CurrentFontList")
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentFontFace" });
}
else if (settingName == L"BackgroundImageAlignment")
{
_UpdateBIAlignmentControl(static_cast<int32_t>(_State.Profile().BackgroundImageAlignment()));
}
_previewControl.Settings(_State.Profile().TermSettings());
_previewControl.UpdateSettings();
});
// The Appearances object handles updating the values in the settings UI, but
// we still need to listen to the changes here just to update the preview control
_AppearanceViewModelChangedRevoker = _State.Profile().DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
_previewControl.Settings(_State.Profile().TermSettings());
_previewControl.UpdateSettings();
});
@ -632,26 +388,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Profiles::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
}
ColorScheme Profiles::CurrentColorScheme()
{
const auto schemeName{ _State.Profile().ColorSchemeName() };
if (const auto scheme{ _State.Schemes().TryLookup(schemeName) })
{
return scheme;
}
else
{
// This Profile points to a color scheme that was renamed or deleted.
// Fallback to Campbell.
return _State.Schemes().TryLookup(L"Campbell");
}
}
void Profiles::CurrentColorScheme(const ColorScheme& val)
{
_State.Profile().ColorSchemeName(val.Name());
_AppearanceViewModelChangedRevoker.revoke();
}
bool Profiles::IsBellStyleFlagSet(const uint32_t flag)
@ -686,18 +423,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
state->DeleteProfile();
}
fire_and_forget Profiles::BackgroundImage_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_State.Profile().BackgroundImagePath(file);
}
}
fire_and_forget Profiles::Icon_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
@ -765,76 +490,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
IInspectable Profiles::CurrentFontWeight() const
{
// if no value was found, we have a custom value
const auto maybeEnumEntry{ _FontWeightMap.TryLookup(_State.Profile().FontWeight().Weight) };
return maybeEnumEntry ? maybeEnumEntry : _CustomFontWeight;
}
void Profiles::CurrentFontWeight(const IInspectable& enumEntry)
{
if (auto ee = enumEntry.try_as<Editor::EnumEntry>())
{
if (ee != _CustomFontWeight)
{
const auto weight{ winrt::unbox_value<uint16_t>(ee.EnumValue()) };
const Windows::UI::Text::FontWeight setting{ weight };
_State.Profile().FontWeight(setting);
// Profile does not have observable properties
// So the TwoWay binding doesn't update on the State --> Slider direction
FontWeightSlider().Value(weight);
}
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsCustomFontWeight" });
}
}
bool Profiles::IsCustomFontWeight()
{
// Use SelectedItem instead of CurrentFontWeight.
// CurrentFontWeight converts the Profile's value to the appropriate enum entry,
// whereas SelectedItem identifies which one was selected by the user.
return FontWeightComboBox().SelectedItem() == _CustomFontWeight;
}
void Profiles::BIAlignment_Click(IInspectable const& sender, RoutedEventArgs const& /*e*/)
{
if (const auto& button{ sender.try_as<Primitives::ToggleButton>() })
{
if (const auto& tag{ button.Tag().try_as<int32_t>() })
{
// Update the Profile's value and the control
_State.Profile().BackgroundImageAlignment(static_cast<ConvergedAlignment>(*tag));
_UpdateBIAlignmentControl(*tag);
}
}
}
// Method Description:
// - Resets all of the buttons to unchecked, and checks the one with the provided tag
// Arguments:
// - val - the background image alignment (ConvergedAlignment) that we want to represent in the control
void Profiles::_UpdateBIAlignmentControl(const int32_t val)
{
for (const auto& biButton : _BIAlignmentButtons)
{
if (const auto& biButtonAlignment{ biButton.Tag().try_as<int32_t>() })
{
biButton.IsChecked(biButtonAlignment == val);
}
}
}
bool Profiles::IsVintageCursor() const
{
return _State.Profile().CursorShape() == Core::CursorStyle::Vintage;
}
void Profiles::Pivot_SelectionChanged(Windows::Foundation::IInspectable const& /*sender*/,
RoutedEventArgs const& /*e*/)
{
_State.LastActivePivot(static_cast<Editor::ProfilesPivots>(ProfilesPivot().SelectedIndex()));
}
}

View file

@ -3,37 +3,16 @@
#pragma once
#include "Font.g.h"
#include "Profiles.g.h"
#include "ProfilePageNavigationState.g.h"
#include "DeleteProfileEventArgs.g.h"
#include "ProfileViewModel.g.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
#include "Appearances.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct FontComparator
{
bool operator()(const Font& lhs, const Font& rhs) const
{
return lhs.LocalizedName() < rhs.LocalizedName();
}
};
struct Font : FontT<Font>
{
public:
Font(std::wstring name, std::wstring localizedName) :
_Name{ name },
_LocalizedName{ localizedName } {};
hstring ToString() { return _LocalizedName; }
WINRT_PROPERTY(hstring, Name);
WINRT_PROPERTY(hstring, LocalizedName);
};
struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
@ -41,11 +20,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Model::TerminalSettings TermSettings() const;
// background image
bool UseDesktopBGImage();
void UseDesktopBGImage(const bool useDesktop);
bool BackgroundImageSettingsVisible();
// starting directory
bool UseParentProcessDirectory();
void UseParentProcessDirectory(const bool useParent);
@ -55,13 +29,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static void UpdateFontList() noexcept;
Windows::Foundation::Collections::IObservableVector<Editor::Font> CompleteFontList() const noexcept;
Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() const noexcept;
bool UsingMonospaceFont() const noexcept;
bool ShowAllFonts() const noexcept;
void ShowAllFonts(const bool& value);
// general profile knowledge
winrt::guid OriginalProfileGuid() const noexcept;
bool CanDeleteProfile() const;
Editor::AppearanceViewModel DefaultAppearance();
WINRT_PROPERTY(bool, IsBaseLayer, false);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
@ -77,21 +49,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic);
OBSERVABLE_PROJECTED_SETTING(_profile, AcrylicOpacity);
OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState);
OBSERVABLE_PROJECTED_SETTING(_profile.FontInfo(), FontFace);
OBSERVABLE_PROJECTED_SETTING(_profile.FontInfo(), FontSize);
OBSERVABLE_PROJECTED_SETTING(_profile.FontInfo(), FontWeight);
OBSERVABLE_PROJECTED_SETTING(_profile, Padding);
OBSERVABLE_PROJECTED_SETTING(_profile, Commandline);
OBSERVABLE_PROJECTED_SETTING(_profile, StartingDirectory);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), BackgroundImagePath);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), BackgroundImageOpacity);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), BackgroundImageAlignment);
OBSERVABLE_PROJECTED_SETTING(_profile, AntialiasingMode);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), RetroTerminalEffect);
OBSERVABLE_PROJECTED_SETTING(_profile, ForceFullRepaintRendering);
OBSERVABLE_PROJECTED_SETTING(_profile, SoftwareRendering);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), ColorSchemeName);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Foreground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground);
@ -99,8 +62,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize);
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorShape);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorHeight);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
private:
@ -108,7 +69,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
winrt::guid _originalProfileGuid;
winrt::hstring _lastBgImagePath;
winrt::hstring _lastStartingDirectoryPath;
bool _ShowAllFonts;
Editor::AppearanceViewModel _defaultAppearanceViewModel;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
@ -139,7 +100,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
const Editor::ProfilePageNavigationState& lastState,
const IHostedInWindow& windowRoot) :
_Profile{ viewModel },
_Schemes{ schemes },
_WindowRoot{ windowRoot }
{
// If there was a previous nav state copy the selected pivot from it.
@ -147,20 +107,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_LastActivePivot = lastState.LastActivePivot();
}
viewModel.DefaultAppearance().Schemes(schemes);
viewModel.DefaultAppearance().WindowRoot(windowRoot);
}
void DeleteProfile();
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> Schemes() { return _Schemes; }
void Schemes(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& val) { _Schemes = val; }
TYPED_EVENT(DeleteProfile, Editor::ProfilePageNavigationState, Editor::DeleteProfileEventArgs);
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
WINRT_PROPERTY(Editor::ProfilesPivots, LastActivePivot, Editor::ProfilesPivots::General);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
};
struct Profiles : ProfilesT<Profiles>
@ -168,45 +124,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
public:
Profiles();
// font face
Windows::Foundation::IInspectable CurrentFontFace() const;
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
Model::ColorScheme CurrentColorScheme();
void CurrentColorScheme(const Model::ColorScheme& val);
// bell style bits
bool IsBellStyleFlagSet(const uint32_t flag);
void SetBellStyleAudible(winrt::Windows::Foundation::IReference<bool> on);
void SetBellStyleWindow(winrt::Windows::Foundation::IReference<bool> on);
void SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on);
fire_and_forget BackgroundImage_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
fire_and_forget Commandline_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
fire_and_forget StartingDirectory_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
fire_and_forget Icon_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void BIAlignment_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void DeleteConfirmation_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void Pivot_SelectionChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void FontFace_SelectionChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& e);
// CursorShape visibility logic
bool IsVintageCursor() const;
// manually bind FontWeight
Windows::Foundation::IInspectable CurrentFontWeight() const;
void CurrentFontWeight(const Windows::Foundation::IInspectable& enumEntry);
bool IsCustomFontWeight();
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Microsoft::Terminal::Settings::Editor::EnumEntry>, FontWeightList);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfilePageNavigationState, State, nullptr);
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Model::ColorScheme>, ColorSchemeList, nullptr);
GETSET_BINDABLE_ENUM_SETTING(CursorShape, Microsoft::Terminal::Core::CursorStyle, State().Profile, CursorShape);
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, State().Profile, BackgroundImageStretchMode);
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, State().Profile, AntialiasingMode);
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, State().Profile, CloseOnExit);
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, State().Profile, ScrollState);
@ -214,10 +149,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
private:
void _UpdateBIAlignmentControl(const int32_t val);
Windows::Foundation::Collections::IMap<uint16_t, Microsoft::Terminal::Settings::Editor::EnumEntry> _FontWeightMap;
Editor::EnumEntry _CustomFontWeight{ nullptr };
std::array<Windows::UI::Xaml::Controls::Primitives::ToggleButton, 9> _BIAlignmentButtons;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
Microsoft::Terminal::Control::TermControl _previewControl;
};

View file

@ -3,6 +3,7 @@
import "EnumEntry.idl";
import "MainPage.idl";
import "Appearances.idl";
#include "ViewModelHelpers.idl.h"
@ -12,12 +13,6 @@ import "MainPage.idl";
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass Font : Windows.Foundation.IStringable
{
String Name { get; };
String LocalizedName { get; };
}
runtimeclass ProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Windows.Foundation.Collections.IObservableVector<Font> CompleteFontList { get; };
@ -25,13 +20,10 @@ namespace Microsoft.Terminal.Settings.Editor
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
Boolean CanDeleteProfile { get; };
Boolean UsingMonospaceFont { get; };
Boolean IsBaseLayer;
Boolean UseDesktopBGImage;
Boolean UseParentProcessDirectory;
Boolean ShowAllFonts;
Boolean UseCustomStartingDirectory { get; };
Boolean BackgroundImageSettingsVisible { get; };
AppearanceViewModel DefaultAppearance { get; };
Guid OriginalProfileGuid { get; };
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
@ -47,21 +39,12 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, AcrylicOpacity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, FontSize);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, BackgroundImagePath);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, BackgroundImageOpacity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.UI.Xaml.Media.Stretch, BackgroundImageStretchMode);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.ConvergedAlignment, BackgroundImageAlignment);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RetroTerminalEffect);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ForceFullRepaintRendering);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SoftwareRendering);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, ColorSchemeName);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Foreground);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Background);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, SelectionBackground);
@ -69,8 +52,6 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, HistorySize);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Core.CursorStyle, CursorShape);
OBSERVABLE_PROJECTED_PROFILE_SETTING(UInt32, CursorHeight);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
}
@ -88,7 +69,6 @@ namespace Microsoft.Terminal.Settings.Editor
runtimeclass ProfilePageNavigationState
{
Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes;
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
ProfileViewModel Profile;
@ -107,13 +87,6 @@ namespace Microsoft.Terminal.Settings.Editor
void SetBellStyleWindow(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
IInspectable CurrentCursorShape;
Boolean IsVintageCursor { get; };
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CursorShapeList { get; };
IInspectable CurrentBackgroundImageStretchMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> BackgroundImageStretchModeList { get; };
IInspectable CurrentAntiAliasingMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AntiAliasingModeList { get; };
@ -122,14 +95,5 @@ namespace Microsoft.Terminal.Settings.Editor
IInspectable CurrentScrollState;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; };
IInspectable CurrentFontWeight;
Boolean IsCustomFontWeight { get; };
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> FontWeightList { get; };
Microsoft.Terminal.Settings.Model.ColorScheme CurrentColorScheme;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Model.ColorScheme> ColorSchemeList { get; };
IInspectable CurrentFontFace { get; };
}
}

View file

@ -237,400 +237,17 @@
<PivotItem x:Uid="Profile_Appearance">
<ScrollViewer>
<StackPanel>
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Control Preview -->
<Border x:Name="ControlPreview"
Width="350"
Height="160"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<!-- Control Preview -->
<Border x:Name="ControlPreview"
Width="350"
Height="160"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<!-- Grouping: Text -->
<TextBlock x:Uid="Profile_TextHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Color Scheme -->
<local:SettingContainer x:Uid="Profile_ColorScheme"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearColorSchemeName}"
HasSettingValue="{x:Bind State.Profile.HasColorSchemeName, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.ColorSchemeNameOverrideSource, Mode=OneWay}">
<ComboBox ItemsSource="{x:Bind ColorSchemeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentColorScheme, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="model:ColorScheme">
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</local:SettingContainer>
<!-- Font Face -->
<local:SettingContainer x:Uid="Profile_FontFace"
ClearSettingValue="{x:Bind State.Profile.ClearFontFace}"
HasSettingValue="{x:Bind State.Profile.HasFontFace, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.FontFaceOverrideSource, Mode=OneWay}">
<StackPanel>
<!--
Binding the ItemsSource to a separate variable that switches between the
two font lists causes a crash within the ComboBox code.
As a workaround, introduce two ComboBox controls and only display one at a time.
-->
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind State.Profile.MonospaceFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind State.Profile.ShowAllFonts, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind State.Profile.CompleteFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind State.Profile.ShowAllFonts, Mode=OneWay}" />
<CheckBox x:Name="ShowAllFontsCheckbox"
x:Uid="Profile_FontFaceShowAllFonts"
IsChecked="{x:Bind State.Profile.ShowAllFonts, Mode=TwoWay}"
IsEnabled="{x:Bind State.Profile.UsingMonospaceFont, Mode=OneWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Font Size -->
<local:SettingContainer x:Uid="Profile_FontSize"
ClearSettingValue="{x:Bind State.Profile.ClearFontSize}"
HasSettingValue="{x:Bind State.Profile.HasFontSize, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.FontSizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox AcceptsExpression="False"
LargeChange="10"
Maximum="128"
Minimum="1"
SmallChange="1"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind State.Profile.FontSize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Font Weight -->
<local:SettingContainer x:Name="FontWeightContainer"
x:Uid="Profile_FontWeight"
ClearSettingValue="{x:Bind State.Profile.ClearFontWeight}"
HasSettingValue="{x:Bind State.Profile.HasFontWeight, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.FontWeightOverrideSource, Mode=OneWay}">
<StackPanel>
<ComboBox x:Name="FontWeightComboBox"
ItemTemplate="{StaticResource EnumComboBoxItemTemplate}"
ItemsSource="{x:Bind FontWeightList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontWeight, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
<!-- Custom Font Weight Control -->
<Grid Margin="0,10,0,0"
Style="{StaticResource CustomSliderControlGridStyle}"
Visibility="{x:Bind IsCustomFontWeight, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="FontWeightSlider"
Grid.Column="0"
Maximum="1000"
Minimum="0"
TickFrequency="50"
TickPlacement="Outside"
Value="{x:Bind State.Profile.FontWeight, Converter={StaticResource FontWeightConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Margin="10,0,0,0"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=FontWeightSlider, Path=Value, Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Retro Terminal Effect -->
<local:SettingContainer x:Uid="Profile_RetroTerminalEffect"
ClearSettingValue="{x:Bind State.Profile.ClearRetroTerminalEffect}"
HasSettingValue="{x:Bind State.Profile.HasRetroTerminalEffect, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.RetroTerminalEffectOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.RetroTerminalEffect, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Cursor -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_CursorHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Cursor Shape -->
<local:SettingContainer x:Uid="Profile_CursorShape"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearCursorShape}"
HasSettingValue="{x:Bind State.Profile.HasCursorShape, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CursorShapeOverrideSource, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind CursorShapeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentCursorShape, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Cursor Height -->
<local:SettingContainer x:Uid="Profile_CursorHeight"
ClearSettingValue="{x:Bind State.Profile.ClearCursorHeight}"
HasSettingValue="{x:Bind State.Profile.HasCursorHeight, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CursorHeightOverrideSource, Mode=OneWay}"
Visibility="{x:Bind IsVintageCursor, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="CursorHeightSlider"
Grid.Column="0"
Maximum="100"
Minimum="1"
Value="{x:Bind State.Profile.CursorHeight, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=CursorHeightSlider, Path=Value, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Background -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_BackgroundHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Background Image -->
<local:SettingContainer x:Name="BackgroundImageContainer"
x:Uid="Profile_BackgroundImage"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearBackgroundImagePath}"
HasSettingValue="{x:Bind State.Profile.HasBackgroundImagePath, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BackgroundImagePathOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{x:Bind State.Profile.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.BackgroundImagePath, Mode=TwoWay, Converter={StaticResource DesktopWallpaperToEmptyStringConverter}}" />
<Button x:Uid="Profile_BackgroundImageBrowse"
Click="BackgroundImage_Click"
IsEnabled="{x:Bind State.Profile.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="UseDesktopImageCheckBox"
x:Uid="Profile_UseDesktopImage"
IsChecked="{x:Bind State.Profile.UseDesktopBGImage, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Background Image Stretch Mode -->
<local:SettingContainer x:Uid="Profile_BackgroundImageStretchMode"
ClearSettingValue="{x:Bind State.Profile.ClearBackgroundImageStretchMode}"
HasSettingValue="{x:Bind State.Profile.HasBackgroundImageStretchMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BackgroundImageStretchModeOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.BackgroundImageSettingsVisible, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind BackgroundImageStretchModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentBackgroundImageStretchMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Background Image Alignment -->
<local:SettingContainer x:Uid="Profile_BackgroundImageAlignment"
ClearSettingValue="{x:Bind State.Profile.ClearBackgroundImageAlignment}"
HasSettingValue="{x:Bind State.Profile.HasBackgroundImageAlignment, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BackgroundImageAlignmentOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.BackgroundImageSettingsVisible, Mode=OneWay}">
<Grid HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style BasedOn="{StaticResource DefaultToggleButtonStyle}"
TargetType="ToggleButton">
<Setter Property="Margin" Value="2" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="40" />
<Setter Property="ToolTipService.Placement" Value="Mouse" />
</Style>
</Grid.Resources>
<!-- Top Row -->
<ToggleButton x:Name="BIAlign_TopLeft"
x:Uid="Profile_BackgroundImageAlignmentTopLeft"
Grid.Row="0"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Left (0x01) -->
<x:Int32>17</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE744;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="90" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Top"
x:Uid="Profile_BackgroundImageAlignmentTop"
Grid.Row="0"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Center (0x00) -->
<x:Int32>16</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE745;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="180" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_TopRight"
x:Uid="Profile_BackgroundImageAlignmentTopRight"
Grid.Row="0"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x10) | Horizontal_Right (0x02) -->
<x:Int32>18</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA5F;"
RenderTransformOrigin="0.5,0.5">
<FontIcon.RenderTransform>
<RotateTransform Angle="270" />
</FontIcon.RenderTransform>
</FontIcon>
</ToggleButton.Content>
</ToggleButton>
<!-- Middle Row -->
<ToggleButton x:Name="BIAlign_Left"
x:Uid="Profile_BackgroundImageAlignmentLeft"
Grid.Row="1"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Left (0x01) -->
<x:Int32>1</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE746;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Center"
x:Uid="Profile_BackgroundImageAlignmentCenter"
Grid.Row="1"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Center (0x00) -->
<x:Int32>0</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xF16E;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Right"
x:Uid="Profile_BackgroundImageAlignmentRight"
Grid.Row="1"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Center (0x00) | Horizontal_Right (0x02) -->
<x:Int32>2</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA61;" />
</ToggleButton.Content>
</ToggleButton>
<!-- Bottom Row -->
<ToggleButton x:Name="BIAlign_BottomLeft"
x:Uid="Profile_BackgroundImageAlignmentBottomLeft"
Grid.Row="2"
Grid.Column="0"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Left (0x01) -->
<x:Int32>33</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE744;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_Bottom"
x:Uid="Profile_BackgroundImageAlignmentBottom"
Grid.Row="2"
Grid.Column="1"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Bottom (0x20) | Horizontal_Center (0x00) -->
<x:Int32>32</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xE745;" />
</ToggleButton.Content>
</ToggleButton>
<ToggleButton x:Name="BIAlign_BottomRight"
x:Uid="Profile_BackgroundImageAlignmentBottomRight"
Grid.Row="2"
Grid.Column="2"
Click="BIAlignment_Click">
<ToggleButton.Tag>
<!-- ConvergedAlignment: Vertical_Top (0x20) | Horizontal_Right (0x02) -->
<x:Int32>34</x:Int32>
</ToggleButton.Tag>
<ToggleButton.Content>
<FontIcon FontFamily="Segoe MDL2 Assets"
Glyph="&#xEA5F;" />
</ToggleButton.Content>
</ToggleButton>
</Grid>
</local:SettingContainer>
<!-- Background Image Opacity -->
<local:SettingContainer x:Name="BackgroundImageOpacityContainer"
x:Uid="Profile_BackgroundImageOpacity"
ClearSettingValue="{x:Bind State.Profile.ClearBackgroundImageOpacity}"
HasSettingValue="{x:Bind State.Profile.HasBackgroundImageOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BackgroundImageOpacityOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.BackgroundImageSettingsVisible, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="BIOpacitySlider"
Grid.Column="0"
Value="{x:Bind State.Profile.BackgroundImageOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=BIOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
</Grid>
</local:SettingContainer>
</StackPanel>
<local:Appearances Appearance="{x:Bind State.Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind State.Profile, Mode=OneWay}" />
<!-- Grouping: Acrylic -->
<StackPanel Style="{StaticResource PivotStackStyle}">

View file

@ -15,6 +15,30 @@ using namespace winrt::Windows::UI::Xaml;
UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"Microsoft.Terminal.Settings.Editor/Resources");
// Function Description:
// - Helper that opens a file picker pre-seeded with image file types.
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
{
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
{ L"All Files (*.*)", L"*.*" }
};
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
try
{
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(pictureFolderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
});
}
namespace winrt::Microsoft::Terminal::Settings
{
hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable)

View file

@ -91,6 +91,42 @@ public: \
private: \
static winrt::Windows::UI::Xaml::DependencyProperty _##name##Property;
// Function Description:
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
// Parameters:
// - customize: A lambda that receives an IFileDialog* to customize.
// Return value:
// (async) path to the selected item.
template<typename TLambda>
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
{
auto fileDialog{ winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
DWORD flags{};
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
customize(fileDialog.get());
auto hr{ fileDialog->Show(parentHwnd) };
if (!SUCCEEDED(hr))
{
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
co_return winrt::hstring{};
}
THROW_HR(hr);
}
winrt::com_ptr<IShellItem> result;
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
wil::unique_cotaskmem_string filePath;
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
co_return winrt::hstring{ filePath.get() };
}
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd);
namespace winrt::Microsoft::Terminal::Settings
{
winrt::hstring GetSelectedItemTag(winrt::Windows::Foundation::IInspectable const& comboBoxAsInspectable);