Compare commits

...

5 Commits

Author SHA1 Message Date
Mike Griese
fb460d7f60 This adds an actual scrollbar. gods, please just use less. 2023-07-13 11:10:09 -05:00
Mike Griese
df2fe4fe66 Turns out, the DX Renderer doesn't support horizontal scrooling. This will help. 2023-07-13 11:09:28 -05:00
Mike Griese
3f9e4559cd this is in fact a scrollbar 2023-07-13 09:00:53 -05:00
Mike Griese
cd1ebb6e67 I mean, I hate it, but that does seem to resize 2023-07-12 15:39:43 -05:00
Mike Griese
e7882c33c1 Huh, this kinda worked for #1860 2023-07-12 15:22:31 -05:00
14 changed files with 1815 additions and 27 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -355,9 +355,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetSelectionBackground(til::color{ _settings->SelectionBackground() });
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
const auto width = vp.Width();
const auto height = vp.Height();
_connection.Resize(height, width);
const auto visibleWidth = vp.Width();
const auto visibleHeight = vp.Height();
// _connection.Resize(height, width);
if (_owningHwnd != 0)
{
@@ -368,11 +368,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// Override the default width and height to match the size of the swapChainPanel
_settings->InitialCols(width);
_settings->InitialRows(height);
_settings->InitialCols(visibleWidth);
_settings->InitialRows(visibleHeight);
_terminal->CreateFromSettings(*_settings, *_renderer);
const auto realSize{ _terminal->GetRealViewportSize() };
_connection.Resize(realSize.height, realSize.width);
// IMPORTANT! Set this callback up sooner than later. If we do it
// after Enable, then it'll be possible to paint the frame once
// _before_ the warning handler is set up, and then warnings from
@@ -659,6 +660,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlCore::UserScrollViewportHorizontally(const int viewLeft)
{
// Clear the regex pattern tree so the renderer does not try to render them while scrolling
_terminal->ClearPatternTree();
// This is a scroll event that wasn't initiated by the terminal
// itself - it was initiated by the mouse wheel, or the scrollbar.
_terminal->UserScrollViewportHorizontally(viewLeft);
const auto shared = _shared.lock_shared();
if (shared->updatePatternLocations)
{
(*shared->updatePatternLocations)();
}
}
void ControlCore::AdjustOpacity(const double adjustment)
{
if (adjustment == 0)
@@ -1392,6 +1409,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _terminal->GetBufferHeight();
}
int ControlCore::HorizontalScrollOffset()
{
return _terminal->_horizontalOffset;
}
int ControlCore::ViewWidth() const
{
return _terminal->_visibleWidth;
}
int ControlCore::BufferWidth() const
{
return _terminal->GetRealViewportSize().width;
}
void ControlCore::_terminalWarningBell()
{
// Since this can only ever be triggered by output from the connection,
@@ -1447,10 +1477,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
viewHeight,
bufferSize) };
if (_inUnitTests) [[unlikely]]
{
_ScrollPositionChangedHandlers(*this, update);
}
if (_inUnitTests)
[[unlikely]]
{
_ScrollPositionChangedHandlers(*this, update);
}
else
{
const auto shared = _shared.lock_shared();

View File

@@ -139,10 +139,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TerminalConnection::ConnectionState ConnectionState() const;
// Vertical scrolling
int ScrollOffset();
int ViewHeight() const;
int BufferHeight() const;
// Horizontal scrolling
int HorizontalScrollOffset();
int ViewWidth() const;
int BufferWidth() const;
bool HasSelection() const;
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
@@ -175,6 +181,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const short wheelDelta,
const ::Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state);
void UserScrollViewport(const int viewTop);
void UserScrollViewportHorizontally(const int viewLeft);
void ClearBuffer(Control::ClearBufferType clearType);

View File

