Add a BreadcrumbBar to the SUI (#12144)

## Summary of the Pull Request
**Note: This PR targets #11720**

Replaces our old pivot-style settings UI with a breadcrumb bar style, as per the windows 11 style guidelines. This required splitting `Profiles.xaml` into 3 separate files, `Profiles_Base.xaml` for general settings, `Profiles_Appearance.xaml` for appearance settings, `Profiles_Advanced.xaml` for advanced settings

The header in the navigation view is now a [BreadcrumbBar](https://docs.microsoft.com/en-us/windows/apps/design/controls/breadcrumbbar), which can be used to navigate back to `Profiles_Base` after moving into the advanced or appearance page (see GIF below)

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
![breadcrumb](https://user-images.githubusercontent.com/26824113/150410517-2232811e-4f5b-4732-9a0d-569cc94093b3.gif)
This commit is contained in:
PankajBhojwani 2022-01-28 10:45:52 -08:00 committed by GitHub
parent 3499e5cf9c
commit 21d30b1904
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 1317 additions and 748 deletions

View File

@ -2,6 +2,8 @@ admins
apc
Apc
bsd
breadcrumb
breadcrumbs
calt
CMMI
ccmp

View File

@ -65,7 +65,7 @@
HasSettingValue="{x:Bind Appearance.HasFontFace, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontFaceOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<StackPanel>
<StackPanel Margin="0,8,0,0">
<!--
Binding the ItemsSource to a separate variable that switches between the
two font lists causes a crash within the ComboBox code.

View File

@ -786,7 +786,85 @@
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ToggleButtonStyle"
TargetType="ToggleButton">
<Setter Property="Background" Value="{ThemeResource ExpanderHeaderBackground}" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="Margin" Value="0,4,8,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="Grid"
Padding="{TemplateBinding Padding}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="ContentPresenter"
Grid.Column="0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<FontIcon Margin="20,0,8,0"
HorizontalAlignment="Right"
FontSize="10"
FontWeight="Black"
Glyph="&#xE76C;" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

View File

@ -28,6 +28,7 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::Foundation::Collections;
static const std::wstring_view launchTag{ L"Launch_Nav" };
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
@ -58,6 +59,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Automation::AutomationProperties::SetHelpText(SaveButton(), RS_(L"Settings_SaveSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
Automation::AutomationProperties::SetHelpText(ResetButton(), RS_(L"Settings_ResetSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
Automation::AutomationProperties::SetHelpText(OpenJsonNavItem(), RS_(L"Nav_OpenJSON/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
_breadcrumbs = single_threaded_observable_vector<IInspectable>();
}
// Method Description:
@ -72,16 +75,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_settingsClone = settings.Copy();
// Deduce information about the currently selected item
IInspectable selectedItemTag;
auto menuItems{ SettingsNav().MenuItems() };
if (const auto& selectedItem{ SettingsNav().SelectedItem() })
IInspectable lastBreadcrumb;
const auto size = _breadcrumbs.Size();
if (size > 0)
{
if (const auto& navViewItem{ selectedItem.try_as<MUX::Controls::NavigationViewItem>() })
{
selectedItemTag = navViewItem.Tag();
}
lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
}
auto menuItems{ SettingsNav().MenuItems() };
// We'll remove a bunch of items and iterate over it twice.
// --> Copy it into an STL vector to simplify our code and reduce COM overhead.
std::vector<IInspectable> menuItemsSTL(menuItems.Size(), nullptr);
@ -128,8 +130,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// We'll update the profile in the _profilesNavState whenever we actually navigate to one
// now that the menuItems are repopulated,
// refresh the current page using the SelectedItem data we collected before the refresh
if (selectedItemTag)
// refresh the current page using the breadcrumb data we collected before the refresh
if (const auto& crumb{ lastBreadcrumb.try_as<Breadcrumb>() })
{
for (const auto& item : menuItems)
{
@ -139,26 +141,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
if (const auto& stringTag{ tag.try_as<hstring>() })
{
if (const auto& selectedItemStringTag{ selectedItemTag.try_as<hstring>() })
if (const auto& breadcrumbStringTag{ crumb->Tag().try_as<hstring>() })
{
if (stringTag == selectedItemStringTag)
if (stringTag == breadcrumbStringTag)
{
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
_Navigate(*stringTag);
_Navigate(*stringTag, crumb->SubPage());
return;
}
}
}
else if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
{
if (const auto& selectedItemProfileTag{ selectedItemTag.try_as<ProfileViewModel>() })
if (const auto& breadcrumbProfileTag{ crumb->Tag().try_as<ProfileViewModel>() })
{
if (profileTag->OriginalProfileGuid() == selectedItemProfileTag->OriginalProfileGuid())
if (profileTag->OriginalProfileGuid() == breadcrumbProfileTag->OriginalProfileGuid())
{
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
_Navigate(*profileTag);
_Navigate(*profileTag, crumb->SubPage());
return;
}
}
@ -173,7 +175,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// We can use menuItemsSTL here because the only things they miss are profile entries.
const auto& firstItem{ menuItemsSTL.at(0).as<MUX::Controls::NavigationViewItem>() };
SettingsNav().SelectedItem(firstItem);
_Navigate(unbox_value<hstring>(firstItem.Tag()));
_Navigate(unbox_value<hstring>(firstItem.Tag()), BreadcrumbSubPage::None);
}
void MainPage::SetHostingWindow(uint64_t hostingWindow) noexcept
@ -242,7 +244,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Manually navigate because setting the selected item programmatically doesn't trigger ItemInvoked.
if (const auto tag = initialItem.as<MUX::Controls::NavigationViewItem>().Tag())
{
_Navigate(unbox_value<hstring>(tag));
_Navigate(unbox_value<hstring>(tag), BreadcrumbSubPage::None);
}
}
}
@ -266,33 +268,96 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (const auto navString = clickedItemContainer.Tag().try_as<hstring>())
{
_Navigate(*navString);
_Navigate(*navString, BreadcrumbSubPage::None);
}
else if (const auto profile = clickedItemContainer.Tag().try_as<Editor::ProfileViewModel>())
{
// Navigate to a page with the given profile
_Navigate(profile);
_Navigate(profile, BreadcrumbSubPage::None);
}
}
}
void MainPage::_Navigate(hstring clickedItemTag)
void MainPage::_PreNavigateHelper()
{
_profileViewModelChangedRevoker.revoke();
_breadcrumbs.Clear();
}
void MainPage::_SetupProfileEventHandling(const Editor::ProfilePageNavigationState state)
{
// Add an event handler to navigate to Profiles_Appearance or Profiles_Advanced
// Some notes on this:
// - At first we tried putting another frame inside Profiles.xaml and having that
// frame default to showing Profiles_Base. This allowed the logic for navigation
// to Profiles_Advanced/Profiles_Appearance to live within Profiles.cpp.
// - However, the header for the SUI lives in MainPage.xaml (because that's where
// the whole NavigationView is) and so the BreadcrumbBar needs to be in MainPage.xaml.
// We decided that it's better for the owner of the BreadcrumbBar to also be responsible
// for navigation, so the navigation to Profiles_Advanced/Profiles_Appearance from
// Profiles_Base got moved here.
const auto profile = state.Profile();
// If this is the base layer, the breadcrumb tag should be the globalProfileTag instead of the
// ProfileViewModel, because the navigation menu item for this profile is the globalProfileTag.
// See MainPage::UpdateSettings for why this matters
const auto breadcrumbTag = profile.IsBaseLayer() ? box_value(globalProfileTag) : box_value(profile);
const auto breadcrumbText = profile.IsBaseLayer() ? RS_(L"Nav_ProfileDefaults/Content") : profile.Name();
_profileViewModelChangedRevoker = profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
const auto settingName{ args.PropertyName() };
if (settingName == L"CurrentPage")
{
const auto currentPage = profile.CurrentPage();
if (currentPage == ProfileSubPage::Base)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), state);
_breadcrumbs.Clear();
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (currentPage == ProfileSubPage::Appearance)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), state);
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance);
_breadcrumbs.Append(crumb);
}
else if (currentPage == ProfileSubPage::Advanced)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), state);
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced);
_breadcrumbs.Append(crumb);
}
}
});
}
void MainPage::_Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage)
{
_PreNavigateHelper();
if (clickedItemTag == launchTag)
{
contentFrame().Navigate(xaml_typename<Editor::Launch>(), winrt::make<LaunchPageNavigationState>(_settingsClone));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Launch/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == interactionTag)
{
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<InteractionPageNavigationState>(_settingsClone.GlobalSettings()));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Interaction/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == renderingTag)
{
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<RenderingPageNavigationState>(_settingsClone.GlobalSettings()));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Rendering/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == actionsTag)
{
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<ActionsPageNavigationState>(_settingsClone));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Actions/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == globalProfileTag)
{
@ -302,21 +367,41 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), state);
_SetupProfileEventHandling(state);
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), state);
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ProfileDefaults/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
// If we were given a label, make sure we are on the correct sub-page
if (subPage == BreadcrumbSubPage::Profile_Appearance)
{
profileVM.CurrentPage(ProfileSubPage::Appearance);
}
else if (subPage == BreadcrumbSubPage::Profile_Advanced)
{
profileVM.CurrentPage(ProfileSubPage::Advanced);
}
}
else if (clickedItemTag == colorSchemesTag)
{
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), _colorSchemesNavState);
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == globalAppearanceTag)
{
contentFrame().Navigate(xaml_typename<Editor::GlobalAppearance>(), winrt::make<GlobalAppearancePageNavigationState>(_settingsClone.GlobalSettings()));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Appearance/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == addProfileTag)
{
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone) };
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
contentFrame().Navigate(xaml_typename<Editor::AddProfile>(), addProfileState);
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
}
@ -325,16 +410,37 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// - NOTE: this does not update the selected item.
// Arguments:
// - profile - the profile object we are getting a view of
void MainPage::_Navigate(const Editor::ProfileViewModel& profile)
void MainPage::_Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage)
{
auto state{ winrt::make<ProfilePageNavigationState>(profile,
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
_PreNavigateHelper();
// Add an event handler for when the user wants to delete a profile.
profile.DeleteProfile({ this, &MainPage::_DeleteProfile });
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), state);
_SetupProfileEventHandling(state);
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), state);
const auto crumb = winrt::make<Breadcrumb>(box_value(profile), profile.Name(), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
// Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
// event handler will do it
if (subPage == BreadcrumbSubPage::None)
{
profile.CurrentPage(ProfileSubPage::Base);
}
else if (subPage == BreadcrumbSubPage::Profile_Appearance)
{
profile.CurrentPage(ProfileSubPage::Appearance);
}
else if (subPage == BreadcrumbSubPage::Profile_Advanced)
{
profile.CurrentPage(ProfileSubPage::Advanced);
}
}
void MainPage::OpenJsonTapped(IInspectable const& /*sender*/, Windows::UI::Xaml::Input::TappedRoutedEventArgs const& /*args*/)
@ -368,6 +474,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
UpdateSettings(_settingsSource);
}
void MainPage::BreadcrumbBar_ItemClicked(Microsoft::UI::Xaml::Controls::BreadcrumbBar const& /*sender*/, Microsoft::UI::Xaml::Controls::BreadcrumbBarItemClickedEventArgs const& args)
{
const auto tag = args.Item().as<Breadcrumb>()->Tag();
const auto subPage = args.Item().as<Breadcrumb>()->SubPage();
if (const auto profileViewModel = tag.try_as<ProfileViewModel>())
{
_Navigate(*profileViewModel, subPage);
}
else
{
_Navigate(tag.as<hstring>(), subPage);
}
}
void MainPage::_InitializeProfilesList()
{
const auto menuItems = SettingsNav().MenuItems();
@ -407,7 +527,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Select and navigate to the new profile
SettingsNav().SelectedItem(navItem);
_Navigate(profileViewModel);
_Navigate(profileViewModel, BreadcrumbSubPage::None);
}
MUX::Controls::NavigationViewItem MainPage::_CreateProfileNavViewItem(const Editor::ProfileViewModel& profile)
@ -467,7 +587,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// navigate to the profile next to this one
const auto newSelectedItem{ menuItems.GetAt(index < menuItems.Size() - 1 ? index : index - 1) };
SettingsNav().SelectedItem(newSelectedItem);
_Navigate(newSelectedItem.try_as<MUX::Controls::NavigationViewItem>().Tag().try_as<Editor::ProfileViewModel>());
_Navigate(newSelectedItem.try_as<MUX::Controls::NavigationViewItem>().Tag().try_as<Editor::ProfileViewModel>(), BreadcrumbSubPage::None);
}
IObservableVector<IInspectable> MainPage::Breadcrumbs() noexcept
{
return _breadcrumbs;
}
}

View File

@ -4,10 +4,23 @@
#pragma once
#include "MainPage.g.h"
#include "Breadcrumb.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Breadcrumb : BreadcrumbT<Breadcrumb>
{
Breadcrumb(IInspectable tag, winrt::hstring label, BreadcrumbSubPage subPage) :
_Tag{ tag },
_Label{ label },
_SubPage{ subPage } {}
WINRT_PROPERTY(IInspectable, Tag);
WINRT_PROPERTY(winrt::hstring, Label);
WINRT_PROPERTY(BreadcrumbSubPage, SubPage);
};
struct MainPage : MainPageT<MainPage>
{
MainPage() = delete;
@ -21,14 +34,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SettingsNav_ItemInvoked(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& args);
void SaveButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void ResetButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void BreadcrumbBar_ItemClicked(Microsoft::UI::Xaml::Controls::BreadcrumbBar const& sender, Microsoft::UI::Xaml::Controls::BreadcrumbBarItemClickedEventArgs const& args);
void SetHostingWindow(uint64_t hostingWindow) noexcept;
bool TryPropagateHostingWindow(IInspectable object) noexcept;
uint64_t GetHostingWindow() const noexcept;
Windows::Foundation::Collections::IObservableVector<IInspectable> Breadcrumbs() noexcept;
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);
private:
Windows::Foundation::Collections::IObservableVector<IInspectable> _breadcrumbs;
Model::CascadiaSettings _settingsSource;
Model::CascadiaSettings _settingsClone;
@ -40,10 +57,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void _DeleteProfile(const Windows::Foundation::IInspectable sender, const Editor::DeleteProfileEventArgs& args);
void _AddProfileHandler(const winrt::guid profileGuid);
void _Navigate(hstring clickedItemTag);
void _Navigate(const Editor::ProfileViewModel& profile);
void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfilePageNavigationState state);
void _PreNavigateHelper();
void _Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage);
void _Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage);
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageNavigationState _colorSchemesNavState{ nullptr };
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _profileViewModelChangedRevoker;
};
}

View File

@ -13,6 +13,20 @@ namespace Microsoft.Terminal.Settings.Editor
UInt64 GetHostingWindow();
}
enum BreadcrumbSubPage
{
None = 0,
Profile_Appearance,
Profile_Advanced
};
runtimeclass Breadcrumb
{
IInspectable Tag;
String Label;
BreadcrumbSubPage SubPage;
}
[default_interface] runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, IHostedInWindow
{
MainPage(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
@ -23,5 +37,7 @@ namespace Microsoft.Terminal.Settings.Editor
// Due to the aforementioned bug, we can't use IInitializeWithWindow _here_ either.
// Let's just smuggle the HWND in as a UInt64 :|
void SetHostingWindow(UInt64 window);
Windows.Foundation.Collections.IObservableVector<IInspectable> Breadcrumbs { get; };
}
}

View File

@ -6,6 +6,7 @@
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:muxc="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
@ -36,12 +37,31 @@
</Page.Resources>
<muxc:NavigationView x:Name="SettingsNav"
Header="{Binding ElementName=SettingsNav, Path=SelectedItem.Content, Mode=OneWay}"
IsBackButtonVisible="Collapsed"
IsSettingsVisible="False"
ItemInvoked="SettingsNav_ItemInvoked"
Loaded="SettingsNav_Loaded"
TabFocusNavigation="Cycle">
<muxc:NavigationView.Header>
<muxc:BreadcrumbBar x:Name="NavigationBreadcrumbBar"
Margin="-40,-40,0,16"
ItemClicked="BreadcrumbBar_ItemClicked"
ItemsSource="{x:Bind Breadcrumbs}">
<muxc:BreadcrumbBar.ItemTemplate>
<DataTemplate x:DataType="local:Breadcrumb">
<TextBlock Text="{x:Bind Label}" />
</DataTemplate>
</muxc:BreadcrumbBar.ItemTemplate>
<muxc:BreadcrumbBar.Resources>
<ResourceDictionary>
<x:Double x:Key="BreadcrumbBarItemThemeFontSize">28</x:Double>
<Thickness x:Key="BreadcrumbBarChevronPadding">11,4,12,0</Thickness>
<FontWeight x:Key="BreadcrumbBarItemFontWeight">SemiBold</FontWeight>
<x:Double x:Key="BreadcrumbBarChevronFontSize">16</x:Double>
</ResourceDictionary>
</muxc:BreadcrumbBar.Resources>
</muxc:BreadcrumbBar>
</muxc:NavigationView.Header>
<muxc:NavigationView.MenuItems>
@ -111,7 +131,7 @@
</muxc:NavigationViewItem>
</muxc:NavigationView.PaneFooter>
<Grid>
<Grid Margin="0,-30,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />

View File

@ -70,13 +70,25 @@
<DependentUpon>MainPage.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Profiles.h">
<DependentUpon>Profiles.xaml</DependentUpon>
<DependentUpon>Profiles.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="ProfileViewModel.h">
<DependentUpon>ProfileViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Profiles_Base.h">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Profiles_Advanced.h">
<DependentUpon>Profiles_Advanced.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Profiles_Appearance.h">
<DependentUpon>Profiles_Appearance.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Appearances.h">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
@ -119,7 +131,13 @@
<Page Include="MainPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles.xaml">
<Page Include="Profiles_Base.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles_Advanced.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles_Appearance.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Appearances.xaml">
@ -168,13 +186,25 @@
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Profiles.cpp">
<DependentUpon>Profiles.xaml</DependentUpon>
<DependentUpon>Profiles.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="ProfileViewModel.cpp">
<DependentUpon>ProfileViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Profiles_Base.cpp">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Profiles_Advanced.cpp">
<DependentUpon>Profiles_Advanced.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Profiles_Appearance.cpp">
<DependentUpon>Profiles_Appearance.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Appearances.cpp">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>
@ -230,10 +260,21 @@
<DependentUpon>MainPage.xaml</DependentUpon>
</Midl>
<Midl Include="Profiles.idl">
<DependentUpon>Profiles.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="ProfileViewModel.idl" />
<Midl Include="Profiles_Base.idl">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Profiles_Advanced.idl">
<DependentUpon>Profiles_Advanced.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Profiles_Appearance.idl">
<DependentUpon>Profiles_Appearance.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Appearances.idl">
<DependentUpon>Appearances.xaml</DependentUpon>
<SubType>Code</SubType>

View File

@ -35,7 +35,9 @@
<Page Include="Interaction.xaml" />
<Page Include="Launch.xaml" />
<Page Include="MainPage.xaml" />
<Page Include="Profiles.xaml" />
<Page Include="Profiles_Base.xaml" />
<Page Include="Profiles_Advanced.xaml" />
<Page Include="Profiles_Appearance.xaml" />
<Page Include="Appearances.xaml" />
<Page Include="Rendering.xaml" />
<Page Include="Actions.xaml" />

View File

@ -70,7 +70,6 @@ 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 },

View File

@ -19,9 +19,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
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();
@ -77,6 +74,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
VIEW_MODEL_OBSERVABLE_PROPERTY(ProfileSubPage, CurrentPage);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
OBSERVABLE_PROJECTED_SETTING(_profile, Name);
@ -123,7 +122,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
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);

View File

@ -18,9 +18,9 @@ namespace Microsoft.Terminal.Settings.Editor
Guid ProfileGuid { get; };
}
enum ProfilesPivots
enum ProfileSubPage
{
General = 0,
Base = 0,
Appearance = 1,
Advanced = 2
};
@ -29,7 +29,6 @@ namespace Microsoft.Terminal.Settings.Editor
{
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; };
@ -54,6 +53,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean CanDeleteProfile { get; };
Boolean IsBaseLayer;
ProfileSubPage CurrentPage;
Boolean UseParentProcessDirectory;
Boolean UseCustomStartingDirectory { get; };
AppearanceViewModel DefaultAppearance { get; };

View File

@ -5,7 +5,6 @@
#include "Profiles.h"
#include "PreviewConnection.h"
#include "Profiles.g.cpp"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
@ -21,153 +20,4 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles::Profiles() :
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
{
InitializeComponent();
const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
_previewControl.IsEnabled(false);
_previewControl.AllowFocusWhenDisabled(false);
ControlPreview().Child(_previewControl);
}
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
{
auto state{ e.Parameter().as<Editor::ProfilePageNavigationState>() };
_Profile = state.Profile();
// generate the font list, if we don't have one
if (!ProfileViewModel::CompleteFontList() || !ProfileViewModel::MonospaceFontList())
{
ProfileViewModel::UpdateFontList();
}
// Check the use parent directory box if the starting directory is empty
if (_Profile.StartingDirectory().empty())
{
StartingDirectoryUseParentCheckbox().IsChecked(true);
}
// 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 = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, auto&&) {
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _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 = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
});
// Navigate to the pivot in the provided navigation state
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(_Profile.TermSettings(), _Profile.TermSettings());
});
}
void Profiles::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
_AppearanceViewModelChangedRevoker.revoke();
}
void Profiles::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
winrt::get_self<ProfileViewModel>(_Profile)->DeleteProfile();
}
void Profiles::CreateUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_Profile.CreateUnfocusedAppearance();
}
void Profiles::DeleteUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_Profile.DeleteUnfocusedAppearance();
}
fire_and_forget Profiles::Icon_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_Profile.Icon(file);
}
}
fire_and_forget Profiles::Commandline_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
{ L"Executable Files (*.exe, *.cmd, *.bat)", L"*.exe;*.cmd;*.bat" },
{ L"All Files (*.*)", L"*.*" }
};
static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
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
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"exe;cmd;bat"));
});
if (!path.empty())
{
_Profile.Commandline(path);
}
}
fire_and_forget Profiles::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
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));
try
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
DWORD flags{};
THROW_IF_FAILED(dialog->GetOptions(&flags));
THROW_IF_FAILED(dialog->SetOptions(flags | FOS_PICKFOLDERS)); // folders only
});
if (!folder.empty())
{
_Profile.StartingDirectory(folder);
}
}
void Profiles::Pivot_SelectionChanged(Windows::Foundation::IInspectable const& /*sender*/,
RoutedEventArgs const& /*e*/)
{
ProfileViewModel::LastActivePivot(static_cast<Editor::ProfilesPivots>(ProfilesPivot().SelectedIndex()));
}
}

View File

@ -3,7 +3,6 @@
#pragma once
#include "Profiles.g.h"
#include "ProfilePageNavigationState.g.h"
#include "ProfileViewModel.h"
#include "Utils.h"
@ -35,39 +34,4 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
};
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
{
public:
Profiles();
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& 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 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 CreateUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void DeleteUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
void _UpdateBIAlignmentControl(const int32_t val);
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;
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Profiles);
}

View File

@ -10,12 +10,4 @@ namespace Microsoft.Terminal.Settings.Editor
{
ProfileViewModel Profile { get; };
};
[default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Profiles();
ProfileViewModel Profile { get; };
Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
}
}

View File

@ -1,510 +0,0 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles"
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"
mc:Ignorable="d">
<Page.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>
</ResourceDictionary>
</Page.Resources>
<!-- Use a Grid instead of a StackPanel. StackPanel suppresses the inner ScrollViewer. -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<Pivot x:Name="ProfilesPivot"
Grid.Row="1"
Margin="1,0,0,0"
HorizontalAlignment="Left"
SelectionChanged="Pivot_SelectionChanged">
<!-- General Tab -->
<PivotItem x:Uid="Profile_General">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
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 Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.StartingDirectory, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValue="{x:Bind Profile.Icon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe Fluent Icons"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitle, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Elevate -->
<local:SettingContainer x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}"
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
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 Profile.CanDeleteProfile}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="ButtonBackground"
Color="{ThemeResource SystemColorButtonFaceColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonForeground"
Color="{ThemeResource SystemColorButtonTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Profile_DeleteConfirmationButton"
Click="DeleteConfirmation_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</ScrollViewer>
</PivotItem>
<!-- Appearance Tab -->
<PivotItem x:Uid="Profile_Appearance">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel>
<!-- Control Preview -->
<Border x:Name="ControlPreview"
Width="350"
Height="160"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Opacity -->
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
Margin="0"
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>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
Grid.Column="0"
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}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
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 Profile.UseAcrylic, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
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="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
Grid.Column="0"
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}" />
</Grid>
</local:SettingContainer>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal"
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(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
Margin="32,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
</Button.Content>
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="ButtonBackground"
Color="{ThemeResource SystemColorButtonFaceColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonForeground"
Color="{ThemeResource SystemColorButtonTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
</Button>
</StackPanel>
<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>
</PivotItem>
<!-- Advanced Tab -->
<PivotItem x:Uid="Profile_Advanced">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
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 Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
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 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 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 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 Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
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 Profile.ClearBellStyle}"
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.BellStyleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(1), BindBack=Profile.SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(2), BindBack=Profile.SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(4), BindBack=Profile.SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
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>
</PivotItem>
</Pivot>
</Grid>
</Page>

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Profiles_Advanced.h"
#include "Profiles_Advanced.g.cpp"
#include "EnumEntry.h"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles_Advanced::Profiles_Advanced()
{
InitializeComponent();
}
void Profiles_Advanced::OnNavigatedTo(const NavigationEventArgs& e)
{
auto state{ e.Parameter().as<Editor::ProfilePageNavigationState>() };
_Profile = state.Profile();
}
void Profiles_Advanced::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Profiles_Advanced.g.h"
#include "ViewModelHelpers.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Profiles_Advanced : public HasScrollViewer<Profiles_Advanced>, Profiles_AdvancedT<Profiles_Advanced>
{
public:
Profiles_Advanced();
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Profiles_Advanced);
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "Profiles.idl";
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass Profiles_Advanced : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Profiles_Advanced();
ProfileViewModel Profile { get; };
}
}

View File

