Skip to content

Commit

Permalink
Add support for hiding the tab close button (#13348)
Browse files Browse the repository at this point in the history
## 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
  • Loading branch information
zadjii-msft authored Aug 1, 2022
1 parent a84f4d5 commit 3d40c43
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/TabManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() })
{
Expand Down
97 changes: 97 additions & 0 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 3 additions & 2 deletions src/cascadia/TerminalSettingsModel/MTSMSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,15 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<winrt:
}
};

JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility)
{
JSON_MAPPINGS(3) = {
pair_type{ "always", ValueType::Always },
pair_type{ "hover", ValueType::Hover },
pair_type{ "never", ValueType::Never },
};
};

// Possible ScrollToMarkDirection values
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::ScrollToMarkDirection)
{
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalSettingsModel/Theme.idl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ namespace Microsoft.Terminal.Settings.Model
TerminalBackground
};

enum TabCloseButtonVisibility
{
Always,
Hover,
Never
};

runtimeclass ThemeColor
{
ThemeColor();
Expand Down Expand Up @@ -39,6 +46,7 @@ namespace Microsoft.Terminal.Settings.Model

runtimeclass TabTheme {
ThemeColor Background { get; };
TabCloseButtonVisibility ShowCloseButton { get; };
}

[default_interface] runtimeclass Theme : Windows.Foundation.IStringable {
Expand Down

0 comments on commit 3d40c43

Please sign in to comment.