Add New Tab Menu Customization to Settings UI
This commit is contained in:
parent
544452dad4
commit
0e304d8197
|
@ -16,6 +16,7 @@
|
|||
#include "AddProfile.h"
|
||||
#include "InteractionViewModel.h"
|
||||
#include "LaunchViewModel.h"
|
||||
#include "NewTabMenuViewModel.h"
|
||||
#include "..\types\inc\utils.hpp"
|
||||
#include <..\WinRTUtils\inc\Utils.h>
|
||||
|
||||
|
@ -40,6 +41,7 @@ static const std::wstring_view launchTag{ L"Launch_Nav" };
|
|||
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
|
||||
static const std::wstring_view renderingTag{ L"Rendering_Nav" };
|
||||
static const std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
static const std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
|
||||
static const std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
static const std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
static const std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
|
@ -59,6 +61,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
InitializeComponent();
|
||||
_UpdateBackgroundForMica();
|
||||
|
||||
_newTabMenuPageVM = winrt::make<NewTabMenuViewModel>(_settingsClone);
|
||||
_colorSchemesPageVM = winrt::make<ColorSchemesPageViewModel>(_settingsClone);
|
||||
_colorSchemesPageViewModelChangedRevoker = _colorSchemesPageVM.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto settingName{ args.PropertyName() };
|
||||
|
@ -134,6 +137,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
_InitializeProfilesList();
|
||||
// Update the Nav State with the new version of the settings
|
||||
_colorSchemesPageVM.UpdateSettings(_settingsClone);
|
||||
get_self<NewTabMenuViewModel>(_newTabMenuPageVM)->UpdateSettings(_settingsClone);
|
||||
|
||||
// We'll update the profile in the _profilesNavState whenever we actually navigate to one
|
||||
|
||||
|
@ -378,6 +382,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Actions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
else if (clickedItemTag == newTabMenuTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), _newTabMenuPageVM);
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
else if (clickedItemTag == globalProfileTag)
|
||||
{
|
||||
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) };
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
void _MoveXamlParsedNavItemsIntoItemSource();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };
|
||||
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _profileViewModelChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _colorSchemesPageViewModelChangedRevoker;
|
||||
|
|
|
@ -142,6 +142,13 @@
|
|||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
|
||||
<muxc:NavigationViewItem x:Uid="Nav_NewTabMenu"
|
||||
Tag="NewTabMenu_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
|
||||
<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="BaseLayerMenuItem"
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
<ClInclude Include="Launch.h">
|
||||
<DependentUpon>Launch.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NewTabMenu.h">
|
||||
<DependentUpon>NewTabMenu.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="MainPage.h">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
|
@ -106,6 +109,10 @@
|
|||
<DependentUpon>LaunchViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NewTabMenuViewModel.h">
|
||||
<DependentUpon>NewTabMenuViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Profiles_Base.h">
|
||||
<DependentUpon>Profiles_Base.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
@ -160,6 +167,9 @@
|
|||
<Page Include="Launch.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="NewTabMenu.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="MainPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
|
@ -210,6 +220,9 @@
|
|||
<ClCompile Include="Launch.cpp">
|
||||
<DependentUpon>Launch.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NewTabMenu.cpp">
|
||||
<DependentUpon>NewTabMenu.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -249,6 +262,10 @@
|
|||
<DependentUpon>LaunchViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NewTabMenuViewModel.cpp">
|
||||
<DependentUpon>NewTabMenuViewModel.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Profiles_Base.cpp">
|
||||
<DependentUpon>Profiles_Base.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
@ -307,6 +324,10 @@
|
|||
<DependentUpon>Launch.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="NewTabMenu.idl">
|
||||
<DependentUpon>NewTabMenu.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="Interaction.idl">
|
||||
<DependentUpon>Interaction.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
@ -326,6 +347,7 @@
|
|||
<Midl Include="InteractionViewModel.idl" />
|
||||
<Midl Include="GlobalAppearanceViewModel.idl" />
|
||||
<Midl Include="LaunchViewModel.idl" />
|
||||
<Midl Include="NewTabMenuViewModel.idl" />
|
||||
<Midl Include="Profiles_Base.idl">
|
||||
<DependentUpon>Profiles_Base.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<Midl Include="LaunchViewModel.idl" />
|
||||
<Midl Include="EnumEntry.idl" />
|
||||
<Midl Include="SettingContainer.idl" />
|
||||
<Midl Include="NewTabMenuViewModel.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -49,5 +50,6 @@
|
|||
<Page Include="SettingContainerStyle.xaml" />
|
||||
<Page Include="AddProfile.xaml" />
|
||||
<Page Include="KeyChordListener.xaml" />
|
||||
<Page Include="NewTabMenu.xaml" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "NewTabMenu.h"
|
||||
#include "NewTabMenu.g.cpp"
|
||||
#include "NewTabMenuEntryTemplateSelector.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
|
||||
#include "NewTabMenuViewModel.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
NewTabMenu::NewTabMenu()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_entryTemplateSelector = Resources().Lookup(box_value(L"NewTabMenuEntryTemplateSelector")).as<Editor::NewTabMenuEntryTemplateSelector>();
|
||||
|
||||
// TODO CARLOS: set auto props, if necessary
|
||||
//Automation::AutomationProperties::SetName(NewTabMenuModeComboBox(), RS_(L"Globals_NewTabMenuModeSetting/Text"));
|
||||
//Automation::AutomationProperties::SetHelpText(NewTabMenuModeComboBox(), RS_(L"Globals_NewTabMenuModeSetting/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
//Automation::AutomationProperties::SetHelpText(PosXBox(), RS_(L"Globals_InitialPosXBox/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
//Automation::AutomationProperties::SetHelpText(PosYBox(), RS_(L"Globals_InitialPosYBox/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
//Automation::AutomationProperties::SetHelpText(UseDefaultNewTabMenuPositionCheckbox(), RS_(L"Globals_DefaultNewTabMenuPositionCheckbox/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
//Automation::AutomationProperties::SetName(CenterOnNewTabMenuToggle(), RS_(L"Globals_CenterOnNewTabMenu/Text"));
|
||||
//Automation::AutomationProperties::SetHelpText(CenterOnNewTabMenuToggle(), RS_(L"Globals_CenterOnNewTabMenu/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
}
|
||||
|
||||
void NewTabMenu::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::NewTabMenuViewModel>();
|
||||
}
|
||||
|
||||
void NewTabMenu::FolderNameTextBox_TextChanged(const IInspectable& sender, const Controls::TextChangedEventArgs& /*e*/)
|
||||
{
|
||||
const auto isTextEmpty = sender.as<Controls::TextBox>().Text().empty();
|
||||
AddFolderButton().IsEnabled(!isTextEmpty);
|
||||
}
|
||||
|
||||
DataTemplate NewTabMenuEntryTemplateSelector::SelectTemplateCore(const IInspectable& item, const DependencyObject& /*container*/)
|
||||
{
|
||||
return SelectTemplateCore(item);
|
||||
}
|
||||
|
||||
DataTemplate NewTabMenuEntryTemplateSelector::SelectTemplateCore(const IInspectable& item)
|
||||
{
|
||||
if (const auto entryVM = item.try_as<Editor::NewTabMenuEntryViewModel>())
|
||||
{
|
||||
switch (entryVM.Type())
|
||||
{
|
||||
case Model::NewTabMenuEntryType::Profile:
|
||||
return ProfileEntryTemplate();
|
||||
case Model::NewTabMenuEntryType::Separator:
|
||||
return SeparatorEntryTemplate();
|
||||
case Model::NewTabMenuEntryType::Folder:
|
||||
return FolderEntryTemplate();
|
||||
case Model::NewTabMenuEntryType::MatchProfiles:
|
||||
return MatchProfilesEntryTemplate();
|
||||
case Model::NewTabMenuEntryType::RemainingProfiles:
|
||||
return RemainingProfilesEntryTemplate();
|
||||
case Model::NewTabMenuEntryType::Invalid:
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NewTabMenu.g.h"
|
||||
#include "NewTabMenuEntryTemplateSelector.g.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct NewTabMenu : public HasScrollViewer<NewTabMenu>, NewTabMenuT<NewTabMenu>
|
||||
{
|
||||
public:
|
||||
NewTabMenu();
|
||||
|
||||
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
|
||||
void FolderNameTextBox_TextChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::Controls::TextChangedEventArgs& e);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(Editor::NewTabMenuViewModel, ViewModel, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
private:
|
||||
Editor::NewTabMenuEntryTemplateSelector _entryTemplateSelector{ nullptr };
|
||||
};
|
||||
|
||||
struct NewTabMenuEntryTemplateSelector : public NewTabMenuEntryTemplateSelectorT<NewTabMenuEntryTemplateSelector>
|
||||
{
|
||||
public:
|
||||
NewTabMenuEntryTemplateSelector() = default;
|
||||
|
||||
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item, const Windows::UI::Xaml::DependencyObject& container);
|
||||
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item);
|
||||
|
||||
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, ProfileEntryTemplate, nullptr);
|
||||
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, SeparatorEntryTemplate, nullptr);
|
||||
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, FolderEntryTemplate, nullptr);
|
||||
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, MatchProfilesEntryTemplate, nullptr);
|
||||
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, RemainingProfilesEntryTemplate, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(NewTabMenu);
|
||||
BASIC_FACTORY(NewTabMenuEntryTemplateSelector);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "NewTabMenuViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
[default_interface] runtimeclass NewTabMenu : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
NewTabMenu();
|
||||
NewTabMenuViewModel ViewModel { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass NewTabMenuEntryTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
|
||||
{
|
||||
NewTabMenuEntryTemplateSelector();
|
||||
|
||||
Windows.UI.Xaml.DataTemplate ProfileEntryTemplate;
|
||||
Windows.UI.Xaml.DataTemplate SeparatorEntryTemplate;
|
||||
Windows.UI.Xaml.DataTemplate FolderEntryTemplate;
|
||||
Windows.UI.Xaml.DataTemplate MatchProfilesEntryTemplate;
|
||||
Windows.UI.Xaml.DataTemplate RemainingProfilesEntryTemplate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
<!--
|
||||
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.NewTabMenu"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
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.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<StaticResource x:Key="ControlExampleDisplayBrush" ResourceKey="SolidBackgroundFillColorBaseBrush" />
|
||||
<Thickness x:Key="ControlExampleDisplayBorderThickness">0</Thickness>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="ControlExampleDisplayBrush" ResourceKey="SolidBackgroundFillColorBaseBrush" />
|
||||
<Thickness x:Key="ControlExampleDisplayBorderThickness">0</Thickness>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<SolidColorBrush x:Key="ControlExampleDisplayBrush" Color="{ThemeResource SystemColorWindowColor}" />
|
||||
<Thickness x:Key="ControlExampleDisplayBorderThickness">1</Thickness>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>-->
|
||||
|
||||
<DataTemplate x:Key="ProfileEntryTemplate"
|
||||
x:DataType="local:ProfileEntryViewModel">
|
||||
<muxc:TreeViewItem AutomationProperties.Name="{x:Bind ProfileEntry.Profile.Name, Mode=OneWay}">
|
||||
<muxc:TreeViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<Image Source="{x:Bind ProfileEntry.Profile.Icon, Mode=OneWay}"
|
||||
Width="16"
|
||||
Height="16" />
|
||||
<TextBlock Text="{x:Bind ProfileEntry.Profile.Name, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</muxc:TreeViewItem.Content>
|
||||
</muxc:TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="SeparatorEntryTemplate"
|
||||
x:DataType="local:SeparatorEntryViewModel">
|
||||
<muxc:TreeViewItem x:Uid="NewTabMenuEntry_Separator"
|
||||
FontStyle="Italic"/>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- TODO CARLOS: I'm using TreeViewItem.ItemsSource to recursively define
|
||||
folder entries. This is the method shown in the WinUI 2 Gallery.
|
||||
It's not working. Investigate.
|
||||
Investigation Notes:
|
||||
If you comment out the images, this works. Otherwise, sometimes you
|
||||
get a crash or the nested folders don't load.-->
|
||||
<DataTemplate x:Key="FolderEntryTemplate"
|
||||
x:DataType="local:FolderEntryViewModel">
|
||||
<muxc:TreeViewItem AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind Entries, Mode=TwoWay}"
|
||||
IsExpanded="True">
|
||||
<muxc:TreeViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<!--<Image Source="{x:Bind Icon}"
|
||||
Width="16"
|
||||
Height="16" />-->
|
||||
<TextBlock Text="{x:Bind Name, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</muxc:TreeViewItem.Content>
|
||||
</muxc:TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="MatchProfilesEntryTemplate"
|
||||
x:DataType="local:MatchProfilesEntryViewModel">
|
||||
<muxc:TreeViewItem FontStyle="Italic"
|
||||
Content="{x:Bind DisplayText, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="RemainingProfilesEntryTemplate"
|
||||
x:DataType="local:RemainingProfilesEntryViewModel">
|
||||
<muxc:TreeViewItem x:Uid="NewTabMenuEntry_RemainingProfiles"
|
||||
FontStyle="Italic"/>
|
||||
</DataTemplate>
|
||||
|
||||
<local:NewTabMenuEntryTemplateSelector x:Key="NewTabMenuEntryTemplateSelector"
|
||||
ProfileEntryTemplate="{StaticResource ProfileEntryTemplate}"
|
||||
SeparatorEntryTemplate="{StaticResource SeparatorEntryTemplate}"
|
||||
FolderEntryTemplate="{StaticResource FolderEntryTemplate}"
|
||||
MatchProfilesEntryTemplate="{StaticResource MatchProfilesEntryTemplate}"
|
||||
RemainingProfilesEntryTemplate="{StaticResource RemainingProfilesEntryTemplate}"/>
|
||||
</ResourceDictionary>
|
||||
</Page.Resources>
|
||||
|
||||
<StackPanel>
|
||||
<!-- Margin stolen from SettingsStackStyle -->
|
||||
<Grid Margin="13,0,13,48">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!--New Tab Menu Content-->
|
||||
<Border Grid.Row="0"
|
||||
Margin="0,12,0,12"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
|
||||
BorderThickness="1"
|
||||
MaxWidth="{StaticResource StandardControlMaxWidth}"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}"
|
||||
Height="200">
|
||||
<muxc:TreeView x:Name="NewTabMenuTreeView"
|
||||
AllowDrop="False"
|
||||
CanDrag="False"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
SelectionMode="None"
|
||||
ItemsSource="{x:Bind ViewModel.Entries, Mode=OneWay}"
|
||||
ItemTemplateSelector="{StaticResource NewTabMenuEntryTemplateSelector}"/>
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Row="1"
|
||||
HorizontalAlignment="Stretch">
|
||||
<!-- Add Profile -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddProfile"
|
||||
FontIconGlyph="">
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
<!--Select profile to add-->
|
||||
<!--TODO CARLOS: sort the list alphabetically?-->
|
||||
<ComboBox x:Name="AddProfileComboBox"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedProfile, Mode=TwoWay}"
|
||||
MinWidth="{StaticResource StandardBoxMinWidth}">
|
||||
<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), Mode=OneTime}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind Name}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Button x:Name="AddProfileButton"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="{x:Bind ViewModel.RequestAddSelectedProfileEntry}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Separator -->
|
||||
<!--TODO CARLOS: the button height is different from the one before.-->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddSeparator"
|
||||
FontIconGlyph="">
|
||||
<Button x:Name="AddSeparatorButton"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="{x:Bind ViewModel.RequestAddSeparatorEntry}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Folder -->
|
||||
<!--TODO CARLOS: adding an icon would be cool, but I don't think we're equipped to do that yet-->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddFolder"
|
||||
FontIconGlyph="">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
<TextBox x:Uid="NewTabMenu_AddFolder_FolderName"
|
||||
x:Name="FolderNameTextBox"
|
||||
MinWidth="{StaticResource StandardBoxMinWidth}"
|
||||
Text="{x:Bind ViewModel.FolderName, Mode=TwoWay}"
|
||||
TextChanged="FolderNameTextBox_TextChanged"/>
|
||||
<Button x:Name="AddFolderButton"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="{x:Bind ViewModel.RequestAddFolderEntry}"
|
||||
IsEnabled="False">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Match Profiles -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddMatchProfiles"
|
||||
FontIconGlyph=""
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Name"
|
||||
Text="{x:Bind ViewModel.ProfileMatcherName, Mode=TwoWay}"/>
|
||||
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Source"
|
||||
Text="{x:Bind ViewModel.ProfileMatcherSource, Mode=TwoWay}"/>
|
||||
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Commandline"
|
||||
Text="{x:Bind ViewModel.ProfileMatcherCommandline, Mode=TwoWay}"/>
|
||||
<Button x:Name="AddMatchProfilesButton"
|
||||
Click="{x:Bind ViewModel.RequestAddProfileMatcherEntry}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="NewTabMenu_AddMatchProfiles_Confirmation"
|
||||
Style="{StaticResource IconButtonTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Remaining Profiles -->
|
||||
<!--TODO CARLOS: it would be cool if when disabled, we should -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddRemainingProfiles"
|
||||
FontIconGlyph="">
|
||||
<Button VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="{x:Bind ViewModel.RequestAddRemainingProfilesEntry}"
|
||||
IsEnabled="{x:Bind ViewModel.IsRemainingProfilesEntryMissing(ViewModel.Entries), Mode=OneWay}">
|
||||
<Button.Content>
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Page>
|
|
@ -0,0 +1,321 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "NewTabMenuViewModel.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "NewTabMenuViewModel.g.cpp"
|
||||
#include "NewTabMenuEntryViewModel.g.cpp"
|
||||
#include "ProfileEntryViewModel.g.cpp"
|
||||
#include "SeparatorEntryViewModel.g.cpp"
|
||||
#include "FolderEntryViewModel.g.cpp"
|
||||
#include "MatchProfilesEntryViewModel.g.cpp"
|
||||
#include "RemainingProfilesEntryViewModel.g.cpp"
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Windows::UI::Xaml::Data;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static IObservableVector<Editor::NewTabMenuEntryViewModel> _ConvertToViewModelEntries(IVector<Model::NewTabMenuEntry> settingsModelEntries)
|
||||
{
|
||||
auto result = single_threaded_observable_vector<Editor::NewTabMenuEntryViewModel>();
|
||||
for (const auto& entry : settingsModelEntries)
|
||||
{
|
||||
switch (entry.Type())
|
||||
{
|
||||
case NewTabMenuEntryType::Profile:
|
||||
{
|
||||
// If the Profile isn't set, this is an invalid entry. Skip it.
|
||||
if (const auto& profileEntry = entry.as<Model::ProfileEntry>(); profileEntry.Profile())
|
||||
{
|
||||
const auto profileEntryVM = make<ProfileEntryViewModel>(profileEntry);
|
||||
result.Append(profileEntryVM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::Separator:
|
||||
{
|
||||
if (const auto& separatorEntry = entry.as<Model::SeparatorEntry>())
|
||||
{
|
||||
const auto separatorEntryVM = make<SeparatorEntryViewModel>(separatorEntry);
|
||||
result.Append(separatorEntryVM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::Folder:
|
||||
{
|
||||
if (const auto& folderEntry = entry.as<Model::FolderEntry>())
|
||||
{
|
||||
const auto folderEntryVM = make<FolderEntryViewModel>(folderEntry);
|
||||
result.Append(folderEntryVM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::MatchProfiles:
|
||||
{
|
||||
if (const auto& matchProfilesEntry = entry.as<Model::MatchProfilesEntry>())
|
||||
{
|
||||
const auto matchProfilesEntryVM = make<MatchProfilesEntryViewModel>(matchProfilesEntry);
|
||||
result.Append(matchProfilesEntryVM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
{
|
||||
if (const auto& remainingProfilesEntry = entry.as<Model::RemainingProfilesEntry>())
|
||||
{
|
||||
const auto remainingProfilesEntryVM = make<RemainingProfilesEntryViewModel>(remainingProfilesEntry);
|
||||
result.Append(remainingProfilesEntryVM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::Invalid:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NewTabMenuViewModel::IsRemainingProfilesEntryMissing(const IObservableVector<Editor::NewTabMenuEntryViewModel>& entries)
|
||||
{
|
||||
for (const auto& entry : entries)
|
||||
{
|
||||
switch (entry.Type())
|
||||
{
|
||||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case NewTabMenuEntryType::Folder:
|
||||
{
|
||||
if (!IsRemainingProfilesEntryMissing(entry.as<Editor::FolderEntryViewModel>().Entries()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
NewTabMenuViewModel::NewTabMenuViewModel(Model::CascadiaSettings settings)
|
||||
{
|
||||
UpdateSettings(settings);
|
||||
|
||||
// Add a property changed handler to our own property changed event.
|
||||
// This propagates changes from the settings model to anybody listening to our
|
||||
// unique view model members.
|
||||
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
||||
const auto viewModelProperty{ args.PropertyName() };
|
||||
if (viewModelProperty == L"AvailableProfiles")
|
||||
{
|
||||
_NotifyChanges(L"SelectedProfile");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::UpdateSettings(Model::CascadiaSettings settings)
|
||||
{
|
||||
_Settings = settings;
|
||||
_NotifyChanges(L"AvailableProfiles");
|
||||
|
||||
const auto& newTabMenuEntries = _Settings.GlobalSettings().NewTabMenu();
|
||||
Entries(_ConvertToViewModelEntries(newTabMenuEntries));
|
||||
|
||||
SelectedProfile(AvailableProfiles().GetAt(0));
|
||||
|
||||
_Entries.VectorChanged([this](auto&&, const IVectorChangedEventArgs& args) {
|
||||
switch (args.CollectionChange())
|
||||
{
|
||||
case CollectionChange::Reset:
|
||||
{
|
||||
// fully replace settings model with _Entries
|
||||
for (const auto& entry : _Entries)
|
||||
{
|
||||
auto modelEntries = single_threaded_vector<Model::NewTabMenuEntry>();
|
||||
modelEntries.Append(NewTabMenuEntryViewModel::GetModel(entry));
|
||||
|
||||
_Settings.GlobalSettings().NewTabMenu(modelEntries);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case CollectionChange::ItemInserted:
|
||||
{
|
||||
const auto& insertedEntry = _Entries.GetAt(args.Index());
|
||||
auto newTabMenu = _Settings.GlobalSettings().NewTabMenu();
|
||||
newTabMenu.InsertAt(args.Index(), NewTabMenuEntryViewModel::GetModel(insertedEntry));
|
||||
return;
|
||||
}
|
||||
case CollectionChange::ItemRemoved:
|
||||
{
|
||||
auto newTabMenu = _Settings.GlobalSettings().NewTabMenu();
|
||||
newTabMenu.RemoveAt(args.Index());
|
||||
return;
|
||||
}
|
||||
case CollectionChange::ItemChanged:
|
||||
{
|
||||
auto newTabMenu = _Settings.GlobalSettings().NewTabMenu();
|
||||
const auto modifiedEntry = _Entries.GetAt(args.Index());
|
||||
newTabMenu.SetAt(args.Index(), NewTabMenuEntryViewModel::GetModel(modifiedEntry));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::RequestAddSelectedProfileEntry()
|
||||
{
|
||||
if (_SelectedProfile)
|
||||
{
|
||||
Model::ProfileEntry profileEntry;
|
||||
profileEntry.Profile(_SelectedProfile);
|
||||
_Settings.GlobalSettings().NewTabMenu().Append(profileEntry);
|
||||
|
||||
_Entries.Append(make<ProfileEntryViewModel>(profileEntry));
|
||||
}
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::RequestAddSeparatorEntry()
|
||||
{
|
||||
Model::SeparatorEntry separatorEntry;
|
||||
_Settings.GlobalSettings().NewTabMenu().Append(separatorEntry);
|
||||
|
||||
_Entries.Append(make<SeparatorEntryViewModel>(separatorEntry));
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::RequestAddFolderEntry()
|
||||
{
|
||||
Model::FolderEntry folderEntry;
|
||||
folderEntry.Name(_FolderName);
|
||||
_Settings.GlobalSettings().NewTabMenu().Append(folderEntry);
|
||||
|
||||
_Entries.Append(make<FolderEntryViewModel>(folderEntry));
|
||||
|
||||
// Clear the field after adding the entry
|
||||
FolderName({});
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::RequestAddProfileMatcherEntry()
|
||||
{
|
||||
Model::MatchProfilesEntry matchProfilesEntry;
|
||||
matchProfilesEntry.Name(_ProfileMatcherName);
|
||||
matchProfilesEntry.Source(_ProfileMatcherSource);
|
||||
matchProfilesEntry.Commandline(_ProfileMatcherCommandline);
|
||||
_Settings.GlobalSettings().NewTabMenu().Append(matchProfilesEntry);
|
||||
|
||||
_Entries.Append(make<MatchProfilesEntryViewModel>(matchProfilesEntry));
|
||||
|
||||
// Clear the fields after adding the entry
|
||||
ProfileMatcherName({});
|
||||
ProfileMatcherSource({});
|
||||
ProfileMatcherCommandline({});
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::RequestAddRemainingProfilesEntry()
|
||||
{
|
||||
Model::RemainingProfilesEntry remainingProfilesEntry;
|
||||
_Settings.GlobalSettings().NewTabMenu().Append(remainingProfilesEntry);
|
||||
|
||||
_Entries.Append(make<RemainingProfilesEntryViewModel>(remainingProfilesEntry));
|
||||
}
|
||||
|
||||
NewTabMenuEntryViewModel::NewTabMenuEntryViewModel(const NewTabMenuEntryType type) noexcept :
|
||||
_Type{ type }
|
||||
{
|
||||
}
|
||||
|
||||
Model::NewTabMenuEntry NewTabMenuEntryViewModel::GetModel(const Editor::NewTabMenuEntryViewModel& viewModel)
|
||||
{
|
||||
switch (viewModel.Type())
|
||||
{
|
||||
case NewTabMenuEntryType::Profile:
|
||||
{
|
||||
const auto& projVM = viewModel.as<Editor::ProfileEntryViewModel>();
|
||||
return get_self<ProfileEntryViewModel>(projVM)->ProfileEntry();
|
||||
}
|
||||
case NewTabMenuEntryType::Separator:
|
||||
{
|
||||
const auto& projVM = viewModel.as<Editor::SeparatorEntryViewModel>();
|
||||
return get_self<SeparatorEntryViewModel>(projVM)->SeparatorEntry();
|
||||
}
|
||||
case NewTabMenuEntryType::Folder:
|
||||
{
|
||||
const auto& projVM = viewModel.as<Editor::FolderEntryViewModel>();
|
||||
return get_self<FolderEntryViewModel>(projVM)->FolderEntry();
|
||||
}
|
||||
case NewTabMenuEntryType::MatchProfiles:
|
||||
{
|
||||
const auto& projVM = viewModel.as<Editor::MatchProfilesEntryViewModel>();
|
||||
return get_self<MatchProfilesEntryViewModel>(projVM)->MatchProfilesEntry();
|
||||
}
|
||||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
{
|
||||
const auto& projVM = viewModel.as<Editor::RemainingProfilesEntryViewModel>();
|
||||
return get_self<RemainingProfilesEntryViewModel>(projVM)->RemainingProfilesEntry();
|
||||
}
|
||||
case NewTabMenuEntryType::Invalid:
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ProfileEntryViewModel::ProfileEntryViewModel(Model::ProfileEntry profileEntry) :
|
||||
ProfileEntryViewModelT<ProfileEntryViewModel, NewTabMenuEntryViewModel>(Model::NewTabMenuEntryType::Profile),
|
||||
_ProfileEntry{ profileEntry }
|
||||
{
|
||||
}
|
||||
|
||||
SeparatorEntryViewModel::SeparatorEntryViewModel(Model::SeparatorEntry separatorEntry) :
|
||||
SeparatorEntryViewModelT<SeparatorEntryViewModel, NewTabMenuEntryViewModel>(Model::NewTabMenuEntryType::Separator),
|
||||
_SeparatorEntry{ separatorEntry }
|
||||
{
|
||||
}
|
||||
|
||||
FolderEntryViewModel::FolderEntryViewModel(Model::FolderEntry folderEntry) :
|
||||
FolderEntryViewModelT<FolderEntryViewModel, NewTabMenuEntryViewModel>(Model::NewTabMenuEntryType::Folder),
|
||||
_FolderEntry{ folderEntry }
|
||||
{
|
||||
_Entries = _ConvertToViewModelEntries(_FolderEntry.Entries());
|
||||
}
|
||||
|
||||
MatchProfilesEntryViewModel::MatchProfilesEntryViewModel(Model::MatchProfilesEntry matchProfilesEntry) :
|
||||
MatchProfilesEntryViewModelT<MatchProfilesEntryViewModel, NewTabMenuEntryViewModel>(Model::NewTabMenuEntryType::MatchProfiles),
|
||||
_MatchProfilesEntry{ matchProfilesEntry }
|
||||
{
|
||||
}
|
||||
|
||||
hstring MatchProfilesEntryViewModel::DisplayText() const
|
||||
{
|
||||
std::wstringstream ss;
|
||||
if (const auto profileName = _MatchProfilesEntry.Name(); !profileName.empty())
|
||||
{
|
||||
ss << fmt::format(L"profile: {}, ", profileName);
|
||||
}
|
||||
if (const auto commandline = _MatchProfilesEntry.Commandline(); !commandline.empty())
|
||||
{
|
||||
ss << fmt::format(L"profile: {}, ", commandline);
|
||||
}
|
||||
if (const auto source = _MatchProfilesEntry.Source(); !source.empty())
|
||||
{
|
||||
ss << fmt::format(L"profile: {}, ", source);
|
||||
}
|
||||
|
||||
// Chop off the last ", "
|
||||
auto s = ss.str();
|
||||
return winrt::hstring{ s.substr(0, s.size() - 2) };
|
||||
}
|
||||
|
||||
RemainingProfilesEntryViewModel::RemainingProfilesEntryViewModel(Model::RemainingProfilesEntry remainingProfilesEntry) :
|
||||
RemainingProfilesEntryViewModelT<RemainingProfilesEntryViewModel, NewTabMenuEntryViewModel>(Model::NewTabMenuEntryType::RemainingProfiles),
|
||||
_RemainingProfilesEntry{ remainingProfilesEntry }
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NewTabMenuViewModel.g.h"
|
||||
#include "NewTabMenuEntryViewModel.g.h"
|
||||
#include "ProfileEntryViewModel.g.h"
|
||||
#include "SeparatorEntryViewModel.g.h"
|
||||
#include "FolderEntryViewModel.g.h"
|
||||
#include "MatchProfilesEntryViewModel.g.h"
|
||||
#include "RemainingProfilesEntryViewModel.g.h"
|
||||
|
||||
#include "ProfileViewModel.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct NewTabMenuViewModel : NewTabMenuViewModelT<NewTabMenuViewModel>, ViewModelHelper<NewTabMenuViewModel>
|
||||
{
|
||||
public:
|
||||
NewTabMenuViewModel(Model::CascadiaSettings settings);
|
||||
|
||||
static bool IsRemainingProfilesEntryMissing(const Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel>& entries);
|
||||
|
||||
void UpdateSettings(Model::CascadiaSettings settings);
|
||||
|
||||
void RequestAddSelectedProfileEntry();
|
||||
void RequestAddSeparatorEntry();
|
||||
void RequestAddFolderEntry();
|
||||
void RequestAddProfileMatcherEntry();
|
||||
void RequestAddRemainingProfilesEntry();
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Model::Profile> AvailableProfiles() { return _Settings.AllProfiles(); }
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel>, Entries);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::Profile, SelectedProfile, nullptr);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, ProfileMatcherName);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, ProfileMatcherSource);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, ProfileMatcherCommandline);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, FolderName);
|
||||
|
||||
private:
|
||||
Model::CascadiaSettings _Settings{ nullptr };
|
||||
};
|
||||
|
||||
struct NewTabMenuEntryViewModel : NewTabMenuEntryViewModelT<NewTabMenuEntryViewModel>, ViewModelHelper<NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
static Model::NewTabMenuEntry GetModel(const Editor::NewTabMenuEntryViewModel& viewModel);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::NewTabMenuEntryType, Type, Model::NewTabMenuEntryType::Invalid);
|
||||
|
||||
protected:
|
||||
explicit NewTabMenuEntryViewModel(const Model::NewTabMenuEntryType type) noexcept;
|
||||
};
|
||||
|
||||
struct ProfileEntryViewModel : ProfileEntryViewModelT<ProfileEntryViewModel, NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
ProfileEntryViewModel(Model::ProfileEntry profileEntry);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::ProfileEntry, ProfileEntry, nullptr);
|
||||
};
|
||||
|
||||
struct SeparatorEntryViewModel : SeparatorEntryViewModelT<SeparatorEntryViewModel, NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
SeparatorEntryViewModel(Model::SeparatorEntry separatorEntry);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::SeparatorEntry, SeparatorEntry, nullptr);
|
||||
};
|
||||
|
||||
struct FolderEntryViewModel : FolderEntryViewModelT<FolderEntryViewModel, NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
FolderEntryViewModel(Model::FolderEntry folderEntry);
|
||||
|
||||
GETSET_OBSERVABLE_PROJECTED_SETTING(_FolderEntry, Name);
|
||||
GETSET_OBSERVABLE_PROJECTED_SETTING(_FolderEntry, Icon);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel>, Entries);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::FolderEntry, FolderEntry, nullptr);
|
||||
};
|
||||
|
||||
struct MatchProfilesEntryViewModel : MatchProfilesEntryViewModelT<MatchProfilesEntryViewModel, NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
MatchProfilesEntryViewModel(Model::MatchProfilesEntry matchProfilesEntry);
|
||||
|
||||
hstring DisplayText() const;
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::MatchProfilesEntry, MatchProfilesEntry, nullptr);
|
||||
};
|
||||
|
||||
struct RemainingProfilesEntryViewModel : RemainingProfilesEntryViewModelT<RemainingProfilesEntryViewModel, NewTabMenuEntryViewModel>
|
||||
{
|
||||
public:
|
||||
RemainingProfilesEntryViewModel(Model::RemainingProfilesEntry remainingProfielsEntry);
|
||||
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Model::RemainingProfilesEntry, RemainingProfilesEntry, nullptr);
|
||||
};
|
||||
};
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(NewTabMenuViewModel);
|
||||
BASIC_FACTORY(ProfileEntryViewModel);
|
||||
BASIC_FACTORY(SeparatorEntryViewModel);
|
||||
BASIC_FACTORY(FolderEntryViewModel);
|
||||
BASIC_FACTORY(MatchProfilesEntryViewModel);
|
||||
BASIC_FACTORY(RemainingProfilesEntryViewModel);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "ProfileViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass NewTabMenuViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
NewTabMenuViewModel(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
|
||||
|
||||
IObservableVector<NewTabMenuEntryViewModel> Entries;
|
||||
IObservableVector<Microsoft.Terminal.Settings.Model.Profile> AvailableProfiles { get; };
|
||||
Microsoft.Terminal.Settings.Model.Profile SelectedProfile;
|
||||
|
||||
String ProfileMatcherName;
|
||||
String ProfileMatcherSource;
|
||||
String ProfileMatcherCommandline;
|
||||
|
||||
String FolderName;
|
||||
|
||||
void RequestAddSelectedProfileEntry();
|
||||
void RequestAddSeparatorEntry();
|
||||
void RequestAddFolderEntry();
|
||||
void RequestAddProfileMatcherEntry();
|
||||
void RequestAddRemainingProfilesEntry();
|
||||
|
||||
static Boolean IsRemainingProfilesEntryMissing(IObservableVector<NewTabMenuEntryViewModel> entries);
|
||||
}
|
||||
|
||||
[default_interface] unsealed runtimeclass NewTabMenuEntryViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
Microsoft.Terminal.Settings.Model.NewTabMenuEntryType Type;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass ProfileEntryViewModel : Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel
|
||||
{
|
||||
ProfileEntryViewModel(Microsoft.Terminal.Settings.Model.ProfileEntry profileEntry);
|
||||
|
||||
Microsoft.Terminal.Settings.Model.ProfileEntry ProfileEntry { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass SeparatorEntryViewModel : Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel
|
||||
{
|
||||
SeparatorEntryViewModel(Microsoft.Terminal.Settings.Model.SeparatorEntry separatorEntry);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass FolderEntryViewModel : Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel
|
||||
{
|
||||
FolderEntryViewModel(Microsoft.Terminal.Settings.Model.FolderEntry folderEntry);
|
||||
|
||||
String Name;
|
||||
String Icon;
|
||||
IObservableVector<Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel> Entries;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass MatchProfilesEntryViewModel : Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel
|
||||
{
|
||||
MatchProfilesEntryViewModel(Microsoft.Terminal.Settings.Model.MatchProfilesEntry matchProfilesEntry);
|
||||
|
||||
String DisplayText { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass RemainingProfilesEntryViewModel : Microsoft.Terminal.Settings.Editor.NewTabMenuEntryViewModel
|
||||
{
|
||||
RemainingProfilesEntryViewModel(Microsoft.Terminal.Settings.Model.RemainingProfilesEntry remainingProfilesEntry);
|
||||
}
|
||||
}
|
|
@ -1839,4 +1839,72 @@
|
|||
<value>Non-monospace fonts:</value>
|
||||
<comment>This is a label that is followed by a list of proportional fonts.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace_ProportionalFontWarning.Title" xml:space="preserve">
|
||||
<value>Warning:</value>
|
||||
<comment>Title for the warning info bar used when a non monospace font face is chosen to indicate that there may be visual artifacts</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace_ProportionalFontWarning.Message" xml:space="preserve">
|
||||
<value>Choosing a non-monospaced font will likely result in visual artifacts. Use at your own discretion.</value>
|
||||
<comment>Warning info bar used when a non monospace font face is chosen to indicate that there may be visual artifacts</comment>
|
||||
</data>
|
||||
<data name="Nav_NewTabMenu.Content" xml:space="preserve">
|
||||
<value>New Tab Menu</value>
|
||||
<comment>Header for the "new tab menu" menu item. This navigates to a page that lets you see and modify settings related to the app's new tab menu (i.e. profile ordering, nested folders, dividers, etc.)</comment>
|
||||
</data>
|
||||
<data name="NewTabMenuEntry_Separator.Content" xml:space="preserve">
|
||||
<value><Separator></value>
|
||||
<comment>{Locked="<"}, {Locked=">"}</comment>
|
||||
</data>
|
||||
<data name="NewTabMenuEntry_RemainingProfiles.Content" xml:space="preserve">
|
||||
<value><Remaining profiles></value>
|
||||
<comment>{Locked="<"}{Locked=">"}</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddProfile.Header" xml:space="preserve">
|
||||
<value>Profile</value>
|
||||
<comment>Header for a control that adds a terminal profile to the new tab menu.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles.Header" xml:space="preserve">
|
||||
<value>Profile matcher</value>
|
||||
<comment>Header for a control that adds a terminal profile matcher to the new tab menu. This entry adds profiles that match the given parameters.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddRemainingProfiles.Header" xml:space="preserve">
|
||||
<value>Remaining profiles</value>
|
||||
<comment>Header for a control that adds any remaining profiles to the new tab menu.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles.HelpText" xml:space="preserve">
|
||||
<value>Add a group of profiles that match at least one of the defined properties</value>
|
||||
<comment>Additional information for a control that adds a terminal profile matcher to the new tab menu. Presented near "NewTabMenu_AddMatchProfiles".</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddRemainingProfiles.HelpText" xml:space="preserve">
|
||||
<value>There can only be one "remaining profiles" entry</value>
|
||||
<comment>Additional information for a control that adds any remaining profiles to the new tab menu. Presented near "NewTabMenu_AddRemainingProfiles".</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddSeparator.Header" xml:space="preserve">
|
||||
<value>Separator</value>
|
||||
<comment>Header for a control that adds a separator to the new tab menu.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddFolder.Header" xml:space="preserve">
|
||||
<value>Folder</value>
|
||||
<comment>Header for a control that adds a folder to the new tab menu.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles_Name.Header" xml:space="preserve">
|
||||
<value>Profile name</value>
|
||||
<comment>Header for a text box used to define a regex for the names of profiles to add.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles_Source.Header" xml:space="preserve">
|
||||
<value>Profile source</value>
|
||||
<comment>Header for a text box used to define a regex for the sources of profiles to add.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles_Commandline.Header" xml:space="preserve">
|
||||
<value>Commandline</value>
|
||||
<comment>Header for a text box used to define a regex for the commandlines of profiles to add.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddMatchProfiles_Confirmation.Text" xml:space="preserve">
|
||||
<value>Add profile matcher</value>
|
||||
<comment>Label for a button confirming to add the profile matcher to the new tab menu as an entry.</comment>
|
||||
</data>
|
||||
<data name="NewTabMenu_AddFolder_FolderName.PlaceholderText" xml:space="preserve">
|
||||
<value>Folder name</value>
|
||||
<comment>Placeholder text for a text box control used to set the name of the folder.</comment>
|
||||
</data>
|
||||
</root>
|
|
@ -12,6 +12,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
{
|
||||
DependencyProperty SettingContainer::_HeaderProperty{ nullptr };
|
||||
DependencyProperty SettingContainer::_HelpTextProperty{ nullptr };
|
||||
DependencyProperty SettingContainer::_FontIconGlyphProperty{ nullptr };
|
||||
DependencyProperty SettingContainer::_CurrentValueProperty{ nullptr };
|
||||
DependencyProperty SettingContainer::_HasSettingValueProperty{ nullptr };
|
||||
DependencyProperty SettingContainer::_SettingOverrideSourceProperty{ nullptr };
|
||||
|
@ -45,6 +46,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
xaml_typename<Editor::SettingContainer>(),
|
||||
PropertyMetadata{ box_value(L"") });
|
||||
}
|
||||
if (!_FontIconGlyphProperty)
|
||||
{
|
||||
_FontIconGlyphProperty =
|
||||
DependencyProperty::Register(
|
||||
L"FontIconGlyph",
|
||||
xaml_typename<hstring>(),
|
||||
xaml_typename<Editor::SettingContainer>(),
|
||||
PropertyMetadata{ box_value(L"") });
|
||||
}
|
||||
if (!_CurrentValueProperty)
|
||||
{
|
||||
_CurrentValueProperty =
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
|
||||
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Header);
|
||||
DEPENDENCY_PROPERTY(hstring, HelpText);
|
||||
DEPENDENCY_PROPERTY(hstring, FontIconGlyph);
|
||||
DEPENDENCY_PROPERTY(hstring, CurrentValue);
|
||||
DEPENDENCY_PROPERTY(bool, HasSettingValue);
|
||||
DEPENDENCY_PROPERTY(bool, StartExpanded);
|
||||
|
|
|
@ -15,6 +15,9 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
String HelpText;
|
||||
static Windows.UI.Xaml.DependencyProperty HelpTextProperty { get; };
|
||||
|
||||
String FontIconGlyph;
|
||||
static Windows.UI.Xaml.DependencyProperty FontIconGlyphProperty { get; };
|
||||
|
||||
String CurrentValue;
|
||||
static Windows.UI.Xaml.DependencyProperty CurrentValueProperty { get; };
|
||||
|
||||
|
|
|
@ -180,10 +180,15 @@
|
|||
<Grid AutomationProperties.Name="{TemplateBinding Header}"
|
||||
Style="{StaticResource NonExpanderGrid}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Style="{StaticResource StackPanelInExpanderStyle}">
|
||||
<FontIcon Grid.Column="0"
|
||||
Glyph="{TemplateBinding FontIconGlyph}"
|
||||
Margin="0,0,10,0"/>
|
||||
<StackPanel Grid.Column="1"
|
||||
Style="{StaticResource StackPanelInExpanderStyle}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
|
||||
Text="{TemplateBinding Header}" />
|
||||
|
@ -197,7 +202,7 @@
|
|||
Style="{StaticResource SettingsPageItemDescriptionStyle}"
|
||||
Text="{TemplateBinding HelpText}" />
|
||||
</StackPanel>
|
||||
<ContentPresenter Grid.Column="1"
|
||||
<ContentPresenter Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Content}" />
|
||||
|
@ -224,10 +229,15 @@
|
|||
<muxc:Expander.Header>
|
||||
<Grid MinHeight="64">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Style="{StaticResource StackPanelInExpanderStyle}">
|
||||
<FontIcon Grid.Column="0"
|
||||
Glyph="{TemplateBinding FontIconGlyph}"
|
||||
Margin="0,0,10,0"/>
|
||||
<StackPanel Grid.Column="1"
|
||||
Style="{StaticResource StackPanelInExpanderStyle}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
|
||||
Text="{TemplateBinding Header}" />
|
||||
|
@ -241,7 +251,7 @@
|
|||
Style="{StaticResource SettingsPageItemDescriptionStyle}"
|
||||
Text="{TemplateBinding HelpText}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1"
|
||||
<TextBlock Grid.Column="2"
|
||||
MaxWidth="250"
|
||||
Margin="0,0,-16,0"
|
||||
HorizontalAlignment="Right"
|
||||
|
|
|
@ -37,7 +37,7 @@ protected:
|
|||
winrt::event<::winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> _propertyChangedHandlers;
|
||||
};
|
||||
|
||||
#define _BASE_OBSERVABLE_PROJECTED_SETTING(target, name) \
|
||||
#define GETSET_OBSERVABLE_PROJECTED_SETTING(target, name) \
|
||||
public: \
|
||||
auto name() const \
|
||||
{ \
|
||||
|
@ -52,7 +52,10 @@ public: \
|
|||
t.name(value); \
|
||||
_NotifyChanges(L"Has" #name, L## #name); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define _BASE_OBSERVABLE_PROJECTED_SETTING(target, name) \
|
||||
GETSET_OBSERVABLE_PROJECTED_SETTING(target, name) \
|
||||
bool Has##name() const \
|
||||
{ \
|
||||
return target.Has##name(); \
|
||||
|
|
|
@ -34,3 +34,10 @@ winrt::com_ptr<NewTabMenuEntry> ActionEntry::FromJson(const Json::Value& json)
|
|||
|
||||
return entry;
|
||||
}
|
||||
|
||||
winrt::com_ptr<ActionEntry> ActionEntry::Copy() const
|
||||
{
|
||||
auto entry = winrt::make_self<ActionEntry>();
|
||||
entry->_ActionId = _ActionId;
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
public:
|
||||
ActionEntry() noexcept;
|
||||
|
||||
winrt::com_ptr<ActionEntry> Copy() const;
|
||||
|
||||
Json::Value ToJson() const override;
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "FolderEntry.h"
|
||||
#include "ProfileEntry.h"
|
||||
#include "SeparatorEntry.h"
|
||||
#include "RemainingProfilesEntry.h"
|
||||
#include "MatchProfilesEntry.h"
|
||||
#include "ActionEntry.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "TerminalSettingsSerializationHelpers.h"
|
||||
|
||||
|
@ -83,7 +88,7 @@ IVector<NewTabMenuEntryModel> FolderEntry::Entries() const
|
|||
// A profile is filtered out if it is not valid, so if it was not resolved
|
||||
case NewTabMenuEntryType::Profile:
|
||||
{
|
||||
const auto profileEntry = entry.as<ProfileEntry>();
|
||||
const auto profileEntry = entry.as<Model::ProfileEntry>();
|
||||
if (profileEntry.Profile() == nullptr)
|
||||
{
|
||||
continue;
|
||||
|
@ -95,7 +100,7 @@ IVector<NewTabMenuEntryModel> FolderEntry::Entries() const
|
|||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
case NewTabMenuEntryType::MatchProfiles:
|
||||
{
|
||||
const auto profileCollectionEntry = entry.as<ProfileCollectionEntry>();
|
||||
const auto profileCollectionEntry = entry.as<Model::ProfileCollectionEntry>();
|
||||
if (profileCollectionEntry.Profiles().Size() == 0)
|
||||
{
|
||||
continue;
|
||||
|
@ -122,3 +127,47 @@ IVector<NewTabMenuEntryModel> FolderEntry::Entries() const
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
winrt::com_ptr<FolderEntry> FolderEntry::Copy() const
|
||||
{
|
||||
auto entry = winrt::make_self<FolderEntry>();
|
||||
entry->_Name = _Name;
|
||||
entry->_Icon = _Icon;
|
||||
entry->_Inlining = _Inlining;
|
||||
entry->_AllowEmpty = _AllowEmpty;
|
||||
|
||||
if (_Entries)
|
||||
{
|
||||
entry->_Entries = winrt::single_threaded_vector<Model::NewTabMenuEntry>();
|
||||
for (const auto& e : _Entries)
|
||||
{
|
||||
switch (e.Type())
|
||||
{
|
||||
case NewTabMenuEntryType::Profile:
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::ProfileEntry>(e.as<Model::ProfileEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Separator:
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::SeparatorEntry>(e.as<Model::SeparatorEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Folder:
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::FolderEntry>(e.as<Model::FolderEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::RemainingProfilesEntry>(e.as<Model::RemainingProfilesEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::MatchProfiles:
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::MatchProfilesEntry>(e.as<Model::MatchProfilesEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Action:
|
||||
{
|
||||
entry->_Entries.Append(*winrt::get_self<implementation::ActionEntry>(e.as<Model::ActionEntry>())->Copy());
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::Invalid:
|
||||
// ignore invalid
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
FolderEntry() noexcept;
|
||||
explicit FolderEntry(const winrt::hstring& name) noexcept;
|
||||
|
||||
winrt::com_ptr<FolderEntry> Copy() const;
|
||||
|
||||
Json::Value ToJson() const override;
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
#include "../../types/inc/Utils.hpp"
|
||||
#include "JsonUtils.h"
|
||||
#include "KeyChordSerialization.h"
|
||||
#include "FolderEntry.h"
|
||||
#include "ProfileEntry.h"
|
||||
#include "SeparatorEntry.h"
|
||||
#include "RemainingProfilesEntry.h"
|
||||
#include "MatchProfilesEntry.h"
|
||||
#include "ActionEntry.h"
|
||||
|
||||
#include "GlobalAppSettings.g.cpp"
|
||||
|
||||
|
@ -79,6 +85,39 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
|||
globals->_themes.Insert(kv.Key(), *themeImpl->Copy());
|
||||
}
|
||||
}
|
||||
if (_NewTabMenu)
|
||||
{
|
||||
globals->_NewTabMenu = winrt::single_threaded_vector<Model::NewTabMenuEntry>();
|
||||
for (auto entry : *_NewTabMenu)
|
||||
{
|
||||
switch (entry.Type())
|
||||
{
|
||||
case NewTabMenuEntryType::Profile:
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<ProfileEntry>(entry.as<Model::ProfileEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Separator:
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<SeparatorEntry>(entry.as<Model::SeparatorEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Folder:
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<FolderEntry>(entry.as<Model::FolderEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::RemainingProfiles:
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<RemainingProfilesEntry>(entry.as<Model::RemainingProfilesEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::MatchProfiles:
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<MatchProfilesEntry>(entry.as<Model::MatchProfilesEntry>())->Copy());
|
||||
break;
|
||||
case NewTabMenuEntryType::Action:
|
||||
{
|
||||
globals->_NewTabMenu->Append(*winrt::get_self<ActionEntry>(entry.as<Model::ActionEntry>())->Copy());
|
||||
break;
|
||||
}
|
||||
case NewTabMenuEntryType::Invalid:
|
||||
// ignore invalid
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& parent : _parents)
|
||||
{
|
||||
|
|
|
@ -71,3 +71,12 @@ bool MatchProfilesEntry::MatchesProfile(const Model::Profile& profile)
|
|||
|
||||
return isMatching.value_or(false);
|
||||
}
|
||||
|
||||
winrt::com_ptr<MatchProfilesEntry> MatchProfilesEntry::Copy() const
|
||||
{
|
||||
auto entry = winrt::make_self<MatchProfilesEntry>();
|
||||
entry->_Name = _Name;
|
||||
entry->_Commandline = _Commandline;
|
||||
entry->_Source = _Source;
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
public:
|
||||
MatchProfilesEntry() noexcept;
|
||||
|
||||
winrt::com_ptr<MatchProfilesEntry> Copy() const;
|
||||
|
||||
Json::Value ToJson() const override;
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
|
||||
|
|
|
@ -57,3 +57,12 @@ winrt::com_ptr<NewTabMenuEntry> ProfileEntry::FromJson(const Json::Value& json)
|
|||
|
||||
return entry;
|
||||
}
|
||||
|
||||
winrt::com_ptr<ProfileEntry> ProfileEntry::Copy() const
|
||||
{
|
||||
auto entry{ winrt::make_self<ProfileEntry>() };
|
||||
entry->_Profile = _Profile;
|
||||
entry->_ProfileIndex = _ProfileIndex;
|
||||
entry->_ProfileName = _ProfileName;
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
ProfileEntry() noexcept;
|
||||
explicit ProfileEntry(const winrt::hstring& profile) noexcept;
|
||||
|
||||
winrt::com_ptr<ProfileEntry> Copy() const;
|
||||
|
||||
Json::Value ToJson() const override;
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
|
||||
|
|
|
@ -20,3 +20,9 @@ winrt::com_ptr<NewTabMenuEntry> RemainingProfilesEntry::FromJson(const Json::Val
|
|||
{
|
||||
return winrt::make_self<RemainingProfilesEntry>();
|
||||
}
|
||||
|
||||
winrt::com_ptr<RemainingProfilesEntry> RemainingProfilesEntry::Copy() const
|
||||
{
|
||||
auto entry = winrt::make_self<RemainingProfilesEntry>();
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
public:
|
||||
RemainingProfilesEntry() noexcept;
|
||||
|
||||
winrt::com_ptr<RemainingProfilesEntry> Copy() const;
|
||||
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,3 +19,8 @@ winrt::com_ptr<NewTabMenuEntry> SeparatorEntry::FromJson(const Json::Value&)
|
|||
{
|
||||
return winrt::make_self<SeparatorEntry>();
|
||||
}
|
||||
|
||||
winrt::com_ptr<SeparatorEntry> SeparatorEntry::Copy() const
|
||||
{
|
||||
return winrt::make_self<SeparatorEntry>();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
public:
|
||||
SeparatorEntry() noexcept;
|
||||
|
||||
winrt::com_ptr<SeparatorEntry> Copy() const;
|
||||
|
||||
static com_ptr<NewTabMenuEntry> FromJson(const Json::Value& json);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue