Repository: microsoft/terminal (language: cpp)

Issue:
Feature request: option to hide tab icons
<!-- 
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨

I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING:
1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement.
2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement.
3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number).
4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement.
5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement.

All good? Then proceed!
-->

# Description of the new feature/enhancement

<!-- 
A clear and concise description of what the problem is that the new feature would solve.
Describe why and how a user would use this new functionality (if applicable).
-->

The `"compact"` [tab width mode](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/global-settings) hides inactive tab titles and only shows icons for them. With multiple tabs of a same profile, it's hard to tell the difference without a descriptive title (which is controllable from the shell).

A "compact" thing means to pack enough information into a small space, often in an unattractive way. A workaround is to use a non-existent `"icon"` target for all profiles in `settings.json`, but that's hacky, and doesn't save enough space as expected. Let's compare Terminal and [ConEmu](https://github.com/Maximus5/ConEmu), both snapped to the right half side of my screen:

![Screenshot046](https://user-images.githubusercontent.com/863369/98061542-051ae900-1e87-11eb-8389-a5db67c703b2.png)

Thus I propose a new tab width mode, say `"textOnly"`, that hides icons (even for the active tab) and shows compact titles only.



Discussion / hints:
Thanks for the request! This is something that I've already got written down as an idea for #3327, so I'll make sure to link the two up ☺️ 
I would love to see this feature implemented as well. Hopefully some progress can be made on this as part of #3327.
> **Note**
> ## Walkthrough

I'm gonna combine this with a related ask for monochrome tab icons. 

* [ ] Start by modifying the `Tab` Theme object.
  * [ ] Add an `IconStyle` enum to `Theme.idl`, with `Default`, `Hidden` and `Monochrome` as options.
  * [ ] add a new property to `TabTheme` in `Theme.idl`. `Icon` which accepts an "IconStyle". 
  * [ ] In `MTSMSettings.h`, add a new setting under `MTSM_THEME_TAB_SETTINGS`. The key for this one should just be `"iconStyle"`
* [ ] Actually use this new setting
  * [ ] `TerminalTab::UpdateIcon` is probably the right place for this. You probably want to add another parameter to this. 
  * [ ] `IconPathConverter::IconSourceMUX` may need some plumbing to support colored OR monochrome icons. 
@zadjii-msft can I attempt to pick this up shortly?
Go for it ☺️ 
(you can also skip the monochrome bit if you want. I put that in the original spec because "I'm sure someone out there wants this" but I'm not actually sure anyone does)

Fix patch:
diff --git a/src/cascadia/LocalTests_SettingsModel/ThemeTests.cpp b/src/cascadia/LocalTests_SettingsModel/ThemeTests.cpp
index 4e3bdacc254..c7bf11326af 100644
--- a/src/cascadia/LocalTests_SettingsModel/ThemeTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/ThemeTests.cpp
@@ -60,7 +60,8 @@ namespace SettingsModelLocalTests
             "tabRow":
             {
                 "background": "#FFFF8800",
-                "unfocusedBackground": "#FF8844"
+                "unfocusedBackground": "#FF8844",
+                "iconStyle": "default"
             },
             "window":
             {
diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp
index 107bbb45732..1c9c4049f66 100644
--- a/src/cascadia/TerminalApp/SettingsTab.cpp
+++ b/src/cascadia/TerminalApp/SettingsTab.cpp
@@ -114,7 +114,7 @@ namespace winrt::TerminalApp::implementation
 
         // The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
         Icon(winrt::hstring{ glyph });
-        TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph));
+        TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph, false));
     }
 
     winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush()
diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp
index 02bd8940746..2d6bfc326d1 100644
--- a/src/cascadia/TerminalApp/TabManagement.cpp
+++ b/src/cascadia/TerminalApp/TabManagement.cpp
@@ -176,7 +176,7 @@ namespace winrt::TerminalApp::implementation
         {
             if (!profile.Icon().empty())
             {
-                newTabImpl->UpdateIcon(profile.Icon());
+                newTabImpl->UpdateIcon(profile.Icon(), _settings.GlobalSettings().CurrentTheme().Tab().IconStyle());
             }
         }
 
