From fb588b8364706790f06c942a46b304a9cdae464a Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 17 Aug 2023 10:04:40 -0500 Subject: [PATCH 1/6] This is easy enough --- src/cascadia/TerminalApp/TabManagement.cpp | 7 ++++--- src/cascadia/TerminalApp/TerminalPage.cpp | 5 +++-- src/cascadia/TerminalSettingsEditor/MainPage.cpp | 2 +- src/cascadia/TerminalSettingsEditor/ProfileViewModel.h | 5 +++++ src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl | 2 ++ src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp | 8 ++++++-- src/cascadia/TerminalSettingsModel/Command.cpp | 2 +- src/cascadia/TerminalSettingsModel/Profile.cpp | 4 ++++ src/cascadia/TerminalSettingsModel/Profile.h | 2 ++ src/cascadia/TerminalSettingsModel/Profile.idl | 4 ++++ 10 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index ef0093dc30d..144c24cc729 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -229,9 +229,10 @@ namespace winrt::TerminalApp::implementation // Set this tab's icon to the icon from the user's profile if (const auto profile{ newTabImpl->GetFocusedProfile() }) { - if (!profile.Icon().empty()) + const auto& icon = profile.EvaluatedIcon(); + if (!icon.empty()) { - newTabImpl->UpdateIcon(profile.Icon()); + newTabImpl->UpdateIcon(icon); } } @@ -296,7 +297,7 @@ namespace winrt::TerminalApp::implementation { if (const auto profile = tab.GetFocusedProfile()) { - tab.UpdateIcon(profile.Icon()); + tab.UpdateIcon(profile.EvaluatedIcon()); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d4ec0666b68..ac02eb4181e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1012,9 +1012,10 @@ namespace winrt::TerminalApp::implementation // If there's an icon set for this profile, set it as the icon for // this flyout item - if (!profile.Icon().empty()) + const auto& iconPath = profile.EvaluatedIcon(); + if (!iconPath.empty()) { - const auto icon = _CreateNewTabFlyoutIcon(profile.Icon()); + const auto icon = _CreateNewTabFlyoutIcon(iconPath); profileMenuItem.Icon(icon); } diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.cpp b/src/cascadia/TerminalSettingsEditor/MainPage.cpp index 2c18ce11c95..11c66408135 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.cpp +++ b/src/cascadia/TerminalSettingsEditor/MainPage.cpp @@ -595,7 +595,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation MUX::Controls::NavigationViewItem profileNavItem; profileNavItem.Content(box_value(profile.Name())); profileNavItem.Tag(box_value(profile)); - profileNavItem.Icon(IconPathConverter::IconWUX(profile.Icon())); + profileNavItem.Icon(IconPathConverter::IconWUX(profile.EvaluatedIcon())); // Update the menu item when the icon/name changes auto weakMenuItem{ make_weak(profileNavItem) }; diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h index 0946d9146ad..39ddd8dd3ea 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h @@ -58,6 +58,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation Padding(to_hstring(value)); } + winrt::hstring EvaluatedIcon() const + { + return _profile.EvaluatedIcon(); + } + // starting directory bool UseParentProcessDirectory(); void UseParentProcessDirectory(const bool useParent); diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl index ab0bcbf2ffb..4c825dd0372 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl @@ -75,6 +75,8 @@ namespace Microsoft.Terminal.Settings.Editor AppearanceViewModel UnfocusedAppearance { get; }; Boolean VtPassthroughAvailable { get; }; + String EvaluatedIcon { get; }; + void CreateUnfocusedAppearance(); void DeleteUnfocusedAppearance(); diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 851e667ac9a..19556209df9 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -515,8 +515,12 @@ void CascadiaSettings::_validateMediaResources() } } - // Anything longer than 2 wchar_t's _isn't_ an emoji or symbol, - // so treat it as an invalid path. + // Anything longer than 2 wchar_t's _isn't_ an emoji or symbol, so treat + // it as an invalid path. + // + // Explicitly just use the Icon here, not the EvaluatedIcon. We don't + // want to blow up if we fell back to the commandline and the + // commandline _isn't an icon_. if (const auto icon = profile.Icon(); icon.size() > 2) { const auto iconPath{ wil::ExpandEnvironmentStringsW(icon.c_str()) }; diff --git a/src/cascadia/TerminalSettingsModel/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp index b211987b677..f5936c2f5be 100644 --- a/src/cascadia/TerminalSettingsModel/Command.cpp +++ b/src/cascadia/TerminalSettingsModel/Command.cpp @@ -602,7 +602,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // - Escape the profile name for JSON appropriately auto escapedProfileName = _escapeForJson(til::u16u8(p.Name())); - auto escapedProfileIcon = _escapeForJson(til::u16u8(p.Icon())); + auto escapedProfileIcon = _escapeForJson(til::u16u8(p.EvaluatedIcon())); auto newJsonString = til::replace_needle_in_haystack(oldJsonString, ProfileNameToken, escapedProfileName); diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index 3aa896f50da..98e3d2f51a8 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -336,3 +336,7 @@ Json::Value Profile::ToJson() const return json; } +winrt::hstring Profile::EvaluatedIcon() const +{ + return Icon().empty() ? Commandline() : Icon(); +} diff --git a/src/cascadia/TerminalSettingsModel/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h index 05bd77cc720..e32a90c2ccb 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -102,6 +102,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation Model::IAppearanceConfig DefaultAppearance(); Model::FontConfig FontInfo(); + winrt::hstring EvaluatedIcon() const; + void _FinalizeInheritance() override; // Special fields diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index 3cfaf96aff9..3d1291e6b35 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -53,6 +53,10 @@ namespace Microsoft.Terminal.Settings.Model Boolean Deleted { get; }; OriginTag Origin { get; }; + // Helper for magically using a commandline for an icon for a profile + // without an explicit icon. + String EvaluatedIcon { get; }; + INHERITABLE_PROFILE_SETTING(Guid, Guid); INHERITABLE_PROFILE_SETTING(String, Name); INHERITABLE_PROFILE_SETTING(String, Source); From c41895e59bccb7e50630298b57969d52c551c71c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 17 Aug 2023 10:30:50 -0500 Subject: [PATCH 2/6] be smart, use the first word as the application name --- .../TerminalSettingsModel/Profile.cpp | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index 98e3d2f51a8..c4272b07883 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -338,5 +338,26 @@ Json::Value Profile::ToJson() const } winrt::hstring Profile::EvaluatedIcon() const { - return Icon().empty() ? Commandline() : Icon(); + // If the profile has an icon, return it. + if (!Icon().empty()) + { + return Icon(); + } + + // Otherwise, return the first word of the commandline - that should be the executable name. + std::wstring_view cmdline{ Commandline() }; + if (cmdline.empty()) + { + return {}; + } + + auto firstSpace = cmdline.find_first_of(L" "); + if (firstSpace == std::wstring::npos) + { + return winrt::hstring{ cmdline }; + } + else + { + return winrt::hstring{ cmdline.substr(0, firstSpace) }; + } } From cf7ebb86739d9b61b3780f9c114f6421d6f5f2aa Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Sep 2023 11:02:34 -0500 Subject: [PATCH 3/6] add a sui checkbox for hiding the icon --- .../ProfileViewModel.cpp | 24 +++++++++++++++++++ .../TerminalSettingsEditor/ProfileViewModel.h | 5 ++++ .../ProfileViewModel.idl | 1 + .../TerminalSettingsEditor/Profiles_Base.xaml | 11 +++++++-- .../Resources/en-US/Resources.resw | 8 +++++++ 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp index 5f31f6be579..3a5061d5e68 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp @@ -69,6 +69,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { _NotifyChanges(L"CurrentScrollState"); } + else if (viewModelProperty == L"Icon") + { + _NotifyChanges(L"HideIcon"); + } }); // Do the same for the starting directory @@ -348,6 +352,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation } } + bool ProfileViewModel::HideIcon() + { + return Icon() == L"none"; + } + void ProfileViewModel::HideIcon(const bool hide) + { + if (hide) + { + // Stash the current value of Icon. If the user + // checks and un-checks the "Hide Icon" checkbox, we want + // the path that we display in the text box to remain unchanged. + _lastIcon = Icon(); + Icon(L"none"); + } + else + { + Icon(_lastIcon); + } + } + bool ProfileViewModel::IsBellStyleFlagSet(const uint32_t flag) { return (WI_EnumValue(BellStyle()) & flag) == flag; diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h index 39ddd8dd3ea..239a95b63ef 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h @@ -68,6 +68,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void UseParentProcessDirectory(const bool useParent); bool UseCustomStartingDirectory(); + // icon + bool HideIcon(); + void HideIcon(const bool hide); + // general profile knowledge winrt::guid OriginalProfileGuid() const noexcept; bool CanDeleteProfile() const; @@ -124,6 +128,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation winrt::guid _originalProfileGuid; winrt::hstring _lastBgImagePath; winrt::hstring _lastStartingDirectoryPath; + winrt::hstring _lastIcon; Editor::AppearanceViewModel _defaultAppearanceViewModel; static Windows::Foundation::Collections::IObservableVector _MonospaceFontList; diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl index 4c825dd0372..ec9da636eaa 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl @@ -67,6 +67,7 @@ namespace Microsoft.Terminal.Settings.Editor ProfileSubPage CurrentPage; Boolean UseParentProcessDirectory; Boolean UseCustomStartingDirectory { get; }; + Boolean HideIcon; AppearanceViewModel DefaultAppearance { get; }; Guid OriginalProfileGuid { get; }; Boolean HasUnfocusedAppearance { get; }; diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml b/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml index f660f40ed90..9c3eeaaffb3 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml +++ b/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml @@ -110,13 +110,20 @@ + Text="{x:Bind Profile.Icon, Mode=TwoWay}" + Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HideIcon), Mode=OneWay}" />