Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for moving focus between panes with the keyboard #1910

Merged
merged 21 commits into from
Jul 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
83f1a3b
Add the keybinding for panes back
zadjii-msft Jun 9, 2019
4840542
Start working on resizable panes. This sorta works as you increase th…
zadjii-msft Jun 10, 2019
aa16bc3
Panes can now be a variable percent of their parent
zadjii-msft Jun 11, 2019
81c1f0b
Add keybindings and code for handling resizing panes
zadjii-msft Jun 11, 2019
9d7857a
Excessive doc commenting
zadjii-msft Jun 11, 2019
ec2cca9
Try fixing resizing to 0
zadjii-msft Jun 12, 2019
356d3bf
Merge remote-tracking branch 'origin/master' into dev/migrie/f/991-re…
zadjii-msft Jun 12, 2019
770cf96
This fixes resizing two panes, but not n panes
zadjii-msft Jun 12, 2019
c101054
Prevent a kinetic dissasembly during resize
zadjii-msft Jun 12, 2019
a365503
runformat
zadjii-msft Jun 12, 2019
0655849
Merge remote-tracking branch 'origin/master' into dev/migrie/f/991-re…
zadjii-msft Jun 19, 2019
1d35517
Stashing this because settings reloading is on fire
zadjii-msft Jun 19, 2019
f1d89d6
Merge remote-tracking branch 'origin/master' into dev/migrie/f/995-na…
zadjii-msft Jun 19, 2019
a29efa3
Add comments to prepare for PR
zadjii-msft Jun 19, 2019
d65f551
Merge remote-tracking branch 'origin/master' into dev/migrie/f/991-re…
zadjii-msft Jul 3, 2019
11a150a
Pr Feedback
zadjii-msft Jul 3, 2019
4e9db7b
Merge remote-tracking branch 'origin/master' into dev/migrie/f/991-re…
zadjii-msft Jul 10, 2019
b9ef995
Merge branch 'dev/migrie/f/991-resizable-panes' into dev/migrie/f/995…
zadjii-msft Jul 10, 2019
a431a80
Merge remote-tracking branch 'origin/master' into dev/migrie/f/995-na…
zadjii-msft Jul 10, 2019
6f8802d
Fix a build break from a bad merge
zadjii-msft Jul 10, 2019
e8c5f9e
Update src/cascadia/TerminalApp/Pane.cpp
zadjii-msft Jul 12, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/cascadia/TerminalApp/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ namespace winrt::TerminalApp::implementation
bindings.SwitchToTab([this](const auto index) { _SelectTab({ index }); });
bindings.OpenSettings([this]() { _OpenSettings(); });
bindings.ResizePane([this](const auto direction) { _ResizePane(direction); });
bindings.MoveFocus([this](const auto direction) { _MoveFocus(direction); });
bindings.CopyText([this](const auto trimWhitespace) { _CopyText(trimWhitespace); });
bindings.PasteText([this]() { _PasteText(); });
}
Expand Down Expand Up @@ -984,6 +985,20 @@ namespace winrt::TerminalApp::implementation
_tabs[focusedTabIndex]->ResizePane(direction);
}

// Method Description:
// - Attempt to move focus between panes, as to focus the child on
// the other side of the separator. See Pane::NavigateFocus for details.
// - Moves the focus of the currently focused tab.
// Arguments:
// - direction: The direction to move the focus in.
// Return Value:
// - <none>
void App::_MoveFocus(const Direction& direction)
{
const auto focusedTabIndex = _GetFocusedTabIndex();
_tabs[focusedTabIndex]->NavigateFocus(direction);
}

// Method Description:
// - Copy text from the focused terminal to the Windows Clipboard
// Arguments:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ namespace winrt::TerminalApp::implementation
// MSFT:20641986: Add keybindings for New Window
void _ScrollPage(int delta);
void _ResizePane(const Direction& direction);
void _MoveFocus(const Direction& direction);

void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _OnTabSelectionChanged(const IInspectable& sender, const Windows::UI::Xaml::Controls::SelectionChangedEventArgs& eventArgs);
Expand Down
14 changes: 13 additions & 1 deletion src/cascadia/TerminalApp/AppKeyBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,18 @@ namespace winrt::TerminalApp::implementation
case ShortcutAction::ResizePaneDown:
_ResizePaneHandlers(Direction::Down);
return true;

case ShortcutAction::MoveFocusLeft:
_MoveFocusHandlers(Direction::Left);
return true;
case ShortcutAction::MoveFocusRight:
_MoveFocusHandlers(Direction::Right);
return true;
case ShortcutAction::MoveFocusUp:
_MoveFocusHandlers(Direction::Up);
return true;
case ShortcutAction::MoveFocusDown:
_MoveFocusHandlers(Direction::Down);
return true;
default:
return false;
}
Expand Down Expand Up @@ -251,5 +262,6 @@ namespace winrt::TerminalApp::implementation
DEFINE_EVENT(AppKeyBindings, ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
DEFINE_EVENT(AppKeyBindings, OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
DEFINE_EVENT(AppKeyBindings, ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
DEFINE_EVENT(AppKeyBindings, MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
// clang-format on
}
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/AppKeyBindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ namespace winrt::TerminalApp::implementation
DECLARE_EVENT(ScrollDownPage, _ScrollDownPageHandlers, TerminalApp::ScrollDownPageEventArgs);
DECLARE_EVENT(OpenSettings, _OpenSettingsHandlers, TerminalApp::OpenSettingsEventArgs);
DECLARE_EVENT(ResizePane, _ResizePaneHandlers, TerminalApp::ResizePaneEventArgs);
DECLARE_EVENT(MoveFocus, _MoveFocusHandlers, TerminalApp::MoveFocusEventArgs);
// clang-format on

private:
Expand Down
9 changes: 7 additions & 2 deletions src/cascadia/TerminalApp/AppKeyBindings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ namespace TerminalApp
ResizePaneRight,
ResizePaneUp,
ResizePaneDown,
MoveFocusLeft,
MoveFocusRight,
MoveFocusUp,
MoveFocusDown,
OpenSettings
};

Expand All @@ -77,9 +81,9 @@ namespace TerminalApp
delegate void ScrollDownPageEventArgs();
delegate void OpenSettingsEventArgs();
delegate void ResizePaneEventArgs(Direction direction);
delegate void MoveFocusEventArgs(Direction direction);

[default_interface]
runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
[default_interface] runtimeclass AppKeyBindings : Microsoft.Terminal.Settings.IKeyBindings
{
AppKeyBindings();

Expand Down Expand Up @@ -107,5 +111,6 @@ namespace TerminalApp
event ScrollDownPageEventArgs ScrollDownPage;
event OpenSettingsEventArgs OpenSettings;
event ResizePaneEventArgs ResizePane;
event MoveFocusEventArgs MoveFocus;
}
}
8 changes: 8 additions & 0 deletions src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ static constexpr std::string_view ResizePaneLeftKey{ "resizePaneLeft" };
static constexpr std::string_view ResizePaneRightKey{ "resizePaneRight" };
static constexpr std::string_view ResizePaneUpKey{ "resizePaneUp" };
static constexpr std::string_view ResizePaneDownKey{ "resizePaneDown" };
static constexpr std::string_view MoveFocusLeftKey{ "moveFocusLeft" };
static constexpr std::string_view MoveFocusRightKey{ "moveFocusRight" };
static constexpr std::string_view MoveFocusUpKey{ "moveFocusUp" };
static constexpr std::string_view MoveFocusDownKey{ "moveFocusDown" };

// Specifically use a map here over an unordered_map. We want to be able to
// iterate over these entries in-order when we're serializing the keybindings.
Expand Down Expand Up @@ -105,6 +109,10 @@ static const std::map<std::string_view, ShortcutAction, std::less<>> commandName
{ ResizePaneRightKey, ShortcutAction::ResizePaneRight },
{ ResizePaneUpKey, ShortcutAction::ResizePaneUp },
{ ResizePaneDownKey, ShortcutAction::ResizePaneDown },
{ MoveFocusLeftKey, ShortcutAction::MoveFocusLeft },
{ MoveFocusRightKey, ShortcutAction::MoveFocusRight },
{ MoveFocusUpKey, ShortcutAction::MoveFocusUp },
{ MoveFocusDownKey, ShortcutAction::MoveFocusDown },
{ OpenSettingsKey, ShortcutAction::OpenSettings },
};

Expand Down
89 changes: 89 additions & 0 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,95 @@ bool Pane::ResizePane(const Direction& direction)
return false;
}

// Method Description:
// - Attempts to handle moving focus to one of our children. If our split
// direction isn't appropriate for the move direction, then we'll return
// false, to try and let our parent handle the move. If our child we'd move
// focus to is already focused, we'll also return false, to again let our
// parent try and handle the focus movement.
// Arguments:
// - direction: The direction to move the focus in.
// Return Value:
// - true if we handled this focus move request.
bool Pane::_NavigateFocus(const Direction& direction)
{
if (!DirectionMatchesSplit(direction, _splitState))
{
return false;
}

const bool focusSecond = (direction == Direction::Right) || (direction == Direction::Down);

const auto newlyFocusedChild = focusSecond ? _secondChild : _firstChild;

// If the child we want to move focus to is _already_ focused, return false,
// to try and let our parent figure it out.
if (newlyFocusedChild->WasLastFocused())
{
return false;
}

// Transfer focus to our child, and update the focus of our tree.
newlyFocusedChild->_FocusFirstChild();
UpdateFocus();

return true;
}

// Method Description:
// - Attempts to move focus to one of our children. If we have a focused child,
// we'll try to move the focus in the direction requested.
// - If there isn't a pane that exists as a child of this pane in the correct
// direction, we'll return false. This will indicate to our parent that they
// should try and move the focus themselves. In this way, the focus can move
// up and down the tree to the correct pane.
// - This method is _very_ similar to ResizePane. Both are trying to find the
// right separator to move (focus) in a direction.
// Arguments:
// - direction: The direction to move the focus in.
// Return Value:
// - true if we or a child handled this focus move request.
bool Pane::NavigateFocus(const Direction& direction)
{
// If we're a leaf, do nothing. We can't possibly have a descendant with a
// separator the correct direction.
if (_IsLeaf())
{
return false;
}

// Check if either our first or second child is the currently focused leaf.
// If it is, and the requested move direction matches our separator, then
// we're the pane that needs to handle this focus move.
const bool firstIsFocused = _firstChild->_IsLeaf() && _firstChild->_lastFocused;
const bool secondIsFocused = _secondChild->_IsLeaf() && _secondChild->_lastFocused;
if (firstIsFocused || secondIsFocused)
{
return _NavigateFocus(direction);
}
else
{
// If neither of our children were the focused leaf, then recurse into
// our children and see if they can handle the focus move.
// For each child, if it has a focused descendant, try having that child
// handle the focus move.
// If the child wasn't able to handle the focus move, it's possible that
// there were no descendants with a separator the correct direction. If
// our separator _is_ the correct direction, then we should be the pane
// to move focus into our other child. Otherwise, just return false, as
// we couldn't handle it either.
if ((!_firstChild->_IsLeaf()) && _firstChild->_HasFocusedChild())
{
return _firstChild->NavigateFocus(direction) || _NavigateFocus(direction);
}
else if ((!_secondChild->_IsLeaf()) && _secondChild->_HasFocusedChild())
{
return _secondChild->NavigateFocus(direction) || _NavigateFocus(direction);
}
}
return false;
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
}

// Method Description:
// - Called when our attached control is closed. Triggers listeners to our close
// event, if we're a leaf pane.
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalApp/Pane.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Pane : public std::enable_shared_from_this<Pane>
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
bool ResizePane(const winrt::TerminalApp::Direction& direction);
bool NavigateFocus(const winrt::TerminalApp::Direction& direction);

void SplitHorizontal(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
void SplitVertical(const GUID& profile, const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
Expand Down Expand Up @@ -80,7 +81,9 @@ class Pane : public std::enable_shared_from_this<Pane>
void _CreateRowColDefinitions(const winrt::Windows::Foundation::Size& rootSize);
void _CreateSplitContent();
void _ApplySplitDefinitions();

bool _Resize(const winrt::TerminalApp::Direction& direction);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
bool _NavigateFocus(const winrt::TerminalApp::Direction& direction);

void _CloseChild(const bool closeFirst);

Expand Down
12 changes: 12 additions & 0 deletions src/cascadia/TerminalApp/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,16 @@ void Tab::ResizePane(const winrt::TerminalApp::Direction& direction)
_rootPane->ResizePane(direction);
}

// Method Description:
// - Attempt to move focus between panes, as to focus the child on
// the other side of the separator. See Pane::NavigateFocus for details.
// Arguments:
// - direction: The direction to move the focus in.
// Return Value:
// - <none>
void Tab::NavigateFocus(const winrt::TerminalApp::Direction& direction)
{
_rootPane->NavigateFocus(direction);
}

DEFINE_EVENT(Tab, Closed, _closedHandlers, ConnectionClosedEventArgs);
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/Tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Tab
void UpdateFocus();
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
void ResizePane(const winrt::TerminalApp::Direction& direction);
void NavigateFocus(const winrt::TerminalApp::Direction& direction);

void UpdateSettings(const winrt::Microsoft::Terminal::Settings::TerminalSettings& settings, const GUID& profile);
winrt::hstring GetFocusedTitle() const;
Expand Down