Skip to content

Commit

Permalink
Add a togglePaneZoom action for zooming a pane (#6989)
Browse files Browse the repository at this point in the history
This PR adds the `togglePaneZoom` action, which can be used to make a
pane expand to fill the entire contents of the window.  A tab that
contains a zoomed pane will have a magnifying glass icon prepended
to its title. Any attempts to manage panes with one zoomed will force
the zoomed pane back to normal size.

VALIDATION
Zoomed in and out a bunch. Tried closing panes while zoomed. Tried
splitting panes while zoomed. Etc.

Closes #996
  • Loading branch information
zadjii-msft authored Aug 7, 2020
1 parent 4e0f313 commit 70fd03f
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 15 deletions.
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/ActionAndArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static constexpr std::string_view ScrolldownpageKey{ "scrollDownPage" };
static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
static constexpr std::string_view OpenSettingsKey{ "openSettings" }; // TODO GH#2557: Add args for OpenSettings
static constexpr std::string_view SplitPaneKey{ "splitPane" };
static constexpr std::string_view TogglePaneZoomKey{ "togglePaneZoom" };
static constexpr std::string_view ResizePaneKey{ "resizePane" };
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
static constexpr std::string_view FindKey{ "find" };
Expand Down Expand Up @@ -87,6 +88,7 @@ namespace winrt::TerminalApp::implementation
{ ToggleFullscreenKey, ShortcutAction::ToggleFullscreen },
{ ToggleAlwaysOnTopKey, ShortcutAction::ToggleAlwaysOnTop },
{ SplitPaneKey, ShortcutAction::SplitPane },
{ TogglePaneZoomKey, ShortcutAction::TogglePaneZoom },
{ SetTabColorKey, ShortcutAction::SetTabColor },
{ OpenTabColorPickerKey, ShortcutAction::OpenTabColorPicker },
{ UnboundKey, ShortcutAction::Invalid },
Expand Down Expand Up @@ -275,6 +277,7 @@ namespace winrt::TerminalApp::implementation
{ ShortcutAction::ToggleFullscreen, RS_(L"ToggleFullscreenCommandKey") },
{ ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") },
{ ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") },
{ ShortcutAction::TogglePaneZoom, RS_(L"TogglePaneZoomCommandKey") },
{ ShortcutAction::Invalid, L"" },
{ ShortcutAction::Find, RS_(L"FindCommandKey") },
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
Expand Down
20 changes: 20 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ namespace winrt::TerminalApp::implementation
}
}

void TerminalPage::_HandleTogglePaneZoom(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
auto activeTab = _GetFocusedTab();
if (activeTab)
{
// First thing's first, remove the current content from the UI
// tree. This is important, because we might be leaving zoom, and if
// a pane is zoomed, then it's currently in the UI tree, and should
// be removed before it's re-added in Pane::Restore
_tabContent.Children().Clear();

activeTab->ToggleZoom();

// Update the selected tab, to trigger us to re-add the tab's GetRootElement to the UI tree
_UpdatedSelectedTab(_tabView.SelectedIndex());
}
args.Handled(true);
}

void TerminalPage::_HandleScrollUpPage(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
Expand Down
102 changes: 90 additions & 12 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,21 +840,29 @@ void Pane::_UpdateBorders()
double top = 0, bottom = 0, left = 0, right = 0;

Thickness newBorders{ 0 };
if (WI_IsFlagSet(_borders, Borders::Top))
if (_zoomed)
{
top = PaneBorderSize;
// When the pane is zoomed, manually show all the borders around the window.
top = bottom = right = left = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Bottom))
{
bottom = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Left))
{
left = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Right))
else
{
right = PaneBorderSize;
if (WI_IsFlagSet(_borders, Borders::Top))
{
top = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Bottom))
{
bottom = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Left))
{
left = PaneBorderSize;
}
if (WI_IsFlagSet(_borders, Borders::Right))
{
right = PaneBorderSize;
}
}
_border.BorderThickness(ThicknessHelper::FromLengths(left, top, right, bottom));
}
Expand Down Expand Up @@ -1172,6 +1180,76 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
return { _firstChild, _secondChild };
}

// Method Description:
// - Recursively attempt to "zoom" the given pane. When the pane is zoomed, it
// won't be displayed as part of the tab tree, instead it'll take up the full
// content of the tab. When we find the given pane, we'll need to remove it
// from the UI tree, so that the caller can re-add it. We'll also set some
// internal state, so the pane can display all of its borders.
// Arguments:
// - zoomedPane: This is the pane which we're attempting to zoom on.
// Return Value:
// - <none>
void Pane::Maximize(std::shared_ptr<Pane> zoomedPane)
{
if (_IsLeaf())
{
_zoomed = (zoomedPane == shared_from_this());
_UpdateBorders();
}
else
{
if (zoomedPane == _firstChild || zoomedPane == _secondChild)
{
// When we're zooming the pane, we'll need to remove it from our UI
// tree. Easy way: just remove both children. We'll re-attach both
// when we un-zoom.
_root.Children().Clear();
}

// Always recurse into both children. If the (un)zoomed pane was one of
// our direct children, we'll still want to update it's borders.
_firstChild->Maximize(zoomedPane);
_secondChild->Maximize(zoomedPane);
}
}

// Method Description:
// - Recursively attempt to "un-zoom" the given pane. This does the opposite of
// Pane::Maximize. When we find the given pane, we should return the pane to our
// UI tree. We'll also clear the internal state, so the pane can display its
// borders correctly.
// - The caller should make sure to have removed the zoomed pane from the UI
// tree _before_ calling this.
// Arguments:
// - zoomedPane: This is the pane which we're attempting to un-zoom.
// Return Value:
// - <none>
void Pane::Restore(std::shared_ptr<Pane> zoomedPane)
{
if (_IsLeaf())
{
_zoomed = false;
_UpdateBorders();
}
else
{
if (zoomedPane == _firstChild || zoomedPane == _secondChild)
{
// When we're un-zooming the pane, we'll need to re-add it to our UI
// tree where it originally belonged. easy way: just re-add both.
_root.Children().Clear();
_root.Children().Append(_firstChild->GetRootElement());
_root.Children().Append(_secondChild->GetRootElement());
}

// Always recurse into both children. If the (un)zoomed pane was one of
// our direct children, we'll still want to update it's borders.
_firstChild->Restore(zoomedPane);
_secondChild->Restore(zoomedPane);
}
}

// Method Description:
// - Gets the size in pixels of each of our children, given the full size they
// should fill. Since these children own their own separators (borders), this
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalApp/Pane.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class Pane : public std::enable_shared_from_this<Pane>

int GetLeafPaneCount() const noexcept;

void Maximize(std::shared_ptr<Pane> zoomedPane);
void Restore(std::shared_ptr<Pane> zoomedPane);

WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);

Expand Down Expand Up @@ -103,6 +106,8 @@ class Pane : public std::enable_shared_from_this<Pane>

Borders _borders{ Borders::None };

bool _zoomed{ false };

bool _IsLeaf() const noexcept;
bool _HasFocusedChild() const noexcept;
void _SetupChildCloseHandlers();
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,9 @@
<data name="SplitPaneCommandKey" xml:space="preserve">
<value>Split pane</value>
</data>
<data name="TogglePaneZoomCommandKey" xml:space="preserve">
<value>Toggle pane zoom</value>
</data>
<data name="NewWindowCommandKey" xml:space="preserve">
<value>New window</value>
</data>
Expand Down
6 changes: 6 additions & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ namespace winrt::TerminalApp::implementation
break;
}

case ShortcutAction::TogglePaneZoom:
{
_TogglePaneZoomHandlers(*this, *eventArgs);
break;
}

case ShortcutAction::SwitchToTab:
{
_SwitchToTabHandlers(*this, *eventArgs);
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(TogglePaneZoom, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/ShortcutActionDispatch.idl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace TerminalApp
SplitVertical,
SplitHorizontal,
SplitPane,
TogglePaneZoom,
SwitchToTab,
AdjustFontSize,
ResetFontSize,
Expand Down Expand Up @@ -69,6 +70,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> NextTab;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> PrevTab;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> SplitPane;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> TogglePaneZoom;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> AdjustFontSize;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ResetFontSize;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ScrollUp;
Expand Down
75 changes: 72 additions & 3 deletions src/cascadia/TerminalApp/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ namespace winrt::TerminalApp::implementation
// - The UIElement acting as root of the Tab's root pane.
UIElement Tab::GetRootElement()
{
return _rootPane->GetRootElement();
if (_zoomedPane)
{
return _zoomedPane->GetRootElement();
}
else
{
return _rootPane->GetRootElement();
}
}

// Method Description:
Expand Down Expand Up @@ -598,8 +605,28 @@ namespace winrt::TerminalApp::implementation

if (!_inRename)
{
// If we're not currently in the process of renaming the tab, then just set the tab's text to whatever our active title is.
_tabViewItem.Header(winrt::box_value(tabText));
if (_zoomedPane)
{
Controls::StackPanel sp;
sp.Orientation(Controls::Orientation::Horizontal);
Controls::FontIcon ico;
ico.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
ico.Glyph(L"\xE8A3"); // "ZoomIn", a magnifying glass with a '+' in it.
ico.FontSize(12);
ico.Margin(ThicknessHelper::FromLengths(0, 0, 8, 0));
sp.Children().Append(ico);
Controls::TextBlock tb;
tb.Text(tabText);
sp.Children().Append(tb);

_tabViewItem.Header(sp);
}
else
{
// If we're not currently in the process of renaming the tab,
// then just set the tab's text to whatever our active title is.
_tabViewItem.Header(winrt::box_value(tabText));
}
}
else
{
Expand Down Expand Up @@ -955,6 +982,48 @@ namespace winrt::TerminalApp::implementation
{
return _rootPane->PreCalculateCanSplit(_activePane, splitType, availableSpace).value_or(false);
}

// Method Description:
// - Toggle our zoom state.
// * If we're not zoomed, then zoom the active pane, making it take the
// full size of the tab. We'll achieve this by changing our response to
// Tab::GetRootElement, so that it'll return the zoomed pane only.
// * If we're currently zoomed on a pane, un-zoom that pane.
// Arguments:
// - <none>
// Return Value:
// - <none>
void Tab::ToggleZoom()
{
if (_zoomedPane)
{
ExitZoom();
}
else
{
EnterZoom();
}
}
void Tab::EnterZoom()
{
_zoomedPane = _activePane;
_rootPane->Maximize(_zoomedPane);
// Update the tab header to show the magnifying glass
_UpdateTabHeader();
}
void Tab::ExitZoom()
{
_rootPane->Restore(_zoomedPane);
_zoomedPane = nullptr;
// Update the tab header to hide the magnifying glass
_UpdateTabHeader();
}

bool Tab::IsZoomed()
{
return _zoomedPane != nullptr;
}

DEFINE_EVENT(Tab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
DEFINE_EVENT(Tab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DEFINE_EVENT(Tab, ColorCleared, _colorCleared, winrt::delegate<>);
Expand Down
6 changes: 6 additions & 0 deletions src/cascadia/TerminalApp/Tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ namespace winrt::TerminalApp::implementation
void ResetRuntimeTabColor();
void ActivateColorPicker();

void ToggleZoom();
bool IsZoomed();
void EnterZoom();
void ExitZoom();

WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
DECLARE_EVENT(ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
Expand All @@ -73,6 +78,7 @@ namespace winrt::TerminalApp::implementation
private:
std::shared_ptr<Pane> _rootPane{ nullptr };
std::shared_ptr<Pane> _activePane{ nullptr };
std::shared_ptr<Pane> _zoomedPane{ nullptr };
winrt::hstring _lastIconPath{};
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
Expand Down
Loading

0 comments on commit 70fd03f

Please sign in to comment.