From 551cc9a98b72ef82a3ac2ba28cfd8c5e7f97b0d1 Mon Sep 17 00:00:00 2001 From: PankajBhojwani Date: Tue, 15 Dec 2020 18:45:15 -0800 Subject: [PATCH] Add a progress ring indicator to the tab header (#8133) This commit adds a [progress ring] to the tab header when we receive an OSC 9 sequence. Adds an event handler in `Tab.cpp` for the event we raise when we get a request to set the taskbar state/progress. This event handler updates the tab header with the active control's state/progress. When we want to show the progress ring, we hide the tab icon and place the progress ring over it. [progress ring]: https://docs.microsoft.com/en-us/uwp/api/Microsoft.UI.Xaml.Controls.ProgressRing?view=winui-2.4 References #6700 --- src/cascadia/TerminalApp/TabHeaderControl.h | 3 + src/cascadia/TerminalApp/TabHeaderControl.idl | 3 + .../TerminalApp/TabHeaderControl.xaml | 15 ++++ src/cascadia/TerminalApp/TerminalTab.cpp | 70 ++++++++++++++++++- src/cascadia/TerminalApp/TerminalTab.h | 2 + 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/TabHeaderControl.h b/src/cascadia/TerminalApp/TabHeaderControl.h index ce24a03df..39744b2bc 100644 --- a/src/cascadia/TerminalApp/TabHeaderControl.h +++ b/src/cascadia/TerminalApp/TabHeaderControl.h @@ -23,6 +23,9 @@ namespace winrt::TerminalApp::implementation WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers); OBSERVABLE_GETSET_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(bool, IsProgressRingActive, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(bool, IsProgressRingIndeterminate, _PropertyChangedHandlers); + OBSERVABLE_GETSET_PROPERTY(uint32_t, ProgressValue, _PropertyChangedHandlers); private: bool _receivedKeyDown{ false }; diff --git a/src/cascadia/TerminalApp/TabHeaderControl.idl b/src/cascadia/TerminalApp/TabHeaderControl.idl index a9dd3f571..0fc8fc2da 100644 --- a/src/cascadia/TerminalApp/TabHeaderControl.idl +++ b/src/cascadia/TerminalApp/TabHeaderControl.idl @@ -9,6 +9,9 @@ namespace TerminalApp { String Title { get; set; }; Boolean IsPaneZoomed { get; set; }; + Boolean IsProgressRingActive { get; set; }; + Boolean IsProgressRingIndeterminate { get; set; }; + UInt32 ProgressValue { get; set; }; TabHeaderControl(); void BeginRename(); diff --git a/src/cascadia/TerminalApp/TabHeaderControl.xaml b/src/cascadia/TerminalApp/TabHeaderControl.xaml index 633585ea9..65e8b5ee7 100644 --- a/src/cascadia/TerminalApp/TabHeaderControl.xaml +++ b/src/cascadia/TerminalApp/TabHeaderControl.xaml @@ -1,16 +1,31 @@ + + + - void TerminalTab::UpdateSettings(const TerminalSettings& settings, const GUID& profile) + void TerminalTab::UpdateSettings(const winrt::TerminalApp::TerminalSettings& settings, const GUID& profile) { _rootPane->UpdateSettings(settings, profile); } @@ -180,6 +181,13 @@ namespace winrt::TerminalApp::implementation _lastIconPath = iconPath; + // If the icon is currently hidden, just return here (but only after setting _lastIconPath to the new path + // for when we show the icon again) + if (_iconHidden) + { + return; + } + auto weakThis{ get_weak() }; co_await winrt::resume_foreground(TabViewItem().Dispatcher()); @@ -192,6 +200,34 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Hide or show the tab icon for this tab + // - Used when we want to show the progress ring, which should replace the icon + // Arguments: + // - hide: if true, we hide the icon; if false, we show the icon + winrt::fire_and_forget TerminalTab::HideIcon(const bool hide) + { + auto weakThis{ get_weak() }; + + co_await winrt::resume_foreground(TabViewItem().Dispatcher()); + + if (auto tab{ weakThis.get() }) + { + if (hide) + { + Icon({}); + TabViewItem().IconSource(IconPathConverter::IconSourceMUX({})); + tab->_iconHidden = true; + } + else + { + Icon(_lastIconPath); + TabViewItem().IconSource(IconPathConverter::IconSourceMUX(_lastIconPath)); + tab->_iconHidden = false; + } + } + } + // Method Description: // - Gets the title string of the last focused terminal control in our tree. // Returns the empty string if there is no such control. @@ -441,6 +477,38 @@ namespace winrt::TerminalApp::implementation tab->_RecalculateAndApplyTabColor(); } }); + + control.SetTaskbarProgress([weakThis](auto&&, auto&&) { + // Check if Tab's lifetime has expired + if (auto tab{ weakThis.get() }) + { + // The progress of the control changed, but not necessarily the progress of the tab. + // Set the tab's progress ring to the active pane's progress + if (tab->GetActiveTerminalControl().TaskbarState() > 0) + { + if (tab->GetActiveTerminalControl().TaskbarState() == 3) + { + // 3 is the indeterminate state, set the progress ring as such + tab->_headerControl.IsProgressRingIndeterminate(true); + } + else + { + // any non-indeterminate state has a value, set the progress ring as such + tab->_headerControl.IsProgressRingIndeterminate(false); + tab->_headerControl.ProgressValue(gsl::narrow(tab->GetActiveTerminalControl().TaskbarProgress())); + } + // Hide the tab icon (the progress ring is placed over it) + tab->HideIcon(true); + tab->_headerControl.IsProgressRingActive(true); + } + else + { + // Show the tab icon + tab->HideIcon(false); + tab->_headerControl.IsProgressRingActive(false); + } + } + }); } // Method Description: diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index c01c49e33..a4e1c6ef5 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -34,6 +34,7 @@ namespace winrt::TerminalApp::implementation void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, const GUID& profile, winrt::Microsoft::Terminal::TerminalControl::TermControl& control); winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath); + winrt::fire_and_forget HideIcon(const bool hide); float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; winrt::Microsoft::Terminal::Settings::Model::SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) const; @@ -87,6 +88,7 @@ namespace winrt::TerminalApp::implementation uint16_t _nextPaneId{ 0 }; bool _receivedKeyDown{ false }; + bool _iconHidden{ false }; winrt::hstring _runtimeTabText{}; bool _inRename{ false };