@@ -241,7 +241,7 @@ namespace winrt::TerminalApp::implementation
     {
         if (const auto profile = tab.GetFocusedProfile())
         {
-            tab.UpdateIcon(profile.Icon());
+            tab.UpdateIcon(profile.Icon(), _settings.GlobalSettings().CurrentTheme().Tab().IconStyle());
         }
     }
 
diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp
index 864ff6aad4e..226efc67dfe 100644
--- a/src/cascadia/TerminalApp/TerminalTab.cpp
+++ b/src/cascadia/TerminalApp/TerminalTab.cpp
@@ -278,17 +278,17 @@ namespace winrt::TerminalApp::implementation
     // - iconPath: The new path string to use as the IconPath for our TabViewItem
     // Return Value:
     // - <none>
-    void TerminalTab::UpdateIcon(const winrt::hstring iconPath)
+    void TerminalTab::UpdateIcon(const winrt::hstring iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle)
     {
         ASSERT_UI_THREAD();
 
-        // Don't reload our icon if it hasn't changed.
-        if (iconPath == _lastIconPath)
+        // Don't reload our icon and iconStyle hasn't changed.
+        if (iconPath == _lastIconPath && iconStyle == _lastIconStyle)
         {
             return;
         }
-
         _lastIconPath = iconPath;
+        _lastIconStyle = iconStyle;
 
         // If the icon is currently hidden, just return here (but only after setting _lastIconPath to the new path
         // for when we show the icon again)
@@ -297,9 +297,18 @@ namespace winrt::TerminalApp::implementation
             return;
         }
 
-        // The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
-        Icon(_lastIconPath);
-        TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
+        if (iconStyle == IconStyle::Hidden)
+        {
+            // The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
+            Icon({});
+            TabViewItem().IconSource(IconSource{ nullptr });
+        }
+        else
+        {
+            Icon(_lastIconPath);
+            bool isMonochrome = iconStyle == IconStyle::Monochrome;
+            TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath, isMonochrome));
+        }
     }
 
     // Method Description:
@@ -321,7 +330,7 @@ namespace winrt::TerminalApp::implementation
             else
             {
                 Icon(_lastIconPath);
-                TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath));
+                TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath, _lastIconStyle == IconStyle::Monochrome));
             }
             _iconHidden = hide;
         }
diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h
index 72ec8d8bac2..8ff0e6cc03f 100644
--- a/src/cascadia/TerminalApp/TerminalTab.h
+++ b/src/cascadia/TerminalApp/TerminalTab.h
@@ -41,7 +41,7 @@ namespace winrt::TerminalApp::implementation
                        std::shared_ptr<Pane> newPane);
 
         void ToggleSplitOrientation();
-        void UpdateIcon(const winrt::hstring iconPath);
+        void UpdateIcon(const winrt::hstring iconPath, const winrt::Microsoft::Terminal::Settings::Model::IconStyle iconStyle);
         void HideIcon(const bool hide);
 
         void ShowBellIndicator(const bool show);
@@ -110,6 +110,7 @@ namespace winrt::TerminalApp::implementation
 
         Windows::UI::Xaml::Controls::MenuFlyoutItem _closePaneMenuItem;
 
+        winrt::Microsoft::Terminal::Settings::Model::IconStyle _lastIconStyle;
         winrt::hstring _lastIconPath{};
         std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
         winrt::TerminalApp::TabHeaderControl _headerControl{};