@ -0,0 +1,133 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles_Advanced"
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"
mc:Ignorable="d">
<Page.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>
</ResourceDictionary>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<ScrollViewer Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
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}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Antialiasing Mode -->
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
ClearSettingValue="{x:Bind Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
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 Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.AltGrAliasing, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- Snap On Input -->
<local:SettingContainer x:Uid="Profile_SnapOnInput"
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}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<!-- History Size -->
<local:SettingContainer x:Uid="Profile_HistorySize"
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 Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
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 Profile.ClearBellStyle}"
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.BellStyleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(1), BindBack=Profile.SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(2), BindBack=Profile.SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind Profile.IsBellStyleFlagSet(4), BindBack=Profile.SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
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}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Profiles_Appearance.h"
#include "Profiles_Appearance.g.cpp"
#include "Profiles.h"
#include "PreviewConnection.h"
#include "EnumEntry.h"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles_Appearance::Profiles_Appearance() :
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
{
InitializeComponent();
_previewControl.IsEnabled(false);
_previewControl.AllowFocusWhenDisabled(false);
ControlPreview().Child(_previewControl);
}
void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
{
auto state{ e.Parameter().as<Editor::ProfilePageNavigationState>() };
_Profile = state.Profile();
// generate the font list, if we don't have one
if (_Profile.CompleteFontList() || !_Profile.MonospaceFontList())
{
ProfileViewModel::UpdateFontList();
}
// 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 = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _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 = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
_previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
});
// 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(_Profile.TermSettings(), _Profile.TermSettings());
});
}
void Profiles_Appearance::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
_AppearanceViewModelChangedRevoker.revoke();
}
void Profiles_Appearance::CreateUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_Profile.CreateUnfocusedAppearance();
}
void Profiles_Appearance::DeleteUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_Profile.DeleteUnfocusedAppearance();
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Profiles_Appearance.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Profiles_Appearance : public HasScrollViewer<Profiles_Appearance>, Profiles_AppearanceT<Profiles_Appearance>
{
public:
Profiles_Appearance();
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void CreateUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void DeleteUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
Microsoft::Terminal::Control::TermControl _previewControl;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Profiles_Appearance);
}

View File

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "Profiles.idl";
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass Profiles_Appearance : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Profiles_Appearance();
ProfileViewModel Profile { get; };
Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
}
}

View File

@ -0,0 +1,215 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles_Appearance"
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"
mc:Ignorable="d">
<Page.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="FontFaceComboBoxItemTemplate"
x:DataType="local:Font">
<TextBlock FontFamily="{x:Bind Name}"
Text="{x:Bind LocalizedName}" />
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<ScrollViewer Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Control Preview -->
<Border x:Name="ControlPreview"
Width="350"
Height="160"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind Profile, Mode=OneWay}" />
<!-- Grouping: Transparency -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_TransparencyHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Opacity -->
<local:SettingContainer x:Name="OpacityContainer"
x:Uid="Profile_Opacity"
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>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="OpacitySlider"
Grid.Column="0"
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}" />
</Grid>
</StackPanel>
</local:SettingContainer>
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
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 Profile.UseAcrylic, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
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="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
Grid.Column="0"
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}" />
</Grid>
</local:SettingContainer>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<muxc:RadioButtons AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind Profile.ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentScrollState, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind Profile.EditableUnfocusedAppearance, Mode=OneWay}">
<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(Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />
</Button.Content>
</Button>
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
Margin="32,0,0,0"
Click="DeleteUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind Profile.HasUnfocusedAppearance, Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
</Button.Content>
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="ButtonBackground"
Color="{ThemeResource SystemColorButtonFaceColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonForeground"
Color="{ThemeResource SystemColorButtonTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
</Button>
</StackPanel>
<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>
</Grid>
</Page>

View File

@ -0,0 +1,126 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Profiles_Base.h"
#include "Profiles_Base.g.cpp"
#include "Profiles.h"
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles_Base::Profiles_Base()
{
InitializeComponent();
const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
}
void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)
{
auto state{ e.Parameter().as<Editor::ProfilePageNavigationState>() };
_Profile = state.Profile();
// Check the use parent directory box if the starting directory is empty
if (_Profile.StartingDirectory().empty())
{
StartingDirectoryUseParentCheckbox().IsChecked(true);
}
}
void Profiles_Base::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
}
void Profiles_Base::Appearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*args*/)
{
_Profile.CurrentPage(ProfileSubPage::Appearance);
}
void Profiles_Base::Advanced_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*args*/)
{
_Profile.CurrentPage(ProfileSubPage::Advanced);
}
void Profiles_Base::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
winrt::get_self<ProfileViewModel>(_Profile)->DeleteProfile();
}
fire_and_forget Profiles_Base::Commandline_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
{ L"Executable Files (*.exe, *.cmd, *.bat)", L"*.exe;*.cmd;*.bat" },
{ L"All Files (*.*)", L"*.*" }
};
static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
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
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"exe;cmd;bat"));
});
if (!path.empty())
{
_Profile.Commandline(path);
}
}
fire_and_forget Profiles_Base::Icon_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
const auto parentHwnd{ reinterpret_cast<HWND>(winrt::get_self<ProfileViewModel>(_Profile)->WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_Profile.Icon(file);
}
}
fire_and_forget Profiles_Base::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
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));
try
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
DWORD flags{};
THROW_IF_FAILED(dialog->GetOptions(&flags));
THROW_IF_FAILED(dialog->SetOptions(flags | FOS_PICKFOLDERS)); // folders only
});
if (!folder.empty())
{
_Profile.StartingDirectory(folder);
}
}
}

