Skip to content

Commit

Permalink
Add Extensions page to Settings UI
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-zamora committed Jan 17, 2025
1 parent 8598ed7 commit 0ba01cc
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 4 deletions.
125 changes: 125 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Extensions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "Extensions.h"
#include "Extensions.g.cpp"
#include "ExtensionsViewModel.g.cpp"

#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"

using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Extensions::Extensions()
{
InitializeComponent();
}

void Extensions::OnNavigatedTo(const NavigationEventArgs& e)
{
_ViewModel = e.Parameter().as<Editor::ExtensionsViewModel>();
}

void Extensions::ExtensionLoaded(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
const auto& toggleSwitch = sender.as<Controls::ToggleSwitch>();
const auto& extensionSource = toggleSwitch.Tag().as<hstring>();
toggleSwitch.IsOn(_ViewModel.GetExtensionState(extensionSource));
}

void Extensions::ExtensionToggled(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
const auto& toggleSwitch = sender.as<Controls::ToggleSwitch>();
const auto& extensionSource = toggleSwitch.Tag().as<hstring>();
_ViewModel.SetExtensionState(extensionSource, toggleSwitch.IsOn());
}

ExtensionsViewModel::ExtensionsViewModel(const Model::CascadiaSettings& settings) :
_settings{ settings }
{
std::vector<IInspectable> fragmentExtensions;
fragmentExtensions.reserve(settings.FragmentExtensions().Size());

std::vector<IInspectable> profilesModified;
std::vector<IInspectable> profilesAdded;
std::vector<IInspectable> colorSchemesAdded;
for (const auto&& fragExt : settings.FragmentExtensions())
{
fragmentExtensions.push_back(fragExt);

for (const auto&& profile : fragExt.ModifiedProfilesView())
{
profilesModified.push_back(profile);
}

for (const auto&& profile : fragExt.NewProfilesView())
{
profilesAdded.push_back(profile);
}

for (const auto&& scheme : fragExt.ColorSchemesView())
{
colorSchemesAdded.push_back(scheme);
}
}

_fragmentExtensions = single_threaded_observable_vector<IInspectable>(std::move(fragmentExtensions));
_profilesModified = single_threaded_observable_vector<IInspectable>(std::move(profilesModified));
_profilesAdded = single_threaded_observable_vector<IInspectable>(std::move(profilesAdded));
_colorSchemesAdded = single_threaded_observable_vector<IInspectable>(std::move(colorSchemesAdded));
}

// Returns true if the extension is enabled, false otherwise
bool ExtensionsViewModel::GetExtensionState(hstring extensionSource) const
{
if (const auto& disabledExtensions = _DisabledProfileSources())
{
uint32_t ignored;
return !disabledExtensions.IndexOf(extensionSource, ignored);
}
// "disabledProfileSources" not defined --> all extensions are enabled
return true;
}

// Enable/Disable an extension
void ExtensionsViewModel::SetExtensionState(hstring extensionSource, bool enableExt)
{
// get the current status of the extension
uint32_t idx;
bool currentlyEnabled = true;
const auto& disabledExtensions = _DisabledProfileSources();
if (disabledExtensions)
{
currentlyEnabled = !disabledExtensions.IndexOf(extensionSource, idx);
}

// current status mismatches the desired status,
// update the list of disabled extensions
if (currentlyEnabled != enableExt)
{
// If we're disabling an extension and we don't have "disabledProfileSources" defined,
// create it in the model directly
if (!disabledExtensions && !enableExt)
{
std::vector<hstring> disabledProfileSources{ extensionSource };
_settings.GlobalSettings().DisabledProfileSources(single_threaded_vector<hstring>(std::move(disabledProfileSources)));
return;
}

// Update the list of disabled extensions
if (enableExt)
{
disabledExtensions.RemoveAt(idx);
}
else
{
disabledExtensions.Append(extensionSource);
}
}
}
}
54 changes: 54 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Extensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