@@ -632,6 +632,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
void ControlInteractivity::UpdateHorizontalScrollbar(const double newValue)
{
// Set this as the new value of our internal scrollbar representation.
// We're doing this so we can accumulate fractional amounts of a row to
// scroll each time the mouse scrolls.
_internalHorizontalScrollbarPosition = std::clamp<double>(newValue, 0.0, _core->BufferWidth());
auto viewLeft = ::base::saturated_cast<int>(::std::round(_internalHorizontalScrollbarPosition));
if (viewLeft != _core->HorizontalScrollOffset())
{
_core->UserScrollViewportHorizontally(viewLeft);
// _core->ScrollOffset() is now set to newValue
_HorizontalScrollPositionChangedHandlers(*this,
winrt::make<ScrollPositionChangedArgs>(_core->HorizontalScrollOffset(),
_core->ViewWidth(),
_core->BufferWidth()));
}
}
void ControlInteractivity::_hyperlinkHandler(const std::wstring_view uri)
{
_OpenHyperlinkHandlers(*this, winrt::make<OpenHyperlinkEventArgs>(winrt::hstring{ uri }));

View File

@@ -79,6 +79,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const Control::MouseButtonState state);
void UpdateScrollbar(const double newValue);
void UpdateHorizontalScrollbar(const double newValue);
#pragma endregion
@@ -94,6 +95,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
TYPED_EVENT(ScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
TYPED_EVENT(HorizontalScrollPositionChanged, IInspectable, Control::ScrollPositionChangedArgs);
TYPED_EVENT(ContextMenuRequested, IInspectable, Control::ContextMenuRequestedEventArgs);
TYPED_EVENT(Attached, IInspectable, IInspectable);
@@ -112,6 +114,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::com_ptr<ControlCore> _core{ nullptr };
unsigned int _rowsToScroll;
double _internalScrollbarPosition{ 0.0 };
double _internalHorizontalScrollbarPosition{ 0.0 };
// If this is set, then we assume we are in the middle of panning the
// viewport via touch input.

View File

@@ -65,11 +65,13 @@ namespace Microsoft.Terminal.Control
MouseButtonState state);
void UpdateScrollbar(Double newValue);
void UpdateHorizontalScrollbar(Double newValue);
Boolean ManglePathsForWsl { get; };
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> HorizontalScrollPositionChanged;
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> Closed;

View File

@@ -45,6 +45,10 @@ namespace Microsoft.Terminal.Control
Int32 ViewHeight { get; };
Int32 BufferHeight { get; };
Int32 HorizontalScrollOffset { get; };
Int32 ViewWidth { get; };
Int32 BufferWidth { get; };
Boolean HasSelection { get; };
IVector<String> SelectedText(Boolean trimTrailingWhitespace);

View File

@@ -94,6 +94,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_revokers.coreOpenHyperlink = _core.OpenHyperlink(winrt::auto_revoke, { get_weak(), &TermControl::_HyperlinkHandler });
_revokers.interactivityOpenHyperlink = _interactivity.OpenHyperlink(winrt::auto_revoke, { get_weak(), &TermControl::_HyperlinkHandler });
_revokers.interactivityScrollPositionChanged = _interactivity.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
_revokers.interactivityHorizontalScrollPositionChanged = _interactivity.HorizontalScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_HorizontalScrollPositionChanged });
_revokers.ContextMenuRequested = _interactivity.ContextMenuRequested(winrt::auto_revoke, { get_weak(), &TermControl::_contextMenuHandler });
// "Bubbled" events - ones we want to handle, by raising our own event.
@@ -157,6 +158,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// _updateScrollBar func. Otherwise, we could get a callback from an
// attached content before we set up the throttled func, and that'll A/V
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
// TODO! Horizontal?
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
_revokers.CursorPositionChanged = _core.CursorPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_CursorPositionChanged });
@@ -280,7 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_isInternalScrollBarUpdate = true;
auto scrollBar = ScrollBar();
auto scrollBar = update.horizontal ? HorizontalScrollBar() : ScrollBar();
if (update.newValue)
{
scrollBar.Value(*update.newValue);
@@ -293,7 +295,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_isInternalScrollBarUpdate = false;
if (_showMarksInScrollbar)
if (!update.horizontal && _showMarksInScrollbar)
{
// Update scrollbar marks
ScrollBarCanvas().Children().Clear();
@@ -977,6 +979,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
ScrollBar().ViewportSize(bufferHeight);
ScrollBar().LargeChange(bufferHeight); // scroll one "screenful" at a time when the scroll bar is clicked
auto bufferWidth = _core.BufferWidth();
auto viewWidth = _core.ViewWidth();
HorizontalScrollBar().Maximum(bufferWidth - viewWidth);
HorizontalScrollBar().Minimum(0);
HorizontalScrollBar().Value(0);
HorizontalScrollBar().ViewportSize(viewWidth);
HorizontalScrollBar().LargeChange(viewWidth); // scroll one "screenful" at a time when the scroll bar is clicked
// Set up blinking cursor
int blinkTime = GetCaretBlinkTime();
if (blinkTime != INFINITE)
@@ -1671,6 +1682,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
update.newValue.reset();
});
}
void TermControl::_HorizontalScrollbarChangeHandler(const Windows::Foundation::IInspectable& /*sender*/,
const Controls::Primitives::RangeBaseValueChangedEventArgs& args)
{
if (_isInternalScrollBarUpdate || _IsClosing())
{
// The update comes from ourselves, more specifically from the
// terminal. So we don't have to update the terminal because it
// already knows.
return;
}
const auto newValue = args.NewValue();
newValue;
_interactivity.UpdateHorizontalScrollbar(newValue);
// // User input takes priority over terminal events so cancel
// // any pending scroll bar update if the user scrolls.
// _updateScrollBar->ModifyPending([](auto& update) {
// update.newValue.reset();
// });
}
// Method Description:
// - captures the pointer so that none of the other XAML elements respond to pointer events
@@ -2009,6 +2041,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
update.newMinimum = 0;
update.newViewportSize = args.ViewHeight();
update.newValue = args.ViewTop();
update.horizontal = false;
_updateScrollBar->Run(update);
// if a selection marker is already visible,
// update the position of those markers
if (SelectionStartMarker().Visibility() == Visibility::Visible || SelectionEndMarker().Visibility() == Visibility::Visible)
{
_updateSelectionMarkers(nullptr, winrt::make<UpdateSelectionMarkersEventArgs>(false));
}
}
void TermControl::_HorizontalScrollPositionChanged(const IInspectable& /*sender*/,
const Control::ScrollPositionChangedArgs& args)
{
ScrollBarUpdate update;
const auto hiddenContent = args.BufferSize() - args.ViewHeight();
update.newMaximum = hiddenContent;
update.newMinimum = 0;
update.newViewportSize = args.ViewHeight();
update.newValue = args.ViewTop();
update.horizontal = true;
_updateScrollBar->Run(update);
@@ -2183,6 +2236,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.BufferHeight();
}
int TermControl::HorizontalScrollOffset() const
{
return _core.HorizontalScrollOffset();
}
int TermControl::ViewWidth() const
{
return _core.ViewWidth();
}
int TermControl::BufferWidth() const
{
return _core.BufferWidth();
}
// Function Description:
// - Determines how much space (in pixels) an app would need to reserve to
// create a control with the settings stored in the settings param. This