View File

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Profiles_Base.g.h"
#include "ViewModelHelpers.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Profiles_Base : public HasScrollViewer<Profiles_Base>, Profiles_BaseT<Profiles_Base>
{
public:
Profiles_Base();
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& 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);
fire_and_forget Commandline_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void Appearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
void Advanced_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);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
};
};
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Profiles_Base);
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "Profiles.idl";
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass Profiles_Base : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Profiles_Base();
ProfileViewModel Profile { get; };
}
}

View File

@ -0,0 +1,228 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles_Base"
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"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<!-- Use a Grid instead of a StackPanel. StackPanel suppresses the inner ScrollViewer. -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind Profile.IsBaseLayer}" />
<ScrollViewer Grid.Row="1"
ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource SettingsStackStyle}">
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Uid="Profile_Name"
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.CommandlineOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}"
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 Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
CurrentValue="{x:Bind Profile.StartingDirectory, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.StartingDirectoryOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind Profile.ClearIcon}"
CurrentValue="{x:Bind Profile.Icon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel Orientation="Horizontal">
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe MDL2 Assets"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
CurrentValue="{x:Bind Profile.TabTitle, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabTitleOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
Margin="0,48,0,0"
Style="{StaticResource SubtitleTextBlockStyle}" />
<ToggleButton Click="Appearance_Click"
Style="{StaticResource ToggleButtonStyle}">
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="Appearance" />
</ToggleButton>
<ToggleButton Click="Advanced_Click"
Style="{StaticResource ToggleButtonStyle}">
<ContentPresenter HorizontalAlignment="Left">
<TextBlock HorizontalAlignment="Left"
Text="Advanced" />
</ContentPresenter>
</ToggleButton>
<!-- Delete Button -->
<Button x:Name="DeleteButton"
Margin="{StaticResource StandardControlMargin}"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind Profile.CanDeleteProfile}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="ButtonBackground"
Color="{ThemeResource SystemColorButtonFaceColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonForeground"
Color="{ThemeResource SystemColorButtonTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Profile_DeleteConfirmationButton"
Click="DeleteConfirmation_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@ -1070,6 +1070,10 @@
<value>Cursor</value>
<comment>Header for a group of settings that control the appearance of the cursor. Presented near "Profile_CursorHeight" and other keys starting with "Profile_Cursor".</comment>
</data>
<data name="Profile_AdditionalSettingsHeader.Text" xml:space="preserve">
<value>Additional settings</value>
<comment>Header for the buttons that navigate to additional settings for the profile.</comment>
</data>
<data name="Profile_TextHeader.Text" xml:space="preserve">
<value>Text</value>
<comment>Header for a group of settings that control the appearance of text in the app.</comment>

View File

@ -18,6 +18,11 @@
</Style>
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{StaticResource SystemBaseMediumColor}" />
<Color x:Key="CardStrokeColorDefault">#0F000000</Color>
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush"
Color="{StaticResource CardStrokeColorDefault}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style x:Key="SecondaryTextBlockStyle"
@ -25,6 +30,8 @@
<!-- Do not mess with the foreground color for High Contrast. Let it ride as is. -->
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{ThemeResource SystemColorWindowTextColor}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="SystemColorButtonTextColorBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Style x:Key="SecondaryTextBlockStyle"
@ -33,6 +40,11 @@
</Style>
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{StaticResource SystemBaseMediumColor}" />
<Color x:Key="CardStrokeColorDefault">#19000000</Color>
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush"
Color="{StaticResource CardStrokeColorDefault}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
@ -67,7 +79,7 @@
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
</Style>
@ -88,6 +100,7 @@
</Style>
<Style TargetType="local:SettingContainer">
<Setter Property="Margin" Value="0,4,8,0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="Template">