Apply MVVM for profiles in SUI (#11877)

## Summary of the Pull Request
Cleans up `ProfileViewModel`, `Profiles`, and `ProfilePageNavigationState` to move all of the view model responsibilities over to `ProfileViewModel`. We don't actually store the `ProfilePageNavigationState` anymore. We only use it as a way to transfer information to the new page.

## References
#9207 - Apply MVVM

## Detailed Description of the Pull Request / Additional comments
- I pulled out `ProfileViewModel` into its own file to keep things cleaner. It was getting pretty big.
- The font lists are now stored in a static location in `ProfileViewModel`, which means that we can reuse the same list between pages.
- the profile pivot was also moved to the `ProfileViewModel` and stored as a static value.

## Validation Steps Performed
 pivot behavior is the same
 font list is still populated
This commit is contained in:
Carlos Zamora
2021-12-07 19:25:38 -05:00
committed by GitHub
parent 00fe2b02bf
commit 0939eec485
17 changed files with 837 additions and 804 deletions

View File

@@ -142,7 +142,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
bool result{ false };
const auto currentFont{ Appearance().FontFace() };
for (const auto& font : SourceProfile().MonospaceFontList())
for (const auto& font : ProfileViewModel::MonospaceFontList())
{
if (font.LocalizedName() == currentFont)
{
@@ -175,7 +175,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// 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() };
const auto& currentFontList{ ShowAllFonts() ? ProfileViewModel::CompleteFontList() : ProfileViewModel::MonospaceFontList() };
IInspectable fallbackFont;
for (const auto& font : currentFontList)
{

View File

@@ -129,16 +129,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
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);
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);
GETSET_BINDABLE_ENUM_SETTING(BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch, Appearance(), BackgroundImageStretchMode);
GETSET_BINDABLE_ENUM_SETTING(IntenseTextStyle, Microsoft::Terminal::Settings::Model::IntenseStyle, Appearance, IntenseTextStyle);
GETSET_BINDABLE_ENUM_SETTING(IntenseTextStyle, Microsoft::Terminal::Settings::Model::IntenseStyle, Appearance(), IntenseTextStyle);
private:
bool _ShowAllFonts;

View File

@@ -28,8 +28,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
bool FeatureNotificationIconEnabled() const noexcept;
WINRT_PROPERTY(Editor::GlobalAppearancePageNavigationState, State, nullptr);
GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals, Theme);
GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals, TabWidthMode);
GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals(), Theme);
GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals(), TabWidthMode);
public:
// LanguageDisplayConverter maps the given BCP 47 tag to a localized string.

View File

@@ -26,8 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WINRT_PROPERTY(Editor::InteractionPageNavigationState, State, nullptr);
GETSET_BINDABLE_ENUM_SETTING(TabSwitcherMode, Model::TabSwitcherMode, State().Globals, TabSwitcherMode);
GETSET_BINDABLE_ENUM_SETTING(CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, State().Globals, CopyFormatting);
GETSET_BINDABLE_ENUM_SETTING(TabSwitcherMode, Model::TabSwitcherMode, State().Globals(), TabSwitcherMode);
GETSET_BINDABLE_ENUM_SETTING(CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, State().Globals(), CopyFormatting);
};
}

View File

@@ -33,9 +33,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WINRT_PROPERTY(Editor::LaunchPageNavigationState, State, nullptr);
GETSET_BINDABLE_ENUM_SETTING(FirstWindowPreference, Model::FirstWindowPreference, State().Settings().GlobalSettings, FirstWindowPreference);
GETSET_BINDABLE_ENUM_SETTING(LaunchMode, Model::LaunchMode, State().Settings().GlobalSettings, LaunchMode);
GETSET_BINDABLE_ENUM_SETTING(WindowingBehavior, Model::WindowingMode, State().Settings().GlobalSettings, WindowingBehavior);
GETSET_BINDABLE_ENUM_SETTING(FirstWindowPreference, Model::FirstWindowPreference, State().Settings().GlobalSettings(), FirstWindowPreference);
GETSET_BINDABLE_ENUM_SETTING(LaunchMode, Model::LaunchMode, State().Settings().GlobalSettings(), LaunchMode);
GETSET_BINDABLE_ENUM_SETTING(WindowingBehavior, Model::WindowingMode, State().Settings().GlobalSettings(), WindowingBehavior);
};
}

View File

@@ -298,12 +298,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) };
profileVM.IsBaseLayer(true);
_lastProfilesNavState = winrt::make<ProfilePageNavigationState>(profileVM,
_settingsClone.GlobalSettings().ColorSchemes(),
_lastProfilesNavState,
*this);
auto state{ winrt::make<ProfilePageNavigationState>(profileVM,
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), _lastProfilesNavState);
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), state);
}
else if (clickedItemTag == colorSchemesTag)
{
@@ -328,15 +327,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// - profile - the profile object we are getting a view of
void MainPage::_Navigate(const Editor::ProfileViewModel& profile)
{
_lastProfilesNavState = winrt::make<ProfilePageNavigationState>(profile,
_settingsClone.GlobalSettings().ColorSchemes(),
_lastProfilesNavState,
*this);
auto state{ winrt::make<ProfilePageNavigationState>(profile,
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
// Add an event handler for when the user wants to delete a profile.
_lastProfilesNavState.DeleteProfile({ this, &MainPage::_DeleteProfile });
profile.DeleteProfile({ this, &MainPage::_DeleteProfile });
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), _lastProfilesNavState);
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), state);
}
void MainPage::OpenJsonTapped(IInspectable const& /*sender*/, Windows::UI::Xaml::Input::TappedRoutedEventArgs const& /*args*/)

View File

@@ -46,7 +46,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void _Navigate(const Editor::ProfileViewModel& profile);
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageNavigationState _colorSchemesNavState{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ProfilePageNavigationState _lastProfilesNavState{ nullptr };
};
}

View File

@@ -73,6 +73,10 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="ProfileViewModel.h">
<DependentUpon>ProfileViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Appearances.h">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -167,6 +171,10 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="ProfileViewModel.cpp">
<DependentUpon>ProfileViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Appearances.cpp">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -225,6 +233,7 @@
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="ProfileViewModel.idl" />
<Midl Include="Appearances.idl">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>

View File

@@ -17,6 +17,7 @@
<ClInclude Include="PreviewConnection.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="ProfileViewModel.idl" />
<Midl Include="EnumEntry.idl" />
<Midl Include="Converters.idl">
<Filter>Converters</Filter>

View File

