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
This commit is contained in:
PankajBhojwani 2020-12-15 18:45:15 -08:00 committed by GitHub
parent 22d43a431c
commit 551cc9a98b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 1 deletions

View file

@ -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 };

View file

@ -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();

View file

@ -1,16 +1,31 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information. -->
<UserControl
x:Class="TerminalApp.TabHeaderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TerminalApp"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel x:Name="HeaderStackPanel"
Orientation="Horizontal">
<mux:ProgressRing x:Name="HeaderProgressRing"
IsActive="{x:Bind IsProgressRingActive, Mode=OneWay}"
Visibility="{x:Bind IsProgressRingActive, Mode=OneWay}"
IsIndeterminate="{x:Bind IsProgressRingIndeterminate, Mode=OneWay}"
Value="{x:Bind ProgressValue, Mode=OneWay}"
MinHeight="0"
MinWidth="0"
Height="15"
Width="15"
Margin="-7.5,0,8,0"/>
<!--We want the progress ring to 'replace' the tab icon, but we don't have control
over the tab icon here (the tab view item does) - so we hide the tab icon there
and use a negative margin for the progress ring here to put it where the icon would be-->
<FontIcon x:Name="HeaderZoomIcon"
FontFamily="Segoe MDL2 Assets"
Visibility="{x:Bind IsPaneZoomed, Mode=OneWay}"

View file

@ -8,6 +8,7 @@
#include "TerminalTab.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"
#include "AppLogic.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
@ -159,7 +160,7 @@ namespace winrt::TerminalApp::implementation
// - profile: The GUID of the profile these settings should apply to.
// Return Value:
// - <none>
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<uint32_t>(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:

View file

@ -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 };