diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
index 26823366401..174039e6775 100644
--- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw
@@ -211,6 +211,45 @@
Split pane
+
+ Right click for split directions - right/down/up/left
+
+
+ Split pane down
+
+
+ Split pane right
+
+
+ Split pane up
+
+
+ Split pane left
+
+
+ Duplicate
+
+
+ Swap pane
+
+
+ Swap pane down
+
+
+ Swap pane right
+
+
+ Swap pane up
+
+
+ Swap pane left
+
+
+ Toggle pane zoom
+
+
+ Close other panes
+
Web search
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 99064fef8bb..841447ae979 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -5034,9 +5034,48 @@ namespace winrt::TerminalApp::implementation
};
};
- auto makeItem = [&menu, &makeCallback](const winrt::hstring& label,
+ auto makeItem = [&makeCallback](const winrt::hstring& label,
+ const winrt::hstring& icon,
+ const auto& action,
+ auto& targetMenu) {
+ AppBarButton button{};
+
+ if (!icon.empty())
+ {
+ auto iconElement = UI::IconPathConverter::IconWUX(icon);
+ Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
+ button.Icon(iconElement);
+ }
+
+ button.Label(label);
+ button.Click(makeCallback(action));
+ targetMenu.SecondaryCommands().Append(button);
+ };
+
+ auto makeMenuItem = [](const winrt::hstring& label,
+ const winrt::hstring& icon,
+ const auto& subMenu,
+ auto& targetMenu) {
+ AppBarButton button{};
+
+ if (!icon.empty())
+ {
+ auto iconElement = UI::IconPathConverter::IconWUX(icon);
+ Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
+ button.Icon(iconElement);
+ }
+
+ button.Label(label);
+ button.Flyout(subMenu);
+ targetMenu.SecondaryCommands().Append(button);
+ };
+
+ auto makeContextItem = [&makeCallback](const winrt::hstring& label,
const winrt::hstring& icon,
- const auto& action) {
+ const winrt::hstring& tooltip,
+ const auto& action,
+ const auto& subMenu,
+ auto& targetMenu) {
AppBarButton button{};
if (!icon.empty())
@@ -5048,34 +5087,122 @@ namespace winrt::TerminalApp::implementation
button.Label(label);
button.Click(makeCallback(action));
- menu.SecondaryCommands().Append(button);
+ WUX::Controls::ToolTipService::SetToolTip(button, box_value(tooltip));
+ button.ContextFlyout(subMenu);
+ targetMenu.SecondaryCommands().Append(button);
};
+ const auto focusedProfile = _GetFocusedTabImpl()->GetFocusedProfile();
+ auto separatorItem = AppBarSeparator{};
+ auto activeProfiles = _settings.ActiveProfiles();
+ auto activeProfileCount = gsl::narrow_cast(activeProfiles.Size());
+ MUX::Controls::CommandBarFlyout splitPaneMenu{};
+
// Wire up each item to the action that should be performed. By actually
// connecting these to actions, we ensure the implementation is
// consistent. This also leaves room for customizing this menu with
// actions in the future.
- makeItem(RS_(L"SplitPaneText"), L"\xF246", ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate } });
- makeItem(RS_(L"DuplicateTabText"), L"\xF5ED", ActionAndArgs{ ShortcutAction::DuplicateTab, nullptr });
+ makeItem(RS_(L"DuplicateTabText"), L"\xF5ED", ActionAndArgs{ ShortcutAction::DuplicateTab, nullptr }, menu);
+
+ const auto focusedProfileName = focusedProfile.Name();
+ const auto focusedProfileIcon = focusedProfile.Icon();
+ const auto splitPaneDuplicateText = RS_(L"SplitPaneDuplicateText") + L" " + focusedProfileName; // SplitPaneDuplicateText
+
+ const auto splitPaneRightText = RS_(L"SplitPaneRightText");
+ const auto splitPaneDownText = RS_(L"SplitPaneDownText");
+ const auto splitPaneUpText = RS_(L"SplitPaneUpText");
+ const auto splitPaneLeftText = RS_(L"SplitPaneLeftText");
+ const auto splitPaneToolTipText = RS_(L"SplitPaneToolTipText");
+
+ MUX::Controls::CommandBarFlyout splitPaneContextMenu{};
+ makeItem(splitPaneRightText, focusedProfileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate, SplitDirection::Right, .5, nullptr } }, splitPaneContextMenu);
+ makeItem(splitPaneDownText, focusedProfileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate, SplitDirection::Down, .5, nullptr } }, splitPaneContextMenu);
+ makeItem(splitPaneUpText, focusedProfileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate, SplitDirection::Up, .5, nullptr } }, splitPaneContextMenu);
+ makeItem(splitPaneLeftText, focusedProfileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate, SplitDirection::Left, .5, nullptr } }, splitPaneContextMenu);
+
+ makeContextItem(splitPaneDuplicateText, focusedProfileIcon, splitPaneToolTipText, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Duplicate, SplitDirection::Automatic, .5, nullptr } }, splitPaneContextMenu, splitPaneMenu);
+
+ // add menu separator
+ const auto separatorAutoItem = AppBarSeparator{};
+
+ splitPaneMenu.SecondaryCommands().Append(separatorAutoItem);
+
+ for (auto profileIndex = 0; profileIndex < activeProfileCount; profileIndex++)
+ {
+ const auto profile = activeProfiles.GetAt(profileIndex);
+ const auto profileName = profile.Name();
+ const auto profileIcon = profile.Icon();
+
+ NewTerminalArgs args{};
+ args.Profile(profileName);
+
+ MUX::Controls::CommandBarFlyout splitPaneContextMenu{};
+ makeItem(splitPaneRightText, profileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Manual, SplitDirection::Right, .5, args } }, splitPaneContextMenu);
+ makeItem(splitPaneDownText, profileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Manual, SplitDirection::Down, .5, args } }, splitPaneContextMenu);
+ makeItem(splitPaneUpText, profileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Manual, SplitDirection::Up, .5, args } }, splitPaneContextMenu);
+ makeItem(splitPaneLeftText, profileIcon, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Manual, SplitDirection::Left, .5, args } }, splitPaneContextMenu);
+
+ makeContextItem(profileName, profileIcon, splitPaneToolTipText, ActionAndArgs{ ShortcutAction::SplitPane, SplitPaneArgs{ SplitType::Manual, SplitDirection::Automatic, .5, args } }, splitPaneContextMenu, splitPaneMenu);
+ }
+
+ makeMenuItem(RS_(L"SplitPaneText"), L"\xF246", splitPaneMenu, menu);
// Only wire up "Close Pane" if there's multiple panes.
if (_GetFocusedTabImpl()->GetLeafPaneCount() > 1)
{
- makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr });
+ MUX::Controls::CommandBarFlyout swapPaneMenu{};
+ const auto rootPane = _GetFocusedTabImpl()->GetRootPane();
+ const auto mruPanes = _GetFocusedTabImpl()->GetMruPanes();
+ auto activePane = _GetFocusedTabImpl()->GetActivePane();
+ rootPane->WalkTree([&](auto p) {
+ if (const auto& c{ p->GetTerminalControl() })
+ {
+ if (c == control)
+ {
+ activePane = p;
+ }
+ }
+ });
+
+ if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Down, mruPanes))
+ {
+ makeItem(RS_(L"SwapPaneDownText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Down } }, swapPaneMenu);
+ }
+
+ if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Right, mruPanes))
+ {
+ makeItem(RS_(L"SwapPaneRightText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Right } }, swapPaneMenu);
+ }
+
+ if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Up, mruPanes))
+ {
+ makeItem(RS_(L"SwapPaneUpText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Up } }, swapPaneMenu);
+ }
+
+ if (auto neighbor = rootPane->NavigateDirection(activePane, FocusDirection::Left, mruPanes))
+ {
+ makeItem(RS_(L"SwapPaneLeftText"), neighbor->GetProfile().Icon(), ActionAndArgs{ ShortcutAction::SwapPane, SwapPaneArgs{ FocusDirection::Left } }, swapPaneMenu);
+ }
+
+ makeMenuItem(RS_(L"SwapPaneText"), L"\xF1CB", swapPaneMenu, menu);
+
+ makeItem(RS_(L"TogglePaneZoomText"), L"\xE8A3", ActionAndArgs{ ShortcutAction::TogglePaneZoom, nullptr }, menu);
+ makeItem(RS_(L"CloseOtherPanesText"), L"\xE89F", ActionAndArgs{ ShortcutAction::CloseOtherPanes, nullptr }, menu);
+ makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr }, menu);
}
if (control.ConnectionState() >= ConnectionState::Closed)
{
- makeItem(RS_(L"RestartConnectionText"), L"\xE72C", ActionAndArgs{ ShortcutAction::RestartConnection, nullptr });
+ makeItem(RS_(L"RestartConnectionText"), L"\xE72C", ActionAndArgs{ ShortcutAction::RestartConnection, nullptr }, menu);
}
if (withSelection)
{
- makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr });
+ makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr }, menu);
}
- makeItem(RS_(L"TabClose"), L"\xE711", ActionAndArgs{ ShortcutAction::CloseTab, CloseTabArgs{ _GetFocusedTabIndex().value() } });
+ makeItem(RS_(L"TabClose"), L"\xE711", ActionAndArgs{ ShortcutAction::CloseTab, CloseTabArgs{ _GetFocusedTabIndex().value() } }, menu);
}
void TerminalPage::_PopulateQuickFixMenu(const TermControl& control,
diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h
index f38895a3da6..723df78c5a3 100644
--- a/src/cascadia/TerminalApp/TerminalTab.h
+++ b/src/cascadia/TerminalApp/TerminalTab.h
@@ -91,6 +91,7 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::TaskbarState GetCombinedTaskbarState() const;
std::shared_ptr GetRootPane() const { return _rootPane; }
+ std::vector GetMruPanes() const { return _mruPanes; }
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
diff --git a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw
index 90648381e1a..85446823b58 100644
--- a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw
@@ -262,10 +262,18 @@ Please either install the missing font or choose another one.
The tooltip for a paste button
+ Find...
+ The label of a button for searching for the text
+
+
Find...
The label of a button for searching for the selected text
+ Find
+ The tooltip for a button for searching for the text
+
+
Find
The tooltip for a button for searching for the selected text
@@ -334,4 +342,4 @@ Please either install the missing font or choose another one.
Suggested input: {0}
{Locked="{0}"} {0} will be replaced with a string of input that is suggested for the user to input
-
\ No newline at end of file
+
diff --git a/src/cascadia/TerminalControl/TermControl.xaml b/src/cascadia/TerminalControl/TermControl.xaml
index b0b24c47ced..16b85c138ce 100644
--- a/src/cascadia/TerminalControl/TermControl.xaml
+++ b/src/cascadia/TerminalControl/TermControl.xaml
@@ -51,6 +51,10 @@
x:Uid="SelectOutputButton"
Click="_SelectOutputHandler"
Icon="AlignLeft" />
+
@@ -64,10 +68,6 @@
Click="_PasteCommandHandler"
Icon="Paste" />
-
@@ -81,6 +81,10 @@
x:Uid="SelectOutputWithSelectionButton"
Click="_SelectOutputHandler"
Icon="AlignLeft" />
+
diff --git a/src/cascadia/TerminalControl/TerminalControlLib.vcxproj b/src/cascadia/TerminalControl/TerminalControlLib.vcxproj
index f585755f209..90d053424f9 100644
--- a/src/cascadia/TerminalControl/TerminalControlLib.vcxproj
+++ b/src/cascadia/TerminalControl/TerminalControlLib.vcxproj
@@ -9,7 +9,6 @@
StaticLibrary
Console
true
-
3
nested
-
-
true
true
-
-
@@ -143,7 +138,9 @@
-
+
+ Designer
+
@@ -183,9 +180,7 @@
-
-
-
+
\ No newline at end of file