@@ -0,0 +1,417 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ProfileViewModel.h"
#include "ProfileViewModel.g.cpp"
#include "EnumEntry.h"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
// This function is a copy of DxFontInfo::_NearbyCollection() with
// * the call to DxFontInfo::s_GetNearbyFonts() inlined
// * checkForUpdates for GetSystemFontCollection() set to true
static wil::com_ptr<IDWriteFontCollection1> NearbyCollection(IDWriteFactory* dwriteFactory)
{
// The convenience interfaces for loading fonts from files
// are only available on Windows 10+.
wil::com_ptr<IDWriteFactory6> factory6;
// wil's query() facilities don't work inside WinRT land at the moment.
// They produce a compilation error due to IUnknown and winrt::Windows::Foundation::IUnknown being ambiguous.
if (!SUCCEEDED(dwriteFactory->QueryInterface(__uuidof(IDWriteFactory6), factory6.put_void())))
{
return nullptr;
}
wil::com_ptr<IDWriteFontCollection1> systemFontCollection;
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, systemFontCollection.addressof(), true));
wil::com_ptr<IDWriteFontSet> systemFontSet;
THROW_IF_FAILED(systemFontCollection->GetFontSet(systemFontSet.addressof()));
wil::com_ptr<IDWriteFontSetBuilder2> fontSetBuilder2;
THROW_IF_FAILED(factory6->CreateFontSetBuilder(fontSetBuilder2.addressof()));
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.get()));
{
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
const auto folder{ module.parent_path() };
for (const auto& p : std::filesystem::directory_iterator(folder))
{
if (til::ends_with(p.path().native(), L".ttf"))
{
fontSetBuilder2->AddFontFile(p.path().c_str());
}
}
}
wil::com_ptr<IDWriteFontSet> fontSet;
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(fontSet.addressof()));
wil::com_ptr<IDWriteFontCollection1> fontCollection;
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.get(), &fontCollection));
return fontCollection;
}
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
{
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
ProfilesPivots ProfileViewModel::_LastActivePivot{ ProfilesPivots::General };
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() },
_appSettings{ appSettings },
_unfocusedAppearanceViewModel{ nullptr }
{
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");
// 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"IsBaseLayer")
{
// we _always_ want to show the background image settings in base layer
_NotifyChanges(L"BackgroundImageSettingsVisible");
}
else if (viewModelProperty == L"StartingDirectory")
{
// notify listener that all starting directory related values might have changed
// NOTE: this is similar to what is done with BackgroundImagePath above
_NotifyChanges(L"UseParentProcessDirectory", L"UseCustomStartingDirectory");
}
else if (viewModelProperty == L"UseAcrylic")
{
// GH#11372: If we're on Windows 10, and someone turns off
// acrylic, we're going to disable opacity for them. Opacity
// doesn't work without acrylic on Windows 10.
//
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
// is basically a "are we on Windows 11" check, because defterm
// only works on Win11. So we'll use that.
//
// Remove when we can remove the rest of GH#11285
if (!UseAcrylic() && !CascadiaSettings::IsDefaultTerminalAvailable())
{
Opacity(1.0);
}
}
});
// Do the same for the starting directory
if (!StartingDirectory().empty())
{
_lastStartingDirectoryPath = StartingDirectory();
}
// generate the font list, if we don't have one
if (!_FontList || !_MonospaceFontList)
{
UpdateFontList();
}
if (profile.HasUnfocusedAppearance())
{
_unfocusedAppearanceViewModel = winrt::make<implementation::AppearanceViewModel>(profile.UnfocusedAppearance().try_as<AppearanceConfig>());
}
_defaultAppearanceViewModel.IsDefault(true);
}
Model::TerminalSettings ProfileViewModel::TermSettings() const
{
return Model::TerminalSettings::CreateWithProfile(_appSettings, _profile, nullptr).DefaultSettings();
}
// Method Description:
// - Updates the lists of fonts and sorts them alphabetically
void ProfileViewModel::UpdateFontList() noexcept
try
{
// initialize font list
std::vector<Editor::Font> fontList;
std::vector<Editor::Font> monospaceFontList;
// get a DWriteFactory
com_ptr<IDWriteFactory> factory;
THROW_IF_FAILED(DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<::IUnknown**>(factory.put())));
// get the font collection; subscribe to updates
const auto fontCollection = NearbyCollection(factory.get());
for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
{
try
{
// get the font family
com_ptr<IDWriteFontFamily> fontFamily;
THROW_IF_FAILED(fontCollection->GetFontFamily(i, fontFamily.put()));
// get the font's localized names
com_ptr<IDWriteLocalizedStrings> localizedFamilyNames;
THROW_IF_FAILED(fontFamily->GetFamilyNames(localizedFamilyNames.put()));
// construct a font entry for tracking
if (const auto fontEntry{ _GetFont(localizedFamilyNames) })
{
// check if the font is monospaced
try
{
com_ptr<IDWriteFont> font;
THROW_IF_FAILED(fontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_NORMAL,
font.put()));
// add the font name to our list of monospace fonts
const auto castedFont{ font.try_as<IDWriteFont1>() };
if (castedFont && castedFont->IsMonospacedFont())
{
monospaceFontList.emplace_back(fontEntry);
}
}
CATCH_LOG();
// add the font name to our list of all fonts
fontList.emplace_back(std::move(fontEntry));
}
}
CATCH_LOG();
}
// sort and save the lists
std::sort(begin(fontList), end(fontList), FontComparator());
_FontList = single_threaded_observable_vector<Editor::Font>(std::move(fontList));
std::sort(begin(monospaceFontList), end(monospaceFontList), FontComparator());
_MonospaceFontList = single_threaded_observable_vector<Editor::Font>(std::move(monospaceFontList));
}
CATCH_LOG();
Editor::Font ProfileViewModel::_GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames)
{
// used for the font's name as an identifier (i.e. text block's font family property)
std::wstring nameID;
UINT32 nameIDIndex;
// used for the font's localized name
std::wstring localizedName;
UINT32 localizedNameIndex;
// use our current locale to find the localized name
BOOL exists{ FALSE };
HRESULT hr;
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH))
{
hr = localizedFamilyNames->FindLocaleName(localeName, &localizedNameIndex, &exists);
}
if (SUCCEEDED(hr) && !exists)
{
// if we can't find the font for our locale, fallback to the en-us one
// Source: https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-findlocalename
hr = localizedFamilyNames->FindLocaleName(L"en-us", &localizedNameIndex, &exists);
}
if (!exists)
{
// failed to find the correct locale, using the first one
localizedNameIndex = 0;
}
// get the localized name
UINT32 nameLength;
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(localizedNameIndex, &nameLength));
localizedName.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(localizedNameIndex, localizedName.data(), nameLength + 1));
// now get the nameID
hr = localizedFamilyNames->FindLocaleName(L"en-us", &nameIDIndex, &exists);
if (FAILED(hr) || !exists)
{
// failed to find it, using the first one
nameIDIndex = 0;
}
// get the nameID
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(nameIDIndex, &nameLength));
nameID.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(nameIDIndex, nameID.data(), nameLength + 1));
if (!nameID.empty() && !localizedName.empty())
{
return make<Font>(nameID, localizedName);
}
return nullptr;
}
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> ProfileViewModel::Schemes() const noexcept
{
return _Schemes;
}
void ProfileViewModel::Schemes(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& val) noexcept
{
_Schemes = val;
}
winrt::guid ProfileViewModel::OriginalProfileGuid() const noexcept
{
return _originalProfileGuid;
}
bool ProfileViewModel::CanDeleteProfile() const
{
return !IsBaseLayer();
}
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance()
{
return _defaultAppearanceViewModel;
}
bool ProfileViewModel::HasUnfocusedAppearance()
{
return _profile.HasUnfocusedAppearance();
}
bool ProfileViewModel::EditableUnfocusedAppearance() const noexcept
{
return Feature_EditableUnfocusedAppearance::IsEnabled();
}
bool ProfileViewModel::ShowUnfocusedAppearance()
{
return EditableUnfocusedAppearance() && HasUnfocusedAppearance();
}
void ProfileViewModel::CreateUnfocusedAppearance()
{
_profile.CreateUnfocusedAppearance();
_unfocusedAppearanceViewModel = winrt::make<implementation::AppearanceViewModel>(_profile.UnfocusedAppearance().try_as<AppearanceConfig>());
_unfocusedAppearanceViewModel.Schemes(_Schemes);
_unfocusedAppearanceViewModel.WindowRoot(_WindowRoot);
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
}
void ProfileViewModel::DeleteUnfocusedAppearance()
{
_profile.DeleteUnfocusedAppearance();
_unfocusedAppearanceViewModel = nullptr;
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
}
Editor::AppearanceViewModel ProfileViewModel::UnfocusedAppearance()
{
return _unfocusedAppearanceViewModel;
}
bool ProfileViewModel::AtlasEngineAvailable() const noexcept
{
return Feature_AtlasEngine::IsEnabled();
}
bool ProfileViewModel::UseParentProcessDirectory()
{
return StartingDirectory().empty();
}
// This function simply returns the opposite of UseParentProcessDirectory.
// We bind the 'IsEnabled' parameters of the textbox and browse button
// to this because it needs to be the reverse of UseParentProcessDirectory
// but we don't want to create a whole new converter for inverting a boolean
bool ProfileViewModel::UseCustomStartingDirectory()
{
return !UseParentProcessDirectory();
}
void ProfileViewModel::UseParentProcessDirectory(const bool useParent)
{
if (useParent)
{
// Stash the current value of StartingDirectory. If the user
// checks and un-checks the "Use parent process directory" button, we want
// the path that we display in the text box to remain unchanged.
//
// Only stash this value if it's not empty
if (!StartingDirectory().empty())
{
_lastStartingDirectoryPath = StartingDirectory();
}
StartingDirectory(L"");
}
else
{
// Restore the path we had previously cached as long as it wasn't empty
// If it was empty, set the starting directory to %USERPROFILE%
// (we need to set it to something non-empty otherwise we will automatically
// disable the text box)
if (_lastStartingDirectoryPath.empty())
{
StartingDirectory(L"%USERPROFILE%");
}
else
{
StartingDirectory(_lastStartingDirectoryPath);
}
}
}
bool ProfileViewModel::IsBellStyleFlagSet(const uint32_t flag)
{
return (WI_EnumValue(BellStyle()) & flag) == flag;
}
void ProfileViewModel::SetBellStyleAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Audible, winrt::unbox_value<bool>(on));
BellStyle(currentStyle);
}
void ProfileViewModel::SetBellStyleWindow(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Window, winrt::unbox_value<bool>(on));
BellStyle(currentStyle);
}
void ProfileViewModel::SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Taskbar, winrt::unbox_value<bool>(on));
BellStyle(currentStyle);
}
void ProfileViewModel::DeleteProfile()
{
auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(Guid()) };
_DeleteProfileHandlers(*this, *deleteProfileArgs);
}
}

View File

@@ -0,0 +1,151 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#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 ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
// font face
static void UpdateFontList() noexcept;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> CompleteFontList() noexcept { return _FontList; };
static Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() noexcept { return _MonospaceFontList; };
static ProfilesPivots LastActivePivot() noexcept { return _LastActivePivot; };
static void LastActivePivot(Editor::ProfilesPivots val) noexcept { _LastActivePivot = val; };
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings);
Model::TerminalSettings TermSettings() const;
void DeleteProfile();
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> Schemes() const noexcept;
void Schemes(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& val) noexcept;
// 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);
void SetAcrylicOpacityPercentageValue(double value)
{
Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
// GH#11372: If we're on Windows 10, and someone wants opacity, then
// we'll turn acrylic on for them. Opacity doesn't work without
// acrylic on Windows 10.
//
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
// is basically a "are we on Windows 11" check, because defterm
// only works on Win11. So we'll use that.
//
// Remove when we can remove the rest of GH#11285
if (value < 100.0 &&
!winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings::IsDefaultTerminalAvailable())
{
UseAcrylic(true);
}
};
void SetPadding(double value)
{
Padding(to_hstring(value));
}
// starting directory
bool UseParentProcessDirectory();
void UseParentProcessDirectory(const bool useParent);
bool UseCustomStartingDirectory();
// general profile knowledge
winrt::guid OriginalProfileGuid() const noexcept;
bool CanDeleteProfile() const;
Editor::AppearanceViewModel DefaultAppearance();
Editor::AppearanceViewModel UnfocusedAppearance();
bool HasUnfocusedAppearance();
bool EditableUnfocusedAppearance() const noexcept;
bool ShowUnfocusedAppearance();
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
WINRT_PROPERTY(bool, IsBaseLayer, false);
WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, _profile, AntialiasingMode);
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, _profile, CloseOnExit);
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, _profile, ScrollState);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
OBSERVABLE_PROJECTED_SETTING(_profile, Name);
OBSERVABLE_PROJECTED_SETTING(_profile, Source);
OBSERVABLE_PROJECTED_SETTING(_profile, Hidden);
OBSERVABLE_PROJECTED_SETTING(_profile, Icon);
OBSERVABLE_PROJECTED_SETTING(_profile, CloseOnExit);
OBSERVABLE_PROJECTED_SETTING(_profile, TabTitle);
OBSERVABLE_PROJECTED_SETTING(_profile, TabColor);
OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic);
OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState);
OBSERVABLE_PROJECTED_SETTING(_profile, Padding);
OBSERVABLE_PROJECTED_SETTING(_profile, Commandline);
OBSERVABLE_PROJECTED_SETTING(_profile, StartingDirectory);
OBSERVABLE_PROJECTED_SETTING(_profile, AntialiasingMode);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Foreground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Opacity);
OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize);
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
TYPED_EVENT(DeleteProfile, Editor::ProfileViewModel, Editor::DeleteProfileEventArgs);
private:
Model::Profile _profile;
winrt::guid _originalProfileGuid;
winrt::hstring _lastBgImagePath;
winrt::hstring _lastStartingDirectoryPath;
Editor::AppearanceViewModel _defaultAppearanceViewModel;
Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme> _Schemes;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
static ProfilesPivots _LastActivePivot;
static Editor::Font _GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames);
Model::CascadiaSettings _appSettings;
Editor::AppearanceViewModel _unfocusedAppearanceViewModel;
};
struct DeleteProfileEventArgs :
public DeleteProfileEventArgsT<DeleteProfileEventArgs>
{
public:
DeleteProfileEventArgs(guid profileGuid) :
_ProfileGuid(profileGuid) {}
guid ProfileGuid() const noexcept { return _ProfileGuid; }
private:
guid _ProfileGuid{};
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
// Since we have static functions, we need a factory.
BASIC_FACTORY(ProfileViewModel);
}

