Skip to content

Commit

Permalink
Horizontal snapping à la conhost
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Aug 5, 2024
1 parent 1ade14e commit 75021d8
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 34 deletions.
4 changes: 4 additions & 0 deletions src/host/_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto writer = gci.GetVtWriterForBuffer(&screenInfo);

screenInfo.SnapOnOutput();

// If we enter this if condition, then someone wrote text in VT mode and now switched to non-VT mode.
// Since the Console APIs don't support delayed EOL wrapping, we need to first put the cursor back
// to a position that the Console APIs expect (= not delayed).
Expand Down Expand Up @@ -343,6 +345,8 @@ void WriteCharsVT(SCREEN_INFORMATION& screenInfo, const std::wstring_view& str)
// may change, so get the VtIo reference now, just in case.
auto writer = gci.GetVtWriterForBuffer(&screenInfo);

screenInfo.SnapOnOutput();

stateMachine.ProcessString(str);

if (writer)
Expand Down
31 changes: 6 additions & 25 deletions src/host/screenInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1687,23 +1687,23 @@ static constexpr bool IsInputKey(WORD vkey)

void SCREEN_INFORMATION::MakeCursorVisible(til::point position)
{
_makeLocationVisible(position, ViewportMovementMask::Vertical | ViewportMovementMask::Horizontal);
_makeLocationVisible(position, true, true);
}

void SCREEN_INFORMATION::SnapOnInput(const WORD vkey)
{
if (IsInputKey(vkey))
{
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), ViewportMovementMask::Vertical);
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), true, false);
}
}

void SCREEN_INFORMATION::SnapOnOutput()
{
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), ViewportMovementMask::HorizontalCenter);
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), false, true);
}

void SCREEN_INFORMATION::_makeLocationVisible(til::point position, ViewportMovementMask movements)
void SCREEN_INFORMATION::_makeLocationVisible(til::point position, bool vertical, bool horizontal)
{
const auto viewportOrigin = _viewport.Origin();
const auto viewportSize = _viewport.Dimensions();
Expand All @@ -1714,37 +1714,18 @@ void SCREEN_INFORMATION::_makeLocationVisible(til::point position, ViewportMovem
position.x = std::clamp(position.x, 0, bufferSize.width - 1);
position.y = std::clamp(position.y, 0, bufferSize.height - 1);

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::Vertical))
if (vertical)
{
origin.y = std::min(origin.y, position.y); // shift up if above
origin.y = std::max(origin.y, position.y - (viewportSize.height - 1)); // shift down if below
}

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::Horizontal))
if (horizontal)
{
origin.x = std::min(origin.x, position.x); // shift left if left
origin.x = std::max(origin.x, position.x - (viewportSize.width - 1)); // shift right if right
}

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::HorizontalCenter))
{
// If the position is horizontally outside the viewport, snap the
// viewport to the nearest multiple of half the viewport width.
if (position.x < origin.x || position.x >= (origin.x + viewportSize.width))
{
const auto div = viewportSize.width / 2;
// We want our viewport to be centered around the position (= "half-width" offset).
// Since the origin is the left edge, we must subtract a half-width from the position.
origin.x = position.x - div;
// Round down to the nearest multiple of the viewport width.
// This also works if origin.x is negative, because the "modulo operator"
// is not a modulo operator, it's a remainder operator. The remainder of a
// negative number is negative and so origin.x cannot end up being less than 0.
origin.x -= origin.x % div;
origin.x = std::min(origin.x, bufferSize.width - viewportSize.width);
}
}

if (origin != viewportOrigin)
{
std::ignore = SetViewportOrigin(true, origin, false);
Expand Down
10 changes: 1 addition & 9 deletions src/host/screenInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,6 @@ Revision History:
#include "../types/inc/Viewport.hpp"
class ConversionAreaInfo; // forward decl window. circular reference

enum class ViewportMovementMask
{
Vertical = 0x1,
Horizontal = 0x2,
HorizontalCenter = 0x4,
};
DEFINE_ENUM_FLAG_OPERATORS(ViewportMovementMask);

class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console::IIoProvider
{
public:
Expand Down Expand Up @@ -244,7 +236,7 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
void _CalculateViewportSize(const til::rect* const prcClientArea, _Out_ til::size* const pcoordSize);
void _AdjustViewportSize(const til::rect* const prcClientNew, const til::rect* const prcClientOld, const til::size* const pcoordSize);
void _InternalSetViewportSize(const til::size* pcoordSize, const bool fResizeFromTop, const bool fResizeFromLeft);
void _makeLocationVisible(til::point position, ViewportMovementMask movements);
void _makeLocationVisible(til::point position, bool vertical, bool horizontal);

static void s_CalculateScrollbarVisibility(const til::rect* const prcClientArea,
const til::size* const pcoordBufferSize,
Expand Down

0 comments on commit 75021d8

Please sign in to comment.