diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
index 325f19ee20b..446bc161976 100644
--- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
@@ -177,8 +177,17 @@
Do you want to close all tabs?
+
+ Close...
+
+
+ Close Tabs to the Right
+
+
+ Close Other Tabs
+
- Close
+ Close Tab
Color...
diff --git a/src/cascadia/TerminalApp/Tab.cpp b/src/cascadia/TerminalApp/Tab.cpp
index f571457d57a..42101c34810 100644
--- a/src/cascadia/TerminalApp/Tab.cpp
+++ b/src/cascadia/TerminalApp/Tab.cpp
@@ -593,10 +593,61 @@ namespace winrt::TerminalApp::implementation
newTabFlyout.Items().Append(chooseColorMenuItem);
newTabFlyout.Items().Append(renameTabMenuItem);
newTabFlyout.Items().Append(menuSeparator);
+ newTabFlyout.Items().Append(_CreateCloseSubMenu());
newTabFlyout.Items().Append(closeTabMenuItem);
_tabViewItem.ContextFlyout(newTabFlyout);
}
+ // Method Description:
+ // - Creates a sub-menu containing menu items to close multiple tabs
+ // Arguments:
+ // -
+ // Return Value:
+ // - the created MenuFlyoutSubItem
+ Controls::MenuFlyoutSubItem Tab::_CreateCloseSubMenu()
+ {
+ auto weakThis{ get_weak() };
+
+ // Close tabs after
+ _closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) {
+ if (auto tab{ weakThis.get() })
+ {
+ tab->_CloseTabsAfter();
+ }
+ });
+ _closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter"));
+
+ // Close other tabs
+ _closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) {
+ if (auto tab{ weakThis.get() })
+ {
+ tab->_CloseOtherTabs();
+ }
+ });
+ _closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther"));
+
+ Controls::MenuFlyoutSubItem closeSubMenu;
+ closeSubMenu.Text(RS_(L"TabCloseSubMenu"));
+ closeSubMenu.Items().Append(_closeTabsAfterMenuItem);
+ closeSubMenu.Items().Append(_closeOtherTabsMenuItem);
+
+ return closeSubMenu;
+ }
+
+ // Method Description:
+ // - Enable the Close menu items based on tab index and total number of tabs
+ // Arguments:
+ // -
+ // Return Value:
+ // -
+ void Tab::_EnableCloseMenuItems()
+ {
+ // close other tabs is enabled only if there are other tabs
+ _closeOtherTabsMenuItem.IsEnabled(TabViewNumTabs() > 1);
+ // close tabs after is enabled only if there are other tabs on the right
+ _closeTabsAfterMenuItem.IsEnabled(TabViewIndex() < TabViewNumTabs() - 1);
+ }
+
// Method Description:
// - This will update the contents of our TabViewItem for our current state.
// - If we're not in a rename, we'll set the Header of the TabViewItem to
@@ -1053,12 +1104,35 @@ namespace winrt::TerminalApp::implementation
SwitchToTabCommand(command);
}
- void Tab::UpdateTabViewIndex(const uint32_t idx)
+ void Tab::_CloseTabsAfter()
+ {
+ CloseTabsAfterArgs args{ _TabViewIndex };
+ ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args };
+
+ _dispatch.DoAction(closeTabsAfter);
+ }
+
+ void Tab::_CloseOtherTabs()
+ {
+ CloseOtherTabsArgs args{ _TabViewIndex };
+ ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args };
+
+ _dispatch.DoAction(closeOtherTabs);
+ }
+
+ void Tab::UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs)
{
TabViewIndex(idx);
+ TabViewNumTabs(numTabs);
+ _EnableCloseMenuItems();
SwitchToTabCommand().Action().Args().as().TabIndex(idx);
}
+ void Tab::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
+ {
+ _dispatch = dispatch;
+ }
+
DEFINE_EVENT(Tab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
DEFINE_EVENT(Tab, ColorSelected, _colorSelected, winrt::delegate);
DEFINE_EVENT(Tab, ColorCleared, _colorCleared, winrt::delegate<>);
diff --git a/src/cascadia/TerminalApp/Tab.h b/src/cascadia/TerminalApp/Tab.h
index 02ce977d874..4dae6bc8744 100644
--- a/src/cascadia/TerminalApp/Tab.h
+++ b/src/cascadia/TerminalApp/Tab.h
@@ -68,7 +68,9 @@ namespace winrt::TerminalApp::implementation
int GetLeafPaneCount() const noexcept;
- void UpdateTabViewIndex(const uint32_t idx);
+ void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
+
+ void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
@@ -83,6 +85,8 @@ namespace winrt::TerminalApp::implementation
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
// This is needed since Tab is going to be managing its own SwitchToTab command.
OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewIndex, _PropertyChangedHandlers, 0);
+ // The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
+ OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewNumTabs, _PropertyChangedHandlers, 0);
private:
std::shared_ptr _rootPane{ nullptr };
@@ -92,6 +96,8 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
std::optional _themeTabColor{};
std::optional _runtimeTabColor{};
+ winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
+ winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
bool _focused{ false };
winrt::Microsoft::UI::Xaml::Controls::TabViewItem _tabViewItem{ nullptr };
@@ -100,10 +106,15 @@ namespace winrt::TerminalApp::implementation
bool _inRename{ false };
winrt::Windows::UI::Xaml::Controls::TextBox::LayoutUpdated_revoker _tabRenameBoxLayoutUpdatedRevoker;
+ winrt::TerminalApp::ShortcutActionDispatch _dispatch;
+
void _MakeTabViewItem();
void _Focus();
void _CreateContextMenu();
+ winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _CreateCloseSubMenu();
+ void _EnableCloseMenuItems();
+
void _RefreshVisualState();
void _BindEventHandlers(const winrt::Microsoft::Terminal::TerminalControl::TermControl& control) noexcept;
@@ -123,6 +134,9 @@ namespace winrt::TerminalApp::implementation
void _MakeSwitchToTabCommand();
+ void _CloseTabsAfter();
+ void _CloseOtherTabs();
+
friend class ::TerminalAppLocalTests::TabTests;
};
}
diff --git a/src/cascadia/TerminalApp/Tab.idl b/src/cascadia/TerminalApp/Tab.idl
index b02e4da0f4b..db9746c99ee 100644
--- a/src/cascadia/TerminalApp/Tab.idl
+++ b/src/cascadia/TerminalApp/Tab.idl
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+import "ShortcutActionDispatch.idl";
namespace TerminalApp
{
@@ -9,5 +10,7 @@ namespace TerminalApp
Windows.UI.Xaml.Controls.IconSource IconSource { get; };
Microsoft.Terminal.Settings.Model.Command SwitchToTabCommand { get; };
UInt32 TabViewIndex { get; };
+
+ void SetDispatch(ShortcutActionDispatch dispatch);
}
}
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 12c0fbf106f..68a7462d226 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -673,8 +673,10 @@ namespace winrt::TerminalApp::implementation
auto newTabImpl = winrt::make_self(profileGuid, term);
_tabs.Append(*newTabImpl);
+ newTabImpl->SetDispatch(*_actionDispatch);
+
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
- newTabImpl->UpdateTabViewIndex(_tabs.Size() - 1);
+ _UpdateTabIndices();
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(term, *newTabImpl);
@@ -2542,9 +2544,10 @@ namespace winrt::TerminalApp::implementation
// -
void TerminalPage::_UpdateTabIndices()
{
- for (uint32_t i = 0; i < _tabs.Size(); ++i)
+ const uint32_t size = _tabs.Size();
+ for (uint32_t i = 0; i < size; ++i)
{
- _GetStrongTabImpl(i)->UpdateTabViewIndex(i);
+ _GetStrongTabImpl(i)->UpdateTabViewIndex(i, size);
}
}
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
index 1ce89a1dc6c..cc9b97d83ab 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp
@@ -20,6 +20,8 @@
#include "SetTabColorArgs.g.cpp"
#include "RenameTabArgs.g.cpp"
#include "ExecuteCommandlineArgs.g.cpp"
+#include "CloseOtherTabsArgs.g.cpp"
+#include "CloseTabsAfterArgs.g.cpp"
#include
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h
index 209fef24c24..8fc53a4b6e4 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.h
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h
@@ -505,6 +505,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct CloseOtherTabsArgs : public CloseOtherTabsArgsT
{
CloseOtherTabsArgs() = default;
+ CloseOtherTabsArgs(uint32_t& tabIndex) :
+ _Index{ tabIndex } {};
GETSET_PROPERTY(Windows::Foundation::IReference, Index, nullptr);
static constexpr std::string_view IndexKey{ "index" };
@@ -533,6 +535,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
struct CloseTabsAfterArgs : public CloseTabsAfterArgsT
{
CloseTabsAfterArgs() = default;
+ CloseTabsAfterArgs(uint32_t& tabIndex) :
+ _Index{ tabIndex } {};
GETSET_PROPERTY(Windows::Foundation::IReference, Index, nullptr);
static constexpr std::string_view IndexKey{ "index" };
@@ -567,4 +571,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
BASIC_FACTORY(NewTabArgs);
BASIC_FACTORY(SplitPaneArgs);
BASIC_FACTORY(ExecuteCommandlineArgs);
+ BASIC_FACTORY(CloseOtherTabsArgs);
+ BASIC_FACTORY(CloseTabsAfterArgs);
}
diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
index 407dbd6d4cb..3c2e87f37e0 100644
--- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl
+++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
@@ -141,11 +141,13 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass CloseOtherTabsArgs : IActionArgs
{
+ CloseOtherTabsArgs(UInt32 tabIndex);
Windows.Foundation.IReference Index { get; };
};
[default_interface] runtimeclass CloseTabsAfterArgs : IActionArgs
{
+ CloseTabsAfterArgs(UInt32 tabIndex);
Windows.Foundation.IReference Index { get; };
};
}