Skip to content

Commit

Permalink
Add 'Move Tab' submenu to tab context menu (#18107)
Browse files Browse the repository at this point in the history
## Summary of the Pull Request
Adds a "Move tab" submenu to the tab's context menu. This submenu includes "move tab to new window", "move left", and "move right".

The new "move left/right" items are disabled if the tab can't be moved in a certain direction.'

Closes #17900

(cherry picked from commit d8089e9)
Service-Card-Id: PVTI_lADOAF3p4s4AmhmQzgU6Yu8
Service-Version: 1.22
  • Loading branch information
carlos-zamora authored and DHowett committed Nov 18, 2024
1 parent 2143ca1 commit ef0a6b7
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 54 deletions.
11 changes: 10 additions & 1 deletion src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@
<data name="TabCloseSubMenu" xml:space="preserve">
<value>Close</value>
</data>
<data name="TabMoveSubMenu" xml:space="preserve">
<value>Move tab</value>
</data>
<data name="TabCloseAfter" xml:space="preserve">
<value>Close tabs to the right</value>
</data>
Expand Down Expand Up @@ -941,4 +944,10 @@
<data name="CloseSnippetsPaneButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Close pane</value>
</data>
</root>
<data name="TabMoveLeft" xml:space="preserve">
<value>Move left</value>
</data>
<data name="TabMoveRight" xml:space="preserve">
<value>Move right</value>
</data>
</root>
103 changes: 82 additions & 21 deletions src/cascadia/TerminalApp/TabBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "TabBase.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"
#include "../inc/WindowingBehavior.h"

using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
Expand Down Expand Up @@ -56,10 +57,72 @@ namespace winrt::TerminalApp::implementation
tab->RequestFocusActiveControl.raise();
}
});
_AppendMoveMenuItems(contextMenuFlyout);
_AppendCloseMenuItems(contextMenuFlyout);
TabViewItem().ContextFlyout(contextMenuFlyout);
}

void TabBase::_AppendMoveMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout)
{
auto weakThis{ get_weak() };

// Move to new window
{
Controls::FontIcon moveTabToNewWindowTabSymbol;
moveTabToNewWindowTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
moveTabToNewWindowTabSymbol.Glyph(L"\xE8A7");

_moveToNewWindowMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ winrt::to_hstring(NewWindow), MoveTabDirection::Forward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveToNewWindowMenuItem.Text(RS_(L"MoveTabToNewWindowText"));
_moveToNewWindowMenuItem.Icon(moveTabToNewWindowTabSymbol);

const auto moveTabToNewWindowToolTip = RS_(L"MoveTabToNewWindowToolTip");
WUX::Controls::ToolTipService::SetToolTip(_moveToNewWindowMenuItem, box_value(moveTabToNewWindowToolTip));
Automation::AutomationProperties::SetHelpText(_moveToNewWindowMenuItem, moveTabToNewWindowToolTip);
}

// Move left
{
_moveLeftMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ hstring{}, MoveTabDirection::Backward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveLeftMenuItem.Text(RS_(L"TabMoveLeft"));
}

// Move right
{
_moveRightMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
MoveTabArgs args{ hstring{}, MoveTabDirection::Forward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
tab->_dispatch.DoAction(*tab, actionAndArgs);
}
});
_moveRightMenuItem.Text(RS_(L"TabMoveRight"));
}

// Create a sub-menu for our extended move tab items.
Controls::MenuFlyoutSubItem moveSubMenu;
moveSubMenu.Text(RS_(L"TabMoveSubMenu"));
moveSubMenu.Items().Append(_moveToNewWindowMenuItem);
moveSubMenu.Items().Append(_moveRightMenuItem);
moveSubMenu.Items().Append(_moveLeftMenuItem);
flyout.Items().Append(moveSubMenu);
}

// Method Description:
// - Append the close menu items to the context menu flyout
// Arguments:
Expand All @@ -75,7 +138,9 @@ namespace winrt::TerminalApp::implementation
_closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_CloseTabsAfter();
CloseTabsAfterArgs args{ tab->_TabViewIndex };
ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args };
tab->_dispatch.DoAction(*tab, closeTabsAfter);
}
});
_closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter"));
Expand All @@ -88,7 +153,9 @@ namespace winrt::TerminalApp::implementation
_closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_CloseOtherTabs();
CloseOtherTabsArgs args{ tab->_TabViewIndex };
ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args };
tab->_dispatch.DoAction(*tab, closeOtherTabs);
}
});
_closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther"));
Expand Down Expand Up @@ -129,33 +196,27 @@ namespace winrt::TerminalApp::implementation
}

// Method Description:
// - Enable the Close menu items based on tab index and total number of tabs
// - Enable menu items based on tab index and total number of tabs
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_EnableCloseMenuItems()
void TabBase::_EnableMenuItems()
{
// 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);
}
const auto tabIndex = TabViewIndex();
const auto numOfTabs = TabViewNumTabs();

void TabBase::_CloseTabsAfter()
{
CloseTabsAfterArgs args{ _TabViewIndex };
ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args };
// enabled if there are other tabs
_closeOtherTabsMenuItem.IsEnabled(numOfTabs > 1);

_dispatch.DoAction(closeTabsAfter);
}
// enabled if there are other tabs on the right
_closeTabsAfterMenuItem.IsEnabled(tabIndex < numOfTabs - 1);

