mirror of
https://github.com/microsoft/terminal.git
synced 2026-07-08 17:56:28 +00:00
Add centralized Profiles page
This commit is contained in:
@@ -1,83 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "AddProfile.h"
|
||||
#include "AddProfile.g.cpp"
|
||||
#include "AddProfilePageNavigationState.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
AddProfile::AddProfile()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetName(AddNewButton(), RS_(L"AddProfile_AddNewTextBlock/Text"));
|
||||
Automation::AutomationProperties::SetName(DuplicateButton(), RS_(L"AddProfile_DuplicateTextBlock/Text"));
|
||||
}
|
||||
|
||||
void AddProfile::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_State = args.ViewModel().as<Editor::AddProfilePageNavigationState>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"NavigatedToPage",
|
||||
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
|
||||
TraceLoggingValue("addProfile", "PageId", "The identifier of the page that was navigated to"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
void AddProfile::AddNewClick(const IInspectable& /*sender*/,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"AddNewProfile",
|
||||
TraceLoggingDescription("Event emitted when the user adds a new profile"),
|
||||
TraceLoggingValue("EmptyProfile", "Type", "The type of the creation method (i.e. empty profile, duplicate)"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_State.RequestAddNew();
|
||||
}
|
||||
|
||||
void AddProfile::DuplicateClick(const IInspectable& /*sender*/,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
if (const auto selected = Profiles().SelectedItem())
|
||||
{
|
||||
const auto selectedProfile = selected.as<Model::Profile>();
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"AddNewProfile",
|
||||
TraceLoggingDescription("Event emitted when the user adds a new profile"),
|
||||
TraceLoggingValue("Duplicate", "Type", "The type of the creation method (i.e. empty profile, duplicate)"),
|
||||
TraceLoggingValue(!selectedProfile.Source().empty(), "SourceProfileHasSource", "True, if the source profile has a source (i.e. dynamic profile generator namespace, fragment). Otherwise, False, indicating it's based on a custom profile."),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_State.RequestDuplicate(selectedProfile.Guid());
|
||||
}
|
||||
}
|
||||
|
||||
void AddProfile::ProfilesSelectionChanged(const IInspectable& /*sender*/,
|
||||
const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
if (!_IsProfileSelected)
|
||||
{
|
||||
IsProfileSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- AddProfile.h
|
||||
|
||||
Abstract:
|
||||
- This creates the 'add new profile' page in the settings UI and handles
|
||||
user interaction with it, raising events to the main page as necessary
|
||||
|
||||
|
||||
Author(s):
|
||||
- Pankaj Bhojwani - March 2021
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AddProfile.g.h"
|
||||
#include "AddProfilePageNavigationState.g.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct AddProfilePageNavigationState : AddProfilePageNavigationStateT<AddProfilePageNavigationState>
|
||||
{
|
||||
public:
|
||||
AddProfilePageNavigationState(const Model::CascadiaSettings& settings) :
|
||||
_Settings{ settings } {}
|
||||
|
||||
void RequestAddNew()
|
||||
{
|
||||
AddNew.raise(winrt::guid{});
|
||||
}
|
||||
|
||||
void RequestDuplicate(GUID profile)
|
||||
{
|
||||
AddNew.raise(profile);
|
||||
}
|
||||
|
||||
til::event<AddNewArgs> AddNew;
|
||||
|
||||
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr);
|
||||
};
|
||||
|
||||
struct AddProfile : public HasScrollViewer<AddProfile>, AddProfileT<AddProfile>
|
||||
{
|
||||
public:
|
||||
AddProfile();
|
||||
|
||||
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
|
||||
void AddNewClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void DuplicateClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void ProfilesSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_PROPERTY(Editor::AddProfilePageNavigationState, State, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsProfileSelected, PropertyChanged.raise, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(AddProfile);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
delegate void AddNewArgs(Guid profile);
|
||||
|
||||
runtimeclass AddProfilePageNavigationState
|
||||
{
|
||||
Microsoft.Terminal.Settings.Model.CascadiaSettings Settings;
|
||||
void RequestAddNew();
|
||||
void RequestDuplicate(Guid profile);
|
||||
event AddNewArgs AddNew;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass AddProfile : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
AddProfile();
|
||||
AddProfilePageNavigationState State { get; };
|
||||
Boolean IsProfileSelected { get; };
|
||||
}
|
||||
}
|
||||
@@ -1,91 +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.AddProfile"
|
||||
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:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
|
||||
<Button x:Name="AddNewButton"
|
||||
Click="AddNewClick"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="AddProfile_AddNewTextBlock"
|
||||
Style="{StaticResource IconButtonTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</Border>
|
||||
<StackPanel Margin="{StaticResource StandardControlMargin}">
|
||||
<local:SettingsCard x:Name="DuplicateProfile"
|
||||
x:Uid="AddProfile_Duplicate">
|
||||
<ComboBox x:Name="Profiles"
|
||||
AutomationProperties.AccessibilityView="Content"
|
||||
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}"
|
||||
SelectedIndex="0"
|
||||
SelectionChanged="ProfilesSelectionChanged"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="model:Profile">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="8">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="16" />
|
||||
<!-- profile name -->
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<IconSourceElement Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Icon.Resolved), Mode=OneTime}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind Name}" />
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</local:SettingsCard>
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
|
||||
<Button x:Name="DuplicateButton"
|
||||
Margin="{StaticResource StandardControlMargin}"
|
||||
Click="DuplicateClick"
|
||||
IsEnabled="{x:Bind IsProfileSelected, Mode=OneWay}"
|
||||
Style="{StaticResource AccentButtonStyle}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="AddProfile_DuplicateTextBlock"
|
||||
Style="{StaticResource IconButtonTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Page>
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "GlobalAppearanceViewModel.h"
|
||||
#include "ColorSchemes.h"
|
||||
#include "EditColorScheme.h"
|
||||
#include "AddProfile.h"
|
||||
#include "Profiles.h"
|
||||
#include "InteractionViewModel.h"
|
||||
#include "LaunchViewModel.h"
|
||||
#include "NewTabMenuViewModel.h"
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <dwmapi.h>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
#include <winrt/Windows.UI.Xaml.Media.Animation.h>
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
@@ -40,6 +42,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::UI::Xaml::Media::Animation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
@@ -102,7 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
MainPage::MainPage(const CascadiaSettings& settings) :
|
||||
_settingsSource{ settings },
|
||||
_settingsClone{ settings.Copy() },
|
||||
_profileVMs{ single_threaded_observable_vector<Editor::ProfileViewModel>() }
|
||||
_profilesPageVM{ winrt::make<ProfilesPageViewModel>() }
|
||||
{
|
||||
InitializeComponent();
|
||||
_UpdateBackgroundForMica();
|
||||
@@ -116,14 +119,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(currentFolder), currentFolder.Name(), BreadcrumbSubPage::NewTabMenu_Folder));
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
_navDirection = NavDirection::Forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we don't have a current folder, we're at the root of the NTM
|
||||
_breadcrumbs.Clear();
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(newTabMenuTag), RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None));
|
||||
_navDirection = NavDirection::Back;
|
||||
}
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this));
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this), _MakeTransitionInfo());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -145,19 +151,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(currentExtensionPackage), currentExtensionPackage.DisplayName(), BreadcrumbSubPage::Extensions_Extension));
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
_navDirection = NavDirection::Forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we don't have a current extension package, we're at the root of the Extensions page
|
||||
_breadcrumbs.Clear();
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(extensionsTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None));
|
||||
_navDirection = NavDirection::Back;
|
||||
}
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this));
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this), _MakeTransitionInfo());
|
||||
}
|
||||
});
|
||||
|
||||
_SetupProfilesPageEventHandling();
|
||||
|
||||
// Make sure to initialize the profiles _after_ we have initialized the color schemes page VM, because we pass
|
||||
// that VM into the appearance VMs within the profiles
|
||||
// that VM into the appearance VMs within the profiles. The Profiles VM owns the per-profile list itself.
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Apply icons and tooltips (GH#19688, long names may be truncated) to static nav items
|
||||
@@ -205,28 +216,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_UpdateBackgroundForMica();
|
||||
|
||||
// Deduce information about the currently selected item
|
||||
IInspectable lastBreadcrumb;
|
||||
const auto size = _breadcrumbs.Size();
|
||||
if (size > 0)
|
||||
// Capture data about where we are right now, so we can re-navigate to the same
|
||||
// place after we rebuild all the settings.
|
||||
IInspectable destination{ nullptr };
|
||||
auto subPage = BreadcrumbSubPage::None;
|
||||
if (const auto size = _breadcrumbs.Size(); size > 0)
|
||||
{
|
||||
lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
|
||||
const auto& crumb = _breadcrumbs.GetAt(size - 1).as<Breadcrumb>();
|
||||
destination = crumb->Tag();
|
||||
subPage = crumb->SubPage();
|
||||
}
|
||||
|
||||
// Collect only the first items out of the menu item source, the static
|
||||
// ones that we don't want to regenerate.
|
||||
//
|
||||
// By manipulating a MenuItemsSource this way, rather than manipulating the
|
||||
// MenuItems directly, we avoid a crash in WinUI.
|
||||
//
|
||||
// By making the vector only _originalNumItems big to start, GetMany
|
||||
// will only fill that number of elements out of the current source.
|
||||
std::vector<IInspectable> menuItemsSTL(_originalNumItems, nullptr);
|
||||
_menuItemSource.GetMany(0, menuItemsSTL);
|
||||
// now, just stick them back in.
|
||||
_menuItemSource.ReplaceAll(menuItemsSTL);
|
||||
|
||||
// Repopulate profile-related menu items
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Update the Nav State with the new version of the settings
|
||||
@@ -236,64 +236,41 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_extensionsVM.UpdateSettings(_settingsClone, _colorSchemesPageVM);
|
||||
_profileDefaultsVM = nullptr; // Lazy-loaded upon navigation
|
||||
|
||||
// Now that the menuItems are repopulated,
|
||||
// refresh the current page using the breadcrumb data we collected before the refresh
|
||||
if (const auto& crumb{ lastBreadcrumb.try_as<Breadcrumb>() }; crumb && crumb->Tag())
|
||||
if (const auto& profileTag{ destination.try_as<Editor::ProfileViewModel>() })
|
||||
{
|
||||
bool foundNavigationParams = false;
|
||||
auto destination = crumb->Tag();
|
||||
auto subPage = crumb->SubPage();
|
||||
for (const auto& item : _menuItemSource)
|
||||
// Find the new profile VM by guid
|
||||
if (const auto newProfileVM = _FindProfileViewModelByGuid(profileTag.OriginalProfileGuid()))
|
||||
{
|
||||
const auto menuItem = item.try_as<MUX::Controls::NavigationViewItem>();
|
||||
if (!menuItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& tag = menuItem.Tag();
|
||||
if (const auto& stringTag{ tag.try_as<hstring>() })
|
||||
{
|
||||
if (const auto& destString{ destination.try_as<hstring>() })
|
||||
{
|
||||
foundNavigationParams = (*stringTag == *destString);
|
||||
}
|
||||
else if (destination.try_as<Editor::FolderEntryViewModel>() && *stringTag == newTabMenuTag)
|
||||
{
|
||||
foundNavigationParams = true;
|
||||
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
|
||||
}
|
||||
else if (destination.try_as<Editor::ExtensionPackageViewModel>() && *stringTag == extensionsTag)
|
||||
{
|
||||
foundNavigationParams = true;
|
||||
subPage = BreadcrumbSubPage::Extensions_Extension;
|
||||
}
|
||||
}
|
||||
else if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
|
||||
{
|
||||
const auto destProfile = destination.try_as<ProfileViewModel>();
|
||||
if (destProfile && profileTag->OriginalProfileGuid() == destProfile->OriginalProfileGuid())
|
||||
{
|
||||
// Use the new profile VM from the refreshed menu items
|
||||
destination = tag;
|
||||
foundNavigationParams = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundNavigationParams)
|
||||
{
|
||||
// found the one that was selected before the refresh
|
||||
_Navigate(destination, subPage);
|
||||
return;
|
||||
}
|
||||
destination = newProfileVM;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall back to the Profiles landing page
|
||||
destination = box_value(profilesTag);
|
||||
subPage = BreadcrumbSubPage::None;
|
||||
}
|
||||
}
|
||||
else if (destination.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
destination = box_value(newTabMenuTag);
|
||||
subPage = BreadcrumbSubPage::NewTabMenu_Folder;
|
||||
}
|
||||
else if (destination.try_as<Editor::ExtensionPackageViewModel>())
|
||||
{
|
||||
destination = box_value(extensionsTag);
|
||||
subPage = BreadcrumbSubPage::Extensions_Extension;
|
||||
}
|
||||
else if (!destination.try_as<hstring>())
|
||||
{
|
||||
// Couldn't find a meaningful previous page. Fall back to the first menu item.
|
||||
if (_menuItemSource && _menuItemSource.Size() > 0)
|
||||
{
|
||||
destination = _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>().Tag();
|
||||
subPage = BreadcrumbSubPage::None;
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find the selected item, fall back to first menu item
|
||||
// This happens when the selected item was a profile which doesn't exist in the new configuration
|
||||
// We can use menuItemsSTL here because the only things they miss are profile entries.
|
||||
const auto& firstItem{ _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
_Navigate(firstItem.Tag(), BreadcrumbSubPage::None);
|
||||
_Navigate(destination, subPage);
|
||||
|
||||
_UpdateSearchIndex();
|
||||
}
|
||||
@@ -325,12 +302,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// can be empty to indicate that we should create a fresh profile
|
||||
void MainPage::_AddProfileHandler(winrt::guid profileGuid)
|
||||
{
|
||||
uint32_t insertIndex;
|
||||
auto selectedItem{ SettingsNav().SelectedItem() };
|
||||
if (_menuItemSource)
|
||||
{
|
||||
_menuItemSource.IndexOf(selectedItem, insertIndex);
|
||||
}
|
||||
if (profileGuid != winrt::guid{})
|
||||
{
|
||||
// if we were given a non-empty guid, we want to duplicate the corresponding profile
|
||||
@@ -338,13 +309,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (profile)
|
||||
{
|
||||
const auto duplicated = _settingsClone.DuplicateProfile(profile);
|
||||
_CreateAndNavigateToNewProfile(insertIndex, duplicated);
|
||||
_CreateAndNavigateToNewProfile(duplicated);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we were given an empty guid, create a new profile
|
||||
_CreateAndNavigateToNewProfile(insertIndex, nullptr);
|
||||
_CreateAndNavigateToNewProfile(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,11 +439,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto currentScheme = _colorSchemesPageVM.CurrentScheme();
|
||||
if (_colorSchemesPageVM.CurrentPage() == ColorSchemesSubPage::EditColorScheme && currentScheme)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), winrt::make<NavigateToPageArgs>(currentScheme, *this));
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), winrt::make<NavigateToPageArgs>(currentScheme, *this), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedTag, currentScheme.Name(), BreadcrumbSubPage::ColorSchemes_Edit));
|
||||
}
|
||||
else if (_colorSchemesPageVM.CurrentPage() == ColorSchemesSubPage::Base)
|
||||
{
|
||||
_navDirection = NavDirection::Back;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(boxedTag, BreadcrumbSubPage::None);
|
||||
}
|
||||
}
|
||||
@@ -493,11 +468,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto boxedTag = box_value(actionsTag);
|
||||
if (_actionsVM.CurrentPage() == ActionsSubPage::Edit)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(_actionsVM.CurrentCommand(), *this));
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(_actionsVM.CurrentCommand(), *this), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedTag, RS_(L"Nav_EditAction/Content"), BreadcrumbSubPage::Actions_Edit));
|
||||
}
|
||||
else if (_actionsVM.CurrentPage() == ActionsSubPage::Base)
|
||||
{
|
||||
_navDirection = NavDirection::Back;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(boxedTag, BreadcrumbSubPage::None);
|
||||
}
|
||||
}
|
||||
@@ -508,21 +487,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
if (page == ProfileSubPage::Base)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus), _MakeTransitionInfo());
|
||||
}
|
||||
else if (page == ProfileSubPage::Appearance)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance));
|
||||
}
|
||||
else if (page == ProfileSubPage::Terminal)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Terminal>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Terminal>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Terminal/Header"), BreadcrumbSubPage::Profile_Terminal));
|
||||
}
|
||||
else if (page == ProfileSubPage::Advanced)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced));
|
||||
}
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
@@ -543,8 +522,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (currentPage == ProfileSubPage::Base)
|
||||
{
|
||||
_breadcrumbs.Clear();
|
||||
_AppendProfilesRootCrumb();
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None));
|
||||
_navDirection = NavDirection::Back;
|
||||
}
|
||||
else
|
||||
{
|
||||
_navDirection = NavDirection::Forward;
|
||||
}
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_NavigateToProfileSubPage(profile, currentPage, breadcrumbTag, {});
|
||||
}
|
||||
});
|
||||
@@ -568,22 +554,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
selectedNavTag = *clickedItemTag;
|
||||
if (*clickedItemTag == launchTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Launch>(), winrt::make<NavigateToPageArgs>(winrt::make<LaunchViewModel>(_settingsClone), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Launch>(), winrt::make<NavigateToPageArgs>(winrt::make<LaunchViewModel>(_settingsClone), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Launch/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == interactionTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<NavigateToPageArgs>(winrt::make<InteractionViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<NavigateToPageArgs>(winrt::make<InteractionViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Interaction/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == renderingTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<NavigateToPageArgs>(winrt::make<RenderingViewModel>(_settingsClone), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<NavigateToPageArgs>(winrt::make<RenderingViewModel>(_settingsClone), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Rendering/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == compatibilityTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Compatibility>(), winrt::make<NavigateToPageArgs>(winrt::make<CompatibilityViewModel>(_settingsClone), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Compatibility>(), winrt::make<NavigateToPageArgs>(winrt::make<CompatibilityViewModel>(_settingsClone), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Compatibility/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == actionsTag)
|
||||
@@ -597,7 +583,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// Navigate directly to EditAction instead of relying on PropertyChanged,
|
||||
// which won't fire if CurrentPage is already Edit
|
||||
_actionsVM.CurrentPage(ActionsSubPage::Edit);
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(_actionsVM.CurrentCommand(), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(_actionsVM.CurrentCommand(), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_EditAction/Content"), BreadcrumbSubPage::Actions_Edit));
|
||||
|
||||
// Re-register the handler for future user-driven changes
|
||||
@@ -605,7 +591,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_actionsVM.CurrentPage(ActionsSubPage::Base);
|
||||
}
|
||||
}
|
||||
@@ -620,7 +606,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
else
|
||||
{
|
||||
// Navigate to the NewTabMenu page
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
}
|
||||
@@ -634,12 +620,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
}
|
||||
else if (*clickedItemTag == profilesTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles>(), winrt::make<NavigateToPageArgs>(_profilesPageVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == globalProfileTag)
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
|
||||
// lazy load profile defaults VM
|
||||
if (!_profileDefaultsVM)
|
||||
{
|
||||
@@ -658,11 +651,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(_profileDefaultsVM);
|
||||
|
||||
// Keep the Profiles nav item selected.
|
||||
selectedNavTag = profilesTag;
|
||||
}
|
||||
else if (*clickedItemTag == colorSchemesTag)
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::ColorSchemes_Edit)
|
||||
{
|
||||
@@ -671,57 +670,51 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (*clickedItemTag == globalAppearanceTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::GlobalAppearance>(), winrt::make<NavigateToPageArgs>(winrt::make<GlobalAppearanceViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::GlobalAppearance>(), winrt::make<NavigateToPageArgs>(winrt::make<GlobalAppearanceViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_Appearance/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
else if (*clickedItemTag == addProfileTag)
|
||||
{
|
||||
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone) };
|
||||
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
|
||||
contentFrame().Navigate(xaml_typename<Editor::AddProfile>(), winrt::make<NavigateToPageArgs>(addProfileState, *this, elementToFocus));
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
}
|
||||
else if (const auto& profile = vm.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
if (profile.Orphaned())
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
profile.CurrentPage(ProfileSubPage::Base);
|
||||
_SetupProfileEventHandling(profile);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set CurrentPage before registering the handler to avoid double-navigation
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
profile.CurrentPage(profileSubPage);
|
||||
|
||||
// Navigate directly to the correct sub-page
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
|
||||
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profile.OriginalProfileGuid()))
|
||||
else
|
||||
{
|
||||
SettingsNav().SelectedItem(profileNavItem);
|
||||
}
|
||||
// Set CurrentPage before registering the handler to avoid double-navigation
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
profile.CurrentPage(profileSubPage);
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(profile);
|
||||
// Navigate directly to the correct sub-page
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(vm, profile.Name(), BreadcrumbSubPage::None));
|
||||
_NavigateToProfileSubPage(profile, profileSubPage, vm, elementToFocus);
|
||||
|
||||
// Register handler for future user-driven sub-page changes
|
||||
_SetupProfileEventHandling(profile);
|
||||
}
|
||||
}
|
||||
else if (const auto& colorSchemeVM = vm.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
selectedNavTag = colorSchemesTag;
|
||||
const auto boxedColorSchemesTag = box_value(colorSchemesTag);
|
||||
|
||||
// Suppress the handler to avoid double-navigation
|
||||
_colorSchemesPageViewModelChangedRevoker.revoke();
|
||||
|
||||
_AppendProfilesRootCrumb();
|
||||
selectedNavTag = profilesTag;
|
||||
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedColorSchemesTag, RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None));
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_colorSchemesPageVM.CurrentScheme(nullptr);
|
||||
_colorSchemesPageVM.CurrentPage(ColorSchemesSubPage::Base);
|
||||
}
|
||||
@@ -729,7 +722,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_colorSchemesPageVM.CurrentScheme(colorSchemeVM);
|
||||
_colorSchemesPageVM.CurrentPage(ColorSchemesSubPage::EditColorScheme);
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), winrt::make<NavigateToPageArgs>(colorSchemeVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), winrt::make<NavigateToPageArgs>(colorSchemeVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedColorSchemesTag, colorSchemeVM.Name(), BreadcrumbSubPage::ColorSchemes_Edit));
|
||||
}
|
||||
|
||||
@@ -740,7 +733,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
selectedNavTag = newTabMenuTag;
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(newTabMenuTag), RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None));
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
@@ -771,7 +764,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
selectedNavTag = extensionsTag;
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(extensionsTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None));
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
@@ -816,7 +809,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None || !commandVM)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_actionsVM.CurrentCommand(nullptr);
|
||||
}
|
||||
else
|
||||
@@ -826,7 +819,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
_actionsVM.CurrentCommand(commandVM);
|
||||
_actionsVM.CurrentPage(ActionsSubPage::Edit);
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(commandVM, *this, elementToFocus));
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<NavigateToPageArgs>(commandVM, *this, elementToFocus), _MakeTransitionInfo());
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(boxedActionsTag, RS_(L"Nav_EditAction/Content"), BreadcrumbSubPage::Actions_Edit));
|
||||
|
||||
// Re-register the handler for future user-driven changes
|
||||
@@ -835,26 +828,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
|
||||
// Select the appropriate nav item
|
||||
// NOTE: profiles are special in that they have their own nav item, so those are handled in the profile branch above
|
||||
if (!selectedNavTag.empty())
|
||||
{
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
if (const auto& tag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& stringTag{ tag.try_as<hstring>() })
|
||||
{
|
||||
if (*stringTag == selectedNavTag)
|
||||
{
|
||||
SettingsNav().SelectedItem(navViewItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_SelectNavItemByTag(selectedNavTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,11 +852,34 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
if (gsl::narrow_cast<uint32_t>(args.Index()) < (_breadcrumbs.Size() - 1))
|
||||
{
|
||||
_navDirection = NavDirection::Back;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
const auto crumb = args.Item().as<Breadcrumb>();
|
||||
_Navigate(crumb->Tag(), crumb->SubPage());
|
||||
}
|
||||
}
|
||||
|
||||
NavigationTransitionInfo MainPage::_MakeTransitionInfo() const
|
||||
{
|
||||
switch (_navDirection)
|
||||
{
|
||||
case NavDirection::Forward:
|
||||
{
|
||||
SlideNavigationTransitionInfo info;
|
||||
info.Effect(SlideNavigationTransitionEffect::FromRight);
|
||||
return info;
|
||||
}
|
||||
case NavDirection::Back:
|
||||
{
|
||||
SlideNavigationTransitionInfo info;
|
||||
info.Effect(SlideNavigationTransitionEffect::FromLeft);
|
||||
return info;
|
||||
}
|
||||
default:
|
||||
return EntranceNavigationTransitionInfo{};
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_InitializeProfilesList()
|
||||
{
|
||||
const auto& itemSource{ SettingsNav().MenuItemsSource() };
|
||||
@@ -894,35 +893,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_MoveXamlParsedNavItemsIntoItemSource();
|
||||
}
|
||||
|
||||
// Manually create a NavigationViewItem and view model for each profile
|
||||
// and keep a reference to them in a map so that we
|
||||
// can easily modify the correct one when the associated
|
||||
// profile changes.
|
||||
_profileVMs.Clear();
|
||||
// Populate the per-profile view models on the Profiles VM. The Profiles landing
|
||||
// page (and the search index) read this same list back through the VM.
|
||||
const auto& profileVMs = _profilesPageVM.Profiles();
|
||||
profileVMs.Clear();
|
||||
for (const auto& profile : _settingsClone.AllProfiles())
|
||||
{
|
||||
if (!profile.Deleted())
|
||||
{
|
||||
auto profileVM = _viewModelForProfile(profile, _settingsClone, Dispatcher());
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
auto navItem = _CreateProfileNavViewItem(profileVM);
|
||||
_menuItemSource.Append(navItem);
|
||||
profileVM.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
profileVMs.Append(profileVM);
|
||||
}
|
||||
}
|
||||
|
||||
// Top off (the end of the nav view) with the Add Profile item
|
||||
MUX::Controls::NavigationViewItem addProfileItem;
|
||||
const auto addProfileText = RS_(L"Nav_AddNewProfile/Content");
|
||||
addProfileItem.Content(box_value(addProfileText));
|
||||
addProfileItem.Tag(box_value(addProfileTag));
|
||||
WUX::Controls::ToolTipService::SetToolTip(addProfileItem, box_value(addProfileText));
|
||||
|
||||
FontIcon icon;
|
||||
// This is the "Add" symbol
|
||||
icon.Glyph(NavTagIconMap[addProfileTag]);
|
||||
addProfileItem.Icon(icon);
|
||||
|
||||
_menuItemSource.Append(addProfileItem);
|
||||
}
|
||||
|
||||
// BODGY
|
||||
@@ -958,79 +942,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
SettingsNav().MenuItemsSource(_menuItemSource);
|
||||
}
|
||||
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
|
||||
void MainPage::_CreateAndNavigateToNewProfile(const Model::Profile& profile)
|
||||
{
|
||||
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile() };
|
||||
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone, Dispatcher()) };
|
||||
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
const auto navItem{ _CreateProfileNavViewItem(profileViewModel) };
|
||||
profileViewModel.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
|
||||
if (_menuItemSource)
|
||||
{
|
||||
_menuItemSource.InsertAt(index, navItem);
|
||||
}
|
||||
_profilesPageVM.Profiles().Append(profileViewModel);
|
||||
|
||||
// Select and navigate to the new profile
|
||||
_Navigate(profileViewModel, BreadcrumbSubPage::None);
|
||||
}
|
||||
|
||||
static MUX::Controls::InfoBadge _createGlyphIconBadge(wil::zwstring_view glyph)
|
||||
{
|
||||
MUX::Controls::InfoBadge badge;
|
||||
MUX::Controls::FontIconSource icon;
|
||||
icon.FontFamily(winrt::Windows::UI::Xaml::Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(12);
|
||||
icon.Glyph(glyph);
|
||||
badge.IconSource(icon);
|
||||
return badge;
|
||||
}
|
||||
|
||||
MUX::Controls::NavigationViewItem MainPage::_CreateProfileNavViewItem(const Editor::ProfileViewModel& profile)
|
||||
{
|
||||
MUX::Controls::NavigationViewItem profileNavItem;
|
||||
profileNavItem.Content(box_value(profile.Name()));
|
||||
profileNavItem.Tag(box_value<Editor::ProfileViewModel>(profile));
|
||||
profileNavItem.Icon(UI::IconPathConverter::IconWUX(profile.EvaluatedIcon()));
|
||||
WUX::Controls::ToolTipService::SetToolTip(profileNavItem, box_value(profile.Name()));
|
||||
|
||||
if (profile.Orphaned())
|
||||
{
|
||||
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xE7BA") /* Warning Triangle */);
|
||||
}
|
||||
else if (profile.Hidden())
|
||||
{
|
||||
profileNavItem.InfoBadge(_createGlyphIconBadge(L"\xED1A") /* Hide */);
|
||||
}
|
||||
|
||||
// Update the menu item when the icon/name changes
|
||||
auto weakMenuItem{ make_weak(profileNavItem) };
|
||||
profile.PropertyChanged([weakMenuItem](const auto&, const WUX::Data::PropertyChangedEventArgs& args) {
|
||||
if (auto menuItem{ weakMenuItem.get() })
|
||||
{
|
||||
const auto& tag{ menuItem.Tag().as<Editor::ProfileViewModel>() };
|
||||
if (args.PropertyName() == L"Icon")
|
||||
{
|
||||
menuItem.Icon(UI::IconPathConverter::IconWUX(tag.EvaluatedIcon()));
|
||||
}
|
||||
else if (args.PropertyName() == L"Name")
|
||||
{
|
||||
menuItem.Content(box_value(tag.Name()));
|
||||
WUX::Controls::ToolTipService::SetToolTip(menuItem, box_value(tag.Name()));
|
||||
}
|
||||
else if (args.PropertyName() == L"Hidden")
|
||||
{
|
||||
menuItem.InfoBadge(tag.Hidden() ? _createGlyphIconBadge(L"\xED1A") /* Hide */ : nullptr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add an event handler for when the user wants to delete a profile.
|
||||
profile.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
|
||||
// Register the VM so that it appears in the search index
|
||||
_profileVMs.Append(profile);
|
||||
|
||||
return profileNavItem;
|
||||
_Navigate(profileViewModel);
|
||||
}
|
||||
|
||||
void MainPage::_DeleteProfile(const IInspectable /*sender*/, const Editor::DeleteProfileEventArgs& args)
|
||||
@@ -1047,33 +969,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// remove selected item
|
||||
uint32_t index;
|
||||
auto selectedItem{ SettingsNav().SelectedItem() };
|
||||
if (_menuItemSource)
|
||||
// Remove the profile VM
|
||||
const auto& profileVMs = _profilesPageVM.Profiles();
|
||||
for (uint32_t i = 0; i < profileVMs.Size(); ++i)
|
||||
{
|
||||
_menuItemSource.IndexOf(selectedItem, index);
|
||||
_menuItemSource.RemoveAt(index);
|
||||
|
||||
// Remove it from the list of VMs
|
||||
auto profileVM = selectedItem.as<MUX::Controls::NavigationViewItem>().Tag().as<Editor::ProfileViewModel>();
|
||||
uint32_t vmIndex;
|
||||
if (_menuItemSource.IndexOf(profileVM, vmIndex))
|
||||
if (profileVMs.GetAt(i).OriginalProfileGuid() == guid)
|
||||
{
|
||||
_profileVMs.RemoveAt(vmIndex);
|
||||
profileVMs.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
|
||||
// navigate to the profile next to this one
|
||||
const auto newSelectedItem{ _menuItemSource.GetAt(index < _menuItemSource.Size() - 1 ? index : index - 1) };
|
||||
const auto newTag = newSelectedItem.as<MUX::Controls::NavigationViewItem>().Tag();
|
||||
if (const auto profileViewModel = newTag.try_as<ProfileViewModel>())
|
||||
{
|
||||
profileViewModel->FocusDeleteButton(true);
|
||||
}
|
||||
_Navigate(newTag, BreadcrumbSubPage::None);
|
||||
// Since we are navigating to a new profile after deletion, scroll up to the top
|
||||
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
|
||||
}
|
||||
|
||||
// Go back to the Profiles landing page
|
||||
_navDirection = NavDirection::Back;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(box_value(profilesTag));
|
||||
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
|
||||
}
|
||||
|
||||
IObservableVector<IInspectable> MainPage::Breadcrumbs() noexcept
|
||||
@@ -1083,29 +994,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void MainPage::_NavigateToProfileHandler(const IInspectable& /*sender*/, winrt::guid profileGuid)
|
||||
{
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profileGuid))
|
||||
if (const auto profileVM = _FindProfileViewModelByGuid(profileGuid))
|
||||
{
|
||||
_Navigate(profileNavItem.Tag(), BreadcrumbSubPage::None);
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(profileVM);
|
||||
}
|
||||
// Silently fail if the profile wasn't found
|
||||
}
|
||||
|
||||
MUX::Controls::NavigationViewItem MainPage::_FindProfileNavItem(winrt::guid profileGuid) const
|
||||
Editor::ProfileViewModel MainPage::_FindProfileViewModelByGuid(winrt::guid profileGuid) const
|
||||
{
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
for (const auto& profileVM : _profilesPageVM.Profiles())
|
||||
{
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
if (profileVM.OriginalProfileGuid() == profileGuid)
|
||||
{
|
||||
if (const auto& tag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& profileTag{ tag.try_as<ProfileViewModel>() })
|
||||
{
|
||||
if (profileTag->OriginalProfileGuid() == profileGuid)
|
||||
{
|
||||
return navViewItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return profileVM;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -1116,6 +1020,60 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_Navigate(box_value(hstring{ colorSchemesTag }), BreadcrumbSubPage::ColorSchemes_Edit);
|
||||
}
|
||||
|
||||
void MainPage::_AppendProfilesRootCrumb()
|
||||
{
|
||||
_breadcrumbs.Append(winrt::make<Breadcrumb>(box_value(profilesTag), RS_(L"Nav_Profiles/Content"), BreadcrumbSubPage::None));
|
||||
}
|
||||
|
||||
void MainPage::_SelectNavItemByTag(std::wstring_view tag)
|
||||
{
|
||||
if (!_menuItemSource)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
if (const auto& navViewItem{ menuItem.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
if (const auto& itemTag{ navViewItem.Tag() })
|
||||
{
|
||||
if (const auto& stringTag{ itemTag.try_as<hstring>() })
|
||||
{
|
||||
if (*stringTag == tag)
|
||||
{
|
||||
SettingsNav().SelectedItem(navViewItem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_SetupProfilesPageEventHandling()
|
||||
{
|
||||
_profilesPageVM.OpenDefaultsRequested([this](const auto&, const auto&) {
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(box_value(globalProfileTag));
|
||||
});
|
||||
_profilesPageVM.OpenColorSchemesRequested([this](const auto&, const auto&) {
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(box_value(colorSchemesTag));
|
||||
});
|
||||
_profilesPageVM.AddProfileRequested([this](const auto&, const winrt::guid& sourceProfile) {
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_AddProfileHandler(sourceProfile);
|
||||
});
|
||||
_profilesPageVM.OpenProfileRequested([this](const auto&, const Editor::ProfileViewModel& profile) {
|
||||
_navDirection = NavDirection::Forward;
|
||||
const auto resetDir = wil::scope_exit([this]() noexcept { _navDirection = NavDirection::Default; });
|
||||
_Navigate(profile);
|
||||
});
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush MainPage::BackgroundBrush()
|
||||
{
|
||||
return SettingsNav().Background();
|
||||
@@ -1218,7 +1176,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
co_return;
|
||||
}
|
||||
_currentSearch = SearchIndex::Instance().SearchAsync(sanitizedQuery,
|
||||
_profileVMs.GetView(),
|
||||
_profilesPageVM.Profiles().GetView(),
|
||||
get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList().GetView(),
|
||||
_colorSchemesPageVM.AllColorSchemes().GetView(),
|
||||
_extensionsVM.ExtensionPackages().GetView(),
|
||||
|
||||
@@ -86,21 +86,33 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
std::optional<HWND> _hostingHwnd;
|
||||
|
||||
void _InitializeProfilesList();
|
||||
void _CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile);
|
||||
winrt::Microsoft::UI::Xaml::Controls::NavigationViewItem _CreateProfileNavViewItem(const Editor::ProfileViewModel& profile);
|
||||
void _CreateAndNavigateToNewProfile(const Model::Profile& profile);
|
||||
void _DeleteProfile(const Windows::Foundation::IInspectable sender, const Editor::DeleteProfileEventArgs& args);
|
||||
void _AddProfileHandler(const winrt::guid profileGuid);
|
||||
|
||||
void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel profile);
|
||||
void _SetupColorSchemesEventHandling();
|
||||
void _SetupActionsEventHandling();
|
||||
void _SetupProfilesPageEventHandling();
|
||||
void _NavigateToProfileSubPage(const Editor::ProfileViewModel& profile, ProfileSubPage page, const IInspectable& breadcrumbTag, const hstring& elementToFocus);
|
||||
|
||||
void _PreNavigateHelper();
|
||||
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const IInspectable& vm, BreadcrumbSubPage subPage = BreadcrumbSubPage::None, hstring elementToFocus = {});
|
||||
Windows::UI::Xaml::Media::Animation::NavigationTransitionInfo _MakeTransitionInfo() const;
|
||||
|
||||
enum class NavDirection
|
||||
{
|
||||
Default,
|
||||
Forward,
|
||||
Back
|
||||
};
|
||||
NavDirection _navDirection{ NavDirection::Default };
|
||||
void _NavigateToProfileHandler(const IInspectable& sender, winrt::guid profileGuid);
|
||||
void _NavigateToColorSchemeHandler(const IInspectable& sender, const IInspectable& args);
|
||||
Microsoft::UI::Xaml::Controls::NavigationViewItem _FindProfileNavItem(winrt::guid profileGuid) const;
|
||||
Editor::ProfileViewModel _FindProfileViewModelByGuid(winrt::guid profileGuid) const;
|
||||
|
||||
void _AppendProfilesRootCrumb();
|
||||
void _SelectNavItemByTag(std::wstring_view tag);
|
||||
|
||||
void _AnnounceNavPaneState(bool opened);
|
||||
|
||||
@@ -110,11 +122,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
safe_void_coroutine _UpdateSearchIndex();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel _profileDefaultsVM{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel> _profileVMs{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ActionsViewModel _actionsVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ExtensionsViewModel _extensionsVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ProfilesPageViewModel _profilesPageVM{ nullptr };
|
||||
|
||||
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable>> _currentSearch{ nullptr };
|
||||
|
||||
|
||||
@@ -164,11 +164,6 @@
|
||||
x:Uid="Nav_Appearance"
|
||||
Tag="GlobalAppearance_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ColorSchemesNavItem"
|
||||
x:Uid="Nav_ColorSchemes"
|
||||
Tag="ColorSchemes_Nav" />
|
||||
|
||||
|
||||
<muxc:NavigationViewItem x:Name="RenderingNavItem"
|
||||
x:Uid="Nav_Rendering"
|
||||
Tag="Rendering_Nav" />
|
||||
@@ -194,11 +189,9 @@
|
||||
x:Uid="Nav_Extensions"
|
||||
Tag="Extensions_Nav" />
|
||||
|
||||
<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="BaseLayerMenuItem"
|
||||
x:Uid="Nav_ProfileDefaults"
|
||||
Tag="GlobalProfile_Nav" />
|
||||
<muxc:NavigationViewItem x:Name="ProfilesNavItem"
|
||||
x:Uid="Nav_Profiles"
|
||||
Tag="Profiles_Nav" />
|
||||
</muxc:NavigationView.MenuItems>
|
||||
|
||||
<muxc:NavigationView.FooterMenuItems>
|
||||
@@ -217,17 +210,7 @@
|
||||
Grid.Row="0">
|
||||
<Frame x:Name="contentFrame"
|
||||
Grid.Row="0"
|
||||
Padding="16,0,16,48">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<NavigationThemeTransition>
|
||||
<NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
<DrillInNavigationTransitionInfo />
|
||||
</NavigationThemeTransition.DefaultNavigationTransitionInfo>
|
||||
</NavigationThemeTransition>
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
Padding="16,0,16,48" />
|
||||
</ScrollViewer>
|
||||
<!-- Explicitly set the background color on grid to prevent the navigation animation from overflowing it -->
|
||||
<Grid Grid.Row="1"
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
<ClInclude Include="EditAction.h">
|
||||
<DependentUpon>EditAction.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AddProfile.h">
|
||||
<DependentUpon>AddProfile.xaml</DependentUpon>
|
||||
<ClInclude Include="Profiles.h">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EnumEntry.h">
|
||||
<DependentUpon>EnumEntry.idl</DependentUpon>
|
||||
@@ -192,7 +192,7 @@
|
||||
<Page Include="EditAction.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="AddProfile.xaml">
|
||||
<Page Include="Profiles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="CommonResources.xaml">
|
||||
@@ -275,8 +275,8 @@
|
||||
<ClCompile Include="EditAction.cpp">
|
||||
<DependentUpon>EditAction.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AddProfile.cpp">
|
||||
<DependentUpon>AddProfile.xaml</DependentUpon>
|
||||
<ClCompile Include="Profiles.cpp">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GlobalAppearance.cpp">
|
||||
<DependentUpon>GlobalAppearance.xaml</DependentUpon>
|
||||
@@ -413,8 +413,8 @@
|
||||
<DependentUpon>Actions.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="AddProfile.idl">
|
||||
<DependentUpon>AddProfile.xaml</DependentUpon>
|
||||
<Midl Include="Profiles.idl">
|
||||
<DependentUpon>Profiles.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="EnumEntry.idl" />
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<Page Include="EditAction.xaml" />
|
||||
<Page Include="SettingsControlsStyle.xaml" />
|
||||
<Page Include="SettingsControlsImplicitStyles.xaml" />
|
||||
<Page Include="AddProfile.xaml" />
|
||||
<Page Include="Profiles.xaml" />
|
||||
<Page Include="KeyChordListener.xaml" />
|
||||
<Page Include="NullableColorPicker.xaml" />
|
||||
<Page Include="IconPicker.xaml" />
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
inline constexpr std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
inline constexpr std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
|
||||
inline constexpr std::wstring_view extensionsTag{ L"Extensions_Nav" };
|
||||
inline constexpr std::wstring_view profilesTag{ L"Profiles_Nav" };
|
||||
inline constexpr std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
inline constexpr std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
inline constexpr std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
inline constexpr std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
std::pair{ actionsTag, L"\xE765" }, /* Keyboard Classic */
|
||||
std::pair{ newTabMenuTag, L"\xE71D" }, /* All Apps */
|
||||
std::pair{ extensionsTag, L"\xEA86" }, /* Puzzle */
|
||||
std::pair{ profilesTag, L"\xE7EE" }, /* Other User */
|
||||
std::pair{ globalProfileTag, L"\xE81E" }, /* Map Layers */
|
||||
std::pair{ addProfileTag, L"\xE710" }, /* Add */
|
||||
std::pair{ openJsonTag, L"\xE713" }, /* Settings */
|
||||
};
|
||||
}
|
||||
|
||||
@@ -128,6 +128,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
_NotifyChanges(L"TabColorPreview");
|
||||
}
|
||||
else if (viewModelProperty == L"Hidden")
|
||||
{
|
||||
_NotifyChanges(L"AccessibleStateDescription");
|
||||
}
|
||||
else if (viewModelProperty == L"Name" || viewModelProperty == L"IsBaseLayer")
|
||||
{
|
||||
_NotifyChanges(L"SectionHeaderText");
|
||||
}
|
||||
});
|
||||
|
||||
// Do the same for the starting directory
|
||||
@@ -340,6 +348,36 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _profile.Orphaned();
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::AccessibleStateDescription() const
|
||||
{
|
||||
const auto hidden = Hidden();
|
||||
const auto orphaned = Orphaned();
|
||||
if (hidden && orphaned)
|
||||
{
|
||||
return til::hstring_format(FMT_COMPILE(L"{}, {}"),
|
||||
RS_(L"Profile_HiddenBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"),
|
||||
RS_(L"Profile_OrphanedBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
}
|
||||
if (hidden)
|
||||
{
|
||||
return RS_(L"Profile_HiddenBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip");
|
||||
}
|
||||
if (orphaned)
|
||||
{
|
||||
return RS_(L"Profile_OrphanedBadge/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::SectionHeaderText() const
|
||||
{
|
||||
if (IsBaseLayer())
|
||||
{
|
||||
return RS_(L"Profile_DefaultsSectionHeader");
|
||||
}
|
||||
return hstring{ RS_fmt(L"Profile_NameSectionHeaderFormat", Name()) };
|
||||
}
|
||||
|
||||
hstring ProfileViewModel::TabTitlePreview() const
|
||||
{
|
||||
if (const auto tabTitle{ TabTitle() }; !tabTitle.empty())
|
||||
|
||||
@@ -102,6 +102,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
bool RepositionCursorWithMouseAvailable() const noexcept;
|
||||
|
||||
bool Orphaned() const;
|
||||
hstring SectionHeaderText() const;
|
||||
hstring AccessibleStateDescription() const;
|
||||
hstring TabTitlePreview() const;
|
||||
hstring AnswerbackMessagePreview() const;
|
||||
Windows::UI::Color TabColorPreview() const;
|
||||
|
||||
@@ -107,6 +107,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
void DeleteUnfocusedAppearance();
|
||||
|
||||
Boolean Orphaned { get; };
|
||||
String SectionHeaderText { get; };
|
||||
String AccessibleStateDescription { get; };
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Name);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Guid, Guid);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Source);
|
||||
|
||||
209
src/cascadia/TerminalSettingsEditor/Profiles.cpp
Normal file
209
src/cascadia/TerminalSettingsEditor/Profiles.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "Profiles.h"
|
||||
#include "Profiles.g.cpp"
|
||||
#include "ProfilesPageViewModel.g.cpp"
|
||||
#include "ProfileViewModel.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
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::Profiles()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetHelpText(DefaultsNavigator(), RS_(L"Profiles_DefaultsNavigator/Description"));
|
||||
Automation::AutomationProperties::SetHelpText(ColorSchemesNavigator(), RS_(L"Profiles_ColorSchemesNavigator/Description"));
|
||||
Automation::AutomationProperties::SetName(AddProfileButton(), RS_(L"Profiles_AddProfileButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
}
|
||||
|
||||
void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ProfilesPageViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"NavigatedToPage",
|
||||
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
|
||||
TraceLoggingValue("profilesLanding", "PageId", "The identifier of the page that was navigated to"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
void Profiles::Defaults_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_ViewModel.RequestOpenDefaults();
|
||||
}
|
||||
|
||||
void Profiles::ColorSchemes_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_ViewModel.RequestOpenColorSchemes();
|
||||
}
|
||||
|
||||
// The primary "+" half of the SplitButton — adds either a new empty
|
||||
// profile or a duplicate of the currently selected source profile,
|
||||
// depending on what the user picked from the flyout.
|
||||
void Profiles::AddProfile_Click(const winrt::Microsoft::UI::Xaml::Controls::SplitButton& /*sender*/,
|
||||
const winrt::Microsoft::UI::Xaml::Controls::SplitButtonClickEventArgs& /*args*/)
|
||||
{
|
||||
const auto selected = _ViewModel.SelectedSourceProfile();
|
||||
const auto sourceGuid = selected ? selected.OriginalProfileGuid() : winrt::guid{};
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
"AddNewProfile",
|
||||
TraceLoggingDescription("Event emitted when the user adds a new profile"),
|
||||
TraceLoggingValue(selected ? "Duplicate" : "EmptyProfile", "Type", "The type of the creation method (i.e. empty profile, duplicate)"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_ViewModel.RequestAddProfile(sourceGuid);
|
||||
}
|
||||
|
||||
// Rebuilds the MenuFlyout each time it opens so newly added/removed
|
||||
// profiles are reflected without having to subscribe to VectorChanged.
|
||||
// Selecting a flyout item updates which profile the SplitButton's primary
|
||||
// action will use as its source — it does NOT add a profile on its own.
|
||||
void Profiles::AddProfileFlyout_Opening(const IInspectable& sender, const IInspectable& /*args*/)
|
||||
{
|
||||
const auto flyout = sender.try_as<MenuFlyout>();
|
||||
if (!flyout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto items = flyout.Items();
|
||||
items.Clear();
|
||||
|
||||
constexpr std::wstring_view groupName{ L"ProfilesAddProfileSource" };
|
||||
const auto selected = _ViewModel.SelectedSourceProfile();
|
||||
const auto weakViewModel = winrt::make_weak(_ViewModel);
|
||||
|
||||
// "New empty profile" item — picking this resets the SplitButton to its
|
||||
// default state where the primary action creates a brand-new profile.
|
||||
{
|
||||
winrt::Microsoft::UI::Xaml::Controls::RadioMenuFlyoutItem newEmptyItem;
|
||||
newEmptyItem.Text(RS_(L"Profiles_AddProfileMenu_NewEmptyProfile/Text"));
|
||||
newEmptyItem.GroupName(groupName);
|
||||
newEmptyItem.IsChecked(!selected);
|
||||
|
||||
Controls::FontIcon plusIcon;
|
||||
plusIcon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
plusIcon.Glyph(L"\xE710");
|
||||
newEmptyItem.Icon(plusIcon);
|
||||
|
||||
newEmptyItem.Click([weakViewModel](const auto&, const auto&) {
|
||||
if (const auto vm = weakViewModel.get())
|
||||
{
|
||||
vm.SelectSourceProfile(nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
items.Append(newEmptyItem);
|
||||
}
|
||||
|
||||
items.Append(MenuFlyoutSeparator{});
|
||||
|
||||
// One RadioMenuFlyoutItem per existing profile — picking one swaps the
|
||||
// SplitButton's primary action over to "duplicate this profile".
|
||||
for (const auto& profileVM : _ViewModel.Profiles())
|
||||
{
|
||||
winrt::Microsoft::UI::Xaml::Controls::RadioMenuFlyoutItem profileItem;
|
||||
profileItem.Text(profileVM.Name());
|
||||
profileItem.Icon(profileVM.IconPreview());
|
||||
profileItem.GroupName(groupName);
|
||||
profileItem.IsChecked(selected && selected.OriginalProfileGuid() == profileVM.OriginalProfileGuid());
|
||||
|
||||
const auto weakProfile = winrt::make_weak(profileVM);
|
||||
profileItem.Click([weakViewModel, weakProfile](const auto&, const auto&) {
|
||||
const auto vm = weakViewModel.get();
|
||||
const auto profile = weakProfile.get();
|
||||
if (vm && profile)
|
||||
{
|
||||
vm.SelectSourceProfile(profile);
|
||||
}
|
||||
});
|
||||
|
||||
items.Append(profileItem);
|
||||
}
|
||||
}
|
||||
|
||||
void Profiles::Profile_Click(const IInspectable& sender, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
// Profile navigators are buttons whose DataContext is the bound ProfileViewModel.
|
||||
if (const auto element = sender.try_as<FrameworkElement>())
|
||||
{
|
||||
if (const auto profile = element.DataContext().try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
_ViewModel.RequestOpenProfile(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProfilesPageViewModel::ProfilesPageViewModel()
|
||||
{
|
||||
_setProfiles(single_threaded_observable_vector<Editor::ProfileViewModel>());
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenDefaults()
|
||||
{
|
||||
OpenDefaultsRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenColorSchemes()
|
||||
{
|
||||
OpenColorSchemesRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestAddProfile(const winrt::guid& sourceProfile)
|
||||
{
|
||||
AddProfileRequested.raise(*this, sourceProfile);
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::SelectSourceProfile(const Editor::ProfileViewModel& profile)
|
||||
{
|
||||
if (_SelectedSourceProfile == profile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_SelectedSourceProfile = profile;
|
||||
_NotifyChanges(L"SelectedSourceProfile",
|
||||
L"HasSelectedSourceProfile",
|
||||
L"SelectedSourceProfileLabel",
|
||||
L"SelectedSourceProfileIcon");
|
||||
}
|
||||
|
||||
winrt::hstring ProfilesPageViewModel::SelectedSourceProfileLabel() const
|
||||
{
|
||||
if (_SelectedSourceProfile)
|
||||
{
|
||||
return _SelectedSourceProfile.Name();
|
||||
}
|
||||
return RS_(L"Profiles_AddProfileButton_DefaultLabel/Text");
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::Controls::IconElement ProfilesPageViewModel::SelectedSourceProfileIcon() const
|
||||
{
|
||||
if (_SelectedSourceProfile)
|
||||
{
|
||||
return _SelectedSourceProfile.IconPreview();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ProfilesPageViewModel::RequestOpenProfile(const Editor::ProfileViewModel& profile)
|
||||
{
|
||||
OpenProfileRequested.raise(*this, profile);
|
||||
}
|
||||
|
||||
}
|
||||
77
src/cascadia/TerminalSettingsEditor/Profiles.h
Normal file
77
src/cascadia/TerminalSettingsEditor/Profiles.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- Profiles.h
|
||||
|
||||
Abstract:
|
||||
- The Profiles landing page in the Settings UI. The page hosts entry points to
|
||||
the list of individual profiles among other profile-related settings.
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Profiles.g.h"
|
||||
#include "ProfilesPageViewModel.g.h"
|
||||
#include "ProfileViewModel.h"
|
||||
#include "Utils.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct ProfilesPageViewModel : ProfilesPageViewModelT<ProfilesPageViewModel>, ViewModelHelper<ProfilesPageViewModel>
|
||||
{
|
||||
public:
|
||||
ProfilesPageViewModel();
|
||||
|
||||
void RequestOpenDefaults();
|
||||
void RequestOpenColorSchemes();
|
||||
void RequestAddProfile(const winrt::guid& sourceProfile);
|
||||
void RequestOpenProfile(const Editor::ProfileViewModel& profile);
|
||||
|
||||
Editor::ProfileViewModel SelectedSourceProfile() const noexcept { return _SelectedSourceProfile; }
|
||||
void SelectSourceProfile(const Editor::ProfileViewModel& profile);
|
||||
bool HasSelectedSourceProfile() const noexcept { return static_cast<bool>(_SelectedSourceProfile); }
|
||||
winrt::hstring SelectedSourceProfileLabel() const;
|
||||
Windows::UI::Xaml::Controls::IconElement SelectedSourceProfileIcon() const;
|
||||
|
||||
// DON'T YOU DARE ADD A `WINRT_CALLBACK(PropertyChanged` TO A CLASS DERIVED FROM ViewModelHelper. Do this instead:
|
||||
using ViewModelHelper<ProfilesPageViewModel>::PropertyChanged;
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::ProfileViewModel>, Profiles, _propertyChangedHandlers, nullptr);
|
||||
|
||||
public:
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenDefaultsRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Windows::Foundation::IInspectable> OpenColorSchemesRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, winrt::guid> AddProfileRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Editor::ProfileViewModel> OpenProfileRequested;
|
||||
|
||||
private:
|
||||
Editor::ProfileViewModel _SelectedSourceProfile{ nullptr };
|
||||
};
|
||||
|
||||
struct Profiles : public HasScrollViewer<Profiles>, ProfilesT<Profiles>
|
||||
{
|
||||
public:
|
||||
Profiles();
|
||||
|
||||
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
|
||||
void Defaults_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void ColorSchemes_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void AddProfile_Click(const Microsoft::UI::Xaml::Controls::SplitButton& sender, const Microsoft::UI::Xaml::Controls::SplitButtonClickEventArgs& args);
|
||||
void AddProfileFlyout_Opening(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& args);
|
||||
void Profile_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_PROPERTY(Editor::ProfilesPageViewModel, ViewModel, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(Profiles);
|
||||
BASIC_FACTORY(ProfilesPageViewModel);
|
||||
}
|
||||
40
src/cascadia/TerminalSettingsEditor/Profiles.idl
Normal file
40
src/cascadia/TerminalSettingsEditor/Profiles.idl
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ProfileViewModel.idl";
|
||||
import "ColorSchemeViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass ProfilesPageViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
ProfilesPageViewModel();
|
||||
|
||||
Windows.Foundation.Collections.IObservableVector<ProfileViewModel> Profiles { get; };
|
||||
|
||||
// The profile whose properties should be used as the source when the
|
||||
// user clicks the SplitButton's primary "+" action. null means "create
|
||||
// a new empty profile" (i.e. the default state).
|
||||
ProfileViewModel SelectedSourceProfile { get; };
|
||||
String SelectedSourceProfileLabel { get; };
|
||||
Windows.UI.Xaml.Controls.IconElement SelectedSourceProfileIcon { get; };
|
||||
Boolean HasSelectedSourceProfile { get; };
|
||||
void SelectSourceProfile(ProfileViewModel profile);
|
||||
|
||||
void RequestOpenDefaults();
|
||||
void RequestOpenColorSchemes();
|
||||
void RequestAddProfile(Guid sourceProfile);
|
||||
void RequestOpenProfile(ProfileViewModel profile);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenDefaultsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, IInspectable> OpenColorSchemesRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Guid> AddProfileRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ProfileViewModel> OpenProfileRequested;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
Profiles();
|
||||
ProfilesPageViewModel ViewModel { get; };
|
||||
}
|
||||
}
|
||||
195
src/cascadia/TerminalSettingsEditor/Profiles.xaml
Normal file
195
src/cascadia/TerminalSettingsEditor/Profiles.xaml
Normal file
@@ -0,0 +1,195 @@
|
||||
<!--
|
||||
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:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}"
|
||||
XYFocusKeyboardNavigation="Enabled">
|
||||
|
||||
<!-- Terminal profiles section -->
|
||||
<local:SettingsExpander x:Uid="Profiles_TerminalProfilesHeader"
|
||||
Margin="0,36,0,0"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind ViewModel.Profiles, Mode=OneWay}">
|
||||
<local:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsExpander.HeaderIcon>
|
||||
<!-- Add Profile split button: primary click adds an empty profile; flyout has "New empty profile" + a separator + one entry per existing profile (which duplicates that profile). -->
|
||||
<muxc:SplitButton x:Name="AddProfileButton"
|
||||
x:Uid="Profiles_AddProfileButton"
|
||||
Click="AddProfile_Click">
|
||||
<muxc:SplitButton.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="SplitButtonBackground"
|
||||
ResourceKey="AccentButtonBackground" />
|
||||
<StaticResource x:Key="SplitButtonForeground"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondary"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPointerOver"
|
||||
ResourceKey="AccentButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPointerOver"
|
||||
ResourceKey="AccentButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPressed"
|
||||
ResourceKey="AccentButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondaryPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrush"
|
||||
ResourceKey="AccentButtonBorderBrush" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPointerOver"
|
||||
ResourceKey="AccentButtonBorderBrushPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPressed"
|
||||
ResourceKey="AccentButtonBorderBrushPressed" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="SplitButtonBackground"
|
||||
ResourceKey="AccentButtonBackground" />
|
||||
<StaticResource x:Key="SplitButtonForeground"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondary"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPointerOver"
|
||||
ResourceKey="AccentButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPointerOver"
|
||||
ResourceKey="AccentButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPressed"
|
||||
ResourceKey="AccentButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondaryPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrush"
|
||||
ResourceKey="AccentButtonBorderBrush" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPointerOver"
|
||||
ResourceKey="AccentButtonBorderBrushPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPressed"
|
||||
ResourceKey="AccentButtonBorderBrushPressed" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="SplitButtonBackground"
|
||||
ResourceKey="AccentButtonBackground" />
|
||||
<StaticResource x:Key="SplitButtonForeground"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondary"
|
||||
ResourceKey="AccentButtonForeground" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPointerOver"
|
||||
ResourceKey="AccentButtonBackgroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPointerOver"
|
||||
ResourceKey="AccentButtonForegroundPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBackgroundPressed"
|
||||
ResourceKey="AccentButtonBackgroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonForegroundSecondaryPressed"
|
||||
ResourceKey="AccentButtonForegroundPressed" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrush"
|
||||
ResourceKey="AccentButtonBorderBrush" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPointerOver"
|
||||
ResourceKey="AccentButtonBorderBrushPointerOver" />
|
||||
<StaticResource x:Key="SplitButtonBorderBrushPressed"
|
||||
ResourceKey="AccentButtonBorderBrushPressed" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
</muxc:SplitButton.Resources>
|
||||
<StackPanel VerticalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<FontIcon FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<ContentControl VerticalAlignment="Center"
|
||||
Content="{x:Bind ViewModel.SelectedSourceProfileIcon, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
Visibility="{x:Bind ViewModel.HasSelectedSourceProfile, Mode=OneWay}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{x:Bind ViewModel.SelectedSourceProfileLabel, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<muxc:SplitButton.Flyout>
|
||||
<MenuFlyout Opening="AddProfileFlyout_Opening"
|
||||
Placement="BottomEdgeAlignedLeft" />
|
||||
</muxc:SplitButton.Flyout>
|
||||
</muxc:SplitButton>
|
||||
<local:SettingsExpander.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:ProfileViewModel">
|
||||
<local:SettingsCard AutomationProperties.HelpText="{x:Bind AccessibleStateDescription, Mode=OneWay}"
|
||||
AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
|
||||
Click="Profile_Click"
|
||||
Header="{x:Bind Name, Mode=OneWay}"
|
||||
HeaderIcon="{x:Bind IconPreview, Mode=OneWay}"
|
||||
IsClickEnabled="True"
|
||||
Style="{StaticResource ClickableSettingsExpanderItemStyle}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<muxc:InfoBadge x:Uid="Profile_HiddenBadge"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind Hidden, Mode=OneWay}">
|
||||
<muxc:InfoBadge.IconSource>
|
||||
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
</muxc:InfoBadge.IconSource>
|
||||
</muxc:InfoBadge>
|
||||
<muxc:InfoBadge x:Uid="Profile_OrphanedBadge"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind Orphaned, Mode=OneWay}">
|
||||
<muxc:InfoBadge.IconSource>
|
||||
<muxc:FontIconSource FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Glyph="" />
|
||||
</muxc:InfoBadge.IconSource>
|
||||
</muxc:InfoBadge>
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
</DataTemplate>
|
||||
</local:SettingsExpander.ItemTemplate>
|
||||
</local:SettingsExpander>
|
||||
|
||||
|
||||
<!-- General Profile Settings -->
|
||||
<TextBlock x:Uid="Profiles_GeneralSettingsHeader"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Defaults navigator -->
|
||||
<local:SettingsCard x:Name="DefaultsNavigator"
|
||||
x:Uid="Profiles_DefaultsNavigator"
|
||||
Click="Defaults_Click"
|
||||
IsClickEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Color schemes navigator -->
|
||||
<local:SettingsCard x:Name="ColorSchemesNavigator"
|
||||
x:Uid="Profiles_ColorSchemesNavigator"
|
||||
Click="ColorSchemes_Click"
|
||||
IsClickEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
</local:SettingsCard>
|
||||
</StackPanel>
|
||||
</Page>
|
||||
@@ -21,9 +21,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
|
||||
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
|
||||
|
||||
AppearanceNavigator().Header(box_value(RS_(L"Profile_Appearance/Header")));
|
||||
TerminalNavigator().Header(box_value(RS_(L"Profile_Terminal/Header")));
|
||||
AdvancedNavigator().Header(box_value(RS_(L"Profile_Advanced/Header")));
|
||||
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
|
||||
}
|
||||
|
||||
void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
@@ -50,7 +48,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (_Profile.FocusDeleteButton())
|
||||
{
|
||||
DeleteProfileButton().Focus(FocusState::Programmatic);
|
||||
DeleteButton().Focus(FocusState::Programmatic);
|
||||
_Profile.FocusDeleteButton(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,56 +32,114 @@
|
||||
Style="{StaticResource DisclaimerStyle}"
|
||||
Visibility="{x:Bind Profile.IsBaseLayer}" />
|
||||
<StackPanel Grid.Row="1"
|
||||
Spacing="2"
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
|
||||
<!-- Section: {Profile.Name} profile (or "Profile defaults") -->
|
||||
<TextBlock Style="{StaticResource TextBlockSubHeaderStyle}"
|
||||
Text="{x:Bind Profile.SectionHeaderText, Mode=OneWay}" />
|
||||
<!-- Name -->
|
||||
<local:SettingsCard x:Name="Name"
|
||||
x:Uid="Profile_Name"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<local:SettingsExpander x:Name="Name"
|
||||
x:Uid="Profile_Name"
|
||||
IsExpanded="True">
|
||||
<TextBox x:Uid="Profile_NameBox"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.Name, Mode=TwoWay}"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}" />
|
||||
<local:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsExpander.HeaderIcon>
|
||||
<local:SettingsExpander.Items>
|
||||
|
||||
<!-- Commandline -->
|
||||
<local:SettingsCard x:Name="Commandline"
|
||||
x:Uid="Profile_Commandline"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<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}">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Starting Directory -->
|
||||
<local:SettingsCard x:Uid="Profile_StartingDirectory"
|
||||
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<TextBox x:Uid="Profile_StartingDirectoryBox"
|
||||
IsSpellCheckEnabled="False"
|
||||
Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.StartingDirectory, Mode=TwoWay}" />
|
||||
<Button x:Name="StartingDirectoryBrowse"
|
||||
x:Uid="Profile_StartingDirectoryBrowse"
|
||||
Click="StartingDirectory_Click"
|
||||
Style="{StaticResource BrowseButtonStyle}">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
|
||||
<local:SettingsCard x:Name="StartingDirectory"
|
||||
ContentAlignment="Left">
|
||||
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
|
||||
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
|
||||
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Elevate -->
|
||||
<local:SettingsCard x:Name="Elevate"
|
||||
ContentAlignment="Left">
|
||||
<CheckBox x:Uid="Profile_Elevate"
|
||||
IsChecked="{x:Bind Profile.Elevate, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Hidden -->
|
||||
<local:SettingsCard x:Name="Hidden"
|
||||
ContentAlignment="Left"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<CheckBox x:Uid="Profile_Hidden"
|
||||
IsChecked="{x:Bind Profile.Hidden, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
</local:SettingsExpander.Items>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Section: Visual/UI Affordance -->
|
||||
<TextBlock x:Uid="Profile_Section_VisualUI"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
<!-- Tab Title -->
|
||||
<local:SettingsCard x:Name="TabTitle"
|
||||
x:Uid="Profile_TabTitle">
|
||||
<TextBox Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.Name, Mode=TwoWay}" />
|
||||
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Commandline -->
|
||||
<local:SettingsCard x:Name="Commandline"
|
||||
x:Uid="Profile_Commandline"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<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:SettingsCard>
|
||||
|
||||
<!-- Starting Directory -->
|
||||
<local:SettingsCard x:Name="StartingDirectory"
|
||||
x:Uid="Profile_StartingDirectory">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<TextBox x:Uid="Profile_StartingDirectoryBox"
|
||||
IsEnabled="{x:Bind mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), 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 mtu:Converters.InvertBoolean(Profile.UseParentProcessDirectory), Mode=OneWay}"
|
||||
Style="{StaticResource BrowseButtonStyle}" />
|
||||
</StackPanel>
|
||||
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
|
||||
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
|
||||
Margin="0,4,0,0"
|
||||
IsChecked="{x:Bind Profile.UseParentProcessDirectory, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</local:SettingsCard>
|
||||
<!-- Tab Color -->
|
||||
<local:SettingsExpander x:Name="TabColor"
|
||||
x:Uid="Profile_TabColor"
|
||||
AutomationProperties.Name="{x:Bind Profile.TabColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}">
|
||||
<local:SettingsExpander.Content>
|
||||
<ContentControl Content="{x:Bind Profile.TabColorPreview, Mode=OneWay}"
|
||||
ContentTemplate="{StaticResource ColorPreviewTemplate}" />
|
||||
</local:SettingsExpander.Content>
|
||||
<local:SettingsExpander.ItemsHeader>
|
||||
<ContentPresenter Padding="16,12,16,16">
|
||||
<local:NullableColorPicker x:Uid="Profile_TabColor_NullableColorPicker"
|
||||
ColorSchemeVM="{x:Bind Profile.DefaultAppearance.CurrentColorScheme, Mode=OneWay}"
|
||||
CurrentColor="{x:Bind Profile.TabColor, Mode=TwoWay}"
|
||||
NullColorPreview="{x:Bind Profile.TabThemeColorPreview, Mode=OneWay}" />
|
||||
</ContentPresenter>
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Icon -->
|
||||
<local:SettingsExpander x:Name="Icon"
|
||||
@@ -111,72 +169,50 @@
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Tab Title -->
|
||||
<local:SettingsCard x:Name="TabTitle"
|
||||
x:Uid="Profile_TabTitle">
|
||||
<TextBox Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
|
||||
<!-- Addition settings -->
|
||||
|
||||
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<local:SettingsCard x:Name="AppearanceNavigator"
|
||||
x:Uid="Profile_AppearanceNavigator"
|
||||
Click="Appearance_Click"
|
||||
IsClickEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
</local:SettingsCard>
|
||||
<local:SettingsCard x:Name="TerminalNavigator"
|
||||
x:Uid="Profile_TerminalNavigator"
|
||||
Click="Terminal_Click"
|
||||
IsClickEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
</local:SettingsCard>
|
||||
<local:SettingsCard x:Name="AdvancedNavigator"
|
||||
x:Uid="Profile_AdvancedNavigator"
|
||||
Click="Advanced_Click"
|
||||
IsClickEnabled="True">
|
||||
<local:SettingsCard.HeaderIcon>
|
||||
<FontIcon Glyph="" />
|
||||
</local:SettingsCard.HeaderIcon>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Tab Color -->
|
||||
<local:SettingsExpander x:Name="TabColor"
|
||||
x:Uid="Profile_TabColor"
|
||||
AutomationProperties.Name="{x:Bind Profile.TabColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}">
|
||||
<local:SettingsExpander.Content>
|
||||
<ContentControl Content="{x:Bind Profile.TabColorPreview, Mode=OneWay}"
|
||||
ContentTemplate="{StaticResource ColorPreviewTemplate}" />
|
||||
</local:SettingsExpander.Content>
|
||||
<local:SettingsExpander.ItemsHeader>
|
||||
<ContentPresenter Padding="16,12,16,16">
|
||||
<local:NullableColorPicker x:Uid="Profile_TabColor_NullableColorPicker"
|
||||
ColorSchemeVM="{x:Bind Profile.DefaultAppearance.CurrentColorScheme, Mode=OneWay}"
|
||||
CurrentColor="{x:Bind Profile.TabColor, Mode=TwoWay}"
|
||||
NullColorPreview="{x:Bind Profile.TabThemeColorPreview, Mode=OneWay}" />
|
||||
</ContentPresenter>
|
||||
</local:SettingsExpander.ItemsHeader>
|
||||
</local:SettingsExpander>
|
||||
|
||||
<!-- Elevate -->
|
||||
<local:SettingsCard x:Name="Elevate"
|
||||
x:Uid="Profile_Elevate">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.Elevate, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Hidden -->
|
||||
<local:SettingsCard x:Name="Hidden"
|
||||
x:Uid="Profile_Hidden"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Reset Profile -->
|
||||
<local:SettingsCard x:Name="ResetProfile"
|
||||
x:Uid="Profile_ResetProfile"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<Button x:Uid="Profile_ResetProfileButton"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="Profile_ResetProfileConfirmationMessage"
|
||||
Style="{StaticResource CustomFlyoutTextStyle}" />
|
||||
<Button x:Uid="Profile_ResetProfileConfirmationButton"
|
||||
Click="ResetProfileConfirmation_Click" />
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</local:SettingsCard>
|
||||
|
||||
<!-- Delete Profile -->
|
||||
<local:SettingsCard x:Name="DeleteProfile"
|
||||
x:Uid="Profile_DeleteProfile"
|
||||
Visibility="{x:Bind Profile.CanDeleteProfile}">
|
||||
<Button x:Name="DeleteProfileButton"
|
||||
x:Uid="Profile_DeleteProfileButton"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
<!-- Delete Button -->
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
|
||||
<Button x:Name="DeleteButton"
|
||||
Margin="{StaticResource StandardControlMargin}"
|
||||
Style="{StaticResource DeleteButtonStyle}"
|
||||
Visibility="{x:Bind Profile.CanDeleteProfile}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Profile_DeleteButton"
|
||||
Margin="8,0,0,0" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
@@ -188,21 +224,7 @@
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</local:SettingsCard>
|
||||
|
||||
<TextBlock x:Uid="Profile_AdditionalSettingsHeader"
|
||||
Margin="0,32,0,4"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<local:SettingsCard x:Name="AppearanceNavigator"
|
||||
Click="Appearance_Click"
|
||||
IsClickEnabled="True" />
|
||||
<local:SettingsCard x:Name="TerminalNavigator"
|
||||
Click="Terminal_Click"
|
||||
IsClickEnabled="True" />
|
||||
<local:SettingsCard x:Name="AdvancedNavigator"
|
||||
Click="Advanced_Click"
|
||||
IsClickEnabled="True" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -117,18 +117,6 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AddProfile_AddNewTextBlock.Text" xml:space="preserve">
|
||||
<value>New empty profile</value>
|
||||
<comment>Button label that creates a new profile with default settings.</comment>
|
||||
</data>
|
||||
<data name="AddProfile_Duplicate.Header" xml:space="preserve">
|
||||
<value>Duplicate a profile</value>
|
||||
<comment>This is the header for a control that lets the user duplicate one of their existing profiles.</comment>
|
||||
</data>
|
||||
<data name="AddProfile_DuplicateTextBlock.Text" xml:space="preserve">
|
||||
<value>Duplicate</value>
|
||||
<comment>Button label that duplicates the selected profile and navigates to the duplicate's page.</comment>
|
||||
</data>
|
||||
<data name="ColorScheme_InboxSchemeDuplicate.Header" xml:space="preserve">
|
||||
<value>This color scheme is part of the built-in settings or an installed extension</value>
|
||||
</data>
|
||||
@@ -930,7 +918,7 @@
|
||||
<value>Executable used in the profile.</value>
|
||||
<comment>A description for what the "command line" setting does. Presented near "Profile_Commandline".</comment>
|
||||
</data>
|
||||
<data name="Profile_CommandlineBrowse.Content" xml:space="preserve">
|
||||
<data name="Profile_CommandlineBrowse.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Browse...</value>
|
||||
<comment>Button label that opens a file picker in a new window. The "..." is standard to mean it will open a new window.</comment>
|
||||
</data>
|
||||
@@ -1101,22 +1089,14 @@
|
||||
<value>The selected font has no font features.</value>
|
||||
<comment>A description provided when the font features setting is disabled. Presented near "Profile_FontFeatures".</comment>
|
||||
</data>
|
||||
<data name="Profile_Hidden.Header" xml:space="preserve">
|
||||
<data name="Profile_Hidden.Content" xml:space="preserve">
|
||||
<value>Hide profile from dropdown</value>
|
||||
<comment>Header for a control to toggle whether the profile is shown in a dropdown menu, or not.</comment>
|
||||
</data>
|
||||
<data name="Profile_Hidden.Description" xml:space="preserve">
|
||||
<value>If enabled, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file.</value>
|
||||
<comment>A description for what the "hidden" setting does. Presented near "Profile_Hidden".</comment>
|
||||
</data>
|
||||
<data name="Profile_Elevate.Header" xml:space="preserve">
|
||||
<value>Run this profile as Administrator</value>
|
||||
<data name="Profile_Elevate.Content" xml:space="preserve">
|
||||
<value>Run as administrator (uses current window if already elevated)</value>
|
||||
<comment>Header for a control to toggle whether the profile should always open elevated (in an admin window)</comment>
|
||||
</data>
|
||||
<data name="Profile_Elevate.Description" xml:space="preserve">
|
||||
<value>If enabled, the profile will open in an Admin terminal window automatically. If the current window is already running as admin, it will open in this window.</value>
|
||||
<comment>A description for what the "elevate" setting does. Presented near "Profile_Elevate".</comment>
|
||||
</data>
|
||||
<data name="Profile_HistorySize.Header" xml:space="preserve">
|
||||
<value>History size</value>
|
||||
<comment>Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.</comment>
|
||||
@@ -1213,11 +1193,7 @@
|
||||
<value>Starting directory</value>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Description" xml:space="preserve">
|
||||
<value>The directory the profile starts in when it is loaded.</value>
|
||||
<comment>A description for what the "starting directory" setting does. Presented near "Profile_StartingDirectory".</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBrowse.Content" xml:space="preserve">
|
||||
<data name="Profile_StartingDirectoryBrowse.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Browse...</value>
|
||||
<comment>Button label that opens a file picker in a new window. The "..." is standard to mean it will open a new window.</comment>
|
||||
</data>
|
||||
@@ -1293,10 +1269,6 @@
|
||||
<value>⚠ You have unsaved changes.</value>
|
||||
<comment>{Locked="⚠"} A disclaimer that appears when the unsaved changes to the settings are present.</comment>
|
||||
</data>
|
||||
<data name="Nav_AddNewProfile.Content" xml:space="preserve">
|
||||
<value>Add a new profile</value>
|
||||
<comment>Header for the "add new" menu item. This navigates to the page where users can add a new profile.</comment>
|
||||
</data>
|
||||
<data name="Nav_Profiles.Content" xml:space="preserve">
|
||||
<value>Profiles</value>
|
||||
<comment>Header for the "profiles" menu items. This acts as a divider to introduce profile-related menu items.</comment>
|
||||
@@ -2820,4 +2792,88 @@
|
||||
<value>None</value>
|
||||
<comment>Default placeholder text shown in text box settings when no value has been set.</comment>
|
||||
</data>
|
||||
<data name="Nav_Profiles.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Profiles</value>
|
||||
<comment>Tooltip for the "profiles" menu item. Navigates to a landing page that lists profile-related settings.</comment>
|
||||
</data>
|
||||
<data name="Profile_AdvancedNavigator.Header" xml:space="preserve">
|
||||
<value>Advanced</value>
|
||||
<comment>Header for the "Advanced" navigator card on the profile page. Navigates to the advanced settings sub-page.</comment>
|
||||
</data>
|
||||
<data name="Profile_AppearanceNavigator.Description" xml:space="preserve">
|
||||
<value>Customize the visual appearance of the profile, including colors, fonts, and text styling.</value>
|
||||
<comment>Description shown below the "Appearance" navigator card on the profile page.</comment>
|
||||
</data>
|
||||
<data name="Profile_AppearanceNavigator.Header" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
<comment>Header for the "Appearance" navigator card on the profile page. Navigates to the appearance sub-page.</comment>
|
||||
</data>
|
||||
<data name="Profile_DefaultsSectionHeader" xml:space="preserve">
|
||||
<value>Profile defaults</value>
|
||||
<comment>Header used in place of the "{name} profile" header when the page is showing the profile-defaults layer (which has no profile name).</comment>
|
||||
</data>
|
||||
<data name="Profile_HiddenBadge.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Hidden from the dropdown menu</value>
|
||||
<comment>Tooltip shown when hovering the InfoBadge next to a profile name on the Profiles landing page when that profile is hidden from the dropdown menu.</comment>
|
||||
</data>
|
||||
<data name="Profile_NameBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Name</value>
|
||||
<comment>Placeholder text shown inside the empty profile name text box, hinting that the user should enter the profile's name here.</comment>
|
||||
</data>
|
||||
<data name="Profile_NameSectionHeaderFormat" xml:space="preserve">
|
||||
<value>{0} profile</value>
|
||||
<comment>Localizable format string used as the section header for a profile (e.g. "PowerShell profile"). {0} is replaced by the profile's name. Reorder the placeholder if your language requires a different word order.</comment>
|
||||
</data>
|
||||
<data name="Profile_OrphanedBadge.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Profile is no longer detected</value>
|
||||
<comment>Tooltip shown when hovering the InfoBadge next to a profile name on the Profiles landing page when that profile's source software is no longer installed.</comment>
|
||||
</data>
|
||||
<data name="Profile_Section_VisualUI.Text" xml:space="preserve">
|
||||
<value>Visual/UI Affordance</value>
|
||||
<comment>Title of a section in a profile page that groups visual and UI settings (tab title, icon, tab color, etc.).</comment>
|
||||
</data>
|
||||
<data name="Profile_TerminalNavigator.Description" xml:space="preserve">
|
||||
<value>Configure how the terminal interprets text and control sequences to behave like a traditional command-line terminal</value>
|
||||
<comment>Description shown below the "Terminal Emulation" navigator card on the profile page.</comment>
|
||||
</data>
|
||||
<data name="Profile_TerminalNavigator.Header" xml:space="preserve">
|
||||
<value>Terminal emulation</value>
|
||||
<comment>Header for the "Terminal Emulation" navigator card on the profile page. Navigates to the terminal emulation sub-page.</comment>
|
||||
</data>
|
||||
<data name="Profiles_AddProfileButton_DefaultLabel.Text" xml:space="preserve">
|
||||
<value>Add new profile</value>
|
||||
<comment>Default label shown next to the "+" icon on the add-profile split button when no source profile has been selected from the flyout. Clicking the button in this state creates a brand-new empty profile.</comment>
|
||||
</data>
|
||||
<data name="Profiles_AddProfileButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Add a new profile</value>
|
||||
<comment>Tooltip (and accessible name) for the split button on the Profiles landing page whose primary "+" action creates a new empty profile and whose flyout lists existing profiles to duplicate.</comment>
|
||||
</data>
|
||||
<data name="Profiles_AddProfileMenu_NewEmptyProfile.Text" xml:space="preserve">
|
||||
<value>New empty profile</value>
|
||||
<comment>Label for the first item in the add-profile split button's flyout. Clicking this creates a new profile with default settings.</comment>
|
||||
</data>
|
||||
<data name="Profiles_ColorSchemesNavigator.Description" xml:space="preserve">
|
||||
<value>Add, edit, or remove the color schemes that your profiles can use.</value>
|
||||
<comment>Help text describing the "Color schemes" navigator on the Profiles landing page.</comment>
|
||||
</data>
|
||||
<data name="Profiles_ColorSchemesNavigator.Header" xml:space="preserve">
|
||||
<value>Color schemes</value>
|
||||
<comment>Title for the "Color schemes" navigator on the Profiles landing page. Clicking this opens the same page reachable from the top-level Color schemes nav item.</comment>
|
||||
</data>
|
||||
<data name="Profiles_DefaultsNavigator.Description" xml:space="preserve">
|
||||
<value>Changes made here apply to all profiles unless overridden by a specific profile. These settings do not affect the Windows Terminal appearance.</value>
|
||||
<comment>Help text describing the "Defaults" navigator on the Profiles landing page. Clarifies that the defaults apply to every profile but are not the same as the global Windows Terminal appearance settings.</comment>
|
||||
</data>
|
||||
<data name="Profiles_DefaultsNavigator.Header" xml:space="preserve">
|
||||
<value>Defaults</value>
|
||||
<comment>Title for the "Defaults" navigator on the Profiles landing page. Clicking this opens the page where defaults shared by all profiles can be edited.</comment>
|
||||
</data>
|
||||
<data name="Profiles_GeneralSettingsHeader.Text" xml:space="preserve">
|
||||
<value>General profile settings</value>
|
||||
<comment>Section header on the Profiles landing page. Introduces general-purpose profile settings such as the defaults shared by all profiles and the color schemes that profiles can use.</comment>
|
||||
</data>
|
||||
<data name="Profiles_TerminalProfilesHeader.Header" xml:space="preserve">
|
||||
<value>Terminal profiles</value>
|
||||
<comment>Section header on the Profiles landing page. Introduces the list of individual terminal profiles configured by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -103,9 +103,9 @@ $ClassMap = @{
|
||||
NavigationParam = "GlobalProfile_Nav"
|
||||
SubPage = "BreadcrumbSubPage::Profile_Advanced"
|
||||
}
|
||||
"Microsoft::Terminal::Settings::Editor::AddProfile" = @{
|
||||
ResourceName = "Nav_AddNewProfile/Content"
|
||||
NavigationParam = "AddProfile"
|
||||
"Microsoft::Terminal::Settings::Editor::Profiles" = @{
|
||||
ResourceName = "Nav_Profiles/Content"
|
||||
NavigationParam = "Profiles_Nav"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
}
|
||||
}
|
||||
@@ -182,18 +182,6 @@ foreach ($xamlFile in Get-ChildItem -Path $SourceDir -Filter *.xaml)
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq "AddProfile.xaml")
|
||||
{
|
||||
# "add new" button
|
||||
$entries += [pscustomobject]@{
|
||||
ResourceName = "AddProfile_AddNewTextBlock/Text"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = $ClassMap[$pageClass].NavigationParam
|
||||
SubPage = $ClassMap[$pageClass].SubPage
|
||||
ElementName = "AddNewButton"
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
|
||||
# Iterate over all local:SettingsCard and local:SettingsExpander nodes
|
||||
foreach ($settingContainer in ($xml.SelectNodes("//local:SettingsCard", $xm) + $xml.SelectNodes("//local:SettingsExpander", $xm)))
|
||||
|
||||
Reference in New Issue
Block a user