View File

@@ -68,6 +68,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int ScrollOffset() const;
int ViewHeight() const;
int BufferHeight() const;
// Horizontal scrolling
int HorizontalScrollOffset() const;
int ViewWidth() const;
int BufferWidth() const;
bool HasSelection() const;
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
@@ -217,6 +221,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double newMaximum;
double newMinimum;
double newViewportSize;
bool horizontal;
};
std::shared_ptr<ThrottledFuncTrailing<ScrollBarUpdate>> _updateScrollBar;
@@ -292,6 +297,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _PointerExitedHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
void _MouseWheelHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
void _ScrollbarChangeHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs& e);
void _HorizontalScrollbarChangeHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs& e);
void _GotFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void _LostFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
@@ -313,6 +319,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _TerminalTabColorChanged(const std::optional<til::color> color);
void _ScrollPositionChanged(const IInspectable& sender, const Control::ScrollPositionChangedArgs& args);
void _HorizontalScrollPositionChanged(const IInspectable& sender, const Control::ScrollPositionChangedArgs& args);
winrt::fire_and_forget _CursorPositionChanged(const IInspectable& sender, const IInspectable& args);
bool _CapturePointer(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
@@ -393,6 +400,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::ControlInteractivity::OpenHyperlink_revoker interactivityOpenHyperlink;
Control::ControlInteractivity::ScrollPositionChanged_revoker interactivityScrollPositionChanged;
Control::ControlInteractivity::HorizontalScrollPositionChanged_revoker interactivityHorizontalScrollPositionChanged;
Control::ControlInteractivity::PasteFromClipboard_revoker PasteFromClipboard;
Control::ControlInteractivity::ContextMenuRequested_revoker ContextMenuRequested;
} _revokers{};

View File

@@ -1260,7 +1260,13 @@
PointerReleased="_PointerReleasedHandler"
Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<SwapChainPanel x:Name="SwapChainPanel"
Grid.Row="0"
CompositionScaleChanged="_SwapChainScaleChanged"
SizeChanged="_SwapChainSizeChanged">
<Canvas x:Name="OverlayCanvas"
@@ -1297,12 +1303,27 @@
ensures that it's always aligned w/ the scrollbar
-->
<local:SearchBoxControl x:Name="SearchBox"
Grid.Row="0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
x:Load="False"
Closed="_CloseSearchBoxControl"
Search="_Search"
Visibility="Collapsed" />
<ScrollBar x:Name="HorizontalScrollBar"
Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
IndicatorMode="MouseIndicator"
IsTabStop="False"
LargeChange="4"
Maximum="1"
Orientation="Horizontal"
SmallChange="1"
Style="{StaticResource ForkedScrollbarTemplate}"
ValueChanged="_HorizontalScrollbarChangeHandler"
ViewportSize="10" />
</Grid>
<ScrollBar x:Name="ScrollBar"

