Skip to content

Commit

Permalink
Make tab header a custom control (microsoft#8227)
Browse files Browse the repository at this point in the history
This PR makes the Header of TabViewItem a custom user control.

## Validation Steps Performed
Manual testing

Closes microsoft#8201
  • Loading branch information
PankajBhojwani authored and mpela81 committed Nov 22, 2020
1 parent 1fb121d commit e895852
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 168 deletions.
85 changes: 85 additions & 0 deletions src/cascadia/TerminalApp/TabHeaderControl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "TabHeaderControl.h"

#include "TabHeaderControl.g.cpp"

using namespace winrt;
using namespace winrt::Microsoft::UI::Xaml;

namespace winrt::TerminalApp::implementation
{
TabHeaderControl::TabHeaderControl()
{
InitializeComponent();

// We'll only process the KeyUp event if we received an initial KeyDown event first.
// Avoids issue immediately closing the tab rename when we see the enter KeyUp event that was
// sent to the command palette to trigger the openTabRenamer action in the first place.
HeaderRenamerTextBox().KeyDown([&](auto&&, auto&&) {
_receivedKeyDown = true;
});

// NOTE: (Preview)KeyDown does not work here. If you use that, we'll
// remove the TextBox from the UI tree, then the following KeyUp
// will bubble to the NewTabButton, which we don't want to have
// happen.
HeaderRenamerTextBox().KeyUp([&](auto&&, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e) {
if (_receivedKeyDown)
{
if (e.OriginalKey() == Windows::System::VirtualKey::Enter)
{
// User is done making changes, close the rename box
_CloseRenameBox();
}
else if (e.OriginalKey() == Windows::System::VirtualKey::Escape)
{
// User wants to discard the changes they made,
// reset the rename box text to the old text and close the rename box
HeaderRenamerTextBox().Text(Title());
_CloseRenameBox();
}
}
});
}

// Method Description:
// - Show the tab rename box for the user to rename the tab title
// - We automatically use the previous title as the initial text of the box
void TabHeaderControl::BeginRename()
{
_receivedKeyDown = false;

HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Visible);

HeaderRenamerTextBox().Text(Title());
HeaderRenamerTextBox().SelectAll();
HeaderRenamerTextBox().Focus(Windows::UI::Xaml::FocusState::Programmatic);
}

// Method Description:
// - Event handler for when the rename box loses focus
// - When the rename box loses focus, we use the text in it as the new title
// (i.e. we commit the change instead of cancelling it)
void TabHeaderControl::RenameBoxLostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
_CloseRenameBox();
}

// Method Description:
// - Hides the rename box and displays the title text block
// - Sends an event to the hosting tab to let them know we wish to change the title
// to whatever is in the renamer box right now - the tab will process that event
// and tell us to update our title
void TabHeaderControl::_CloseRenameBox()
{
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);

_TitleChangeRequestedHandlers(HeaderRenamerTextBox().Text());
}
}
37 changes: 37 additions & 0 deletions src/cascadia/TerminalApp/TabHeaderControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "inc/cppwinrt_utils.h"

#include "TabHeaderControl.g.h"

namespace winrt::TerminalApp::implementation
{
struct TabHeaderControl : TabHeaderControlT<TabHeaderControl>
{
TabHeaderControl();
void BeginRename();

void RenameBoxLostFocusHandler(winrt::Windows::Foundation::IInspectable const& sender,
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);

WINRT_CALLBACK(TitleChangeRequested, TerminalApp::TitleChangeRequestedArgs);

WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers);

private:
bool _receivedKeyDown{ false };

void _CloseRenameBox();
};
}

namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TabHeaderControl);
}
18 changes: 18 additions & 0 deletions src/cascadia/TerminalApp/TabHeaderControl.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace TerminalApp
{
delegate void TitleChangeRequestedArgs(String title);

[default_interface] runtimeclass TabHeaderControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Title { get; set; };
Boolean IsPaneZoomed { get; set; };

TabHeaderControl();
void BeginRename();

event TitleChangeRequestedArgs TitleChangeRequested;
}
}
30 changes: 30 additions & 0 deletions src/cascadia/TerminalApp/TabHeaderControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- 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: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">
<FontIcon x:Name="HeaderZoomIcon"
FontFamily="Segoe MDL2 Assets"
Visibility="{x:Bind IsPaneZoomed, Mode=OneWay}"
Glyph="&#xE8A3;"
FontSize="12"
Margin="0,0,8,0"/>
<TextBlock x:Name="HeaderTextBlock"
Visibility="Visible"
Text="{x:Bind Title, Mode=OneWay}"/>
<TextBox x:Name="HeaderRenamerTextBox"
Visibility="Collapsed"
MinHeight="0"
Padding="4,0,4,0"
Margin="0,-8,0,-8"
LostFocus="RenameBoxLostFocusHandler"/>
</StackPanel>
</UserControl>
13 changes: 13 additions & 0 deletions src/cascadia/TerminalApp/TerminalAppLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
</Page>
<Page Include="TabRowControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="TabHeaderControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="HighlightedTextControl.xaml">
<SubType>Designer</SubType>
Expand Down Expand Up @@ -89,6 +92,9 @@
<ClInclude Include="TabRowControl.h">
<DependentUpon>TabRowControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="TabHeaderControl.h">
<DependentUpon>TabHeaderControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="HighlightedTextControl.h">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
</ClInclude>
Expand Down Expand Up @@ -154,6 +160,9 @@
<ClCompile Include="TabRowControl.cpp">
<DependentUpon>TabRowControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="TabHeaderControl.cpp">
<DependentUpon>TabHeaderControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="HighlightedTextControl.cpp">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
</ClCompile>
Expand Down Expand Up @@ -230,6 +239,10 @@
<DependentUpon>TabRowControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="TabHeaderControl.idl">
<DependentUpon>TabHeaderControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="HighlightedTextControl.idl">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/TerminalAppLib.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@
<Page Include="TabRowControl.xaml">
<Filter>controls</Filter>
</Page>
<Page Include="TabHeaderControl.xaml">
<Filter>controls</Filter>
</Page>
<Page Include="TerminalPage.xaml">
<Filter>controls</Filter>
</Page>
Expand Down
Loading

0 comments on commit e895852

Please sign in to comment.