Ensure hyperlinks de-underline when pointer leaves terminal (#9195)

Introduced PointerExited handler to nullify last hovered cell
(which will also de-underline the hyperlink if required).

Closes #9141
This commit is contained in:
Don-Vito 2021-02-17 23:33:53 +02:00 committed by GitHub
parent ac3e4bfe56
commit 52d1533c4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 44 deletions

View file

@ -1435,48 +1435,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
}
}
if (terminalPosition != _lastHoveredCell)
{
const auto uri = _terminal->GetHyperlinkAtPosition(terminalPosition);
if (!uri.empty())
{
// Update the tooltip with the URI
HoveredUri().Text(uri);
// Set the border thickness so it covers the entire cell
const auto charSizeInPixels = CharacterDimensions();
const auto htInDips = charSizeInPixels.Height / SwapChainPanel().CompositionScaleY();
const auto wtInDips = charSizeInPixels.Width / SwapChainPanel().CompositionScaleX();
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
HyperlinkTooltipBorder().BorderThickness(newThickness);
// Compute the location of the top left corner of the cell in DIPS
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
const til::point startPos{ terminalPosition.X, terminalPosition.Y };
const til::size fontSize{ _actualFont.GetSize() };
const til::point posInPixels{ startPos * fontSize };
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
const til::point locationInDIPs{ posInDIPs + marginsInDips };
// Move the border to the top left corner of the cell
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), (locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), (locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
}
_lastHoveredCell = terminalPosition;
const auto newId = _terminal->GetHyperlinkIdAtPosition(terminalPosition);
const auto newInterval = _terminal->GetHyperlinkIntervalFromPosition(terminalPosition);
// If the hyperlink ID changed or the interval changed, trigger a redraw all
// (so this will happen both when we move onto a link and when we move off a link)
if (newId != _lastHoveredId || (newInterval != _lastHoveredInterval))
{
_lastHoveredId = newId;
_lastHoveredInterval = newInterval;
_renderEngine->UpdateHyperlinkHoveredId(newId);
_renderer->UpdateLastHoveredInterval(newInterval);
_renderer->TriggerRedrawAll();
}
}
_UpdateHoveredCell(terminalPosition);
}
else if (_focused && ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Touch && _touchAnchor)
{
@ -3303,6 +3262,74 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
}
}
// Method description:
// - Updates last hovered cell, renders / removes rendering of hyper-link if required
// Arguments:
// - terminalPosition: The terminal position of the pointer
void TermControl::_UpdateHoveredCell(const std::optional<COORD>& terminalPosition)
{
if (terminalPosition == _lastHoveredCell)
{
return;
}
_lastHoveredCell = terminalPosition;
if (terminalPosition.has_value())
{
const auto uri = _terminal->GetHyperlinkAtPosition(*terminalPosition);
if (!uri.empty())
{
// Update the tooltip with the URI
HoveredUri().Text(uri);
// Set the border thickness so it covers the entire cell
const auto charSizeInPixels = CharacterDimensions();
const auto htInDips = charSizeInPixels.Height / SwapChainPanel().CompositionScaleY();
const auto wtInDips = charSizeInPixels.Width / SwapChainPanel().CompositionScaleX();
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
HyperlinkTooltipBorder().BorderThickness(newThickness);
// Compute the location of the top left corner of the cell in DIPS
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
const til::point startPos{ terminalPosition->X, terminalPosition->Y };
const til::size fontSize{ _actualFont.GetSize() };
const til::point posInPixels{ startPos * fontSize };
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
const til::point locationInDIPs{ posInDIPs + marginsInDips };
// Move the border to the top left corner of the cell
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), (locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), (locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
}
}
const uint16_t newId = terminalPosition.has_value() ? _terminal->GetHyperlinkIdAtPosition(*terminalPosition) : 0u;
const auto newInterval = terminalPosition.has_value() ? _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition) : std::nullopt;
// If the hyperlink ID changed or the interval changed, trigger a redraw all
// (so this will happen both when we move onto a link and when we move off a link)
if (newId != _lastHoveredId || (newInterval != _lastHoveredInterval))
{
_lastHoveredId = newId;
_lastHoveredInterval = newInterval;
_renderEngine->UpdateHyperlinkHoveredId(newId);
_renderer->UpdateLastHoveredInterval(newInterval);
_renderer->TriggerRedrawAll();
}
}
// Method Description:
// - Handle a mouse exited event, specifically clearing last hovered cell
// and removing selection from hyper link if exists
// Arguments:
// - sender: not used
// - args: event data
void TermControl::_PointerExitedHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& /*e*/)
{
_UpdateHoveredCell(std::nullopt);
}
// -------------------------------- 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.

View file

@ -244,7 +244,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
std::optional<winrt::Windows::Foundation::Point> _touchAnchor;
// Track the last cell we hovered over (used in pointerMovedHandler)
COORD _lastHoveredCell;
std::optional<COORD> _lastHoveredCell;
// Track the last hyperlink ID we hovered over
uint16_t _lastHoveredId;
@ -283,6 +283,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
void _PointerPressedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerMovedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerReleasedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerExitedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _MouseWheelHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _ScrollbarChangeHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
void _GotFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
@ -345,6 +346,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
winrt::fire_and_forget _AsyncCloseConnection();
winrt::fire_and_forget _RaiseReadOnlyWarning();
void _UpdateHoveredCell(const std::optional<COORD>& terminalPosition);
};
}

View file

@ -45,7 +45,8 @@ the MIT License. See LICENSE in the project root for license information. -->
Background="Transparent"
PointerPressed="_PointerPressedHandler"
PointerMoved="_PointerMovedHandler"
PointerReleased="_PointerReleasedHandler">
PointerReleased="_PointerReleasedHandler"
PointerExited="_PointerExitedHandler">
<SwapChainPanel x:Name="SwapChainPanel"
SizeChanged="_SwapChainSizeChanged"