View File

@@ -22,6 +22,7 @@ namespace Microsoft::Terminal::Core
[[nodiscard]] virtual HRESULT UserResize(const til::size size) noexcept = 0;
virtual void UserScrollViewport(const int viewTop) = 0;
virtual void UserScrollViewportHorizontally(const int viewLeft) = 0;
virtual int GetScrollOffset() = 0;
virtual void TrySnapOnInput() = 0;

View File

@@ -30,9 +30,12 @@ Terminal::Terminal()
void Terminal::Create(til::size viewportSize, til::CoordType scrollbackLines, Renderer& renderer)
{
_mutableViewport = Viewport::FromDimensions({ 0, 0 }, viewportSize);
_visibleWidth = viewportSize.width;
auto realWidth = std::max(_visibleWidth, _minWidth);
_mutableViewport = Viewport::FromDimensions({ 0, 0 }, { realWidth, viewportSize.height });
_scrollbackLines = scrollbackLines;
const til::size bufferSize{ viewportSize.width,
const til::size bufferSize{ realWidth,
Utils::ClampToShortMax(viewportSize.height + scrollbackLines, 1) };
const TextAttribute attr{};
const UINT cursorSize = 12;
@@ -227,18 +230,30 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// appropriate HRESULT for failing to resize.
[[nodiscard]] HRESULT Terminal::UserResize(const til::size viewportSize) noexcept
{
const auto oldDimensions = _GetMutableViewport().Dimensions();
if (viewportSize == oldDimensions)
const auto oldBackingDimensions = _GetMutableViewport().Dimensions();
const auto oldVisibleDimensions = _GetVisibleViewport().Dimensions();
if (oldVisibleDimensions == viewportSize)
{
return S_FALSE;
}
// IMPORTANT: Make sure to change the visible view width, even if we no-op the rest of the resize.
_visibleWidth = viewportSize.width;
// const auto oldDimensions = _GetMutableViewport().Dimensions();
// if (viewportSize == oldDimensions)
// {
// return S_FALSE;
// }
// Shortcut: if we're in the alt buffer, just resize the
// alt buffer and put off resizing the main buffer till we switch back. Fortunately, this is easy. We don't need to
// worry about the viewport and scrollback at all! The alt buffer never has
// any scrollback, so we just need to resize it and presto, we're done.
if (_inAltBuffer())
{
// TODO! deal with the alt buffer
// stash this resize for the future.
_deferredResize = viewportSize;
@@ -259,10 +274,16 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
return S_OK;
}
const auto dx = viewportSize.width - oldDimensions.width;
const auto newBufferHeight = std::clamp(viewportSize.height + _scrollbackLines, 0, SHRT_MAX);
const til::size newRealSize{ std::max(viewportSize.width, _minWidth), viewportSize.height };
if (newRealSize == oldBackingDimensions)
{
return S_FALSE;
}
til::size bufferSize{ viewportSize.width, newBufferHeight };
const auto dx = newRealSize.width - oldBackingDimensions.width;
const auto newBufferHeight = std::clamp(newRealSize.height + _scrollbackLines, 0, SHRT_MAX);
til::size bufferSize{ newRealSize.width, newBufferHeight };
// This will be used to determine where the viewport should be in the new buffer.
const auto oldViewportTop = _mutableViewport.Top();
@@ -365,7 +386,7 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
const auto maxRow = std::max(newLastChar.y, newCursorPos.y);
const auto proposedTopFromLastLine = maxRow - viewportSize.height + 1;
const auto proposedTopFromLastLine = maxRow - newRealSize.height + 1;
const auto proposedTopFromScrollback = newViewportTop;
auto proposedTop = std::max(proposedTopFromLastLine,
@@ -386,7 +407,7 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// this proposed top position.
if (proposedTop == proposedTopFromScrollback)
{
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, viewportSize);
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, newRealSize);
if (maxRow < proposedViewFromTop.BottomInclusive())
{
if (dx < 0 && proposedTop > 0)
@@ -407,7 +428,7 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// If the new bottom would be higher than the last row of text, then we
// definitely want to use the last row of text to determine where the
// viewport should be.
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, viewportSize);
const auto proposedViewFromTop = Viewport::FromDimensions({ 0, proposedTopFromScrollback }, newRealSize);
if (maxRow > proposedViewFromTop.BottomInclusive())
{
proposedTop = proposedTopFromLastLine;
@@ -419,14 +440,14 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// If the new bottom would be below the bottom of the buffer, then slide the
// top up so that we'll still fit within the buffer.
const auto newView = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
const auto newView = Viewport::FromDimensions({ 0, proposedTop }, newRealSize);
const auto proposedBottom = newView.BottomExclusive();
if (proposedBottom > bufferSize.height)
{
proposedTop = ::base::ClampSub(proposedTop, ::base::ClampSub(proposedBottom, bufferSize.height));
}
_mutableViewport = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
_mutableViewport = Viewport::FromDimensions({ 0, proposedTop }, newRealSize);
_mainBuffer.swap(newTextBuffer);
@@ -440,6 +461,8 @@ std::wstring_view Terminal::GetWorkingDirectory() noexcept
// before, and shouldn't be now either.
_scrollOffset = originalOffsetWasZero ? 0 : static_cast<int>(::base::ClampSub(_mutableViewport.Top(), newVisibleTop));
// _visibleWidth = viewportSize.width;
// GH#5029 - make sure to InvalidateAll here, so that we'll paint the entire visible viewport.
try
{
@@ -1049,11 +1072,11 @@ Viewport Terminal::_GetVisibleViewport() const noexcept
// GH#3493: if we're in the alt buffer, then it's possible that the mutable
// viewport's size hasn't been updated yet. In that case, use the
// temporarily stashed _altBufferSize instead.
const til::point origin{ 0, _VisibleStartIndex() };
const til::point origin{ _horizontalOffset, _VisibleStartIndex() };
const auto size{ _inAltBuffer() ? _altBufferSize :
_mutableViewport.Dimensions() };
return Viewport::FromDimensions(origin,
size);
{ _visibleWidth, size.height });
}
void Terminal::_PreserveUserScrollOffset(const int viewportDelta) noexcept
@@ -1091,6 +1114,31 @@ void Terminal::UserScrollViewport(const int viewTop)
// from the previous frame drawn.
_activeBuffer().TriggerScroll();
}
void Terminal::UserScrollViewportHorizontally(const int viewLeft)
{
if (_inAltBuffer())
{
return;
}
// we're going to modify state here that the renderer could be reading.
auto lock = LockForWriting();
const auto clampedNewLeft = std::max(0, viewLeft);
// const auto realLeft = _horizontalOffset;
// const auto newDelta = realLeft - clampedNewLeft;
// if viewTop > realTop, we want the offset to be 0.
// _scrollOffset = std::max(0, newDelta);
// We need to clamp to the right though too.
// We can't scroll past the right edge of the buffer.
const auto maxScrollOffset = _mutableViewport.Width() - _visibleWidth;
_horizontalOffset = std::min(clampedNewLeft, maxScrollOffset);
// TODO! I'm just redrawing all cause I'm pretty sure the renderers HATE horizontal scrolling.
_activeBuffer().TriggerRedrawAll();
}
int Terminal::GetScrollOffset() noexcept
{

View File

@@ -150,6 +150,7 @@ public:
[[nodiscard]] HRESULT UserResize(const til::size viewportSize) noexcept override;
void UserScrollViewport(const int viewTop) override;
void UserScrollViewportHorizontally(const int viewLeft) override;
int GetScrollOffset() noexcept override;
void TrySnapOnInput() override;
@@ -287,6 +288,16 @@ public:
const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace);
#pragma endregion
til::CoordType _minWidth = 128;
til::CoordType _visibleWidth;
til::CoordType _horizontalOffset = 0;
til::size GetRealViewportSize()
{
const auto mutableView{ _GetMutableViewport() };
// return til::size{ std::min(_minWidth, mutableView.Width()), mutableView.Height() };
return til::size{ mutableView.Width(), mutableView.Height() };
}
private:
std::function<void(std::wstring_view)> _pfnWriteInput;
std::function<void()> _pfnWarningBell;

View File

@@ -509,7 +509,7 @@ CATCH_RETURN()
clipRect.top = origin.y + drawingContext->topClipOffset;
clipRect.bottom = origin.y + drawingContext->cellSize.height - drawingContext->bottomClipOffset;
clipRect.left = 0;
clipRect.right = drawingContext->targetSize.width;
clipRect.right = origin.x + drawingContext->targetSize.width;
// If we already have a clip rectangle, check if it different than the previous one.
if (_clipRect.has_value())