diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 9fa780a3a..5f325b1a6 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -662,10 +662,13 @@ Open a new tab in given starting directory + + Split Tab + Open a new window with given starting directory Split the window and start in given directory - \ No newline at end of file + diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp index dd3a7aa7c..b93f50cab 100644 --- a/src/cascadia/TerminalApp/TabManagement.cpp +++ b/src/cascadia/TerminalApp/TabManagement.cpp @@ -192,6 +192,16 @@ namespace winrt::TerminalApp::implementation } }); + newTabImpl->SplitTabRequested([weakTab, weakThis{ get_weak() }]() { + auto page{ weakThis.get() }; + auto tab{ weakTab.get() }; + + if (page && tab) + { + page->_SplitTab(*tab); + } + }); + auto tabViewItem = newTabImpl->TabViewItem(); _tabView.TabItems().Append(tabViewItem); @@ -357,6 +367,20 @@ namespace winrt::TerminalApp::implementation CATCH_LOG(); } + // Method Description: + // - Sets the specified tab as the focused tab and splits its active pane + // Arguments: + // - tab: tab to split + void TerminalPage::_SplitTab(TerminalTab& tab) + { + try + { + _SetFocusedTab(tab); + _SplitPane(tab, SplitState::Automatic, SplitType::Duplicate); + } + CATCH_LOG(); + } + // Method Description: // - Removes the tab (both TerminalControl and XAML) after prompting for approval // Arguments: diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 281189920..96e5f38e0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1238,6 +1238,33 @@ namespace winrt::TerminalApp::implementation return; } + _SplitPane(*focusedTab, splitType, splitMode, splitSize, newTerminalArgs); + } + + // Method Description: + // - Split the focused pane of the given tab, either horizontally or vertically, and place the + // given TermControl into the newly created pane. + // - If splitType == SplitState::None, this method does nothing. + // Arguments: + // - tab: The tab that is going to be split. + // - splitType: one value from the TerminalApp::SplitState enum, indicating how the + // new pane should be split from its parent. + // - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane. + // - newTerminalArgs: An object that may contain a blob of parameters to + // control which profile is created and with possible other + // configurations. See CascadiaSettings::BuildSettings for more details. + void TerminalPage::_SplitPane(TerminalTab& tab, + const SplitState splitType, + const SplitType splitMode, + const float splitSize, + const NewTerminalArgs& newTerminalArgs) + { + // Do nothing if we're requesting no split. + if (splitType == SplitState::None) + { + return; + } + try { TerminalSettingsCreateResult controlSettings{ nullptr }; @@ -1246,12 +1273,12 @@ namespace winrt::TerminalApp::implementation if (splitMode == SplitType::Duplicate) { - std::optional current_guid = focusedTab->GetFocusedProfile(); + std::optional current_guid = tab.GetFocusedProfile(); if (current_guid) { profileFound = true; controlSettings = TerminalSettings::CreateWithProfileByID(_settings, current_guid.value(), *_bindings); - const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory(); + const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory(); const auto validWorkingDirectory = !workingDirectory.empty(); if (validWorkingDirectory) { @@ -1287,10 +1314,10 @@ namespace winrt::TerminalApp::implementation auto realSplitType = splitType; if (realSplitType == SplitState::Automatic) { - realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace); + realSplitType = tab.PreCalculateAutoSplit(availableSpace); } - const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, splitSize, availableSpace); + const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace); if (!canSplit) { return; @@ -1299,11 +1326,11 @@ namespace winrt::TerminalApp::implementation auto newControl = _InitControl(controlSettings, controlConnection); // Hookup our event handlers to the new terminal - _RegisterTerminalEvents(newControl, *focusedTab); + _RegisterTerminalEvents(newControl, tab); _UnZoomIfNeeded(); - focusedTab->SplitPane(realSplitType, splitSize, realGuid, newControl); + tab.SplitPane(realSplitType, splitSize, realGuid, newControl); } CATCH_LOG(); } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index aa2db9529..d6476b5ad 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -219,6 +219,8 @@ namespace winrt::TerminalApp::implementation void _DuplicateFocusedTab(); void _DuplicateTab(const TerminalTab& tab); + void _SplitTab(TerminalTab& tab); + winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab); void _CloseTabAtIndex(uint32_t index); void _RemoveTab(const winrt::TerminalApp::TabBase& tab); @@ -254,6 +256,11 @@ namespace winrt::TerminalApp::implementation const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const float splitSize = 0.5f, const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); + void _SplitPane(TerminalTab& tab, + const Microsoft::Terminal::Settings::Model::SplitState splitType, + const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, + const float splitSize = 0.5f, + const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction); void _ToggleSplitOrientation(); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 4e420c5c2..ad4595a1b 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -936,12 +936,30 @@ namespace winrt::TerminalApp::implementation duplicateTabMenuItem.Icon(duplicateTabSymbol); } + Controls::MenuFlyoutItem splitTabMenuItem; + { + // "Split Tab" + Controls::FontIcon splitTabSymbol; + splitTabSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" }); + splitTabSymbol.Glyph(L"\xF246"); // ViewDashboard + + splitTabMenuItem.Click([weakThis](auto&&, auto&&) { + if (auto tab{ weakThis.get() }) + { + tab->_SplitTabRequestedHandlers(); + } + }); + splitTabMenuItem.Text(RS_(L"SplitTabText")); + splitTabMenuItem.Icon(splitTabSymbol); + } + // Build the menu Controls::MenuFlyout contextMenuFlyout; Controls::MenuFlyoutSeparator menuSeparator; contextMenuFlyout.Items().Append(chooseColorMenuItem); contextMenuFlyout.Items().Append(renameTabMenuItem); contextMenuFlyout.Items().Append(duplicateTabMenuItem); + contextMenuFlyout.Items().Append(splitTabMenuItem); contextMenuFlyout.Items().Append(menuSeparator); // GH#5750 - When the context menu is dismissed with ESC, toss the focus @@ -1315,4 +1333,5 @@ namespace winrt::TerminalApp::implementation DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>); DEFINE_EVENT(TerminalTab, TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>); DEFINE_EVENT(TerminalTab, DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>); + DEFINE_EVENT(TerminalTab, SplitTabRequested, _SplitTabRequestedHandlers, winrt::delegate<>); } diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index 3ef935364..f3cee7555 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -94,6 +94,7 @@ namespace winrt::TerminalApp::implementation DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>); DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>); DECLARE_EVENT(DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>); + DECLARE_EVENT(SplitTabRequested, _SplitTabRequestedHandlers, winrt::delegate<>); TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable); private: