Add setTabColor and openTabColorPicker actions (#6567)

## Summary of the Pull Request

Adds a pair of `ShortcutAction`s for setting the tab color.
* `setTabColor`: This changes the color of the current tab to the provided color, or can be used to clear the color.
* `openTabColorPicker`: This keybinding immediately activates the tab color picker for the currently focused tab.

## References

## PR Checklist
* [x] scratches my own itch
* [x] I work here
* [x] Tests added/passed
* [x] https://github.com/MicrosoftDocs/terminal/pull/69

## Detailed Description of the Pull Request / Additional comments

## Validation Steps Performed
* hey look there are tests
* Tested with the following:
```json

        // { "command": "setTabColor", "keys": [ "alt+c" ] },
        { "keys": "ctrl+alt+c", "command": { "action": "setTabColor", "color": "#123456" } },
        { "keys": "alt+shift+c", "command": { "action": "setTabColor", "color": null} },
        { "keys": "alt+c", "command": "openTabColorPicker" },
```
This commit is contained in:
Mike Griese 2020-06-25 08:06:21 -05:00 committed by GitHub
parent 9215b5282d
commit a3a9df82b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 207 additions and 13 deletions

View file

@ -8,6 +8,7 @@ abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
ABE
BBGGRR
BBBBBBBBBBBBBBDDDD
QQQQQQQQQQABCDEFGHIJ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ

View file

@ -56,6 +56,8 @@
"switchToTab",
"toggleFullscreen",
"find",
"setTabColor",
"openTabColorPicker",
"unbound"
],
"type": "string"
@ -257,6 +259,22 @@
}
]
},
"SetTabColorAction": {
"description": "Arguments corresponding to a Set Tab Color Action",
"allOf": [
{ "$ref": "#/definitions/ShortcutAction" },
{
"properties": {
"action": { "type": "string", "pattern": "setTabColor" },
"color": {
"$ref": "#/definitions/Color",
"default": null,
"description": "If provided, will set the tab's color to the given value. If omitted, will reset the tab's color."
}
}
}
]
},
"Keybinding": {
"additionalProperties": false,
"properties": {
@ -272,6 +290,7 @@
{ "$ref": "#/definitions/ResizePaneAction" },
{ "$ref": "#/definitions/SplitPaneAction" },
{ "$ref": "#/definitions/OpenSettingsAction" },
{ "$ref": "#/definitions/SetTabColorAction" },
{ "type": "null" }
]
},

View file

@ -44,6 +44,8 @@ namespace TerminalAppLocalTests
TEST_METHOD(TestStringOverload);
TEST_METHOD(TestSetTabColorArgs);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
@ -400,6 +402,63 @@ namespace TerminalAppLocalTests
}
}
void KeyBindingsTests::TestSetTabColorArgs()
{
const std::string bindings0String{ R"([
{ "keys": ["ctrl+c"], "command": { "action": "setTabColor", "color": null } },
{ "keys": ["ctrl+d"], "command": { "action": "setTabColor", "color": "#123456" } },
{ "keys": ["ctrl+e"], "command": { "action": "setTabColor", "color": "thisStringObviouslyWontWork" } },
{ "keys": ["ctrl+f"], "command": "setTabColor" },
])" };
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
auto appKeyBindings = winrt::make_self<implementation::AppKeyBindings>();
VERIFY_IS_NOT_NULL(appKeyBindings);
VERIFY_ARE_EQUAL(0u, appKeyBindings->_keyShortcuts.size());
appKeyBindings->LayerJson(bindings0Json);
VERIFY_ARE_EQUAL(4u, appKeyBindings->_keyShortcuts.size());
{
KeyChord kc{ true, false, false, static_cast<int32_t>('C') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SetTabColorArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NULL(realArgs.TabColor());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('D') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SetTabColorArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NOT_NULL(realArgs.TabColor());
// Remember that COLORREFs are actually BBGGRR order, while the string is in #RRGGBB order
VERIFY_ARE_EQUAL(static_cast<uint32_t>(til::color(0x563412)), realArgs.TabColor().Value());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('E') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SetTabColorArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NULL(realArgs.TabColor());
}
{
KeyChord kc{ true, false, false, static_cast<int32_t>('F') };
auto actionAndArgs = TestUtils::GetActionAndArgs(*appKeyBindings, kc);
VERIFY_ARE_EQUAL(ShortcutAction::SetTabColor, actionAndArgs.Action());
const auto& realArgs = actionAndArgs.Args().try_as<SetTabColorArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_IS_NULL(realArgs.TabColor());
}
}
void KeyBindingsTests::TestStringOverload()
{
const std::string bindings0String{ R"([

View file

@ -33,6 +33,8 @@ static constexpr std::string_view ResizePaneKey{ "resizePane" };
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
static constexpr std::string_view FindKey{ "find" };
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
static constexpr std::string_view OpenTabColorPickerKey{ "openTabColorPicker" };
static constexpr std::string_view RenameTabKey{ "renameTab" };
namespace winrt::TerminalApp::implementation
@ -69,6 +71,8 @@ namespace winrt::TerminalApp::implementation
{ OpenSettingsKey, ShortcutAction::OpenSettings },
{ ToggleFullscreenKey, ShortcutAction::ToggleFullscreen },
{ SplitPaneKey, ShortcutAction::SplitPane },
{ SetTabColorKey, ShortcutAction::SetTabColor },
{ OpenTabColorPickerKey, ShortcutAction::OpenTabColorPicker },
{ UnboundKey, ShortcutAction::Invalid },
{ FindKey, ShortcutAction::Find },
{ RenameTabKey, ShortcutAction::RenameTab }
@ -99,6 +103,8 @@ namespace winrt::TerminalApp::implementation
{ ShortcutAction::OpenSettings, winrt::TerminalApp::implementation::OpenSettingsArgs::FromJson },
{ ShortcutAction::SetTabColor, winrt::TerminalApp::implementation::SetTabColorArgs::FromJson },
{ ShortcutAction::RenameTab, winrt::TerminalApp::implementation::RenameTabArgs::FromJson },
{ ShortcutAction::Invalid, nullptr },

View file

@ -15,4 +15,5 @@
#include "AdjustFontSizeArgs.g.cpp"
#include "SplitPaneArgs.g.cpp"
#include "OpenSettingsArgs.g.cpp"
#include "SetTabColorArgs.g.cpp"
#include "RenameTabArgs.g.cpp"

View file

@ -15,10 +15,12 @@
#include "AdjustFontSizeArgs.g.h"
#include "SplitPaneArgs.g.h"
#include "OpenSettingsArgs.g.h"
#include "SetTabColorArgs.g.h"
#include "RenameTabArgs.g.h"
#include "../../cascadia/inc/cppwinrt_utils.h"
#include "Utils.h"
#include "JsonUtils.h"
#include "TerminalWarnings.h"
// Notes on defining ActionArgs and ActionEventArgs:
@ -443,6 +445,41 @@ namespace winrt::TerminalApp::implementation
}
};
struct SetTabColorArgs : public SetTabColorArgsT<SetTabColorArgs>
{
SetTabColorArgs() = default;
GETSET_PROPERTY(Windows::Foundation::IReference<uint32_t>, TabColor, nullptr);
static constexpr std::string_view ColorKey{ "color" };
public:
bool Equals(const IActionArgs& other)
{
auto otherAsUs = other.try_as<SetTabColorArgs>();
if (otherAsUs)
{
return otherAsUs->_TabColor == _TabColor;
}
return false;
};
static FromJsonResult FromJson(const Json::Value& json)
{
// LOAD BEARING: Not using make_self here _will_ break you in the future!
auto args = winrt::make_self<SetTabColorArgs>();
std::optional<til::color> temp;
try
{
::TerminalApp::JsonUtils::GetOptionalColor(json, ColorKey, temp);
if (temp.has_value())
{
args->_TabColor = static_cast<uint32_t>(temp.value());
}
}
CATCH_LOG();
return { *args, {} };
}
};
struct RenameTabArgs : public RenameTabArgsT<RenameTabArgs>
{
RenameTabArgs() = default;

View file

@ -103,6 +103,11 @@ namespace TerminalApp
SettingsTarget Target { get; };
};
[default_interface] runtimeclass SetTabColorArgs : IActionArgs
{
Windows.Foundation.IReference<UInt32> TabColor { get; };
};
[default_interface] runtimeclass RenameTabArgs : IActionArgs
{
String Title { get; };

View file

@ -238,6 +238,45 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}
void TerminalPage::_HandleSetTabColor(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
std::optional<til::color> tabColor;
if (const auto& realArgs = args.ActionArgs().try_as<TerminalApp::SetTabColorArgs>())
{
if (realArgs.TabColor() != nullptr)
{
tabColor = realArgs.TabColor().Value();
}
}
auto activeTab = _GetFocusedTab();
if (activeTab)
{
if (tabColor.has_value())
{
activeTab->SetTabColor(tabColor.value());
}
else
{
activeTab->ResetTabColor();
}
}
args.Handled(true);
}
void TerminalPage::_HandleOpenTabColorPicker(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
auto activeTab = _GetFocusedTab();
if (activeTab)
{
activeTab->ActivateColorPicker();
}
args.Handled(true);
}
void TerminalPage::_HandleRenameTab(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
@ -262,5 +301,4 @@ namespace winrt::TerminalApp::implementation
}
args.Handled(true);
}
}

View file

@ -159,6 +159,16 @@ namespace winrt::TerminalApp::implementation
_ToggleFullscreenHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::SetTabColor:
{
_SetTabColorHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::OpenTabColorPicker:
{
_OpenTabColorPickerHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::RenameTab:
{
_RenameTabHandlers(*this, *eventArgs);

View file

@ -47,6 +47,8 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SetTabColor, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenTabColorPicker,TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(RenameTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
// clang-format on

View file

@ -4,9 +4,6 @@ import "../ActionArgs.idl";
namespace TerminalApp
{
// TODO: GH#1069 - Many of these shortcut actions are "legacy" now that we
// have support for arbitrary args (#1142). We should remove them, and our
// legacy deserializers.
enum ShortcutAction
{
Invalid = 0,
@ -35,6 +32,8 @@ namespace TerminalApp
MoveFocus,
Find,
ToggleFullscreen,
SetTabColor,
OpenTabColorPicker,
OpenSettings,
RenameTab
};
@ -74,7 +73,8 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> Find;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> MoveFocus;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ToggleFullscreen;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> SetTabColor;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> OpenTabColorPicker;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> RenameTab;
}
}

View file

@ -520,7 +520,7 @@ namespace winrt::TerminalApp::implementation
chooseColorMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_tabColorPickup.ShowAt(tab->_tabViewItem);
tab->ActivateColorPicker();
}
});
chooseColorMenuItem.Text(RS_(L"TabColorChoose"));
@ -530,14 +530,14 @@ namespace winrt::TerminalApp::implementation
_tabColorPickup.ColorSelected([weakThis](auto newTabColor) {
if (auto tab{ weakThis.get() })
{
tab->_SetTabColor(newTabColor);
tab->SetTabColor(newTabColor);
}
});
_tabColorPickup.ColorCleared([weakThis]() {
if (auto tab{ weakThis.get() })
{
tab->_ResetTabColor();
tab->ResetTabColor();
}
});
@ -718,7 +718,7 @@ namespace winrt::TerminalApp::implementation
// - color: the shiny color the user picked for their tab
// Return Value:
// - <none>
void Tab::_SetTabColor(const winrt::Windows::UI::Color& color)
void Tab::SetTabColor(const winrt::Windows::UI::Color& color)
{
auto weakThis{ get_weak() };
@ -779,7 +779,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - <none>
void Tab::_ResetTabColor()
void Tab::ResetTabColor()
{
auto weakThis{ get_weak() };
@ -817,6 +817,17 @@ namespace winrt::TerminalApp::implementation
});
}
// Method Description:
// - Display the tab color picker at the location of the TabViewItem for this tab.
// Arguments:
// - <none>
// Return Value:
// - <none>
void Tab::ActivateColorPicker()
{
_tabColorPickup.ShowAt(_tabViewItem);
}
// Method Description:
// Toggles the visual state of the tab view item,
// so that changes to the tab color are reflected immediately

View file

@ -56,6 +56,10 @@ namespace winrt::TerminalApp::implementation
std::optional<winrt::Windows::UI::Color> GetTabColor();
void SetTabColor(const winrt::Windows::UI::Color& color);
void ResetTabColor();
void ActivateColorPicker();
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
DECLARE_EVENT(ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
@ -83,8 +87,6 @@ namespace winrt::TerminalApp::implementation
void _Focus();
void _CreateContextMenu();
void _SetTabColor(const winrt::Windows::UI::Color& color);
void _ResetTabColor();
void _RefreshVisualState();
void _BindEventHandlers(const winrt::Microsoft::Terminal::TerminalControl::TermControl& control) noexcept;

View file

@ -755,6 +755,8 @@ namespace winrt::TerminalApp::implementation
_actionDispatch->Find({ this, &TerminalPage::_HandleFind });
_actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize });
_actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen });
_actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor });
_actionDispatch->OpenTabColorPicker({ this, &TerminalPage::_HandleOpenTabColorPicker });
_actionDispatch->RenameTab({ this, &TerminalPage::_HandleRenameTab });
}

View file

@ -198,8 +198,9 @@ namespace winrt::TerminalApp::implementation
void _HandleFind(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleResetFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleToggleFullscreen(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleSetTabColor(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleOpenTabColorPicker(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleRenameTab(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
#pragma endregion
friend class TerminalAppLocalTests::TabTests;