#include "Extensions.g.h"
#include "ExtensionsViewModel.g.h"
#include "ViewModelHelpers.h"
#include "Utils.h"

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Extensions : public HasScrollViewer<Extensions>, ExtensionsT<Extensions>
{
public:
Extensions();

void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void ExtensionLoaded(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
void ExtensionToggled(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);

WINRT_PROPERTY(Editor::ExtensionsViewModel, ViewModel, nullptr);
};

struct ExtensionsViewModel : ExtensionsViewModelT<ExtensionsViewModel>, ViewModelHelper<ExtensionsViewModel>
{
public:
ExtensionsViewModel(const Model::CascadiaSettings& settings);

// Views
Windows::Foundation::Collections::IVectorView<IInspectable> FragmentExtensions() const noexcept { return _fragmentExtensions.GetView(); }
Windows::Foundation::Collections::IVectorView<IInspectable> ProfilesModified() const noexcept { return _profilesModified.GetView(); }
Windows::Foundation::Collections::IVectorView<IInspectable> ProfilesAdded() const noexcept { return _profilesAdded.GetView(); }
Windows::Foundation::Collections::IVectorView<IInspectable> ColorSchemesAdded() const noexcept { return _colorSchemesAdded.GetView(); }

bool GetExtensionState(hstring extensionSource) const;
void SetExtensionState(hstring extensionSource, bool enableExt);

private:
Model::CascadiaSettings _settings;
Windows::Foundation::Collections::IVector<IInspectable> _fragmentExtensions;
Windows::Foundation::Collections::IVector<IInspectable> _profilesModified;
Windows::Foundation::Collections::IVector<IInspectable> _profilesAdded;
Windows::Foundation::Collections::IVector<IInspectable> _colorSchemesAdded;

Windows::Foundation::Collections::IVector<hstring> _DisabledProfileSources() const noexcept { return _settings.GlobalSettings().DisabledProfileSources(); }
};
};

namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(Extensions);
BASIC_FACTORY(ExtensionsViewModel);
}
26 changes: 26 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Extensions.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass Extensions : Windows.UI.Xaml.Controls.Page
{
Extensions();
ExtensionsViewModel ViewModel { get; };
}

[default_interface] runtimeclass ExtensionsViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
ExtensionsViewModel(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);

// Views
Windows.Foundation.Collections.IVectorView<IInspectable> FragmentExtensions { get; };
Windows.Foundation.Collections.IVectorView<IInspectable> ProfilesModified { get; };
Windows.Foundation.Collections.IVectorView<IInspectable> ProfilesAdded { get; };
Windows.Foundation.Collections.IVectorView<IInspectable> ColorSchemesAdded { get; };

// Methods
Boolean GetExtensionState(String extensionSource);
void SetExtensionState(String extensionSource, Boolean enableExt);
}
}
75 changes: 75 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Extensions.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!--
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.Extensions"
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}"
Spacing="20">
<StackPanel>
<!-- Grouping: Active Extensions -->
<TextBlock x:Uid="Globals_ActiveExtensionsHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<ItemsControl ItemsSource="{x:Bind ViewModel.FragmentExtensions, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="model:FragmentSettings">
<local:SettingContainer Header="{x:Bind Source}">
<ToggleSwitch Toggled="ExtensionToggled"
Loaded="ExtensionLoaded"
Tag="{x:Bind Source}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingContainer>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

</StackPanel>

<StackPanel>
<!-- Grouping: Modified Profiles -->
<TextBlock x:Uid="Globals_ModifiedProfilesHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<TextBlock FontStyle="Italic">Coming soon!</TextBlock>

<!--TODO CARLOS: ItemsRepeater of Expanders-->

</StackPanel>

<StackPanel>
<!-- Grouping: Added Profiles -->
<TextBlock x:Uid="Globals_AddedProfilesHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<TextBlock FontStyle="Italic">Coming soon!</TextBlock>

<!--TODO CARLOS: ItemsRepeater of Expanders-->

</StackPanel>

<StackPanel>
<!-- Grouping: Added Color Schemes -->
<TextBlock x:Uid="Globals_AddedColorSchemesHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<TextBlock FontStyle="Italic">Coming soon!</TextBlock>

<!--TODO CARLOS: ItemsRepeater of Expanders-->

</StackPanel>
</StackPanel>
</Page>
8 changes: 8 additions & 0 deletions src/cascadia/TerminalSettingsEditor/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Compatibility.h"
#include "Rendering.h"
#include "RenderingViewModel.h"
#include "Extensions.h"
#include "Actions.h"
#include "ProfileViewModel.h"
#include "GlobalAppearance.h"
Expand Down Expand Up @@ -44,6 +45,7 @@ static const std::wstring_view renderingTag{ L"Rendering_Nav" };
static const std::wstring_view compatibilityTag{ L"Compatibility_Nav" };
static const std::wstring_view actionsTag{ L"Actions_Nav" };
static const std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
static const std::wstring_view extensionsTag{ L"Extensions_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" };
Expand Down Expand Up @@ -445,6 +447,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_breadcrumbs.Append(crumb);
}
}
else if (clickedItemTag == extensionsTag)
{
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<ExtensionsViewModel>(_settingsClone));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
}
else if (clickedItemTag == globalProfileTag)
{
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher()) };
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalSettingsEditor/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@
<FontIcon Glyph="&#xE71d;" />
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>

<muxc:NavigationViewItem x:Uid="Nav_Extensions"
Tag="Extensions_Nav">
<muxc:NavigationViewItem.Icon>
<FontIcon Glyph="&#xE74C;" />
<!--Alternative: Puzzle - EA86-->
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>

<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@
<DependentUpon>NewTabMenuViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Extensions.h">
<DependentUpon>Extensions.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="Profiles_Base.h">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down Expand Up @@ -199,6 +203,9 @@
<Page Include="MainPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Extensions.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles_Base.xaml">
<SubType>Designer</SubType>
</Page>
Expand Down Expand Up @@ -309,6 +316,10 @@
<DependentUpon>NewTabMenuViewModel.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Extensions.cpp">
<DependentUpon>Extensions.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="Profiles_Base.cpp">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down Expand Up @@ -408,6 +419,10 @@
<Midl Include="GlobalAppearanceViewModel.idl" />
<Midl Include="LaunchViewModel.idl" />
<Midl Include="NewTabMenuViewModel.idl" />
<Midl Include="Extensions.idl">
<DependentUpon>Extensions.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="Profiles_Base.idl">
<DependentUpon>Profiles_Base.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down
16 changes: 16 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,10 @@
<value>Actions</value>
<comment>Header for the "actions" menu item. This navigates to a page that lets you see and modify commands, key bindings, and actions that can be done in the app.</comment>
</data>
<data name="Nav_Extensions.Content" xml:space="preserve">
<value>Extensions</value>
<comment>Header for the "extensions" menu item. This navigates to a page that lets you see and modify extensions for the app.</comment>
</data>
<data name="Profile_OpacitySlider.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Background opacity</value>
<comment>Name for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque.</comment>
Expand Down Expand Up @@ -2316,4 +2320,16 @@
<data name="Profile_Source_Orphaned.HelpText" xml:space="preserve">
<value>Indicates the software that originally created this profile.</value>
</data>
<data name="Globals_ActiveExtensionsHeader.Text" xml:space="preserve">
<value>Active Extensions</value>
</data>
<data name="Globals_ModifiedProfilesHeader.Text" xml:space="preserve">
<value>Modified Profiles</value>
</data>
<data name="Globals_AddedProfilesHeader.Text" xml:space="preserve">
<value>Added Profiles</value>
</data>
<data name="Globals_AddedColorSchemesHeader.Text" xml:space="preserve">
<value>Added Color Schemes</value>
</data>
</root>
Loading

0 comments on commit 0ba01cc

Please sign in to comment.