Allow a Pane to host a UserControl instead of a TermControl

This commit is contained in:
Mike Griese 2021-09-01 12:53:46 -05:00
parent 14d21f492b
commit c66a56656e
2 changed files with 93 additions and 47 deletions

View file

@ -34,7 +34,7 @@ static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Wi
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
Pane::Pane(const Profile& profile, const Controls::UserControl& control, const bool lastFocused) :
_control{ control },
_lastActive{ lastFocused },
_profile{ profile }
@ -42,8 +42,12 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo
_root.Children().Append(_border);
_border.Child(_control);
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
const auto& termControl{ _control.try_as<TermControl>() };
if (termControl)
{
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
}
// On the first Pane's creation, lookup resources we'll use to theme the
// Pane, including the brushed to use for the focused/unfocused border
@ -829,8 +833,12 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
{
return;
}
const auto newConnectionState = _control.ConnectionState();
const auto& termControl{ _control.try_as<TermControl>() };
if (!termControl)
{
return;
}
const auto newConnectionState = termControl.ConnectionState();
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
if (newConnectionState < ConnectionState::Closed)
@ -873,7 +881,9 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
{
return;
}
if (_profile)
const auto& termControl{ _control.try_as<TermControl>() };
if (_profile && termControl)
{
// We don't want to do anything if nothing is set, so check for that first
if (static_cast<int>(_profile.BellStyle()) != 0)
@ -887,7 +897,7 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
{
_control.BellLightOn();
termControl.BellLightOn();
}
// raise the event with the bool value corresponding to the taskbar flag
@ -942,7 +952,11 @@ void Pane::Shutdown()
std::unique_lock lock{ _createCloseLock };
if (_IsLeaf())
{
_control.Close();
const auto& termControl{ _control.try_as<TermControl>() };
if (termControl)
{
termControl.Close();
}
}
else
{
@ -952,7 +966,7 @@ void Pane::Shutdown()
}
// Method Description:
// - Get the root UIElement of this pane. There may be a single TermControl as a
// - Get the root UIElement of this pane. There may be a single UserControl as a
// child, or an entire tree of grids and panes as children of this element.
// Arguments:
// - <none>
@ -993,10 +1007,11 @@ std::shared_ptr<Pane> Pane::GetActivePane()
// Arguments:
// - <none>
// Return Value:
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
TermControl Pane::GetTerminalControl()
// - nullptr if this Pane is a parent or isn't hosting a Terminal, otherwise the
// TermControl of this Pane.
TermControl Pane::GetTerminalControl() const
{
return _IsLeaf() ? _control : nullptr;
return _IsLeaf() ? _control.try_as<TermControl>() : nullptr;
}
// Method Description:
@ -1147,9 +1162,13 @@ void Pane::_FocusFirstChild()
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
{
assert(_IsLeaf());
const auto& termControl{ _control.try_as<TermControl>() };
if (!termControl)
{
return;
}
_profile = profile;
auto controlSettings = _control.Settings().as<TerminalSettings>();
auto controlSettings = termControl.Settings().as<TerminalSettings>();
// Update the parent of the control's settings object (and not the object itself) so
// that any overrides made by the control don't get affected by the reload
controlSettings.SetParent(settings.DefaultSettings());
@ -1162,8 +1181,8 @@ void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Pr
// sure the unfocused settings inherit from that.
unfocusedSettings.SetParent(controlSettings);
}
_control.UnfocusedAppearance(unfocusedSettings);
_control.UpdateSettings();
termControl.UnfocusedAppearance(unfocusedSettings);
termControl.UpdateSettings();
}
// Method Description:
@ -1294,8 +1313,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_id = remainingChild->Id();
// Add our new event handler before revoking the old one.
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
const auto& termControl{ _control.try_as<TermControl>() };
if (termControl)
{
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
}
// Revoke the old event handlers. Remove both the handlers for the panes
// themselves closing, and remove their handlers for their controls
@ -1306,21 +1329,30 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
// handlers since it is just getting moved.
if (!isDetaching)
{
closedChild->_control.ConnectionStateChanged(closedChild->_connectionStateChangedToken);
closedChild->_control.WarningBell(closedChild->_warningBellToken);
const auto& closedControl{ closedChild->_control.try_as<TermControl>() };
if (closedControl)
{
closedControl.ConnectionStateChanged(closedChild->_connectionStateChangedToken);
closedControl.WarningBell(closedChild->_warningBellToken);
}
}
closedChild->Closed(closedChildClosedToken);
remainingChild->Closed(remainingChildClosedToken);
remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
remainingChild->_control.WarningBell(remainingChild->_warningBellToken);
const auto& remainingControl{ remainingChild->_control.try_as<TermControl>() };
if (remainingControl)
{
remainingControl.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
remainingControl.WarningBell(remainingChild->_warningBellToken);
}
// If either of our children was focused, we want to take that focus from
// them.
_lastActive = _firstChild->_lastActive || _secondChild->_lastActive;
// Remove all the ui elements of the remaining child. This'll make sure
// we can re-attach the TermControl to our Grid.
// we can re-attach the UserControl to our Grid.
remainingChild->_root.Children().Clear();
remainingChild->_border.Child(nullptr);
@ -1330,7 +1362,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
_root.ColumnDefinitions().Clear();
_root.RowDefinitions().Clear();
// Reattach the TermControl to our grid.
// Reattach the UserControl to our grid.
_root.Children().Append(_border);
_border.Child(_control);
@ -1389,8 +1421,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
closedChild->Closed(closedChildClosedToken);
if (!isDetaching)
{
closedChild->_control.ConnectionStateChanged(closedChild->_connectionStateChangedToken);
closedChild->_control.WarningBell(closedChild->_warningBellToken);
const auto& closedControl{ closedChild->_control.try_as<TermControl>() };
if (closedControl)
{
closedControl.ConnectionStateChanged(closedChild->_connectionStateChangedToken);
closedControl.WarningBell(closedChild->_warningBellToken);
}
}
// Reset our UI:
@ -1958,18 +1994,18 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
// Method Description:
// - Split the focused pane in our tree of panes, and place the given
// TermControl into the newly created pane. If we're the focused pane, then
// UserControl into the newly created pane. If we're the focused pane, then
// we'll create two new children, and place them side-by-side in our Grid.
// Arguments:
// - splitType: what type of split we want to create.
// - profile: The profile to associate with the newly created pane.
// - control: A TermControl to use in the new pane.
// - control: A UserControl to use in the new pane.
// Return Value:
// - The two newly created Panes
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType,
const float splitSize,
const Profile& profile,
const TermControl& control)
const Controls::UserControl& control)
{
if (!_IsLeaf())
{
@ -2075,10 +2111,11 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
// modify our tree
std::unique_lock lock{ _createCloseLock };
const auto& termControl{ _control.try_as<TermControl>() };
// revoke our handler - the child will take care of the control now.
_control.ConnectionStateChanged(_connectionStateChangedToken);
termControl.ConnectionStateChanged(_connectionStateChangedToken);
_connectionStateChangedToken.value = 0;
_control.WarningBell(_warningBellToken);
termControl.WarningBell(_warningBellToken);
_warningBellToken.value = 0;
// Remove our old GotFocus handler from the control. We don't what the
@ -2091,7 +2128,7 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
_desiredSplitPosition = 1.0f - splitSize;
// Remove any children we currently have. We can't add the existing
// TermControl to a new grid until we do this.
// UserControl to a new grid until we do this.
_root.Children().Clear();
_border.Child(nullptr);
@ -2413,8 +2450,13 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
// If requested size is already snapped, then both returned values equal this value.
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
const auto& termControl{ _control.try_as<TermControl>() };
if (_IsLeaf())
{
if (!termControl)
{
return { dimension, dimension };
}
// If we're a leaf pane, align to the grid of controlling terminal
const auto minSize = _GetMinSize();
@ -2425,7 +2467,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
return { minDimension, minDimension };
}
float lower = _control.SnapDimensionToGrid(widthOrHeight, dimension);
float lower = termControl.SnapDimensionToGrid(widthOrHeight, dimension);
if (widthOrHeight)
{
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
@ -2445,7 +2487,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
}
else
{
const auto cellSize = _control.CharacterDimensions();
const auto cellSize = termControl.CharacterDimensions();
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
return { lower, higher };
}
@ -2490,7 +2532,8 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
// - <none>
void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const
{
if (_IsLeaf())
const auto& termControl{ _control.try_as<TermControl>() };
if (_IsLeaf() && termControl)
{
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
// is true, see below).
@ -2505,11 +2548,11 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si
}
else
{
const auto cellSize = _control.CharacterDimensions();
const auto cellSize = termControl.CharacterDimensions();
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
}
}
else
else if (!_IsLeaf())
{
// We're a parent pane, so we have to advance dimension of our children panes. In
// fact, we advance only one child (chosen later) to keep the growth fine-grained.
@ -2611,7 +2654,8 @@ Size Pane::_GetMinSize() const
{
if (_IsLeaf())
{
auto controlSize = _control.MinimumSize();
const auto& termControl{ _control.try_as<TermControl>() };
auto controlSize = termControl ? termControl.MinimumSize() : Size{ 1, 1 };
auto newWidth = controlSize.Width;
auto newHeight = controlSize.Height;
@ -2800,7 +2844,8 @@ std::optional<SplitState> Pane::PreCalculateAutoSplit(const std::shared_ptr<Pane
// - Returns true if the pane or one of its descendants is read-only
bool Pane::ContainsReadOnly() const
{
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
const auto& termControl{ GetTerminalControl() };
return termControl ? termControl.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
}
// Method Description:
@ -2813,13 +2858,14 @@ bool Pane::ContainsReadOnly() const
// - <none>
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
{
if (_IsLeaf())
const auto& termControl{ GetTerminalControl() };
if (termControl)
{
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
_control.TaskbarProgress()) };
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(termControl.TaskbarState(),
termControl.TaskbarProgress()) };
states.push_back(tbState);
}
else
else if (!_IsLeaf())
{
_firstChild->CollectTaskbarStates(states);
_secondChild->CollectTaskbarStates(states);

View file

@ -48,11 +48,11 @@ class Pane : public std::enable_shared_from_this<Pane>
{
public:
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control,
const winrt::Windows::UI::Xaml::Controls::UserControl& control,
const bool lastFocused = false);
std::shared_ptr<Pane> GetActivePane();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
// Method Description:
@ -84,7 +84,7 @@ public:
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
const float splitSize,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
const winrt::Microsoft::Terminal::Control::TermControl& control);
const winrt::Windows::UI::Xaml::Controls::UserControl& control);
bool ToggleSplitOrientation();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,
@ -155,7 +155,7 @@ private:
winrt::Windows::UI::Xaml::Controls::Grid _root{};
winrt::Windows::UI::Xaml::Controls::Border _border{};
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
winrt::Windows::UI::Xaml::Controls::UserControl _control{ nullptr };
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;