mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 18:43:54 -06:00
* Scroll from selection dragging out of window * Review changes, dynamic dt measurement, function separation
This commit is contained in:
parent
e662277cb0
commit
5da2ab1a86
@ -35,6 +35,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_settings{ settings },
|
||||
_closing{ false },
|
||||
_lastScrollOffset{ std::nullopt },
|
||||
_autoScrollVelocity{ 0 },
|
||||
_autoScrollingPointerPoint{ std::nullopt },
|
||||
_autoScrollTimer{},
|
||||
_lastAutoScrollUpdateTime{ std::nullopt },
|
||||
_desiredFont{ DEFAULT_FONT_FACE.c_str(), 0, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
|
||||
_actualFont{ DEFAULT_FONT_FACE.c_str(), 0, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false },
|
||||
_touchAnchor{ std::nullopt },
|
||||
@ -500,6 +504,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
auto pfnScrollPositionChanged = std::bind(&TermControl::_TerminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
_terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged);
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||
|
||||
// Set up blinking cursor
|
||||
int blinkTime = GetCaretBlinkTime();
|
||||
if (blinkTime != INFINITE)
|
||||
@ -743,14 +751,33 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Mouse)
|
||||
{
|
||||
if (point.Properties().IsLeftButtonPressed())
|
||||
if (_terminal->IsSelectionActive() && point.Properties().IsLeftButtonPressed())
|
||||
{
|
||||
const auto cursorPosition = point.Position();
|
||||
const auto terminalPosition = _GetTerminalPosition(cursorPosition);
|
||||
_SetEndSelectionPointAtCursor(cursorPosition);
|
||||
|
||||
// save location (for rendering) + render
|
||||
_terminal->SetEndSelectionPosition(terminalPosition);
|
||||
_renderer->TriggerSelection();
|
||||
const double cursorBelowBottomDist = cursorPosition.Y - _swapChainPanel.Margin().Top - _swapChainPanel.ActualHeight();
|
||||
const double cursorAboveTopDist = -1 * cursorPosition.Y + _swapChainPanel.Margin().Top;
|
||||
|
||||
constexpr double MinAutoScrollDist = 2.0; // Arbitrary value
|
||||
double newAutoScrollVelocity = 0.0;
|
||||
if (cursorBelowBottomDist > MinAutoScrollDist)
|
||||
{
|
||||
newAutoScrollVelocity = _GetAutoScrollSpeed(cursorBelowBottomDist);
|
||||
}
|
||||
else if (cursorAboveTopDist > MinAutoScrollDist)
|
||||
{
|
||||
newAutoScrollVelocity = -1.0 * _GetAutoScrollSpeed(cursorAboveTopDist);
|
||||
}
|
||||
|
||||
if (newAutoScrollVelocity != 0)
|
||||
{
|
||||
_TryStartAutoScroll(point, newAutoScrollVelocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_TryStopAutoScroll(ptr.PointerId());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch && _touchAnchor)
|
||||
@ -806,6 +833,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_touchAnchor = std::nullopt;
|
||||
}
|
||||
|
||||
_TryStopAutoScroll(ptr.PointerId());
|
||||
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@ -818,7 +847,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void TermControl::_MouseWheelHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Input::PointerRoutedEventArgs const& args)
|
||||
{
|
||||
auto delta = args.GetCurrentPoint(_root).Properties().MouseWheelDelta();
|
||||
const auto point = args.GetCurrentPoint(_root);
|
||||
const auto delta = point.Properties().MouseWheelDelta();
|
||||
|
||||
// Get the state of the Ctrl & Shift keys
|
||||
// static_cast to a uint32_t because we can't use the WI_IsFlagSet macro
|
||||
// directly with a VirtualKeyModifiers
|
||||
@ -836,7 +867,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
_MouseScrollHandler(delta);
|
||||
_MouseScrollHandler(delta, point);
|
||||
}
|
||||
}
|
||||
|
||||
@ -893,7 +924,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// - Scroll the visible viewport in response to a mouse wheel event.
|
||||
// Arguments:
|
||||
// - mouseDelta: the mouse wheel delta that triggered this event.
|
||||
void TermControl::_MouseScrollHandler(const double mouseDelta)
|
||||
void TermControl::_MouseScrollHandler(const double mouseDelta, Windows::UI::Input::PointerPoint const& pointerPoint)
|
||||
{
|
||||
const auto currentOffset = this->GetScrollOffset();
|
||||
|
||||
@ -915,6 +946,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// The scroll bar's ValueChanged handler will actually move the viewport
|
||||
// for us.
|
||||
_scrollBar.Value(static_cast<int>(newValue));
|
||||
|
||||
if (_terminal->IsSelectionActive() && pointerPoint.Properties().IsLeftButtonPressed())
|
||||
{
|
||||
// If user is mouse selecting and scrolls, they then point at new character.
|
||||
// Make sure selection reflects that immediately.
|
||||
_SetEndSelectionPointAtCursor(pointerPoint.Position());
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::_ScrollbarChangeHandler(Windows::Foundation::IInspectable const& sender,
|
||||
@ -982,6 +1020,84 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Starts new pointer related auto scroll behavior, or continues existing one.
|
||||
// Does nothing when there is already auto scroll associated with another pointer.
|
||||
// Arguments:
|
||||
// - pointerPoint: info about pointer that causes auto scroll. Pointer's position
|
||||
// is later used to update selection.
|
||||
// - scrollVelocity: target velocity of scrolling in characters / sec
|
||||
void TermControl::_TryStartAutoScroll(Windows::UI::Input::PointerPoint const& pointerPoint, const double scrollVelocity)
|
||||
{
|
||||
// Allow only one pointer at the time
|
||||
if (!_autoScrollingPointerPoint.has_value() || _autoScrollingPointerPoint.value().PointerId() == pointerPoint.PointerId())
|
||||
{
|
||||
_autoScrollingPointerPoint = pointerPoint;
|
||||
_autoScrollVelocity = scrollVelocity;
|
||||
|
||||
// If this is first time the auto scroll update is about to be called,
|
||||
// kick-start it by initializing its time delta as if it started now
|
||||
if (!_lastAutoScrollUpdateTime.has_value())
|
||||
{
|
||||
_lastAutoScrollUpdateTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// Apparently this check is not necessary but greatly improves performance
|
||||
if (!_autoScrollTimer.IsEnabled())
|
||||
{
|
||||
_autoScrollTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Stops auto scroll if it's active and is associated with supplied pointer id.
|
||||
// Arguments:
|
||||
// - pointerId: id of pointer for which to stop auto scroll
|
||||
void TermControl::_TryStopAutoScroll(const uint32_t pointerId)
|
||||
{
|
||||
if (_autoScrollingPointerPoint.has_value() && pointerId == _autoScrollingPointerPoint.value().PointerId())
|
||||
{
|
||||
_autoScrollingPointerPoint = std::nullopt;
|
||||
_autoScrollVelocity = 0;
|
||||
_lastAutoScrollUpdateTime = std::nullopt;
|
||||
|
||||
// Apparently this check is not necessary but greatly improves performance
|
||||
if (_autoScrollTimer.IsEnabled())
|
||||
{
|
||||
_autoScrollTimer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called continuously to gradually scroll viewport when user is
|
||||
// mouse selecting outside it (to 'follow' the cursor).
|
||||
// Arguments:
|
||||
// - none
|
||||
void TermControl::_UpdateAutoScroll(Windows::Foundation::IInspectable const& /* sender */,
|
||||
Windows::Foundation::IInspectable const& /* e */)
|
||||
{
|
||||
if (_autoScrollVelocity != 0)
|
||||
{
|
||||
const auto timeNow = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (_lastAutoScrollUpdateTime.has_value())
|
||||
{
|
||||
static constexpr double microSecPerSec = 1000000.0;
|
||||
const double deltaTime = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - _lastAutoScrollUpdateTime.value()).count() / microSecPerSec;
|
||||
_scrollBar.Value(_scrollBar.Value() + _autoScrollVelocity * deltaTime);
|
||||
|
||||
if (_autoScrollingPointerPoint.has_value())
|
||||
{
|
||||
_SetEndSelectionPointAtCursor(_autoScrollingPointerPoint.value().Position());
|
||||
}
|
||||
}
|
||||
|
||||
_lastAutoScrollUpdateTime = timeNow;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Event handler for the GotFocus event. This is used to start
|
||||
// blinking the cursor when the window is focused.
|
||||
@ -1087,6 +1203,25 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
_terminal->SetCursorVisible(!_terminal->IsCursorVisible());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
|
||||
// Arguments:
|
||||
// - cursorPosition: in pixels, relative to the origin of the control
|
||||
void TermControl::_SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition)
|
||||
{
|
||||
auto terminalPosition = _GetTerminalPosition(cursorPosition);
|
||||
|
||||
const short lastVisibleRow = std::max(_terminal->GetViewport().Height() - 1, 0);
|
||||
const short lastVisibleCol = std::max(_terminal->GetViewport().Width() - 1, 0);
|
||||
|
||||
terminalPosition.Y = std::clamp(terminalPosition.Y, short{ 0 }, lastVisibleRow);
|
||||
terminalPosition.X = std::clamp(terminalPosition.X, short{ 0 }, lastVisibleCol);
|
||||
|
||||
// save location (for rendering) + render
|
||||
_terminal->SetEndSelectionPosition(terminalPosition);
|
||||
_renderer->TriggerSelection();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Process a resize event that was initiated by the user. This can either
|
||||
// be due to the user resizing the window (causing the swapchain to
|
||||
@ -1237,6 +1372,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
// cursorTimer timer, now stopped, is destroyed.
|
||||
}
|
||||
|
||||
if (auto localAutoScrollTimer{ std::exchange(_autoScrollTimer, nullptr) })
|
||||
{
|
||||
localAutoScrollTimer.Stop();
|
||||
// _autoScrollTimer timer, now stopped, is destroyed.
|
||||
}
|
||||
|
||||
if (auto localConnection{ std::exchange(_connection, nullptr) })
|
||||
{
|
||||
localConnection.Close();
|
||||
@ -1580,6 +1721,20 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
return _multiClickCounter;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Calculates speed of single axis of auto scrolling. It has to allow for both
|
||||
// fast and precise selection.
|
||||
// Arguments:
|
||||
// - cursorDistanceFromBorder: distance from viewport border to cursor, in pixels. Must be non-negative.
|
||||
// Return Value:
|
||||
// - positive speed in characters / sec
|
||||
double TermControl::_GetAutoScrollSpeed(double cursorDistanceFromBorder) const
|
||||
{
|
||||
// The numbers below just feel well, feel free to change.
|
||||
// TODO: Maybe account for space beyond border that user has available
|
||||
return std::pow(cursorDistanceFromBorder, 2.0) / 25.0 + 2.0;
|
||||
}
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
// Winrt events need a method for adding a callback to the event and removing the callback.
|
||||
// These macros will define them both for you.
|
||||
|
||||
@ -92,6 +92,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
std::optional<int> _lastScrollOffset;
|
||||
|
||||
// Auto scroll occurs when user, while selecting, drags cursor outside viewport. View is then scrolled to 'follow' the cursor.
|
||||
double _autoScrollVelocity;
|
||||
std::optional<Windows::UI::Input::PointerPoint> _autoScrollingPointerPoint;
|
||||
Windows::UI::Xaml::DispatcherTimer _autoScrollTimer;
|
||||
std::optional<std::chrono::high_resolution_clock::time_point> _lastAutoScrollUpdateTime;
|
||||
|
||||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
std::optional<wchar_t> _leadingSurrogate;
|
||||
|
||||
@ -135,6 +141,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _LostFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
|
||||
void _BlinkCursor(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
|
||||
void _SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition);
|
||||
void _SendInputToConnection(const std::wstring& wstr);
|
||||
void _SwapChainSizeChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::SizeChangedEventArgs const& e);
|
||||
void _SwapChainScaleChanged(Windows::UI::Xaml::Controls::SwapChainPanel const& sender, Windows::Foundation::IInspectable const& args);
|
||||
@ -142,13 +149,17 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
void _TerminalTitleChanged(const std::wstring_view& wstr);
|
||||
void _TerminalScrollPositionChanged(const int viewTop, const int viewHeight, const int bufferSize);
|
||||
|
||||
void _MouseScrollHandler(const double delta);
|
||||
void _MouseScrollHandler(const double delta, Windows::UI::Input::PointerPoint const& pointerPoint);
|
||||
void _MouseZoomHandler(const double delta);
|
||||
void _MouseTransparencyHandler(const double delta);
|
||||
|
||||
bool _CapturePointer(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
bool _ReleasePointerCapture(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
|
||||
void _TryStartAutoScroll(Windows::UI::Input::PointerPoint const& pointerPoint, const double scrollVelocity);
|
||||
void _TryStopAutoScroll(const uint32_t pointerId);
|
||||
void _UpdateAutoScroll(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
|
||||
|
||||
void _ScrollbarUpdater(Windows::UI::Xaml::Controls::Primitives::ScrollBar scrollbar, const int viewTop, const int viewHeight, const int bufferSize);
|
||||
static Windows::UI::Xaml::Thickness _ParseThicknessFromPadding(const hstring padding);
|
||||
|
||||
@ -156,6 +167,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
||||
|
||||
const COORD _GetTerminalPosition(winrt::Windows::Foundation::Point cursorPosition);
|
||||
const unsigned int _NumberOfClicks(winrt::Windows::Foundation::Point clickPos, Timestamp clickTime);
|
||||
double _GetAutoScrollSpeed(double cursorDistanceFromBorder) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user