From 5b634657980ecfa2d65e9ffec622dfd842839628 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Tue, 29 Oct 2024 18:45:19 +0000 Subject: [PATCH] Add icon override setting for newTabMenu entries (#18116) ## Summary of the Pull Request This PR is to allow users to set a custom icon for entries in the new tab menu for "action" and "profile" type entries. ## References and Relevant Issues This PR is in response to #18103 ## Detailed Description of the Pull Request / Additional comments It is now possible to specify an optional "icon" setting for any "action" or "profile" type entry in the "newTabMenu" JSON settings. When specified, this icon will be used as the menu icon for that action/profile in the new tab menu. If not specified, the action/profile definition's default icon will be used instead (if present). The Cascadia settings schema ("doc/cascadia/profiles.schema.json") has been updated to reflect this. ## Validation Steps Performed Manually tested with multiple combinations of icon settings: - ActionEntry: - valid path in action definition and new tab entry (renders new tab entry icon) - valid path in action definition but no path in new tab entry (renders action definition icon) - no path in action definition, valid path in new tab entry (renders new tab entry icon) - invalid path in action definition, valid path in new tab entry (renders new tab entry icon) - valid path in action definition, invalid path in new tab entry (renders no icon) - invalid path in both (renders no icon) - no path in both (renders no icon) - ProfileEntry: - valid path in new tab entry (renders new tab entry icon) - no path in new tab entry (renders profile's default icon) - invalid path in new tab entry (renders no icon) ## PR Checklist - [x] Closes #18103 - [x] Tests added/passed - [x] Documentation updated - If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: [#808](https://github.com/MicrosoftDocs/terminal/pull/808) - [x] Schema updated (if necessary) --- doc/cascadia/profiles.schema.json | 6 +++++ src/cascadia/TerminalApp/TerminalPage.cpp | 24 ++++++++++--------- src/cascadia/TerminalApp/TerminalPage.h | 4 ++-- .../TerminalSettingsModel/ActionEntry.cpp | 3 +++ .../TerminalSettingsModel/ActionEntry.h | 1 + .../TerminalSettingsModel/NewTabMenuEntry.idl | 2 ++ .../TerminalSettingsModel/ProfileEntry.cpp | 4 ++++ .../TerminalSettingsModel/ProfileEntry.h | 1 + 8 files changed, 32 insertions(+), 13 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index ec903dc5b8..9774c51844 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -733,6 +733,9 @@ "type": "string", "default": "", "description": "The name or GUID of the profile to show in this entry" + }, + "icon": { + "$ref": "#/$defs/Icon" } } } @@ -804,6 +807,9 @@ "type": "string", "default": "", "description": "The ID of the action to show in this entry" + }, + "icon": { + "$ref": "#/$defs/Icon" } } } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index b3111e9b63..99064fef8b 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -989,7 +989,7 @@ namespace winrt::TerminalApp::implementation for (auto&& [profileIndex, remainingProfile] : remainingProfilesEntry.Profiles()) { - items.push_back(_CreateNewTabFlyoutProfile(remainingProfile, profileIndex)); + items.push_back(_CreateNewTabFlyoutProfile(remainingProfile, profileIndex, {})); } break; @@ -1003,7 +1003,7 @@ namespace winrt::TerminalApp::implementation break; } - auto profileItem = _CreateNewTabFlyoutProfile(profileEntry.Profile(), profileEntry.ProfileIndex()); + auto profileItem = _CreateNewTabFlyoutProfile(profileEntry.Profile(), profileEntry.ProfileIndex(), profileEntry.Icon()); items.push_back(profileItem); break; } @@ -1013,7 +1013,7 @@ namespace winrt::TerminalApp::implementation const auto actionId = actionEntry.ActionId(); if (_settings.ActionMap().GetActionByID(actionId)) { - auto actionItem = _CreateNewTabFlyoutAction(actionId); + auto actionItem = _CreateNewTabFlyoutAction(actionId, actionEntry.Icon()); items.push_back(actionItem); } @@ -1028,7 +1028,7 @@ namespace winrt::TerminalApp::implementation // Method Description: // - This method creates a flyout menu item for a given profile with the given index. // It makes sure to set the correct icon, keybinding, and click-action. - WUX::Controls::MenuFlyoutItem TerminalPage::_CreateNewTabFlyoutProfile(const Profile profile, int profileIndex) + WUX::Controls::MenuFlyoutItem TerminalPage::_CreateNewTabFlyoutProfile(const Profile profile, int profileIndex, const winrt::hstring& iconPathOverride) { auto profileMenuItem = WUX::Controls::MenuFlyoutItem{}; @@ -1049,9 +1049,10 @@ namespace winrt::TerminalApp::implementation auto profileName = profile.Name(); profileMenuItem.Text(profileName); - // If there's an icon set for this profile, set it as the icon for - // this flyout item - const auto& iconPath = profile.EvaluatedIcon(); + // If a custom icon path has been specified, set it as the icon for + // this flyout item. Otherwise, if an icon is set for this profile, set that icon + // for this flyout item. + const auto& iconPath = iconPathOverride.empty() ? profile.EvaluatedIcon() : iconPathOverride; if (!iconPath.empty()) { const auto icon = _CreateNewTabFlyoutIcon(iconPath); @@ -1112,7 +1113,7 @@ namespace winrt::TerminalApp::implementation // Method Description: // - This method creates a flyout menu item for a given action // It makes sure to set the correct icon, keybinding, and click-action. - WUX::Controls::MenuFlyoutItem TerminalPage::_CreateNewTabFlyoutAction(const winrt::hstring& actionId) + WUX::Controls::MenuFlyoutItem TerminalPage::_CreateNewTabFlyoutAction(const winrt::hstring& actionId, const winrt::hstring& iconPathOverride) { auto actionMenuItem = WUX::Controls::MenuFlyoutItem{}; const auto action{ _settings.ActionMap().GetActionByID(actionId) }; @@ -1125,9 +1126,10 @@ namespace winrt::TerminalApp::implementation actionMenuItem.Text(action.Name()); - // If there's an icon set for this action, set it as the icon for - // this flyout item - const auto& iconPath = action.IconPath(); + // If a custom icon path has been specified, set it as the icon for + // this flyout item. Otherwise, if an icon is set for this action, set that icon + // for this flyout item. + const auto& iconPath = iconPathOverride.empty() ? action.IconPath() : iconPathOverride; if (!iconPath.empty()) { const auto icon = _CreateNewTabFlyoutIcon(iconPath); diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 9e5d3029c7..30627d5b7e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -316,8 +316,8 @@ namespace winrt::TerminalApp::implementation void _CreateNewTabFlyout(); std::vector _CreateNewTabFlyoutItems(winrt::Windows::Foundation::Collections::IVector entries); winrt::Windows::UI::Xaml::Controls::IconElement _CreateNewTabFlyoutIcon(const winrt::hstring& icon); - winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex); - winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutAction(const winrt::hstring& actionId); + winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutProfile(const Microsoft::Terminal::Settings::Model::Profile profile, int profileIndex, const winrt::hstring& iconPathOverride); + winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _CreateNewTabFlyoutAction(const winrt::hstring& actionId, const winrt::hstring& iconPathOverride); void _OpenNewTabDropdown(); HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::INewContentArgs& newContentArgs); diff --git a/src/cascadia/TerminalSettingsModel/ActionEntry.cpp b/src/cascadia/TerminalSettingsModel/ActionEntry.cpp index b48207e74e..6f7773e715 100644 --- a/src/cascadia/TerminalSettingsModel/ActionEntry.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionEntry.cpp @@ -11,6 +11,7 @@ using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; static constexpr std::string_view ActionIdKey{ "id" }; +static constexpr std::string_view IconKey{ "icon" }; ActionEntry::ActionEntry() noexcept : ActionEntryT(NewTabMenuEntryType::Action) @@ -22,6 +23,7 @@ Json::Value ActionEntry::ToJson() const auto json = NewTabMenuEntry::ToJson(); JsonUtils::SetValueForKey(json, ActionIdKey, _ActionId); + JsonUtils::SetValueForKey(json, IconKey, _Icon); return json; } @@ -31,6 +33,7 @@ winrt::com_ptr ActionEntry::FromJson(const Json::Value& json) auto entry = winrt::make_self(); JsonUtils::GetValueForKey(json, ActionIdKey, entry->_ActionId); + JsonUtils::GetValueForKey(json, IconKey, entry->_Icon); return entry; } diff --git a/src/cascadia/TerminalSettingsModel/ActionEntry.h b/src/cascadia/TerminalSettingsModel/ActionEntry.h index 9c89077828..711cec13bf 100644 --- a/src/cascadia/TerminalSettingsModel/ActionEntry.h +++ b/src/cascadia/TerminalSettingsModel/ActionEntry.h @@ -28,6 +28,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation static com_ptr FromJson(const Json::Value& json); WINRT_PROPERTY(winrt::hstring, ActionId); + WINRT_PROPERTY(winrt::hstring, Icon); }; } diff --git a/src/cascadia/TerminalSettingsModel/NewTabMenuEntry.idl b/src/cascadia/TerminalSettingsModel/NewTabMenuEntry.idl index 84bc377769..acf1f33f6f 100644 --- a/src/cascadia/TerminalSettingsModel/NewTabMenuEntry.idl +++ b/src/cascadia/TerminalSettingsModel/NewTabMenuEntry.idl @@ -33,6 +33,7 @@ namespace Microsoft.Terminal.Settings.Model Profile Profile; Int32 ProfileIndex; + String Icon; } [default_interface] runtimeclass ActionEntry : NewTabMenuEntry @@ -40,6 +41,7 @@ namespace Microsoft.Terminal.Settings.Model ActionEntry(); String ActionId; + String Icon; } enum FolderEntryInlining diff --git a/src/cascadia/TerminalSettingsModel/ProfileEntry.cpp b/src/cascadia/TerminalSettingsModel/ProfileEntry.cpp index c857eea867..5f01a293be 100644 --- a/src/cascadia/TerminalSettingsModel/ProfileEntry.cpp +++ b/src/cascadia/TerminalSettingsModel/ProfileEntry.cpp @@ -11,6 +11,7 @@ using namespace Microsoft::Terminal::Settings::Model; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; static constexpr std::string_view ProfileKey{ "profile" }; +static constexpr std::string_view IconKey{ "icon" }; ProfileEntry::ProfileEntry() noexcept : ProfileEntry{ winrt::hstring{} } @@ -46,6 +47,8 @@ Json::Value ProfileEntry::ToJson() const JsonUtils::SetValueForKey(json, ProfileKey, _Profile.Guid()); } + JsonUtils::SetValueForKey(json, IconKey, _Icon); + return json; } @@ -54,6 +57,7 @@ winrt::com_ptr ProfileEntry::FromJson(const Json::Value& json) auto entry = winrt::make_self(); JsonUtils::GetValueForKey(json, ProfileKey, entry->_ProfileName); + JsonUtils::GetValueForKey(json, IconKey, entry->_Icon); return entry; } diff --git a/src/cascadia/TerminalSettingsModel/ProfileEntry.h b/src/cascadia/TerminalSettingsModel/ProfileEntry.h index fe0f4573d2..9ea78497f1 100644 --- a/src/cascadia/TerminalSettingsModel/ProfileEntry.h +++ b/src/cascadia/TerminalSettingsModel/ProfileEntry.h @@ -41,6 +41,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation WINRT_PROPERTY(Model::Profile, Profile); WINRT_PROPERTY(int, ProfileIndex); + WINRT_PROPERTY(winrt::hstring, Icon); private: winrt::hstring _ProfileName;