Add selection marker overlays for keyboard selection
This commit is contained in:
parent
b7842624a0
commit
ad2678051f
|
@ -378,6 +378,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second);
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(false));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -386,6 +387,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// When there is a selection active, escape should clear it and NOT flow through
|
||||
|
@ -909,6 +911,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_terminal->SetSelectionAnchor(position);
|
||||
}
|
||||
|
||||
Core::Point ControlCore::SelectionAnchor() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return til::point{ _terminal->SelectionStartForRendering() };
|
||||
}
|
||||
|
||||
Core::Point ControlCore::SelectionEnd() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return til::point{ _terminal->SelectionEndForRendering() };
|
||||
}
|
||||
|
||||
bool ControlCore::MovingStart() const
|
||||
{
|
||||
auto lock = _terminal->LockForReading();
|
||||
return _terminal->MovingStart();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
|
||||
// Arguments:
|
||||
|
@ -935,6 +955,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// save location (for rendering) + render
|
||||
_terminal->SetSelectionEnd(terminalPosition);
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// Called when the Terminal wants to set something to the clipboard, i.e.
|
||||
|
@ -995,6 +1016,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
{
|
||||
_terminal->ClearSelection();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
// send data up for clipboard
|
||||
|
@ -1286,6 +1308,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_terminal->SetBlockSelection(false);
|
||||
search.Select();
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1478,6 +1501,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
_renderer->TriggerSelection();
|
||||
_UpdateSelectionMarkersHandlers(*this, winrt::make<implementation::UpdateSelectionMarkersEventArgs>(true));
|
||||
}
|
||||
|
||||
void ControlCore::AttachUiaEngine(::Microsoft::Console::Render::IRenderEngine* const pEngine)
|
||||
|
|
|
@ -128,6 +128,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
bool HasSelection() const;
|
||||
bool CopyOnSelect() const;
|
||||
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
|
||||
Core::Point SelectionAnchor() const;
|
||||
Core::Point SelectionEnd() const;
|
||||
bool MovingStart() const;
|
||||
void SetSelectionAnchor(til::point const& position);
|
||||
void SetEndSelectionPoint(til::point const& position);
|
||||
|
||||
|
@ -169,6 +172,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);
|
||||
TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
|
||||
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
|
||||
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
|
||||
// clang-format on
|
||||
|
||||
private:
|
||||
|
|
|
@ -80,6 +80,9 @@ namespace Microsoft.Terminal.Control
|
|||
|
||||
Boolean HasSelection { get; };
|
||||
IVector<String> SelectedText(Boolean trimTrailingWhitespace);
|
||||
Microsoft.Terminal.Core.Point SelectionAnchor { get; };
|
||||
Microsoft.Terminal.Core.Point SelectionEnd { get; };
|
||||
Boolean MovingStart { get; };
|
||||
|
||||
String HoveredUriText { get; };
|
||||
Windows.Foundation.IReference<Microsoft.Terminal.Core.Point> HoveredCell { get; };
|
||||
|
@ -110,6 +113,7 @@ namespace Microsoft.Terminal.Control
|
|||
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
|
||||
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
#include "ScrollPositionChangedArgs.g.cpp"
|
||||
#include "RendererWarningArgs.g.cpp"
|
||||
#include "TransparencyChangedEventArgs.g.cpp"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.cpp"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "ScrollPositionChangedArgs.g.h"
|
||||
#include "RendererWarningArgs.g.h"
|
||||
#include "TransparencyChangedEventArgs.g.h"
|
||||
#include "UpdateSelectionMarkersEventArgs.g.h"
|
||||
#include "cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
@ -131,4 +132,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
WINRT_PROPERTY(double, Opacity);
|
||||
};
|
||||
|
||||
struct UpdateSelectionMarkersEventArgs : public UpdateSelectionMarkersEventArgsT<UpdateSelectionMarkersEventArgs>
|
||||
{
|
||||
public:
|
||||
UpdateSelectionMarkersEventArgs(const bool clearMarkers) :
|
||||
_ClearMarkers(clearMarkers)
|
||||
{
|
||||
}
|
||||
|
||||
WINRT_PROPERTY(bool, ClearMarkers, false);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -67,4 +67,9 @@ namespace Microsoft.Terminal.Control
|
|||
{
|
||||
Double Opacity { get; };
|
||||
}
|
||||
|
||||
runtimeclass UpdateSelectionMarkersEventArgs
|
||||
{
|
||||
Boolean ClearMarkers { get; };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
|
||||
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
|
||||
_core.HoveredHyperlinkChanged({ this, &TermControl::_hoveredHyperlinkChanged });
|
||||
_core.UpdateSelectionMarkers({ this, &TermControl::_updateSelectionMarkers });
|
||||
_interactivity.OpenHyperlink({ this, &TermControl::_HyperlinkHandler });
|
||||
_interactivity.ScrollPositionChanged({ this, &TermControl::_ScrollPositionChanged });
|
||||
|
||||
|
@ -333,6 +334,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const auto bg = newAppearance.DefaultBackground();
|
||||
_changeBackgroundColor(bg);
|
||||
|
||||
// Update selection markers
|
||||
Windows::UI::Xaml::Media::SolidColorBrush selectionBackgroundBrush{ til::color{ newAppearance.SelectionBackground() } };
|
||||
SelectionStartIcon().Foreground(selectionBackgroundBrush);
|
||||
SelectionEndIcon().Foreground(selectionBackgroundBrush);
|
||||
|
||||
// Set TSF Foreground
|
||||
Media::SolidColorBrush foregroundBrush{};
|
||||
foregroundBrush.Color(static_cast<til::color>(newAppearance.DefaultForeground()));
|
||||
|
@ -1659,6 +1665,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
update.newValue = args.ViewTop();
|
||||
|
||||
_updateScrollBar->Run(update);
|
||||
_updatePatternLocations->Run();
|
||||
_updateSelectionMarkers(nullptr, winrt::make<UpdateSelectionMarkersEventArgs>(false));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2464,8 +2472,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_core.ClearHoveredCell();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable sender,
|
||||
IInspectable args)
|
||||
winrt::fire_and_forget TermControl::_hoveredHyperlinkChanged(IInspectable /*sender*/,
|
||||
IInspectable /*args*/)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await resume_foreground(Dispatcher());
|
||||
|
@ -2488,12 +2496,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
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{ lastHoveredCell.Value() };
|
||||
const til::size fontSize{ til::math::rounding, _core.FontSize() };
|
||||
const til::point posInPixels{ startPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
const til::point locationInDIPs{ posInDIPs + marginsInDips };
|
||||
const til::point locationInDIPs{ _toPosInDips(lastHoveredCell.Value()) };
|
||||
|
||||
// Move the border to the top left corner of the cell
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(),
|
||||
|
@ -2505,10 +2508,71 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TermControl::_updateSelectionMarkers(IInspectable /*sender*/, Control::UpdateSelectionMarkersEventArgs args)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
co_await resume_foreground(Dispatcher());
|
||||
if (weakThis.get() && args)
|
||||
{
|
||||
if (_core.HasSelection() && !args.ClearMarkers())
|
||||
{
|
||||
// show/update selection markers
|
||||
// figure out which endpoint to move, get it and the relevant icon (hide the other icon)
|
||||
const auto movingStart{ _core.MovingStart() };
|
||||
const auto selectionAnchor{ movingStart ? _core.SelectionAnchor() : _core.SelectionEnd() };
|
||||
const auto& icon{ movingStart ? SelectionStartIcon() : SelectionEndIcon() };
|
||||
const auto& otherIcon{ movingStart ? SelectionEndIcon() : SelectionStartIcon() };
|
||||
icon.Opacity(1);
|
||||
otherIcon.Opacity(0);
|
||||
|
||||
// Compute the location of the top left corner of the cell in DIPS
|
||||
const til::point locationInDIPs{ _toPosInDips(selectionAnchor) };
|
||||
|
||||
// Move the icon to the top left corner of the cell
|
||||
SelectionCanvas().SetLeft(icon,
|
||||
(locationInDIPs.x() - SwapChainPanel().ActualOffset().x));
|
||||
SelectionCanvas().SetTop(icon,
|
||||
(locationInDIPs.y() - SwapChainPanel().ActualOffset().y));
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide selection markers
|
||||
SelectionStartIcon().Opacity(0);
|
||||
SelectionEndIcon().Opacity(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
til::point TermControl::_toPosInDips(const til::point terminalCellPos)
|
||||
{
|
||||
const til::size marginsInDips{ til::math::rounding, GetPadding().Left, GetPadding().Top };
|
||||
const til::size fontSize{ til::math::rounding, _core.FontSize() };
|
||||
const til::point posInPixels{ terminalCellPos * fontSize };
|
||||
const til::point posInDIPs{ posInPixels / SwapChainPanel().CompositionScaleX() };
|
||||
return posInDIPs + marginsInDips;
|
||||
}
|
||||
|
||||
void TermControl::_coreFontSizeChanged(const int fontWidth,
|
||||
const int fontHeight,
|
||||
const bool isInitialChange)
|
||||
{
|
||||
// scale the selection markers to be the size of a cell
|
||||
auto scaleIconMarker = [fontWidth, fontHeight](Windows::UI::Xaml::Controls::FontIcon icon) {
|
||||
const auto size{ icon.DesiredSize() };
|
||||
const auto scaleX = fontWidth / size.Width;
|
||||
const auto scaleY = fontHeight / size.Height;
|
||||
|
||||
Windows::UI::Xaml::Media::ScaleTransform transform{};
|
||||
transform.ScaleX(transform.ScaleX() * scaleX);
|
||||
transform.ScaleY(transform.ScaleY() * scaleY);
|
||||
icon.RenderTransform(transform);
|
||||
|
||||
// now hide the icon
|
||||
icon.Opacity(0);
|
||||
};
|
||||
scaleIconMarker(SelectionStartIcon());
|
||||
scaleIconMarker(SelectionEndIcon());
|
||||
|
||||
// Don't try to inspect the core here. The Core is raising this while
|
||||
// it's holding its write lock. If the handlers calls back to some
|
||||
// method on the TermControl on the same thread, and that _method_ calls
|
||||
|
|
|
@ -267,6 +267,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
void _FontInfoHandler(const IInspectable& sender, const FontInfoEventArgs& eventArgs);
|
||||
|
||||
winrt::fire_and_forget _hoveredHyperlinkChanged(IInspectable sender, IInspectable args);
|
||||
winrt::fire_and_forget _updateSelectionMarkers(IInspectable sender, Control::UpdateSelectionMarkersEventArgs args);
|
||||
|
||||
void _coreFontSizeChanged(const int fontWidth,
|
||||
const int fontHeight,
|
||||
|
@ -274,6 +275,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
|
||||
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
|
||||
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
|
||||
|
||||
til::point _toPosInDips(const til::point terminalCellPos);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,23 @@
|
|||
</ToolTipService.ToolTip>
|
||||
</Border>
|
||||
</Canvas>
|
||||
|
||||
<Canvas x:Name="SelectionCanvas"
|
||||
Visibility="Visible">
|
||||
<!-- LOAD BEARING Use Opacity instead of Visibility for these two FontIcons.
|
||||
Visibility::Collapsed prevents us from aquiring the desired size of the icons,
|
||||
resulting in an inability to scale them upon a FontSize change event -->
|
||||
<FontIcon x:Name="SelectionStartIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
Opacity="0">
|
||||
</FontIcon>
|
||||
<FontIcon x:Name="SelectionEndIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
Opacity="0">
|
||||
</FontIcon>
|
||||
</Canvas>
|
||||
</SwapChainPanel>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -251,6 +251,9 @@ public:
|
|||
|
||||
using UpdateSelectionParams = std::optional<std::pair<SelectionDirection, SelectionExpansion>>;
|
||||
static UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey);
|
||||
bool MovingStart() const noexcept;
|
||||
til::point SelectionStartForRendering() const;
|
||||
til::point SelectionEndForRendering() const;
|
||||
|
||||
const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace);
|
||||
#pragma endregion
|
||||
|
|
|
@ -82,6 +82,24 @@ const COORD Terminal::GetSelectionEnd() const noexcept
|
|||
return _selection->end;
|
||||
}
|
||||
|
||||
til::point Terminal::SelectionStartForRendering() const
|
||||
{
|
||||
auto pos{ _selection->start };
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
bufferSize.DecrementInBounds(pos);
|
||||
pos.Y = std::clamp<short>(base::ClampSub(pos.Y, _VisibleStartIndex()), bufferSize.Top(), bufferSize.BottomInclusive());
|
||||
return pos;
|
||||
}
|
||||
|
||||
til::point Terminal::SelectionEndForRendering() const
|
||||
{
|
||||
auto pos{ _selection->end };
|
||||
const auto bufferSize{ _buffer->GetSize() };
|
||||
bufferSize.IncrementInBounds(pos);
|
||||
pos.Y = std::clamp<short>(base::ClampSub(pos.Y, _VisibleStartIndex()), bufferSize.Top(), bufferSize.BottomInclusive());
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Checks if selection is active
|
||||
// Return Value:
|
||||
|
|
Loading…
Reference in a new issue