Skip to content

Commit

Permalink
Introduce the Terminal Settings Editor (#8048)
Browse files Browse the repository at this point in the history
This commit introduces the terminal settings editor (to wit: the
Settings UI) as a standalone project. This project, and this commit, is
the result of two and a half months of work.

TSE started as a hackathon project in the Microsoft 2020 Hackathon, and
from there it's grown to be a bona-fide graphical settings editor.

There is a lot of xaml data binding in here, a number of views and a
number of view models, and a bunch of paradigms that we've been
reviewing and testing out and designing and refining.

Specified in #6720, #8269
Follow-up work in #6800
Closes #1564
Closes #8048 (PR)

Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
Co-authored-by: Kayla Cinnamon <cinnamon@microsoft.com>
Co-authored-by: Alberto Medina Gutierrez <almedina@microsoft.com>
Co-authored-by: John Grandle <jograndl@microsoft.com>
Co-authored-by: xerootg <xerootg@users.noreply.github.com>
Co-authored-by: Scott <sarmiger1@gmail.com>
Co-authored-by: Vineeth Thomas Alex <vineeththomasalex@gmail.com>
Co-authored-by: Leon Liang <lelian@microsoft.com>
Co-authored-by: Dustin L. Howett <duhowett@microsoft.com>
Signed-off-by: Dustin L. Howett <duhowett@microsoft.com>
  • Loading branch information
9 people committed Dec 11, 2020
1 parent b80a4e4 commit 05f3ccb
Show file tree
Hide file tree
Showing 57 changed files with 4,280 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .github/actions/spell-check/dictionary/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ IInheritable
IMap
IObject
IStorage
ITab
ITaskbar
llabs
LCID
Expand Down Expand Up @@ -63,17 +64,24 @@ semver
serializer
shobjidl
SIZENS
GETDESKWALLPAPER
snprintf
spsc
sregex
STDCPP
strchr
Subheader
Subpage
UPDATEINIFILE
syscall
TBPF
THEMECHANGED
tmp
tolower
tx
UPDATEINIFILE
userenv
wcsstr
wcstoui
wsregex
XDocument
Expand Down
1 change: 1 addition & 0 deletions .github/actions/spell-check/dictionary/microsoft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ LKG
mfcribbon
microsoft
microsoftonline
muxc
netcore
osgvsowi
pgc
Expand Down
48 changes: 48 additions & 0 deletions OpenConsole.sln
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
Expand All @@ -180,6 +181,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
Expand Down Expand Up @@ -233,6 +235,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\casca
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
Expand Down Expand Up @@ -315,6 +318,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Editor", "src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj", "{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model.Lib", "src\cascadia\TerminalSettingsModel\Microsoft.Terminal.Settings.ModelLib.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
ProjectSection(ProjectDependencies) = postProject
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
Expand Down Expand Up @@ -2012,6 +2020,45 @@ Global
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Build.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.Build.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.Build.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.Build.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x64.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x64.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.ActiveCfg = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.Build.0 = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.Deploy.0 = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|Any CPU.ActiveCfg = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|ARM64.ActiveCfg = Debug|ARM64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|ARM64.Build.0 = Debug|ARM64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.ActiveCfg = Debug|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.Build.0 = Debug|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.Deploy.0 = Debug|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.ActiveCfg = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.Build.0 = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.Deploy.0 = Debug|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|Any CPU.ActiveCfg = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|ARM64.ActiveCfg = Release|ARM64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|ARM64.Build.0 = Release|ARM64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.ActiveCfg = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.Build.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.Deploy.0 = Release|x64
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.ActiveCfg = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.Build.0 = Release|Win32
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.Deploy.0 = Release|Win32
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
Expand Down Expand Up @@ -2170,6 +2217,7 @@ Global
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87}
{1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {59840756-302F-44DF-AA47-441A9D673202}
{506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-082C-4476-9F33-94B339494076} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
Expand Down
143 changes: 143 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "ColorSchemes.h"
#include "ColorTableEntry.g.cpp"
#include "ColorSchemes.g.cpp"
#include "ColorSchemesPageNavigationState.g.cpp"

#include <LibraryResources.h>

using namespace winrt;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Media;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
static const std::array<hstring, 16> TableColorNames = {
RS_(L"ColorScheme_Black/Header"),
RS_(L"ColorScheme_Red/Header"),
RS_(L"ColorScheme_Green/Header"),
RS_(L"ColorScheme_Yellow/Header"),
RS_(L"ColorScheme_Blue/Header"),
RS_(L"ColorScheme_Purple/Header"),
RS_(L"ColorScheme_Cyan/Header"),
RS_(L"ColorScheme_White/Header"),
RS_(L"ColorScheme_BrightBlack/Header"),
RS_(L"ColorScheme_BrightRed/Header"),
RS_(L"ColorScheme_BrightGreen/Header"),
RS_(L"ColorScheme_BrightYellow/Header"),
RS_(L"ColorScheme_BrightBlue/Header"),
RS_(L"ColorScheme_BrightPurple/Header"),
RS_(L"ColorScheme_BrightCyan/Header"),
RS_(L"ColorScheme_BrightWhite/Header")
};

ColorSchemes::ColorSchemes() :
_ColorSchemeList{ single_threaded_observable_vector<hstring>() },
_CurrentColorTable{ single_threaded_observable_vector<Editor::ColorTableEntry>() }
{
InitializeComponent();
}

void ColorSchemes::OnNavigatedTo(const NavigationEventArgs& e)
{
_State = e.Parameter().as<Editor::ColorSchemesPageNavigationState>();
_UpdateColorSchemeList();

// Initialize our color table view model with 16 dummy colors
// so that on a ColorScheme selection change, we can loop through
// each ColorTableEntry and just change its color. Performing a
// clear and 16 appends doesn't seem to update the color pickers
// very accurately.
for (uint8_t i = 0; i < TableColorNames.size(); ++i)
{
auto entry = winrt::make<ColorTableEntry>(i, Windows::UI::Color{ 0, 0, 0, 0 });
_CurrentColorTable.Append(entry);
}
}

// Function Description:
// - Called when a different color scheme is selected. Updates our current
// color scheme and updates our currently modifiable color table.
// Arguments:
// - args: The selection changed args that tells us what's the new color scheme selected.
// Return Value:
// - <none>
void ColorSchemes::ColorSchemeSelectionChanged(IInspectable const& /*sender*/,
SelectionChangedEventArgs const& args)
{
// Update the color scheme this page is modifying
auto str = winrt::unbox_value<hstring>(args.AddedItems().GetAt(0));
auto colorScheme = _State.Globals().ColorSchemes().Lookup(str);
CurrentColorScheme(colorScheme);
_UpdateColorTable(colorScheme);
}

// Function Description:
// - Updates the list of all color schemes available to choose from.
// Arguments:
// - <none>
// Return Value:
// - <none>
void ColorSchemes::_UpdateColorSchemeList()
{
// Surprisingly, though this is called every time we navigate to the page,
// the list does not keep growing on each navigation.
const auto& colorSchemeMap{ _State.Globals().ColorSchemes() };
for (const auto& pair : colorSchemeMap)
{
_ColorSchemeList.Append(pair.Key());
}
}

// Function Description:
// - Called when a ColorPicker control has selected a new color. This is specifically
// called by color pickers assigned to a color table entry. It takes the index
// that's been stuffed in the Tag property of the color picker and uses it
// to update the color table accordingly.
// Arguments:
// - sender: the color picker that raised this event.
// - args: the args that contains the new color that was picked.
// Return Value:
// - <none>
void ColorSchemes::ColorPickerChanged(IInspectable const& sender,
ColorChangedEventArgs const& args)
{
if (auto picker = sender.try_as<ColorPicker>())
{
if (auto tag = picker.Tag())
{
auto index = winrt::unbox_value<uint8_t>(tag);
CurrentColorScheme().SetColorTableEntry(index, args.NewColor());
_CurrentColorTable.GetAt(index).Color(args.NewColor());
}
}
}

// Function Description:
// - Updates the currently modifiable color table based on the given current color scheme.
// Arguments:
// - colorScheme: the color scheme to retrieve the color table from
// Return Value:
// - <none>
void ColorSchemes::_UpdateColorTable(const Model::ColorScheme& colorScheme)
{
for (uint8_t i = 0; i < TableColorNames.size(); ++i)
{
_CurrentColorTable.GetAt(i).Color(colorScheme.Table()[i]);
}
}

ColorTableEntry::ColorTableEntry(uint8_t index, Windows::UI::Color color)
{
Name(TableColorNames[index]);
Index(winrt::box_value<uint8_t>(index));
Color(color);
}
}
58 changes: 58 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ColorSchemes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

#include "ColorTableEntry.g.h"
#include "ColorSchemes.g.h"
#include "ColorSchemesPageNavigationState.g.h"
#include "Utils.h"

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ColorSchemesPageNavigationState : ColorSchemesPageNavigationStateT<ColorSchemesPageNavigationState>
{
public:
ColorSchemesPageNavigationState(const Model::GlobalAppSettings& settings) :
_Globals{ settings } {}

GETSET_PROPERTY(Model::GlobalAppSettings, Globals, nullptr);
};

struct ColorSchemes : ColorSchemesT<ColorSchemes>
{
ColorSchemes();

void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);

void ColorSchemeSelectionChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::SelectionChangedEventArgs const& args);
void ColorPickerChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::ColorChangedEventArgs const& args);

GETSET_PROPERTY(Editor::ColorSchemesPageNavigationState, State, nullptr);
GETSET_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::ColorTableEntry>, CurrentColorTable, nullptr);
GETSET_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::hstring>, ColorSchemeList, nullptr);

WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
OBSERVABLE_GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::ColorScheme, CurrentColorScheme, _PropertyChangedHandlers, nullptr);

private:
void _UpdateColorTable(const winrt::Microsoft::Terminal::Settings::Model::ColorScheme& colorScheme);
void _UpdateColorSchemeList();
};

struct ColorTableEntry : ColorTableEntryT<ColorTableEntry>
{
public:
ColorTableEntry(uint8_t index, Windows::UI::Color color);

WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(IInspectable, Index, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(Windows::UI::Color, Color, _PropertyChangedHandlers);
};
}

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

namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass ColorSchemesPageNavigationState
{
Microsoft.Terminal.Settings.Model.GlobalAppSettings Globals;
};

[default_interface] runtimeclass ColorSchemes : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
ColorSchemes();
ColorSchemesPageNavigationState State { get; };

Microsoft.Terminal.Settings.Model.ColorScheme CurrentColorScheme { get; };
Windows.Foundation.Collections.IObservableVector<ColorTableEntry> CurrentColorTable;
Windows.Foundation.Collections.IObservableVector<String> ColorSchemeList { get; };
}

[default_interface] runtimeclass ColorTableEntry : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Name { get; };
IInspectable Index;
Windows.UI.Color Color;
}
}

0 comments on commit 05f3ccb

Please sign in to comment.