View File

@@ -0,0 +1,97 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "EnumEntry.idl";
import "MainPage.idl";
import "Appearances.idl";
#include "ViewModelHelpers.idl.h"
#define OBSERVABLE_PROJECTED_PROFILE_SETTING(Type, Name) \
OBSERVABLE_PROJECTED_SETTING(Type, Name); \
Object Name##OverrideSource { get; }
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass DeleteProfileEventArgs
{
Guid ProfileGuid { get; };
}
enum ProfilesPivots
{
General = 0,
Appearance = 1,
Advanced = 2
};
runtimeclass ProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
static Windows.Foundation.Collections.IObservableVector<Font> CompleteFontList { get; };
static Windows.Foundation.Collections.IObservableVector<Font> MonospaceFontList { get; };
static ProfilesPivots LastActivePivot;
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
event Windows.Foundation.TypedEventHandler<ProfileViewModel, DeleteProfileEventArgs> DeleteProfile;
void SetAcrylicOpacityPercentageValue(Double value);
void SetPadding(Double value);
Boolean IsBellStyleFlagSet(UInt32 flag);
void SetBellStyleAudible(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleWindow(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
IInspectable CurrentAntiAliasingMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AntiAliasingModeList { get; };
IInspectable CurrentCloseOnExitMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CloseOnExitModeList { get; };
IInspectable CurrentScrollState;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; };
Boolean CanDeleteProfile { get; };
Boolean IsBaseLayer;
Boolean UseParentProcessDirectory;
Boolean UseCustomStartingDirectory { get; };
AppearanceViewModel DefaultAppearance { get; };
Guid OriginalProfileGuid { get; };
Boolean HasUnfocusedAppearance { get; };
Boolean EditableUnfocusedAppearance { get; };
Boolean ShowUnfocusedAppearance { get; };
AppearanceViewModel UnfocusedAppearance { get; };
Boolean AtlasEngineAvailable { get; };
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, Guid);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Source);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, ConnectionType);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Hidden);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Icon);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.CloseOnExitMode, CloseOnExit);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, TabTitle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, Opacity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode);
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);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, CursorColor);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, HistorySize);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
}
}

View File

@@ -6,59 +6,10 @@
#include "PreviewConnection.h"
#include "Profiles.g.cpp"
#include "EnumEntry.h"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
// This function is a copy of DxFontInfo::_NearbyCollection() with
// * the call to DxFontInfo::s_GetNearbyFonts() inlined
// * checkForUpdates for GetSystemFontCollection() set to true
static wil::com_ptr<IDWriteFontCollection1> NearbyCollection(IDWriteFactory* dwriteFactory)
{
// The convenience interfaces for loading fonts from files
// are only available on Windows 10+.
wil::com_ptr<IDWriteFactory6> factory6;
// wil's query() facilities don't work inside WinRT land at the moment.
// They produce a compilation error due to IUnknown and winrt::Windows::Foundation::IUnknown being ambiguous.
if (!SUCCEEDED(dwriteFactory->QueryInterface(__uuidof(IDWriteFactory6), factory6.put_void())))
{
return nullptr;
}
wil::com_ptr<IDWriteFontCollection1> systemFontCollection;
THROW_IF_FAILED(factory6->GetSystemFontCollection(false, systemFontCollection.addressof(), true));
wil::com_ptr<IDWriteFontSet> systemFontSet;
THROW_IF_FAILED(systemFontCollection->GetFontSet(systemFontSet.addressof()));
wil::com_ptr<IDWriteFontSetBuilder2> fontSetBuilder2;
THROW_IF_FAILED(factory6->CreateFontSetBuilder(fontSetBuilder2.addressof()));
THROW_IF_FAILED(fontSetBuilder2->AddFontSet(systemFontSet.get()));
{
const std::filesystem::path module{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
const auto folder{ module.parent_path() };
for (const auto& p : std::filesystem::directory_iterator(folder))
{
if (til::ends_with(p.path().native(), L".ttf"))
{
fontSetBuilder2->AddFontFile(p.path().c_str());
}
}
}
wil::com_ptr<IDWriteFontSet> fontSet;
THROW_IF_FAILED(fontSetBuilder2->CreateFontSet(fontSet.addressof()));
wil::com_ptr<IDWriteFontCollection1> fontCollection;
THROW_IF_FAILED(factory6->CreateFontCollectionFromFontSet(fontSet.get(), &fontCollection));
return fontCollection;
}
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
@@ -70,342 +21,11 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
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() },
_appSettings{ appSettings },
_unfocusedAppearanceViewModel{ nullptr }
{
// 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"IsBaseLayer")
{
// we _always_ want to show the background image settings in base layer
_NotifyChanges(L"BackgroundImageSettingsVisible");
}
else if (viewModelProperty == L"StartingDirectory")
{
// notify listener that all starting directory related values might have changed
// NOTE: this is similar to what is done with BackgroundImagePath above
_NotifyChanges(L"UseParentProcessDirectory", L"UseCustomStartingDirectory");
}
else if (viewModelProperty == L"UseAcrylic")
{
// GH#11372: If we're on Windows 10, and someone turns off
// acrylic, we're going to disable opacity for them. Opacity
// doesn't work without acrylic on Windows 10.
//
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
// is basically a "are we on Windows 11" check, because defterm
// only works on Win11. So we'll use that.
//
// Remove when we can remove the rest of GH#11285
if (!UseAcrylic() && !CascadiaSettings::IsDefaultTerminalAvailable())
{
Opacity(1.0);
}
}
});
// Do the same for the starting directory
if (!StartingDirectory().empty())
{
_lastStartingDirectoryPath = StartingDirectory();
}
// generate the font list, if we don't have one
if (!_FontList || !_MonospaceFontList)
{
UpdateFontList();
}
if (profile.HasUnfocusedAppearance())
{
_unfocusedAppearanceViewModel = winrt::make<implementation::AppearanceViewModel>(profile.UnfocusedAppearance().try_as<AppearanceConfig>());
}
_defaultAppearanceViewModel.IsDefault(true);
}
Model::TerminalSettings ProfileViewModel::TermSettings() const
{
return Model::TerminalSettings::CreateWithProfile(_appSettings, _profile, nullptr).DefaultSettings();
}
// Method Description:
// - Updates the lists of fonts and sorts them alphabetically
void ProfileViewModel::UpdateFontList() noexcept
try
{
// initialize font list
std::vector<Editor::Font> fontList;
std::vector<Editor::Font> monospaceFontList;
// get a DWriteFactory
com_ptr<IDWriteFactory> factory;
THROW_IF_FAILED(DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<::IUnknown**>(factory.put())));
// get the font collection; subscribe to updates
const auto fontCollection = NearbyCollection(factory.get());
for (UINT32 i = 0; i < fontCollection->GetFontFamilyCount(); ++i)
{
try
{
// get the font family
com_ptr<IDWriteFontFamily> fontFamily;
THROW_IF_FAILED(fontCollection->GetFontFamily(i, fontFamily.put()));
// get the font's localized names
com_ptr<IDWriteLocalizedStrings> localizedFamilyNames;
THROW_IF_FAILED(fontFamily->GetFamilyNames(localizedFamilyNames.put()));
// construct a font entry for tracking
if (const auto fontEntry{ _GetFont(localizedFamilyNames) })
{
// check if the font is monospaced
try
{
com_ptr<IDWriteFont> font;
THROW_IF_FAILED(fontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_NORMAL,
font.put()));
// add the font name to our list of monospace fonts
const auto castedFont{ font.try_as<IDWriteFont1>() };
if (castedFont && castedFont->IsMonospacedFont())
{
monospaceFontList.emplace_back(fontEntry);
}
}
CATCH_LOG();
// add the font name to our list of all fonts
fontList.emplace_back(std::move(fontEntry));
}
}
CATCH_LOG();
}
// sort and save the lists
std::sort(begin(fontList), end(fontList), FontComparator());
_FontList = single_threaded_observable_vector<Editor::Font>(std::move(fontList));
std::sort(begin(monospaceFontList), end(monospaceFontList), FontComparator());
_MonospaceFontList = single_threaded_observable_vector<Editor::Font>(std::move(monospaceFontList));
}
CATCH_LOG();
Editor::Font ProfileViewModel::_GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames)
{
// used for the font's name as an identifier (i.e. text block's font family property)
std::wstring nameID;
UINT32 nameIDIndex;
// used for the font's localized name
std::wstring localizedName;
UINT32 localizedNameIndex;
// use our current locale to find the localized name
BOOL exists{ FALSE };
HRESULT hr;
wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH))
{
hr = localizedFamilyNames->FindLocaleName(localeName, &localizedNameIndex, &exists);
}
if (SUCCEEDED(hr) && !exists)
{
// if we can't find the font for our locale, fallback to the en-us one
// Source: https://docs.microsoft.com/en-us/windows/win32/api/dwrite/nf-dwrite-idwritelocalizedstrings-findlocalename
hr = localizedFamilyNames->FindLocaleName(L"en-us", &localizedNameIndex, &exists);
}
if (!exists)
{
// failed to find the correct locale, using the first one
localizedNameIndex = 0;
}
// get the localized name
UINT32 nameLength;
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(localizedNameIndex, &nameLength));
localizedName.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(localizedNameIndex, localizedName.data(), nameLength + 1));
// now get the nameID
hr = localizedFamilyNames->FindLocaleName(L"en-us", &nameIDIndex, &exists);
if (FAILED(hr) || !exists)
{
// failed to find it, using the first one
nameIDIndex = 0;
}
// get the nameID
THROW_IF_FAILED(localizedFamilyNames->GetStringLength(nameIDIndex, &nameLength));
nameID.resize(nameLength);
THROW_IF_FAILED(localizedFamilyNames->GetString(nameIDIndex, nameID.data(), nameLength + 1));
if (!nameID.empty() && !localizedName.empty())
{
return make<Font>(nameID, localizedName);
}
return nullptr;
}
IObservableVector<Editor::Font> ProfileViewModel::CompleteFontList() const noexcept
{
return _FontList;
}
IObservableVector<Editor::Font> ProfileViewModel::MonospaceFontList() const noexcept
{
return _MonospaceFontList;
}
winrt::guid ProfileViewModel::OriginalProfileGuid() const noexcept
{
return _originalProfileGuid;
}
bool ProfileViewModel::CanDeleteProfile() const
{
return !IsBaseLayer();
}
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance()
{
return _defaultAppearanceViewModel;
}
bool ProfileViewModel::HasUnfocusedAppearance()
{
return _profile.HasUnfocusedAppearance();
}
bool ProfileViewModel::EditableUnfocusedAppearance() const noexcept
{
return Feature_EditableUnfocusedAppearance::IsEnabled();
}
bool ProfileViewModel::ShowUnfocusedAppearance()
{
return EditableUnfocusedAppearance() && HasUnfocusedAppearance();
}
void ProfileViewModel::CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
const IHostedInWindow& windowRoot)
{
_profile.CreateUnfocusedAppearance();
_unfocusedAppearanceViewModel = winrt::make<implementation::AppearanceViewModel>(_profile.UnfocusedAppearance().try_as<AppearanceConfig>());
_unfocusedAppearanceViewModel.Schemes(schemes);
_unfocusedAppearanceViewModel.WindowRoot(windowRoot);
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
}
void ProfileViewModel::DeleteUnfocusedAppearance()
{
_profile.DeleteUnfocusedAppearance();
_unfocusedAppearanceViewModel = nullptr;
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
}
Editor::AppearanceViewModel ProfileViewModel::UnfocusedAppearance()
{
return _unfocusedAppearanceViewModel;
}
bool ProfileViewModel::AtlasEngineAvailable() const noexcept
{
return Feature_AtlasEngine::IsEnabled();
}
bool ProfileViewModel::UseParentProcessDirectory()
{
return StartingDirectory().empty();
}
// This function simply returns the opposite of UseParentProcessDirectory.
// We bind the 'IsEnabled' parameters of the textbox and browse button
// to this because it needs to be the reverse of UseParentProcessDirectory
// but we don't want to create a whole new converter for inverting a boolean
bool ProfileViewModel::UseCustomStartingDirectory()
{
return !UseParentProcessDirectory();
}
void ProfileViewModel::UseParentProcessDirectory(const bool useParent)
{
if (useParent)
{
// Stash the current value of StartingDirectory. If the user
// checks and un-checks the "Use parent process directory" button, we want
// the path that we display in the text box to remain unchanged.
//
// Only stash this value if it's not empty
if (!StartingDirectory().empty())
{
_lastStartingDirectoryPath = StartingDirectory();
}
StartingDirectory(L"");
}
else
{
// Restore the path we had previously cached as long as it wasn't empty
// If it was empty, set the starting directory to %USERPROFILE%
// (we need to set it to something non-empty otherwise we will automatically
// disable the text box)
if (_lastStartingDirectoryPath.empty())
{
StartingDirectory(L"%USERPROFILE%");
}
else
{
StartingDirectory(_lastStartingDirectoryPath);
}
}
}
void ProfilePageNavigationState::DeleteProfile()
{
auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(_Profile.Guid()) };
_DeleteProfileHandlers(*this, *deleteProfileArgs);
}
void ProfilePageNavigationState::CreateUnfocusedAppearance()
{
_Profile.CreateUnfocusedAppearance(_Schemes, _WindowRoot);
}
void ProfilePageNavigationState::DeleteUnfocusedAppearance()
{
_Profile.DeleteUnfocusedAppearance();
}
Profiles::Profiles() :
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
{
InitializeComponent();
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");
const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
@@ -418,16 +38,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
{
_State = e.Parameter().as<Editor::ProfilePageNavigationState>();
auto state{ e.Parameter().as<Editor::ProfilePageNavigationState>() };
_Profile = state.Profile();
// generate the font list, if we don't have one
if (!_State.Profile().CompleteFontList() || !_State.Profile().MonospaceFontList())
if (!ProfileViewModel::CompleteFontList() || !ProfileViewModel::MonospaceFontList())
{
ProfileViewModel::UpdateFontList();
}
// Check the use parent directory box if the starting directory is empty
if (_State.Profile().StartingDirectory().empty())
if (_Profile.StartingDirectory().empty())
{
StartingDirectoryUseParentCheckbox().IsChecked(true);
}
@@ -435,7 +56,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Subscribe to some changes in the view model
// These changes should force us to update our own set of "Current<Setting>" members,
// and propagate those changes to the UI
_ViewModelChangedRevoker = _State.Profile().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
_ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
const auto settingName{ args.PropertyName() };
if (settingName == L"AntialiasingMode")
{
@@ -453,23 +74,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentScrollState" });
}
_previewControl.UpdateControlSettings(_State.Profile().TermSettings());
_previewControl.UpdateControlSettings(_Profile.TermSettings());
});
// 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.UpdateControlSettings(_State.Profile().TermSettings());
_AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
_previewControl.UpdateControlSettings(_Profile.TermSettings());
});
// Navigate to the pivot in the provided navigation state
ProfilesPivot().SelectedIndex(static_cast<int>(_State.LastActivePivot()));
ProfilesPivot().SelectedIndex(static_cast<int>(ProfileViewModel::LastActivePivot()));
// There is a possibility that the control has not fully initialized yet,
// so wait for it to initialize before updating the settings (so we know
// that the renderer is set up)
_previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
_previewControl.UpdateControlSettings(_State.Profile().TermSettings());
_previewControl.UpdateControlSettings(_Profile.TermSettings());
});
}
@@ -479,57 +100,30 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_AppearanceViewModelChangedRevoker.revoke();
}
bool Profiles::IsBellStyleFlagSet(const uint32_t flag)
{
return (WI_EnumValue(_State.Profile().BellStyle()) & flag) == flag;
}
void Profiles::SetBellStyleAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = State().Profile().BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Audible, winrt::unbox_value<bool>(on));
State().Profile().BellStyle(currentStyle);
}
void Profiles::SetBellStyleWindow(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = State().Profile().BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Window, winrt::unbox_value<bool>(on));
State().Profile().BellStyle(currentStyle);
}
void Profiles::SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = State().Profile().BellStyle();
WI_UpdateFlag(currentStyle, Model::BellStyle::Taskbar, winrt::unbox_value<bool>(on));
State().Profile().BellStyle(currentStyle);
}
void Profiles::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
auto state{ winrt::get_self<ProfilePageNavigationState>(_State) };
state->DeleteProfile();
winrt::get_self<ProfileViewModel>(_Profile)->DeleteProfile();
}
void Profiles::CreateUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_State.CreateUnfocusedAppearance();
_Profile.CreateUnfocusedAppearance();
}
void Profiles::DeleteUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_State.DeleteUnfocusedAppearance();
_Profile.DeleteUnfocusedAppearance();
}
fire_and_forget Profiles::Icon_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_State.Profile().Icon(file);
_Profile.Icon(file);
}
}
@@ -543,7 +137,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
};
static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
auto path = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExecutables));
try
@@ -559,14 +153,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (!path.empty())
{
_State.Profile().Commandline(path);
_Profile.Commandline(path);
}
}
fire_and_forget Profiles::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
auto folder = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
static constexpr winrt::guid clientGuidFolderPicker{ 0xAADAA433, 0xB04D, 0x4BAE, { 0xB1, 0xEA, 0x1E, 0x6C, 0xD1, 0xCD, 0xA6, 0x8B } };
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidFolderPicker));
@@ -584,13 +178,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (!folder.empty())
{
_State.Profile().StartingDirectory(folder);
_Profile.StartingDirectory(folder);
}
}
void Profiles::Pivot_SelectionChanged(Windows::Foundation::IInspectable const& /*sender*/,
RoutedEventArgs const& /*e*/)
{
_State.LastActivePivot(static_cast<Editor::ProfilesPivots>(ProfilesPivot().SelectedIndex()));
ProfileViewModel::LastActivePivot(static_cast<Editor::ProfilesPivots>(ProfilesPivot().SelectedIndex()));
}
}

