Skip to content

Commit

Permalink
Add UI for adding, renaming, and deleting a color scheme (#8403)
Browse files Browse the repository at this point in the history
Introduces the following UI controls to the ColorSchemes page:
- "Add new" button
  - next to dropdown selector
  - adds a new color scheme named ("Color Scheme #" where # is the number of color schemes you have)
- "Rename" Button
  - next to the selector
  - replaces the ComboBox with a TextBox and the accept/cancel buttons appear
- "Delete" button
  - bottom of the page
  - opens flyout, when confirmed, deletes the current color scheme and selects another one

This also adds a Delete button to the Profiles page. The Hide checkbox was moved above the Delete button.

## References
#1564 - Settings UI
#6800 - Settings UI Completion Epic

## Detailed Description of the Pull Request / Additional comments

**Color Schemes:**
- Deleting a color scheme selects another one from the list available
- Rename replaces the combobox with a textbox to allow editing
- The Add New button creates a new color scheme named "Color Scheme X" where X is the number of schemes defined
- In-box color schemes cannot be deleted

**Profile:**
- Deleting a profile selects another one from the list available
- the rename button does not exist (yet), because it needs a modification to the NavigationView's Header Template
- The delete button is disabled for in-box profiles (CMD and Windows Powershell) and dynamic profiles

## Validation Steps Performed
**Color Schemes - Add New**
✅ Creates a new color scheme named "Color Scheme X" (X being the number of color schemes)
✅ The new color scheme can be renamed/deleted/modified

**Color Schemes - Rename**
✅ You cannot rename an in-box color scheme
✅ The rename button has a tooltip
✅ Clicking the rename button replaces the combobox with a textbox
✅ Accept --> changes name
✅ Cancel --> does not change the name
✅ accepting/cancelling the rename operation updates the combo box appropriately

**Color Schemes - Delete**
✅ Clicking delete produces a flyout to confirm deletion
✅ Deleting a color scheme removes it from the list and select the one under it
✅ Deleting the last color scheme selects the last available color scheme after it's deleted
✅ In-box color schemes have the delete button disabled, and a disclaimer appears next to it

**Profile- Delete**
✅ Base layer presents a disclaimer at the top, and hides the delete button
✅ Dynamic and in-box profiles disable the delete button and show the appropriate disclaimer next to the disabled button
✅ Clicking delete produces a flyout to confirm deletion
✅ Regular profiles have a delete button that is styled appropriately
✅ Clicking the delete profile button opens a content dialog. Confirmation deletes the profile and navigates to the profile indexed under it (deleting the last one redirects to the last one)


## Demo
Refer to this post [here](#8403 (comment).
Confirmation flyout demo: #8403 (comment)
  • Loading branch information
carlos-zamora committed Dec 17, 2020
1 parent c5366ce commit 33470ad
Show file tree
Hide file tree
Showing 26 changed files with 1,162 additions and 517 deletions.
129 changes: 125 additions & 4 deletions src/cascadia/TerminalSettingsEditor/ColorSchemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using namespace winrt;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Media;
Expand Down Expand Up @@ -38,8 +39,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
RS_(L"ColorScheme_BrightWhite/Header")
};

static const std::array<std::wstring, 9> InBoxSchemes = {
L"Campbell",
L"Campbell Powershell",
L"Vintage",
L"One Half Dark",
L"One Half Light",
L"Solarized Dark",
L"Solarized Light",
L"Tango Dark",
L"Tango Light"
};

ColorSchemes::ColorSchemes() :
_ColorSchemeList{ single_threaded_observable_vector<hstring>() },
_ColorSchemeList{ single_threaded_observable_vector<Model::ColorScheme>() },
_CurrentColorTable{ single_threaded_observable_vector<Editor::ColorTableEntry>() }
{
InitializeComponent();
Expand Down Expand Up @@ -73,10 +86,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
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);
const auto colorScheme{ args.AddedItems().GetAt(0).try_as<Model::ColorScheme>() };
CurrentColorScheme(colorScheme);
_UpdateColorTable(colorScheme);

// Set the text disclaimer for the text box
hstring disclaimer{};
const std::wstring schemeName{ colorScheme.Name() };
if (std::find(std::begin(InBoxSchemes), std::end(InBoxSchemes), schemeName) != std::end(InBoxSchemes))
{
// load disclaimer for in-box profiles
disclaimer = RS_(L"ColorScheme_DeleteButtonDisclaimerInBox");
}
DeleteButtonDisclaimer().Text(disclaimer);

// Update the state of the page
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"CanDeleteCurrentScheme" });
IsRenaming(false);
}

// Function Description:
Expand All @@ -92,7 +118,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
const auto& colorSchemeMap{ _State.Globals().ColorSchemes() };
for (const auto& pair : colorSchemeMap)
{
_ColorSchemeList.Append(pair.Key());
_ColorSchemeList.Append(pair.Value());
}
}

Expand Down Expand Up @@ -120,6 +146,101 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}

bool ColorSchemes::CanDeleteCurrentScheme() const
{
if (const auto scheme{ CurrentColorScheme() })
{
// Only allow this color scheme to be deleted if it's not provided in-box
const std::wstring myName{ scheme.Name() };
return std::find(std::begin(InBoxSchemes), std::end(InBoxSchemes), myName) == std::end(InBoxSchemes);
}
return false;
}

void ColorSchemes::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
const auto schemeName{ CurrentColorScheme().Name() };
_State.Globals().RemoveColorScheme(schemeName);

const auto removedSchemeIndex{ ColorSchemeComboBox().SelectedIndex() };
if (static_cast<uint32_t>(removedSchemeIndex) < _ColorSchemeList.Size() - 1)
{
// select same index
ColorSchemeComboBox().SelectedIndex(removedSchemeIndex + 1);
}
else
{
// select last color scheme (avoid out of bounds error)
ColorSchemeComboBox().SelectedIndex(removedSchemeIndex - 1);
}
_ColorSchemeList.RemoveAt(removedSchemeIndex);
DeleteButton().Flyout().Hide();
}

void ColorSchemes::AddNew_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
// Give the new scheme a distinct name
const hstring schemeName{ fmt::format(L"Color Scheme {}", _State.Globals().ColorSchemes().Size() + 1) };
Model::ColorScheme scheme{ schemeName };

// Add the new color scheme
_State.Globals().AddColorScheme(scheme);

// Update current page
_ColorSchemeList.Append(scheme);
ColorSchemeComboBox().SelectedItem(scheme);
}

// Function Description:
// - Pre-populates/focuses the name TextBox, updates the UI
// Arguments:
// - <unused>
// Return Value:
// - <none>
void ColorSchemes::Rename_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
NameBox().Text(CurrentColorScheme().Name());
IsRenaming(true);
NameBox().Focus(FocusState::Programmatic);
NameBox().SelectAll();
}

void ColorSchemes::RenameAccept_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
_RenameCurrentScheme(NameBox().Text());
}

void ColorSchemes::RenameCancel_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
{
IsRenaming(false);
}

void ColorSchemes::NameBox_PreviewKeyDown(IInspectable const& /*sender*/, winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Enter)
{
_RenameCurrentScheme(NameBox().Text());
e.Handled(true);
}
else if (e.OriginalKey() == winrt::Windows::System::VirtualKey::Escape)
{
IsRenaming(false);
e.Handled(true);
}
}

void ColorSchemes::_RenameCurrentScheme(hstring newName)
{
CurrentColorScheme().Name(newName);
IsRenaming(false);

// The color scheme is renamed appropriately, but the ComboBox still shows the old name (until you open it)
// We need to manually force the ComboBox to refresh itself.
const auto selectedIndex{ ColorSchemeComboBox().SelectedIndex() };
ColorSchemeComboBox().SelectedIndex((selectedIndex + 1) % ColorSchemeList().Size());
ColorSchemeComboBox().SelectedIndex(selectedIndex);
}

// Function Description:
// - Updates the currently modifiable color table based on the given current color scheme.
// Arguments:
Expand Down
13 changes: 12 additions & 1 deletion src/cascadia/TerminalSettingsEditor/ColorSchemes.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,28 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

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);
void AddNew_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);

void Rename_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void RenameAccept_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void RenameCancel_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void NameBox_PreviewKeyDown(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);

bool CanDeleteCurrentScheme() const;
void DeleteConfirmation_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);

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);
GETSET_PROPERTY(Windows::Foundation::Collections::IObservableVector<Model::ColorScheme>, ColorSchemeList, nullptr);

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

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

struct ColorTableEntry : ColorTableEntryT<ColorTableEntry>
Expand Down
5 changes: 4 additions & 1 deletion src/cascadia/TerminalSettingsEditor/ColorSchemes.idl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ namespace Microsoft.Terminal.Settings.Editor
ColorSchemes();
ColorSchemesPageNavigationState State { get; };

Boolean CanDeleteCurrentScheme { get; };
Boolean IsRenaming { get; };

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

[default_interface] runtimeclass ColorTableEntry : Windows.UI.Xaml.Data.INotifyPropertyChanged
Expand Down

0 comments on commit 33470ad

Please sign in to comment.