From 81ca24b06abba5935d504ff7f1643fad51d7c73a Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Thu, 29 Oct 2020 16:38:13 -0700 Subject: [PATCH] Make ITab an unsealed runtimeclass (#8053) `TerminalTab` and `SettingsTab` share some implementation details. The close submenu introduced in #7728 is a good example of functionality that is consistent across all tabs. This PR transforms `ITab` from an interface, into an [unsealed runtime class] to de-duplicate some functionality. Most of the logic from `SettingsTab` was moved there because I expect the default behavior of a tab to resemble the `SettingsTab` over a `TerminalTab`. ## References Verified that Close submenu work was transferred over (#7728, #7961, #8010). ## Validation Steps Performed Check close submenu on first/last tab when multiple tabs are open. Closes #7969 [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes --- .../actions/spell-check/dictionary/apis.txt | 1 + src/cascadia/TerminalApp/SettingsTab.cpp | 140 ++--------------- src/cascadia/TerminalApp/SettingsTab.h | 33 +--- src/cascadia/TerminalApp/SettingsTab.idl | 4 +- src/cascadia/TerminalApp/Tab.idl | 18 --- src/cascadia/TerminalApp/TabBase.cpp | 148 ++++++++++++++++++ src/cascadia/TerminalApp/TabBase.h | 57 +++++++ .../TerminalApp/{ITab.idl => TabBase.idl} | 9 +- .../TerminalApp/TerminalAppLib.vcxproj | 8 +- src/cascadia/TerminalApp/TerminalPage.cpp | 18 ++- src/cascadia/TerminalApp/TerminalPage.h | 8 +- src/cascadia/TerminalApp/TerminalTab.cpp | 85 ---------- src/cascadia/TerminalApp/TerminalTab.h | 33 +--- src/cascadia/TerminalApp/TerminalTab.idl | 4 +- src/cascadia/inc/cppwinrt_utils.h | 2 +- 15 files changed, 259 insertions(+), 309 deletions(-) delete mode 100644 src/cascadia/TerminalApp/Tab.idl create mode 100644 src/cascadia/TerminalApp/TabBase.cpp create mode 100644 src/cascadia/TerminalApp/TabBase.h rename src/cascadia/TerminalApp/{ITab.idl => TabBase.idl} (65%) diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt index affb621171c..ffce734db6d 100644 --- a/.github/actions/spell-check/dictionary/apis.txt +++ b/.github/actions/spell-check/dictionary/apis.txt @@ -46,6 +46,7 @@ oaidl ocidl otms OUTLINETEXTMETRICW +overridable PAGESCROLL RETURNCMD rfind diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp index 58c09267622..dd78edabf98 100644 --- a/src/cascadia/TerminalApp/SettingsTab.cpp +++ b/src/cascadia/TerminalApp/SettingsTab.cpp @@ -31,19 +31,6 @@ namespace winrt::TerminalApp::implementation _CreateIcon(); } - // Method Description: - // - Initializes a TabViewItem for this Tab instance. - // Arguments: - // - - // Return Value: - // - - void SettingsTab::_MakeTabViewItem() - { - TabViewItem(::winrt::MUX::Controls::TabViewItem{}); - Title(RS_(L"SettingsTab")); - TabViewItem().Header(winrt::box_value(Title())); - } - // Method Description: // - Focus the settings UI // Arguments: @@ -56,13 +43,21 @@ namespace winrt::TerminalApp::implementation if (_focusState != FocusState::Unfocused) { - Content().Focus(focusState); + Content().as().Focus(focusState); } } - WUX::FocusState SettingsTab::FocusState() const noexcept + // Method Description: + // - Initializes a TabViewItem for this Tab instance. + // Arguments: + // - + // Return Value: + // - + void SettingsTab::_MakeTabViewItem() { - return _focusState; + TabViewItem(::winrt::MUX::Controls::TabViewItem{}); + Title(RS_(L"SettingsTab")); + TabViewItem().Header(winrt::box_value(Title())); } // Method Description: @@ -90,117 +85,4 @@ namespace winrt::TerminalApp::implementation SwitchToTabCommand().Icon(glyph); } } - - // Method Description: - // - Prepares this tab for being removed from the UI hierarchy - void SettingsTab::Shutdown() - { - // TODO: Does/Will the settings UI need some shutdown procedures? - Content(nullptr); - _ClosedHandlers(nullptr, nullptr); - } - - // Method Description: - // - Creates a context menu attached to the tab. - // Currently contains elements allowing the user to close the selected tab - // Arguments: - // - - // Return Value: - // - - void SettingsTab::_CreateContextMenu() - { - auto weakThis{ get_weak() }; - - // Close - Controls::MenuFlyoutItem closeTabMenuItem; - Controls::FontIcon closeSymbol; - closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" }); - closeSymbol.Glyph(L"\xE8BB"); - - closeTabMenuItem.Click([weakThis](auto&&, auto&&) { - if (auto tab{ weakThis.get() }) - { - tab->_ClosedHandlers(nullptr, nullptr); - } - }); - closeTabMenuItem.Text(RS_(L"TabClose")); - closeTabMenuItem.Icon(closeSymbol); - - // Build the menu - Controls::MenuFlyout newTabFlyout; - newTabFlyout.Items().Append(_CreateCloseSubMenu()); - newTabFlyout.Items().Append(closeTabMenuItem); - TabViewItem().ContextFlyout(newTabFlyout); - } - - // Method Description: - // - Creates a sub-menu containing menu items to close multiple tabs - // Arguments: - // - - // Return Value: - // - the created MenuFlyoutSubItem - Controls::MenuFlyoutSubItem SettingsTab::_CreateCloseSubMenu() - { - auto weakThis{ get_weak() }; - - // Close tabs after - _closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) { - if (auto tab{ weakThis.get() }) - { - tab->_CloseTabsAfter(); - } - }); - _closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter")); - - // Close other tabs - _closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) { - if (auto tab{ weakThis.get() }) - { - tab->_CloseOtherTabs(); - } - }); - _closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther")); - - Controls::MenuFlyoutSubItem closeSubMenu; - closeSubMenu.Text(RS_(L"TabCloseSubMenu")); - closeSubMenu.Items().Append(_closeTabsAfterMenuItem); - closeSubMenu.Items().Append(_closeOtherTabsMenuItem); - - return closeSubMenu; - } - - // Method Description: - // - Enable the Close menu items based on tab index and total number of tabs - // Arguments: - // - - // Return Value: - // - - void SettingsTab::_EnableCloseMenuItems() - { - // 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); - } - - void SettingsTab::_CloseTabsAfter() - { - CloseTabsAfterArgs args{ _TabViewIndex }; - ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args }; - - _dispatch.DoAction(closeTabsAfter); - } - - void SettingsTab::_CloseOtherTabs() - { - CloseOtherTabsArgs args{ _TabViewIndex }; - ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args }; - - _dispatch.DoAction(closeOtherTabs); - } - - void SettingsTab::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch) - { - _dispatch = dispatch; - } } diff --git a/src/cascadia/TerminalApp/SettingsTab.h b/src/cascadia/TerminalApp/SettingsTab.h index ea2f6dc8af3..28399b426a8 100644 --- a/src/cascadia/TerminalApp/SettingsTab.h +++ b/src/cascadia/TerminalApp/SettingsTab.h @@ -16,6 +16,7 @@ Author(s): --*/ #pragma once +#include "TabBase.h" #include "SettingsTab.g.h" #include #include @@ -23,43 +24,15 @@ Author(s): namespace winrt::TerminalApp::implementation { - struct SettingsTab : SettingsTabT + struct SettingsTab : SettingsTabT { public: SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI); - void Focus(winrt::Windows::UI::Xaml::FocusState focusState); - winrt::Windows::UI::Xaml::FocusState FocusState() const noexcept; - void Shutdown(); - - void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch); - WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler); - WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); - - GETSET_PROPERTY(winrt::hstring, Title); - GETSET_PROPERTY(winrt::hstring, Icon); - GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::Command, SwitchToTabCommand, nullptr); - GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr); - GETSET_PROPERTY(winrt::Windows::UI::Xaml::Controls::Page, Content, nullptr); - - // The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector. - // This is needed since Tab is going to be managing its own SwitchToTab command. - OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewIndex, _PropertyChangedHandlers, 0); - // The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector. - OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewNumTabs, _PropertyChangedHandlers, 0); + void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override; private: - 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::TerminalApp::ShortcutActionDispatch _dispatch; - void _MakeTabViewItem(); - void _CreateContextMenu(); - winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _CreateCloseSubMenu(); - void _EnableCloseMenuItems(); winrt::fire_and_forget _CreateIcon(); - void _CloseTabsAfter(); - void _CloseOtherTabs(); }; } diff --git a/src/cascadia/TerminalApp/SettingsTab.idl b/src/cascadia/TerminalApp/SettingsTab.idl index bea4f29ef65..38d53e7b64e 100644 --- a/src/cascadia/TerminalApp/SettingsTab.idl +++ b/src/cascadia/TerminalApp/SettingsTab.idl @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "ITab.idl"; +import "TabBase.idl"; namespace TerminalApp { - [default_interface] runtimeclass SettingsTab : ITab + [default_interface] runtimeclass SettingsTab : TabBase { } } diff --git a/src/cascadia/TerminalApp/Tab.idl b/src/cascadia/TerminalApp/Tab.idl deleted file mode 100644 index 4e2bd8bdb0d..00000000000 --- a/src/cascadia/TerminalApp/Tab.idl +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -import "ShortcutActionDispatch.idl"; - -namespace TerminalApp -{ - [default_interface] runtimeclass Tab : Windows.UI.Xaml.Data.INotifyPropertyChanged - { - String Title { get; }; - Windows.UI.Xaml.Controls.IconSource IconSource { get; }; - Microsoft.Terminal.Settings.Model.Command SwitchToTabCommand { get; }; - UInt32 TabViewIndex { get; }; - - Windows.UI.Xaml.FrameworkElement Content { get; }; - - void SetDispatch(ShortcutActionDispatch dispatch); - } -} diff --git a/src/cascadia/TerminalApp/TabBase.cpp b/src/cascadia/TerminalApp/TabBase.cpp new file mode 100644 index 00000000000..84d6a8b4c4d --- /dev/null +++ b/src/cascadia/TerminalApp/TabBase.cpp @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include +#include "TabBase.h" +#include "TabBase.g.cpp" + +using namespace winrt; +using namespace winrt::Windows::UI::Xaml; +using namespace winrt::Windows::UI::Core; +using namespace winrt::Microsoft::Terminal::TerminalControl; +using namespace winrt::Microsoft::Terminal::Settings::Model; +using namespace winrt::Windows::System; + +namespace winrt +{ + namespace MUX = Microsoft::UI::Xaml; + namespace WUX = Windows::UI::Xaml; +} + +namespace winrt::TerminalApp::implementation +{ + WUX::FocusState TabBase::FocusState() const noexcept + { + return _focusState; + } + + // Method Description: + // - Prepares this tab for being removed from the UI hierarchy + void TabBase::Shutdown() + { + Content(nullptr); + _ClosedHandlers(nullptr, nullptr); + } + + // Method Description: + // - Creates a context menu attached to the tab. + // Currently contains elements allowing the user to close the selected tab + // Arguments: + // - + // Return Value: + // - + void TabBase::_CreateContextMenu() + { + auto weakThis{ get_weak() }; + + // Close + Controls::MenuFlyoutItem closeTabMenuItem; + Controls::FontIcon closeSymbol; + closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" }); + closeSymbol.Glyph(L"\xE8BB"); + + closeTabMenuItem.Click([weakThis](auto&&, auto&&) { + if (auto tab{ weakThis.get() }) + { + tab->_ClosedHandlers(nullptr, nullptr); + } + }); + closeTabMenuItem.Text(RS_(L"TabClose")); + closeTabMenuItem.Icon(closeSymbol); + + // Build the menu + Controls::MenuFlyout newTabFlyout; + newTabFlyout.Items().Append(_CreateCloseSubMenu()); + newTabFlyout.Items().Append(closeTabMenuItem); + TabViewItem().ContextFlyout(newTabFlyout); + } + + // Method Description: + // - Creates a sub-menu containing menu items to close multiple tabs + // Arguments: + // - + // Return Value: + // - the created MenuFlyoutSubItem + Controls::MenuFlyoutSubItem TabBase::_CreateCloseSubMenu() + { + auto weakThis{ get_weak() }; + + // Close tabs after + _closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) { + if (auto tab{ weakThis.get() }) + { + tab->_CloseTabsAfter(); + } + }); + _closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter")); + + // Close other tabs + _closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) { + if (auto tab{ weakThis.get() }) + { + tab->_CloseOtherTabs(); + } + }); + _closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther")); + + Controls::MenuFlyoutSubItem closeSubMenu; + closeSubMenu.Text(RS_(L"TabCloseSubMenu")); + closeSubMenu.Items().Append(_closeTabsAfterMenuItem); + closeSubMenu.Items().Append(_closeOtherTabsMenuItem); + + return closeSubMenu; + } + + // Method Description: + // - Enable the Close menu items based on tab index and total number of tabs + // Arguments: + // - + // Return Value: + // - + void TabBase::_EnableCloseMenuItems() + { + // 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); + } + + void TabBase::_CloseTabsAfter() + { + CloseTabsAfterArgs args{ _TabViewIndex }; + ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args }; + + _dispatch.DoAction(closeTabsAfter); + } + + void TabBase::_CloseOtherTabs() + { + CloseOtherTabsArgs args{ _TabViewIndex }; + ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args }; + + _dispatch.DoAction(closeOtherTabs); + } + + void TabBase::UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs) + { + TabViewIndex(idx); + TabViewNumTabs(numTabs); + _EnableCloseMenuItems(); + SwitchToTabCommand().Action().Args().as().TabIndex(idx); + } + + void TabBase::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch) + { + _dispatch = dispatch; + } +} diff --git a/src/cascadia/TerminalApp/TabBase.h b/src/cascadia/TerminalApp/TabBase.h new file mode 100644 index 00000000000..d4697fadcd6 --- /dev/null +++ b/src/cascadia/TerminalApp/TabBase.h @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once +#include "inc/cppwinrt_utils.h" +#include "TabBase.g.h" + +// fwdecl unittest classes +namespace TerminalAppLocalTests +{ + class TabTests; +}; + +namespace winrt::TerminalApp::implementation +{ + struct TabBase : TabBaseT + { + public: + virtual void Focus(winrt::Windows::UI::Xaml::FocusState focusState) = 0; + winrt::Windows::UI::Xaml::FocusState FocusState() const noexcept; + + virtual void Shutdown(); + void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch); + + void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs); + + WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler); + WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); + + // The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector. + // This is needed since Tab is going to be managing its own SwitchToTab command. + GETSET_PROPERTY(uint32_t, TabViewIndex, 0); + // The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector. + GETSET_PROPERTY(uint32_t, TabViewNumTabs, 0); + + OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr); + GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr); + + OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, _PropertyChangedHandlers, nullptr); + + protected: + 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::TerminalApp::ShortcutActionDispatch _dispatch; + + virtual void _CreateContextMenu(); + winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _CreateCloseSubMenu(); + void _EnableCloseMenuItems(); + void _CloseTabsAfter(); + void _CloseOtherTabs(); + + friend class ::TerminalAppLocalTests::TabTests; + }; +} diff --git a/src/cascadia/TerminalApp/ITab.idl b/src/cascadia/TerminalApp/TabBase.idl similarity index 65% rename from src/cascadia/TerminalApp/ITab.idl rename to src/cascadia/TerminalApp/TabBase.idl index f4204397c03..040a2559120 100644 --- a/src/cascadia/TerminalApp/ITab.idl +++ b/src/cascadia/TerminalApp/TabBase.idl @@ -4,7 +4,7 @@ import "ShortcutActionDispatch.idl"; namespace TerminalApp { - interface ITab + unsealed runtimeclass TabBase : Windows.UI.Xaml.Data.INotifyPropertyChanged { String Title { get; }; String Icon { get; }; @@ -13,8 +13,11 @@ namespace TerminalApp Windows.UI.Xaml.FrameworkElement Content { get; }; Windows.UI.Xaml.FocusState FocusState { get; }; - void Focus(Windows.UI.Xaml.FocusState focusState); - void Shutdown(); + UInt32 TabViewIndex; + UInt32 TabViewNumTabs; + + overridable void Focus(Windows.UI.Xaml.FocusState focusState); + overridable void Shutdown(); void SetDispatch(ShortcutActionDispatch dispatch); } diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 2e4e5f568f6..f8b4d6faafa 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -73,6 +73,9 @@ SettingsTab.idl + + TabBase.idl + TerminalTab.idl @@ -133,6 +136,9 @@ SettingsTab.idl + + TabBase.idl + TerminalTab.idl @@ -204,7 +210,7 @@ MinMaxCloseControl.xaml Code - + TerminalPage.xaml diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index a44c03af939..d7a6e10e0d0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -43,7 +43,7 @@ namespace winrt namespace winrt::TerminalApp::implementation { TerminalPage::TerminalPage() : - _tabs{ winrt::single_threaded_observable_vector() }, + _tabs{ winrt::single_threaded_observable_vector() }, _mruTabActions{ winrt::single_threaded_vector() }, _startupActions{ winrt::single_threaded_vector() } { @@ -1325,7 +1325,7 @@ namespace winrt::TerminalApp::implementation // Method Description: // - returns a com_ptr to the currently focused tab. This might return null, // so make sure to check the result! - ITab TerminalPage::_GetFocusedTab() + winrt::TerminalApp::TabBase TerminalPage::_GetFocusedTab() { if (auto index{ _GetFocusedTabIndex() }) { @@ -2571,8 +2571,9 @@ namespace winrt::TerminalApp::implementation const uint32_t size = _tabs.Size(); for (uint32_t i = 0; i < size; ++i) { - auto command = _tabs.GetAt(i).SwitchToTabCommand(); - command.Action().Args().as().TabIndex(i); + auto tab{ _tabs.GetAt(i) }; + auto tabImpl{ winrt::get_self(tab) }; + tabImpl->UpdateTabViewIndex(i, size); } } @@ -2603,6 +2604,11 @@ namespace winrt::TerminalApp::implementation _tabs.Append(*newTabImpl); _mruTabActions.Append(newTabImpl->SwitchToTabCommand()); + newTabImpl->SetDispatch(*_actionDispatch); + + // Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command. + _UpdateTabIndices(); + // Don't capture a strong ref to the tab. If the tab is removed as this // is called, we don't really care anymore about handling the event. auto weakTab = make_weak(newTabImpl); @@ -2643,7 +2649,7 @@ namespace winrt::TerminalApp::implementation // Return Value: // - If the tab is a TerminalTab, a com_ptr to the implementation type. // If the tab is not a TerminalTab, nullptr - winrt::com_ptr TerminalPage::_GetTerminalTabImpl(const ITab& tab) const + winrt::com_ptr TerminalPage::_GetTerminalTabImpl(const TerminalApp::TabBase& tab) const { if (auto terminalTab = tab.try_as()) { @@ -2685,7 +2691,7 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - void TerminalPage::_MakeSwitchToTabCommand(const ITab& tab, const uint32_t index) + void TerminalPage::_MakeSwitchToTabCommand(const TerminalApp::TabBase& tab, const uint32_t index) { SwitchToTabArgs args{ index }; ActionAndArgs focusTabAction{ ShortcutAction::SwitchToTab, args }; diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index fd715a1e506..1a7af1d0607 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -96,9 +96,9 @@ namespace winrt::TerminalApp::implementation Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr }; - Windows::Foundation::Collections::IObservableVector _tabs; + Windows::Foundation::Collections::IObservableVector _tabs; Windows::Foundation::Collections::IVector _mruTabActions; - winrt::com_ptr _GetTerminalTabImpl(const ITab& tab) const; + winrt::com_ptr _GetTerminalTabImpl(const TerminalApp::TabBase& tab) const; void _UpdateTabIndices(); @@ -167,7 +167,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::TerminalControl::TermControl _GetActiveControl(); std::optional _GetFocusedTabIndex() const noexcept; - ITab _GetFocusedTab(); + TerminalApp::TabBase _GetFocusedTab(); winrt::fire_and_forget _SetFocusedTabIndex(const uint32_t tabIndex); void _CloseFocusedTab(); void _CloseFocusedPane(); @@ -222,7 +222,7 @@ namespace winrt::TerminalApp::implementation void _ReapplyCompactTabSize(); - void _MakeSwitchToTabCommand(const ITab& tab, const uint32_t index); + void _MakeSwitchToTabCommand(const TerminalApp::TabBase& tab, const uint32_t index); static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll); static uint32_t _ReadSystemRowsToScroll(); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 579056ab837..567d48a7ba1 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -88,20 +88,6 @@ namespace winrt::TerminalApp::implementation _BindEventHandlers(control); } - // Method Description: - // - Returns the focus state of this Tab. Unfocused means this tab is not focused, - // and any other FocusState means that this tab is focused. For any set of tabs, - // there should only be one tab that is marked as focused, though each tab has - // no control over the other tabs in the set. - // Arguments: - // - - // Return Value: - // - A FocusState enum value - WUX::FocusState TerminalTab::FocusState() const noexcept - { - return _focusState; - } - // Method Description: // - Updates our focus state. If we're gaining focus, make sure to transfer // focus to the last focused terminal control in our tree of controls. @@ -583,56 +569,6 @@ namespace winrt::TerminalApp::implementation TabViewItem().ContextFlyout(newTabFlyout); } - // Method Description: - // - Creates a sub-menu containing menu items to close multiple tabs - // Arguments: - // - - // Return Value: - // - the created MenuFlyoutSubItem - Controls::MenuFlyoutSubItem TerminalTab::_CreateCloseSubMenu() - { - auto weakThis{ get_weak() }; - - // Close tabs after - _closeTabsAfterMenuItem.Click([weakThis](auto&&, auto&&) { - if (auto tab{ weakThis.get() }) - { - tab->_CloseTabsAfter(); - } - }); - _closeTabsAfterMenuItem.Text(RS_(L"TabCloseAfter")); - - // Close other tabs - _closeOtherTabsMenuItem.Click([weakThis](auto&&, auto&&) { - if (auto tab{ weakThis.get() }) - { - tab->_CloseOtherTabs(); - } - }); - _closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther")); - - Controls::MenuFlyoutSubItem closeSubMenu; - closeSubMenu.Text(RS_(L"TabCloseSubMenu")); - closeSubMenu.Items().Append(_closeTabsAfterMenuItem); - closeSubMenu.Items().Append(_closeOtherTabsMenuItem); - - return closeSubMenu; - } - - // Method Description: - // - Enable the Close menu items based on tab index and total number of tabs - // Arguments: - // - - // Return Value: - // - - void TerminalTab::_EnableCloseMenuItems() - { - // 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); - } - // Method Description: // - This will update the contents of our TabViewItem for our current state. // - If we're not in a rename, we'll set the Header of the TabViewItem to @@ -1080,27 +1016,6 @@ namespace winrt::TerminalApp::implementation return _zoomedPane != nullptr; } - void TerminalTab::_CloseTabsAfter() - { - CloseTabsAfterArgs args{ _TabViewIndex }; - ActionAndArgs closeTabsAfter{ ShortcutAction::CloseTabsAfter, args }; - - _dispatch.DoAction(closeTabsAfter); - } - - void TerminalTab::_CloseOtherTabs() - { - CloseOtherTabsArgs args{ _TabViewIndex }; - ActionAndArgs closeOtherTabs{ ShortcutAction::CloseOtherTabs, args }; - - _dispatch.DoAction(closeOtherTabs); - } - - void TerminalTab::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch) - { - _dispatch = dispatch; - } - DEFINE_EVENT(TerminalTab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>); DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate); DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>); diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index d74e6c2dbce..7144a961fa4 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -4,6 +4,7 @@ #pragma once #include "Pane.h" #include "ColorPickupFlyout.h" +#include "TabBase.h" #include "TerminalTab.g.h" // fwdecl unittest classes @@ -14,7 +15,7 @@ namespace TerminalAppLocalTests namespace winrt::TerminalApp::implementation { - struct TerminalTab : TerminalTabT + struct TerminalTab : TerminalTabT { public: TerminalTab(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control); @@ -25,8 +26,7 @@ namespace winrt::TerminalApp::implementation winrt::Microsoft::Terminal::TerminalControl::TermControl GetActiveTerminalControl() const; std::optional GetFocusedProfile() const noexcept; - void Focus(winrt::Windows::UI::Xaml::FocusState focusState); - winrt::Windows::UI::Xaml::FocusState FocusState() const noexcept; + void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override; winrt::fire_and_forget Scroll(const int delta); @@ -46,7 +46,7 @@ namespace winrt::TerminalApp::implementation void UpdateSettings(const winrt::TerminalApp::TerminalSettings& settings, const GUID& profile); winrt::fire_and_forget UpdateTitle(); - void Shutdown(); + void Shutdown() override; void ClosePane(); void SetTabText(winrt::hstring title); @@ -66,27 +66,10 @@ namespace winrt::TerminalApp::implementation int GetLeafPaneCount() const noexcept; - void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch); - - WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler); - WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); DECLARE_EVENT(ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>); DECLARE_EVENT(ColorSelected, _colorSelected, winrt::delegate); DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>); - OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers); - OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers); - OBSERVABLE_GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr); - - GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr); - // The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector. - // This is needed since Tab is going to be managing its own SwitchToTab command. - OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewIndex, _PropertyChangedHandlers, 0); - // The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector. - OBSERVABLE_GETSET_PROPERTY(uint32_t, TabViewNumTabs, _PropertyChangedHandlers, 0); - - OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, _PropertyChangedHandlers, nullptr); - private: std::shared_ptr _rootPane{ nullptr }; std::shared_ptr _activePane{ nullptr }; @@ -99,7 +82,6 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{}; bool _receivedKeyDown{ false }; - winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused }; winrt::hstring _runtimeTabText{}; bool _inRename{ false }; @@ -109,9 +91,7 @@ namespace winrt::TerminalApp::implementation void _MakeTabViewItem(); - void _CreateContextMenu(); - winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _CreateCloseSubMenu(); - void _EnableCloseMenuItems(); + void _CreateContextMenu() override; void _RefreshVisualState(); @@ -130,9 +110,6 @@ namespace winrt::TerminalApp::implementation void _ApplyTabColor(const winrt::Windows::UI::Color& color); void _ClearTabBackgroundColor(); - void _CloseTabsAfter(); - void _CloseOtherTabs(); - friend class ::TerminalAppLocalTests::TabTests; }; } diff --git a/src/cascadia/TerminalApp/TerminalTab.idl b/src/cascadia/TerminalApp/TerminalTab.idl index ed28d175a02..7485acbf27d 100644 --- a/src/cascadia/TerminalApp/TerminalTab.idl +++ b/src/cascadia/TerminalApp/TerminalTab.idl @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "ITab.idl"; +import "TabBase.idl"; namespace TerminalApp { - [default_interface] runtimeclass TerminalTab : ITab, Windows.UI.Xaml.Data.INotifyPropertyChanged + [default_interface] runtimeclass TerminalTab : TabBase { } } diff --git a/src/cascadia/inc/cppwinrt_utils.h b/src/cascadia/inc/cppwinrt_utils.h index 24315a26948..e20dcca82db 100644 --- a/src/cascadia/inc/cppwinrt_utils.h +++ b/src/cascadia/inc/cppwinrt_utils.h @@ -82,7 +82,7 @@ public: winrt::event_token name(args const& handler) { return _##name##Handlers.add(handler); } \ void name(winrt::event_token const& token) { _##name##Handlers.remove(token); } \ \ -private: \ +protected: \ winrt::event _##name##Handlers; // This is a helper macro for both declaring the signature and body of an event