void TabBase::_CloseOtherTabs()
{
CloseOtherTabsArgs args{ _TabViewIndex };
ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args };
// enabled if not left-most tab
_moveLeftMenuItem.IsEnabled(tabIndex > 0);

_dispatch.DoAction(closeOtherTabs);
// enabled if not last tab
_moveRightMenuItem.IsEnabled(tabIndex < numOfTabs - 1);
}

void TabBase::UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs)
Expand All @@ -164,7 +225,7 @@ namespace winrt::TerminalApp::implementation

TabViewIndex(idx);
TabViewNumTabs(numTabs);
_EnableCloseMenuItems();
_EnableMenuItems();
_UpdateSwitchToTabKeyChord();
}

Expand Down
8 changes: 5 additions & 3 deletions src/cascadia/TerminalApp/TabBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveToNewWindowMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveRightMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveLeftMenuItem{};
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
winrt::hstring _keyChord{};
Expand All @@ -69,10 +72,9 @@ namespace winrt::TerminalApp::implementation

virtual void _MakeTabViewItem();

void _AppendMoveMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
void _EnableCloseMenuItems();
void _CloseTabsAfter();
void _CloseOtherTabs();
void _EnableMenuItems();
void _UpdateSwitchToTabKeyChord();
void _UpdateToolTip();

Expand Down
32 changes: 4 additions & 28 deletions src/cascadia/TerminalApp/TerminalTab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "Utils.h"
#include "ColorHelper.h"
#include "AppLogic.h"
#include "../inc/WindowingBehavior.h"

using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
Expand Down Expand Up @@ -1443,23 +1442,6 @@ namespace winrt::TerminalApp::implementation
Automation::AutomationProperties::SetHelpText(splitTabMenuItem, splitTabToolTip);
}

Controls::MenuFlyoutItem moveTabToNewWindowMenuItem;
{
// "Move tab to new window"
Controls::FontIcon moveTabToNewWindowTabSymbol;
moveTabToNewWindowTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
moveTabToNewWindowTabSymbol.Glyph(L"\xE8A7");

moveTabToNewWindowMenuItem.Click({ get_weak(), &TerminalTab::_moveTabToNewWindowClicked });
moveTabToNewWindowMenuItem.Text(RS_(L"MoveTabToNewWindowText"));
moveTabToNewWindowMenuItem.Icon(moveTabToNewWindowTabSymbol);

const auto moveTabToNewWindowToolTip = RS_(L"MoveTabToNewWindowToolTip");

WUX::Controls::ToolTipService::SetToolTip(moveTabToNewWindowMenuItem, box_value(moveTabToNewWindowToolTip));
Automation::AutomationProperties::SetHelpText(moveTabToNewWindowMenuItem, moveTabToNewWindowToolTip);
}

Controls::MenuFlyoutItem closePaneMenuItem = _closePaneMenuItem;
{
// "Close pane"
Expand Down Expand Up @@ -1535,12 +1517,15 @@ namespace winrt::TerminalApp::implementation
contextMenuFlyout.Items().Append(renameTabMenuItem);
contextMenuFlyout.Items().Append(duplicateTabMenuItem);
contextMenuFlyout.Items().Append(splitTabMenuItem);
contextMenuFlyout.Items().Append(moveTabToNewWindowMenuItem);
_AppendMoveMenuItems(contextMenuFlyout);
contextMenuFlyout.Items().Append(exportTabMenuItem);
contextMenuFlyout.Items().Append(findMenuItem);
contextMenuFlyout.Items().Append(restartConnectionMenuItem);
contextMenuFlyout.Items().Append(menuSeparator);

auto closeSubMenu = _AppendCloseMenuItems(contextMenuFlyout);
closeSubMenu.Items().Append(closePaneMenuItem);

// GH#5750 - When the context menu is dismissed with ESC, toss the focus
// back to our control.
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
Expand All @@ -1560,8 +1545,6 @@ namespace winrt::TerminalApp::implementation
}
}
});
auto closeSubMenu = _AppendCloseMenuItems(contextMenuFlyout);
closeSubMenu.Items().Append(closePaneMenuItem);

TabViewItem().ContextFlyout(contextMenuFlyout);
}
Expand Down Expand Up @@ -2001,13 +1984,6 @@ namespace winrt::TerminalApp::implementation
actionAndArgs.Action(ShortcutAction::ExportBuffer);
_dispatch.DoAction(*this, actionAndArgs);
}
void TerminalTab::_moveTabToNewWindowClicked(const winrt::Windows::Foundation::IInspectable& /* sender */,
const winrt::Windows::UI::Xaml::RoutedEventArgs& /* args */)
{
MoveTabArgs args{ winrt::to_hstring(NewWindow), MoveTabDirection::Forward };
ActionAndArgs actionAndArgs{ ShortcutAction::MoveTab, args };
_dispatch.DoAction(*this, actionAndArgs);
}
void TerminalTab::_findClicked(const winrt::Windows::Foundation::IInspectable& /* sender */,
const winrt::Windows::UI::Xaml::RoutedEventArgs& /* args */)
{
Expand Down
1 change: 0 additions & 1 deletion src/cascadia/TerminalApp/TerminalTab.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ namespace winrt::TerminalApp::implementation
void _splitTabClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _closePaneClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _exportTextClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _moveTabToNewWindowClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _findClicked(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& e);

void _bubbleRestartTerminalRequested(TerminalApp::TerminalPaneContent sender, const winrt::Windows::Foundation::IInspectable& args);
Expand Down

0 comments on commit ef0a6b7

Please sign in to comment.