diff --git a/src/cascadia/TerminalSettingsModel/IconPathConverter.cpp b/src/cascadia/TerminalSettingsModel/IconPathConverter.cpp
index 4b2239a9ad7..a51ead61899 100644
--- a/src/cascadia/TerminalSettingsModel/IconPathConverter.cpp
+++ b/src/cascadia/TerminalSettingsModel/IconPathConverter.cpp
@@ -72,7 +72,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
     // Return Value:
     // - An IconElement with its IconSource set, if possible.
     template<typename TIconSource>
-    TIconSource _getColoredBitmapIcon(const winrt::hstring& path)
+    TIconSource _getColoredBitmapIcon(const winrt::hstring& path, bool monochrome)
     {
         // FontIcon uses glyphs in the private use area, whereas valid URIs only contain ASCII characters.
         // To skip throwing on Uri construction, we can quickly check if the first character is ASCII.
@@ -85,7 +85,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
                 // Make sure to set this to false, so we keep the RGB data of the
                 // image. Otherwise, the icon will be white for all the
                 // non-transparent pixels in the image.
-                iconSource.ShowAsMonochrome(false);
+                iconSource.ShowAsMonochrome(monochrome);
                 iconSource.UriSource(iconUri);
                 return iconSource;
             }
@@ -121,14 +121,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
     // Return Value:
     // - An IconElement with its IconSource set, if possible.
     template<typename TIconSource>
-    TIconSource _getIconSource(const winrt::hstring& iconPath)
+    TIconSource _getIconSource(const winrt::hstring& iconPath, bool monochrome)
     {
         TIconSource iconSource{ nullptr };
 
         if (iconPath.size() != 0)
         {
             const auto expandedIconPath{ _expandIconPath(iconPath) };
-            iconSource = _getColoredBitmapIcon<TIconSource>(expandedIconPath);
+            iconSource = _getColoredBitmapIcon<TIconSource>(expandedIconPath, monochrome);
 
             // If we fail to set the icon source using the "icon" as a path,
             // let's try it as a symbol/emoji.
@@ -197,7 +197,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
                                                         const hstring& /* language */)
     {
         const auto& iconPath = winrt::unbox_value_or<winrt::hstring>(value, L"");
-        return _getIconSource<Controls::IconSource>(iconPath);
+        return _getIconSource<Controls::IconSource>(iconPath, false);
     }
 
     // unused for one-way bindings
@@ -211,12 +211,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
 
     Windows::UI::Xaml::Controls::IconSource _IconSourceWUX(hstring path)
     {
-        return _getIconSource<Windows::UI::Xaml::Controls::IconSource>(path);
+        return _getIconSource<Windows::UI::Xaml::Controls::IconSource>(path, false);
     }
 
-    Microsoft::UI::Xaml::Controls::IconSource _IconSourceMUX(hstring path)
+    Microsoft::UI::Xaml::Controls::IconSource _IconSourceMUX(hstring path, bool monochrome)
     {
-        return _getIconSource<Microsoft::UI::Xaml::Controls::IconSource>(path);
+        return _getIconSource<Microsoft::UI::Xaml::Controls::IconSource>(path, monochrome);
     }
 
     SoftwareBitmap _convertToSoftwareBitmap(HICON hicon,
@@ -329,13 +329,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         return bitmapSource;
     }
 
-    MUX::Controls::IconSource IconPathConverter::IconSourceMUX(const winrt::hstring& iconPath)
+    MUX::Controls::IconSource IconPathConverter::IconSourceMUX(const winrt::hstring& iconPath,
+                                                               const bool monochrome)
     {
         std::wstring_view iconPathWithoutIndex;
         const auto indexOpt = _getIconIndex(iconPath, iconPathWithoutIndex);
         if (!indexOpt.has_value())
         {
-            return _IconSourceMUX(iconPath);
+            return _IconSourceMUX(iconPath, monochrome);
         }
 
         const auto bitmapSource = _getImageIconSourceForBinary(iconPathWithoutIndex, indexOpt.value());
diff --git a/src/cascadia/TerminalSettingsModel/IconPathConverter.h b/src/cascadia/TerminalSettingsModel/IconPathConverter.h
index a9eee104b94..f91fdcad7bd 100644
--- a/src/cascadia/TerminalSettingsModel/IconPathConverter.h
+++ b/src/cascadia/TerminalSettingsModel/IconPathConverter.h
@@ -19,7 +19,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
                                                       const hstring& language);
 
         static Windows::UI::Xaml::Controls::IconElement IconWUX(const winrt::hstring& iconPath);
-        static Microsoft::UI::Xaml::Controls::IconSource IconSourceMUX(const winrt::hstring& iconPath);
+        static Microsoft::UI::Xaml::Controls::IconSource IconSourceMUX(const winrt::hstring& iconPath, const bool convertToGrayscale);
     };
 }
 
diff --git a/src/cascadia/TerminalSettingsModel/IconPathConverter.idl b/src/cascadia/TerminalSettingsModel/IconPathConverter.idl
index bbe1e055b8c..b52367b6c34 100644
--- a/src/cascadia/TerminalSettingsModel/IconPathConverter.idl
+++ b/src/cascadia/TerminalSettingsModel/IconPathConverter.idl
@@ -16,7 +16,7 @@ namespace Microsoft.Terminal.Settings.Model
         IconPathConverter();
 
         static Windows.UI.Xaml.Controls.IconElement IconWUX(String path);
-        static Microsoft.UI.Xaml.Controls.IconSource IconSourceMUX(String path);
+        static Microsoft.UI.Xaml.Controls.IconSource IconSourceMUX(String path, Boolean convertToGrayscale);
     };
 
 }
diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
index 6c7b08649f9..ae676362dea 100644
--- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h
+++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
@@ -151,7 +151,8 @@ Author(s):
     X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \
     X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr)
 
-#define MTSM_THEME_TAB_SETTINGS(X)                                                                                  \
-    X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr)                   \
-    X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr) \
+#define MTSM_THEME_TAB_SETTINGS(X)                                                                                                                     \
+    X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr)                                                      \
+    X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr)                                    \
+    X(winrt::Microsoft::Terminal::Settings::Model::IconStyle, IconStyle, "iconStyle", winrt::Microsoft::Terminal::Settings::Model::IconStyle::Default) \
     X(winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility, ShowCloseButton, "showCloseButton", winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility::Always)
diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
index 0dc91e30b11..f5431aabf3d 100644
--- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
+++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h
@@ -652,6 +652,15 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVi
     };
 };
 
+JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::IconStyle)
+{
+    JSON_MAPPINGS(3) = {
+        pair_type{ "default", ValueType::Default },
+        pair_type{ "hidden", ValueType::Hidden },
+        pair_type{ "monochrome", ValueType::Monochrome },
+    };
+};
+
 // Possible ScrollToMarkDirection values
 JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::ScrollToMarkDirection)
 {
diff --git a/src/cascadia/TerminalSettingsModel/Theme.idl b/src/cascadia/TerminalSettingsModel/Theme.idl
index f7f041a9dda..830bafef2a2 100644
--- a/src/cascadia/TerminalSettingsModel/Theme.idl
+++ b/src/cascadia/TerminalSettingsModel/Theme.idl
@@ -4,6 +4,13 @@
 namespace Microsoft.Terminal.Settings.Model
 {
 
+    enum IconStyle
+    {
+        Default,
+        Hidden,
+        Monochrome
+    };
+
     enum ThemeColorType
     {
         Accent,
@@ -63,6 +70,7 @@ namespace Microsoft.Terminal.Settings.Model
         ThemeColor Background { get; };
         ThemeColor UnfocusedBackground { get; };
         TabCloseButtonVisibility ShowCloseButton { get; };
+        IconStyle IconStyle { get; };
     }
 
     [default_interface] runtimeclass Theme : Windows.Foundation.IStringable {


Test patch: