diff --git a/src/cascadia/TerminalApp/App.cpp b/src/cascadia/TerminalApp/App.cpp index 421aa4577e1..70b60c00412 100644 --- a/src/cascadia/TerminalApp/App.cpp +++ b/src/cascadia/TerminalApp/App.cpp @@ -167,9 +167,12 @@ namespace winrt::TerminalApp::implementation } // Method Description: - // - Show a ContentDialog with a single button to dismiss. Uses the + // - Show a ContentDialog with buttons to take further action. Uses the // FrameworkElements provided as the title and content of this dialog, and - // displays a single button to dismiss. + // displays buttons (or a single button). Two buttons (primary and secondary) + // will be displayed if this is an warning dialog for closing the termimal, + // this allows the users to abondon the closing action. Otherwise, a single + // close button will be displayed. // - Only one dialog can be visible at a time. If another dialog is visible // when this is called, nothing happens. // Arguments: diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 1abce6291d3..908dce978c4 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -60,6 +60,13 @@ namespace winrt::TerminalApp::implementation args.Handled(true); } + void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/, + const TerminalApp::ActionEventArgs& args) + { + _CloseWindow(); + args.Handled(true); + } + void TerminalPage::_HandleScrollUp(const IInspectable& /*sender*/, const TerminalApp::ActionEventArgs& args) { diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index c461da5b42b..46e0acbfbe7 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -1,17 +1,17 @@  - @@ -193,4 +193,13 @@ Temporarily using the Windows Terminal default settings. Settings - + + Cancel + + + Close all + + + Do you want to close all tabs? + + \ No newline at end of file diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 1fe835defec..99ad7e4bf4d 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -182,6 +182,29 @@ namespace winrt::TerminalApp::implementation _showDialogHandlers(*this, dialog); } + // Method Description: + // - Displays a dialog for warnings found while closing the terminal app using + // key binding with multiple tabs opened. Display messages to warn user + // that more than 1 tab is opend, and once the user clicks the OK button, remove + // all the tabs and shut down and app. If cancel is clicked, the dialog will close + // - Only one dialog can be visible at a time. If another dialog is visible + // when this is called, nothing happens. See _ShowDialog for details + void TerminalPage::_ShowCloseWarningDialog() + { + auto title = _resourceLoader->GetLocalizedString(L"CloseWindowWarningTitle"); + auto primaryButtonText = _resourceLoader->GetLocalizedString(L"CloseAll"); + auto secondaryButtonText = _resourceLoader->GetLocalizedString(L"Cancel"); + + Controls::ContentDialog dialog; + dialog.Title(winrt::box_value(title)); + + dialog.PrimaryButtonText(primaryButtonText); + dialog.SecondaryButtonText(secondaryButtonText); + auto token = dialog.PrimaryButtonClick({ this, &TerminalPage::_CloseWarningPrimaryButtonOnClick }); + + _showDialogHandlers(*this, dialog); + } + // Method Description: // - Builds the flyout (dropdown) attached to the new tab button, and // attaches it to the button. Populates the flyout with one entry per @@ -500,6 +523,7 @@ namespace winrt::TerminalApp::implementation bindings.DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab }); bindings.CloseTab({ this, &TerminalPage::_HandleCloseTab }); bindings.ClosePane({ this, &TerminalPage::_HandleClosePane }); + bindings.CloseWindow({ this, &TerminalPage::_HandleCloseWindow }); bindings.ScrollUp({ this, &TerminalPage::_HandleScrollUp }); bindings.ScrollDown({ this, &TerminalPage::_HandleScrollDown }); bindings.NextTab({ this, &TerminalPage::_HandleNextTab }); @@ -590,25 +614,36 @@ namespace winrt::TerminalApp::implementation } // Method Description: - // - Removes the tab (both TerminalControl and XAML) + // - Look for the index of the input tabView in the tabs vector, + // and call _RemoveTabViewItemByIndex // Arguments: // - tabViewItem: the TabViewItem in the TabView that is being removed. void TerminalPage::_RemoveTabViewItem(const IInspectable& tabViewItem) + { + uint32_t tabIndexFromControl = 0; + _tabView.Items().IndexOf(tabViewItem, tabIndexFromControl); + + _RemoveTabViewItemByIndex(tabIndexFromControl); + } + + // Method Description: + // - Removes the tab (both TerminalControl and XAML) + // Arguments: + // - tabIndex: the index of the tab to be removed + void TerminalPage::_RemoveTabViewItemByIndex(uint32_t tabIndex) { // To close the window here, we need to close the hosting window. if (_tabs.size() == 1) { _lastTabClosedHandlers(*this, nullptr); } - uint32_t tabIndexFromControl = 0; - _tabView.Items().IndexOf(tabViewItem, tabIndexFromControl); - auto focusedTabIndex = _GetFocusedTabIndex(); // Removing the tab from the collection will destroy its control and disconnect its connection. - _tabs.erase(_tabs.begin() + tabIndexFromControl); - _tabView.Items().RemoveAt(tabIndexFromControl); + _tabs.erase(_tabs.begin() + tabIndex); + _tabView.Items().RemoveAt(tabIndex); - if (tabIndexFromControl == focusedTabIndex) + auto focusedTabIndex = _GetFocusedTabIndex(); + if (tabIndex == focusedTabIndex) { auto const tabCount = gsl::narrow_cast(_tabs.size()); if (focusedTabIndex >= tabCount) @@ -758,9 +793,8 @@ namespace winrt::TerminalApp::implementation // - Close the currently focused tab. Focus will move to the left, if possible. void TerminalPage::_CloseFocusedTab() { - int focusedTabIndex = _GetFocusedTabIndex(); - std::shared_ptr focusedTab{ _tabs[focusedTabIndex] }; - _RemoveTabViewItem(focusedTab->GetTabViewItem()); + uint32_t focusedTabIndex = _GetFocusedTabIndex(); + _RemoveTabViewItemByIndex(focusedTabIndex); } // Method Description: @@ -774,6 +808,32 @@ namespace winrt::TerminalApp::implementation focusedTab->ClosePane(); } + // Method Description: + // - Close the terminal app with keys. If there is more + // than one tab opened, show a warning dialog. + void TerminalPage::_CloseWindow() + { + if (_tabs.size() > 1) + { + _ShowCloseWarningDialog(); + } + else + { + _CloseAllTabs(); + } + } + + // Method Description: + // - Remove all the tabs opened and the terminal will terminate + // on its own when the last tab is closed. + void TerminalPage::_CloseAllTabs() + { + while (!_tabs.empty()) + { + _RemoveTabViewItemByIndex(0); + } + } + // Method Description: // - Move the viewport of the terminal of the currently focused tab up or // down a number of lines. Negative values of `delta` will move the @@ -1196,6 +1256,20 @@ namespace winrt::TerminalApp::implementation eventArgs.Cancel(true); } + // Method Description: + // - Called when the primary button of the content dialog is clicked. + // This calls _CloseAllTabs(), which closes all the tabs currently + // opened and then the Terminal app. This method will be called if + // the user confirms to close all the tabs. + // Arguments: + // - sender: unused + // - ContentDialogButtonClickEventArgs: unused + void TerminalPage::_CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog /* sender */, + Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs /* eventArgs*/) + { + _CloseAllTabs(); + } + // Method Description: // - Hook up keybindings, and refresh the UI of the terminal. // This includes update the settings of all the tabs according diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 244e8e25ddb..80022868c6e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -61,6 +61,7 @@ namespace winrt::TerminalApp::implementation std::shared_ptr _resourceLoader{ nullptr }; void _ShowAboutDialog(); + void _ShowCloseWarningDialog(); void _CreateNewTabFlyout(); void _OpenNewTabDropdown(); @@ -71,6 +72,7 @@ namespace winrt::TerminalApp::implementation void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs); void _FeedbackButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs); void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs); + void _CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs eventArgs); void _HookupKeyBindings(TerminalApp::AppKeyBindings bindings) noexcept; @@ -79,6 +81,7 @@ namespace winrt::TerminalApp::implementation void _UpdateTabView(); void _DuplicateTabViewItem(); void _RemoveTabViewItem(const IInspectable& tabViewItem); + void _RemoveTabViewItemByIndex(uint32_t tabIndex); void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr hostingTab); @@ -91,6 +94,8 @@ namespace winrt::TerminalApp::implementation void _SetFocusedTabIndex(int tabIndex); void _CloseFocusedTab(); void _CloseFocusedPane(); + void _CloseWindow(); + void _CloseAllTabs(); // Todo: add more event implementations here // MSFT:20641986: Add keybindings for New Window @@ -143,6 +148,7 @@ namespace winrt::TerminalApp::implementation void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); + void _HandleCloseWindow(const IInspectable&, const TerminalApp::ActionEventArgs& args); #pragma endregion }; }