Introduce duplicate tab menu (#9388)
## PR Checklist * [x] Closes https://github.com/microsoft/terminal/issues/9373 * [x] CLA signed. * [ ] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [ ] I've discussed this with core contributors already.
This commit is contained in:
parent
1202f89399
commit
629c06d0ad
|
@ -330,7 +330,7 @@ namespace TerminalAppLocalTests
|
|||
{
|
||||
// * Create a tab with a profile with GUID 1
|
||||
// * Reload the settings so that GUID 1 is no longer in the list of profiles
|
||||
// * Try calling _DuplicateTabViewItem on tab 1
|
||||
// * Try calling _DuplicateFocusedTab on tab 1
|
||||
// * No new tab should be created (and more importantly, the app should not crash)
|
||||
//
|
||||
// Created to test GH#2455
|
||||
|
@ -392,7 +392,7 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Duplicate the first tab");
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_DuplicateTabViewItem();
|
||||
page->_DuplicateFocusedTab();
|
||||
VERIFY_ARE_EQUAL(2u, page->_tabs.Size());
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
|
@ -407,7 +407,7 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(L"Duplicate the tab, and don't crash");
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_DuplicateTabViewItem();
|
||||
page->_DuplicateFocusedTab();
|
||||
VERIFY_ARE_EQUAL(2u, page->_tabs.Size(), L"We should gracefully do nothing here - the profile no longer exists.");
|
||||
});
|
||||
VERIFY_SUCCEEDED(result);
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void TerminalPage::_HandleDuplicateTab(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_DuplicateTabViewItem();
|
||||
_DuplicateFocusedTab();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -211,6 +211,9 @@
|
|||
<data name="RenameTabText" xml:space="preserve">
|
||||
<value>Rename Tab</value>
|
||||
</data>
|
||||
<data name="DuplicateTabText" xml:space="preserve">
|
||||
<value>Duplicate Tab</value>
|
||||
</data>
|
||||
<data name="InvalidBackgroundImage" xml:space="preserve">
|
||||
<value>Found a profile with an invalid "backgroundImage". Defaulting that profile to have no background image. Make sure that when setting a "backgroundImage", the value is a valid file path to an image.</value>
|
||||
<comment>{Locked="\"backgroundImage\""}</comment>
|
||||
|
|
|
@ -847,6 +847,16 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
});
|
||||
|
||||
newTabImpl->DuplicateRequested([weakTab, weakThis{ get_weak() }]() {
|
||||
auto page{ weakThis.get() };
|
||||
auto tab{ weakTab.get() };
|
||||
|
||||
if (page && tab)
|
||||
{
|
||||
page->_DuplicateTab(*tab);
|
||||
}
|
||||
});
|
||||
|
||||
auto tabViewItem = newTabImpl->TabViewItem();
|
||||
_tabView.TabItems().Append(tabViewItem);
|
||||
|
||||
|
@ -1228,43 +1238,52 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Duplicates the current focused tab
|
||||
void TerminalPage::_DuplicateTabViewItem()
|
||||
void TerminalPage::_DuplicateFocusedTab()
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
// settings so we can duplicate this tab/pane.
|
||||
//
|
||||
// Currently, if the profile doesn't exist anymore in our
|
||||
// settings, we'll silently do nothing.
|
||||
//
|
||||
// In the future, it will be preferable to just duplicate the
|
||||
// current control's settings, but we can't do that currently,
|
||||
// because we won't be able to create a new instance of the
|
||||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
|
||||
const auto& profileGuid = terminalTab->GetFocusedProfile();
|
||||
if (profileGuid.has_value())
|
||||
{
|
||||
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
|
||||
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
settings.StartingDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
_DuplicateTab(*terminalTab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Duplicates specified tab
|
||||
// Arguments:
|
||||
// - tab: tab to duplicate
|
||||
void TerminalPage::_DuplicateTab(const TerminalTab& tab)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
// settings so we can duplicate this tab/pane.
|
||||
//
|
||||
// Currently, if the profile doesn't exist anymore in our
|
||||
// settings, we'll silently do nothing.
|
||||
//
|
||||
// In the future, it will be preferable to just duplicate the
|
||||
// current control's settings, but we can't do that currently,
|
||||
// because we won't be able to create a new instance of the
|
||||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
|
||||
const auto& profileGuid = tab.GetFocusedProfile();
|
||||
if (profileGuid.has_value())
|
||||
{
|
||||
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
|
||||
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
settings.StartingDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Look for the index of the input tabView in the tabs vector,
|
||||
// and call _RemoveTab
|
||||
|
|
|
@ -176,7 +176,8 @@ namespace winrt::TerminalApp::implementation
|
|||
Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::Profile> profiles,
|
||||
Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::ColorScheme> schemes);
|
||||
|
||||
void _DuplicateTabViewItem();
|
||||
void _DuplicateFocusedTab();
|
||||
void _DuplicateTab(const TerminalTab& tab);
|
||||
void _RemoveTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem);
|
||||
winrt::Windows::Foundation::IAsyncAction _RemoveTab(winrt::TerminalApp::TabBase tab);
|
||||
winrt::fire_and_forget _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);
|
||||
|
|
|
@ -841,11 +841,29 @@ namespace winrt::TerminalApp::implementation
|
|||
renameTabMenuItem.Icon(renameTabSymbol);
|
||||
}
|
||||
|
||||
Controls::MenuFlyoutItem duplicateTabMenuItem;
|
||||
{
|
||||
// "Duplicate Tab"
|
||||
Controls::FontIcon duplicateTabSymbol;
|
||||
duplicateTabSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
||||
duplicateTabSymbol.Glyph(L"\xF5ED");
|
||||
|
||||
duplicateTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_DuplicateRequestedHandlers();
|
||||
}
|
||||
});
|
||||
duplicateTabMenuItem.Text(RS_(L"DuplicateTabText"));
|
||||
duplicateTabMenuItem.Icon(duplicateTabSymbol);
|
||||
}
|
||||
|
||||
// Build the menu
|
||||
Controls::MenuFlyout newTabFlyout;
|
||||
Controls::MenuFlyoutSeparator menuSeparator;
|
||||
newTabFlyout.Items().Append(chooseColorMenuItem);
|
||||
newTabFlyout.Items().Append(renameTabMenuItem);
|
||||
newTabFlyout.Items().Append(duplicateTabMenuItem);
|
||||
newTabFlyout.Items().Append(menuSeparator);
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
|
@ -1203,4 +1221,5 @@ namespace winrt::TerminalApp::implementation
|
|||
DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
|
||||
DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>);
|
||||
DEFINE_EVENT(TerminalTab, TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
|
||||
DEFINE_EVENT(TerminalTab, DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace winrt::TerminalApp::implementation
|
|||
DECLARE_EVENT(ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
|
||||
DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>);
|
||||
DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
|
||||
DECLARE_EVENT(DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
|
||||
FORWARDED_TYPED_EVENT(TabRenamerDeactivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, (&_headerControl), RenameEnded);
|
||||
|
||||
private:
|
||||
|
@ -143,6 +144,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void _RecalculateAndApplyReadOnly();
|
||||
|
||||
void _DuplicateTab();
|
||||
|
||||
friend class ::TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue