Skip to content

Commit

Permalink
Move most of TerminalApp's runtime Xaml to a .xaml file and class (#1885
Browse files Browse the repository at this point in the history
)
  • Loading branch information
DHowett authored Jul 9, 2019
1 parent cfbc9e8 commit 122f0de
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 124 deletions.
133 changes: 31 additions & 102 deletions src/cascadia/TerminalApp/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>

#include "App.g.cpp"
#include "TerminalPage.h"

using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::UI::Xaml;
Expand Down Expand Up @@ -76,110 +77,43 @@ namespace winrt::TerminalApp::implementation

// Method Description:
// - Create all of the initial UI elements of the Terminal app.
// * Creates the tab bar, initially hidden.
// * Creates the tab content area, which is where we'll display the tabs/panes.
// * Initializes the first terminal control, using the default profile,
// and adds it to our list of tabs.
void App::_Create(uint64_t parentHwnd)
{
_tabView = MUX::Controls::TabView{};

_tabView.SelectionChanged({ this, &App::_OnTabSelectionChanged });
_tabView.TabClosing({ this, &App::_OnTabClosing });
_tabView.Items().VectorChanged({ this, &App::_OnTabItemsChanged });

_root = Controls::Grid{};

_tabRow = Controls::Grid{};
_tabRow.Name(L"Tab Row");
_tabContent = Controls::Grid{};
_tabContent.Name(L"Tab Content");

// Set up two columns in the tabs row - one for the tabs themselves, and
// another for the settings button.
auto tabsColDef = Controls::ColumnDefinition();
auto newTabBtnColDef = Controls::ColumnDefinition();
newTabBtnColDef.Width(GridLengthHelper::Auto());

_tabRow.ColumnDefinitions().Append(tabsColDef);
_tabRow.ColumnDefinitions().Append(newTabBtnColDef);

// Set up two rows - one for the tabs, the other for the tab content,
// the terminal panes.
auto tabBarRowDef = Controls::RowDefinition();
tabBarRowDef.Height(GridLengthHelper::Auto());
_root.RowDefinitions().Append(tabBarRowDef);
_root.RowDefinitions().Append(Controls::RowDefinition{});

_root.Children().Append(_tabRow);

Controls::Grid::SetRow(_tabRow, 0);

_root.Children().Append(_tabContent);
Controls::Grid::SetRow(_tabContent, 1);
Controls::Grid::SetColumn(_tabView, 0);

// Create the new tab button.
_newTabButton = Controls::SplitButton{};
Controls::SymbolIcon newTabIco{};
newTabIco.Symbol(Controls::Symbol::Add);
_newTabButton.Content(newTabIco);
Controls::Grid::SetRow(_newTabButton, 0);
Controls::Grid::SetColumn(_newTabButton, 1);
_newTabButton.VerticalAlignment(VerticalAlignment::Stretch);
_newTabButton.HorizontalAlignment(HorizontalAlignment::Left);
/* !!! TODO
This is not the correct way to host a XAML page. This exists today because we valued
getting a .xaml over tearing out all of the terminal logic and splitting it across App
and Page.
The work to clarify the boundary between app global state and "terminal page" state
is tracked in GH#1878.
*/
auto terminalPage = winrt::make_self<TerminalPage>();
_root = terminalPage.as<winrt::Windows::UI::Xaml::Controls::Control>();
_tabContent = terminalPage->TabContent();
_tabRow = terminalPage->TabRow();
_tabView = terminalPage->TabView();
_newTabButton = terminalPage->NewTabButton();

_minMaxCloseControl = terminalPage->MinMaxCloseControl();
_minMaxCloseControl.ParentWindowHandle(parentHwnd);

if (!_settings->GlobalSettings().GetShowTabsInTitlebar())
{
_minMaxCloseControl.Visibility(Visibility::Collapsed);
}

// When the new tab button is clicked, open the default profile
// Event Bindings (Early)
_newTabButton.Click([this](auto&&, auto&&) {
this->_OpenNewTab(std::nullopt);
});
_tabView.SelectionChanged({ this, &App::_OnTabSelectionChanged });
_tabView.TabClosing({ this, &App::_OnTabClosing });
_tabView.Items().VectorChanged({ this, &App::_OnTabItemsChanged });
_root.Loaded({ this, &App::_OnLoaded });

// Populate the new tab button's flyout with entries for each profile
_CreateNewTabFlyout();

_tabRow.Children().Append(_tabView);

if (_settings->GlobalSettings().GetShowTabsInTitlebar())
{
_minMaxCloseControl = winrt::TerminalApp::MinMaxCloseControl(parentHwnd);
Controls::Grid::SetRow(_minMaxCloseControl, 0);
Controls::Grid::SetColumn(_minMaxCloseControl, 1);
_minMaxCloseControl.Content().Children().Append(_newTabButton);

_tabRow.Children().Append(_minMaxCloseControl);
}
else
{
_tabRow.Children().Append(_newTabButton);
}

_tabContent.VerticalAlignment(VerticalAlignment::Stretch);
_tabContent.HorizontalAlignment(HorizontalAlignment::Stretch);

// Here, we're doing the equivalent of defining the _tabRow as the
// following: <Grid Background="{ThemeResource
// ApplicationPageBackgroundThemeBrush}"> We need to set the Background
// to that ThemeResource, so it'll be colored appropriately regardless
// of what theme the user has selected.
// We're looking up the Style we've defined in App.xaml, and applying it
// here. A ResourceDictionary is a Map<IInspectable, IInspectable>, so
// you'll need to try_as to get the type we actually want.
auto res = Resources();
IInspectable key = winrt::box_value(L"BackgroundGridThemeStyle");
if (res.HasKey(key))
{
IInspectable g = res.Lookup(key);
winrt::Windows::UI::Xaml::Style style = g.try_as<winrt::Windows::UI::Xaml::Style>();
_root.Style(style);
_tabRow.Style(style);
}

// Apply the UI theme from our settings to our UI elements
_ApplyTheme(_settings->GlobalSettings().GetRequestedTheme());

_OpenNewTab(std::nullopt);

_root.Loaded({ this, &App::_OnLoaded });
}

// Method Description:
Expand Down Expand Up @@ -210,9 +144,10 @@ namespace winrt::TerminalApp::implementation
dialog.Content(contentElement);
dialog.CloseButtonText(closeButtonText);

// IMPORTANT: Add the dialog to the _root UIElement before you show it,
// so it knows how to attach to the XAML content.
_root.Children().Append(dialog);
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
// xaml tree somehow.
dialog.XamlRoot(_root.XamlRoot());

// Display the dialog.
Controls::ContentDialogResult result = co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
Expand Down Expand Up @@ -766,19 +701,13 @@ namespace winrt::TerminalApp::implementation
void App::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
{
_root.RequestedTheme(newTheme);
_tabRow.RequestedTheme(newTheme);
}

UIElement App::GetRoot() noexcept
{
return _root;
}

UIElement App::GetTabs() noexcept
{
return _tabRow;
}

void App::_SetFocusedTabIndex(int tabIndex)
{
// GH#1117: This is a workaround because _tabView.SelectedIndex(tabIndex)
Expand Down
3 changes: 1 addition & 2 deletions src/cascadia/TerminalApp/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ namespace winrt::TerminalApp::implementation
App();

Windows::UI::Xaml::UIElement GetRoot() noexcept;
Windows::UI::Xaml::UIElement GetTabs() noexcept;

// Gets the current dragglable area in the non client region of the top level window
Windows::UI::Xaml::Controls::Border GetDragBar() noexcept;
Expand All @@ -52,7 +51,7 @@ namespace winrt::TerminalApp::implementation
// ALSO: If you add any UIElements as roots here, make sure they're
// updated in _ApplyTheme. The two roots currently are _root and _tabRow
// (which is a root when the tabs are in the titlebar.)
Windows::UI::Xaml::Controls::Grid _root{ nullptr };
Windows::UI::Xaml::Controls::Control _root{ nullptr };
Microsoft::UI::Xaml::Controls::TabView _tabView{ nullptr };
Windows::UI::Xaml::Controls::Grid _tabRow{ nullptr };
Windows::UI::Xaml::Controls::Grid _tabContent{ nullptr };
Expand Down
1 change: 0 additions & 1 deletion src/cascadia/TerminalApp/App.idl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace TerminalApp
void LoadSettings();

Windows.UI.Xaml.UIElement GetRoot();
Windows.UI.Xaml.UIElement GetTabs();
Windows.UI.Xaml.Controls.Border GetDragBar{ get; };

Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
Expand Down
47 changes: 31 additions & 16 deletions src/cascadia/TerminalApp/MinMaxCloseControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,41 @@

namespace winrt::TerminalApp::implementation
{
MinMaxCloseControl::MinMaxCloseControl(uint64_t hWnd) :
_window(reinterpret_cast<HWND>(hWnd))
MinMaxCloseControl::MinMaxCloseControl()
{
const winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///MinMaxCloseControl.xaml" };
winrt::Windows::UI::Xaml::Application::LoadComponent(*this, resourceLocator, winrt::Windows::UI::Xaml::Controls::Primitives::ComponentResourceLocation::Nested);
}

uint64_t MinMaxCloseControl::ParentWindowHandle() const
{
return reinterpret_cast<uint64_t>(_window);
}

void MinMaxCloseControl::ParentWindowHandle(uint64_t handle)
{
_window = reinterpret_cast<HWND>(handle);
}

void MinMaxCloseControl::_OnMaximize(byte flag)
{
POINT point1 = {};
::GetCursorPos(&point1);
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
WINDOWPLACEMENT placement = { sizeof(placement) };
::GetWindowPlacement(_window, &placement);
if (placement.showCmd == SW_SHOWNORMAL)
{
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateMaximized", false);
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
}
else if (placement.showCmd == SW_SHOWMAXIMIZED)
if (_window)
{
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateNormal", false);
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
POINT point1 = {};
::GetCursorPos(&point1);
const LPARAM lParam = MAKELPARAM(point1.x, point1.y);
WINDOWPLACEMENT placement = { sizeof(placement) };
::GetWindowPlacement(_window, &placement);
if (placement.showCmd == SW_SHOWNORMAL)
{
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateMaximized", false);
::PostMessage(_window, WM_SYSCOMMAND, SC_MAXIMIZE | flag, lParam);
}
else if (placement.showCmd == SW_SHOWMAXIMIZED)
{
winrt::Windows::UI::Xaml::VisualStateManager::GoToState(this->Maximize(), L"WindowStateNormal", false);
::PostMessage(_window, WM_SYSCOMMAND, SC_RESTORE | flag, lParam);
}
}
}

Expand All @@ -49,7 +61,10 @@ namespace winrt::TerminalApp::implementation

void MinMaxCloseControl::Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
if (_window)
{
::PostMessage(_window, WM_SYSCOMMAND, SC_MINIMIZE | HTMINBUTTON, 0);
}
}

void MinMaxCloseControl::Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
Expand Down
7 changes: 5 additions & 2 deletions src/cascadia/TerminalApp/MinMaxCloseControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ namespace winrt::TerminalApp::implementation
{
struct MinMaxCloseControl : MinMaxCloseControlT<MinMaxCloseControl>
{
MinMaxCloseControl(uint64_t hWnd);
MinMaxCloseControl();

void Minimize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void Maximize_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void Close_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
void DragBar_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);

uint64_t ParentWindowHandle() const;
void ParentWindowHandle(uint64_t handle);

private:
void _OnMaximize(byte flag);
HWND _window = nullptr;
HWND _window{ nullptr }; // non-owning handle; should not be freed in the dtor.
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/cascadia/TerminalApp/MinMaxCloseControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
[default_interface]
runtimeclass MinMaxCloseControl : Windows.UI.Xaml.Controls.StackPanel
{
MinMaxCloseControl(UInt64 hParentWnd);
MinMaxCloseControl();

Windows.UI.Xaml.Controls.Grid Content{ get; };
Windows.UI.Xaml.Controls.Border DragBar{ get; };

UInt64 ParentWindowHandle;
}
}
15 changes: 15 additions & 0 deletions src/cascadia/TerminalApp/TerminalApp.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="App.base.h" />
<ClInclude Include="TerminalPage.h">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="MinMaxCloseControl.h">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClInclude>
Expand All @@ -58,9 +62,17 @@
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="TerminalPage.cpp">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="MinMaxCloseControl.cpp">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClCompile>
<Midl Include="TerminalPage.idl">
<DependentUpon>TerminalPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="MinMaxCloseControl.idl">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down Expand Up @@ -119,6 +131,9 @@
<!-- This is needed to be able to reference the XamlApplication type. -->
</ItemGroup>
<ItemGroup>
<Page Include="TerminalPage.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="MinMaxCloseControl.xaml">
<SubType>Designer</SubType>
</Page>
Expand Down
30 changes: 30 additions & 0 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#include "pch.h"
#include "TerminalPage.h"

#include "TerminalPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::TerminalApp::implementation
{
TerminalPage::TerminalPage()
{
// The generated code will by default attempt to load from ms-appx://TerminalApp/TerminalPage.xaml.
// We'll force it to load from the root of the appx instead.
const winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///TerminalPage.xaml" };
winrt::Windows::UI::Xaml::Application::LoadComponent(*this, resourceLocator, winrt::Windows::UI::Xaml::Controls::Primitives::ComponentResourceLocation::Nested);
}

// Method Description:
// - Bound in the Xaml editor to the [+] button.
// Arguments:
// - sender
// - event arguments
void TerminalPage::OnNewTabButtonClick(IInspectable const&, Controls::SplitButtonClickEventArgs const&)
{
}
}
Loading

0 comments on commit 122f0de

Please sign in to comment.