From 3d40c43f5b663099c581221457280054af04ba02 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 1 Aug 2022 12:20:15 -0500 Subject: [PATCH] Add support for hiding the tab close button (#13348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of the Pull Request Adds support for the `tab.showCloseButton` property to themes. This accepts three values: * `"always"` (default): The close button acts like it does today. * `"hover"`: The close button is always visible on the active tab. On inactive tabs, the close button only appears on mouse over. * `"never"`: The close button is never visible. You can't close the tab with middle-click, but you can still use keyboard shortcuts to close the tab. ## References * See #3327 * ⚠️ targets #13178 ⚠️ ## PR Checklist * [x] Closes #3335 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated - YUP ## Detailed Description of the Pull Request / Additional comments See the following two properties in WInUI that we're leveraging here. * [`TabViewCloseButtonOverlayMode.OnPointerOver`](https://docs.microsoft.com/en-us/windows/winui/api/microsoft.ui.xaml.controls.tabviewclosebuttonoverlaymode?view=winui-2.7&viewFallbackFrom=winui-2.2) * [`TabViewItem.IsClosable`](https://docs.microsoft.com/en-us/windows/winui/api/microsoft.ui.xaml.controls.tabviewitem.isclosable?view=winui-2.2#microsoft-ui-xaml-controls-tabviewitem-isclosable) One is a tabview-level property, the other is a per-tab-item property, hence why this code is a little wacky. ## Validation Steps Performed gifs below --- src/cascadia/TerminalApp/TabManagement.cpp | 3 + src/cascadia/TerminalApp/TerminalPage.cpp | 97 +++++++++++++++++++ src/cascadia/TerminalApp/TerminalPage.h | 1 + .../TerminalSettingsModel/MTSMSettings.h | 5 +- .../TerminalSettingsSerializationHelpers.h | 9 ++ src/cascadia/TerminalSettingsModel/Theme.idl | 8 ++ 6 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index 332b8331292..97679d99b3c 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -234,6 +234,9 @@ namespace winrt::TerminalApp::implementation auto tabViewItem = newTabImpl->TabViewItem(); _tabView.TabItems().InsertAt(insertPosition, tabViewItem); + // Update the state of the close button to match the current theme + _updateTabCloseButton(tabViewItem); + // Set this tab's icon to the icon from the user's profile if (const auto profile{ newTabImpl->GetFocusedProfile() }) { diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 2032125d0e4..f867bba2c08 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -225,6 +225,26 @@ namespace winrt::TerminalApp::implementation } _updateThemeColors(); + // Initialize the state of the the CloseButtonOverlayMode property of + // our TabView, to match the tab.showCloseButton property in the theme. + if (const auto theme = _settings.GlobalSettings().CurrentTheme()) + { + const auto visibility = theme.Tab() ? theme.Tab().ShowCloseButton() : Settings::Model::TabCloseButtonVisibility::Always; + + switch (visibility) + { + case Settings::Model::TabCloseButtonVisibility::Never: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Auto); + break; + case Settings::Model::TabCloseButtonVisibility::Hover: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::OnPointerOver); + break; + default: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Always); + break; + } + } + // Hookup our event handlers to the ShortcutActionDispatch _RegisterActionCallbacks(); @@ -2708,6 +2728,48 @@ namespace winrt::TerminalApp::implementation //////////////////////////////////////////////////////////////////////// // Begin Theme handling _updateThemeColors(); + + // Update the state of the the CloseButtonOverlayMode property of + // our TabView, to match the tab.showCloseButton property in the theme. + // + // Also update every tab's individual IsClosable to match. + // + // This is basically the same as _updateTabCloseButton, but with some + // code moved around to better facilitate updating every tab view item + // at once + if (const auto theme = _settings.GlobalSettings().CurrentTheme()) + { + const auto visibility = theme.Tab() ? theme.Tab().ShowCloseButton() : Settings::Model::TabCloseButtonVisibility::Always; + + for (const auto& tab : _tabs) + { + switch (visibility) + { + case Settings::Model::TabCloseButtonVisibility::Never: + tab.TabViewItem().IsClosable(false); + break; + case Settings::Model::TabCloseButtonVisibility::Hover: + tab.TabViewItem().IsClosable(true); + break; + default: + tab.TabViewItem().IsClosable(true); + break; + } + } + + switch (visibility) + { + case Settings::Model::TabCloseButtonVisibility::Never: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Auto); + break; + case Settings::Model::TabCloseButtonVisibility::Hover: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::OnPointerOver); + break; + default: + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Always); + break; + } + } } // This is a helper to aid in sorting commands by their `Name`s, alphabetically. @@ -3261,6 +3323,9 @@ namespace winrt::TerminalApp::implementation auto tabViewItem = newTabImpl->TabViewItem(); _tabView.TabItems().Append(tabViewItem); + // Update the state of the close button to match the current theme + _updateTabCloseButton(tabViewItem); + tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick }); // When the tab requests close, try to close it (prompt for approval, if required) @@ -4142,6 +4207,38 @@ namespace winrt::TerminalApp::implementation _SetNewTabButtonColor(bgColor, bgColor); } + void TerminalPage::_updateTabCloseButton(const winrt::Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem) + { + // Update the state of the close button to match the current theme. + // IMPORTANT: Should be called AFTER the tab view item is added to the TabView. + if (const auto theme = _settings.GlobalSettings().CurrentTheme()) + { + const auto visibility = theme.Tab() ? theme.Tab().ShowCloseButton() : Settings::Model::TabCloseButtonVisibility::Always; + + // Update both the tab item's IsClosable, but also the TabView's + // CloseButtonOverlayMode here. Because the TabViewItem was created + // outside the context of the TabView, it doesn't get the + // CloseButtonOverlayMode assigned on creation. We have to update + // that property again here, when we add the tab, so that the + // TabView will re-apply the value. + switch (visibility) + { + case Settings::Model::TabCloseButtonVisibility::Never: + tabViewItem.IsClosable(false); + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Auto); + break; + case Settings::Model::TabCloseButtonVisibility::Hover: + tabViewItem.IsClosable(true); + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::OnPointerOver); + break; + default: + tabViewItem.IsClosable(true); + _tabView.CloseButtonOverlayMode(MUX::Controls::TabViewCloseButtonOverlayMode::Always); + break; + } + } + } + void TerminalPage::WindowActivated(const bool activated) { // Stash if we're activated. Use that when we reload diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 3d5b70efe5e..c0081b54d39 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -448,6 +448,7 @@ namespace winrt::TerminalApp::implementation static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message); void _updateThemeColors(); + void _updateTabCloseButton(const winrt::Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem); winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args); diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h index 5b2882c7e6c..aeb3872b399 100644 --- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h +++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h @@ -130,5 +130,6 @@ 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) +#define MTSM_THEME_TAB_SETTINGS(X) \ + X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \ + 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 0cd768e3f8d..de205f332ff 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -659,6 +659,15 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait