diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 6ff980d9c35..df05b540007 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -2816,14 +2816,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } - void ControlCore::AnchorContextMenu(const til::point viewportRelativeCharacterPosition) - { - // viewportRelativeCharacterPosition is relative to the current - // viewport, so adjust for that: - const auto lock = _terminal->LockForReading(); - _contextMenuBufferPosition = _terminal->GetViewport().Origin() + viewportRelativeCharacterPosition; - } - void ControlCore::_contextMenuSelectMark( const til::point& pos, bool (*filter)(const ::MarkExtents&), @@ -2859,17 +2851,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } - void ControlCore::ContextMenuSelectCommand() + void ControlCore::ContextMenuSelectCommand(Core::Point viewportRelativeCharacterPosition) { + const auto contextMenuBufferPosition = _terminal->GetViewport().Origin() + til::point{ viewportRelativeCharacterPosition }; _contextMenuSelectMark( - _contextMenuBufferPosition, + contextMenuBufferPosition, [](const ::MarkExtents& m) -> bool { return !m.HasCommand(); }, [](const ::MarkExtents& m) { return til::point_span{ m.end, *m.commandEnd }; }); } - void ControlCore::ContextMenuSelectOutput() + void ControlCore::ContextMenuSelectOutput(Core::Point viewportRelativeCharacterPosition) { + const auto contextMenuBufferPosition = _terminal->GetViewport().Origin() + til::point{ viewportRelativeCharacterPosition }; _contextMenuSelectMark( - _contextMenuBufferPosition, + contextMenuBufferPosition, [](const ::MarkExtents& m) -> bool { return !m.HasOutput(); }, [](const ::MarkExtents& m) { return til::point_span{ *m.commandEnd, *m.outputEnd }; }); } @@ -2909,24 +2903,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation return false; } - // Method Description: - // * Don't show this if the click was on the _current_ selection - // * Don't show this if the click wasn't on a mark with at least a command - // * Otherwise yea, show it. - bool ControlCore::ShouldShowSelectCommand() + MenuAction ControlCore::GetApplicableMenuActionsAtPosition(Core::Point viewportRelativeCharacterPosition) { - // Relies on the anchor set in AnchorContextMenu - return _clickedOnMark(_contextMenuBufferPosition, - [](const ::MarkExtents& m) -> bool { return !m.HasCommand(); }); - } + const auto contextMenuBufferPosition = _terminal->GetViewport().Origin() + til::point{ viewportRelativeCharacterPosition }; + MenuAction r{}; - // Method Description: - // * Same as ShouldShowSelectCommand, but with the mark needing output - bool ControlCore::ShouldShowSelectOutput() - { - // Relies on the anchor set in AnchorContextMenu - return _clickedOnMark(_contextMenuBufferPosition, - [](const ::MarkExtents& m) -> bool { return !m.HasOutput(); }); + const auto clickedOnCommand = _clickedOnMark(contextMenuBufferPosition, + [](const ::MarkExtents& m) -> bool { return !m.HasCommand(); }); + const auto clickedOnOutput = _clickedOnMark(contextMenuBufferPosition, + [](const ::MarkExtents& m) -> bool { return !m.HasOutput(); }); + + WI_UpdateFlag(r, MenuAction::SelectCommand, clickedOnCommand); + WI_UpdateFlag(r, MenuAction::SelectOutput, clickedOnOutput); + return r; } void ControlCore::PreviewInput(std::wstring_view input) diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index 59ebdc9e830..46a32fe0c15 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -186,8 +186,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation void SelectCommand(const bool goUp); void SelectOutput(const bool goUp); - void ContextMenuSelectCommand(); - void ContextMenuSelectOutput(); + void ContextMenuSelectCommand(winrt::Microsoft::Terminal::Core::Point viewportRelativeCharacterPosition); + void ContextMenuSelectOutput(winrt::Microsoft::Terminal::Core::Point viewportRelativeCharacterPosition); #pragma endregion #pragma region ITerminalInput @@ -258,10 +258,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TerminalConnection::ITerminalConnection Connection(); void Connection(const TerminalConnection::ITerminalConnection& connection); - void AnchorContextMenu(til::point viewportRelativeCharacterPosition); - - bool ShouldShowSelectCommand(); - bool ShouldShowSelectOutput(); + MenuAction GetApplicableMenuActionsAtPosition(winrt::Microsoft::Terminal::Core::Point viewportRelativeCharacterPosition); void PreviewInput(std::wstring_view input); diff --git a/src/cascadia/TerminalControl/ControlCore.idl b/src/cascadia/TerminalControl/ControlCore.idl index c4a09a42122..4d45d3da9dd 100644 --- a/src/cascadia/TerminalControl/ControlCore.idl +++ b/src/cascadia/TerminalControl/ControlCore.idl @@ -20,6 +20,11 @@ namespace Microsoft.Terminal.Control IsRightButtonDown = 0x4 }; + [flags] enum MenuAction { + SelectCommand = 0x1, + SelectOutput = 0x2, + }; + enum ClearBufferType { Screen, @@ -163,10 +168,9 @@ namespace Microsoft.Terminal.Control void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode); - void ContextMenuSelectCommand(); - void ContextMenuSelectOutput(); - Boolean ShouldShowSelectCommand(); - Boolean ShouldShowSelectOutput(); + MenuAction GetApplicableMenuActionsAtPosition(Microsoft.Terminal.Core.Point pos); + void ContextMenuSelectCommand(Microsoft.Terminal.Core.Point pos); + void ContextMenuSelectOutput(Microsoft.Terminal.Core.Point pos); void ClearQuickFix(); diff --git a/src/cascadia/TerminalControl/ControlInteractivity.cpp b/src/cascadia/TerminalControl/ControlInteractivity.cpp index 7b59babd2e5..9b20fe7b50f 100644 --- a/src/cascadia/TerminalControl/ControlInteractivity.cpp +++ b/src/cascadia/TerminalControl/ControlInteractivity.cpp @@ -301,12 +301,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation { if (_core->Settings().RightClickContextMenu()) { - // Let the core know we're about to open a menu here. It has - // some separate conditional logic based on _where_ the user - // wanted to open the menu. - _core->AnchorContextMenu(terminalPosition); - - auto contextArgs = winrt::make(til::point{ pixelPosition }.to_winrt_point()); + auto contextArgs = winrt::make( + til::point{ pixelPosition }.to_winrt_point(), + terminalPosition.to_core_point()); ContextMenuRequested.raise(*this, contextArgs); } else diff --git a/src/cascadia/TerminalControl/EventArgs.h b/src/cascadia/TerminalControl/EventArgs.h index 6770da9f62d..687f3f3e2b8 100644 --- a/src/cascadia/TerminalControl/EventArgs.h +++ b/src/cascadia/TerminalControl/EventArgs.h @@ -49,10 +49,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation struct ContextMenuRequestedEventArgs : public ContextMenuRequestedEventArgsT { public: - ContextMenuRequestedEventArgs(winrt::Windows::Foundation::Point pos) : - _Position(pos) {} + ContextMenuRequestedEventArgs(winrt::Windows::Foundation::Point pos, winrt::Microsoft::Terminal::Core::Point pos2) : + _PixelPosition(pos), + _TerminalPosition(pos2) {} - WINRT_PROPERTY(winrt::Windows::Foundation::Point, Position); + WINRT_PROPERTY(winrt::Windows::Foundation::Point, PixelPosition); + WINRT_PROPERTY(winrt::Microsoft::Terminal::Core::Point, TerminalPosition); }; struct PasteFromClipboardEventArgs : public PasteFromClipboardEventArgsT diff --git a/src/cascadia/TerminalControl/EventArgs.idl b/src/cascadia/TerminalControl/EventArgs.idl index 6cad9ccff7d..613b33dc5ab 100644 --- a/src/cascadia/TerminalControl/EventArgs.idl +++ b/src/cascadia/TerminalControl/EventArgs.idl @@ -33,7 +33,8 @@ namespace Microsoft.Terminal.Control runtimeclass ContextMenuRequestedEventArgs { - Windows.Foundation.Point Position { get; }; + Windows.Foundation.Point PixelPosition { get; }; + Microsoft.Terminal.Core.Point TerminalPosition { get; }; } runtimeclass TitleChangedEventArgs diff --git a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw index 90648381e1a..e6f0fe1836e 100644 --- a/src/cascadia/TerminalControl/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalControl/Resources/en-US/Resources.resw @@ -253,14 +253,6 @@ Please either install the missing font or choose another one. Copy The tooltip for a copy button - - Paste - The label of a button for pasting the contents of the clipboard. - - - Paste - The tooltip for a paste button - Find... The label of a button for searching for the selected text @@ -285,22 +277,6 @@ Please either install the missing font or choose another one. Select output The tooltip for a button for selecting all of a command's output - - Select command - The label of a button for selecting all of the text of a command - - - Select command - The tooltip for a button for selecting all of the text of a command - - - Select output - The label of a button for selecting all of a command's output - - - Select output - The tooltip for a button for selecting all of a command's output - Quick fix @@ -334,4 +310,4 @@ Please either install the missing font or choose another one. Suggested input: {0} {Locked="{0}"} {0} will be replaced with a string of input that is suggested for the user to input - \ No newline at end of file + diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index e53a8ada1c4..3e4ee03b0ac 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -3844,6 +3844,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation this->TransformToVisual(nullptr).TransformPoint(Windows::Foundation::Point(0, 0)) }; const auto pos = (absolutePointerPos - absoluteWindowOrigin - controlOrigin); + _lastContextMenuTerminalPosition = args.TerminalPosition(); _showContextMenuAt(pos); } @@ -3854,14 +3855,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation myOption.Placement(Controls::Primitives::FlyoutPlacementMode::TopEdgeAlignedLeft); myOption.Position(controlRelativePos.to_winrt_point()); + const auto applicableActions{ _core.GetApplicableMenuActionsAtPosition(_lastContextMenuTerminalPosition) }; + + const auto applicabilityToVisibility = [applicableActions](MenuAction a) { + return (applicableActions & a) != (MenuAction)0 ? Visibility::Visible : Visibility::Collapsed; + }; + // The "Select command" and "Select output" buttons should only be // visible if shell integration is actually turned on. - const auto shouldShowSelectCommand{ _core.ShouldShowSelectCommand() }; - const auto shouldShowSelectOutput{ _core.ShouldShowSelectOutput() }; - SelectCommandButton().Visibility(shouldShowSelectCommand ? Visibility::Visible : Visibility::Collapsed); - SelectOutputButton().Visibility(shouldShowSelectOutput ? Visibility::Visible : Visibility::Collapsed); - SelectCommandWithSelectionButton().Visibility(shouldShowSelectCommand ? Visibility::Visible : Visibility::Collapsed); - SelectOutputWithSelectionButton().Visibility(shouldShowSelectOutput ? Visibility::Visible : Visibility::Collapsed); + SelectCommandButton().Visibility(applicabilityToVisibility(MenuAction::SelectCommand)); + SelectCommandWithSelectionButton().Visibility(applicabilityToVisibility(MenuAction::SelectCommand)); + SelectOutputButton().Visibility(applicabilityToVisibility(MenuAction::SelectOutput)); + SelectOutputWithSelectionButton().Visibility(applicabilityToVisibility(MenuAction::SelectOutput)); (_core.HasSelection() ? SelectionContextMenu() : ContextMenu()) @@ -3881,6 +3886,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation // * {+1,+1} if there's no selection, to be on the bottom-right corner of // the cursor position cursorPos += til::point{ hasSelection ? 0 : 1, 1 }; + _lastContextMenuTerminalPosition = cursorPos.to_core_point(); _showContextMenuAt(_toControlOrigin(cursorPos)); } @@ -4014,7 +4020,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { ContextMenu().Hide(); SelectionContextMenu().Hide(); - _core.ContextMenuSelectCommand(); + _core.ContextMenuSelectCommand(_lastContextMenuTerminalPosition); } void TermControl::_SelectOutputHandler(const IInspectable& /*sender*/, @@ -4022,7 +4028,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { ContextMenu().Hide(); SelectionContextMenu().Hide(); - _core.ContextMenuSelectOutput(); + _core.ContextMenuSelectOutput(_lastContextMenuTerminalPosition); } // Should the text cursor be displayed, even when the control isn't focused? diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h index 13166e18c7a..d500d746311 100644 --- a/src/cascadia/TerminalControl/TermControl.h +++ b/src/cascadia/TerminalControl/TermControl.h @@ -275,6 +275,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation std::optional _lastAutoScrollUpdateTime; bool _pointerPressedInBounds{ false }; + winrt::Microsoft::Terminal::Core::Point _lastContextMenuTerminalPosition{}; + winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellLightAnimation{ nullptr }; winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellDarkAnimation{ nullptr }; SafeDispatcherTimer _bellLightTimer; diff --git a/src/cascadia/TerminalControl/TermControl.xaml b/src/cascadia/TerminalControl/TermControl.xaml index b0b24c47ced..c7bb9d6238c 100644 --- a/src/cascadia/TerminalControl/TermControl.xaml +++ b/src/cascadia/TerminalControl/TermControl.xaml @@ -60,7 +60,7 @@ Click="_CopyCommandHandler" Icon="Copy" /> @@ -69,7 +69,7 @@ Click="_SearchCommandHandler" Icon="Find" />