View File

@@ -5,143 +5,25 @@
#include "Profiles.g.h"
#include "ProfilePageNavigationState.g.h"
#include "DeleteProfileEventArgs.g.h"
#include "ProfileViewModel.g.h"
#include "ProfileViewModel.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
#include "Appearances.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings);
Model::TerminalSettings TermSettings() const;
void SetAcrylicOpacityPercentageValue(double value)
{
Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
// GH#11372: If we're on Windows 10, and someone wants opacity, then
// we'll turn acrylic on for them. Opacity doesn't work without
// acrylic on Windows 10.
//
// BODGY: CascadiaSettings's function IsDefaultTerminalAvailable
// is basically a "are we on Windows 11" check, because defterm
// only works on Win11. So we'll use that.
//
// Remove when we can remove the rest of GH#11285
if (value < 100.0 &&
!winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings::IsDefaultTerminalAvailable())
{
UseAcrylic(true);
}
};
void SetPadding(double value)
{
Padding(to_hstring(value));
}
// starting directory
bool UseParentProcessDirectory();
void UseParentProcessDirectory(const bool useParent);
bool UseCustomStartingDirectory();
// font face
static void UpdateFontList() noexcept;
Windows::Foundation::Collections::IObservableVector<Editor::Font> CompleteFontList() const noexcept;
Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() const noexcept;
// general profile knowledge
winrt::guid OriginalProfileGuid() const noexcept;
bool CanDeleteProfile() const;
Editor::AppearanceViewModel DefaultAppearance();
Editor::AppearanceViewModel UnfocusedAppearance();
bool HasUnfocusedAppearance();
bool EditableUnfocusedAppearance() const noexcept;
bool ShowUnfocusedAppearance();
void CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
const IHostedInWindow& windowRoot);
void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
WINRT_PROPERTY(bool, IsBaseLayer, false);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
OBSERVABLE_PROJECTED_SETTING(_profile, Name);
OBSERVABLE_PROJECTED_SETTING(_profile, Source);
OBSERVABLE_PROJECTED_SETTING(_profile, Hidden);
OBSERVABLE_PROJECTED_SETTING(_profile, Icon);
OBSERVABLE_PROJECTED_SETTING(_profile, CloseOnExit);
OBSERVABLE_PROJECTED_SETTING(_profile, TabTitle);
OBSERVABLE_PROJECTED_SETTING(_profile, TabColor);
OBSERVABLE_PROJECTED_SETTING(_profile, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAcrylic);
OBSERVABLE_PROJECTED_SETTING(_profile, ScrollState);
OBSERVABLE_PROJECTED_SETTING(_profile, Padding);
OBSERVABLE_PROJECTED_SETTING(_profile, Commandline);
OBSERVABLE_PROJECTED_SETTING(_profile, StartingDirectory);
OBSERVABLE_PROJECTED_SETTING(_profile, AntialiasingMode);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Foreground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), CursorColor);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Opacity);
OBSERVABLE_PROJECTED_SETTING(_profile, HistorySize);
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
private:
Model::Profile _profile;
winrt::guid _originalProfileGuid;
winrt::hstring _lastBgImagePath;
winrt::hstring _lastStartingDirectoryPath;
Editor::AppearanceViewModel _defaultAppearanceViewModel;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
static Editor::Font _GetFont(com_ptr<IDWriteLocalizedStrings> localizedFamilyNames);
Model::CascadiaSettings _appSettings;
Editor::AppearanceViewModel _unfocusedAppearanceViewModel;
};
struct DeleteProfileEventArgs :
public DeleteProfileEventArgsT<DeleteProfileEventArgs>
{
public:
DeleteProfileEventArgs(guid profileGuid) :
_ProfileGuid(profileGuid) {}
guid ProfileGuid() const noexcept { return _ProfileGuid; }
private:
guid _ProfileGuid{};
};
struct ProfilePageNavigationState : ProfilePageNavigationStateT<ProfilePageNavigationState>
{
public:
ProfilePageNavigationState(const Editor::ProfileViewModel& viewModel,
const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
const Editor::ProfilePageNavigationState& lastState,
const IHostedInWindow& windowRoot) :
_Profile{ viewModel },
_Schemes{ schemes },
_WindowRoot{ windowRoot }
_Profile{ viewModel }
{
// If there was a previous nav state copy the selected pivot from it.
if (lastState)
{
_LastActivePivot = lastState.LastActivePivot();
}
auto profile{ winrt::get_self<ProfileViewModel>(viewModel) };
profile->Schemes(schemes);
profile->WindowRoot(windowRoot);
viewModel.DefaultAppearance().Schemes(schemes);
viewModel.DefaultAppearance().WindowRoot(windowRoot);
@@ -151,20 +33,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
viewModel.UnfocusedAppearance().WindowRoot(windowRoot);
}
}
void DeleteProfile();
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
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 : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
@@ -175,12 +44,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
// 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 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);
@@ -191,10 +54,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfilePageNavigationState, State, nullptr);
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);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
void _UpdateBIAlignmentControl(const int32_t val);

View File

@@ -1,113 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "EnumEntry.idl";
import "MainPage.idl";
import "Appearances.idl";
#include "ViewModelHelpers.idl.h"
#define OBSERVABLE_PROJECTED_PROFILE_SETTING(Type, Name) \
OBSERVABLE_PROJECTED_SETTING(Type, Name); \
Object Name##OverrideSource { get; }
import "ProfileViewModel.idl";
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass ProfileViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Windows.Foundation.Collections.IObservableVector<Font> CompleteFontList { get; };
Windows.Foundation.Collections.IObservableVector<Font> MonospaceFontList { get; };
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
void SetAcrylicOpacityPercentageValue(Double value);
void SetPadding(Double value);
Boolean CanDeleteProfile { get; };
Boolean IsBaseLayer;
Boolean UseParentProcessDirectory;
Boolean UseCustomStartingDirectory { get; };
AppearanceViewModel DefaultAppearance { get; };
Guid OriginalProfileGuid { get; };
Boolean HasUnfocusedAppearance { get; };
Boolean EditableUnfocusedAppearance { get; };
Boolean ShowUnfocusedAppearance { get; };
AppearanceViewModel UnfocusedAppearance { get; };
Boolean AtlasEngineAvailable { get; };
void CreateUnfocusedAppearance(Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes, IHostedInWindow WindowRoot);
void DeleteUnfocusedAppearance();
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, Guid);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Source);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, ConnectionType);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Hidden);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Icon);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.CloseOnExitMode, CloseOnExit);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, TabTitle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, TabColor);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SuppressApplicationTitle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAcrylic);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Double, Opacity);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.ScrollbarState, ScrollState);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Padding);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode);
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);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, CursorColor);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Int32, HistorySize);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
}
runtimeclass DeleteProfileEventArgs
{
Guid ProfileGuid { get; };
}
enum ProfilesPivots
{
General = 0,
Appearance = 1,
Advanced = 2
};
runtimeclass ProfilePageNavigationState
{
IHostedInWindow WindowRoot; // necessary to send the right HWND into the file picker dialogs.
ProfileViewModel Profile;
ProfilesPivots LastActivePivot;
void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance();
event Windows.Foundation.TypedEventHandler<ProfilePageNavigationState, DeleteProfileEventArgs> DeleteProfile;
ProfileViewModel Profile { get; };
};
[default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Profiles();
ProfilePageNavigationState State { get; };
Boolean IsBellStyleFlagSet(UInt32 flag);
void SetBellStyleAudible(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleWindow(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
IInspectable CurrentAntiAliasingMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AntiAliasingModeList { get; };
IInspectable CurrentCloseOnExitMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CloseOnExitModeList { get; };
IInspectable CurrentScrollState;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; };
ProfileViewModel Profile { get; };
Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
}

View File

@@ -47,7 +47,7 @@
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind State.Profile.IsBaseLayer}" />
Visibility="{x:Bind Profile.IsBaseLayer}" />
<Pivot x:Name="ProfilesPivot"
Grid.Row="1"
@@ -67,24 +67,24 @@
-->
<local:SettingContainer x:Uid="Profile_Name"
Margin="0,0,0,24"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Name, Mode=TwoWay}" />
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
Margin="0,0,0,24"
ClearSettingValue="{x:Bind State.Profile.ClearCommandline}"
HasSettingValue="{x:Bind State.Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CommandlineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Commandline, Mode=TwoWay}" />
Text="{x:Bind Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
@@ -95,39 +95,39 @@
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearStartingDirectory}"
HasSettingValue="{x:Bind State.Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.StartingDirectoryOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.StartingDirectory, Mode=TwoWay}" />
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
IsChecked="{x:Bind State.Profile.UseParentProcessDirectory, Mode=TwoWay}" />
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind State.Profile.ClearIcon}"
HasSettingValue="{x:Bind State.Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.IconOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearIcon}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe MDL2 Assets"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Icon, Mode=TwoWay}" />
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
@@ -136,24 +136,24 @@
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind State.Profile.ClearTabTitle}"
HasSettingValue="{x:Bind State.Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.TabTitleOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.TabTitle, Mode=TwoWay}" />
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.Hidden, Mode=TwoWay}" />
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Delete Button -->
<Button x:Name="DeleteButton"
Margin="{StaticResource StandardControlMargin}"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind State.Profile.CanDeleteProfile}">
Visibility="{x:Bind Profile.CanDeleteProfile}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
@@ -238,8 +238,8 @@
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<local:Appearances Appearance="{x:Bind State.Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind State.Profile, Mode=OneWay}" />
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
@@ -250,9 +250,9 @@
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearOpacity}"
HasSettingValue="{x:Bind State.Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.OpacityOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
<StackPanel x:Name="OpacityControl">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
@@ -261,7 +261,7 @@
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
Grid.Column="0"
Value="{x:Bind local:Converters.PercentageToPercentageValue(State.Profile.Opacity), BindBack=State.Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
Value="{x:Bind local:Converters.PercentageToPercentageValue(Profile.Opacity), BindBack=Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{x:Bind local:Converters.AppendPercentageSign(OpacitySlider.Value), Mode=OneWay}" />
@@ -272,11 +272,11 @@
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind State.Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.UseAcrylicOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch x:Name="UseAcrylicToggleSwitch"
IsOn="{x:Bind State.Profile.UseAcrylic, Mode=TwoWay}" />
IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
@@ -289,9 +289,9 @@
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearPadding}"
HasSettingValue="{x:Bind State.Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.PaddingOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearPadding}"
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.PaddingOverrideSource, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@@ -299,7 +299,7 @@
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
Grid.Column="0"
Value="{x:Bind local:Converters.MaxValueFromPaddingString(State.Profile.Padding), BindBack=State.Profile.SetPadding, Mode=TwoWay}" />
Value="{x:Bind local:Converters.MaxValueFromPaddingString(Profile.Padding), BindBack=Profile.SetPadding, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=PaddingSlider, Path=Value, Mode=OneWay}" />
@@ -308,25 +308,25 @@
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind State.Profile.ClearScrollState}"
HasSettingValue="{x:Bind State.Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.ScrollStateOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentScrollState, Mode=TwoWay}" />
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance}">
Visibility="{x:Bind Profile.EditableUnfocusedAppearance}">
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
Margin="32,0,0,0"
Click="CreateUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.HasUnfocusedAppearance), Mode=OneWay}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
@@ -336,7 +336,7 @@
Margin="32,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind State.Profile.HasUnfocusedAppearance, Mode=OneWay}">
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
@@ -391,9 +391,9 @@
</Button.Resources>
</Button>
</StackPanel>
<local:Appearances Appearance="{x:Bind State.Profile.UnfocusedAppearance, Mode=OneWay}"
SourceProfile="{x:Bind State.Profile, Mode=OneWay}"
Visibility="{x:Bind State.Profile.ShowUnfocusedAppearance, Mode=OneWay}" />
<local:Appearances Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}"
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
@@ -406,85 +406,85 @@
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearSuppressApplicationTitle}"
HasSettingValue="{x:Bind State.Profile.HasSuppressApplicationTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.SuppressApplicationTitle, Mode=TwoWay}" />
ClearSettingValue="{x:Bind Profile.ClearSuppressApplicationTitle}"
HasSettingValue="{x:Bind Profile.HasSuppressApplicationTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SuppressApplicationTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Antialiasing Mode -->
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
ClearSettingValue="{x:Bind State.Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind State.Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind AntiAliasingModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentAntiAliasingMode, Mode=TwoWay}" />
ItemsSource="{x:Bind Profile.AntiAliasingModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentAntiAliasingMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- AltGr Aliasing -->
<local:SettingContainer x:Uid="Profile_AltGrAliasing"
ClearSettingValue="{x:Bind State.Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind State.Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.AltGrAliasing, Mode=TwoWay}" />
ClearSettingValue="{x:Bind Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AltGrAliasing, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Snap On Input -->
<local:SettingContainer x:Uid="Profile_SnapOnInput"
ClearSettingValue="{x:Bind State.Profile.ClearSnapOnInput}"
HasSettingValue="{x:Bind State.Profile.HasSnapOnInput, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.SnapOnInputOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.SnapOnInput, Mode=TwoWay}" />
ClearSettingValue="{x:Bind Profile.ClearSnapOnInput}"
HasSettingValue="{x:Bind Profile.HasSnapOnInput, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.SnapOnInputOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.SnapOnInput, Mode=TwoWay}" />
</local:SettingContainer>
<!-- History Size -->
<local:SettingContainer x:Uid="Profile_HistorySize"
ClearSettingValue="{x:Bind State.Profile.ClearHistorySize}"
HasSettingValue="{x:Bind State.Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.HistorySizeOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearHistorySize}"
HasSettingValue="{x:Bind Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.HistorySizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox x:Uid="Profile_HistorySizeBox"
LargeChange="100"
Minimum="0"
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind State.Profile.HistorySize, Mode=TwoWay}" />
Value="{x:Bind Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind State.Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind State.Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CloseOnExitOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind CloseOnExitModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentCloseOnExitMode, Mode=TwoWay}" />
ItemsSource="{x:Bind Profile.CloseOnExitModeList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentCloseOnExitMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Bell Style -->
<local:SettingContainer x:Uid="Profile_BellStyle"
ClearSettingValue="{x:Bind State.Profile.ClearBellStyle}"
HasSettingValue="{x:Bind State.Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BellStyleOverrideSource, Mode=OneWay}">
ClearSettingValue="{x:Bind Profile.ClearBellStyle}"
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.BellStyleOverrideSource, Mode=OneWay}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind IsBellStyleFlagSet(1), BindBack=SetBellStyleAudible, Mode=TwoWay}" />
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(1), BindBack=Profile.SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind IsBellStyleFlagSet(2), BindBack=SetBellStyleWindow, Mode=TwoWay}" />
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(2), BindBack=Profile.SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" />
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(4), BindBack=Profile.SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
ClearSettingValue="{x:Bind State.Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind State.Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.UseAtlasEngineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.AtlasEngineAvailable}">
<ToggleSwitch IsOn="{x:Bind State.Profile.UseAtlasEngine, Mode=TwoWay}" />
ClearSettingValue="{x:Bind Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.UseAtlasEngineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Profile.AtlasEngineAvailable}">
<ToggleSwitch IsOn="{x:Bind Profile.UseAtlasEngine, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>

View File

@@ -49,29 +49,29 @@
// of EnumEntries so that we may display all possible values of the given
// enum type and its localized names. It also provides a getter and setter
// for the setting we wish to bind to.
#define GETSET_BINDABLE_ENUM_SETTING(name, enumType, settingsModelName, settingNameInModel) \
public: \
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> name##List() \
{ \
return _##name##List; \
} \
\
winrt::Windows::Foundation::IInspectable Current##name() \
{ \
return winrt::box_value<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry>(_##name##Map.Lookup(settingsModelName().settingNameInModel())); \
} \
\
void Current##name(const winrt::Windows::Foundation::IInspectable& enumEntry) \
{ \
if (auto ee = enumEntry.try_as<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry>()) \
{ \
auto setting = winrt::unbox_value<enumType>(ee.EnumValue()); \
settingsModelName().settingNameInModel(setting); \
} \
} \
\
private: \
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _##name##List; \
#define GETSET_BINDABLE_ENUM_SETTING(name, enumType, settingsModelName, settingNameInModel) \
public: \
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> name##List() \
{ \
return _##name##List; \
} \
\
winrt::Windows::Foundation::IInspectable Current##name() \
{ \
return winrt::box_value<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry>(_##name##Map.Lookup(settingsModelName.settingNameInModel())); \
} \
\
void Current##name(const winrt::Windows::Foundation::IInspectable& enumEntry) \
{ \
if (auto ee = enumEntry.try_as<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry>()) \
{ \
auto setting = winrt::unbox_value<enumType>(ee.EnumValue()); \
settingsModelName.settingNameInModel(setting); \
} \
} \
\
private: \
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _##name##List; \
winrt::Windows::Foundation::Collections::IMap<enumType, winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _##name##Map;
// This macro defines a dependency property for a WinRT class.