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:
parent
22d43a431c
commit
551cc9a98b
|
@ -23,6 +23,9 @@ namespace winrt::TerminalApp::implementation
|
||||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
||||||
OBSERVABLE_GETSET_PROPERTY(bool, IsPaneZoomed, _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:
|
private:
|
||||||
bool _receivedKeyDown{ false };
|
bool _receivedKeyDown{ false };
|
||||||
|
|
|
@ -9,6 +9,9 @@ namespace TerminalApp
|
||||||
{
|
{
|
||||||
String Title { get; set; };
|
String Title { get; set; };
|
||||||
Boolean IsPaneZoomed { get; set; };
|
Boolean IsPaneZoomed { get; set; };
|
||||||
|
Boolean IsProgressRingActive { get; set; };
|
||||||
|
Boolean IsProgressRingIndeterminate { get; set; };
|
||||||
|
UInt32 ProgressValue { get; set; };
|
||||||
|
|
||||||
TabHeaderControl();
|
TabHeaderControl();
|
||||||
void BeginRename();
|
void BeginRename();
|
||||||
|
|
|
@ -1,16 +1,31 @@
|
||||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||||
the MIT License. See LICENSE in the project root for license information. -->
|
the MIT License. See LICENSE in the project root for license information. -->
|
||||||
|
|
||||||
<UserControl
|
<UserControl
|
||||||
x:Class="TerminalApp.TabHeaderControl"
|
x:Class="TerminalApp.TabHeaderControl"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="using:TerminalApp"
|
xmlns:local="using:TerminalApp"
|
||||||
|
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<StackPanel x:Name="HeaderStackPanel"
|
<StackPanel x:Name="HeaderStackPanel"
|
||||||
Orientation="Horizontal">
|
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"
|
<FontIcon x:Name="HeaderZoomIcon"
|
||||||
FontFamily="Segoe MDL2 Assets"
|
FontFamily="Segoe MDL2 Assets"
|
||||||
Visibility="{x:Bind IsPaneZoomed, Mode=OneWay}"
|
Visibility="{x:Bind IsPaneZoomed, Mode=OneWay}"
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "TerminalTab.g.cpp"
|
#include "TerminalTab.g.cpp"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "ColorHelper.h"
|
#include "ColorHelper.h"
|
||||||
|
#include "AppLogic.h"
|
||||||
|
|
||||||
using namespace winrt;
|
using namespace winrt;
|
||||||
using namespace winrt::Windows::UI::Xaml;
|
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.
|
// - profile: The GUID of the profile these settings should apply to.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <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);
|
_rootPane->UpdateSettings(settings, profile);
|
||||||
}
|
}
|
||||||
|
@ -180,6 +181,13 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
_lastIconPath = iconPath;
|
_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() };
|
auto weakThis{ get_weak() };
|
||||||
|
|
||||||
co_await winrt::resume_foreground(TabViewItem().Dispatcher());
|
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:
|
// Method Description:
|
||||||
// - Gets the title string of the last focused terminal control in our tree.
|
// - Gets the title string of the last focused terminal control in our tree.
|
||||||
// Returns the empty string if there is no such control.
|
// Returns the empty string if there is no such control.
|
||||||
|
@ -441,6 +477,38 @@ namespace winrt::TerminalApp::implementation
|
||||||
tab->_RecalculateAndApplyTabColor();
|
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:
|
// Method Description:
|
||||||
|
|
|
@ -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);
|
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 UpdateIcon(const winrt::hstring iconPath);
|
||||||
|
winrt::fire_and_forget HideIcon(const bool hide);
|
||||||
|
|
||||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||||
winrt::Microsoft::Terminal::Settings::Model::SplitState PreCalculateAutoSplit(winrt::Windows::Foundation::Size rootSize) 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 };
|
uint16_t _nextPaneId{ 0 };
|
||||||
|
|
||||||
bool _receivedKeyDown{ false };
|
bool _receivedKeyDown{ false };
|
||||||
|
bool _iconHidden{ false };
|
||||||
|
|
||||||
winrt::hstring _runtimeTabText{};
|
winrt::hstring _runtimeTabText{};
|
||||||
bool _inRename{ false };
|
bool _inRename{ false };
|
||||||
|
|
Loading…
Reference in a new issue