mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Prepare til wrappers for migrating off of SMALL_RECT (#11902)
This commit makes the following changes to `til::point/size/rectangle` for the following reasons: * Rename `rectangle` into `rect` This will make the naming consistent with a later `small_rect` struct as well as the existing Win32 POINT/SIZE/RECT structs. * Standardizes til wrappers on `int32_t` instead of `ptrdiff_t` Provides a consistent behavior between x86 and x64, preventing accidental errors on x86, as it's less rigorously tested than x64. Additionally it improves interop with MIDL3 which only supports fixed width integer types. * Standardizes til wrappers on throwing `gsl::narrow_error` Makes the behavior of our code more consistent. * Makes all eligible functions `constexpr` Because why not. * Removes implicit constructors and conversion operators This is a complex and controversial topic. My reasons are: You can't Ctrl+F for an implicit conversion. This breaks most non-IDE engines, like the one on GitHub or those we have internally at MS. This is important for me as these implicit conversion operators aren't cost free. Narrowing integers itself, as well as the boundary checks that need to be done have a certain, fixed overhead each time. Additionally the lack of noexcept prevents many advanced compiler optimizations. Removing their use entirely drops conhost's code segment size by around ~6.5%. ## References Preliminary work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine.
This commit is contained in:
parent
1a62f473ad
commit
b3fab518f8
@ -1076,7 +1076,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
|
||||
#pragma warning(suppress : 26496)
|
||||
auto copy{ target };
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
if (target == bufferSize.Origin())
|
||||
{
|
||||
// can't expand left
|
||||
@ -1088,10 +1088,10 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
|
||||
// that it actually points to a space in the buffer
|
||||
copy = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() };
|
||||
}
|
||||
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
else if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0)
|
||||
{
|
||||
// if at/past the limit --> clamp to limit
|
||||
copy = *limitOptional;
|
||||
copy = limitOptional->to_win32_coord();
|
||||
}
|
||||
|
||||
if (accessibilityMode)
|
||||
@ -1203,15 +1203,15 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
|
||||
|
||||
// Already at/past the limit. Can't move forward.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
if (accessibilityMode)
|
||||
{
|
||||
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
|
||||
return _GetWordEndForAccessibility(target, wordDelimiters, limit.to_win32_coord());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1366,10 +1366,10 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite
|
||||
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
|
||||
// This is also the inclusive start of the next word.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit.to_win32_coord()) };
|
||||
|
||||
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
|
||||
if (bufferSize.CompareInBounds(copy, limit.to_win32_coord(), true) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -1411,23 +1411,23 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters
|
||||
// - pos - The COORD for the first cell of the current glyph (inclusive)
|
||||
const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
COORD resultPos = pos.to_win32_coord();
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
resultPos = limit.to_win32_coord();
|
||||
}
|
||||
|
||||
// limit is exclusive, so we need to move back to be within valid bounds
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
|
||||
if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
|
||||
{
|
||||
bufferSize.DecrementInBounds(resultPos, true);
|
||||
}
|
||||
|
||||
return resultPos;
|
||||
return til::point{ resultPos };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -1439,17 +1439,17 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<t
|
||||
// - pos - The COORD for the last cell of the current glyph (exclusive)
|
||||
const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
COORD resultPos = pos.to_win32_coord();
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
|
||||
// Clamp pos to limit
|
||||
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
|
||||
if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0)
|
||||
{
|
||||
resultPos = limit;
|
||||
resultPos = limit.to_win32_coord();
|
||||
}
|
||||
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
}
|
||||
@ -1459,7 +1459,7 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilit
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
}
|
||||
return resultPos;
|
||||
return til::point{ resultPos };
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -1474,9 +1474,9 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilit
|
||||
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
|
||||
const auto distanceToLimit{ bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) };
|
||||
if (distanceToLimit >= 0)
|
||||
{
|
||||
// Corner Case: we're on/past the limit
|
||||
@ -1493,7 +1493,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
|
||||
}
|
||||
|
||||
// Try to move forward, but if we hit the buffer boundary, we fail to move.
|
||||
auto iter{ GetCellDataAt(pos, bufferSize) };
|
||||
auto iter{ GetCellDataAt(pos.to_win32_coord(), bufferSize) };
|
||||
const bool success{ ++iter };
|
||||
|
||||
// Move again if we're on a wide glyph
|
||||
@ -1502,7 +1502,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
|
||||
++iter;
|
||||
}
|
||||
|
||||
pos = iter.Pos();
|
||||
pos = til::point{ iter.Pos() };
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -1515,11 +1515,11 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
|
||||
// - pos - The COORD for the first cell of the previous glyph (inclusive)
|
||||
bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
COORD resultPos = pos;
|
||||
COORD resultPos = pos.to_win32_coord();
|
||||
const auto bufferSize = GetSize();
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
|
||||
|
||||
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
|
||||
if (bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) > 0)
|
||||
{
|
||||
// we're past the end
|
||||
// clamp us to the limit
|
||||
@ -1534,7 +1534,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
|
||||
bufferSize.DecrementInBounds(resultPos, true);
|
||||
}
|
||||
|
||||
pos = resultPos;
|
||||
pos = til::point{ resultPos };
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@ -549,11 +549,11 @@ try
|
||||
|
||||
if (multiClickMapper == 3)
|
||||
{
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line);
|
||||
_terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Line);
|
||||
}
|
||||
else if (multiClickMapper == 2)
|
||||
{
|
||||
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word);
|
||||
_terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Word);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -582,19 +582,25 @@ try
|
||||
|
||||
RETURN_HR_IF(E_NOT_VALID_STATE, fontSize.area() == 0); // either dimension = 0, area == 0
|
||||
|
||||
if (this->_singleClickTouchdownPos)
|
||||
// This is a copy of ControlInteractivity::PointerMoved
|
||||
if (_singleClickTouchdownPos)
|
||||
{
|
||||
const auto& touchdownPoint{ *this->_singleClickTouchdownPos };
|
||||
const auto distance{ std::sqrtf(std::powf(cursorPosition.x<float>() - touchdownPoint.x<float>(), 2) + std::powf(cursorPosition.y<float>() - touchdownPoint.y<float>(), 2)) };
|
||||
if (distance >= (std::min(fontSize.width(), fontSize.height()) / 4.f))
|
||||
const auto touchdownPoint = *_singleClickTouchdownPos;
|
||||
const auto dx = cursorPosition.x - touchdownPoint.x;
|
||||
const auto dy = cursorPosition.y - touchdownPoint.y;
|
||||
const auto w = fontSize.width;
|
||||
const auto distanceSquared = dx * dx + dy * dy;
|
||||
const auto maxDistanceSquared = w * w / 16; // (w / 4)^2
|
||||
|
||||
if (distanceSquared >= maxDistanceSquared)
|
||||
{
|
||||
_terminal->SetSelectionAnchor(touchdownPoint / fontSize);
|
||||
_terminal->SetSelectionAnchor((touchdownPoint / fontSize).to_win32_coord());
|
||||
// stop tracking the touchdown point
|
||||
_singleClickTouchdownPos = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
this->_terminal->SetSelectionEnd(cursorPosition / fontSize);
|
||||
this->_terminal->SetSelectionEnd((cursorPosition / fontSize).to_win32_coord());
|
||||
this->_renderer->TriggerSelection();
|
||||
|
||||
return S_OK;
|
||||
@ -696,9 +702,9 @@ try
|
||||
wheelDelta = HIWORD(wParam);
|
||||
|
||||
// If it's a *WHEEL event, it's in screen coordinates, not window (?!)
|
||||
POINT coordsToTransform = cursorPosition;
|
||||
POINT coordsToTransform = cursorPosition.to_win32_point();
|
||||
ScreenToClient(_hwnd.get(), &coordsToTransform);
|
||||
cursorPosition = coordsToTransform;
|
||||
cursorPosition = til::point{ coordsToTransform };
|
||||
}
|
||||
|
||||
const TerminalInput::MouseButtonState state{
|
||||
@ -707,7 +713,7 @@ try
|
||||
WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed)
|
||||
};
|
||||
|
||||
return _terminal->SendMouseEvent(cursorPosition / fontSize, uMsg, getControlKeyState(), wheelDelta, state);
|
||||
return _terminal->SendMouseEvent((cursorPosition / fontSize).to_win32_coord(), uMsg, getControlKeyState(), wheelDelta, state);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@ -423,7 +423,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const short wheelDelta,
|
||||
const TerminalInput::MouseButtonState state)
|
||||
{
|
||||
return _terminal->SendMouseEvent(viewportPos, uiButton, states, wheelDelta, state);
|
||||
return _terminal->SendMouseEvent(viewportPos.to_win32_coord(), uiButton, states, wheelDelta, state);
|
||||
}
|
||||
|
||||
void ControlCore::UserScrollViewport(const int viewTop)
|
||||
@ -546,12 +546,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_lastHoveredCell = terminalPosition;
|
||||
uint16_t newId{ 0u };
|
||||
// we can't use auto here because we're pre-declaring newInterval.
|
||||
decltype(_terminal->GetHyperlinkIntervalFromPosition(til::point{})) newInterval{ std::nullopt };
|
||||
decltype(_terminal->GetHyperlinkIntervalFromPosition(COORD{})) newInterval{ std::nullopt };
|
||||
if (terminalPosition.has_value())
|
||||
{
|
||||
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
|
||||
newId = _terminal->GetHyperlinkIdAtPosition(*terminalPosition);
|
||||
newInterval = _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition);
|
||||
newId = _terminal->GetHyperlinkIdAtPosition(terminalPosition->to_win32_coord());
|
||||
newInterval = _terminal->GetHyperlinkIntervalFromPosition(terminalPosition->to_win32_coord());
|
||||
}
|
||||
|
||||
// If the hyperlink ID changed or the interval changed, trigger a redraw all
|
||||
@ -577,11 +577,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
winrt::hstring ControlCore::GetHyperlink(const til::point pos) const
|
||||
winrt::hstring ControlCore::GetHyperlink(const Core::Point pos) const
|
||||
{
|
||||
// Lock for the duration of our reads.
|
||||
auto lock = _terminal->LockForReading();
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(pos) };
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(til::point{ pos }.to_win32_coord()) };
|
||||
}
|
||||
|
||||
winrt::hstring ControlCore::HoveredUriText() const
|
||||
@ -589,14 +589,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
|
||||
if (_lastHoveredCell.has_value())
|
||||
{
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
|
||||
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(_lastHoveredCell->to_win32_coord()) };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Windows::Foundation::IReference<Core::Point> ControlCore::HoveredCell() const
|
||||
{
|
||||
return _lastHoveredCell.has_value() ? Windows::Foundation::IReference<Core::Point>{ _lastHoveredCell.value() } : nullptr;
|
||||
return _lastHoveredCell.has_value() ? Windows::Foundation::IReference<Core::Point>{ _lastHoveredCell.value().to_core_point() } : nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -938,7 +938,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ControlCore::SetSelectionAnchor(til::point const& position)
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
_terminal->SetSelectionAnchor(position);
|
||||
_terminal->SetSelectionAnchor(position.to_win32_coord());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -956,16 +956,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// you move its endpoints while it is generating a frame.
|
||||
auto lock = _terminal->LockForWriting();
|
||||
|
||||
const short lastVisibleRow = std::max<short>(_terminal->GetViewport().Height() - 1, 0);
|
||||
const short lastVisibleCol = std::max<short>(_terminal->GetViewport().Width() - 1, 0);
|
||||
|
||||
til::point terminalPosition{
|
||||
std::clamp<short>(position.x<short>(), 0, lastVisibleCol),
|
||||
std::clamp<short>(position.y<short>(), 0, lastVisibleRow)
|
||||
std::clamp(position.x, 0, _terminal->GetViewport().Width() - 1),
|
||||
std::clamp(position.y, 0, _terminal->GetViewport().Height() - 1)
|
||||
};
|
||||
|
||||
// save location (for rendering) + render
|
||||
_terminal->SetSelectionEnd(terminalPosition);
|
||||
_terminal->SetSelectionEnd(terminalPosition.to_win32_coord());
|
||||
_renderer->TriggerSelection();
|
||||
}
|
||||
|
||||
@ -1433,7 +1430,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _terminal != nullptr && _terminal->IsTrackingMouseInput();
|
||||
}
|
||||
|
||||
til::point ControlCore::CursorPosition() const
|
||||
Core::Point ControlCore::CursorPosition() const
|
||||
{
|
||||
// If we haven't been initialized yet, then fake it.
|
||||
if (!_initializedTerminal)
|
||||
@ -1442,7 +1439,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
auto lock = _terminal->LockForReading();
|
||||
return _terminal->GetCursorPosition();
|
||||
return til::point{ _terminal->GetCursorPosition() }.to_core_point();
|
||||
}
|
||||
|
||||
// This one's really pushing the boundary of what counts as "encapsulation".
|
||||
@ -1494,7 +1491,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
// If shift is pressed and there is a selection we extend it using
|
||||
// the selection mode (expand the "end" selection point)
|
||||
_terminal->SetSelectionEnd(terminalPosition, mode);
|
||||
_terminal->SetSelectionEnd(terminalPosition.to_win32_coord(), mode);
|
||||
selectionNeedsToBeCopied = true;
|
||||
}
|
||||
else if (mode != ::Terminal::SelectionExpansion::Char || shiftEnabled)
|
||||
@ -1502,7 +1499,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// If we are handling a double / triple-click or shift+single click
|
||||
// we establish selection using the selected mode
|
||||
// (expand both "start" and "end" selection points)
|
||||
_terminal->MultiClickSelection(terminalPosition, mode);
|
||||
_terminal->MultiClickSelection(terminalPosition.to_win32_coord(), mode);
|
||||
selectionNeedsToBeCopied = true;
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void UpdatePatternLocations();
|
||||
void SetHoveredCell(Core::Point terminalPosition);
|
||||
void ClearHoveredCell();
|
||||
winrt::hstring GetHyperlink(const til::point position) const;
|
||||
winrt::hstring GetHyperlink(const Core::Point position) const;
|
||||
winrt::hstring HoveredUriText() const;
|
||||
Windows::Foundation::IReference<Core::Point> HoveredCell() const;
|
||||
|
||||
@ -138,7 +138,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void CursorOn(const bool isCursorOn);
|
||||
|
||||
bool IsVtMouseModeEnabled() const;
|
||||
til::point CursorPosition() const;
|
||||
Core::Point CursorPosition() const;
|
||||
|
||||
bool HasSelection() const;
|
||||
bool CopyOnSelect() const;
|
||||
|
||||
@ -84,7 +84,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Return Value:
|
||||
// - if the click is in the same position as the last click and within the timeout, the number of clicks within that time window
|
||||
// - otherwise, 1
|
||||
unsigned int ControlInteractivity::_numberOfClicks(til::point clickPos,
|
||||
unsigned int ControlInteractivity::_numberOfClicks(Core::Point clickPos,
|
||||
Timestamp clickTime)
|
||||
{
|
||||
// if click occurred at a different location or past the multiClickTimer...
|
||||
@ -192,16 +192,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const til::point pixelPosition)
|
||||
const Core::Point pixelPosition)
|
||||
{
|
||||
const til::point terminalPosition = _getTerminalPosition(pixelPosition);
|
||||
const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition });
|
||||
|
||||
const auto altEnabled = modifiers.IsAltPressed();
|
||||
const auto shiftEnabled = modifiers.IsShiftPressed();
|
||||
const auto ctrlEnabled = modifiers.IsCtrlPressed();
|
||||
|
||||
// GH#9396: we prioritize hyper-link over VT mouse events
|
||||
auto hyperlink = _core->GetHyperlink(terminalPosition);
|
||||
auto hyperlink = _core->GetHyperlink(terminalPosition.to_core_point());
|
||||
if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) &&
|
||||
ctrlEnabled && !hyperlink.empty())
|
||||
{
|
||||
@ -265,7 +265,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchPressed(const til::point contactPoint)
|
||||
void ControlInteractivity::TouchPressed(const Core::Point contactPoint)
|
||||
{
|
||||
_touchAnchor = contactPoint;
|
||||
}
|
||||
@ -274,10 +274,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
const til::point pixelPosition,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds)
|
||||
{
|
||||
const til::point terminalPosition = _getTerminalPosition(pixelPosition);
|
||||
const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition });
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
@ -292,21 +292,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (_singleClickTouchdownPos)
|
||||
{
|
||||
// Figure out if the user's moved a quarter of a cell's smaller axis away from the clickdown point
|
||||
auto& touchdownPoint{ *_singleClickTouchdownPos };
|
||||
float dx = ::base::saturated_cast<float>(pixelPosition.x() - touchdownPoint.x());
|
||||
float dy = ::base::saturated_cast<float>(pixelPosition.y() - touchdownPoint.y());
|
||||
auto distance{ std::sqrtf(std::powf(dx, 2) +
|
||||
std::powf(dy, 2)) };
|
||||
// Figure out if the user's moved a 1/4th of a cell's smaller axis
|
||||
// (practically always the width) away from the clickdown point.
|
||||
const auto fontSizeInDips = _core->FontSizeInDips();
|
||||
const auto touchdownPoint = *_singleClickTouchdownPos;
|
||||
const auto dx = pixelPosition.X - touchdownPoint.X;
|
||||
const auto dy = pixelPosition.Y - touchdownPoint.Y;
|
||||
const auto w = fontSizeInDips.width;
|
||||
const auto distanceSquared = dx * dx + dy * dy;
|
||||
const auto maxDistanceSquared = w * w / 16; // (w / 4)^2
|
||||
|
||||
const auto fontSizeInDips{ _core->FontSizeInDips() };
|
||||
if (distance >= (std::min(fontSizeInDips.width(), fontSizeInDips.height()) / 4.f))
|
||||
if (distanceSquared >= maxDistanceSquared)
|
||||
{
|
||||
// GH#9955.c: Make sure to use the terminal location of the
|
||||
// _touchdown_ point here. We want to start the selection
|
||||
// from where the user initially clicked, not where they are
|
||||
// now.
|
||||
_core->SetSelectionAnchor(_getTerminalPosition(touchdownPoint));
|
||||
_core->SetSelectionAnchor(_getTerminalPosition(til::point{ touchdownPoint }));
|
||||
|
||||
// stop tracking the touchdown point
|
||||
_singleClickTouchdownPos = std::nullopt;
|
||||
@ -316,10 +318,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
SetEndSelectionPoint(pixelPosition);
|
||||
}
|
||||
|
||||
_core->SetHoveredCell(terminalPosition);
|
||||
_core->SetHoveredCell(terminalPosition.to_core_point());
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchMoved(const til::point newTouchPoint,
|
||||
void ControlInteractivity::TouchMoved(const Core::Point newTouchPoint,
|
||||
const bool focused)
|
||||
{
|
||||
if (focused &&
|
||||
@ -332,19 +334,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto fontSizeInDips{ _core->FontSizeInDips() };
|
||||
|
||||
// Get the difference between the point we've dragged to and the start of the touch.
|
||||
const float dy = ::base::saturated_cast<float>(newTouchPoint.y() - anchor.y());
|
||||
const auto dy = static_cast<double>(newTouchPoint.Y - anchor.Y);
|
||||
|
||||
// Start viewport scroll after we've moved more than a half row of text
|
||||
if (std::abs(dy) > (fontSizeInDips.height<float>() / 2.0f))
|
||||
if (std::abs(dy) > (fontSizeInDips.height / 2.0))
|
||||
{
|
||||
// Multiply by -1, because moving the touch point down will
|
||||
// create a positive delta, but we want the viewport to move up,
|
||||
// so we'll need a negative scroll amount (and the inverse for
|
||||
// panning down)
|
||||
const float numRows = -1.0f * (dy / fontSizeInDips.height<float>());
|
||||
const auto numRows = dy / -fontSizeInDips.height;
|
||||
|
||||
const double currentOffset = ::base::ClampedNumeric<double>(_core->ScrollOffset());
|
||||
const double newValue = numRows + currentOffset;
|
||||
const auto currentOffset = _core->ScrollOffset();
|
||||
const auto newValue = numRows + currentOffset;
|
||||
|
||||
// Update the Core's viewport position, and raise a
|
||||
// ScrollPositionChanged event to update the scrollbar
|
||||
@ -359,9 +361,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ControlInteractivity::PointerReleased(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const til::point pixelPosition)
|
||||
const Core::Point pixelPosition)
|
||||
{
|
||||
const til::point terminalPosition = _getTerminalPosition(pixelPosition);
|
||||
const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition });
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
@ -402,10 +404,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - delta: the mouse wheel delta that triggered this event.
|
||||
bool ControlInteractivity::MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const int32_t delta,
|
||||
const til::point pixelPosition,
|
||||
const Core::Point pixelPosition,
|
||||
const Control::MouseButtonState buttonState)
|
||||
{
|
||||
const til::point terminalPosition = _getTerminalPosition(pixelPosition);
|
||||
const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition });
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
@ -470,7 +472,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - pixelPosition: the location of the mouse during this event
|
||||
// - isLeftButtonPressed: true iff the left mouse button was pressed during this event.
|
||||
void ControlInteractivity::_mouseScrollHandler(const double mouseDelta,
|
||||
const til::point pixelPosition,
|
||||
const Core::Point pixelPosition,
|
||||
const bool isLeftButtonPressed)
|
||||
{
|
||||
// GH#9955.b: Start scrolling from our internal scrollbar position. This
|
||||
@ -573,9 +575,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - 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 ControlInteractivity::SetEndSelectionPoint(const til::point pixelPosition)
|
||||
void ControlInteractivity::SetEndSelectionPoint(const Core::Point pixelPosition)
|
||||
{
|
||||
_core->SetEndSelectionPoint(_getTerminalPosition(pixelPosition));
|
||||
_core->SetEndSelectionPoint(_getTerminalPosition(til::point{ pixelPosition }));
|
||||
_selectionNeedsToBeCopied = true;
|
||||
}
|
||||
|
||||
@ -587,7 +589,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// NOTE: origin (0,0) is top-left.
|
||||
// Return Value:
|
||||
// - the corresponding viewport terminal position for the given Point parameter
|
||||
til::point ControlInteractivity::_getTerminalPosition(const til::point& pixelPosition)
|
||||
til::point ControlInteractivity::_getTerminalPosition(const til::point pixelPosition)
|
||||
{
|
||||
// Get the size of the font, which is in pixels
|
||||
const til::size fontSize{ _core->GetFont().GetSize() };
|
||||
@ -603,9 +605,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
const auto adjustment = _core->ScrollOffset() > 0 ? _core->BufferHeight() - _core->ScrollOffset() - _core->ViewHeight() : 0;
|
||||
// If the click happened outside the active region, just don't send any mouse event
|
||||
if (const auto adjustedY = terminalPosition.y() - adjustment; adjustedY >= 0)
|
||||
if (const auto adjustedY = terminalPosition.y - adjustment; adjustedY >= 0)
|
||||
{
|
||||
return _core->SendMouseEvent({ terminalPosition.x(), adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState));
|
||||
return _core->SendMouseEvent({ terminalPosition.x, adjustedY }, pointerUpdateKind, modifiers, wheelDelta, toInternalMouseState(buttonState));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -52,27 +52,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const til::point pixelPosition);
|
||||
void TouchPressed(const til::point contactPoint);
|
||||
const Core::Point pixelPosition);
|
||||
void TouchPressed(const Core::Point contactPoint);
|
||||
|
||||
void PointerMoved(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const bool focused,
|
||||
const til::point pixelPosition,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds);
|
||||
void TouchMoved(const til::point newTouchPoint,
|
||||
void TouchMoved(const Core::Point newTouchPoint,
|
||||
const bool focused);
|
||||
|
||||
void PointerReleased(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const til::point pixelPosition);
|
||||
const Core::Point pixelPosition);
|
||||
void TouchReleased();
|
||||
|
||||
bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const int32_t delta,
|
||||
const til::point pixelPosition,
|
||||
const Core::Point pixelPosition,
|
||||
const Control::MouseButtonState state);
|
||||
|
||||
void UpdateScrollbar(const double newValue);
|
||||
@ -82,7 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool CopySelectionToClipboard(bool singleLine,
|
||||
const Windows::Foundation::IReference<CopyFormat>& formats);
|
||||
void RequestPasteTextFromClipboard();
|
||||
void SetEndSelectionPoint(const til::point pixelPosition);
|
||||
void SetEndSelectionPoint(const Core::Point pixelPosition);
|
||||
bool ManglePathsForWsl();
|
||||
|
||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||
@ -105,7 +105,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// If this is set, then we assume we are in the middle of panning the
|
||||
// viewport via touch input.
|
||||
std::optional<til::point> _touchAnchor;
|
||||
std::optional<Core::Point> _touchAnchor;
|
||||
|
||||
using Timestamp = uint64_t;
|
||||
|
||||
@ -114,9 +114,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Timestamp _multiClickTimer;
|
||||
unsigned int _multiClickCounter;
|
||||
Timestamp _lastMouseClickTimestamp;
|
||||
std::optional<til::point> _lastMouseClickPos;
|
||||
std::optional<til::point> _singleClickTouchdownPos;
|
||||
std::optional<til::point> _lastMouseClickPosNoSelection;
|
||||
std::optional<Core::Point> _lastMouseClickPos;
|
||||
std::optional<Core::Point> _singleClickTouchdownPos;
|
||||
std::optional<Core::Point> _lastMouseClickPosNoSelection;
|
||||
// This field tracks whether the selection has changed meaningfully
|
||||
// since it was last copied. It's generally used to prevent copyOnSelect
|
||||
// from firing when the pointer _just happens_ to be released over the
|
||||
@ -129,20 +129,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _lastHoveredInterval{ std::nullopt };
|
||||
|
||||
unsigned int _numberOfClicks(til::point clickPos, Timestamp clickTime);
|
||||
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
|
||||
void _updateSystemParameterSettings() noexcept;
|
||||
|
||||
void _mouseTransparencyHandler(const double mouseDelta);
|
||||
void _mouseZoomHandler(const double mouseDelta);
|
||||
void _mouseScrollHandler(const double mouseDelta,
|
||||
const til::point terminalPosition,
|
||||
const Core::Point terminalPosition,
|
||||
const bool isLeftButtonPressed);
|
||||
|
||||
void _hyperlinkHandler(const std::wstring_view uri);
|
||||
bool _canSendVTMouseInput(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
|
||||
|
||||
void _sendPastedTextToConnection(std::wstring_view wstr);
|
||||
til::point _getTerminalPosition(const til::point& pixelPosition);
|
||||
til::point _getTerminalPosition(const til::point pixelPosition);
|
||||
|
||||
bool _sendMouseEventHelper(const til::point terminalPosition,
|
||||
const unsigned int pointerUpdateKind,
|
||||
|
||||
@ -37,11 +37,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void InteractivityAutomationPeer::SetControlBounds(const Windows::Foundation::Rect bounds)
|
||||
{
|
||||
_controlBounds = til::rectangle{ til::math::rounding, bounds };
|
||||
_controlBounds = til::rect{ til::math::rounding, bounds };
|
||||
}
|
||||
void InteractivityAutomationPeer::SetControlPadding(const Core::Padding padding)
|
||||
{
|
||||
_controlPadding = padding;
|
||||
_controlPadding = til::rect{ til::math::rounding, padding };
|
||||
}
|
||||
void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider)
|
||||
{
|
||||
@ -143,12 +143,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
#pragma region IControlAccessibilityInfo
|
||||
COORD InteractivityAutomationPeer::GetFontSize() const noexcept
|
||||
{
|
||||
return til::size{ til::math::rounding, _interactivity->Core().FontSize() };
|
||||
return til::size{ til::math::rounding, _interactivity->Core().FontSize() }.to_win32_coord();
|
||||
}
|
||||
|
||||
RECT InteractivityAutomationPeer::GetBounds() const noexcept
|
||||
{
|
||||
return _controlBounds;
|
||||
return _controlBounds.to_win32_rect();
|
||||
}
|
||||
|
||||
HRESULT InteractivityAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
|
||||
@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
RECT InteractivityAutomationPeer::GetPadding() const noexcept
|
||||
{
|
||||
return _controlPadding;
|
||||
return _controlPadding.to_win32_rect();
|
||||
}
|
||||
|
||||
double InteractivityAutomationPeer::GetScaleFactor() const noexcept
|
||||
|
||||
@ -81,8 +81,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity;
|
||||
weak_ref<Windows::UI::Xaml::Automation::Peers::AutomationPeer> _parentProvider;
|
||||
|
||||
til::rectangle _controlBounds{};
|
||||
til::rectangle _controlPadding{};
|
||||
til::rect _controlBounds{};
|
||||
til::rect _controlPadding{};
|
||||
|
||||
winrt::com_array<Windows::UI::Xaml::Automation::Provider::ITextRangeProvider> WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges);
|
||||
};
|
||||
|
||||
@ -144,7 +144,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Get the cursor position in text buffer position
|
||||
auto cursorArgs = winrt::make_self<CursorPositionEventArgs>();
|
||||
_CurrentCursorPositionHandlers(*this, *cursorArgs);
|
||||
const til::point cursorPos{ gsl::narrow_cast<ptrdiff_t>(cursorArgs->CurrentPosition().X), gsl::narrow_cast<ptrdiff_t>(cursorArgs->CurrentPosition().Y) };
|
||||
const til::point cursorPos{ til::math::flooring, cursorArgs->CurrentPosition() };
|
||||
|
||||
const double actualCanvasWidth{ Canvas().ActualWidth() };
|
||||
const double actualTextBlockHeight{ TextBlock().ActualHeight() };
|
||||
@ -189,14 +189,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Get scale factor for view
|
||||
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
|
||||
|
||||
const til::point clientCursorInDips{ clientCursorPos / scaleFactor };
|
||||
const til::point clientCursorInDips{ til::math::flooring, clientCursorPos.x / scaleFactor, clientCursorPos.y / scaleFactor };
|
||||
|
||||
// Position our TextBlock at the cursor position
|
||||
Canvas().SetLeft(TextBlock(), clientCursorInDips.x<double>());
|
||||
Canvas().SetTop(TextBlock(), clientCursorInDips.y<double>());
|
||||
Canvas().SetLeft(TextBlock(), clientCursorInDips.x);
|
||||
Canvas().SetTop(TextBlock(), clientCursorInDips.y);
|
||||
|
||||
// calculate FontSize in pixels from Points
|
||||
const double fontSizePx = (fontSize.height<double>() * 72) / USER_DEFAULT_SCREEN_DPI;
|
||||
const double fontSizePx = (fontSize.height * 72) / USER_DEFAULT_SCREEN_DPI;
|
||||
const double unscaledFontSizePx = fontSizePx / scaleFactor;
|
||||
|
||||
// Make sure to unscale the font size to correct for DPI! XAML needs
|
||||
@ -212,7 +212,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TextBlock().MinHeight(unscaledFontSizePx);
|
||||
_currentTextBlockHeight = std::max(unscaledFontSizePx, _currentTextBlockHeight);
|
||||
|
||||
const auto widthToTerminalEnd = _currentCanvasWidth - clientCursorInDips.x<double>();
|
||||
const auto widthToTerminalEnd = _currentCanvasWidth - clientCursorInDips.x;
|
||||
// Make sure that we're setting the MaxWidth to a positive number - a
|
||||
// negative number here will crash us in mysterious ways with a useless
|
||||
// stack trace
|
||||
@ -221,7 +221,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// Get window in screen coordinates, this is the entire window including
|
||||
// tabs. THIS IS IN DIPs
|
||||
const til::point windowOrigin{ til::math::flooring, _currentWindowBounds };
|
||||
const til::point windowOrigin{ til::math::flooring, _currentWindowBounds.X, _currentWindowBounds.Y };
|
||||
|
||||
// Get the offset (margin + tabs, etc..) of the control within the window
|
||||
const til::point controlOrigin{ til::math::flooring,
|
||||
@ -232,25 +232,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const til::point controlAbsoluteOrigin{ windowOrigin + controlOrigin };
|
||||
|
||||
// Convert the control origin to pixels
|
||||
const til::point scaledFrameOrigin = controlAbsoluteOrigin * scaleFactor;
|
||||
const til::point scaledFrameOrigin = til::point{ til::math::flooring, controlAbsoluteOrigin.x * scaleFactor, controlAbsoluteOrigin.y * scaleFactor };
|
||||
|
||||
// Get the location of the cursor in the display, in pixels.
|
||||
til::point screenCursorPos{ scaledFrameOrigin + clientCursorPos };
|
||||
|
||||
// GH #5007 - make sure to account for wrapping the IME composition at
|
||||
// the right side of the viewport.
|
||||
const ptrdiff_t textBlockHeight = ::base::ClampMul(_currentTextBlockHeight, scaleFactor);
|
||||
const auto textBlockHeight = ::base::ClampMul(_currentTextBlockHeight, scaleFactor);
|
||||
|
||||
// Get the bounds of the composition text, in pixels.
|
||||
const til::rectangle textBounds{ til::point{ screenCursorPos.x(), screenCursorPos.y() },
|
||||
til::size{ 0, textBlockHeight } };
|
||||
const til::rect textBounds{ til::point{ screenCursorPos.x, screenCursorPos.y },
|
||||
til::size{ 0, textBlockHeight } };
|
||||
|
||||
_currentTextBounds = textBounds;
|
||||
_currentTextBounds = textBounds.to_winrt_rect();
|
||||
|
||||
_currentControlBounds = Rect(screenCursorPos.x<float>(),
|
||||
screenCursorPos.y<float>(),
|
||||
0,
|
||||
fontSize.height<float>());
|
||||
_currentControlBounds = Rect(static_cast<float>(screenCursorPos.x),
|
||||
static_cast<float>(screenCursorPos.y),
|
||||
0.0f,
|
||||
static_cast<float>(fontSize.height));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@ -1137,7 +1137,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
auto anchor = til::point{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
_interactivity.TouchPressed(anchor);
|
||||
_interactivity.TouchPressed(anchor.to_core_point());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1146,7 +1146,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
point.Timestamp(),
|
||||
ControlKeyStates{ args.KeyModifiers() },
|
||||
_toTerminalOrigin(cursorPosition));
|
||||
_toTerminalOrigin(cursorPosition).to_core_point());
|
||||
}
|
||||
|
||||
args.Handled(true);
|
||||
@ -1185,7 +1185,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
_focused,
|
||||
pixelPosition,
|
||||
pixelPosition.to_core_point(),
|
||||
_pointerPressedInBounds);
|
||||
|
||||
// GH#9109 - Only start an auto-scroll when the drag actually
|
||||
@ -1227,7 +1227,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
|
||||
_interactivity.TouchMoved(newTouchPoint, _focused);
|
||||
_interactivity.TouchMoved(newTouchPoint.to_core_point(), _focused);
|
||||
}
|
||||
|
||||
args.Handled(true);
|
||||
@ -1263,7 +1263,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_interactivity.PointerReleased(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
pixelPosition);
|
||||
pixelPosition.to_core_point());
|
||||
}
|
||||
else if (type == Windows::Devices::Input::PointerDeviceType::Touch)
|
||||
{
|
||||
@ -1303,7 +1303,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() },
|
||||
point.Properties().MouseWheelDelta(),
|
||||
_toTerminalOrigin(point.Position()),
|
||||
_toTerminalOrigin(point.Position()).to_core_point(),
|
||||
TermControl::GetPressedMouseButtons(point));
|
||||
if (result)
|
||||
{
|
||||
@ -1334,7 +1334,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
WI_SetFlagIf(state, Control::MouseButtonState::IsMiddleButtonDown, midButtonDown);
|
||||
WI_SetFlagIf(state, Control::MouseButtonState::IsRightButtonDown, rightButtonDown);
|
||||
|
||||
return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location), state);
|
||||
return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location).to_core_point(), state);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -1704,7 +1704,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - cursorPosition: in pixels, relative to the origin of the control
|
||||
void TermControl::_SetEndSelectionPointAtCursor(Windows::Foundation::Point const& cursorPosition)
|
||||
{
|
||||
_interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition));
|
||||
_interactivity.SetEndSelectionPoint(_toTerminalOrigin(cursorPosition).to_core_point());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -2157,7 +2157,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const til::point relativeToMarginInDIPs = cursorPosInDIPs - marginsInDips;
|
||||
|
||||
// Convert it to pixels
|
||||
const til::point relativeToMarginInPixels{ relativeToMarginInDIPs * SwapChainPanel().CompositionScaleX() };
|
||||
const auto scale = SwapChainPanel().CompositionScaleX();
|
||||
const til::point relativeToMarginInPixels{
|
||||
til::math::flooring,
|
||||
relativeToMarginInDIPs.x * scale,
|
||||
relativeToMarginInDIPs.y * scale,
|
||||
};
|
||||
|
||||
return relativeToMarginInPixels;
|
||||
}
|
||||
@ -2196,10 +2201,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
const til::point cursorPos = _core.CursorPosition();
|
||||
Windows::Foundation::Point p = { ::base::ClampedNumeric<float>(cursorPos.x()),
|
||||
::base::ClampedNumeric<float>(cursorPos.y()) };
|
||||
eventArgs.CurrentPosition(p);
|
||||
const auto cursorPos = _core.CursorPosition();
|
||||
eventArgs.CurrentPosition({ static_cast<float>(cursorPos.X), static_cast<float>(cursorPos.Y) });
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -2597,13 +2600,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto uriText = _core.HoveredUriText();
|
||||
if (!uriText.empty())
|
||||
{
|
||||
const auto panel = SwapChainPanel();
|
||||
const auto scale = panel.CompositionScaleX();
|
||||
const auto offset = panel.ActualOffset();
|
||||
|
||||
// Update the tooltip with the URI
|
||||
HoveredUri().Text(uriText);
|
||||
|
||||
// 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 auto htInDips = charSizeInPixels.Height / scale;
|
||||
const auto wtInDips = charSizeInPixels.Width / scale;
|
||||
const Thickness newThickness{ wtInDips, htInDips, 0, 0 };
|
||||
HyperlinkTooltipBorder().BorderThickness(newThickness);
|
||||
|
||||
@ -2612,14 +2619,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
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 posInDIPs{ til::math::flooring, posInPixels.x / scale, posInPixels.y / scale };
|
||||
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));
|
||||
OverlayCanvas().SetLeft(HyperlinkTooltipBorder(), locationInDIPs.x - offset.x);
|
||||
OverlayCanvas().SetTop(HyperlinkTooltipBorder(), locationInDIPs.y - offset.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -515,8 +515,8 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
|
||||
const auto end = result->stop;
|
||||
std::wstring uri;
|
||||
|
||||
const auto startIter = _buffer->GetCellDataAt(_ConvertToBufferCell(start));
|
||||
const auto endIter = _buffer->GetCellDataAt(_ConvertToBufferCell(end));
|
||||
const auto startIter = _buffer->GetCellDataAt(_ConvertToBufferCell(start.to_win32_coord()));
|
||||
const auto endIter = _buffer->GetCellDataAt(_ConvertToBufferCell(end.to_win32_coord()));
|
||||
for (auto iter = startIter; iter != endIter; ++iter)
|
||||
{
|
||||
uri += iter->Chars();
|
||||
@ -545,7 +545,7 @@ uint16_t Terminal::GetHyperlinkIdAtPosition(const COORD position)
|
||||
// - The interval representing the start and end coordinates
|
||||
std::optional<PointTree::interval> Terminal::GetHyperlinkIntervalFromPosition(const COORD position)
|
||||
{
|
||||
const auto results = _patternIntervalTree.findOverlapping(COORD{ position.X + 1, position.Y }, position);
|
||||
const auto results = _patternIntervalTree.findOverlapping(til::point{ position.X + 1, position.Y }, til::point{ position });
|
||||
if (results.size() > 0)
|
||||
{
|
||||
for (const auto& result : results)
|
||||
@ -715,8 +715,8 @@ void Terminal::_InvalidatePatternTree(interval_tree::IntervalTree<til::point, si
|
||||
{
|
||||
const auto vis = _VisibleStartIndex();
|
||||
auto invalidate = [=](const PointTree::interval& interval) {
|
||||
COORD startCoord{ gsl::narrow<SHORT>(interval.start.x()), gsl::narrow<SHORT>(interval.start.y() + vis) };
|
||||
COORD endCoord{ gsl::narrow<SHORT>(interval.stop.x()), gsl::narrow<SHORT>(interval.stop.y() + vis) };
|
||||
COORD startCoord{ gsl::narrow<SHORT>(interval.start.x), gsl::narrow<SHORT>(interval.start.y + vis) };
|
||||
COORD endCoord{ gsl::narrow<SHORT>(interval.stop.x), gsl::narrow<SHORT>(interval.stop.y + vis) };
|
||||
_InvalidateFromCoords(startCoord, endCoord);
|
||||
};
|
||||
tree.visit_all(invalidate);
|
||||
@ -738,18 +738,18 @@ void Terminal::_InvalidateFromCoords(const COORD start, const COORD end)
|
||||
const auto rowSize = gsl::narrow<SHORT>(_buffer->GetRowByOffset(0).size());
|
||||
|
||||
// invalidate the first line
|
||||
SMALL_RECT region{ start.X, start.Y, rowSize - 1, start.Y };
|
||||
SMALL_RECT region{ start.X, start.Y, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(start.Y) };
|
||||
_buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region));
|
||||
|
||||
if ((end.Y - start.Y) > 1)
|
||||
{
|
||||
// invalidate the lines in between the first and last line
|
||||
region = til::rectangle(0, start.Y + 1, rowSize - 1, end.Y - 1);
|
||||
region = SMALL_RECT{ 0, start.Y + 1, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(end.Y - 1) };
|
||||
_buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region));
|
||||
}
|
||||
|
||||
// invalidate the last line
|
||||
region = til::rectangle(0, end.Y, end.X, end.Y);
|
||||
region = SMALL_RECT{ 0, end.Y, end.X, end.Y };
|
||||
_buffer->GetRenderTarget().TriggerRedraw(Viewport::FromInclusive(region));
|
||||
}
|
||||
}
|
||||
@ -1104,7 +1104,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
||||
// We have to report the delta here because we might have circled the text buffer.
|
||||
// That didn't change the viewport and therefore the TriggerScroll(void)
|
||||
// method can't detect the delta on its own.
|
||||
COORD delta{ 0, -rowsPushedOffTopOfBuffer };
|
||||
COORD delta{ 0, gsl::narrow_cast<short>(-rowsPushedOffTopOfBuffer) };
|
||||
_buffer->GetRenderTarget().TriggerScroll(&delta);
|
||||
}
|
||||
|
||||
|
||||
@ -335,11 +335,11 @@ void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos)
|
||||
{
|
||||
case SelectionDirection::Left:
|
||||
_buffer->GetSize().DecrementInBounds(pos);
|
||||
pos = _buffer->GetGlyphStart(pos);
|
||||
pos = _buffer->GetGlyphStart(til::point{ pos }).to_win32_coord();
|
||||
break;
|
||||
case SelectionDirection::Right:
|
||||
_buffer->GetSize().IncrementInBounds(pos);
|
||||
pos = _buffer->GetGlyphEnd(pos);
|
||||
pos = _buffer->GetGlyphEnd(til::point{ pos }).to_win32_coord();
|
||||
break;
|
||||
case SelectionDirection::Up:
|
||||
{
|
||||
|
||||
@ -169,7 +169,7 @@ const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkCustomId(uin
|
||||
const std::vector<size_t> Terminal::GetPatternId(const COORD location) const noexcept
|
||||
{
|
||||
// Look through our interval tree for this location
|
||||
const auto intervals = _patternIntervalTree.findOverlapping(COORD{ location.X + 1, location.Y }, location);
|
||||
const auto intervals = _patternIntervalTree.findOverlapping(til::point{ location.X + 1, location.Y }, til::point{ location });
|
||||
if (intervals.size() == 0)
|
||||
{
|
||||
return {};
|
||||
|
||||
@ -144,7 +144,7 @@ namespace ControlUnitTests
|
||||
// The mouse location and buttons don't matter here.
|
||||
interactivity->MouseWheel(modifiers,
|
||||
30,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ namespace ControlUnitTests
|
||||
// The mouse location and buttons don't matter here.
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-30,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
}
|
||||
@ -219,7 +219,7 @@ namespace ControlUnitTests
|
||||
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
|
||||
Log::Comment(L"Scroll up 19 more times, to the top");
|
||||
@ -228,18 +228,18 @@ namespace ControlUnitTests
|
||||
expectedTop--;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
Log::Comment(L"Scrolling up more should do nothing");
|
||||
expectedTop = 0;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
|
||||
Log::Comment(L"Scroll down 21 more times, to the bottom");
|
||||
@ -249,7 +249,7 @@ namespace ControlUnitTests
|
||||
expectedTop++;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
Log::Comment(NoThrowString().Format(L"internal scrollbar pos:%f", interactivity->_internalScrollbarPosition));
|
||||
}
|
||||
@ -257,11 +257,11 @@ namespace ControlUnitTests
|
||||
expectedTop = 21;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
interactivity->MouseWheel(modifiers,
|
||||
-WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
buttonState);
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
@ -305,7 +305,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -318,7 +318,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition2,
|
||||
cursorPosition2.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's now two selections (one on each row)");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -328,7 +328,7 @@ namespace ControlUnitTests
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
WM_LBUTTONUP, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition2);
|
||||
cursorPosition2.to_core_point());
|
||||
Log::Comment(L"Verify that there's still two selections");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
VERIFY_ARE_EQUAL(2u, core->_terminal->GetSelectionRects().size());
|
||||
@ -340,7 +340,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition3);
|
||||
cursorPosition3.to_core_point());
|
||||
Log::Comment(L"Verify that there's now no selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
VERIFY_ARE_EQUAL(0u, core->_terminal->GetSelectionRects().size());
|
||||
@ -352,7 +352,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition4,
|
||||
cursorPosition4.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's now one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -392,13 +392,13 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
|
||||
VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value());
|
||||
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
@ -407,7 +407,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -423,7 +423,7 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Scroll up a line, with the left mouse button selected");
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
leftMouseDown);
|
||||
|
||||
Log::Comment(L"Verify the location of the selection");
|
||||
@ -466,7 +466,7 @@ namespace ControlUnitTests
|
||||
// WHEEL_DELTA is 120, so we'll use 24 for now as the delta, just so the tests don't take forever.
|
||||
|
||||
const int delta = WHEEL_DELTA / 5;
|
||||
const til::point mousePos{ 0, 0 };
|
||||
const Core::Point mousePos{ 0, 0 };
|
||||
Control::MouseButtonState state{};
|
||||
|
||||
interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5
|
||||
@ -541,21 +541,21 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
|
||||
VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value());
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width<int>() * 2, 0 };
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -586,21 +586,21 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
|
||||
VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value());
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width<int>() * 2, 0 };
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
@ -615,18 +615,18 @@ namespace ControlUnitTests
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
WM_LBUTTONUP,
|
||||
modifiers,
|
||||
cursorPosition1);
|
||||
cursorPosition1.to_core_point());
|
||||
|
||||
VERIFY_ARE_EQUAL(expectedAnchor, core->_terminal->GetSelectionAnchor());
|
||||
VERIFY_ARE_EQUAL(expectedEnd, core->_terminal->GetSelectionEnd());
|
||||
|
||||
Log::Comment(L"Simulate dragging the mouse into the control, without first clicking into the control");
|
||||
const til::point cursorPosition2{ fontSize.width<int>() * 10, 0 };
|
||||
const til::point cursorPosition2{ fontSize.width * 10, 0 };
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition2,
|
||||
cursorPosition2.to_core_point(),
|
||||
false);
|
||||
|
||||
Log::Comment(L"The selection should be unchanged.");
|
||||
@ -689,7 +689,7 @@ namespace ControlUnitTests
|
||||
expectedTop--;
|
||||
interactivity->MouseWheel(modifiers,
|
||||
WHEEL_DELTA,
|
||||
til::point{ 0, 0 },
|
||||
Core::Point{ 0, 0 },
|
||||
noMouseDown);
|
||||
}
|
||||
|
||||
@ -704,7 +704,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
@ -717,7 +717,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's still no selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
@ -753,13 +753,13 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
cursorPosition0);
|
||||
cursorPosition0.to_core_point());
|
||||
|
||||
Log::Comment(L"Verify that there's not yet a selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
|
||||
VERIFY_IS_TRUE(interactivity->_singleClickTouchdownPos.has_value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0, interactivity->_singleClickTouchdownPos.value());
|
||||
VERIFY_ARE_EQUAL(cursorPosition0.to_core_point(), interactivity->_singleClickTouchdownPos.value());
|
||||
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
@ -768,7 +768,7 @@ namespace ControlUnitTests
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
true, // focused,
|
||||
cursorPosition1,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
#include "../../renderer/vt/Xterm256Engine.hpp"
|
||||
#include "../../renderer/vt/XtermEngine.hpp"
|
||||
|
||||
class InputBuffer; // This for some reason needs to be fwd-decl'd
|
||||
#include "../host/inputBuffer.hpp"
|
||||
#include "../host/readDataCooked.hpp"
|
||||
#include "../host/output.h"
|
||||
@ -227,7 +226,7 @@ private:
|
||||
void _resizeConpty(const unsigned short sx, const unsigned short sy);
|
||||
void _clearConpty();
|
||||
|
||||
[[nodiscard]] std::tuple<TextBuffer*, TextBuffer*> _performResize(const til::size& newSize);
|
||||
[[nodiscard]] std::tuple<TextBuffer*, TextBuffer*> _performResize(const til::size newSize);
|
||||
|
||||
std::deque<std::string> expectedOutput;
|
||||
|
||||
@ -307,7 +306,7 @@ void ConptyRoundtripTests::_clearConpty()
|
||||
_pConApi->PrivateClearBuffer();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::tuple<TextBuffer*, TextBuffer*> ConptyRoundtripTests::_performResize(const til::size& newSize)
|
||||
[[nodiscard]] std::tuple<TextBuffer*, TextBuffer*> ConptyRoundtripTests::_performResize(const til::size newSize)
|
||||
{
|
||||
// IMPORTANT! Anyone calling this should make sure that the test is running
|
||||
// in IsolationLevel: Method. If you don't add that, then it might secretly
|
||||
@ -315,9 +314,9 @@ void ConptyRoundtripTests::_clearConpty()
|
||||
|
||||
Log::Comment(L"========== Resize the Terminal and conpty ==========");
|
||||
|
||||
auto resizeResult = term->UserResize(newSize);
|
||||
auto resizeResult = term->UserResize(newSize.to_win32_coord());
|
||||
VERIFY_SUCCEEDED(resizeResult);
|
||||
_resizeConpty(newSize.width<unsigned short>(), newSize.height<unsigned short>());
|
||||
_resizeConpty(newSize.narrow_width<unsigned short>(), newSize.narrow_height<unsigned short>());
|
||||
|
||||
// After we resize, make sure to get the new textBuffers
|
||||
return { &ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer().GetTextBuffer(),
|
||||
@ -900,7 +899,7 @@ void ConptyRoundtripTests::TestResizeHeight()
|
||||
// Conpty's doesn't have a scrollback, it's view's origin is always 0,0
|
||||
const auto thirdHostView = si.GetViewport();
|
||||
VERIFY_ARE_EQUAL(0, thirdHostView.Top());
|
||||
VERIFY_ARE_EQUAL(newViewportSize.height(), thirdHostView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(newViewportSize.height, thirdHostView.BottomExclusive());
|
||||
|
||||
// The Terminal should be stuck to the top of the viewport, unless dy<0,
|
||||
// rows=50. In that set of cases, we _didn't_ pin the top of the Terminal to
|
||||
@ -928,7 +927,7 @@ void ConptyRoundtripTests::TestResizeHeight()
|
||||
// Conpty's doesn't have a scrollback, it's view's origin is always 0,0
|
||||
const auto fourthHostView = si.GetViewport();
|
||||
VERIFY_ARE_EQUAL(0, fourthHostView.Top());
|
||||
VERIFY_ARE_EQUAL(newViewportSize.height(), fourthHostView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(newViewportSize.height, fourthHostView.BottomExclusive());
|
||||
|
||||
// The Terminal should be stuck to the top of the viewport, unless dy<0,
|
||||
// rows=50. In that set of cases, we _didn't_ pin the top of the Terminal to
|
||||
@ -1086,16 +1085,16 @@ void ConptyRoundtripTests::PassthroughClearAll()
|
||||
sm.ProcessString(L"~");
|
||||
}
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool afterClear = false) {
|
||||
const auto width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool afterClear = false) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
|
||||
// "~" rows
|
||||
for (short row = 0; row < viewport.bottom<short>(); row++)
|
||||
for (short row = 0; row < viewport.narrow_bottom<short>(); row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced());
|
||||
auto iter = tb.GetCellDataAt({ 0, row });
|
||||
if (afterClear && row >= viewport.top<short>())
|
||||
if (afterClear && row >= viewport.narrow_top<short>())
|
||||
{
|
||||
TestUtils::VerifySpanOfText(L" ", iter, 0, width);
|
||||
}
|
||||
@ -1108,15 +1107,15 @@ void ConptyRoundtripTests::PassthroughClearAll()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
|
||||
const til::rectangle originalTerminalView{ term->_mutableViewport.ToInclusive() };
|
||||
const til::rect originalTerminalView{ term->_mutableViewport.ToInclusive() };
|
||||
|
||||
// Here, we'll emit the 2J to EraseAll, and move the viewport contents into
|
||||
// the scrollback.
|
||||
@ -1127,12 +1126,12 @@ void ConptyRoundtripTests::PassthroughClearAll()
|
||||
|
||||
// Make sure that the terminal's new viewport is actually just lower than it
|
||||
// used to be.
|
||||
const til::rectangle newTerminalView{ term->_mutableViewport.ToInclusive() };
|
||||
VERIFY_ARE_EQUAL(end, newTerminalView.top<short>());
|
||||
VERIFY_IS_GREATER_THAN(newTerminalView.top(), originalTerminalView.top());
|
||||
const til::rect newTerminalView{ term->_mutableViewport.ToInclusive() };
|
||||
VERIFY_ARE_EQUAL(end, newTerminalView.narrow_top<short>());
|
||||
VERIFY_IS_GREATER_THAN(newTerminalView.top, originalTerminalView.top);
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
@ -1370,9 +1369,9 @@ void ConptyRoundtripTests::OutputWrappedLinesAtBottomOfBuffer()
|
||||
|
||||
auto iter0 = tb.GetCellDataAt({ 0, wrappedRow });
|
||||
TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth);
|
||||
auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 });
|
||||
auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L"A", iter1, 0, 20);
|
||||
auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 });
|
||||
auto iter2 = tb.GetCellDataAt({ 20, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20);
|
||||
};
|
||||
|
||||
@ -1457,9 +1456,9 @@ void ConptyRoundtripTests::ScrollWithChangesInMiddle()
|
||||
L"8"); // Restore
|
||||
hostSm.ProcessString(std::wstring(wrappedLineLength, L'A')); // Print 100 'A's
|
||||
|
||||
auto verifyBuffer = [](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
const short wrappedRow = viewport.bottom<short>() - 2;
|
||||
const short start = viewport.top<short>();
|
||||
auto verifyBuffer = [](const TextBuffer& tb, const til::rect& viewport) {
|
||||
const auto wrappedRow = gsl::narrow<short>(viewport.bottom - 2);
|
||||
const short start = viewport.narrow_top<short>();
|
||||
for (short i = start; i < wrappedRow; i++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", i));
|
||||
@ -1472,20 +1471,20 @@ void ConptyRoundtripTests::ScrollWithChangesInMiddle()
|
||||
auto iter0 = tb.GetCellDataAt({ 0, wrappedRow });
|
||||
TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth);
|
||||
|
||||
auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 });
|
||||
auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L"A", iter1, 0, 20);
|
||||
auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 });
|
||||
auto iter2 = tb.GetCellDataAt({ 20, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20);
|
||||
};
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Checking the host buffer..."));
|
||||
verifyBuffer(hostTb, hostView.ToInclusive());
|
||||
verifyBuffer(hostTb, til::rect{ hostView.ToInclusive() });
|
||||
Log::Comment(NoThrowString().Format(L"... Done"));
|
||||
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Checking the terminal buffer..."));
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
Log::Comment(NoThrowString().Format(L"... Done"));
|
||||
}
|
||||
|
||||
@ -1840,11 +1839,11 @@ void ConptyRoundtripTests::ClearHostTrickeryTest()
|
||||
_flushFirstFrame();
|
||||
|
||||
auto verifyBuffer = [&cursorOnNextLine, &useLongSpaces, &printTextAfterSpaces](const TextBuffer& tb,
|
||||
const til::rectangle viewport) {
|
||||
const til::rect viewport) {
|
||||
// We _would_ expect the Terminal's cursor to be on { 8, 0 }, but this
|
||||
// is currently broken due to #381/#4676. So we'll use the viewport
|
||||
// provided to find the actual Y position of the cursor.
|
||||
const short viewTop = viewport.origin().y<short>();
|
||||
const short viewTop = viewport.origin().narrow_y<short>();
|
||||
const short cursorRow = viewTop + (cursorOnNextLine ? 1 : 0);
|
||||
const short cursorCol = (cursorOnNextLine ? 5 :
|
||||
(10 + (useLongSpaces ? 5 : 0) + (printTextAfterSpaces ? 5 : 0)));
|
||||
@ -1921,13 +1920,13 @@ void ConptyRoundtripTests::ClearHostTrickeryTest()
|
||||
hostSm.ProcessString(L"\x1b[?1049l");
|
||||
|
||||
Log::Comment(L"Checking the host buffer state");
|
||||
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"Checking the terminal buffer state");
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer()
|
||||
@ -1948,15 +1947,15 @@ void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer()
|
||||
_flushFirstFrame();
|
||||
|
||||
auto verifyBuffer = [](const TextBuffer& tb,
|
||||
const til::rectangle viewport) {
|
||||
const auto lastRow = viewport.bottom<short>() - 1;
|
||||
const til::rect viewport) {
|
||||
const auto lastRow = viewport.bottom - 1;
|
||||
const til::point expectedCursor{ 0, lastRow - 1 };
|
||||
VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() });
|
||||
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
|
||||
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", til::point{ 0, lastRow - 2 });
|
||||
TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", til::point{ 0, lastRow - 1 });
|
||||
TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", til::point{ 0, lastRow });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", COORD{ 0, gsl::narrow<short>(lastRow - 2) });
|
||||
TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", COORD{ 0, gsl::narrow<short>(lastRow - 1) });
|
||||
TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", COORD{ 0, gsl::narrow<short>(lastRow) });
|
||||
};
|
||||
|
||||
_logConpty = true;
|
||||
@ -1993,14 +1992,14 @@ void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer()
|
||||
hostSm.ProcessString(L"\n");
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::MarginsWithStatusLine()
|
||||
@ -2026,17 +2025,17 @@ void ConptyRoundtripTests::MarginsWithStatusLine()
|
||||
_flushFirstFrame();
|
||||
|
||||
auto verifyBuffer = [](const TextBuffer& tb,
|
||||
const til::rectangle viewport) {
|
||||
const auto lastRow = viewport.bottom<short>() - 1;
|
||||
const til::rect viewport) {
|
||||
const auto lastRow = gsl::narrow<short>(viewport.bottom - 1);
|
||||
const til::point expectedCursor{ 1, lastRow };
|
||||
VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() });
|
||||
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
|
||||
|
||||
TestUtils::VerifyExpectedString(tb, L"EEEEEEEEEE", til::point{ 0, lastRow - 4 });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA", til::point{ 0, lastRow - 3 });
|
||||
TestUtils::VerifyExpectedString(tb, L" ", til::point{ 0, lastRow - 2 });
|
||||
TestUtils::VerifyExpectedString(tb, L"XBBBBBBBBB", til::point{ 0, lastRow - 1 });
|
||||
TestUtils::VerifyExpectedString(tb, L"YCCCCCCCCC", til::point{ 0, lastRow });
|
||||
TestUtils::VerifyExpectedString(tb, L"EEEEEEEEEE", COORD{ 0, gsl::narrow<short>(lastRow - 4) });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA", COORD{ 0, gsl::narrow<short>(lastRow - 3) });
|
||||
TestUtils::VerifyExpectedString(tb, L" ", COORD{ 0, gsl::narrow<short>(lastRow - 2) });
|
||||
TestUtils::VerifyExpectedString(tb, L"XBBBBBBBBB", COORD{ 0, gsl::narrow<short>(lastRow - 1) });
|
||||
TestUtils::VerifyExpectedString(tb, L"YCCCCCCCCC", COORD{ 0, lastRow });
|
||||
};
|
||||
|
||||
// We're _not_ checking the conpty output during this test, only the side effects.
|
||||
@ -2076,7 +2075,7 @@ void ConptyRoundtripTests::MarginsWithStatusLine()
|
||||
src.Left = 0;
|
||||
src.Right = si.GetViewport().Width();
|
||||
src.Bottom = originalBottom;
|
||||
COORD tgt = { 0, newBottom - 1 };
|
||||
COORD tgt{ 0, gsl::narrow<short>(newBottom - 1) };
|
||||
TextAttribute useThisAttr(0x07); // We don't terribly care about the attributes so this is arbitrary
|
||||
ScrollRegion(si, src, std::nullopt, tgt, L' ', useThisAttr);
|
||||
}
|
||||
@ -2090,14 +2089,14 @@ void ConptyRoundtripTests::MarginsWithStatusLine()
|
||||
hostSm.ProcessString(L"Y");
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::OutputWrappedLineWithSpace()
|
||||
@ -2273,7 +2272,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer()
|
||||
sm.ProcessString(std::wstring(spacesLength, L' '));
|
||||
sm.ProcessString(std::wstring(secondTextLength, L'B'));
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) {
|
||||
// Buffer contents should look like the following: (80 wide)
|
||||
// (w) means we hard wrapped the line
|
||||
// (b) means the line is _not_ wrapped (it's broken, the default state.)
|
||||
@ -2282,7 +2281,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer()
|
||||
// | B_ ... | (b) (cursor is on the '_')
|
||||
// | ... | (b)
|
||||
|
||||
const short wrappedRow = viewport.bottom<short>() - 2;
|
||||
const auto wrappedRow = gsl::narrow<short>(viewport.bottom - 2);
|
||||
VERIFY_IS_TRUE(tb.GetRowByOffset(wrappedRow).WasWrapForced());
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(wrappedRow + 1).WasWrapForced());
|
||||
|
||||
@ -2292,20 +2291,20 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer()
|
||||
TestUtils::VerifySpanOfText(L" ", iter0, 0, 2);
|
||||
|
||||
// Second row
|
||||
auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 });
|
||||
auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L" ", iter1, 0, 1);
|
||||
auto iter2 = tb.GetCellDataAt({ 1, wrappedRow + 1 });
|
||||
auto iter2 = tb.GetCellDataAt({ 1, gsl::narrow<short>(wrappedRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L"B", iter2, 0, secondTextLength);
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(hostTb, hostView.ToInclusive());
|
||||
verifyBuffer(hostTb, til::rect{ hostView.ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::BreakLinesOnCursorMovement()
|
||||
@ -2344,22 +2343,22 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement()
|
||||
(cursorMovementMode == MoveCursorWithCUB_LF);
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb,
|
||||
const til::rectangle viewport) {
|
||||
const auto lastRow = viewport.bottom<short>() - 1;
|
||||
const til::rect viewport) {
|
||||
const auto lastRow = gsl::narrow<short>(viewport.bottom - 1);
|
||||
const til::point expectedCursor{ 5, lastRow };
|
||||
VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() });
|
||||
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
|
||||
|
||||
for (auto y = viewport.top<short>(); y < lastRow; y++)
|
||||
for (auto y = viewport.narrow_top<short>(); y < lastRow; y++)
|
||||
{
|
||||
// We're using CUP to move onto the status line _always_, so the
|
||||
// second-last row will always be marked as wrapped.
|
||||
const auto rowWrapped = (!expectHardBreak) || (y == lastRow - 1);
|
||||
VERIFY_ARE_EQUAL(rowWrapped, tb.GetRowByOffset(y).WasWrapForced());
|
||||
TestUtils::VerifyExpectedString(tb, L"~ ", til::point{ 0, y });
|
||||
TestUtils::VerifyExpectedString(tb, L"~ ", COORD{ 0, y });
|
||||
}
|
||||
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAA", til::point{ 0, lastRow });
|
||||
TestUtils::VerifyExpectedString(tb, L"AAAAA", COORD{ 0, lastRow });
|
||||
};
|
||||
|
||||
// We're _not_ checking the conpty output during this test, only the side effects.
|
||||
@ -2468,14 +2467,14 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement()
|
||||
hostSm.ProcessString(L"AAAAA");
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(altTextBuffer, altBuffer.GetViewport().ToInclusive());
|
||||
verifyBuffer(altTextBuffer, til::rect{ altBuffer.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
|
||||
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces()
|
||||
@ -2519,7 +2518,7 @@ void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces()
|
||||
VERIFY_IS_FALSE(lastRow.WasWrapForced());
|
||||
|
||||
auto expectedStringSecondToLastRow{ std::wstring(gsl::narrow_cast<size_t>(tb.GetSize().Width()) - 1, L'A') + L" " };
|
||||
TestUtils::VerifyExpectedString(tb, expectedStringSecondToLastRow, { 0, bottomRow - 1 });
|
||||
TestUtils::VerifyExpectedString(tb, expectedStringSecondToLastRow, { 0, gsl::narrow<short>(bottomRow - 1) });
|
||||
TestUtils::VerifyExpectedString(tb, L"B", { 0, bottomRow });
|
||||
};
|
||||
|
||||
@ -2588,9 +2587,9 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
|
||||
|
||||
drawVim();
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
const auto firstRow = viewport.top<short>();
|
||||
const auto width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) {
|
||||
const auto firstRow = viewport.narrow_top<short>();
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
|
||||
// First row
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(firstRow).WasWrapForced());
|
||||
@ -2600,12 +2599,12 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
|
||||
|
||||
// Second row
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(firstRow + 1).WasWrapForced());
|
||||
auto iter1 = tb.GetCellDataAt({ 0, firstRow + 1 });
|
||||
auto iter1 = tb.GetCellDataAt({ 0, gsl::narrow<short>(firstRow + 1) });
|
||||
TestUtils::VerifySpanOfText(L"B", iter1, 0, 3);
|
||||
TestUtils::VerifySpanOfText(L" ", iter1, 0, width - 3);
|
||||
|
||||
// "~" rows
|
||||
for (short row = firstRow + 2; row < viewport.bottom<short>() - 1; row++)
|
||||
for (short row = firstRow + 2; row < viewport.bottom - 1; row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
VERIFY_IS_TRUE(tb.GetRowByOffset(row).WasWrapForced());
|
||||
@ -2616,7 +2615,7 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
|
||||
|
||||
// Last row
|
||||
{
|
||||
short row = viewport.bottom<short>() - 1;
|
||||
const auto row = gsl::narrow<short>(viewport.bottom - 1);
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
VERIFY_IS_TRUE(tb.GetRowByOffset(row).WasWrapForced());
|
||||
auto iter = tb.GetCellDataAt({ 0, row });
|
||||
@ -2626,13 +2625,13 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
|
||||
// After we resize, make sure to get the new textBuffers
|
||||
std::tie(hostTb, termTb) = _performResize({ TerminalViewWidth - 1,
|
||||
@ -2646,13 +2645,13 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
|
||||
drawVim();
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest()
|
||||
@ -2698,11 +2697,11 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest()
|
||||
sm.ProcessString(L"~");
|
||||
}
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool afterClear = false) {
|
||||
const auto width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool afterClear = false) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
|
||||
// "~" rows
|
||||
for (short row = 0; row < viewport.bottom<short>(); row++)
|
||||
for (short row = 0; row < viewport.narrow_bottom<short>(); row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced());
|
||||
@ -2720,13 +2719,13 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
|
||||
VERIFY_ARE_EQUAL(si.GetViewport().Dimensions(), si.GetBufferSize().Dimensions());
|
||||
VERIFY_ARE_EQUAL(si.GetViewport(), si.GetBufferSize());
|
||||
@ -2790,12 +2789,12 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest()
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true);
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::TestResizeWithCookedRead()
|
||||
@ -2934,8 +2933,8 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
|
||||
sm.ProcessString(L"#");
|
||||
}
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool isTerminal, const bool afterResize) {
|
||||
const auto width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool isTerminal, const bool afterResize) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
|
||||
// Conhost and Terminal attributes are potentially different.
|
||||
const auto greenAttrs = isTerminal ? terminalGreenAttrs : conhostGreenAttrs;
|
||||
@ -2967,19 +2966,19 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
|
||||
}
|
||||
else
|
||||
{
|
||||
TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.width<size_t>());
|
||||
TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.narrow_width<size_t>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false, false);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false, false);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true, false);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true, false);
|
||||
|
||||
// After we resize, make sure to get the new textBuffers
|
||||
std::tie(hostTb, termTb) = _performResize({ TerminalViewWidth + dx,
|
||||
@ -2989,13 +2988,13 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false, true);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false, true);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true, true);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true, true);
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
||||
@ -3072,20 +3071,20 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
||||
}
|
||||
}
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
const auto width = viewport.width<short>();
|
||||
const auto isTerminal = viewport.top() != 0;
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
const auto isTerminal = viewport.top != 0;
|
||||
|
||||
// Conhost and Terminal attributes are potentially different.
|
||||
const auto blueAttrs = isTerminal ? terminalBlueAttrs : conhostBlueAttrs;
|
||||
|
||||
for (short row = 0; row < viewport.bottom<short>() - 2; row++)
|
||||
for (short row = 0; row < viewport.bottom - 2; row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(row).WasWrapForced());
|
||||
|
||||
const auto isBlank = (row % 2) == 0;
|
||||
const auto rowCircled = row > (viewport.bottom<short>() - 1 - circledRows);
|
||||
const auto rowCircled = row > (viewport.bottom - 1 - circledRows);
|
||||
// When the buffer circles, new lines will be initialized using the
|
||||
// current text attributes. Those will be the default-on-default
|
||||
// attributes. All of the Terminal's buffer will use
|
||||
@ -3095,7 +3094,7 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
||||
|
||||
if (isBlank)
|
||||
{
|
||||
TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.width<size_t>());
|
||||
TestUtils::VerifyLineContains(tb, { 0, row }, L' ', actualDefaultAttrs, viewport.narrow_width<size_t>());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3109,13 +3108,13 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void doWriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view string, DWORD flags = 0)
|
||||
@ -3272,17 +3271,17 @@ void ConptyRoundtripTests::WrapNewLineAtBottom()
|
||||
// row[4]: |~~~~~~~~~~~~~~~~~~~| <wrap>
|
||||
// row[5]: |~~~~~~ | <break>
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
const auto width = viewport.width<short>();
|
||||
const auto isTerminal = viewport.top() != 0;
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
const auto isTerminal = viewport.top != 0;
|
||||
|
||||
for (short row = 0; row < viewport.bottom<short>(); row++)
|
||||
for (short row = 0; row < viewport.narrow_bottom<short>(); row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
|
||||
// The first line wrapped, the second didn't, so on and so forth
|
||||
const auto isWrapped = (row % 2) == 0;
|
||||
const auto rowCircled = row >= (viewport.bottom<short>() - circledRows);
|
||||
const auto rowCircled = row >= (viewport.bottom - circledRows);
|
||||
|
||||
const auto actualNonSpacesAttrs = defaultAttrs;
|
||||
const auto actualSpacesAttrs = rowCircled || isTerminal ? defaultAttrs : conhostDefaultAttrs;
|
||||
@ -3290,25 +3289,25 @@ void ConptyRoundtripTests::WrapNewLineAtBottom()
|
||||
VERIFY_ARE_EQUAL(isWrapped, tb.GetRowByOffset(row).WasWrapForced());
|
||||
if (isWrapped)
|
||||
{
|
||||
TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), til::point{ 0, row });
|
||||
TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), COORD{ 0, row });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), til::point{ 0, row });
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), COORD{ 0, row });
|
||||
TestUtils::VerifyExpectedString(std::wstring(width - charsInSecondLine, L' '), iter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
VERIFY_ARE_EQUAL(circledRows, term->_mutableViewport.Top());
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS()
|
||||
@ -3474,10 +3473,10 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS()
|
||||
}
|
||||
}
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport) {
|
||||
const auto width = viewport.width<short>();
|
||||
const auto isTerminal = viewport.top() != 0;
|
||||
auto lastRow = viewport.bottom<short>() - 1;
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
const auto isTerminal = viewport.top != 0;
|
||||
auto lastRow = gsl::narrow<short>(viewport.bottom - 1);
|
||||
for (short row = 0; row < lastRow; row++)
|
||||
{
|
||||
Log::Comment(NoThrowString().Format(L"Checking row %d", row));
|
||||
@ -3489,7 +3488,7 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS()
|
||||
// buffer, then the top line of the conpty will _not_ be wrapped,
|
||||
// when the 0th line of the terminal buffer _is_.
|
||||
const auto isWrapped = (row % 2) == (isTerminal ? 0 : 1);
|
||||
const auto rowCircled = row >= (viewport.bottom<short>() - circledRows);
|
||||
const auto rowCircled = row >= (viewport.bottom - circledRows);
|
||||
|
||||
const auto actualNonSpacesAttrs = defaultAttrs;
|
||||
const auto actualSpacesAttrs = rowCircled || isTerminal ? defaultAttrs : conhostDefaultAttrs;
|
||||
@ -3497,28 +3496,28 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS()
|
||||
VERIFY_ARE_EQUAL(isWrapped, tb.GetRowByOffset(row).WasWrapForced());
|
||||
if (isWrapped)
|
||||
{
|
||||
TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), til::point{ 0, row });
|
||||
TestUtils::VerifyExpectedString(tb, std::wstring(charsInFirstLine, L'~'), COORD{ 0, row });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), til::point{ 0, row });
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(charsInSecondLine, L'~'), COORD{ 0, row });
|
||||
TestUtils::VerifyExpectedString(std::wstring(width - charsInSecondLine, L' '), iter);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_FALSE(tb.GetRowByOffset(lastRow).WasWrapForced());
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(1, L':'), til::point{ 0, lastRow });
|
||||
auto iter = TestUtils::VerifyExpectedString(tb, std::wstring(1, L':'), COORD{ 0, lastRow });
|
||||
TestUtils::VerifyExpectedString(std::wstring(width - 1, L' '), iter);
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive());
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() });
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
|
||||
Log::Comment(L"========== Checking the terminal buffer state ==========");
|
||||
VERIFY_ARE_EQUAL(circledRows + 1, term->_mutableViewport.Top());
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive());
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() });
|
||||
}
|
||||
|
||||
void ConptyRoundtripTests::DeleteWrappedWord()
|
||||
@ -3550,8 +3549,8 @@ void ConptyRoundtripTests::DeleteWrappedWord()
|
||||
sm.ProcessString(std::wstring(50, L'B'));
|
||||
sm.ProcessString(L"\x1b[?25h");
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool after) {
|
||||
const auto width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool after) {
|
||||
const auto width = viewport.narrow_width<short>();
|
||||
|
||||
auto iter1 = tb.GetCellDataAt({ 0, 0 });
|
||||
TestUtils::VerifySpanOfText(L"A", iter1, 0, 50);
|
||||
@ -3574,12 +3573,12 @@ void ConptyRoundtripTests::DeleteWrappedWord()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), false);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, false);
|
||||
|
||||
// Now, go back and erase all the 'B's, as if the user executed a
|
||||
// backward-kill-word in PowerShell. Afterwards, the buffer will look like:
|
||||
@ -3603,12 +3602,12 @@ void ConptyRoundtripTests::DeleteWrappedWord()
|
||||
sm.ProcessString(L"\x1b[?25h");
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true);
|
||||
}
|
||||
|
||||
// This test checks that upon conpty rendering again, terminal still maintains
|
||||
@ -3712,8 +3711,8 @@ void ConptyRoundtripTests::ClearBufferSignal()
|
||||
sm.ProcessString(L"\x1b[?m");
|
||||
sm.ProcessString(L"\x1b[?25h");
|
||||
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool before) {
|
||||
const short width = viewport.width<short>();
|
||||
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool before) {
|
||||
const short width = viewport.narrow_width<short>();
|
||||
const short numCharsOnSecondLine = 50 - (width - 51);
|
||||
auto iter1 = tb.GetCellDataAt({ 0, 0 });
|
||||
if (before)
|
||||
@ -3733,21 +3732,21 @@ void ConptyRoundtripTests::ClearBufferSignal()
|
||||
};
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (before) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), true);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, true);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
Log::Comment(L"========== Checking the terminal buffer state (before) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), true);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, true);
|
||||
|
||||
Log::Comment(L"========== Clear the ConPTY buffer with the signal ==========");
|
||||
_clearConpty();
|
||||
|
||||
Log::Comment(L"========== Checking the host buffer state (after) ==========");
|
||||
verifyBuffer(*hostTb, si.GetViewport().ToInclusive(), false);
|
||||
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, false);
|
||||
|
||||
Log::Comment(L"Painting the frame");
|
||||
VERIFY_SUCCEEDED(renderer.PaintFrame());
|
||||
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
|
||||
verifyBuffer(*termTb, term->_mutableViewport.ToInclusive(), false);
|
||||
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, false);
|
||||
}
|
||||
|
||||
@ -3,23 +3,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// Method Description:
|
||||
// - Scales a Rect based on a scale factor
|
||||
// Arguments:
|
||||
// - rect: Rect to scale by scale
|
||||
// - scale: amount to scale rect by
|
||||
// Return Value:
|
||||
// - Rect scaled by scale
|
||||
inline winrt::Windows::Foundation::Rect ScaleRect(winrt::Windows::Foundation::Rect rect, double scale)
|
||||
{
|
||||
const auto scaleLocal = base::ClampedNumeric<float>(scale);
|
||||
rect.X = base::ClampMul(rect.X, scaleLocal);
|
||||
rect.Y = base::ClampMul(rect.Y, scaleLocal);
|
||||
rect.Width = base::ClampMul(rect.Width, scaleLocal);
|
||||
rect.Height = base::ClampMul(rect.Height, scaleLocal);
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
|
||||
// Parameters:
|
||||
|
||||
@ -532,10 +532,10 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
|
||||
|
||||
// Get the size of a window we'd need to host that client rect. This will
|
||||
// add the titlebar space.
|
||||
const til::size nonClientSize = _window->GetTotalNonClientExclusiveSize(dpix);
|
||||
const til::rectangle nonClientFrame = _window->GetNonClientFrame(dpix);
|
||||
adjustedWidth = islandWidth + nonClientSize.width<long>();
|
||||
adjustedHeight = islandHeight + nonClientSize.height<long>();
|
||||
const til::size nonClientSize{ _window->GetTotalNonClientExclusiveSize(dpix) };
|
||||
const til::rect nonClientFrame{ _window->GetNonClientFrame(dpix) };
|
||||
adjustedWidth = islandWidth + nonClientSize.width;
|
||||
adjustedHeight = islandHeight + nonClientSize.height;
|
||||
|
||||
til::size dimensions{ Utils::ClampToShortMax(adjustedWidth, 1),
|
||||
Utils::ClampToShortMax(adjustedHeight, 1) };
|
||||
@ -554,7 +554,7 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
|
||||
// for the top here - the IslandWindow includes the titlebar in
|
||||
// nonClientFrame.top, so adjusting for that would actually place the
|
||||
// titlebar _off_ the monitor.
|
||||
til::point origin{ (proposedRect.left + nonClientFrame.left<LONG>()),
|
||||
til::point origin{ (proposedRect.left + nonClientFrame.left),
|
||||
(proposedRect.top) };
|
||||
|
||||
if (_logic.IsQuakeWindow())
|
||||
@ -564,12 +564,12 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
|
||||
const til::size availableSpace = desktopDimensions + nonClientSize;
|
||||
|
||||
origin = til::point{
|
||||
::base::ClampSub<long>(nearestMonitorInfo.rcWork.left, (nonClientSize.width() / 2)),
|
||||
::base::ClampSub(nearestMonitorInfo.rcWork.left, (nonClientSize.width / 2)),
|
||||
(nearestMonitorInfo.rcWork.top)
|
||||
};
|
||||
dimensions = til::size{
|
||||
availableSpace.width(),
|
||||
availableSpace.height() / 2
|
||||
availableSpace.width,
|
||||
availableSpace.height / 2
|
||||
};
|
||||
launchMode = LaunchMode::FocusMode;
|
||||
}
|
||||
@ -577,18 +577,18 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
|
||||
{
|
||||
// Move our proposed location into the center of that specific monitor.
|
||||
origin = til::point{
|
||||
(nearestMonitorInfo.rcWork.left + ((desktopDimensions.width() / 2) - (dimensions.width() / 2))),
|
||||
(nearestMonitorInfo.rcWork.top + ((desktopDimensions.height() / 2) - (dimensions.height() / 2)))
|
||||
(nearestMonitorInfo.rcWork.left + ((desktopDimensions.width / 2) - (dimensions.width / 2))),
|
||||
(nearestMonitorInfo.rcWork.top + ((desktopDimensions.height / 2) - (dimensions.height / 2)))
|
||||
};
|
||||
}
|
||||
|
||||
const til::rectangle newRect{ origin, dimensions };
|
||||
const til::rect newRect{ origin, dimensions };
|
||||
bool succeeded = SetWindowPos(hwnd,
|
||||
nullptr,
|
||||
newRect.left<int>(),
|
||||
newRect.top<int>(),
|
||||
newRect.width<int>(),
|
||||
newRect.height<int>(),
|
||||
newRect.left,
|
||||
newRect.top,
|
||||
newRect.width(),
|
||||
newRect.height(),
|
||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
|
||||
// Refresh the dpi of HWND because the dpi where the window will launch may be different
|
||||
@ -705,7 +705,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta)
|
||||
if (_logic)
|
||||
{
|
||||
// Find all the elements that are underneath the mouse
|
||||
auto elems = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::FindElementsInHostCoordinates(coord, _logic.GetRoot());
|
||||
auto elems = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::FindElementsInHostCoordinates(coord.to_winrt_point(), _logic.GetRoot());
|
||||
for (const auto& e : elems)
|
||||
{
|
||||
// If that element has implemented IMouseWheelListener, call OnMouseWheel on that element.
|
||||
@ -716,7 +716,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta)
|
||||
// Translate the event to the coordinate space of the control
|
||||
// we're attempting to dispatch it to
|
||||
const auto transform = e.TransformToVisual(nullptr);
|
||||
const til::point controlOrigin{ til::math::flooring, transform.TransformPoint(til::point{ 0, 0 }) };
|
||||
const til::point controlOrigin{ til::math::flooring, transform.TransformPoint({}) };
|
||||
|
||||
const til::point offsetPoint = coord - controlOrigin;
|
||||
|
||||
@ -724,7 +724,7 @@ void AppHost::_WindowMouseWheeled(const til::point coord, const int32_t delta)
|
||||
const auto mButtonDown = WI_IsFlagSet(GetKeyState(VK_MBUTTON), KeyPressed);
|
||||
const auto rButtonDown = WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed);
|
||||
|
||||
if (control.OnMouseWheel(offsetPoint, delta, lButtonDown, mButtonDown, rButtonDown))
|
||||
if (control.OnMouseWheel(offsetPoint.to_winrt_point(), delta, lButtonDown, mButtonDown, rButtonDown))
|
||||
{
|
||||
// If the element handled the mouse wheel event, don't
|
||||
// continue to iterate over the remaining controls.
|
||||
|
||||
@ -202,8 +202,7 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
|
||||
// bad parameters, which we won't have, so no big deal.
|
||||
LOG_IF_FAILED(GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy));
|
||||
|
||||
const auto widthScale = base::ClampedNumeric<float>(dpix) / USER_DEFAULT_SCREEN_DPI;
|
||||
const long minWidthScaled = minimumWidth * widthScale;
|
||||
const long minWidthScaled = minimumWidth * dpix / USER_DEFAULT_SCREEN_DPI;
|
||||
|
||||
const auto nonClientSize = GetTotalNonClientExclusiveSize(dpix);
|
||||
|
||||
@ -383,11 +382,10 @@ void IslandWindow::_OnGetMinMaxInfo(const WPARAM /*wParam*/, const LPARAM lParam
|
||||
|
||||
// From now we use dpix for all computations (same as in _OnSizing).
|
||||
const auto nonClientSizeScaled = GetTotalNonClientExclusiveSize(dpix);
|
||||
const auto scale = base::ClampedNumeric<float>(dpix) / USER_DEFAULT_SCREEN_DPI;
|
||||
|
||||
auto lpMinMaxInfo = reinterpret_cast<LPMINMAXINFO>(lParam);
|
||||
lpMinMaxInfo->ptMinTrackSize.x = _calculateTotalSize(true, minimumWidth * scale, nonClientSizeScaled.cx);
|
||||
lpMinMaxInfo->ptMinTrackSize.y = _calculateTotalSize(false, minimumHeight * scale, nonClientSizeScaled.cy);
|
||||
lpMinMaxInfo->ptMinTrackSize.x = _calculateTotalSize(true, minimumWidth * dpix / USER_DEFAULT_SCREEN_DPI, nonClientSizeScaled.cx);
|
||||
lpMinMaxInfo->ptMinTrackSize.y = _calculateTotalSize(false, minimumHeight * dpiy / USER_DEFAULT_SCREEN_DPI, nonClientSizeScaled.cy);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -521,11 +519,12 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
// and HIWORD treat the coordinates as unsigned quantities.
|
||||
const til::point eventPoint{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
|
||||
// This mouse event is relative to the display origin, not the window. Convert here.
|
||||
const til::rectangle windowRect{ GetWindowRect() };
|
||||
const til::rect windowRect{ GetWindowRect() };
|
||||
const auto origin = windowRect.origin();
|
||||
const auto relative = eventPoint - origin;
|
||||
// Convert to logical scaling before raising the event.
|
||||
const auto real = relative / GetCurrentDpiScale();
|
||||
const auto scale = GetCurrentDpiScale();
|
||||
const til::point real{ til::math::flooring, relative.x / scale, relative.y / scale };
|
||||
|
||||
const short wheelDelta = static_cast<short>(HIWORD(wparam));
|
||||
|
||||
@ -574,8 +573,8 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
GetMonitorInfo(proposed, &proposedInfo);
|
||||
|
||||
// If the monitor changed...
|
||||
if (til::rectangle{ proposedInfo.rcMonitor } !=
|
||||
til::rectangle{ currentInfo.rcMonitor })
|
||||
if (til::rect{ proposedInfo.rcMonitor } !=
|
||||
til::rect{ currentInfo.rcMonitor })
|
||||
{
|
||||
const auto newWindowRect{ _getQuakeModeSize(proposed) };
|
||||
|
||||
@ -583,10 +582,10 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
||||
// and dimensions that _getQuakeModeSize returned. When we
|
||||
// snap across monitor boundaries, this will re-evaluate our
|
||||
// size for the new monitor.
|
||||
lpwpos->x = newWindowRect.left<int>();
|
||||
lpwpos->y = newWindowRect.top<int>();
|
||||
lpwpos->cx = newWindowRect.width<int>();
|
||||
lpwpos->cy = newWindowRect.height<int>();
|
||||
lpwpos->x = newWindowRect.left;
|
||||
lpwpos->y = newWindowRect.top;
|
||||
lpwpos->cx = newWindowRect.width();
|
||||
lpwpos->cy = newWindowRect.height();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -973,14 +972,14 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled)
|
||||
|
||||
// Resize the window, with SWP_FRAMECHANGED, to trigger user32 to
|
||||
// recalculate the non/client areas
|
||||
const til::rectangle windowPos{ GetWindowRect() };
|
||||
const til::rect windowPos{ GetWindowRect() };
|
||||
|
||||
SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
windowPos.left<int>(),
|
||||
windowPos.top<int>(),
|
||||
windowPos.width<int>(),
|
||||
windowPos.height<int>(),
|
||||
windowPos.left,
|
||||
windowPos.top,
|
||||
windowPos.width(),
|
||||
windowPos.height(),
|
||||
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
@ -1048,8 +1047,8 @@ void IslandWindow::_RestoreFullscreenPosition(const RECT rcWork)
|
||||
// We want to make sure the window is restored within the bounds of the
|
||||
// monitor we're on, but it's totally fine if the invisible borders are
|
||||
// outside the monitor.
|
||||
const auto halfWidth{ ncSize.width<long>() / 2 };
|
||||
const auto halfHeight{ ncSize.height<long>() / 2 };
|
||||
const auto halfWidth{ ncSize.width / 2 };
|
||||
const auto halfHeight{ ncSize.height / 2 };
|
||||
|
||||
rcWorkAdjusted.left -= halfWidth;
|
||||
rcWorkAdjusted.right += halfWidth;
|
||||
@ -1254,8 +1253,8 @@ void IslandWindow::_summonWindowRoutineBody(Remoting::SummonWindowBehavior args)
|
||||
// mouse, then we should move to that monitor instead of dismissing.
|
||||
if (args.ToMonitor() == Remoting::MonitorBehavior::ToMouse)
|
||||
{
|
||||
const til::rectangle cursorMonitorRect{ _getMonitorForCursor().rcMonitor };
|
||||
const til::rectangle currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor };
|
||||
const til::rect cursorMonitorRect{ _getMonitorForCursor().rcMonitor };
|
||||
const til::rect currentMonitorRect{ _getMonitorForWindow(GetHandle()).rcMonitor };
|
||||
if (cursorMonitorRect != currentMonitorRect)
|
||||
{
|
||||
// We're not on the same monitor as the mouse. Go to that monitor.
|
||||
@ -1292,8 +1291,8 @@ void IslandWindow::_summonWindowRoutineBody(Remoting::SummonWindowBehavior args)
|
||||
// - <none>
|
||||
void IslandWindow::_doSlideAnimation(const uint32_t dropdownDuration, const bool down)
|
||||
{
|
||||
til::rectangle fullWindowSize{ GetWindowRect() };
|
||||
const double fullHeight = fullWindowSize.height<double>();
|
||||
til::rect fullWindowSize{ GetWindowRect() };
|
||||
const auto fullHeight = fullWindowSize.height();
|
||||
|
||||
const double animationDuration = dropdownDuration; // use floating-point math throughout
|
||||
const auto start = std::chrono::system_clock::now();
|
||||
@ -1312,15 +1311,11 @@ void IslandWindow::_doSlideAnimation(const uint32_t dropdownDuration, const bool
|
||||
}
|
||||
|
||||
// If going down, increase the height over time. If going up, decrease the height.
|
||||
const double currentHeight = ::base::saturated_cast<double>(
|
||||
const auto currentHeight = ::base::saturated_cast<int>(
|
||||
down ? ((dt / animationDuration) * fullHeight) :
|
||||
((1.0 - (dt / animationDuration)) * fullHeight));
|
||||
|
||||
wil::unique_hrgn rgn{ CreateRectRgn(0,
|
||||
0,
|
||||
fullWindowSize.width<int>(),
|
||||
::base::saturated_cast<int>(currentHeight)) };
|
||||
|
||||
wil::unique_hrgn rgn{ CreateRectRgn(0, 0, fullWindowSize.width(), currentHeight) };
|
||||
SetWindowRgn(_interopWindowHandle, rgn.get(), true);
|
||||
|
||||
// Go immediately into another frame. This prevents the window from
|
||||
@ -1562,20 +1557,20 @@ void IslandWindow::_moveToMonitor(const MONITORINFO activeMonitor)
|
||||
// Get the monitor info for the window's current monitor.
|
||||
const auto currentMonitor = _getMonitorForWindow(GetHandle());
|
||||
|
||||
const til::rectangle currentRect{ currentMonitor.rcMonitor };
|
||||
const til::rectangle activeRect{ activeMonitor.rcMonitor };
|
||||
const til::rect currentRect{ currentMonitor.rcMonitor };
|
||||
const til::rect activeRect{ activeMonitor.rcMonitor };
|
||||
if (currentRect != activeRect)
|
||||
{
|
||||
const til::rectangle currentWindowRect{ GetWindowRect() };
|
||||
const til::rect currentWindowRect{ GetWindowRect() };
|
||||
const til::point offset{ currentWindowRect.origin() - currentRect.origin() };
|
||||
const til::point newOrigin{ activeRect.origin() + offset };
|
||||
|
||||
SetWindowPos(GetHandle(),
|
||||
0,
|
||||
newOrigin.x<int>(),
|
||||
newOrigin.y<int>(),
|
||||
currentWindowRect.width<int>(),
|
||||
currentWindowRect.height<int>(),
|
||||
newOrigin.x,
|
||||
newOrigin.y,
|
||||
currentWindowRect.width(),
|
||||
currentWindowRect.height(),
|
||||
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
|
||||
// GH#10274, GH#10182: Re-evaluate the size of the quake window when we
|
||||
@ -1627,10 +1622,10 @@ void IslandWindow::_enterQuakeMode()
|
||||
|
||||
SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
newRect.left<int>(),
|
||||
newRect.top<int>(),
|
||||
newRect.width<int>(),
|
||||
newRect.height<int>(),
|
||||
newRect.left,
|
||||
newRect.top,
|
||||
newRect.width(),
|
||||
newRect.height(),
|
||||
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
@ -1642,7 +1637,7 @@ void IslandWindow::_enterQuakeMode()
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
til::rectangle IslandWindow::_getQuakeModeSize(HMONITOR hmon)
|
||||
til::rect IslandWindow::_getQuakeModeSize(HMONITOR hmon)
|
||||
{
|
||||
MONITORINFO nearestMonitorInfo;
|
||||
|
||||
@ -1667,15 +1662,15 @@ til::rectangle IslandWindow::_getQuakeModeSize(HMONITOR hmon)
|
||||
// smaller on either side to account for that, so they don't hang onto
|
||||
// adjacent monitors.
|
||||
const til::point origin{
|
||||
::base::ClampSub<long>(nearestMonitorInfo.rcWork.left, (ncSize.width() / 2)) + 1,
|
||||
::base::ClampSub(nearestMonitorInfo.rcWork.left, (ncSize.width / 2)) + 1,
|
||||
(nearestMonitorInfo.rcWork.top)
|
||||
};
|
||||
const til::size dimensions{
|
||||
availableSpace.width() - 2,
|
||||
availableSpace.height() / 2
|
||||
availableSpace.width - 2,
|
||||
availableSpace.height / 2
|
||||
};
|
||||
|
||||
return til::rectangle{ origin, dimensions };
|
||||
return til::rect{ origin, dimensions };
|
||||
}
|
||||
|
||||
void IslandWindow::HideWindow()
|
||||
|
||||
@ -134,7 +134,7 @@ protected:
|
||||
bool _isQuakeWindow{ false };
|
||||
|
||||
void _enterQuakeMode();
|
||||
til::rectangle _getQuakeModeSize(HMONITOR hmon);
|
||||
til::rect _getQuakeModeSize(HMONITOR hmon);
|
||||
|
||||
void _summonWindowRoutineBody(winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior args);
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ void NonClientIslandWindow::MakeWindow() noexcept
|
||||
THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow);
|
||||
}
|
||||
|
||||
LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer)
|
||||
LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point pointer)
|
||||
{
|
||||
RECT rcParent = GetWindowRect();
|
||||
// The size of the buttons doesn't change over the life of the application.
|
||||
@ -97,23 +97,23 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer)
|
||||
const auto buttonWidthInPixels{ buttonWidthInDips * GetCurrentDpiScale() };
|
||||
|
||||
// make sure to account for the width of the window frame!
|
||||
const til::rectangle nonClientFrame{ GetNonClientFrame(_currentDpi) };
|
||||
const auto rightBorder{ rcParent.right - nonClientFrame.right<int>() };
|
||||
const til::rect nonClientFrame{ GetNonClientFrame(_currentDpi) };
|
||||
const auto rightBorder{ rcParent.right - nonClientFrame.right };
|
||||
// From the right to the left,
|
||||
// * are we in the close button?
|
||||
// * the maximize button?
|
||||
// * the minimize button?
|
||||
// If we're not, then we're in either the top resize border, or just
|
||||
// generally in the titlebar.
|
||||
if ((rightBorder - pointer.x()) < (buttonWidthInPixels))
|
||||
if ((rightBorder - pointer.x) < (buttonWidthInPixels))
|
||||
{
|
||||
return HTCLOSE;
|
||||
}
|
||||
else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 2))
|
||||
else if ((rightBorder - pointer.x) < (buttonWidthInPixels * 2))
|
||||
{
|
||||
return HTMAXBUTTON;
|
||||
}
|
||||
else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 3))
|
||||
else if ((rightBorder - pointer.x) < (buttonWidthInPixels * 3))
|
||||
{
|
||||
return HTMINBUTTON;
|
||||
}
|
||||
@ -123,7 +123,7 @@ LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer)
|
||||
// border. If we're not on the top border, then we're just generally in
|
||||
// the caption area.
|
||||
const auto resizeBorderHeight = _GetResizeHandleHeight();
|
||||
const auto isOnResizeBorder = pointer.y() < rcParent.top + resizeBorderHeight;
|
||||
const auto isOnResizeBorder = pointer.y < rcParent.top + resizeBorderHeight;
|
||||
|
||||
return isOnResizeBorder ? HTTOP : HTCAPTION;
|
||||
}
|
||||
@ -294,15 +294,15 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message,
|
||||
// This window is used to capture clicks on the non-client area.
|
||||
void NonClientIslandWindow::_ResizeDragBarWindow() noexcept
|
||||
{
|
||||
const til::rectangle rect{ _GetDragAreaRect() };
|
||||
const til::rect rect{ _GetDragAreaRect() };
|
||||
if (_IsTitlebarVisible() && rect.size().area() > 0)
|
||||
{
|
||||
SetWindowPos(_dragBarWindow.get(),
|
||||
HWND_TOP,
|
||||
rect.left<int>(),
|
||||
rect.top<int>() + _GetTopBorderHeight(),
|
||||
rect.width<int>(),
|
||||
rect.height<int>(),
|
||||
rect.left,
|
||||
rect.top + _GetTopBorderHeight(),
|
||||
rect.width(),
|
||||
rect.height(),
|
||||
SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||
SetLayeredWindowAttributes(_dragBarWindow.get(), 0, 255, LWA_ALPHA);
|
||||
}
|
||||
@ -1087,13 +1087,13 @@ void NonClientIslandWindow::_SetIsBorderless(const bool borderlessEnabled)
|
||||
|
||||
// Resize the window, with SWP_FRAMECHANGED, to trigger user32 to
|
||||
// recalculate the non/client areas
|
||||
const til::rectangle windowPos{ GetWindowRect() };
|
||||
const til::rect windowPos{ GetWindowRect() };
|
||||
SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
windowPos.left<int>(),
|
||||
windowPos.top<int>(),
|
||||
windowPos.width<int>(),
|
||||
windowPos.height<int>(),
|
||||
windowPos.left,
|
||||
windowPos.top,
|
||||
windowPos.width(),
|
||||
windowPos.height(),
|
||||
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ private:
|
||||
int _GetResizeHandleHeight() const noexcept;
|
||||
RECT _GetDragAreaRect() const noexcept;
|
||||
int _GetTopBorderHeight() const noexcept;
|
||||
LRESULT _dragBarNcHitTest(const til::point& pointer);
|
||||
LRESULT _dragBarNcHitTest(const til::point pointer);
|
||||
|
||||
[[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;
|
||||
[[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||
|
||||
@ -109,7 +109,7 @@ void NotificationIcon::CreateNotificationIcon()
|
||||
// - peasants: The map of all peasants that should be available in the context menu.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void NotificationIcon::ShowContextMenu(const til::point& coord,
|
||||
void NotificationIcon::ShowContextMenu(const til::point coord,
|
||||
const IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo>& peasants)
|
||||
{
|
||||
if (const auto hMenu = _CreateContextMenu(peasants))
|
||||
@ -132,7 +132,7 @@ void NotificationIcon::ShowContextMenu(const til::point& coord,
|
||||
uFlags |= TPM_LEFTALIGN;
|
||||
}
|
||||
|
||||
TrackPopupMenuEx(hMenu, uFlags, gsl::narrow_cast<int>(coord.x()), gsl::narrow_cast<int>(coord.y()), _owningHwnd, NULL);
|
||||
TrackPopupMenuEx(hMenu, uFlags, coord.x, coord.y, _owningHwnd, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ public:
|
||||
void ReAddNotificationIcon();
|
||||
|
||||
void NotificationIconPressed();
|
||||
void ShowContextMenu(const til::point& coord, const winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo>& peasants);
|
||||
void ShowContextMenu(const til::point coord, const winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo>& peasants);
|
||||
void MenuItemSelected(const HMENU menu, const UINT menuItemIndex);
|
||||
|
||||
WINRT_CALLBACK(SummonWindowRequested, winrt::delegate<void(winrt::Microsoft::Terminal::Remoting::SummonWindowSelectionArgs)>);
|
||||
|
||||
@ -24,6 +24,8 @@ Revision History:
|
||||
#include "../server/IWaitRoutine.h"
|
||||
#include "../server/WaitTerminationReason.h"
|
||||
|
||||
class InputBuffer;
|
||||
|
||||
class ReadData : public IWaitRoutine
|
||||
{
|
||||
public:
|
||||
|
||||
@ -2196,7 +2196,7 @@ void TextBufferTests::MoveByWord()
|
||||
Log::Comment(NoThrowString().Format(L"COORD (%hd, %hd)", test.startPos.X, test.startPos.Y));
|
||||
auto pos{ test.startPos };
|
||||
const auto result = movingForwards ?
|
||||
_buffer->MoveToNextWord(pos, delimiters, lastCharPos) :
|
||||
_buffer->MoveToNextWord(pos, delimiters, til::point{ lastCharPos }) :
|
||||
_buffer->MoveToPreviousWord(pos, delimiters);
|
||||
const auto expected = movingForwards ? test.expected.moveForwards : test.expected.moveBackwards;
|
||||
VERIFY_ARE_EQUAL(expected, pos);
|
||||
@ -2250,7 +2250,7 @@ void TextBufferTests::GetGlyphBoundaries()
|
||||
{
|
||||
Log::Comment(test.name.c_str());
|
||||
auto target = test.start;
|
||||
_buffer->Write(iter, target);
|
||||
_buffer->Write(iter, target.to_win32_coord());
|
||||
|
||||
auto start = _buffer->GetGlyphStart(target);
|
||||
auto end = _buffer->GetGlyphEnd(target, true);
|
||||
|
||||
@ -234,7 +234,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
VERIFY_SUCCEEDED(engine->Invalidate(&invalid));
|
||||
TestPaint(*engine, [&]() {
|
||||
VERIFY_IS_TRUE(engine->_invalidMap.one());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin()));
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin()));
|
||||
});
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
@ -249,7 +249,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
|
||||
const auto runs = engine->_invalidMap.runs();
|
||||
VERIFY_ARE_EQUAL(1u, runs.size());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
qExpectedInput.push_back("\x1b[H"); // Go Home
|
||||
qExpectedInput.push_back("\x1b[L"); // insert a line
|
||||
|
||||
@ -275,7 +275,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
// We would expect a CUP here, but the cursor is already at the home position
|
||||
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
||||
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
||||
@ -291,7 +291,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
|
||||
const auto runs = engine->_invalidMap.runs();
|
||||
VERIFY_ARE_EQUAL(1u, runs.size());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
|
||||
qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer
|
||||
qExpectedInput.push_back("\n"); // Scroll down once
|
||||
@ -316,7 +316,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
|
||||
// We would expect a CUP here, but we're already at the bottom from the last call.
|
||||
qExpectedInput.push_back("\n\n\n"); // Scroll down three times
|
||||
@ -346,7 +346,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
|
||||
qExpectedInput.push_back("\x1b[H"); // Go to home
|
||||
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
||||
@ -386,7 +386,7 @@ void VtRendererTest::Xterm256TestInvalidate()
|
||||
// 0000
|
||||
// 0000
|
||||
// 1111
|
||||
const til::rectangle expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } };
|
||||
const til::rect expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } };
|
||||
VERIFY_ARE_EQUAL(expected, invalidRect);
|
||||
|
||||
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
||||
@ -912,7 +912,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
VERIFY_SUCCEEDED(engine->Invalidate(&invalid));
|
||||
TestPaint(*engine, [&]() {
|
||||
VERIFY_IS_TRUE(engine->_invalidMap.one());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin()));
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, *(engine->_invalidMap.begin()));
|
||||
});
|
||||
|
||||
Log::Comment(NoThrowString().Format(
|
||||
@ -927,7 +927,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
|
||||
const auto runs = engine->_invalidMap.runs();
|
||||
VERIFY_ARE_EQUAL(1u, runs.size());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
|
||||
qExpectedInput.push_back("\x1b[H"); // Go Home
|
||||
qExpectedInput.push_back("\x1b[L"); // insert a line
|
||||
@ -952,7 +952,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
// We would expect a CUP here, but the cursor is already at the home position
|
||||
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
||||
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
||||
@ -968,7 +968,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
|
||||
const auto runs = engine->_invalidMap.runs();
|
||||
VERIFY_ARE_EQUAL(1u, runs.size());
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, runs.front());
|
||||
|
||||
qExpectedInput.push_back("\x1b[32;1H"); // Bottom of buffer
|
||||
qExpectedInput.push_back("\n"); // Scroll down once
|
||||
@ -993,7 +993,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
|
||||
// We would expect a CUP here, but we're already at the bottom from the last call.
|
||||
qExpectedInput.push_back("\n\n\n"); // Scroll down three times
|
||||
@ -1023,7 +1023,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
}
|
||||
|
||||
// verify the rect matches the invalid one.
|
||||
VERIFY_ARE_EQUAL(til::rectangle{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
VERIFY_ARE_EQUAL(til::rect{ Viewport::FromExclusive(invalid).ToInclusive() }, invalidRect);
|
||||
|
||||
qExpectedInput.push_back("\x1b[H"); // Go to home
|
||||
qExpectedInput.push_back("\x1b[3L"); // insert 3 lines
|
||||
@ -1063,7 +1063,7 @@ void VtRendererTest::XtermTestInvalidate()
|
||||
// 0000
|
||||
// 0000
|
||||
// 1111
|
||||
const til::rectangle expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } };
|
||||
const til::rect expected{ til::point{ view.Left(), view.BottomInclusive() }, til::size{ view.Width(), 1 } };
|
||||
VERIFY_ARE_EQUAL(expected, invalidRect);
|
||||
|
||||
VERIFY_SUCCEEDED(engine->ScrollFrame());
|
||||
|
||||
@ -242,66 +242,14 @@ namespace WEX::TestExecution
|
||||
public:
|
||||
static bool AreEqual(const CONSOLE_SCREEN_BUFFER_INFOEX& expected, const CONSOLE_SCREEN_BUFFER_INFOEX& actual)
|
||||
{
|
||||
return expected.bFullscreenSupported == actual.bFullscreenSupported &&
|
||||
expected.wAttributes == actual.wAttributes &&
|
||||
expected.wPopupAttributes == actual.wPopupAttributes &&
|
||||
VerifyCompareTraits<COORD>::AreEqual(expected.dwCursorPosition, actual.dwCursorPosition) &&
|
||||
VerifyCompareTraits<COORD>::AreEqual(expected.dwSize, actual.dwSize) &&
|
||||
VerifyCompareTraits<COORD>::AreEqual(expected.dwMaximumWindowSize, actual.dwMaximumWindowSize) &&
|
||||
VerifyCompareTraits<SMALL_RECT>::AreEqual(expected.srWindow, actual.srWindow) &&
|
||||
expected.ColorTable[0] == actual.ColorTable[0] &&
|
||||
expected.ColorTable[1] == actual.ColorTable[1] &&
|
||||
expected.ColorTable[2] == actual.ColorTable[2] &&
|
||||
expected.ColorTable[3] == actual.ColorTable[3] &&
|
||||
expected.ColorTable[4] == actual.ColorTable[4] &&
|
||||
expected.ColorTable[5] == actual.ColorTable[5] &&
|
||||
expected.ColorTable[6] == actual.ColorTable[6] &&
|
||||
expected.ColorTable[7] == actual.ColorTable[7] &&
|
||||
expected.ColorTable[8] == actual.ColorTable[8] &&
|
||||
expected.ColorTable[9] == actual.ColorTable[9] &&
|
||||
expected.ColorTable[10] == actual.ColorTable[10] &&
|
||||
expected.ColorTable[11] == actual.ColorTable[11] &&
|
||||
expected.ColorTable[12] == actual.ColorTable[12] &&
|
||||
expected.ColorTable[13] == actual.ColorTable[13] &&
|
||||
expected.ColorTable[14] == actual.ColorTable[14] &&
|
||||
expected.ColorTable[15] == actual.ColorTable[15];
|
||||
static_assert(std::has_unique_object_representations_v<CONSOLE_SCREEN_BUFFER_INFOEX>);
|
||||
return memcmp(&expected, &actual, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX)) == 0;
|
||||
}
|
||||
|
||||
static bool AreSame(const CONSOLE_SCREEN_BUFFER_INFOEX& expected, const CONSOLE_SCREEN_BUFFER_INFOEX& actual)
|
||||
{
|
||||
return &expected == &actual;
|
||||
}
|
||||
|
||||
static bool IsLessThan(const CONSOLE_SCREEN_BUFFER_INFOEX& expectedLess, const CONSOLE_SCREEN_BUFFER_INFOEX& expectedGreater) = delete;
|
||||
|
||||
static bool IsGreaterThan(const CONSOLE_SCREEN_BUFFER_INFOEX& expectedGreater, const CONSOLE_SCREEN_BUFFER_INFOEX& expectedLess) = delete;
|
||||
|
||||
static bool IsNull(const CONSOLE_SCREEN_BUFFER_INFOEX& object)
|
||||
{
|
||||
return object.bFullscreenSupported == 0 &&
|
||||
object.wAttributes == 0 &&
|
||||
object.wPopupAttributes == 0 &&
|
||||
VerifyCompareTraits<COORD>::IsNull(object.dwCursorPosition) &&
|
||||
VerifyCompareTraits<COORD>::IsNull(object.dwSize) &&
|
||||
VerifyCompareTraits<COORD>::IsNull(object.dwMaximumWindowSize) &&
|
||||
VerifyCompareTraits<SMALL_RECT>::IsNull(object.srWindow) &&
|
||||
object.ColorTable[0] == 0x0 &&
|
||||
object.ColorTable[1] == 0x0 &&
|
||||
object.ColorTable[2] == 0x0 &&
|
||||
object.ColorTable[3] == 0x0 &&
|
||||
object.ColorTable[4] == 0x0 &&
|
||||
object.ColorTable[5] == 0x0 &&
|
||||
object.ColorTable[6] == 0x0 &&
|
||||
object.ColorTable[7] == 0x0 &&
|
||||
object.ColorTable[8] == 0x0 &&
|
||||
object.ColorTable[9] == 0x0 &&
|
||||
object.ColorTable[10] == 0x0 &&
|
||||
object.ColorTable[11] == 0x0 &&
|
||||
object.ColorTable[12] == 0x0 &&
|
||||
object.ColorTable[13] == 0x0 &&
|
||||
object.ColorTable[14] == 0x0 &&
|
||||
object.ColorTable[15] == 0x0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@ -6,22 +6,15 @@
|
||||
#define _TIL_INLINEPREFIX __declspec(noinline) inline
|
||||
|
||||
#include "til/at.h"
|
||||
#include "til/color.h"
|
||||
#include "til/math.h"
|
||||
#include "til/some.h"
|
||||
#include "til/size.h"
|
||||
#include "til/point.h"
|
||||
#include "til/operators.h"
|
||||
#include "til/rectangle.h"
|
||||
#include "til/rle.h"
|
||||
#include "til/bitmap.h"
|
||||
#include "til/u8u16convert.h"
|
||||
#include "til/spsc.h"
|
||||
#include "til/coalesce.h"
|
||||
#include "til/replace.h"
|
||||
#include "til/string.h"
|
||||
#include "til/pmr.h"
|
||||
#include "til/color.h"
|
||||
#include "til/enumset.h"
|
||||
#include "til/pmr.h"
|
||||
#include "til/replace.h"
|
||||
#include "til/rle.h"
|
||||
#include "til/string.h"
|
||||
#include "til/u8u16convert.h"
|
||||
|
||||
// Use keywords on TraceLogging providers to specify the category
|
||||
// of event that we are emitting for filtering purposes.
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rect.h"
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
class BitmapTests;
|
||||
#endif
|
||||
@ -15,13 +17,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
class _bitmap_const_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = typename std::input_iterator_tag;
|
||||
using value_type = typename const til::rectangle;
|
||||
using difference_type = typename ptrdiff_t;
|
||||
using pointer = typename const til::rectangle*;
|
||||
using reference = typename const til::rectangle&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = const til::rect;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = const til::rect*;
|
||||
using reference = const til::rect&;
|
||||
|
||||
_bitmap_const_iterator(const dynamic_bitset<unsigned long long, Allocator>& values, til::rectangle rc, ptrdiff_t pos) :
|
||||
_bitmap_const_iterator(const dynamic_bitset<unsigned long long, Allocator>& values, til::rect rc, ptrdiff_t pos) :
|
||||
_values(values),
|
||||
_rc(rc),
|
||||
_pos(pos),
|
||||
@ -76,11 +78,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
|
||||
private:
|
||||
const dynamic_bitset<unsigned long long, Allocator>& _values;
|
||||
const til::rectangle _rc;
|
||||
ptrdiff_t _pos;
|
||||
ptrdiff_t _nextPos;
|
||||
const ptrdiff_t _end;
|
||||
til::rectangle _run;
|
||||
const til::rect _rc;
|
||||
size_t _pos;
|
||||
size_t _nextPos;
|
||||
const size_t _end;
|
||||
til::rect _run;
|
||||
|
||||
// Update _run to contain the next rectangle of consecutively set bits within this bitmap.
|
||||
// _calculateArea may be called repeatedly to yield all those rectangles.
|
||||
@ -92,23 +94,22 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
// dynamic_bitset allows you to quickly find the next set bit using find_next(prev),
|
||||
// where "prev" is the position _past_ which should be searched (i.e. excluding position "prev").
|
||||
// If _pos is still 0, we thus need to use the counterpart find_first().
|
||||
const auto nextPos = _pos == 0 ? _values.find_first() : _values.find_next(_pos - 1);
|
||||
// If no next set bit can be found, npos is returned, which is SIZE_T_MAX.
|
||||
// saturated_cast can ensure that this will be converted to PTRDIFF_T_MAX (which is greater than _end).
|
||||
_nextPos = base::saturated_cast<ptrdiff_t>(nextPos);
|
||||
_nextPos = _pos == 0 ? _values.find_first() : _values.find_next(_pos - 1);
|
||||
|
||||
// If we haven't reached the end yet...
|
||||
if (_nextPos < _end)
|
||||
{
|
||||
// pos is now at the first on bit.
|
||||
const auto runStart = _rc.point_at(_nextPos);
|
||||
// If no next set bit can be found, npos is returned, which is SIZE_T_MAX.
|
||||
// saturated_cast can ensure that this will be converted to CoordType's max (which is greater than _end).
|
||||
const auto runStart = _rc.point_at(base::saturated_cast<CoordType>(_nextPos));
|
||||
|
||||
// We'll only count up until the end of this row.
|
||||
// a run can be a max of one row tall.
|
||||
const ptrdiff_t rowEndIndex = _rc.index_of(til::point(_rc.right() - 1, runStart.y())) + 1;
|
||||
const size_t rowEndIndex = _rc.index_of<size_t>(til::point(_rc.right - 1, runStart.y)) + 1;
|
||||
|
||||
// Find the length for the rectangle.
|
||||
ptrdiff_t runLength = 0;
|
||||
size_t runLength = 0;
|
||||
|
||||
// We have at least 1 so start with a do/while.
|
||||
do
|
||||
@ -119,7 +120,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
// Keep going until we reach end of row, end of the buffer, or the next bit is off.
|
||||
|
||||
// Assemble and store that run.
|
||||
_run = til::rectangle{ runStart, til::size{ runLength, static_cast<ptrdiff_t>(1) } };
|
||||
_run = til::rect{ runStart, til::size{ base::saturated_cast<CoordType>(runLength), 1 } };
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -127,7 +128,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
// ---> Mark the end of the iterator by updating the state with _end.
|
||||
_pos = _end;
|
||||
_nextPos = _end;
|
||||
_run = til::rectangle{};
|
||||
_run = til::rect{};
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -140,7 +141,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
using const_iterator = details::_bitmap_const_iterator<allocator_type>;
|
||||
|
||||
private:
|
||||
using run_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<til::rectangle>;
|
||||
using run_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<til::rect>;
|
||||
|
||||
public:
|
||||
explicit bitmap(const allocator_type& allocator) noexcept :
|
||||
@ -255,15 +256,15 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return const_iterator(_bits, _sz, 0);
|
||||
return const_iterator(_bits, til::rect{ _sz }, 0);
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return const_iterator(_bits, _sz, _sz.area());
|
||||
return const_iterator(_bits, til::rect{ _sz }, _sz.area());
|
||||
}
|
||||
|
||||
const gsl::span<const til::rectangle> runs() const
|
||||
const gsl::span<const til::rect> runs() const
|
||||
{
|
||||
// If we don't have cached runs, rebuild.
|
||||
if (!_runs.has_value())
|
||||
@ -278,10 +279,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
// optional fill the uncovered area with bits.
|
||||
void translate(const til::point delta, bool fill = false)
|
||||
{
|
||||
if (delta.x() == 0)
|
||||
if (delta.x == 0)
|
||||
{
|
||||
// fast path by using bit shifting
|
||||
translate_y(delta.y(), fill);
|
||||
translate_y(delta.y, fill);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -356,14 +357,14 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
_bits.set(_rc.index_of(pt));
|
||||
}
|
||||
|
||||
void set(const til::rectangle rc)
|
||||
void set(const til::rect& rc)
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, !_rc.contains(rc));
|
||||
_runs.reset(); // reset cached runs on any non-const method
|
||||
|
||||
for (auto row = rc.top(); row < rc.bottom(); ++row)
|
||||
for (auto row = rc.top; row < rc.bottom; ++row)
|
||||
{
|
||||
_bits.set(_rc.index_of(til::point{ rc.left(), row }), rc.width(), true);
|
||||
_bits.set(_rc.index_of(til::point{ rc.left, row }), rc.width(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,7 +481,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
return;
|
||||
}
|
||||
|
||||
const auto bitShift = delta_y * _sz.width();
|
||||
const auto bitShift = delta_y * _sz.width;
|
||||
|
||||
#pragma warning(push)
|
||||
// we can't depend on GSL here, so we use static_cast for explicit narrowing
|
||||
@ -530,10 +531,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
|
||||
allocator_type _alloc;
|
||||
til::size _sz;
|
||||
til::rectangle _rc;
|
||||
til::rect _rc;
|
||||
dynamic_bitset<unsigned long long, allocator_type> _bits;
|
||||
|
||||
mutable std::optional<std::vector<til::rectangle, run_allocator_type>> _runs;
|
||||
mutable std::optional<std::vector<til::rect, run_allocator_type>> _runs;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::BitmapTests;
|
||||
|
||||
@ -12,19 +12,30 @@ namespace til
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
// Just like gsl::narrow, but also checks for NAN.
|
||||
template<typename O, typename T>
|
||||
constexpr O narrow_float(T val)
|
||||
{
|
||||
const auto o = gsl::narrow_cast<O>(val);
|
||||
if (std::isnan(val) || static_cast<T>(o) != val)
|
||||
{
|
||||
throw gsl::narrowing_error{};
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
struct ceiling_t
|
||||
{
|
||||
template<typename O, typename T>
|
||||
static O cast(T val)
|
||||
static constexpr O cast(T val)
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, ::std::isnan(val));
|
||||
return ::base::saturated_cast<O>(::std::ceil(val));
|
||||
return narrow_float<O, T>(std::ceil(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::base::saturated_cast<O>(val);
|
||||
return gsl::narrow<O>(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -32,16 +43,15 @@ namespace til
|
||||
struct flooring_t
|
||||
{
|
||||
template<typename O, typename T>
|
||||
static O cast(T val)
|
||||
static constexpr O cast(T val)
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, ::std::isnan(val));
|
||||
return ::base::saturated_cast<O>(::std::floor(val));
|
||||
return narrow_float<O, T>(std::floor(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::base::saturated_cast<O>(val);
|
||||
return gsl::narrow<O>(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -49,37 +59,22 @@ namespace til
|
||||
struct rounding_t
|
||||
{
|
||||
template<typename O, typename T>
|
||||
static O cast(T val)
|
||||
static constexpr O cast(T val)
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, ::std::isnan(val));
|
||||
return ::base::saturated_cast<O>(::std::round(val));
|
||||
return narrow_float<O, T>(std::round(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::base::saturated_cast<O>(val);
|
||||
return gsl::narrow<O>(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct truncating_t
|
||||
{
|
||||
template<typename O, typename T>
|
||||
static O cast(T val)
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, ::std::isnan(val));
|
||||
}
|
||||
return ::base::saturated_cast<O>(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr details::ceiling_t ceiling; // positives become more positive, negatives become less negative
|
||||
static constexpr details::flooring_t flooring; // positives become less positive, negatives become more negative
|
||||
static constexpr details::rounding_t rounding; // it's rounding, from math class
|
||||
static constexpr details::truncating_t truncating; // drop the decimal point, regardless of how close it is to the next value
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,47 +9,47 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
|
||||
#pragma region POINT VS SIZE
|
||||
// This is a convenience and will take X vs WIDTH and Y vs HEIGHT.
|
||||
_TIL_INLINEPREFIX point operator+(const point& lhs, const size& rhs)
|
||||
constexpr point operator+(const point lhs, const size rhs)
|
||||
{
|
||||
return lhs + til::point{ rhs.width(), rhs.height() };
|
||||
return lhs + til::point{ rhs.width, rhs.height };
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX point operator-(const point& lhs, const size& rhs)
|
||||
constexpr point operator-(const point lhs, const size rhs)
|
||||
{
|
||||
return lhs - til::point{ rhs.width(), rhs.height() };
|
||||
return lhs - til::point{ rhs.width, rhs.height };
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX point operator*(const point& lhs, const size& rhs)
|
||||
constexpr point operator*(const point lhs, const size rhs)
|
||||
{
|
||||
return lhs * til::point{ rhs.width(), rhs.height() };
|
||||
return lhs * til::point{ rhs.width, rhs.height };
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX point operator/(const point& lhs, const size& rhs)
|
||||
constexpr point operator/(const point lhs, const size rhs)
|
||||
{
|
||||
return lhs / til::point{ rhs.width(), rhs.height() };
|
||||
return lhs / til::point{ rhs.width, rhs.height };
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region SIZE VS POINT
|
||||
// This is a convenience and will take WIDTH vs X and HEIGHT vs Y.
|
||||
_TIL_INLINEPREFIX size operator+(const size& lhs, const point& rhs)
|
||||
constexpr size operator+(const size lhs, const point rhs)
|
||||
{
|
||||
return lhs + til::size(rhs.x(), rhs.y());
|
||||
return lhs + til::size(rhs.x, rhs.y);
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX size operator-(const size& lhs, const point& rhs)
|
||||
constexpr size operator-(const size lhs, const point rhs)
|
||||
{
|
||||
return lhs - til::size(rhs.x(), rhs.y());
|
||||
return lhs - til::size(rhs.x, rhs.y);
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX size operator*(const size& lhs, const point& rhs)
|
||||
constexpr size operator*(const size lhs, const point rhs)
|
||||
{
|
||||
return lhs * til::size(rhs.x(), rhs.y());
|
||||
return lhs * til::size(rhs.x, rhs.y);
|
||||
}
|
||||
|
||||
_TIL_INLINEPREFIX size operator/(const size& lhs, const point& rhs)
|
||||
constexpr size operator/(const size lhs, const point rhs)
|
||||
{
|
||||
return lhs / til::size(rhs.x(), rhs.y());
|
||||
return lhs / til::size(rhs.x, rhs.y);
|
||||
}
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
@ -3,368 +3,231 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
class PointTests;
|
||||
#endif
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
class point
|
||||
using CoordType = int32_t;
|
||||
|
||||
namespace details
|
||||
{
|
||||
public:
|
||||
constexpr point() noexcept :
|
||||
point(0, 0)
|
||||
template<typename T, typename U = T>
|
||||
constexpr U extract(const ::base::CheckedNumeric<T>& num)
|
||||
{
|
||||
U val;
|
||||
if (!num.AssignIfValid(&val))
|
||||
{
|
||||
throw gsl::narrowing_error{};
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// On 64-bit processors, int and ptrdiff_t are different fundamental types.
|
||||
// On 32-bit processors, they're the same which makes this a double-definition
|
||||
// with the `ptrdiff_t` one below.
|
||||
#if defined(_M_AMD64) || defined(_M_ARM64)
|
||||
constexpr point(int x, int y) noexcept :
|
||||
point(static_cast<ptrdiff_t>(x), static_cast<ptrdiff_t>(y))
|
||||
{
|
||||
}
|
||||
constexpr point(ptrdiff_t width, int height) noexcept :
|
||||
point(width, static_cast<ptrdiff_t>(height))
|
||||
{
|
||||
}
|
||||
constexpr point(int width, ptrdiff_t height) noexcept :
|
||||
point(static_cast<ptrdiff_t>(width), height)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
struct point
|
||||
{
|
||||
CoordType x = 0;
|
||||
CoordType y = 0;
|
||||
|
||||
point(size_t x, size_t y)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y));
|
||||
}
|
||||
point(long x, long y)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y));
|
||||
}
|
||||
constexpr point() noexcept = default;
|
||||
|
||||
constexpr point(ptrdiff_t x, ptrdiff_t y) noexcept :
|
||||
_x(x),
|
||||
_y(y)
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr point(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().X)> && std::is_integral_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
||||
point(static_cast<ptrdiff_t>(other.X), static_cast<ptrdiff_t>(other.Y))
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a x and a y field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr point(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().x)> && std::is_integral_v<decltype(std::declval<TOther>().y)>, int> /*sentinel*/ = 0) :
|
||||
point(static_cast<ptrdiff_t>(other.x), static_cast<ptrdiff_t>(other.y))
|
||||
constexpr point(CoordType x, CoordType y) noexcept :
|
||||
x{ x }, y{ y }
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to point from floating-point args;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::point"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr point(TilMath, const TOther& x, const TOther& y, std::enable_if_t<std::is_floating_point_v<TOther>, int> /*sentinel*/ = 0) :
|
||||
point(TilMath::template cast<ptrdiff_t>(x), TilMath::template cast<ptrdiff_t>(y))
|
||||
template<typename TilMath, typename T>
|
||||
constexpr point(TilMath, const T x, const T y) :
|
||||
x{ TilMath::template cast<CoordType>(x) }, y{ TilMath::template cast<CoordType>(y) }
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a X and a Y field that are floating-point;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::point"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr point(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().X)> && std::is_floating_point_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
||||
point(TilMath::template cast<ptrdiff_t>(other.X), TilMath::template cast<ptrdiff_t>(other.Y))
|
||||
constexpr bool operator==(const point rhs) const noexcept
|
||||
{
|
||||
// `__builtin_memcmp` isn't an official standard, but it's the
|
||||
// only way at the time of writing to get a constexpr `memcmp`.
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0;
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a x and a y field that are floating-point;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::point"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr point(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().x)> && std::is_floating_point_v<decltype(std::declval<TOther>().y)>, int> /*sentinel*/ = 0) :
|
||||
point(TilMath::template cast<ptrdiff_t>(other.x), TilMath::template cast<ptrdiff_t>(other.y))
|
||||
constexpr bool operator!=(const point rhs) const noexcept
|
||||
{
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const point& other) const noexcept
|
||||
constexpr bool operator<(const point other) const noexcept
|
||||
{
|
||||
return _x == other._x &&
|
||||
_y == other._y;
|
||||
return y < other.y || (y == other.y && x < other.x);
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const point& other) const noexcept
|
||||
constexpr bool operator<=(const point other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
return y < other.y || (y == other.y && x <= other.x);
|
||||
}
|
||||
|
||||
constexpr bool operator<(const point& other) const noexcept
|
||||
constexpr bool operator>(const point other) const noexcept
|
||||
{
|
||||
if (_y < other._y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_y > other._y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _x < other._x;
|
||||
}
|
||||
return y > other.y || (y == other.y && x > other.x);
|
||||
}
|
||||
|
||||
constexpr bool operator>(const point& other) const noexcept
|
||||
constexpr bool operator>=(const point other) const noexcept
|
||||
{
|
||||
if (_y > other._y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_y < other._y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _x > other._x;
|
||||
}
|
||||
return y > other.y || (y == other.y && x >= other.x);
|
||||
}
|
||||
|
||||
constexpr bool operator<=(const point& other) const noexcept
|
||||
constexpr point operator+(const point other) const
|
||||
{
|
||||
if (_y < other._y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_y > other._y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _x <= other._x;
|
||||
}
|
||||
return point{
|
||||
details::extract(::base::CheckAdd(x, other.x)),
|
||||
details::extract(::base::CheckAdd(y, other.y)),
|
||||
};
|
||||
}
|
||||
|
||||
constexpr bool operator>=(const point& other) const noexcept
|
||||
{
|
||||
if (_y > other._y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_y < other._y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _x >= other._x;
|
||||
}
|
||||
}
|
||||
|
||||
point operator+(const point& other) const
|
||||
{
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(_x, other._x).AssignIfValid(&x));
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(_y, other._y).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
}
|
||||
|
||||
point& operator+=(const point& other)
|
||||
constexpr point& operator+=(const point other)
|
||||
{
|
||||
*this = *this + other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
point operator-(const point& other) const
|
||||
constexpr point operator-(const point other) const
|
||||
{
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(_x, other._x).AssignIfValid(&x));
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(_y, other._y).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
return point{
|
||||
details::extract(::base::CheckSub(x, other.x)),
|
||||
details::extract(::base::CheckSub(y, other.y)),
|
||||
};
|
||||
}
|
||||
|
||||
point& operator-=(const point& other)
|
||||
constexpr point& operator-=(const point other)
|
||||
{
|
||||
*this = *this - other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
point operator*(const point& other) const
|
||||
constexpr point operator*(const point other) const
|
||||
{
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_x, other._x).AssignIfValid(&x));
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_y, other._y).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
return point{
|
||||
details::extract(::base::CheckMul(x, other.x)),
|
||||
details::extract(::base::CheckMul(y, other.y)),
|
||||
};
|
||||
}
|
||||
|
||||
point& operator*=(const point& other)
|
||||
constexpr point& operator*=(const point other)
|
||||
{
|
||||
*this = *this * other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename TilMath>
|
||||
point scale(TilMath, const float scale) const
|
||||
constexpr point operator/(const point other) const
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x, y;
|
||||
} pt;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _x).AssignIfValid(&pt.x));
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _y).AssignIfValid(&pt.y));
|
||||
|
||||
return til::point(TilMath(), pt);
|
||||
return point{
|
||||
details::extract(::base::CheckDiv(x, other.x)),
|
||||
details::extract(::base::CheckDiv(y, other.y)),
|
||||
};
|
||||
}
|
||||
|
||||
point operator/(const point& other) const
|
||||
{
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_x, other._x).AssignIfValid(&x));
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, other._y).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
}
|
||||
|
||||
point& operator/=(const point& other)
|
||||
constexpr point& operator/=(const point other)
|
||||
{
|
||||
*this = *this / other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
point operator*(const T& scale) const
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
constexpr point operator*(const T scale) const
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "Type must be arithmetic");
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_x, scale).AssignIfValid(&x));
|
||||
return point{
|
||||
details::extract(::base::CheckMul(x, scale)),
|
||||
details::extract(::base::CheckMul(y, scale)),
|
||||
};
|
||||
}
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_y, scale).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
constexpr point operator/(const T scale) const
|
||||
{
|
||||
return point{
|
||||
details::extract(::base::CheckDiv(x, scale)),
|
||||
details::extract(::base::CheckDiv(y, scale)),
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
point operator/(const T& scale) const
|
||||
constexpr T narrow_x() const
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "Type must be arithmetic");
|
||||
ptrdiff_t x;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_x, scale).AssignIfValid(&x));
|
||||
|
||||
ptrdiff_t y;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, scale).AssignIfValid(&y));
|
||||
|
||||
return point{ x, y };
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t x() const noexcept
|
||||
{
|
||||
return _x;
|
||||
return gsl::narrow<T>(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T x() const
|
||||
constexpr T narrow_y() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t y() const noexcept
|
||||
{
|
||||
return _y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T y() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
return gsl::narrow<T>(y);
|
||||
}
|
||||
|
||||
#ifdef _WINCONTYPES_
|
||||
operator COORD() const
|
||||
explicit constexpr point(const COORD other) noexcept :
|
||||
x{ other.X }, y{ other.Y }
|
||||
{
|
||||
COORD ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.X));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.Y));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr COORD to_win32_coord() const
|
||||
{
|
||||
return { narrow_x<short>(), narrow_y<short>() };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINDEF_
|
||||
operator POINT() const
|
||||
explicit constexpr point(const POINT other) noexcept :
|
||||
x{ other.x }, y{ other.y }
|
||||
{
|
||||
POINT ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.x));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.y));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr POINT to_win32_point() const noexcept
|
||||
{
|
||||
return { x, y };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DCOMMON_H_INCLUDED
|
||||
constexpr operator D2D1_POINT_2F() const noexcept
|
||||
template<typename TilMath>
|
||||
constexpr point(TilMath, const D2D1_POINT_2F other) :
|
||||
x{ TilMath::template cast<CoordType>(other.x) },
|
||||
y{ TilMath::template cast<CoordType>(other.y) }
|
||||
{
|
||||
return D2D1_POINT_2F{ gsl::narrow_cast<float>(_x), gsl::narrow_cast<float>(_y) };
|
||||
}
|
||||
|
||||
constexpr D2D1_POINT_2F to_d2d_point() const noexcept
|
||||
{
|
||||
return { static_cast<float>(x), static_cast<float>(y) };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Windows_Foundation_H
|
||||
operator winrt::Windows::Foundation::Point() const
|
||||
template<typename TilMath>
|
||||
constexpr point(TilMath, const winrt::Windows::Foundation::Point other) :
|
||||
x{ TilMath::template cast<CoordType>(other.X) },
|
||||
y{ TilMath::template cast<CoordType>(other.Y) }
|
||||
{
|
||||
winrt::Windows::Foundation::Point ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_x).AssignIfValid(&ret.X));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_y).AssignIfValid(&ret.Y));
|
||||
return ret;
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Point to_winrt_point() const noexcept
|
||||
{
|
||||
return { static_cast<float>(x), static_cast<float>(y) };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Microsoft_Terminal_Core_H
|
||||
constexpr point(const winrt::Microsoft::Terminal::Core::Point& corePoint) :
|
||||
point(corePoint.X, corePoint.Y)
|
||||
explicit constexpr point(const winrt::Microsoft::Terminal::Core::Point other) :
|
||||
x{ other.X }, y{ other.Y }
|
||||
{
|
||||
}
|
||||
|
||||
operator winrt::Microsoft::Terminal::Core::Point() const
|
||||
winrt::Microsoft::Terminal::Core::Point to_core_point() const noexcept
|
||||
{
|
||||
winrt::Microsoft::Terminal::Core::Point ret;
|
||||
ret.X = x<int>();
|
||||
ret.Y = y<int>();
|
||||
return ret;
|
||||
return { x, y };
|
||||
}
|
||||
#endif
|
||||
|
||||
std::wstring to_string() const
|
||||
{
|
||||
return wil::str_printf<std::wstring>(L"(X:%td, Y:%td)", x(), y());
|
||||
return wil::str_printf<std::wstring>(L"(X:%td, Y:%td)", x, y);
|
||||
}
|
||||
|
||||
protected:
|
||||
ptrdiff_t _x;
|
||||
ptrdiff_t _y;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::PointTests;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@ -372,34 +235,34 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
namespace WEX::TestExecution
|
||||
{
|
||||
template<>
|
||||
class VerifyOutputTraits<::til::point>
|
||||
class VerifyOutputTraits<til::point>
|
||||
{
|
||||
public:
|
||||
static WEX::Common::NoThrowString ToString(const ::til::point& point)
|
||||
static WEX::Common::NoThrowString ToString(const til::point point)
|
||||
{
|
||||
return WEX::Common::NoThrowString(point.to_string().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class VerifyCompareTraits<::til::point, ::til::point>
|
||||
class VerifyCompareTraits<til::point, til::point>
|
||||
{
|
||||
public:
|
||||
static bool AreEqual(const ::til::point& expected, const ::til::point& actual) noexcept
|
||||
static constexpr bool AreEqual(const til::point expected, const til::point actual) noexcept
|
||||
{
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
static bool AreSame(const ::til::point& expected, const ::til::point& actual) noexcept
|
||||
static constexpr bool AreSame(const til::point expected, const til::point actual) noexcept
|
||||
{
|
||||
return &expected == &actual;
|
||||
}
|
||||
|
||||
static bool IsLessThan(const ::til::point& expectedLess, const ::til::point& expectedGreater) = delete;
|
||||
static constexpr bool IsLessThan(const til::point expectedLess, const til::point expectedGreater) = delete;
|
||||
|
||||
static bool IsGreaterThan(const ::til::point& expectedGreater, const ::til::point& expectedLess) = delete;
|
||||
static constexpr bool IsGreaterThan(const til::point expectedGreater, const til::point expectedLess) = delete;
|
||||
|
||||
static bool IsNull(const ::til::point& object) noexcept
|
||||
static constexpr bool IsNull(const til::point object) noexcept
|
||||
{
|
||||
return object == til::point{};
|
||||
}
|
||||
|
||||
860
src/inc/til/rect.h
Normal file
860
src/inc/til/rect.h
Normal file
@ -0,0 +1,860 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bit.h"
|
||||
#include "some.h"
|
||||
#include "math.h"
|
||||
#include "size.h"
|
||||
#include "point.h"
|
||||
#include "operators.h"
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
class _rectangle_const_iterator
|
||||
{
|
||||
public:
|
||||
constexpr _rectangle_const_iterator(point topLeft, point bottomRight) :
|
||||
_topLeft{ topLeft },
|
||||
_bottomRight{ bottomRight },
|
||||
_current{ topLeft }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr _rectangle_const_iterator(point topLeft, point bottomRight, point start) :
|
||||
_topLeft{ topLeft },
|
||||
_bottomRight{ bottomRight },
|
||||
_current{ start }
|
||||
{
|
||||
}
|
||||
|
||||
_rectangle_const_iterator& operator++()
|
||||
{
|
||||
const auto nextX = details::extract(::base::CheckAdd(_current.x, 1));
|
||||
|
||||
if (nextX >= _bottomRight.x)
|
||||
{
|
||||
const auto nextY = details::extract(::base::CheckAdd(_current.y, 1));
|
||||
// Note for the standard Left-to-Right, Top-to-Bottom walk,
|
||||
// the end position is one cell below the bottom left.
|
||||
// (or more accurately, on the exclusive bottom line in the inclusive left column.)
|
||||
_current = { _topLeft.x, nextY };
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = { nextX, _current.y };
|
||||
}
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const _rectangle_const_iterator& rhs) const noexcept
|
||||
{
|
||||
// `__builtin_memcmp` isn't an official standard, but it's the
|
||||
// only way at the time of writing to get a constexpr `memcmp`.
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const _rectangle_const_iterator& rhs) const noexcept
|
||||
{
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0;
|
||||
}
|
||||
|
||||
constexpr bool operator<(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return _current < other._current;
|
||||
}
|
||||
|
||||
constexpr bool operator>(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return _current > other._current;
|
||||
}
|
||||
|
||||
constexpr point operator*() const
|
||||
{
|
||||
return _current;
|
||||
}
|
||||
|
||||
protected:
|
||||
point _current;
|
||||
const point _topLeft;
|
||||
const point _bottomRight;
|
||||
};
|
||||
}
|
||||
|
||||
struct rect
|
||||
{
|
||||
using const_iterator = details::_rectangle_const_iterator;
|
||||
|
||||
CoordType left = 0;
|
||||
CoordType top = 0;
|
||||
CoordType right = 0;
|
||||
CoordType bottom = 0;
|
||||
|
||||
constexpr rect() noexcept = default;
|
||||
|
||||
constexpr rect(CoordType left, CoordType top, CoordType right, CoordType bottom) noexcept :
|
||||
left{ left }, top{ top }, right{ right }, bottom{ bottom }
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to point from floating-point args;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::point"
|
||||
template<typename TilMath, typename T>
|
||||
constexpr rect(TilMath, T left, T top, T right, T bottom) :
|
||||
left{ TilMath::template cast<CoordType>(left) },
|
||||
top{ TilMath::template cast<CoordType>(top) },
|
||||
right{ TilMath::template cast<CoordType>(right) },
|
||||
bottom{ TilMath::template cast<CoordType>(bottom) }
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a rect where you specify the top-left corner (included)
|
||||
// and the bottom-right corner (excluded)
|
||||
constexpr rect(point topLeft, point bottomRight) noexcept :
|
||||
left{ topLeft.x }, top{ topLeft.y }, right{ bottomRight.x }, bottom{ bottomRight.y }
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a rect with the given size where the top-left corner
|
||||
// is set to 0,0.
|
||||
explicit constexpr rect(size size) noexcept :
|
||||
right{ size.width }, bottom{ size.height }
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a rect at the given top-left corner point X,Y that extends
|
||||
// down (+Y direction) and right (+X direction) for the given size.
|
||||
constexpr rect(point topLeft, size size) :
|
||||
rect{ topLeft, topLeft + size }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator==(const rect& rhs) const noexcept
|
||||
{
|
||||
// `__builtin_memcmp` isn't an official standard, but it's the
|
||||
// only way at the time of writing to get a constexpr `memcmp`.
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const rect& rhs) const noexcept
|
||||
{
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0;
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return (left >= 0) & (top >= 0) &
|
||||
(right > left) & (bottom > top);
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const
|
||||
{
|
||||
return const_iterator({ left, top }, { right, bottom });
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const
|
||||
{
|
||||
// For the standard walk: Left-To-Right then Top-To-Bottom
|
||||
// the end box is one cell below the left most column.
|
||||
// |----| 5x2 square. Remember bottom & right are exclusive
|
||||
// | | while top & left are inclusive.
|
||||
// X----- X is the end position.
|
||||
|
||||
return const_iterator({ left, top }, { right, bottom }, { left, bottom });
|
||||
}
|
||||
|
||||
#pragma region RECTANGLE OPERATORS
|
||||
// OR = union
|
||||
constexpr rect operator|(const rect& other) const noexcept
|
||||
{
|
||||
const auto thisEmpty = empty();
|
||||
const auto otherEmpty = other.empty();
|
||||
|
||||
// If both are empty, return empty rect.
|
||||
if (thisEmpty && otherEmpty)
|
||||
{
|
||||
return rect{};
|
||||
}
|
||||
|
||||
// If this is empty but not the other one, then give the other.
|
||||
if (thisEmpty)
|
||||
{
|
||||
return other;
|
||||
}
|
||||
|
||||
// If the other is empty but not this, give this.
|
||||
if (otherEmpty)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we get here, they're both not empty. Do math.
|
||||
const auto l = std::min(left, other.left);
|
||||
const auto t = std::min(top, other.top);
|
||||
const auto r = std::max(right, other.right);
|
||||
const auto b = std::max(bottom, other.bottom);
|
||||
return rect{ l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rect& operator|=(const rect& other) noexcept
|
||||
{
|
||||
*this = *this | other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// AND = intersect
|
||||
constexpr rect operator&(const rect& other) const noexcept
|
||||
{
|
||||
const auto l = std::max(left, other.left);
|
||||
const auto r = std::min(right, other.right);
|
||||
|
||||
// If the width dimension would be empty, give back empty rect.
|
||||
if (l >= r)
|
||||
{
|
||||
return rect{};
|
||||
}
|
||||
|
||||
const auto t = std::max(top, other.top);
|
||||
const auto b = std::min(bottom, other.bottom);
|
||||
|
||||
// If the height dimension would be empty, give back empty rect.
|
||||
if (t >= b)
|
||||
{
|
||||
return rect{};
|
||||
}
|
||||
|
||||
return rect{ l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rect& operator&=(const rect& other) noexcept
|
||||
{
|
||||
*this = *this & other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - = subtract
|
||||
constexpr some<rect, 4> operator-(const rect& other) const
|
||||
{
|
||||
some<rect, 4> result;
|
||||
|
||||
// We could have up to four rectangles describing the area resulting when you take removeMe out of main.
|
||||
// Find the intersection of the two so we know which bits of removeMe are actually applicable
|
||||
// to the original rect for subtraction purposes.
|
||||
const auto intersect = *this & other;
|
||||
|
||||
// If there's no intersect, there's nothing to remove.
|
||||
if (intersect.empty())
|
||||
{
|
||||
// Just put the original rect into the results and return early.
|
||||
result.push_back(*this);
|
||||
}
|
||||
// If the original rect matches the intersect, there is nothing to return.
|
||||
else if (*this != intersect)
|
||||
{
|
||||
// Generate our potential four viewports that represent the region of the original that falls outside of the remove area.
|
||||
// We will bias toward generating wide rectangles over tall rectangles (if possible) so that optimizations that apply
|
||||
// to manipulating an entire row at once can be realized by other parts of the console code. (i.e. Run Length Encoding)
|
||||
// In the following examples, the found remaining regions are represented by:
|
||||
// T = Top B = Bottom L = Left R = Right
|
||||
//
|
||||
// 4 Sides but Identical:
|
||||
// |-----------this-----------| |-----------this-----------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | ======> | intersect | ======> early return of nothing
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |-----------other----------| |--------------------------|
|
||||
//
|
||||
// 4 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR|
|
||||
// | |other | | ======> | |intersect| | ======> |LLLLLLLL| |RRRRRRR|
|
||||
// | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// |--------------------------| |--------------------------| |--------------------------|
|
||||
//
|
||||
// 3 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | |other | ======> | |intersect | ======> |LLLLLLLL| |
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// |--------------------------| |--------------------------| |--------------------------|
|
||||
//
|
||||
// 2 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | |other | ======> | |intersect | ======> |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// |--------| | |--------------------------| |--------------------------|
|
||||
// | |
|
||||
// |--------------------|
|
||||
//
|
||||
// 1 Side:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// |-----------------------------| |--------------------------| |--------------------------|
|
||||
// | other | ======> | intersect | ======> | |
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// | | |--------------------------| |--------------------------|
|
||||
// | |
|
||||
// |-----------------------------|
|
||||
//
|
||||
// 0 Sides:
|
||||
// |-----------this-----------| |-----------this-----------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | ======> | | ======> early return of this
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |--------------------------| |--------------------------|
|
||||
//
|
||||
//
|
||||
// |---------------|
|
||||
// | other |
|
||||
// |---------------|
|
||||
|
||||
// We generate these rectangles by the original and intersect points, but some of them might be empty when the intersect
|
||||
// lines up with the edge of the original. That's OK. That just means that the subtraction didn't leave anything behind.
|
||||
// We will filter those out below when adding them to the result.
|
||||
const rect t{ left, top, right, intersect.top };
|
||||
const rect b{ left, intersect.bottom, right, bottom };
|
||||
const rect l{ left, intersect.top, intersect.left, intersect.bottom };
|
||||
const rect r{ intersect.right, intersect.top, right, intersect.bottom };
|
||||
|
||||
if (!t.empty())
|
||||
{
|
||||
result.push_back(t);
|
||||
}
|
||||
|
||||
if (!b.empty())
|
||||
{
|
||||
result.push_back(b);
|
||||
}
|
||||
|
||||
if (!l.empty())
|
||||
{
|
||||
result.push_back(l);
|
||||
}
|
||||
|
||||
if (!r.empty())
|
||||
{
|
||||
result.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RECTANGLE VS POINT
|
||||
// ADD will translate (offset) the rect by the point.
|
||||
constexpr rect operator+(const point point) const
|
||||
{
|
||||
const auto l = details::extract(::base::CheckAdd(left, point.x));
|
||||
const auto t = details::extract(::base::CheckAdd(top, point.y));
|
||||
const auto r = details::extract(::base::CheckAdd(right, point.x));
|
||||
const auto b = details::extract(::base::CheckAdd(bottom, point.y));
|
||||
return { l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rect& operator+=(const point point)
|
||||
{
|
||||
*this = *this + point;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SUB will translate (offset) the rect by the point.
|
||||
constexpr rect operator-(const point point) const
|
||||
{
|
||||
const auto l = details::extract(::base::CheckSub(left, point.x));
|
||||
const auto t = details::extract(::base::CheckSub(top, point.y));
|
||||
const auto r = details::extract(::base::CheckSub(right, point.x));
|
||||
const auto b = details::extract(::base::CheckSub(bottom, point.y));
|
||||
return { l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rect& operator-=(const point point)
|
||||
{
|
||||
*this = *this - point;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RECTANGLE VS SIZE
|
||||
// ADD will grow the total area of the rect. The sign is the direction to grow.
|
||||
constexpr rect operator+(const size size) const
|
||||
{
|
||||
// Fetch the pieces of the rect.
|
||||
auto l = left;
|
||||
auto r = right;
|
||||
auto t = top;
|
||||
auto b = bottom;
|
||||
|
||||
// Fetch the scale factors we're using.
|
||||
const auto width = size.width;
|
||||
const auto height = size.height;
|
||||
|
||||
// Since this is the add operation versus a size, the result
|
||||
// should grow the total rect area.
|
||||
// The sign determines which edge of the rect moves.
|
||||
// We use the magnitude as how far to move.
|
||||
if (width > 0)
|
||||
{
|
||||
// Adding the positive makes the rect "grow"
|
||||
// because right stretches outward (to the right).
|
||||
//
|
||||
// Example with adding width 3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x------------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------------|
|
||||
// BEFORE AFTER
|
||||
r = details::extract(::base::CheckAdd(r, width));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adding the negative makes the rect "grow"
|
||||
// because left stretches outward (to the left).
|
||||
//
|
||||
// Example with adding width -3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| |--x---------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------------|
|
||||
// BEFORE AFTER
|
||||
l = details::extract(::base::CheckAdd(l, width));
|
||||
}
|
||||
|
||||
if (height > 0)
|
||||
{
|
||||
// Adding the positive makes the rect "grow"
|
||||
// because bottom stretches outward (to the down).
|
||||
//
|
||||
// Example with adding height 2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x---------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| | |
|
||||
// | |
|
||||
// |---------|
|
||||
// BEFORE AFTER
|
||||
b = details::extract(::base::CheckAdd(b, height));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adding the negative makes the rect "grow"
|
||||
// because top stretches outward (to the up).
|
||||
//
|
||||
// Example with adding height -2...
|
||||
// |-- x = origin
|
||||
// |
|
||||
// | |---------|
|
||||
// V | |
|
||||
// x---------| x |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |---------|
|
||||
// BEFORE AFTER
|
||||
t = details::extract(::base::CheckAdd(t, height));
|
||||
}
|
||||
|
||||
return rect{ point{ l, t }, point{ r, b } };
|
||||
}
|
||||
|
||||
constexpr rect& operator+=(const size size)
|
||||
{
|
||||
*this = *this + size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SUB will shrink the total area of the rect. The sign is the direction to shrink.
|
||||
constexpr rect operator-(const size size) const
|
||||
{
|
||||
// Fetch the pieces of the rect.
|
||||
auto l = left;
|
||||
auto r = right;
|
||||
auto t = top;
|
||||
auto b = bottom;
|
||||
|
||||
// Fetch the scale factors we're using.
|
||||
const auto width = size.width;
|
||||
const auto height = size.height;
|
||||
|
||||
// Since this is the subtract operation versus a size, the result
|
||||
// should shrink the total rect area.
|
||||
// The sign determines which edge of the rect moves.
|
||||
// We use the magnitude as how far to move.
|
||||
if (width > 0)
|
||||
{
|
||||
// Subtracting the positive makes the rect "shrink"
|
||||
// because right pulls inward (to the left).
|
||||
//
|
||||
// Example with subtracting width 3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------|
|
||||
// BEFORE AFTER
|
||||
r = details::extract(::base::CheckSub(r, width));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subtracting the negative makes the rect "shrink"
|
||||
// because left pulls inward (to the right).
|
||||
//
|
||||
// Example with subtracting width -3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x |------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------|
|
||||
// BEFORE AFTER
|
||||
l = details::extract(::base::CheckSub(l, width));
|
||||
}
|
||||
|
||||
if (height > 0)
|
||||
{
|
||||
// Subtracting the positive makes the rect "shrink"
|
||||
// because bottom pulls inward (to the up).
|
||||
//
|
||||
// Example with subtracting height 2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x---------|
|
||||
// | | |---------|
|
||||
// | |
|
||||
// |---------|
|
||||
// BEFORE AFTER
|
||||
b = details::extract(::base::CheckSub(b, height));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subtracting the positive makes the rect "shrink"
|
||||
// because top pulls inward (to the down).
|
||||
//
|
||||
// Example with subtracting height -2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x
|
||||
// | |
|
||||
// | | |---------|
|
||||
// |---------| |---------|
|
||||
// BEFORE AFTER
|
||||
t = details::extract(::base::CheckSub(t, height));
|
||||
}
|
||||
|
||||
return rect{ point{ l, t }, point{ r, b } };
|
||||
}
|
||||
|
||||
constexpr rect& operator-=(const size size)
|
||||
{
|
||||
*this = *this - size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// scale_up will scale the entire rect up by the size factor
|
||||
// This includes moving the origin.
|
||||
constexpr rect scale_up(const size size) const
|
||||
{
|
||||
const auto topLeft = point{ left, top } * size;
|
||||
const auto bottomRight = point{ right, bottom } * size;
|
||||
return rect{ topLeft, bottomRight };
|
||||
}
|
||||
|
||||
// scale_down will scale the entire rect down by the size factor,
|
||||
// but rounds the bottom-right corner out.
|
||||
// This includes moving the origin.
|
||||
constexpr rect scale_down(const size size) const
|
||||
{
|
||||
auto topLeft = point{ left, top };
|
||||
auto bottomRight = point{ right, bottom };
|
||||
topLeft = topLeft / size;
|
||||
|
||||
// Move bottom right point into a size
|
||||
// Use size specialization of divide_ceil to round up against the size given.
|
||||
// Add leading addition to point to convert it back into a point.
|
||||
bottomRight = point{} + til::size{ right, bottom }.divide_ceil(size);
|
||||
|
||||
return rect{ topLeft, bottomRight };
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_left() const
|
||||
{
|
||||
return gsl::narrow<T>(left);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_top() const
|
||||
{
|
||||
return gsl::narrow<T>(top);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_right() const
|
||||
{
|
||||
return gsl::narrow<T>(right);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_bottom() const
|
||||
{
|
||||
return gsl::narrow<T>(bottom);
|
||||
}
|
||||
|
||||
constexpr CoordType width() const
|
||||
{
|
||||
return details::extract(::base::CheckSub(right, left));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_width() const
|
||||
{
|
||||
return details::extract<CoordType, T>(::base::CheckSub(right, left));
|
||||
}
|
||||
|
||||
constexpr CoordType height() const
|
||||
{
|
||||
return details::extract(::base::CheckSub(bottom, top));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr T narrow_height() const
|
||||
{
|
||||
return details::extract<CoordType, T>(::base::CheckSub(bottom, top));
|
||||
}
|
||||
|
||||
constexpr point origin() const noexcept
|
||||
{
|
||||
return { left, top };
|
||||
}
|
||||
|
||||
constexpr size size() const noexcept
|
||||
{
|
||||
return til::size{ width(), height() };
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return !operator bool();
|
||||
}
|
||||
|
||||
constexpr bool contains(point pt) const noexcept
|
||||
{
|
||||
return (pt.x >= left) & (pt.x < right) &
|
||||
(pt.y >= top) & (pt.y < bottom);
|
||||
}
|
||||
|
||||
constexpr bool contains(const rect& rc) const noexcept
|
||||
{
|
||||
return (rc.left >= left) & (rc.top >= top) &
|
||||
(rc.right <= right) & (rc.bottom <= bottom);
|
||||
}
|
||||
|
||||
template<typename T = CoordType>
|
||||
constexpr T index_of(point pt) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, !contains(pt));
|
||||
|
||||
// Take Y away from the top to find how many rows down
|
||||
auto check = ::base::CheckSub(pt.y, top);
|
||||
|
||||
// Multiply by the width because we've passed that many
|
||||
// widths-worth of indices.
|
||||
check *= width();
|
||||
|
||||
// Then add in the last few indices in the x position this row
|
||||
// and subtract left to find the offset from left edge.
|
||||
check = check + pt.x - left;
|
||||
|
||||
return details::extract<CoordType, T>(check);
|
||||
}
|
||||
|
||||
point point_at(size_t index) const
|
||||
{
|
||||
const auto width = details::extract<CoordType, size_t>(::base::CheckSub(right, left));
|
||||
const auto area = details::extract<CoordType, size_t>(::base::CheckSub(bottom, top) * width);
|
||||
|
||||
THROW_HR_IF(E_INVALIDARG, index >= area);
|
||||
|
||||
// Not checking math on these because we're presuming
|
||||
// that the point can't be in bounds of a rect where
|
||||
// this would overflow on addition after the division.
|
||||
const auto quot = gsl::narrow_cast<CoordType>(index / width);
|
||||
const auto rem = gsl::narrow_cast<CoordType>(index % width);
|
||||
return point{ left + rem, top + quot };
|
||||
}
|
||||
|
||||
#ifdef _WINCONTYPES_
|
||||
// NOTE: This will convert from INCLUSIVE on the way in because
|
||||
// that is generally how SMALL_RECTs are handled in console code and via the APIs.
|
||||
explicit constexpr rect(const SMALL_RECT other) noexcept :
|
||||
rect{ other.Left, other.Top, other.Right + 1, other.Bottom + 1 }
|
||||
{
|
||||
}
|
||||
|
||||
// NOTE: This will convert back to INCLUSIVE on the way out because
|
||||
// that is generally how SMALL_RECTs are handled in console code and via the APIs.
|
||||
constexpr SMALL_RECT to_small_rect() const
|
||||
{
|
||||
// The two -1 operations below are technically UB if they underflow.
|
||||
// But practically speaking no hardware without two's complement for
|
||||
// signed integers is supported by Windows. If they do underflow, they'll
|
||||
// result in INT_MAX which will throw in gsl::narrow just like INT_MAX does.
|
||||
return {
|
||||
gsl::narrow<short>(left),
|
||||
gsl::narrow<short>(top),
|
||||
gsl::narrow<short>(right - 1),
|
||||
gsl::narrow<short>(bottom - 1),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINDEF_
|
||||
explicit constexpr rect(const RECT& other) noexcept :
|
||||
rect{ other.left, other.top, other.right, other.bottom }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr RECT to_win32_rect() const noexcept
|
||||
{
|
||||
return { left, top, right, bottom };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DCOMMON_H_INCLUDED
|
||||
template<typename TilMath>
|
||||
constexpr rect(TilMath&& math, const D2D1_RECT_F& other) :
|
||||
rect{ std::forward<TilMath>(math), other.left, other.top, other.right, other.bottom }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr D2D1_RECT_F to_d2d_rect() const noexcept
|
||||
{
|
||||
return {
|
||||
static_cast<float>(left),
|
||||
static_cast<float>(top),
|
||||
static_cast<float>(right),
|
||||
static_cast<float>(bottom),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Windows_Foundation_H
|
||||
template<typename TilMath>
|
||||
constexpr rect(TilMath&& math, const winrt::Windows::Foundation::Rect& other) :
|
||||
rect{ std::forward<TilMath>(math), other.X, other.Y, other.X + other.Width, other.Y + other.Height }
|
||||
{
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Rect to_winrt_rect() const noexcept
|
||||
{
|
||||
return {
|
||||
static_cast<float>(left),
|
||||
static_cast<float>(top),
|
||||
static_cast<float>(width()),
|
||||
static_cast<float>(height()),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Microsoft_Terminal_Core_H
|
||||
template<typename TilMath>
|
||||
constexpr rect(TilMath&& math, const winrt::Microsoft::Terminal::Core::Padding& other) :
|
||||
rect{ std::forward<TilMath>(math), other.Left, other.Top, other.Right, other.Bottom }
|
||||
{
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Core::Padding to_core_padding() const noexcept
|
||||
{
|
||||
return {
|
||||
static_cast<float>(left),
|
||||
static_cast<float>(top),
|
||||
static_cast<float>(right),
|
||||
static_cast<float>(bottom),
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
std::wstring to_string() const
|
||||
{
|
||||
return wil::str_printf<std::wstring>(L"(L:%d, T:%d, R:%d, B:%d) [W:%d, H:%d]", left, top, right, bottom, width(), height());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __WEX_COMMON_H__
|
||||
namespace WEX::TestExecution
|
||||
{
|
||||
template<>
|
||||
class VerifyOutputTraits<til::rect>
|
||||
{
|
||||
public:
|
||||
static WEX::Common::NoThrowString ToString(const til::rect& rect)
|
||||
{
|
||||
return WEX::Common::NoThrowString(rect.to_string().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class VerifyCompareTraits<til::rect, til::rect>
|
||||
{
|
||||
public:
|
||||
static bool AreEqual(const til::rect& expected, const til::rect& actual) noexcept
|
||||
{
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
static bool AreSame(const til::rect& expected, const til::rect& actual) noexcept
|
||||
{
|
||||
return &expected == &actual;
|
||||
}
|
||||
|
||||
static bool IsLessThan(const til::rect& expectedLess, const til::rect& expectedGreater) = delete;
|
||||
|
||||
static bool IsGreaterThan(const til::rect& expectedGreater, const til::rect& expectedLess) = delete;
|
||||
|
||||
static bool IsNull(const til::rect& object) noexcept
|
||||
{
|
||||
return object == til::rect{};
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
||||
@ -1,955 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
class RectangleTests;
|
||||
#endif
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
class _rectangle_const_iterator
|
||||
{
|
||||
public:
|
||||
constexpr _rectangle_const_iterator(point topLeft, point bottomRight) :
|
||||
_topLeft(topLeft),
|
||||
_bottomRight(bottomRight),
|
||||
_current(topLeft)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr _rectangle_const_iterator(point topLeft, point bottomRight, point start) :
|
||||
_topLeft(topLeft),
|
||||
_bottomRight(bottomRight),
|
||||
_current(start)
|
||||
{
|
||||
}
|
||||
|
||||
_rectangle_const_iterator& operator++()
|
||||
{
|
||||
ptrdiff_t nextX;
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(_current.x(), 1).AssignIfValid(&nextX));
|
||||
|
||||
if (nextX >= _bottomRight.x())
|
||||
{
|
||||
ptrdiff_t nextY;
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(_current.y(), 1).AssignIfValid(&nextY));
|
||||
// Note for the standard Left-to-Right, Top-to-Bottom walk,
|
||||
// the end position is one cell below the bottom left.
|
||||
// (or more accurately, on the exclusive bottom line in the inclusive left column.)
|
||||
_current = { _topLeft.x(), nextY };
|
||||
}
|
||||
else
|
||||
{
|
||||
_current = { nextX, _current.y() };
|
||||
}
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return _current == other._current &&
|
||||
_topLeft == other._topLeft &&
|
||||
_bottomRight == other._bottomRight;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
constexpr bool operator<(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return _current < other._current;
|
||||
}
|
||||
|
||||
constexpr bool operator>(const _rectangle_const_iterator& other) const
|
||||
{
|
||||
return _current > other._current;
|
||||
}
|
||||
|
||||
constexpr point operator*() const
|
||||
{
|
||||
return _current;
|
||||
}
|
||||
|
||||
protected:
|
||||
point _current;
|
||||
const point _topLeft;
|
||||
const point _bottomRight;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::RectangleTests;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
class rectangle
|
||||
{
|
||||
public:
|
||||
using const_iterator = details::_rectangle_const_iterator;
|
||||
|
||||
constexpr rectangle() noexcept :
|
||||
rectangle(til::point{ 0, 0 }, til::point{ 0, 0 })
|
||||
{
|
||||
}
|
||||
|
||||
// On 64-bit processors, int and ptrdiff_t are different fundamental types.
|
||||
// On 32-bit processors, they're the same which makes this a double-definition
|
||||
// with the `ptrdiff_t` one below.
|
||||
#if defined(_M_AMD64) || defined(_M_ARM64)
|
||||
constexpr rectangle(int left, int top, int right, int bottom) noexcept :
|
||||
rectangle(til::point{ left, top }, til::point{ right, bottom })
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
rectangle(size_t left, size_t top, size_t right, size_t bottom) :
|
||||
rectangle(til::point{ left, top }, til::point{ right, bottom })
|
||||
{
|
||||
}
|
||||
|
||||
constexpr rectangle(ptrdiff_t left, ptrdiff_t top, ptrdiff_t right, ptrdiff_t bottom) noexcept :
|
||||
rectangle(til::point{ left, top }, til::point{ right, bottom })
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a 1x1 rectangle with the given top-left corner.
|
||||
rectangle(til::point topLeft) :
|
||||
_topLeft(topLeft)
|
||||
{
|
||||
_bottomRight = _topLeft + til::point{ 1, 1 };
|
||||
}
|
||||
|
||||
// Creates a rectangle where you specify the top-left corner (included)
|
||||
// and the bottom-right corner (excluded)
|
||||
constexpr rectangle(til::point topLeft, til::point bottomRight) noexcept :
|
||||
_topLeft(topLeft),
|
||||
_bottomRight(bottomRight)
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a rectangle with the given size where the top-left corner
|
||||
// is set to 0,0.
|
||||
constexpr rectangle(til::size size) noexcept :
|
||||
_topLeft(til::point{ 0, 0 }),
|
||||
_bottomRight(til::point{ size.width(), size.height() })
|
||||
{
|
||||
}
|
||||
|
||||
// Creates a rectangle at the given top-left corner point X,Y that extends
|
||||
// down (+Y direction) and right (+X direction) for the given size.
|
||||
rectangle(til::point topLeft, til::size size) :
|
||||
_topLeft(topLeft),
|
||||
_bottomRight(topLeft + til::point{ size.width(), size.height() })
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef _WINCONTYPES_
|
||||
// This extra specialization exists for SMALL_RECT because it's the only rectangle in the world that we know of
|
||||
// with the bottom and right fields INCLUSIVE to the rectangle itself.
|
||||
// It will perform math on the way in to ensure that it is represented as EXCLUSIVE.
|
||||
rectangle(SMALL_RECT sr)
|
||||
{
|
||||
_topLeft = til::point{ static_cast<ptrdiff_t>(sr.Left), static_cast<ptrdiff_t>(sr.Top) };
|
||||
|
||||
_bottomRight = til::point{ static_cast<ptrdiff_t>(sr.Right), static_cast<ptrdiff_t>(sr.Bottom) } + til::point{ 1, 1 };
|
||||
}
|
||||
#endif
|
||||
|
||||
// This template will convert to rectangle from anything that has a Left, Top, Right, and Bottom field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr rectangle(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().Top)> && std::is_integral_v<decltype(std::declval<TOther>().Left)> && std::is_integral_v<decltype(std::declval<TOther>().Bottom)> && std::is_integral_v<decltype(std::declval<TOther>().Right)>, int> /*sentinel*/ = 0) :
|
||||
rectangle(til::point{ static_cast<ptrdiff_t>(other.Left), static_cast<ptrdiff_t>(other.Top) }, til::point{ static_cast<ptrdiff_t>(other.Right), static_cast<ptrdiff_t>(other.Bottom) })
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to rectangle from anything that has a left, top, right, and bottom field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr rectangle(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().top)> && std::is_integral_v<decltype(std::declval<TOther>().left)> && std::is_integral_v<decltype(std::declval<TOther>().bottom)> && std::is_integral_v<decltype(std::declval<TOther>().right)>, int> /*sentinel*/ = 0) :
|
||||
rectangle(til::point{ static_cast<ptrdiff_t>(other.left), static_cast<ptrdiff_t>(other.top) }, til::point{ static_cast<ptrdiff_t>(other.right), static_cast<ptrdiff_t>(other.bottom) })
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to rectangle from anything that has a Left, Top, Right, and Bottom field that are floating-point;
|
||||
// a math type is required.
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr rectangle(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().Left)> && std::is_floating_point_v<decltype(std::declval<TOther>().Top)> && std::is_floating_point_v<decltype(std::declval<TOther>().Right)> && std::is_floating_point_v<decltype(std::declval<TOther>().Bottom)>, int> /*sentinel*/ = 0) :
|
||||
rectangle(til::point{ TilMath::template cast<ptrdiff_t>(other.Left), TilMath::template cast<ptrdiff_t>(other.Top) }, til::point{ TilMath::template cast<ptrdiff_t>(other.Right), TilMath::template cast<ptrdiff_t>(other.Bottom) })
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to rectangle from anything that has a X, Y, Width, and Height field that are floating-point;
|
||||
// a math type is required.
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr rectangle(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().X)> && std::is_floating_point_v<decltype(std::declval<TOther>().Y)> && std::is_floating_point_v<decltype(std::declval<TOther>().Width)> && std::is_floating_point_v<decltype(std::declval<TOther>().Height)>, int> /*sentinel*/ = 0) :
|
||||
rectangle(til::point{ TilMath::template cast<ptrdiff_t>(other.X), TilMath::template cast<ptrdiff_t>(other.Y) }, til::size{ TilMath::template cast<ptrdiff_t>(other.Width), TilMath::template cast<ptrdiff_t>(other.Height) })
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to rectangle from anything that has a left, top, right, and bottom field that are floating-point;
|
||||
// a math type is required.
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr rectangle(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().left)> && std::is_floating_point_v<decltype(std::declval<TOther>().top)> && std::is_floating_point_v<decltype(std::declval<TOther>().right)> && std::is_floating_point_v<decltype(std::declval<TOther>().bottom)>, int> /*sentinel*/ = 0) :
|
||||
rectangle(til::point{ TilMath::template cast<ptrdiff_t>(other.left), TilMath::template cast<ptrdiff_t>(other.top) }, til::point{ TilMath::template cast<ptrdiff_t>(other.right), TilMath::template cast<ptrdiff_t>(other.bottom) })
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator==(const rectangle& other) const noexcept
|
||||
{
|
||||
return _topLeft == other._topLeft &&
|
||||
_bottomRight == other._bottomRight;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const rectangle& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept
|
||||
{
|
||||
return _topLeft.x() < _bottomRight.x() &&
|
||||
_topLeft.y() < _bottomRight.y();
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const
|
||||
{
|
||||
return const_iterator(_topLeft, _bottomRight);
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const
|
||||
{
|
||||
// For the standard walk: Left-To-Right then Top-To-Bottom
|
||||
// the end box is one cell below the left most column.
|
||||
// |----| 5x2 square. Remember bottom & right are exclusive
|
||||
// | | while top & left are inclusive.
|
||||
// X----- X is the end position.
|
||||
|
||||
return const_iterator(_topLeft, _bottomRight, { _topLeft.x(), _bottomRight.y() });
|
||||
}
|
||||
|
||||
#pragma region RECTANGLE OPERATORS
|
||||
// OR = union
|
||||
constexpr rectangle operator|(const rectangle& other) const noexcept
|
||||
{
|
||||
const auto thisEmpty = empty();
|
||||
const auto otherEmpty = other.empty();
|
||||
|
||||
// If both are empty, return empty rect.
|
||||
if (thisEmpty && otherEmpty)
|
||||
{
|
||||
return rectangle{};
|
||||
}
|
||||
|
||||
// If this is empty but not the other one, then give the other.
|
||||
if (thisEmpty)
|
||||
{
|
||||
return other;
|
||||
}
|
||||
|
||||
// If the other is empty but not this, give this.
|
||||
if (otherEmpty)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we get here, they're both not empty. Do math.
|
||||
const auto l = std::min(left(), other.left());
|
||||
const auto t = std::min(top(), other.top());
|
||||
const auto r = std::max(right(), other.right());
|
||||
const auto b = std::max(bottom(), other.bottom());
|
||||
return rectangle{ l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rectangle& operator|=(const rectangle& other) noexcept
|
||||
{
|
||||
*this = *this | other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// AND = intersect
|
||||
constexpr rectangle operator&(const rectangle& other) const noexcept
|
||||
{
|
||||
const auto l = std::max(left(), other.left());
|
||||
const auto r = std::min(right(), other.right());
|
||||
|
||||
// If the width dimension would be empty, give back empty rectangle.
|
||||
if (l >= r)
|
||||
{
|
||||
return rectangle{};
|
||||
}
|
||||
|
||||
const auto t = std::max(top(), other.top());
|
||||
const auto b = std::min(bottom(), other.bottom());
|
||||
|
||||
// If the height dimension would be empty, give back empty rectangle.
|
||||
if (t >= b)
|
||||
{
|
||||
return rectangle{};
|
||||
}
|
||||
|
||||
return rectangle{ l, t, r, b };
|
||||
}
|
||||
|
||||
constexpr rectangle& operator&=(const rectangle& other) noexcept
|
||||
{
|
||||
*this = *this & other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// - = subtract
|
||||
some<rectangle, 4> operator-(const rectangle& other) const
|
||||
{
|
||||
some<rectangle, 4> result;
|
||||
|
||||
// We could have up to four rectangles describing the area resulting when you take removeMe out of main.
|
||||
// Find the intersection of the two so we know which bits of removeMe are actually applicable
|
||||
// to the original rectangle for subtraction purposes.
|
||||
const auto intersect = *this & other;
|
||||
|
||||
// If there's no intersect, there's nothing to remove.
|
||||
if (intersect.empty())
|
||||
{
|
||||
// Just put the original rectangle into the results and return early.
|
||||
result.push_back(*this);
|
||||
}
|
||||
// If the original rectangle matches the intersect, there is nothing to return.
|
||||
else if (*this != intersect)
|
||||
{
|
||||
// Generate our potential four viewports that represent the region of the original that falls outside of the remove area.
|
||||
// We will bias toward generating wide rectangles over tall rectangles (if possible) so that optimizations that apply
|
||||
// to manipulating an entire row at once can be realized by other parts of the console code. (i.e. Run Length Encoding)
|
||||
// In the following examples, the found remaining regions are represented by:
|
||||
// T = Top B = Bottom L = Left R = Right
|
||||
//
|
||||
// 4 Sides but Identical:
|
||||
// |-----------this-----------| |-----------this-----------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | ======> | intersect | ======> early return of nothing
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |-----------other----------| |--------------------------|
|
||||
//
|
||||
// 4 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR|
|
||||
// | |other | | ======> | |intersect| | ======> |LLLLLLLL| |RRRRRRR|
|
||||
// | |---------| | | |---------| | |LLLLLLLL|---------|RRRRRRR|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// |--------------------------| |--------------------------| |--------------------------|
|
||||
//
|
||||
// 3 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | |other | ======> | |intersect | ======> |LLLLLLLL| |
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// | | | | |BBBBBBBBBBBBBBBBBBBBBBBBBB|
|
||||
// |--------------------------| |--------------------------| |--------------------------|
|
||||
//
|
||||
// 2 Sides:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | |--------------------| | |-----------------| |LLLLLLLL|-----------------|
|
||||
// | |other | ======> | |intersect | ======> |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// | | | | | | |LLLLLLLL| |
|
||||
// |--------| | |--------------------------| |--------------------------|
|
||||
// | |
|
||||
// |--------------------|
|
||||
//
|
||||
// 1 Side:
|
||||
// |-----------this-----------| |-----------this-----------| |--------------------------|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// | | | | |TTTTTTTTTTTTTTTTTTTTTTTTTT|
|
||||
// |-----------------------------| |--------------------------| |--------------------------|
|
||||
// | other | ======> | intersect | ======> | |
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// | | | | | |
|
||||
// | | |--------------------------| |--------------------------|
|
||||
// | |
|
||||
// |-----------------------------|
|
||||
//
|
||||
// 0 Sides:
|
||||
// |-----------this-----------| |-----------this-----------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | ======> | | ======> early return of this
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |--------------------------| |--------------------------|
|
||||
//
|
||||
//
|
||||
// |---------------|
|
||||
// | other |
|
||||
// |---------------|
|
||||
|
||||
// We generate these rectangles by the original and intersect points, but some of them might be empty when the intersect
|
||||
// lines up with the edge of the original. That's OK. That just means that the subtraction didn't leave anything behind.
|
||||
// We will filter those out below when adding them to the result.
|
||||
const til::rectangle t{ left(), top(), right(), intersect.top() };
|
||||
const til::rectangle b{ left(), intersect.bottom(), right(), bottom() };
|
||||
const til::rectangle l{ left(), intersect.top(), intersect.left(), intersect.bottom() };
|
||||
const til::rectangle r{ intersect.right(), intersect.top(), right(), intersect.bottom() };
|
||||
|
||||
if (!t.empty())
|
||||
{
|
||||
result.push_back(t);
|
||||
}
|
||||
|
||||
if (!b.empty())
|
||||
{
|
||||
result.push_back(b);
|
||||
}
|
||||
|
||||
if (!l.empty())
|
||||
{
|
||||
result.push_back(l);
|
||||
}
|
||||
|
||||
if (!r.empty())
|
||||
{
|
||||
result.push_back(r);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RECTANGLE VS POINT
|
||||
// ADD will translate (offset) the rectangle by the point.
|
||||
rectangle operator+(const point& point) const
|
||||
{
|
||||
ptrdiff_t l, t, r, b;
|
||||
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(left(), point.x()).AssignIfValid(&l));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(top(), point.y()).AssignIfValid(&t));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(right(), point.x()).AssignIfValid(&r));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckAdd(bottom(), point.y()).AssignIfValid(&b));
|
||||
|
||||
return til::rectangle{ til::point{ l, t }, til::point{ r, b } };
|
||||
}
|
||||
|
||||
rectangle& operator+=(const point& point)
|
||||
{
|
||||
*this = *this + point;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SUB will translate (offset) the rectangle by the point.
|
||||
rectangle operator-(const point& point) const
|
||||
{
|
||||
ptrdiff_t l, t, r, b;
|
||||
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(left(), point.x()).AssignIfValid(&l));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(top(), point.y()).AssignIfValid(&t));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(right(), point.x()).AssignIfValid(&r));
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(bottom(), point.y()).AssignIfValid(&b));
|
||||
|
||||
return til::rectangle{ til::point{ l, t }, til::point{ r, b } };
|
||||
}
|
||||
|
||||
rectangle& operator-=(const point& point)
|
||||
{
|
||||
*this = *this - point;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RECTANGLE VS SIZE
|
||||
// ADD will grow the total area of the rectangle. The sign is the direction to grow.
|
||||
rectangle operator+(const size& size) const
|
||||
{
|
||||
// Fetch the pieces of the rectangle.
|
||||
auto l = left();
|
||||
auto r = right();
|
||||
auto t = top();
|
||||
auto b = bottom();
|
||||
|
||||
// Fetch the scale factors we're using.
|
||||
const auto width = size.width();
|
||||
const auto height = size.height();
|
||||
|
||||
// Since this is the add operation versus a size, the result
|
||||
// should grow the total rectangle area.
|
||||
// The sign determines which edge of the rectangle moves.
|
||||
// We use the magnitude as how far to move.
|
||||
if (width > 0)
|
||||
{
|
||||
// Adding the positive makes the rectangle "grow"
|
||||
// because right stretches outward (to the right).
|
||||
//
|
||||
// Example with adding width 3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x------------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(r, width).AssignIfValid(&r));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adding the negative makes the rectangle "grow"
|
||||
// because left stretches outward (to the left).
|
||||
//
|
||||
// Example with adding width -3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| |--x---------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(l, width).AssignIfValid(&l));
|
||||
}
|
||||
|
||||
if (height > 0)
|
||||
{
|
||||
// Adding the positive makes the rectangle "grow"
|
||||
// because bottom stretches outward (to the down).
|
||||
//
|
||||
// Example with adding height 2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x---------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| | |
|
||||
// | |
|
||||
// |---------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(b, height).AssignIfValid(&b));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Adding the negative makes the rectangle "grow"
|
||||
// because top stretches outward (to the up).
|
||||
//
|
||||
// Example with adding height -2...
|
||||
// |-- x = origin
|
||||
// |
|
||||
// | |---------|
|
||||
// V | |
|
||||
// x---------| x |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |---------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(t, height).AssignIfValid(&t));
|
||||
}
|
||||
|
||||
return rectangle{ til::point{ l, t }, til::point{ r, b } };
|
||||
}
|
||||
|
||||
rectangle& operator+=(const size& size)
|
||||
{
|
||||
*this = *this + size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// SUB will shrink the total area of the rectangle. The sign is the direction to shrink.
|
||||
rectangle operator-(const size& size) const
|
||||
{
|
||||
// Fetch the pieces of the rectangle.
|
||||
auto l = left();
|
||||
auto r = right();
|
||||
auto t = top();
|
||||
auto b = bottom();
|
||||
|
||||
// Fetch the scale factors we're using.
|
||||
const auto width = size.width();
|
||||
const auto height = size.height();
|
||||
|
||||
// Since this is the subtract operation versus a size, the result
|
||||
// should shrink the total rectangle area.
|
||||
// The sign determines which edge of the rectangle moves.
|
||||
// We use the magnitude as how far to move.
|
||||
if (width > 0)
|
||||
{
|
||||
// Subtracting the positive makes the rectangle "shrink"
|
||||
// because right pulls inward (to the left).
|
||||
//
|
||||
// Example with subtracting width 3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(r, width).AssignIfValid(&r));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subtracting the negative makes the rectangle "shrink"
|
||||
// because left pulls inward (to the right).
|
||||
//
|
||||
// Example with subtracting width -3...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x |------|
|
||||
// | | | |
|
||||
// | | | |
|
||||
// |---------| |------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(l, width).AssignIfValid(&l));
|
||||
}
|
||||
|
||||
if (height > 0)
|
||||
{
|
||||
// Subtracting the positive makes the rectangle "shrink"
|
||||
// because bottom pulls inward (to the up).
|
||||
//
|
||||
// Example with subtracting height 2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x---------|
|
||||
// | | |---------|
|
||||
// | |
|
||||
// |---------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(b, height).AssignIfValid(&b));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Subtracting the positive makes the rectangle "shrink"
|
||||
// because top pulls inward (to the down).
|
||||
//
|
||||
// Example with subtracting height -2...
|
||||
// |-- x = origin
|
||||
// V
|
||||
// x---------| x
|
||||
// | |
|
||||
// | | |---------|
|
||||
// |---------| |---------|
|
||||
// BEFORE AFTER
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(t, height).AssignIfValid(&t));
|
||||
}
|
||||
|
||||
return rectangle{ til::point{ l, t }, til::point{ r, b } };
|
||||
}
|
||||
|
||||
rectangle& operator-=(const size& size)
|
||||
{
|
||||
*this = *this - size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// scale_up will scale the entire rectangle up by the size factor
|
||||
// This includes moving the origin.
|
||||
rectangle scale_up(const size& size) const
|
||||
{
|
||||
const auto topLeft = _topLeft * size;
|
||||
const auto bottomRight = _bottomRight * size;
|
||||
return til::rectangle{ topLeft, bottomRight };
|
||||
}
|
||||
|
||||
// scale_down will scale the entire rectangle down by the size factor,
|
||||
// but rounds the bottom-right corner out.
|
||||
// This includes moving the origin.
|
||||
rectangle scale_down(const size& size) const
|
||||
{
|
||||
auto topLeft = _topLeft;
|
||||
auto bottomRight = _bottomRight;
|
||||
topLeft = topLeft / size;
|
||||
|
||||
// Move bottom right point into a size
|
||||
// Use size specialization of divide_ceil to round up against the size given.
|
||||
// Add leading addition to point to convert it back into a point.
|
||||
bottomRight = til::point{} + til::size{ right(), bottom() }.divide_ceil(size);
|
||||
|
||||
return til::rectangle{ topLeft, bottomRight };
|
||||
}
|
||||
|
||||
template<typename TilMath>
|
||||
rectangle scale(TilMath, const float scale) const
|
||||
{
|
||||
return til::rectangle{ _topLeft.scale(TilMath{}, scale), _bottomRight.scale(TilMath{}, scale) };
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
constexpr ptrdiff_t top() const noexcept
|
||||
{
|
||||
return _topLeft.y();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T top() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t bottom() const noexcept
|
||||
{
|
||||
return _bottomRight.y();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T bottom() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t left() const noexcept
|
||||
{
|
||||
return _topLeft.x();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T left() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t right() const noexcept
|
||||
{
|
||||
return _bottomRight.x();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T right() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptrdiff_t width() const
|
||||
{
|
||||
ptrdiff_t ret;
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(right(), left()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T width() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptrdiff_t height() const
|
||||
{
|
||||
ptrdiff_t ret;
|
||||
THROW_HR_IF(E_ABORT, !::base::CheckSub(bottom(), top()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T height() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr point origin() const noexcept
|
||||
{
|
||||
return _topLeft;
|
||||
}
|
||||
|
||||
size size() const
|
||||
{
|
||||
return til::size{ width(), height() };
|
||||
}
|
||||
|
||||
constexpr bool empty() const noexcept
|
||||
{
|
||||
return !operator bool();
|
||||
}
|
||||
|
||||
constexpr bool contains(til::point pt) const
|
||||
{
|
||||
return pt.x() >= _topLeft.x() && pt.x() < _bottomRight.x() &&
|
||||
pt.y() >= _topLeft.y() && pt.y() < _bottomRight.y();
|
||||
}
|
||||
|
||||
bool contains(ptrdiff_t index) const
|
||||
{
|
||||
return index >= 0 && index < size().area();
|
||||
}
|
||||
|
||||
constexpr bool contains(til::rectangle rc) const
|
||||
{
|
||||
// Union the other rectangle and ourselves.
|
||||
// If the result of that didn't grow at all, then we already
|
||||
// fully contained the rectangle we were given.
|
||||
return (*this | rc) == *this;
|
||||
}
|
||||
|
||||
ptrdiff_t index_of(til::point pt) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, !contains(pt));
|
||||
|
||||
// Take Y away from the top to find how many rows down
|
||||
auto check = base::CheckSub(pt.y(), top());
|
||||
|
||||
// Multiply by the width because we've passed that many
|
||||
// widths-worth of indices.
|
||||
check *= width();
|
||||
|
||||
// Then add in the last few indices in the x position this row
|
||||
// and subtract left to find the offset from left edge.
|
||||
check = check + pt.x() - left();
|
||||
|
||||
ptrdiff_t result;
|
||||
THROW_HR_IF(E_ABORT, !check.AssignIfValid(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
til::point point_at(ptrdiff_t index) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, !contains(index));
|
||||
|
||||
const auto div = std::div(index, width());
|
||||
|
||||
// Not checking math on these because we're presuming
|
||||
// that the point can't be in bounds of a rectangle where
|
||||
// this would overflow on addition after the division.
|
||||
return til::point{ div.rem + left(), div.quot + top() };
|
||||
}
|
||||
|
||||
#ifdef _WINCONTYPES_
|
||||
// NOTE: This will convert back to INCLUSIVE on the way out because
|
||||
// that is generally how SMALL_RECTs are handled in console code and via the APIs.
|
||||
operator SMALL_RECT() const
|
||||
{
|
||||
SMALL_RECT ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.Left));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Top));
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(right(), 1).AssignIfValid(&ret.Right));
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(bottom(), 1).AssignIfValid(&ret.Bottom));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINDEF_
|
||||
operator RECT() const
|
||||
{
|
||||
RECT ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.left));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.top));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret.right));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret.bottom));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DCOMMON_H_INCLUDED
|
||||
constexpr operator D2D1_RECT_F() const noexcept
|
||||
{
|
||||
return D2D1_RECT_F{ gsl::narrow_cast<FLOAT>(left()), gsl::narrow_cast<FLOAT>(top()), gsl::narrow_cast<FLOAT>(right()), gsl::narrow_cast<FLOAT>(bottom()) };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Windows_Foundation_H
|
||||
operator winrt::Windows::Foundation::Rect() const
|
||||
{
|
||||
winrt::Windows::Foundation::Rect ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.X));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Y));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret.Width));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret.Height));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Microsoft_Terminal_Core_H
|
||||
operator winrt::Microsoft::Terminal::Core::Padding() const
|
||||
{
|
||||
winrt::Microsoft::Terminal::Core::Padding ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(left()).AssignIfValid(&ret.Left));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(top()).AssignIfValid(&ret.Top));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(right()).AssignIfValid(&ret.Right));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(bottom()).AssignIfValid(&ret.Bottom));
|
||||
return ret;
|
||||
}
|
||||
constexpr rectangle(const winrt::Microsoft::Terminal::Core::Padding& padding) :
|
||||
rectangle(til::math::rounding, padding)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
std::wstring to_string() const
|
||||
{
|
||||
return wil::str_printf<std::wstring>(L"(L:%td, T:%td, R:%td, B:%td) [W:%td, H:%td]", left(), top(), right(), bottom(), width(), height());
|
||||
}
|
||||
|
||||
protected:
|
||||
til::point _topLeft;
|
||||
til::point _bottomRight;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::RectangleTests;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __WEX_COMMON_H__
|
||||
namespace WEX::TestExecution
|
||||
{
|
||||
template<>
|
||||
class VerifyOutputTraits<::til::rectangle>
|
||||
{
|
||||
public:
|
||||
static WEX::Common::NoThrowString ToString(const ::til::rectangle& rect)
|
||||
{
|
||||
return WEX::Common::NoThrowString(rect.to_string().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class VerifyCompareTraits<::til::rectangle, ::til::rectangle>
|
||||
{
|
||||
public:
|
||||
static bool AreEqual(const ::til::rectangle& expected, const ::til::rectangle& actual) noexcept
|
||||
{
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
static bool AreSame(const ::til::rectangle& expected, const ::til::rectangle& actual) noexcept
|
||||
{
|
||||
return &expected == &actual;
|
||||
}
|
||||
|
||||
static bool IsLessThan(const ::til::rectangle& expectedLess, const ::til::rectangle& expectedGreater) = delete;
|
||||
|
||||
static bool IsGreaterThan(const ::til::rectangle& expectedGreater, const ::til::rectangle& expectedLess) = delete;
|
||||
|
||||
static bool IsNull(const ::til::rectangle& object) noexcept
|
||||
{
|
||||
return object == til::rectangle{};
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
||||
@ -3,195 +3,107 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
class SizeTests;
|
||||
#endif
|
||||
#include "point.h"
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
class size
|
||||
struct size
|
||||
{
|
||||
public:
|
||||
constexpr size() noexcept :
|
||||
size(0, 0)
|
||||
{
|
||||
}
|
||||
CoordType width = 0;
|
||||
CoordType height = 0;
|
||||
|
||||
// On 64-bit processors, int and ptrdiff_t are different fundamental types.
|
||||
// On 32-bit processors, they're the same which makes this a double-definition
|
||||
// with the `ptrdiff_t` one below.
|
||||
#if defined(_M_AMD64) || defined(_M_ARM64)
|
||||
constexpr size(int width, int height) noexcept :
|
||||
size(static_cast<ptrdiff_t>(width), static_cast<ptrdiff_t>(height))
|
||||
{
|
||||
}
|
||||
constexpr size(ptrdiff_t width, int height) noexcept :
|
||||
size(width, static_cast<ptrdiff_t>(height))
|
||||
{
|
||||
}
|
||||
constexpr size(int width, ptrdiff_t height) noexcept :
|
||||
size(static_cast<ptrdiff_t>(width), height)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
constexpr size() noexcept = default;
|
||||
|
||||
size(size_t width, size_t height)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
||||
}
|
||||
size(long width, long height)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
||||
}
|
||||
|
||||
constexpr size(ptrdiff_t width, ptrdiff_t height) noexcept :
|
||||
_width(width),
|
||||
_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr size(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().X)> && std::is_integral_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
||||
size(static_cast<ptrdiff_t>(other.X), static_cast<ptrdiff_t>(other.Y))
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a cx and a cy field that appear convertible to an integer value
|
||||
template<typename TOther>
|
||||
constexpr size(const TOther& other, std::enable_if_t<std::is_integral_v<decltype(std::declval<TOther>().cx)> && std::is_integral_v<decltype(std::declval<TOther>().cy)>, int> /*sentinel*/ = 0) :
|
||||
size(static_cast<ptrdiff_t>(other.cx), static_cast<ptrdiff_t>(other.cy))
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a X and a Y field that are floating-point;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().X)> && std::is_floating_point_v<decltype(std::declval<TOther>().Y)>, int> /*sentinel*/ = 0) :
|
||||
size(TilMath::template cast<ptrdiff_t>(other.X), TilMath::template cast<ptrdiff_t>(other.Y))
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a cx and a cy field that are floating-point;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().cx)> && std::is_floating_point_v<decltype(std::declval<TOther>().cy)>, int> /*sentinel*/ = 0) :
|
||||
size(TilMath::template cast<ptrdiff_t>(other.cx), TilMath::template cast<ptrdiff_t>(other.cy))
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from anything that has a Width and a Height field that are floating-point;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr size(TilMath, const TOther& other, std::enable_if_t<std::is_floating_point_v<decltype(std::declval<TOther>().Width)> && std::is_floating_point_v<decltype(std::declval<TOther>().Height)>, int> /*sentinel*/ = 0) :
|
||||
size(TilMath::template cast<ptrdiff_t>(other.Width), TilMath::template cast<ptrdiff_t>(other.Height))
|
||||
constexpr size(CoordType width, CoordType height) noexcept :
|
||||
width{ width }, height{ height }
|
||||
{
|
||||
}
|
||||
|
||||
// This template will convert to size from floating-point args;
|
||||
// a math type is required. If you _don't_ provide one, you're going to
|
||||
// get a compile-time error about "cannot convert from initializer-list to til::size"
|
||||
template<typename TilMath, typename TOther>
|
||||
constexpr size(TilMath, const TOther& width, const TOther& height, std::enable_if_t<std::is_floating_point_v<TOther>, int> /*sentinel*/ = 0) :
|
||||
size(TilMath::template cast<ptrdiff_t>(width), TilMath::template cast<ptrdiff_t>(height))
|
||||
template<typename TilMath, typename T>
|
||||
constexpr size(TilMath, const T width, const T height) :
|
||||
width{ TilMath::template cast<CoordType>(width) }, height{ TilMath::template cast<CoordType>(height) }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator==(const size& other) const noexcept
|
||||
constexpr bool operator==(const size rhs) const noexcept
|
||||
{
|
||||
return _width == other._width &&
|
||||
_height == other._height;
|
||||
// `__builtin_memcmp` isn't an official standard, but it's the
|
||||
// only way at the time of writing to get a constexpr `memcmp`.
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const size& other) const noexcept
|
||||
constexpr bool operator!=(const size rhs) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return _width > 0 && _height > 0;
|
||||
return width > 0 && height > 0;
|
||||
}
|
||||
|
||||
size operator+(const size& other) const
|
||||
constexpr size operator+(const size other) const
|
||||
{
|
||||
ptrdiff_t width;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(_width, other._width).AssignIfValid(&width));
|
||||
|
||||
ptrdiff_t height;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckAdd(_height, other._height).AssignIfValid(&height));
|
||||
|
||||
return size{ width, height };
|
||||
return size{
|
||||
details::extract(::base::CheckAdd(width, other.width)),
|
||||
details::extract(::base::CheckAdd(height, other.height)),
|
||||
};
|
||||
}
|
||||
|
||||
size operator-(const size& other) const
|
||||
constexpr size operator-(const size other) const
|
||||
{
|
||||
ptrdiff_t width;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(_width, other._width).AssignIfValid(&width));
|
||||
|
||||
ptrdiff_t height;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckSub(_height, other._height).AssignIfValid(&height));
|
||||
|
||||
return size{ width, height };
|
||||
return size{
|
||||
details::extract(::base::CheckSub(width, other.width)),
|
||||
details::extract(::base::CheckSub(height, other.height)),
|
||||
};
|
||||
}
|
||||
|
||||
size operator*(const size& other) const
|
||||
constexpr size operator*(const size other) const
|
||||
{
|
||||
ptrdiff_t width;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, other._width).AssignIfValid(&width));
|
||||
|
||||
ptrdiff_t height;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_height, other._height).AssignIfValid(&height));
|
||||
|
||||
return size{ width, height };
|
||||
return size{
|
||||
details::extract(::base::CheckMul(width, other.width)),
|
||||
details::extract(::base::CheckMul(height, other.height)),
|
||||
};
|
||||
}
|
||||
|
||||
template<typename TilMath>
|
||||
size scale(TilMath, const float scale) const
|
||||
constexpr size operator/(const size other) const
|
||||
{
|
||||
struct
|
||||
{
|
||||
float Width, Height;
|
||||
} sz;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _width).AssignIfValid(&sz.Width));
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(scale, _height).AssignIfValid(&sz.Height));
|
||||
|
||||
return til::size(TilMath(), sz);
|
||||
return size{
|
||||
details::extract(::base::CheckDiv(width, other.width)),
|
||||
details::extract(::base::CheckDiv(height, other.height)),
|
||||
};
|
||||
}
|
||||
|
||||
size operator/(const size& other) const
|
||||
template<typename TilMath, typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
|
||||
constexpr size scale(TilMath math, const T scale) const
|
||||
{
|
||||
ptrdiff_t width;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_width, other._width).AssignIfValid(&width));
|
||||
|
||||
ptrdiff_t height;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckDiv(_height, other._height).AssignIfValid(&height));
|
||||
|
||||
return size{ width, height };
|
||||
return til::size{
|
||||
math,
|
||||
width * scale,
|
||||
height * scale,
|
||||
};
|
||||
}
|
||||
|
||||
size divide_ceil(const size& other) const
|
||||
constexpr size divide_ceil(const size other) const
|
||||
{
|
||||
// Divide normally to get the floor.
|
||||
const size floor = *this / other;
|
||||
|
||||
ptrdiff_t adjWidth = 0;
|
||||
ptrdiff_t adjHeight = 0;
|
||||
CoordType adjWidth = 0;
|
||||
CoordType adjHeight = 0;
|
||||
|
||||
// Check for width remainder, anything not 0.
|
||||
// If we multiply the floored number with the other, it will equal
|
||||
// the old width if there was no remainder.
|
||||
if (other._width * floor._width != _width)
|
||||
if (other.width * floor.width != width)
|
||||
{
|
||||
// If there was any remainder,
|
||||
// Grow the magnitude by 1 in the
|
||||
// direction of the sign.
|
||||
if (floor.width() >= 0)
|
||||
if (floor.width >= 0)
|
||||
{
|
||||
++adjWidth;
|
||||
}
|
||||
@ -204,12 +116,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
// Check for height remainder, anything not 0.
|
||||
// If we multiply the floored number with the other, it will equal
|
||||
// the old width if there was no remainder.
|
||||
if (other._height * floor._height != _height)
|
||||
if (other.height * floor.height != height)
|
||||
{
|
||||
// If there was any remainder,
|
||||
// Grow the magnitude by 1 in the
|
||||
// direction of the sign.
|
||||
if (_height >= 0)
|
||||
if (height >= 0)
|
||||
{
|
||||
++adjHeight;
|
||||
}
|
||||
@ -222,86 +134,80 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
return floor + size{ adjWidth, adjHeight };
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t width() const noexcept
|
||||
template<typename T = CoordType>
|
||||
constexpr T narrow_width() const
|
||||
{
|
||||
return _width;
|
||||
return gsl::narrow<T>(width);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T width() const
|
||||
template<typename T = CoordType>
|
||||
constexpr T narrow_height() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
return gsl::narrow<T>(height);
|
||||
}
|
||||
|
||||
constexpr ptrdiff_t height() const noexcept
|
||||
template<typename T = CoordType>
|
||||
constexpr T area() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T height() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height()).AssignIfValid(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptrdiff_t area() const
|
||||
{
|
||||
ptrdiff_t result;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T area() const
|
||||
{
|
||||
T ret;
|
||||
THROW_HR_IF(E_ABORT, !base::CheckMul(_width, _height).AssignIfValid(&ret));
|
||||
return ret;
|
||||
return gsl::narrow<T>(static_cast<int64_t>(width) * static_cast<int64_t>(height));
|
||||
}
|
||||
|
||||
#ifdef _WINCONTYPES_
|
||||
operator COORD() const
|
||||
explicit constexpr size(const COORD other) noexcept :
|
||||
width{ other.X }, height{ other.Y }
|
||||
{
|
||||
COORD ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.X));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.Y));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr COORD to_win32_coord() const
|
||||
{
|
||||
return { gsl::narrow<short>(width), gsl::narrow<short>(height) };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINDEF_
|
||||
operator SIZE() const
|
||||
explicit constexpr size(const SIZE other) noexcept :
|
||||
width{ other.cx }, height{ other.cy }
|
||||
{
|
||||
SIZE ret;
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_width).AssignIfValid(&ret.cx));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(_height).AssignIfValid(&ret.cy));
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr SIZE to_win32_size() const noexcept
|
||||
{
|
||||
return { width, height };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DCOMMON_H_INCLUDED
|
||||
constexpr operator D2D1_SIZE_F() const noexcept
|
||||
template<typename TilMath>
|
||||
constexpr size(TilMath, const D2D1_SIZE_F other) :
|
||||
width{ TilMath::template cast<CoordType>(other.width) },
|
||||
height{ TilMath::template cast<CoordType>(other.height) }
|
||||
{
|
||||
return D2D1_SIZE_F{ gsl::narrow_cast<float>(_width), gsl::narrow_cast<float>(_height) };
|
||||
}
|
||||
|
||||
constexpr D2D1_SIZE_F to_d2d_size() const noexcept
|
||||
{
|
||||
return { static_cast<float>(width), static_cast<float>(height) };
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINRT_Windows_Foundation_H
|
||||
template<typename TilMath>
|
||||
constexpr size(TilMath, const winrt::Windows::Foundation::Size other) :
|
||||
width{ TilMath::template cast<CoordType>(other.Width) },
|
||||
height{ TilMath::template cast<CoordType>(other.Height) }
|
||||
{
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Size to_winrt_size() const noexcept
|
||||
{
|
||||
return { static_cast<float>(width), static_cast<float>(height) };
|
||||
}
|
||||
#endif
|
||||
|
||||
std::wstring to_string() const
|
||||
{
|
||||
return wil::str_printf<std::wstring>(L"[W:%td, H:%td]", width(), height());
|
||||
return wil::str_printf<std::wstring>(L"[W:%td, H:%td]", width, height);
|
||||
}
|
||||
|
||||
protected:
|
||||
ptrdiff_t _width;
|
||||
ptrdiff_t _height;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class ::SizeTests;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
@ -309,34 +215,34 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
namespace WEX::TestExecution
|
||||
{
|
||||
template<>
|
||||
class VerifyOutputTraits<::til::size>
|
||||
class VerifyOutputTraits<til::size>
|
||||
{
|
||||
public:
|
||||
static WEX::Common::NoThrowString ToString(const ::til::size& size)
|
||||
static WEX::Common::NoThrowString ToString(const til::size size)
|
||||
{
|
||||
return WEX::Common::NoThrowString(size.to_string().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class VerifyCompareTraits<::til::size, ::til::size>
|
||||
class VerifyCompareTraits<til::size, til::size>
|
||||
{
|
||||
public:
|
||||
static bool AreEqual(const ::til::size& expected, const ::til::size& actual) noexcept
|
||||
static bool AreEqual(const til::size expected, const til::size actual) noexcept
|
||||
{
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
static bool AreSame(const ::til::size& expected, const ::til::size& actual) noexcept
|
||||
static bool AreSame(const til::size expected, const til::size actual) noexcept
|
||||
{
|
||||
return &expected == &actual;
|
||||
}
|
||||
|
||||
static bool IsLessThan(const ::til::size& expectedLess, const ::til::size& expectedGreater) = delete;
|
||||
static bool IsLessThan(const til::size expectedLess, const til::size expectedGreater) = delete;
|
||||
|
||||
static bool IsGreaterThan(const ::til::size& expectedGreater, const ::til::size& expectedLess) = delete;
|
||||
static bool IsGreaterThan(const til::size expectedGreater, const til::size expectedLess) = delete;
|
||||
|
||||
static bool IsNull(const ::til::size& object) noexcept
|
||||
static bool IsNull(const til::size object) noexcept
|
||||
{
|
||||
return object == til::size{};
|
||||
}
|
||||
|
||||
@ -33,13 +33,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
using reverse_iterator = typename decltype(_array)::reverse_iterator;
|
||||
using const_reverse_iterator = typename decltype(_array)::const_reverse_iterator;
|
||||
|
||||
some() noexcept :
|
||||
constexpr some() noexcept :
|
||||
_array{},
|
||||
_used{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
some(std::initializer_list<T> init)
|
||||
constexpr some(std::initializer_list<T> init)
|
||||
{
|
||||
if (init.size() > N)
|
||||
{
|
||||
@ -60,13 +60,13 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void fill(const T& _Value)
|
||||
constexpr void fill(const T& _Value)
|
||||
{
|
||||
_array.fill(_Value);
|
||||
_used = N;
|
||||
}
|
||||
|
||||
void swap(some& _Other) noexcept(std::is_nothrow_swappable<T>::value)
|
||||
constexpr void swap(some& _Other) noexcept(std::is_nothrow_swappable<T>::value)
|
||||
{
|
||||
_array.swap(_Other._array);
|
||||
std::swap(_used, _Other._used);
|
||||
@ -163,7 +163,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
return _array.data();
|
||||
}
|
||||
|
||||
void push_back(const T& val)
|
||||
constexpr void push_back(const T& val)
|
||||
{
|
||||
if (_used >= N)
|
||||
{
|
||||
@ -175,7 +175,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
++_used;
|
||||
}
|
||||
|
||||
void push_back(T&& val)
|
||||
constexpr void push_back(T&& val)
|
||||
{
|
||||
if (_used >= N)
|
||||
{
|
||||
@ -187,7 +187,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
++_used;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
constexpr void pop_back()
|
||||
{
|
||||
if (_used <= 0)
|
||||
{
|
||||
@ -199,12 +199,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
til::at(_array, _used) = 0;
|
||||
}
|
||||
|
||||
[[noreturn]] void _invalidArg() const
|
||||
[[noreturn]] constexpr void _invalidArg() const
|
||||
{
|
||||
throw std::invalid_argument("invalid argument");
|
||||
}
|
||||
|
||||
[[noreturn]] void _outOfRange() const
|
||||
[[noreturn]] constexpr void _outOfRange() const
|
||||
{
|
||||
throw std::out_of_range("invalid some<T, N> subscript");
|
||||
}
|
||||
|
||||
@ -231,15 +231,10 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT BgfxEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT BgfxEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
SMALL_RECT r;
|
||||
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
|
||||
r.Top = 0;
|
||||
r.Left = 0;
|
||||
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
|
||||
|
||||
_dirtyArea = r;
|
||||
_dirtyArea.bottom = std::max(0, _displayHeight);
|
||||
_dirtyArea.right = std::max(0, _displayWidth);
|
||||
|
||||
area = { &_dirtyArea,
|
||||
1 };
|
||||
|
||||
@ -68,7 +68,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
||||
|
||||
@ -81,7 +81,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
LONG _displayHeight;
|
||||
LONG _displayWidth;
|
||||
til::rectangle _dirtyArea;
|
||||
til::rect _dirtyArea;
|
||||
|
||||
COORD _fontSize;
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// These were generated by tools\TestTableWriter\GenerateTests.ps1
|
||||
// Read tools\TestTableWriter\README.md for more details
|
||||
// Define a few helpful variables
|
||||
constexpr til::rectangle bufferSize{ 0, 0, 80, 300 };
|
||||
constexpr til::rect bufferSize{ 0, 0, 80, 300 };
|
||||
constexpr short midX{ 40 };
|
||||
constexpr short midY{ 150 };
|
||||
constexpr short midPopulatedY{ 75 };
|
||||
@ -28,7 +28,7 @@ constexpr auto docEndM1L{ point_offset_by_line(docEnd, bufferSize, -1) };
|
||||
constexpr auto docEndM5C{ point_offset_by_char(docEnd, bufferSize, -5) };
|
||||
constexpr auto docEndM5L{ point_offset_by_line(docEnd, bufferSize, -5) };
|
||||
constexpr auto docEndP1C{ point_offset_by_char(docEnd, bufferSize, 1) };
|
||||
constexpr til::point lastCharPosLeft{ bufferSize.left(), lastCharPos.y() };
|
||||
constexpr til::point lastCharPosLeft{ bufferSize.left, lastCharPos.y };
|
||||
constexpr auto lastCharPosM1C{ point_offset_by_char(lastCharPos, bufferSize, -1) };
|
||||
constexpr auto lastCharPosM1L{ point_offset_by_line(lastCharPos, bufferSize, -1) };
|
||||
constexpr auto lastCharPosM4C{ point_offset_by_char(lastCharPos, bufferSize, -4) };
|
||||
@ -39,7 +39,7 @@ constexpr auto lastCharPosP1C{ point_offset_by_char(lastCharPos, bufferSize, 1)
|
||||
constexpr auto lastCharPosP2C{ point_offset_by_char(lastCharPos, bufferSize, 2) };
|
||||
constexpr auto lastCharPosP5C{ point_offset_by_char(lastCharPos, bufferSize, 5) };
|
||||
constexpr auto lastCharPosP6C{ point_offset_by_char(lastCharPos, bufferSize, 6) };
|
||||
constexpr til::point midDocEndLeft{ bufferSize.left(), midDocEnd.y() };
|
||||
constexpr til::point midDocEndLeft{ bufferSize.left, midDocEnd.y };
|
||||
constexpr auto midDocEndM1C{ point_offset_by_char(midDocEnd, bufferSize, -1) };
|
||||
constexpr auto midDocEndM1L{ point_offset_by_line(midDocEnd, bufferSize, -1) };
|
||||
constexpr auto midDocEndM4C{ point_offset_by_char(midDocEnd, bufferSize, -4) };
|
||||
@ -51,7 +51,7 @@ constexpr auto midDocEndP2C{ point_offset_by_char(midDocEnd, bufferSize, 2) };
|
||||
constexpr auto midDocEndP5C{ point_offset_by_char(midDocEnd, bufferSize, 5) };
|
||||
constexpr auto midDocEndP6C{ point_offset_by_char(midDocEnd, bufferSize, 6) };
|
||||
constexpr auto midEmptySpaceP1C{ point_offset_by_char(midEmptySpace, bufferSize, 1) };
|
||||
constexpr til::point midHistoryLeft{ bufferSize.left(), midHistory.y() };
|
||||
constexpr til::point midHistoryLeft{ bufferSize.left, midHistory.y };
|
||||
constexpr auto midHistoryM1C{ point_offset_by_char(midHistory, bufferSize, -1) };
|
||||
constexpr auto midHistoryM1L{ point_offset_by_line(midHistory, bufferSize, -1) };
|
||||
constexpr auto midHistoryM4C{ point_offset_by_char(midHistory, bufferSize, -4) };
|
||||
@ -83,29 +83,29 @@ constexpr auto originP5C{ point_offset_by_char(origin, bufferSize, 5) };
|
||||
constexpr auto originP5L{ point_offset_by_line(origin, bufferSize, 5) };
|
||||
constexpr auto originP6C{ point_offset_by_char(origin, bufferSize, 6) };
|
||||
constexpr auto originP6L{ point_offset_by_line(origin, bufferSize, 6) };
|
||||
constexpr til::point segment0LmidTopP1L{ segment0, midTopP1L.y() };
|
||||
constexpr til::point segment1LmidDocEnd{ segment1, midDocEnd.y() };
|
||||
constexpr til::point segment1LmidHistory{ segment1, midHistory.y() };
|
||||
constexpr til::point segment1LmidTop{ segment1, midTop.y() };
|
||||
constexpr til::point segment1LmidTopP1L{ segment1, midTopP1L.y() };
|
||||
constexpr til::point segment2LmidDocEnd{ segment2, midDocEnd.y() };
|
||||
constexpr til::point segment2LmidDocEndM1L{ segment2, midDocEndM1L.y() };
|
||||
constexpr til::point segment2LmidHistory{ segment2, midHistory.y() };
|
||||
constexpr til::point segment2LmidHistoryM1L{ segment2, midHistoryM1L.y() };
|
||||
constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y() };
|
||||
constexpr til::point segment2LmidTop{ segment2, midTop.y() };
|
||||
constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y() };
|
||||
constexpr til::point segment3LmidDocEnd{ segment3, midDocEnd.y() };
|
||||
constexpr til::point segment3LmidDocEndM1L{ segment3, midDocEndM1L.y() };
|
||||
constexpr til::point segment3LmidHistory{ segment3, midHistory.y() };
|
||||
constexpr til::point segment3LmidHistoryM1L{ segment3, midHistoryM1L.y() };
|
||||
constexpr til::point segment3LmidHistoryP1L{ segment3, midHistoryP1L.y() };
|
||||
constexpr til::point segment3LmidTop{ segment3, midTop.y() };
|
||||
constexpr til::point segment3LmidTopP1L{ segment3, midTopP1L.y() };
|
||||
constexpr til::point segment4LlastCharPosM1L{ segment4, lastCharPosM1L.y() };
|
||||
constexpr til::point segment4LmidDocEnd{ segment4, midDocEnd.y() };
|
||||
constexpr til::point segment4LmidHistory{ segment4, midHistory.y() };
|
||||
constexpr til::point segment4LmidTop{ segment4, midTop.y() };
|
||||
constexpr til::point segment0LmidTopP1L{ segment0, midTopP1L.y };
|
||||
constexpr til::point segment1LmidDocEnd{ segment1, midDocEnd.y };
|
||||
constexpr til::point segment1LmidHistory{ segment1, midHistory.y };
|
||||
constexpr til::point segment1LmidTop{ segment1, midTop.y };
|
||||
constexpr til::point segment1LmidTopP1L{ segment1, midTopP1L.y };
|
||||
constexpr til::point segment2LmidDocEnd{ segment2, midDocEnd.y };
|
||||
constexpr til::point segment2LmidDocEndM1L{ segment2, midDocEndM1L.y };
|
||||
constexpr til::point segment2LmidHistory{ segment2, midHistory.y };
|
||||
constexpr til::point segment2LmidHistoryM1L{ segment2, midHistoryM1L.y };
|
||||
constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y };
|
||||
constexpr til::point segment2LmidTop{ segment2, midTop.y };
|
||||
constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y };
|
||||
constexpr til::point segment3LmidDocEnd{ segment3, midDocEnd.y };
|
||||
constexpr til::point segment3LmidDocEndM1L{ segment3, midDocEndM1L.y };
|
||||
constexpr til::point segment3LmidHistory{ segment3, midHistory.y };
|
||||
constexpr til::point segment3LmidHistoryM1L{ segment3, midHistoryM1L.y };
|
||||
constexpr til::point segment3LmidHistoryP1L{ segment3, midHistoryP1L.y };
|
||||
constexpr til::point segment3LmidTop{ segment3, midTop.y };
|
||||
constexpr til::point segment3LmidTopP1L{ segment3, midTopP1L.y };
|
||||
constexpr til::point segment4LlastCharPosM1L{ segment4, lastCharPosM1L.y };
|
||||
constexpr til::point segment4LmidDocEnd{ segment4, midDocEnd.y };
|
||||
constexpr til::point segment4LmidHistory{ segment4, midHistory.y };
|
||||
constexpr til::point segment4LmidTop{ segment4, midTop.y };
|
||||
struct GeneratedMovementTestInput
|
||||
{
|
||||
TextUnit unit;
|
||||
|
||||
@ -21,23 +21,23 @@ using namespace Microsoft::WRL;
|
||||
|
||||
using namespace Microsoft::Console::Interactivity::Win32;
|
||||
|
||||
static constexpr til::point point_offset_by_char(const til::point start, const til::rectangle bounds, ptrdiff_t amt)
|
||||
static constexpr til::point point_offset_by_char(const til::point start, const til::rect& bounds, til::CoordType amt)
|
||||
{
|
||||
ptrdiff_t pos_x = start.x();
|
||||
ptrdiff_t pos_y = start.y();
|
||||
auto pos_x = start.x;
|
||||
auto pos_y = start.y;
|
||||
while (amt != 0)
|
||||
{
|
||||
if (amt > 0)
|
||||
{
|
||||
if (pos_x == bounds.left() && pos_y == bounds.bottom())
|
||||
if (pos_x == bounds.left && pos_y == bounds.bottom)
|
||||
{
|
||||
// end exclusive --> can't move any more
|
||||
break;
|
||||
}
|
||||
else if (pos_x == bounds.right() - 1)
|
||||
else if (pos_x == bounds.right - 1)
|
||||
{
|
||||
// right boundary --> wrap
|
||||
pos_x = bounds.left();
|
||||
pos_x = bounds.left;
|
||||
++pos_y;
|
||||
}
|
||||
else
|
||||
@ -49,15 +49,15 @@ static constexpr til::point point_offset_by_char(const til::point start, const t
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos_x == bounds.left() && pos_y == bounds.top())
|
||||
if (pos_x == bounds.left && pos_y == bounds.top)
|
||||
{
|
||||
// origin --> can't move any more
|
||||
break;
|
||||
}
|
||||
else if (pos_x == bounds.left())
|
||||
else if (pos_x == bounds.left)
|
||||
{
|
||||
// left boundary --> wrap
|
||||
pos_x = bounds.right() - 1;
|
||||
pos_x = bounds.right - 1;
|
||||
--pos_y;
|
||||
}
|
||||
else
|
||||
@ -71,16 +71,16 @@ static constexpr til::point point_offset_by_char(const til::point start, const t
|
||||
return { pos_x, pos_y };
|
||||
}
|
||||
|
||||
static constexpr til::point point_offset_by_line(const til::point start, const til::rectangle bounds, ptrdiff_t amt)
|
||||
static constexpr til::point point_offset_by_line(const til::point start, const til::rect& bounds, til::CoordType amt)
|
||||
{
|
||||
// X = left boundary for UIA
|
||||
ptrdiff_t pos_x = bounds.left();
|
||||
ptrdiff_t pos_y = start.y();
|
||||
auto pos_x = bounds.left;
|
||||
auto pos_y = start.y;
|
||||
while (amt != 0)
|
||||
{
|
||||
if (amt > 0)
|
||||
{
|
||||
if (pos_y == bounds.bottom() + 1)
|
||||
if (pos_y == bounds.bottom + 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -92,7 +92,7 @@ static constexpr til::point point_offset_by_line(const til::point start, const t
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos_y == bounds.top())
|
||||
if (pos_y == bounds.top)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -399,8 +399,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(°enerate,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
origin));
|
||||
origin.to_win32_coord(),
|
||||
origin.to_win32_coord()));
|
||||
VERIFY_IS_TRUE(degenerate->IsDegenerate());
|
||||
VERIFY_ARE_EQUAL(degenerate->_start, degenerate->_end);
|
||||
|
||||
@ -410,8 +410,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(¬Degenerate,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
end));
|
||||
origin.to_win32_coord(),
|
||||
end.to_win32_coord()));
|
||||
VERIFY_IS_FALSE(notDegenerate->IsDegenerate());
|
||||
VERIFY_ARE_NOT_EQUAL(notDegenerate->_start, notDegenerate->_end);
|
||||
}
|
||||
@ -422,8 +422,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr1,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
origin));
|
||||
origin.to_win32_coord(),
|
||||
origin.to_win32_coord()));
|
||||
|
||||
// utr2 initialized to have the same start/end as utr1
|
||||
Microsoft::WRL::ComPtr<ITextRangeProvider> utr2;
|
||||
@ -439,8 +439,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr2,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
end));
|
||||
origin.to_win32_coord(),
|
||||
end.to_win32_coord()));
|
||||
|
||||
Log::Comment(L"_end is different");
|
||||
THROW_IF_FAILED(utr1->Compare(utr2.Get(), &comparison));
|
||||
@ -453,8 +453,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr1,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
origin));
|
||||
origin.to_win32_coord(),
|
||||
origin.to_win32_coord()));
|
||||
|
||||
Microsoft::WRL::ComPtr<ITextRangeProvider> utr2;
|
||||
THROW_IF_FAILED(utr1->Clone(&utr2));
|
||||
@ -475,8 +475,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr2,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
end));
|
||||
origin.to_win32_coord(),
|
||||
end.to_win32_coord()));
|
||||
|
||||
Log::Comment(L"_start should match");
|
||||
THROW_IF_FAILED(utr1->CompareEndpoints(TextPatternRangeEndpoint_Start, utr2.Get(), TextPatternRangeEndpoint_Start, &comparison));
|
||||
@ -659,8 +659,8 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&target,
|
||||
_pUiaData,
|
||||
&_dummyProvider,
|
||||
origin,
|
||||
origin));
|
||||
origin.to_win32_coord(),
|
||||
origin.to_win32_coord()));
|
||||
};
|
||||
|
||||
Log::Comment(L"Move target's end to utr1's start");
|
||||
@ -669,7 +669,7 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_End,
|
||||
utr.Get(),
|
||||
TextPatternRangeEndpoint_Start));
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin);
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin.to_win32_coord());
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_End), utr->GetEndpoint(TextPatternRangeEndpoint_Start));
|
||||
}
|
||||
|
||||
@ -679,7 +679,7 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_End,
|
||||
utr.Get(),
|
||||
TextPatternRangeEndpoint_End));
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin);
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_Start), origin.to_win32_coord());
|
||||
VERIFY_ARE_EQUAL(target->GetEndpoint(TextPatternRangeEndpoint_End), utr->GetEndpoint(TextPatternRangeEndpoint_End));
|
||||
|
||||
THROW_IF_FAILED(target->MoveEndpointByRange(TextPatternRangeEndpoint_Start,
|
||||
@ -738,7 +738,7 @@ class UiaTextRangeTests
|
||||
|
||||
// GH#6986: This is used as the "end of the buffer" to help screen readers run faster
|
||||
// instead of parsing through thousands of empty lines of text.
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 };
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow<short>(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) };
|
||||
|
||||
// clang-format off
|
||||
const std::vector<MoveTest> testData
|
||||
@ -798,8 +798,8 @@ class UiaTextRangeTests
|
||||
-5,
|
||||
{
|
||||
-5,
|
||||
{lastColumnIndex - 4, 0},
|
||||
{lastColumnIndex - 3, 0}
|
||||
{gsl::narrow<short>(lastColumnIndex - 4), 0},
|
||||
{gsl::narrow<short>(lastColumnIndex - 3), 0}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -826,7 +826,7 @@ class UiaTextRangeTests
|
||||
|
||||
// GH#6986: This is used as the "end of the buffer" to help screen readers run faster
|
||||
// instead of parsing through thousands of empty lines of text.
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 };
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow<short>(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) };
|
||||
|
||||
// clang-format off
|
||||
const std::vector<MoveTest> testData
|
||||
@ -1060,7 +1060,7 @@ class UiaTextRangeTests
|
||||
|
||||
// GH#6986: This is used as the "end of the buffer" to help screen readers run faster
|
||||
// instead of parsing through thousands of empty lines of text.
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 };
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow<short>(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) };
|
||||
|
||||
// clang-format off
|
||||
const std::vector<MoveEndpointTest> testData
|
||||
@ -1134,7 +1134,7 @@ class UiaTextRangeTests
|
||||
MoveEndpointTest{
|
||||
L"can't move _end forwards when it's on the bottom row (past doc end)",
|
||||
{0, 0},
|
||||
{lastColumnIndex - 3, bottomRow},
|
||||
{gsl::narrow<short>(lastColumnIndex - 3), bottomRow},
|
||||
1,
|
||||
TextPatternRangeEndpoint_End,
|
||||
0,
|
||||
@ -1145,7 +1145,7 @@ class UiaTextRangeTests
|
||||
MoveEndpointTest{
|
||||
L"can't move _end forwards when it's at the end of the buffer already (past doc end)",
|
||||
{0, 0},
|
||||
{0, bottomRow+1},
|
||||
{0, gsl::narrow<short>(bottomRow + 1)},
|
||||
1,
|
||||
TextPatternRangeEndpoint_End,
|
||||
0,
|
||||
@ -1167,7 +1167,7 @@ class UiaTextRangeTests
|
||||
MoveEndpointTest{
|
||||
L"moving _end backward when it's already on the top row creates a degenerate range at the document start",
|
||||
{4, 0},
|
||||
{lastColumnIndex - 5, 0},
|
||||
{gsl::narrow<short>(lastColumnIndex - 5), 0},
|
||||
-1,
|
||||
TextPatternRangeEndpoint_End,
|
||||
-1,
|
||||
@ -1198,7 +1198,7 @@ class UiaTextRangeTests
|
||||
|
||||
// GH#6986: This is used as the "end of the buffer" to help screen readers run faster
|
||||
// instead of parsing through thousands of empty lines of text.
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 };
|
||||
const COORD documentEnd{ _pTextBuffer->GetSize().Left(), gsl::narrow<short>(_pTextBuffer->GetLastNonSpaceCharacter().Y + 1) };
|
||||
|
||||
// clang-format off
|
||||
const std::vector<MoveEndpointTest> testData =
|
||||
@ -1232,7 +1232,7 @@ class UiaTextRangeTests
|
||||
MoveEndpointTest{
|
||||
L"can't move _end forward when it's already at the end of the buffer (past doc end)",
|
||||
{3, 2},
|
||||
{0, bottomRow+1},
|
||||
{0, gsl::narrow<short>(bottomRow + 1)},
|
||||
1,
|
||||
TextPatternRangeEndpoint_End,
|
||||
{
|
||||
@ -1320,10 +1320,10 @@ class UiaTextRangeTests
|
||||
Log::Comment(NoThrowString().Format(L"%s", toString(static_cast<TextUnit>(textUnit))));
|
||||
|
||||
// Create a degenerate UTR at EndExclusive
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, bufferEnd, endExclusive));
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, bufferEnd.to_win32_coord(), endExclusive.to_win32_coord()));
|
||||
THROW_IF_FAILED(utr->ExpandToEnclosingUnit(static_cast<TextUnit>(textUnit)));
|
||||
|
||||
VERIFY_ARE_EQUAL(documentEnd, til::point{ utr->_end });
|
||||
VERIFY_ARE_EQUAL(documentEnd, utr->_end);
|
||||
}
|
||||
|
||||
TEST_METHOD(MovementAtExclusiveEnd)
|
||||
@ -1335,16 +1335,16 @@ class UiaTextRangeTests
|
||||
// write "temp" at (2,2)
|
||||
_pTextBuffer->Reset();
|
||||
const til::point writeTarget{ 2, 2 };
|
||||
_pTextBuffer->Write({ L"temp" }, writeTarget);
|
||||
_pTextBuffer->Write({ L"temp" }, writeTarget.to_win32_coord());
|
||||
|
||||
// GH#6986: This is used as the "end of the buffer" to help screen readers run faster
|
||||
// instead of parsing through thousands of empty lines of text.
|
||||
const COORD documentEndInclusive{ base::ClampSub<short, short>(static_cast<short>(bufferSize.right()), 1), _pTextBuffer->GetLastNonSpaceCharacter().Y };
|
||||
const COORD documentEndExclusive{ static_cast<short>(bufferSize.left()), base::ClampAdd(documentEndInclusive.Y, 1) };
|
||||
const til::point documentEndInclusive{ base::ClampSub<short, short>(static_cast<short>(bufferSize.right), 1), _pTextBuffer->GetLastNonSpaceCharacter().Y };
|
||||
const til::point documentEndExclusive{ static_cast<short>(bufferSize.left), base::ClampAdd(documentEndInclusive.y, 1) };
|
||||
|
||||
const COORD lastLineStart{ static_cast<short>(bufferSize.left()), documentEndInclusive.Y };
|
||||
const auto secondToLastLinePos{ point_offset_by_line(lastLineStart, bufferSize, -1) };
|
||||
const COORD secondToLastCharacterPos{ documentEndInclusive.X - 1, documentEndInclusive.Y };
|
||||
const til::point lastLineStart{ static_cast<short>(bufferSize.left), documentEndInclusive.y };
|
||||
const til::point secondToLastLinePos{ point_offset_by_line(til::point{ lastLineStart }, bufferSize, -1) };
|
||||
const til::point secondToLastCharacterPos{ documentEndInclusive.x - 1, documentEndInclusive.y };
|
||||
|
||||
// Iterate over each TextUnit. If we don't support
|
||||
// the given TextUnit, we're supposed to fallback
|
||||
@ -1368,22 +1368,22 @@ class UiaTextRangeTests
|
||||
Log::Comment(NoThrowString().Format(L"Forward by %s", toString(textUnit)));
|
||||
|
||||
// Create an UTR at EndExclusive
|
||||
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
|
||||
const auto utrEnd{ atDocumentEnd ? documentEndExclusive : til::point{ endExclusive } };
|
||||
if (degenerate)
|
||||
{
|
||||
// UTR: (exclusive, exclusive) range
|
||||
const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
|
||||
const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// UTR: (inclusive, exclusive) range
|
||||
const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast<COORD>(endInclusive) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
|
||||
const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord()));
|
||||
}
|
||||
THROW_IF_FAILED(utr->Move(textUnit, 1, &moveAmt));
|
||||
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end);
|
||||
VERIFY_ARE_EQUAL(0, moveAmt);
|
||||
|
||||
// Verify expansion works properly
|
||||
@ -1391,37 +1391,37 @@ class UiaTextRangeTests
|
||||
THROW_IF_FAILED(utr->ExpandToEnclosingUnit(textUnit));
|
||||
if (textUnit <= TextUnit::TextUnit_Character)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(documentEndInclusive, utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(documentEndInclusive.to_win32_coord(), utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end);
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Word)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(writeTarget, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(writeTarget.to_win32_coord(), utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end);
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Line)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(lastLineStart, utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(lastLineStart.to_win32_coord(), utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end);
|
||||
}
|
||||
else // textUnit <= TextUnit::TextUnit_Document:
|
||||
{
|
||||
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(origin.to_win32_coord(), utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndExclusive.to_win32_coord(), utr->_end);
|
||||
}
|
||||
|
||||
// reset the UTR
|
||||
if (degenerate)
|
||||
{
|
||||
// UTR: (exclusive, exclusive) range
|
||||
const auto utrStart{ atDocumentEnd ? documentEndExclusive : static_cast<COORD>(endExclusive) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
|
||||
const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// UTR: (inclusive, exclusive) range
|
||||
const auto utrStart{ atDocumentEnd ? documentEndInclusive : static_cast<COORD>(endInclusive) };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
|
||||
const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart.to_win32_coord(), utrEnd.to_win32_coord()));
|
||||
}
|
||||
|
||||
// Verify that moving backwards still works properly
|
||||
@ -1435,8 +1435,8 @@ class UiaTextRangeTests
|
||||
// - degenerate --> it moves with _start to stay degenerate
|
||||
// - !degenerate --> it excludes the last char, to select the second to last char
|
||||
VERIFY_ARE_EQUAL(-1, moveAmt);
|
||||
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? documentEndInclusive : secondToLastCharacterPos, utr->_start);
|
||||
VERIFY_ARE_EQUAL(documentEndInclusive, utr->_end);
|
||||
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? documentEndInclusive : secondToLastCharacterPos, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(documentEndInclusive, til::point{ utr->_end });
|
||||
}
|
||||
else if (textUnit <= TextUnit::TextUnit_Word)
|
||||
{
|
||||
@ -1448,7 +1448,7 @@ class UiaTextRangeTests
|
||||
{
|
||||
VERIFY_ARE_EQUAL(-1, moveAmt);
|
||||
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? til::point{ lastLineStart } : secondToLastLinePos, til::point{ utr->_start });
|
||||
VERIFY_ARE_EQUAL(lastLineStart, utr->_end);
|
||||
VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_end });
|
||||
}
|
||||
else // textUnit <= TextUnit::TextUnit_Document:
|
||||
{
|
||||
@ -1464,11 +1464,11 @@ class UiaTextRangeTests
|
||||
|
||||
const auto originExclusive{ point_offset_by_char(origin, bufferSize, 1) };
|
||||
|
||||
_pTextBuffer->Write({ L"My name is Carlos" }, origin);
|
||||
_pTextBuffer->Write({ L"My name is Carlos" }, origin.to_win32_coord());
|
||||
|
||||
// Create degenerate UTR at origin
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> utr;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, origin, origin));
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, origin.to_win32_coord(), origin.to_win32_coord()));
|
||||
|
||||
// move forward by a word
|
||||
int moveAmt;
|
||||
@ -1503,17 +1503,17 @@ class UiaTextRangeTests
|
||||
const auto viewportSize{ _pUiaData->GetViewport() };
|
||||
|
||||
const std::vector<ScrollTest> testData{
|
||||
{ L"Origin", gsl::narrow<short>(bufferSize.top()) },
|
||||
{ L"ViewportHeight From Top - 1", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Top", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() },
|
||||
{ L"ViewportHeight From Top + 1", base::ClampedNumeric<short>(bufferSize.top()) + viewportSize.Height() + 1 },
|
||||
{ L"ViewportHeight From Bottom - 1", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() - 2 },
|
||||
{ L"ViewportHeight From Bottom", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Bottom + 1", base::ClampedNumeric<short>(bufferSize.bottom()) - viewportSize.Height() + 1 },
|
||||
{ L"Origin", gsl::narrow<short>(bufferSize.top) },
|
||||
{ L"ViewportHeight From Top - 1", base::ClampedNumeric<short>(bufferSize.top) + viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Top", base::ClampedNumeric<short>(bufferSize.top) + viewportSize.Height() },
|
||||
{ L"ViewportHeight From Top + 1", base::ClampedNumeric<short>(bufferSize.top) + viewportSize.Height() + 1 },
|
||||
{ L"ViewportHeight From Bottom - 1", base::ClampedNumeric<short>(bufferSize.bottom) - viewportSize.Height() - 2 },
|
||||
{ L"ViewportHeight From Bottom", base::ClampedNumeric<short>(bufferSize.bottom) - viewportSize.Height() - 1 },
|
||||
{ L"ViewportHeight From Bottom + 1", base::ClampedNumeric<short>(bufferSize.bottom) - viewportSize.Height() + 1 },
|
||||
|
||||
// GH#7839: ExclusiveEnd is a non-existent space,
|
||||
// so scrolling to it when !alignToTop used to crash
|
||||
{ L"Exclusive End", gsl::narrow<short>(bufferSize.bottom()) }
|
||||
{ L"Exclusive End", gsl::narrow<short>(bufferSize.bottom) }
|
||||
};
|
||||
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
@ -1527,8 +1527,8 @@ class UiaTextRangeTests
|
||||
for (const auto test : testData)
|
||||
{
|
||||
Log::Comment(test.comment.c_str());
|
||||
const til::point pos{ bufferSize.left(), test.yPos };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, pos, pos));
|
||||
const til::point pos{ bufferSize.left, test.yPos };
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, pos.to_win32_coord(), pos.to_win32_coord()));
|
||||
VERIFY_SUCCEEDED(utr->ScrollIntoView(alignToTop));
|
||||
}
|
||||
}
|
||||
@ -1856,7 +1856,7 @@ class UiaTextRangeTests
|
||||
const auto secondChar{ point_offset_by_char(origin, bufferSize, 2) };
|
||||
const auto fifthChar{ point_offset_by_char(origin, bufferSize, 5) };
|
||||
const auto sixthChar{ point_offset_by_char(origin, bufferSize, 6) };
|
||||
const til::point documentEnd{ bufferSize.left(), (bufferSize.height() / 2) + 1 };
|
||||
const til::point documentEnd{ bufferSize.left, (bufferSize.height() / 2) + 1 };
|
||||
|
||||
// Populate buffer
|
||||
// Split the line into 5 segments alternating between "X" and whitespace
|
||||
@ -1868,9 +1868,9 @@ class UiaTextRangeTests
|
||||
// |_______________|
|
||||
{
|
||||
short i = 0;
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(origin) };
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(origin.to_win32_coord()) };
|
||||
const auto segment{ bufferSize.width() / 5 };
|
||||
while (iter.Pos() != documentEnd)
|
||||
while (iter.Pos() != documentEnd.to_win32_coord())
|
||||
{
|
||||
bool fill{ true };
|
||||
if (i % segment == 0)
|
||||
@ -1936,12 +1936,12 @@ class UiaTextRangeTests
|
||||
// +------------------------------+
|
||||
{
|
||||
short i = 0;
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin()) };
|
||||
auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin().to_win32_coord()) };
|
||||
const auto segment{ bufferSize.width() / 10 };
|
||||
bool fill{ true };
|
||||
while (iter.Pos() != docEnd)
|
||||
while (iter.Pos() != docEnd.to_win32_coord())
|
||||
{
|
||||
if (iter.Pos().X == bufferSize.left())
|
||||
if (iter.Pos().X == bufferSize.left)
|
||||
{
|
||||
fill = true;
|
||||
}
|
||||
@ -1977,7 +1977,7 @@ class UiaTextRangeTests
|
||||
{
|
||||
Microsoft::WRL::ComPtr<UiaTextRange> utr;
|
||||
int amountMoved;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, testCase.input.start, testCase.input.end));
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, testCase.input.start.to_win32_coord(), testCase.input.end.to_win32_coord()));
|
||||
THROW_IF_FAILED(utr->Move(testCase.input.unit, testCase.input.moveAmount, &amountMoved));
|
||||
|
||||
VERIFY_ARE_EQUAL(testCase.expected.moveAmount, amountMoved);
|
||||
|
||||
@ -232,7 +232,7 @@ try
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
[[nodiscard]] HRESULT AtlasEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT AtlasEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
area = gsl::span{ &_api.dirtyRect, 1 };
|
||||
return S_OK;
|
||||
|
||||
@ -377,11 +377,11 @@ try
|
||||
}
|
||||
}
|
||||
|
||||
_api.dirtyRect = til::rectangle{
|
||||
static_cast<ptrdiff_t>(0),
|
||||
static_cast<ptrdiff_t>(_api.invalidatedRows.x),
|
||||
static_cast<ptrdiff_t>(_api.cellCount.x),
|
||||
static_cast<ptrdiff_t>(_api.invalidatedRows.y),
|
||||
_api.dirtyRect = til::rect{
|
||||
0,
|
||||
_api.invalidatedRows.x,
|
||||
_api.cellCount.x,
|
||||
_api.invalidatedRows.y,
|
||||
};
|
||||
|
||||
return S_OK;
|
||||
|
||||
@ -49,7 +49,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT UpdateDpi(int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept override;
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateTitle(std::wstring_view newTitle) noexcept override;
|
||||
@ -741,7 +741,7 @@ namespace Microsoft::Console::Render
|
||||
u32 selectionColor = 0x7fffffff;
|
||||
|
||||
// dirtyRect is a computed value based on invalidatedRows.
|
||||
til::rectangle dirtyRect;
|
||||
til::rect dirtyRect;
|
||||
// These "invalidation" fields are reset in EndPaint()
|
||||
u16r invalidatedCursorArea = invalidatedAreaNone;
|
||||
u16x2 invalidatedRows = invalidatedRowsNone; // x is treated as "top" and y as "bottom"
|
||||
|
||||
@ -107,8 +107,8 @@ FontResource::operator HFONT()
|
||||
|
||||
void FontResource::_regenerateFont()
|
||||
{
|
||||
const auto targetWidth = _targetSize.width<WORD>();
|
||||
const auto targetHeight = _targetSize.height<WORD>();
|
||||
const auto targetWidth = _targetSize.narrow_width<WORD>();
|
||||
const auto targetHeight = _targetSize.narrow_height<WORD>();
|
||||
const auto charSizeInBytes = (targetWidth + 7) / 8 * targetHeight;
|
||||
|
||||
const DWORD fontBitmapSize = charSizeInBytes * CHAR_COUNT;
|
||||
@ -171,10 +171,10 @@ void FontResource::_regenerateFont()
|
||||
|
||||
void FontResource::_resizeBitPattern(gsl::span<byte> targetBuffer)
|
||||
{
|
||||
auto sourceWidth = _sourceSize.width<int>();
|
||||
auto targetWidth = _targetSize.width<int>();
|
||||
const auto sourceHeight = _sourceSize.height<int>();
|
||||
const auto targetHeight = _targetSize.height<int>();
|
||||
auto sourceWidth = _sourceSize.width;
|
||||
auto targetWidth = _targetSize.width;
|
||||
const auto sourceHeight = _sourceSize.height;
|
||||
const auto targetHeight = _targetSize.height;
|
||||
|
||||
// If the text in the font is not perfectly centered, the _centeringHint
|
||||
// gives us the offset needed to correct that misalignment. So to ensure
|
||||
@ -214,7 +214,7 @@ void FontResource::_resizeBitPattern(gsl::span<byte> targetBuffer)
|
||||
|
||||
// Once we've calculated the scaling increments, taking the centering hint
|
||||
// into account, we reset the target width back to its original value.
|
||||
targetWidth = _targetSize.width<int>();
|
||||
targetWidth = _targetSize.width;
|
||||
|
||||
auto targetBufferPointer = targetBuffer.begin();
|
||||
for (auto ch = 0; ch < CHAR_COUNT; ch++)
|
||||
|
||||
@ -354,17 +354,17 @@ void Renderer::TriggerSelection()
|
||||
// Restrict all previous selection rectangles to inside the current viewport bounds
|
||||
for (auto& sr : _previousSelection)
|
||||
{
|
||||
// Make the exclusive SMALL_RECT into a til::rectangle.
|
||||
til::rectangle rc{ Viewport::FromExclusive(sr).ToInclusive() };
|
||||
// Make the exclusive SMALL_RECT into a til::rect.
|
||||
til::rect rc{ Viewport::FromExclusive(sr).ToInclusive() };
|
||||
|
||||
// Make a viewport representing the coordinates that are currently presentable.
|
||||
const til::rectangle viewport{ til::size{ _pData->GetViewport().Dimensions() } };
|
||||
const til::rect viewport{ til::size{ _pData->GetViewport().Dimensions() } };
|
||||
|
||||
// Intersect them so we only invalidate things that are still visible.
|
||||
rc &= viewport;
|
||||
|
||||
// Convert back into the exclusive SMALL_RECT and store in the vector.
|
||||
sr = Viewport::FromInclusive(rc).ToExclusive();
|
||||
sr = Viewport::FromInclusive(rc.to_small_rect()).ToExclusive();
|
||||
}
|
||||
|
||||
FOREACH_ENGINE(pEngine)
|
||||
@ -408,7 +408,7 @@ bool Renderer::_CheckViewportAndScroll()
|
||||
LOG_IF_FAILED(engine->InvalidateScroll(&coordDelta));
|
||||
}
|
||||
|
||||
_ScrollPreviousSelection(coordDelta);
|
||||
_ScrollPreviousSelection(til::point{ coordDelta });
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -443,7 +443,7 @@ void Renderer::TriggerScroll(const COORD* const pcoordDelta)
|
||||
LOG_IF_FAILED(pEngine->InvalidateScroll(pcoordDelta));
|
||||
}
|
||||
|
||||
_ScrollPreviousSelection(*pcoordDelta);
|
||||
_ScrollPreviousSelection(til::point{ *pcoordDelta });
|
||||
|
||||
_NotifyPaintFrame();
|
||||
}
|
||||
@ -665,7 +665,7 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
|
||||
// This is effectively the number of cells on the visible screen that need to be redrawn.
|
||||
// The origin is always 0, 0 because it represents the screen itself, not the underlying buffer.
|
||||
gsl::span<const til::rectangle> dirtyAreas;
|
||||
gsl::span<const til::rect> dirtyAreas;
|
||||
LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas));
|
||||
|
||||
// This is to make sure any transforms are reset when this paint is finished.
|
||||
@ -676,12 +676,12 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
for (const auto& dirtyRect : dirtyAreas)
|
||||
{
|
||||
// Shortcut: don't bother redrawing if the width is 0.
|
||||
if (dirtyRect.left() == dirtyRect.right())
|
||||
if (dirtyRect.left == dirtyRect.right)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto dirty = Viewport::FromInclusive(dirtyRect);
|
||||
auto dirty = Viewport::FromInclusive(dirtyRect.to_small_rect());
|
||||
|
||||
// Shift the origin of the dirty region to match the underlying buffer so we can
|
||||
// compare the two regions directly for intersection.
|
||||
@ -805,7 +805,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// We also accumulate clusters according to regex patterns
|
||||
do
|
||||
{
|
||||
COORD thisPoint{ screenPoint.X + gsl::narrow<SHORT>(cols), screenPoint.Y };
|
||||
COORD thisPoint{ gsl::narrow<SHORT>(screenPoint.X + cols), screenPoint.Y };
|
||||
const auto thisPointPatterns = _pData->GetPatternId(thisPoint);
|
||||
const auto thisUsingSoftFont = s_IsSoftFontChar(it->Chars(), _firstSoftFontChar, _lastSoftFontChar);
|
||||
const auto changedPatternOrFont = patternIds != thisPointPatterns || usingSoftFont != thisUsingSoftFont;
|
||||
@ -1113,12 +1113,13 @@ void Renderer::_PaintOverlay(IRenderEngine& engine,
|
||||
// Set it up in a Viewport helper structure and trim it the IME viewport to be within the full console viewport.
|
||||
Viewport viewConv = Viewport::FromInclusive(srCaView);
|
||||
|
||||
gsl::span<const til::rectangle> dirtyAreas;
|
||||
gsl::span<const til::rect> dirtyAreas;
|
||||
LOG_IF_FAILED(engine.GetDirtyArea(dirtyAreas));
|
||||
|
||||
for (SMALL_RECT srDirty : dirtyAreas)
|
||||
for (const auto& rect : dirtyAreas)
|
||||
{
|
||||
// Dirty is an inclusive rectangle, but oddly enough the IME was an exclusive one, so correct it.
|
||||
auto srDirty = rect.to_small_rect();
|
||||
srDirty.Bottom++;
|
||||
srDirty.Right++;
|
||||
|
||||
@ -1173,7 +1174,7 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine)
|
||||
{
|
||||
try
|
||||
{
|
||||
gsl::span<const til::rectangle> dirtyAreas;
|
||||
gsl::span<const til::rect> dirtyAreas;
|
||||
LOG_IF_FAILED(pEngine->GetDirtyArea(dirtyAreas));
|
||||
|
||||
// Get selection rectangles
|
||||
@ -1185,7 +1186,7 @@ void Renderer::_PaintSelection(_In_ IRenderEngine* const pEngine)
|
||||
// Make a copy as `TrimToViewport` will manipulate it and
|
||||
// can destroy it for the next dirtyRect to test against.
|
||||
auto rectCopy = rect;
|
||||
Viewport dirtyView = Viewport::FromInclusive(dirtyRect);
|
||||
Viewport dirtyView = Viewport::FromInclusive(dirtyRect.to_small_rect());
|
||||
if (dirtyView.TrimToViewport(&rectCopy))
|
||||
{
|
||||
LOG_IF_FAILED(pEngine->PaintSelection(rectCopy));
|
||||
@ -1280,13 +1281,13 @@ void Renderer::_ScrollPreviousSelection(const til::point delta)
|
||||
for (auto& sr : _previousSelection)
|
||||
{
|
||||
// Get a rectangle representing this piece of the selection.
|
||||
til::rectangle rc = Viewport::FromExclusive(sr).ToInclusive();
|
||||
til::rect rc{ Viewport::FromExclusive(sr).ToInclusive() };
|
||||
|
||||
// Offset the entire existing rectangle by the delta.
|
||||
rc += delta;
|
||||
|
||||
// Store it back into the vector.
|
||||
sr = Viewport::FromInclusive(rc).ToExclusive();
|
||||
sr = Viewport::FromInclusive(rc.to_small_rect()).ToExclusive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<DxFontRenderData*> const fontRe
|
||||
_runs{},
|
||||
_breakpoints{},
|
||||
_runIndex{ 0 },
|
||||
_width{ gsl::narrow_cast<size_t>(fontRenderData->GlyphCell().width()) },
|
||||
_width{ gsl::narrow_cast<size_t>(fontRenderData->GlyphCell().width) },
|
||||
_isEntireTextSimple{ false }
|
||||
{
|
||||
_localeName.resize(gsl::narrow_cast<size_t>(fontRenderData->DefaultTextFormat()->GetLocaleNameLength()) + 1); // +1 for null
|
||||
|
||||
@ -273,18 +273,17 @@ try
|
||||
// TODO GH#6338: Add support for `"cursorTextColor": null` for letting the
|
||||
// cursor draw on top again.
|
||||
|
||||
// **MATH** PHASE
|
||||
const til::size glyphSize{ til::math::flooring,
|
||||
drawingContext.cellSize.width,
|
||||
drawingContext.cellSize.height };
|
||||
|
||||
// Create rectangular block representing where the cursor can fill.
|
||||
D2D1_RECT_F rect = til::rectangle{ til::point{ options.coordCursor } }.scale_up(glyphSize);
|
||||
D2D1_RECT_F rect;
|
||||
rect.left = options.coordCursor.X * drawingContext.cellSize.width;
|
||||
rect.top = options.coordCursor.Y * drawingContext.cellSize.height;
|
||||
rect.right = rect.left + drawingContext.cellSize.width;
|
||||
rect.bottom = rect.top + drawingContext.cellSize.height;
|
||||
|
||||
// If we're double-width, make it one extra glyph wider
|
||||
if (options.fIsDoubleWidth)
|
||||
{
|
||||
rect.right += glyphSize.width();
|
||||
rect.right += drawingContext.cellSize.width;
|
||||
}
|
||||
|
||||
// If the cursor isn't within the bounds of this current run of text, do nothing.
|
||||
@ -303,7 +302,7 @@ try
|
||||
{
|
||||
// Enforce min/max cursor height
|
||||
ULONG ulHeight = std::clamp(options.ulCursorHeightPercent, MinCursorHeightPercent, MaxCursorHeightPercent);
|
||||
ulHeight = (glyphSize.height<ULONG>() * ulHeight) / 100;
|
||||
ulHeight = gsl::narrow_cast<ULONG>(drawingContext.cellSize.height * ulHeight) / 100;
|
||||
ulHeight = std::max(ulHeight, MinCursorHeightPixels); // No smaller than 1px
|
||||
|
||||
rect.top = rect.bottom - ulHeight;
|
||||
|
||||
@ -114,7 +114,7 @@ DxFontRenderData::DxFontRenderData(::Microsoft::WRL::ComPtr<IDWriteFactory1> dwr
|
||||
if (!_boxDrawingEffect)
|
||||
{
|
||||
// Calculate and cache the box effect for the base font. Scale is 1.0f because the base font is exactly the scale we want already.
|
||||
THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat().Get(), _glyphCell.width(), DefaultFontFace().Get(), 1.0f, &_boxDrawingEffect));
|
||||
THROW_IF_FAILED(s_CalculateBoxEffect(DefaultTextFormat().Get(), _glyphCell.width, DefaultFontFace().Get(), 1.0f, &_boxDrawingEffect));
|
||||
}
|
||||
|
||||
return _boxDrawingEffect;
|
||||
@ -738,7 +738,7 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
||||
// - 12 ppi font * (96 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 16 pixels tall font for 100% display (96 dpi is 100%)
|
||||
// - 12 ppi font * (144 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 24 pixels tall font for 150% display (144 dpi is 150%)
|
||||
// - 12 ppi font * (192 dpi / 96 dpi) * (96 dpi / 72 points per inch) = 32 pixels tall font for 200% display (192 dpi is 200%)
|
||||
float heightDesired = static_cast<float>(desired.GetEngineSize().Y) * static_cast<float>(USER_DEFAULT_SCREEN_DPI) / POINTS_PER_INCH;
|
||||
float heightDesired = desired.GetEngineSize().Y * USER_DEFAULT_SCREEN_DPI / POINTS_PER_INCH;
|
||||
|
||||
// The advance is the number of pixels left-to-right (X dimension) for the given font.
|
||||
// We're finding a proportional factor here with the design units in "ems", not an actual pixel measurement.
|
||||
@ -891,7 +891,7 @@ void DxFontRenderData::_BuildFontRenderData(const FontInfoDesired& desired, Font
|
||||
|
||||
_lineMetrics = lineMetrics;
|
||||
|
||||
_glyphCell = actual.GetSize();
|
||||
_glyphCell = til::size{ actual.GetSize() };
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(const DxFontInfo& fontInfo, const std::wstring_view localeName)
|
||||
|
||||
@ -344,8 +344,8 @@ HRESULT DxEngine::_SetupTerminalEffects()
|
||||
|
||||
// Setup the viewport.
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = _displaySizePixels.width<float>();
|
||||
vp.Height = _displaySizePixels.height<float>();
|
||||
vp.Width = static_cast<float>(_displaySizePixels.width);
|
||||
vp.Height = static_cast<float>(_displaySizePixels.height);
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
@ -463,8 +463,8 @@ void DxEngine::_ComputePixelShaderSettings() noexcept
|
||||
_pixelShaderSettings.Scale = _scale;
|
||||
|
||||
// Set the display resolution
|
||||
const float w = 1.0f * _displaySizePixels.width<UINT>();
|
||||
const float h = 1.0f * _displaySizePixels.height<UINT>();
|
||||
const float w = static_cast<float>(_displaySizePixels.width);
|
||||
const float h = static_cast<float>(_displaySizePixels.height);
|
||||
_pixelShaderSettings.Resolution = XMFLOAT2{ w, h };
|
||||
|
||||
// Set the background
|
||||
@ -653,8 +653,8 @@ try
|
||||
RETURN_IF_FAILED(_dxgiFactory2.As(&_dxgiFactoryMedia));
|
||||
|
||||
// Use the given target size for compositions.
|
||||
_swapChainDesc.Width = _displaySizePixels.width<UINT>();
|
||||
_swapChainDesc.Height = _displaySizePixels.height<UINT>();
|
||||
_swapChainDesc.Width = _displaySizePixels.narrow_width<UINT>();
|
||||
_swapChainDesc.Height = _displaySizePixels.narrow_height<UINT>();
|
||||
|
||||
// We're doing advanced composition pretty much for the purpose of pretty alpha, so turn it on.
|
||||
_swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
|
||||
@ -942,8 +942,8 @@ try
|
||||
return _dwriteFactory->CreateTextLayout(string,
|
||||
gsl::narrow<UINT32>(stringLength),
|
||||
_fontRenderData->DefaultTextFormat().Get(),
|
||||
_displaySizePixels.width<float>(),
|
||||
_fontRenderData->GlyphCell().height() != 0 ? _fontRenderData->GlyphCell().height<float>() : _displaySizePixels.height<float>(),
|
||||
static_cast<float>(_displaySizePixels.width),
|
||||
_fontRenderData->GlyphCell().height != 0 ? _fontRenderData->GlyphCell().narrow_height<float>() : _displaySizePixels.narrow_height<float>(),
|
||||
ppTextLayout);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
@ -965,7 +965,7 @@ CATCH_RETURN()
|
||||
[[nodiscard]] HRESULT DxEngine::SetWindowSize(const SIZE Pixels) noexcept
|
||||
try
|
||||
{
|
||||
_sizeTarget = Pixels;
|
||||
_sizeTarget = til::size{ Pixels };
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
@ -1006,7 +1006,7 @@ try
|
||||
{
|
||||
// Enable shader effects if the path isn't empty. Otherwise leave it untouched.
|
||||
_terminalEffectsEnabled = value.empty() ? _terminalEffectsEnabled : true;
|
||||
_pixelShaderPath = { value };
|
||||
_pixelShaderPath = std::wstring{ value };
|
||||
_recreateDeviceRequested = true;
|
||||
LOG_IF_FAILED(InvalidateAll());
|
||||
}
|
||||
@ -1058,17 +1058,17 @@ HANDLE DxEngine::GetSwapChainHandle() noexcept
|
||||
return _swapChainHandle.get();
|
||||
}
|
||||
|
||||
void DxEngine::_InvalidateRectangle(const til::rectangle& rc)
|
||||
void DxEngine::_InvalidateRectangle(const til::rect& rc)
|
||||
{
|
||||
const auto size = _invalidMap.size();
|
||||
const auto topLeft = til::point{ 0, std::min(size.height(), rc.top()) };
|
||||
const auto bottomRight = til::point{ size.width(), std::min(size.height(), rc.bottom()) };
|
||||
_invalidMap.set({ topLeft, bottomRight });
|
||||
const auto topLeft = til::point{ 0, std::min(size.height, rc.top) };
|
||||
const auto bottomRight = til::point{ size.width, std::min(size.height, rc.bottom) };
|
||||
_invalidMap.set(til::rect{ topLeft, bottomRight });
|
||||
}
|
||||
|
||||
bool DxEngine::_IsAllInvalid() const noexcept
|
||||
{
|
||||
return std::llabs(_invalidScroll.y()) >= _invalidMap.size().height();
|
||||
return std::abs(_invalidScroll.y) >= _invalidMap.size().height;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@ -1084,7 +1084,7 @@ try
|
||||
|
||||
if (!_allInvalid)
|
||||
{
|
||||
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
|
||||
_InvalidateRectangle(til::rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() });
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@ -1117,7 +1117,7 @@ try
|
||||
{
|
||||
// Dirty client is in pixels. Use divide specialization against glyph factor to make conversion
|
||||
// to cells.
|
||||
_InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_fontRenderData->GlyphCell()));
|
||||
_InvalidateRectangle(til::rect{ *prcDirtyClient }.scale_down(_fontRenderData->GlyphCell()));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@ -1159,7 +1159,7 @@ try
|
||||
|
||||
if (!_allInvalid)
|
||||
{
|
||||
if (deltaCells != til::point{ 0, 0 })
|
||||
if (deltaCells != til::point{})
|
||||
{
|
||||
// Shift the contents of the map and fill in revealed area.
|
||||
_invalidMap.translate(deltaCells, true);
|
||||
@ -1226,7 +1226,7 @@ CATCH_RETURN();
|
||||
RECT clientRect = { 0 };
|
||||
LOG_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &clientRect));
|
||||
|
||||
return til::rectangle{ clientRect }.size();
|
||||
return til::rect{ clientRect }.size();
|
||||
}
|
||||
case SwapChainMode::ForComposition:
|
||||
{
|
||||
@ -1323,7 +1323,7 @@ try
|
||||
_d2dBitmap.Reset();
|
||||
|
||||
// Change the buffer size and recreate the render target (and surface)
|
||||
RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.width<UINT>(), clientSize.height<UINT>(), _swapChainDesc.Format, _swapChainDesc.Flags));
|
||||
RETURN_IF_FAILED(_dxgiSwapChain->ResizeBuffers(2, clientSize.narrow_width<UINT>(), clientSize.narrow_height<UINT>(), _swapChainDesc.Format, _swapChainDesc.Flags));
|
||||
RETURN_IF_FAILED(_PrepareRenderTarget());
|
||||
|
||||
// OK we made it past the parts that can cause errors. We can release our failure handler.
|
||||
@ -1354,7 +1354,7 @@ try
|
||||
_ShouldForceGrayscaleAA(),
|
||||
_dwriteFactory.Get(),
|
||||
spacing,
|
||||
glyphCellSize,
|
||||
glyphCellSize.to_d2d_size(),
|
||||
_d2dDeviceContext->GetSize(),
|
||||
std::nullopt,
|
||||
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
|
||||
@ -1391,11 +1391,11 @@ try
|
||||
{
|
||||
if (_invalidScroll != til::point{ 0, 0 })
|
||||
{
|
||||
// Copy `til::rectangles` into RECT map.
|
||||
// Copy `til::rects` into RECT map.
|
||||
_presentDirty.assign(_invalidMap.begin(), _invalidMap.end());
|
||||
|
||||
// Scale all dirty rectangles into pixels
|
||||
std::transform(_presentDirty.begin(), _presentDirty.end(), _presentDirty.begin(), [&](til::rectangle rc) {
|
||||
std::transform(_presentDirty.begin(), _presentDirty.end(), _presentDirty.begin(), [&](const til::rect& rc) {
|
||||
return rc.scale_up(_fontRenderData->GlyphCell());
|
||||
});
|
||||
|
||||
@ -1403,20 +1403,25 @@ try
|
||||
const auto scrollPixels = (_invalidScroll * _fontRenderData->GlyphCell());
|
||||
|
||||
// The scroll rect is the entire field of cells, but in pixels.
|
||||
til::rectangle scrollArea{ _invalidMap.size() * _fontRenderData->GlyphCell() };
|
||||
til::rect scrollArea{ _invalidMap.size() * _fontRenderData->GlyphCell() };
|
||||
|
||||
// Reduce the size of the rectangle by the scroll.
|
||||
scrollArea -= til::size{} - scrollPixels;
|
||||
|
||||
// Assign the area to the present storage
|
||||
_presentScroll = scrollArea;
|
||||
_presentScroll = scrollArea.to_win32_rect();
|
||||
|
||||
// Pass the offset.
|
||||
_presentOffset = scrollPixels;
|
||||
_presentOffset = scrollPixels.to_win32_point();
|
||||
|
||||
// Now fill up the parameters structure from the member variables.
|
||||
_presentParams.DirtyRectsCount = gsl::narrow<UINT>(_presentDirty.size());
|
||||
_presentParams.pDirtyRects = _presentDirty.data();
|
||||
|
||||
// It's not nice to use reinterpret_cast between til::rect and RECT,
|
||||
// but to be honest... it does save a ton of type juggling.
|
||||
static_assert(sizeof(decltype(_presentDirty)::value_type) == sizeof(RECT));
|
||||
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
|
||||
_presentParams.pDirtyRects = reinterpret_cast<RECT*>(_presentDirty.data());
|
||||
|
||||
_presentParams.pScrollOffset = &_presentOffset;
|
||||
_presentParams.pScrollRect = &_presentScroll;
|
||||
@ -1646,7 +1651,7 @@ try
|
||||
// Runs are counts of cells.
|
||||
// Use a transform by the size of one cell to convert cells-to-pixels
|
||||
// as we clear.
|
||||
_d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Scale(_fontRenderData->GlyphCell()));
|
||||
_d2dDeviceContext->SetTransform(D2D1::Matrix3x2F::Scale(_fontRenderData->GlyphCell().to_d2d_size()));
|
||||
for (const auto& rect : _invalidMap.runs())
|
||||
{
|
||||
// Use aliased.
|
||||
@ -1654,7 +1659,7 @@ try
|
||||
// the edges are cut nice and sharp (not blended by anti-aliasing).
|
||||
// For performance reasons, it takes a lot less work to not
|
||||
// do anti-alias blending.
|
||||
_d2dDeviceContext->PushAxisAlignedClip(rect, D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
_d2dDeviceContext->PushAxisAlignedClip(rect.to_d2d_rect(), D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
_d2dDeviceContext->Clear(nothing);
|
||||
_d2dDeviceContext->PopAxisAlignedClip();
|
||||
}
|
||||
@ -1680,7 +1685,7 @@ CATCH_RETURN()
|
||||
try
|
||||
{
|
||||
// Calculate positioning of our origin.
|
||||
const D2D1_POINT_2F origin = til::point{ coord } * _fontRenderData->GlyphCell();
|
||||
const D2D1_POINT_2F origin = (til::point{ coord } * _fontRenderData->GlyphCell()).to_d2d_point();
|
||||
|
||||
// Create the text layout
|
||||
RETURN_IF_FAILED(_customLayout->Reset());
|
||||
@ -1714,7 +1719,7 @@ try
|
||||
|
||||
_d2dBrushForeground->SetColor(_ColorFFromColorRef(color));
|
||||
|
||||
const D2D1_SIZE_F font = _fontRenderData->GlyphCell();
|
||||
const D2D1_SIZE_F font = _fontRenderData->GlyphCell().to_d2d_size();
|
||||
const D2D_POINT_2F target = { coordTarget.X * font.width, coordTarget.Y * font.height };
|
||||
const auto fullRunWidth = font.width * gsl::narrow_cast<unsigned>(cchLine);
|
||||
|
||||
@ -1833,7 +1838,7 @@ try
|
||||
_d2dBrushForeground->SetColor(_selectionBackground);
|
||||
const auto resetColorOnExit = wil::scope_exit([&]() noexcept { _d2dBrushForeground->SetColor(existingColor); });
|
||||
|
||||
const D2D1_RECT_F draw = til::rectangle{ Viewport::FromExclusive(rect).ToInclusive() }.scale_up(_fontRenderData->GlyphCell());
|
||||
const D2D1_RECT_F draw = til::rect{ Viewport::FromExclusive(rect).ToInclusive() }.scale_up(_fontRenderData->GlyphCell()).to_d2d_rect();
|
||||
|
||||
_d2dDeviceContext->FillRectangle(draw, _d2dBrushForeground.Get());
|
||||
|
||||
@ -2018,16 +2023,16 @@ CATCH_RETURN();
|
||||
|
||||
[[nodiscard]] Viewport DxEngine::GetViewportInCharacters(const Viewport& viewInPixels) const noexcept
|
||||
{
|
||||
const short widthInChars = base::saturated_cast<short>(viewInPixels.Width() / _fontRenderData->GlyphCell().width());
|
||||
const short heightInChars = base::saturated_cast<short>(viewInPixels.Height() / _fontRenderData->GlyphCell().height());
|
||||
const short widthInChars = base::saturated_cast<short>(viewInPixels.Width() / _fontRenderData->GlyphCell().width);
|
||||
const short heightInChars = base::saturated_cast<short>(viewInPixels.Height() / _fontRenderData->GlyphCell().height);
|
||||
|
||||
return Viewport::FromDimensions(viewInPixels.Origin(), { widthInChars, heightInChars });
|
||||
}
|
||||
|
||||
[[nodiscard]] Viewport DxEngine::GetViewportInPixels(const Viewport& viewInCharacters) const noexcept
|
||||
{
|
||||
const short widthInPixels = base::saturated_cast<short>(viewInCharacters.Width() * _fontRenderData->GlyphCell().width());
|
||||
const short heightInPixels = base::saturated_cast<short>(viewInCharacters.Height() * _fontRenderData->GlyphCell().height());
|
||||
const short widthInPixels = base::saturated_cast<short>(viewInCharacters.Width() * _fontRenderData->GlyphCell().width);
|
||||
const short heightInPixels = base::saturated_cast<short>(viewInCharacters.Height() * _fontRenderData->GlyphCell().height);
|
||||
|
||||
return Viewport::FromDimensions(viewInCharacters.Origin(), { widthInPixels, heightInPixels });
|
||||
}
|
||||
@ -2099,7 +2104,7 @@ float DxEngine::GetScaling() const noexcept
|
||||
// - area - Rectangle describing dirty area in characters.
|
||||
// Return Value:
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT DxEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT DxEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
try
|
||||
{
|
||||
area = _invalidMap.runs();
|
||||
@ -2116,7 +2121,9 @@ CATCH_RETURN();
|
||||
[[nodiscard]] HRESULT DxEngine::GetFontSize(_Out_ COORD* const pFontSize) noexcept
|
||||
try
|
||||
{
|
||||
*pFontSize = _fontRenderData->GlyphCell();
|
||||
const auto size = _fontRenderData->GlyphCell();
|
||||
pFontSize->X = size.narrow_width<short>();
|
||||
pFontSize->Y = size.narrow_height<short>();
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
@ -116,7 +116,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
||||
@ -177,7 +177,7 @@ namespace Microsoft::Console::Render
|
||||
bool _allInvalid;
|
||||
|
||||
bool _presentReady;
|
||||
std::vector<RECT> _presentDirty;
|
||||
std::vector<til::rect> _presentDirty;
|
||||
RECT _presentScroll;
|
||||
POINT _presentOffset;
|
||||
DXGI_PRESENT_PARAMETERS _presentParams;
|
||||
@ -298,7 +298,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] til::size _GetClientSize() const;
|
||||
|
||||
void _InvalidateRectangle(const til::rectangle& rc);
|
||||
void _InvalidateRectangle(const til::rect& rc);
|
||||
bool _IsAllInvalid() const noexcept;
|
||||
|
||||
[[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept;
|
||||
|
||||
@ -76,7 +76,7 @@ namespace Microsoft::Console::Render
|
||||
_Out_ FontInfo& Font,
|
||||
const int iDpi) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
||||
|
||||
@ -92,7 +92,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
bool _fPaintStarted;
|
||||
|
||||
til::rectangle _invalidCharacters;
|
||||
til::rect _invalidCharacters;
|
||||
PAINTSTRUCT _psInvalidData;
|
||||
HDC _hdcMemoryContext;
|
||||
bool _isTrueTypeFont;
|
||||
|
||||
@ -16,14 +16,14 @@ using namespace Microsoft::Console::Render;
|
||||
// This is an Inclusive rect.
|
||||
// Return Value:
|
||||
// - S_OK or math failure
|
||||
[[nodiscard]] HRESULT GdiEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT GdiEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
RECT rc = _psInvalidData.rcPaint;
|
||||
|
||||
SMALL_RECT sr = { 0 };
|
||||
RETURN_IF_FAILED(_ScaleByFont(&rc, &sr));
|
||||
|
||||
_invalidCharacters = sr;
|
||||
_invalidCharacters = til::rect{ sr };
|
||||
|
||||
area = { &_invalidCharacters, 1 };
|
||||
|
||||
|
||||
@ -435,7 +435,7 @@ GdiEngine::~GdiEngine()
|
||||
_fontCodepage = Font.GetCodePage();
|
||||
|
||||
// Inform the soft font of the change in size.
|
||||
_softFont.SetTargetSize(_GetFontSize());
|
||||
_softFont.SetTargetSize(til::size{ _GetFontSize() });
|
||||
|
||||
LOG_IF_FAILED(InvalidateAll());
|
||||
|
||||
@ -462,7 +462,7 @@ GdiEngine::~GdiEngine()
|
||||
}
|
||||
|
||||
// Create a new font resource with the updated pattern, or delete if empty.
|
||||
_softFont = { bitPattern, cellSize, _GetFontSize(), centeringHint };
|
||||
_softFont = FontResource{ bitPattern, til::size{ cellSize }, til::size{ _GetFontSize() }, centeringHint };
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT UpdateDpi(int iDpi) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT UpdateTitle(std::wstring_view newTitle) noexcept = 0;
|
||||
|
||||
@ -440,11 +440,11 @@ void UiaEngine::WaitUntilCanRender() noexcept
|
||||
// - area - Rectangle describing dirty area in characters.
|
||||
// Return Value:
|
||||
// - S_OK.
|
||||
[[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT UiaEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
// Magic static is only valid because any instance of this object has the same behavior.
|
||||
// Use member variable instead if this ever changes.
|
||||
const static til::rectangle empty;
|
||||
static constexpr til::rect empty;
|
||||
area = { &empty, 1 };
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override;
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, const int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
||||
{
|
||||
RETURN_IF_FAILED(VtEngine::StartPaint());
|
||||
|
||||
_trace.TraceLastText(_lastText);
|
||||
_trace.TraceLastText(til::point{ _lastText });
|
||||
|
||||
// Prep us to think that the cursor is not visible this frame. If it _is_
|
||||
// visible, then PaintCursor will be called, and we'll set this to true
|
||||
@ -57,16 +57,16 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
||||
}
|
||||
else
|
||||
{
|
||||
gsl::span<const til::rectangle> dirty;
|
||||
gsl::span<const til::rect> dirty;
|
||||
RETURN_IF_FAILED(GetDirtyArea(dirty));
|
||||
|
||||
// If we have 0 or 1 dirty pieces in the area, set as appropriate.
|
||||
Viewport dirtyView = dirty.empty() ? Viewport::Empty() : Viewport::FromInclusive(til::at(dirty, 0));
|
||||
Viewport dirtyView = dirty.empty() ? Viewport::Empty() : Viewport::FromInclusive(til::at(dirty, 0).to_small_rect());
|
||||
|
||||
// If there's more than 1, union them all up with the 1 we already have.
|
||||
for (size_t i = 1; i < dirty.size(); ++i)
|
||||
{
|
||||
dirtyView = Viewport::Union(dirtyView, Viewport::FromInclusive(til::at(dirty, i)));
|
||||
dirtyView = Viewport::Union(dirtyView, Viewport::FromInclusive(til::at(dirty, i).to_small_rect()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +237,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
const auto originalPos = _lastText;
|
||||
_trace.TraceMoveCursor(_lastText, coord);
|
||||
_trace.TraceMoveCursor(til::point{ _lastText }, til::point{ coord });
|
||||
bool performedSoftWrap = false;
|
||||
if (coord.X != _lastText.X || coord.Y != _lastText.Y)
|
||||
{
|
||||
@ -348,18 +348,18 @@ try
|
||||
{
|
||||
_trace.TraceScrollFrame(_scrollDelta);
|
||||
|
||||
if (_scrollDelta.x() != 0)
|
||||
if (_scrollDelta.x != 0)
|
||||
{
|
||||
// No easy way to shift left-right. Everything needs repainting.
|
||||
return InvalidateAll();
|
||||
}
|
||||
if (_scrollDelta.y() == 0)
|
||||
if (_scrollDelta.y == 0)
|
||||
{
|
||||
// There's nothing to do here. Do nothing.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const short dy = _scrollDelta.y<short>();
|
||||
const short dy = _scrollDelta.narrow_y<short>();
|
||||
const short absDy = static_cast<short>(abs(dy));
|
||||
|
||||
// Save the old wrap state here. We're going to clear it so that
|
||||
@ -411,7 +411,7 @@ try
|
||||
// position we think we left the cursor.
|
||||
//
|
||||
// See GH#5113
|
||||
_trace.TraceLastText(_lastText);
|
||||
_trace.TraceLastText(til::point{ _lastText });
|
||||
if (_wrappedRow.has_value())
|
||||
{
|
||||
_wrappedRow.value() += dy;
|
||||
@ -430,7 +430,7 @@ try
|
||||
// one frame, and the second line in another frame that included other
|
||||
// changes _above_ the wrapped line, that we maintain the wrap state in
|
||||
// the Terminal.
|
||||
const til::rectangle lastCellOfWrappedRow{
|
||||
const til::rect lastCellOfWrappedRow{
|
||||
til::point{ _lastViewport.RightInclusive(), _wrappedRow.value() },
|
||||
til::size{ 1, 1 }
|
||||
};
|
||||
|
||||
@ -49,7 +49,7 @@ using namespace Microsoft::Console::Render;
|
||||
[[nodiscard]] HRESULT VtEngine::Invalidate(const SMALL_RECT* const psrRegion) noexcept
|
||||
try
|
||||
{
|
||||
const til::rectangle rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() };
|
||||
const til::rect rect{ Viewport::FromExclusive(*psrRegion).ToInclusive() };
|
||||
_trace.TraceInvalidate(rect);
|
||||
_invalidMap.set(rect);
|
||||
return S_OK;
|
||||
@ -91,7 +91,7 @@ CATCH_RETURN();
|
||||
[[nodiscard]] HRESULT VtEngine::InvalidateAll() noexcept
|
||||
try
|
||||
{
|
||||
_trace.TraceInvalidateAll(_lastViewport.ToOrigin().ToInclusive());
|
||||
_trace.TraceInvalidateAll(til::rect{ _lastViewport.ToOrigin().ToInclusive() });
|
||||
_invalidMap.set_all();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ using namespace Microsoft::Console::Types;
|
||||
// This is an Inclusive rect.
|
||||
// Return Value:
|
||||
// - S_OK.
|
||||
[[nodiscard]] HRESULT VtEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT VtEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
area = _invalidMap.runs();
|
||||
return S_OK;
|
||||
|
||||
@ -34,7 +34,7 @@ using namespace Microsoft::Console::Types;
|
||||
_quickReturn = !somethingToDo;
|
||||
_trace.TraceStartPaint(_quickReturn,
|
||||
_invalidMap,
|
||||
_lastViewport.ToInclusive(),
|
||||
til::rect{ _lastViewport.ToInclusive() },
|
||||
_scrollDelta,
|
||||
_cursorMoved,
|
||||
_wrappedRow);
|
||||
@ -158,7 +158,7 @@ using namespace Microsoft::Console::Types;
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::PaintCursor(const CursorOptions& options) noexcept
|
||||
{
|
||||
_trace.TracePaintCursor(options.coordCursor);
|
||||
_trace.TracePaintCursor(til::point{ options.coordCursor });
|
||||
|
||||
// MSFT:15933349 - Send the terminal the updated cursor information, if it's changed.
|
||||
LOG_IF_FAILED(_MoveCursor(options.coordCursor));
|
||||
|
||||
@ -32,9 +32,9 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
_lastTextAttributes(INVALID_COLOR, INVALID_COLOR),
|
||||
_lastViewport(initialViewport),
|
||||
_pool(til::pmr::get_default_resource()),
|
||||
_invalidMap(initialViewport.Dimensions(), false, &_pool),
|
||||
_invalidMap(til::size{ initialViewport.Dimensions() }, false, &_pool),
|
||||
_lastText({ 0 }),
|
||||
_scrollDelta({ 0, 0 }),
|
||||
_scrollDelta(0, 0),
|
||||
_quickReturn(false),
|
||||
_clearedAllThisFrame(false),
|
||||
_cursorMoved(false),
|
||||
@ -245,13 +245,13 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
// buffer will have triggered it's own invalidations for what it knows is
|
||||
// invalid. Previously, we'd invalidate everything if the width changed,
|
||||
// because we couldn't be sure if lines were reflowed.
|
||||
_invalidMap.resize(newView.Dimensions());
|
||||
_invalidMap.resize(til::size{ newView.Dimensions() });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_invalidMap.resize(newView.Dimensions(), true); // resize while filling in new space with repaint requests.
|
||||
_invalidMap.resize(til::size{ newView.Dimensions() }, true); // resize while filling in new space with repaint requests.
|
||||
|
||||
// Viewport is smaller now - just update it all.
|
||||
if (oldView.Height() > newView.Height() || oldView.Width() > newView.Width())
|
||||
|
||||
@ -82,7 +82,7 @@ void RenderTracing::TraceString(const std::string_view& instr) const
|
||||
#endif UNIT_TESTING
|
||||
}
|
||||
|
||||
void RenderTracing::TraceInvalidate(const til::rectangle invalidRect) const
|
||||
void RenderTracing::TraceInvalidate(const til::rect& invalidRect) const
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, TIL_KEYWORD_TRACE))
|
||||
@ -100,7 +100,7 @@ void RenderTracing::TraceInvalidate(const til::rectangle invalidRect) const
|
||||
#endif UNIT_TESTING
|
||||
}
|
||||
|
||||
void RenderTracing::TraceInvalidateAll(const til::rectangle viewport) const
|
||||
void RenderTracing::TraceInvalidateAll(const til::rect& viewport) const
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, TIL_KEYWORD_TRACE))
|
||||
@ -151,7 +151,7 @@ void RenderTracing::TraceInvalidateScroll(const til::point scroll) const
|
||||
|
||||
void RenderTracing::TraceStartPaint(const bool quickReturn,
|
||||
const til::pmr::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::rect& lastViewport,
|
||||
const til::point scrollDelt,
|
||||
const bool cursorMoved,
|
||||
const std::optional<short>& wrappedRow) const
|
||||
|
||||
@ -27,7 +27,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
RenderTracing();
|
||||
~RenderTracing();
|
||||
void TraceString(const std::string_view& str) const;
|
||||
void TraceInvalidate(const til::rectangle view) const;
|
||||
void TraceInvalidate(const til::rect& view) const;
|
||||
void TraceLastText(const til::point lastText) const;
|
||||
void TraceScrollFrame(const til::point scrollDelta) const;
|
||||
void TraceMoveCursor(const til::point lastText, const til::point cursor) const;
|
||||
@ -35,12 +35,12 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void TraceClearWrapped() const;
|
||||
void TraceWrapped() const;
|
||||
void TracePaintCursor(const til::point coordCursor) const;
|
||||
void TraceInvalidateAll(const til::rectangle view) const;
|
||||
void TraceInvalidateAll(const til::rect& view) const;
|
||||
void TraceTriggerCircling(const bool newFrame) const;
|
||||
void TraceInvalidateScroll(const til::point scroll) const;
|
||||
void TraceStartPaint(const bool quickReturn,
|
||||
const til::pmr::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::rect& lastViewport,
|
||||
const til::point scrollDelta,
|
||||
const bool cursorMoved,
|
||||
const std::optional<short>& wrappedRow) const;
|
||||
|
||||
@ -66,7 +66,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT UpdateDpi(int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT UpdateViewport(SMALL_RECT srNewViewport) noexcept override;
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, int iDpi) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept override;
|
||||
|
||||
|
||||
@ -354,15 +354,10 @@ bool WddmConEngine::IsInitialized()
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
[[nodiscard]] HRESULT WddmConEngine::GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept
|
||||
[[nodiscard]] HRESULT WddmConEngine::GetDirtyArea(gsl::span<const til::rect>& area) noexcept
|
||||
{
|
||||
SMALL_RECT r;
|
||||
r.Bottom = _displayHeight > 0 ? (SHORT)(_displayHeight - 1) : 0;
|
||||
r.Top = 0;
|
||||
r.Left = 0;
|
||||
r.Right = _displayWidth > 0 ? (SHORT)(_displayWidth - 1) : 0;
|
||||
|
||||
_dirtyArea = r;
|
||||
_dirtyArea.bottom = std::max(0, _displayHeight);
|
||||
_dirtyArea.right = std::max(0, _displayWidth);
|
||||
|
||||
area = { &_dirtyArea,
|
||||
1 };
|
||||
|
||||
@ -60,7 +60,7 @@ namespace Microsoft::Console::Render
|
||||
|
||||
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rect>& area) noexcept override;
|
||||
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
|
||||
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
|
||||
|
||||
@ -76,7 +76,7 @@ namespace Microsoft::Console::Render
|
||||
// Variables
|
||||
LONG _displayHeight;
|
||||
LONG _displayWidth;
|
||||
til::rectangle _dirtyArea;
|
||||
til::rect _dirtyArea;
|
||||
|
||||
PCD_IO_ROW_INFORMATION* _displayState;
|
||||
|
||||
|
||||
@ -222,9 +222,9 @@ gsl::span<const uint16_t> FontBuffer::GetBitPattern() const noexcept
|
||||
return { _buffer.data(), MAX_CHARS * _fullHeight };
|
||||
}
|
||||
|
||||
til::size FontBuffer::GetCellSize() const
|
||||
til::size FontBuffer::GetCellSize() const noexcept
|
||||
{
|
||||
return { _fullWidth, _fullHeight };
|
||||
return { gsl::narrow_cast<til::CoordType>(_fullWidth), gsl::narrow_cast<til::CoordType>(_fullHeight) };
|
||||
}
|
||||
|
||||
size_t FontBuffer::GetTextCenteringHint() const noexcept
|
||||
|
||||
@ -31,7 +31,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
bool FinalizeSixelData();
|
||||
|
||||
gsl::span<const uint16_t> GetBitPattern() const noexcept;
|
||||
til::size GetCellSize() const;
|
||||
til::size GetCellSize() const noexcept;
|
||||
size_t GetTextCenteringHint() const noexcept;
|
||||
VTID GetDesignation() const noexcept;
|
||||
|
||||
|
||||
@ -2474,7 +2474,7 @@ ITermDispatch::StringHandler AdaptDispatch::DownloadDRCS(const size_t fontNumber
|
||||
const auto bitPattern = _fontBuffer->GetBitPattern();
|
||||
const auto cellSize = _fontBuffer->GetCellSize();
|
||||
const auto centeringHint = _fontBuffer->GetTextCenteringHint();
|
||||
_pConApi->PrivateUpdateSoftFont(bitPattern, cellSize, centeringHint);
|
||||
_pConApi->PrivateUpdateSoftFont(bitPattern, cellSize.to_win32_size(), centeringHint);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -1794,7 +1794,7 @@ public:
|
||||
|
||||
wchar_t pwszBuffer[50];
|
||||
|
||||
swprintf_s(pwszBuffer, ARRAYSIZE(pwszBuffer), L"\x1b[%d;%dR\x1b[%d;%dR", coordCursorExpectedFirst.y<int>(), coordCursorExpectedFirst.x<int>(), coordCursorExpectedSecond.y<int>(), coordCursorExpectedSecond.x<int>());
|
||||
swprintf_s(pwszBuffer, ARRAYSIZE(pwszBuffer), L"\x1b[%d;%dR\x1b[%d;%dR", coordCursorExpectedFirst.y, coordCursorExpectedFirst.x, coordCursorExpectedSecond.y, coordCursorExpectedSecond.x);
|
||||
_testGetSet->ValidateInputEvent(pwszBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +387,7 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter
|
||||
DWORD buttonState = 0;
|
||||
DWORD eventFlags = 0;
|
||||
const size_t firstParameter = parameters.at(0).value_or(0);
|
||||
const til::point uiPos{ parameters.at(1) - 1, parameters.at(2) - 1 };
|
||||
const til::point uiPos{ gsl::narrow_cast<til::CoordType>(parameters.at(1) - 1), gsl::narrow_cast<til::CoordType>(parameters.at(2) - 1) };
|
||||
|
||||
modifierState = _GetSGRMouseModifierState(firstParameter);
|
||||
success = _UpdateSGRMouseButtonState(id, firstParameter, buttonState, eventFlags, uiPos);
|
||||
@ -730,7 +730,7 @@ bool InputStateMachineEngine::_WriteMouseEvent(const til::point uiPos, const DWO
|
||||
{
|
||||
INPUT_RECORD rgInput;
|
||||
rgInput.EventType = MOUSE_EVENT;
|
||||
rgInput.Event.MouseEvent.dwMousePosition = uiPos;
|
||||
rgInput.Event.MouseEvent.dwMousePosition = uiPos.to_win32_coord();
|
||||
rgInput.Event.MouseEvent.dwButtonState = buttonState;
|
||||
rgInput.Event.MouseEvent.dwControlKeyState = controlKeyState;
|
||||
rgInput.Event.MouseEvent.dwEventFlags = eventFlags;
|
||||
|
||||
@ -14,14 +14,14 @@ class BitmapTests
|
||||
TEST_CLASS(BitmapTests);
|
||||
|
||||
template<typename T>
|
||||
void _checkBits(const til::rectangle& bitsOn,
|
||||
void _checkBits(const til::rect& bitsOn,
|
||||
const til::details::bitmap<T>& map)
|
||||
{
|
||||
_checkBits(std::vector<til::rectangle>{ bitsOn }, map);
|
||||
_checkBits(std::vector<til::rect>{ bitsOn }, map);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void _checkBits(const std::vector<til::rectangle>& bitsOn,
|
||||
void _checkBits(const std::vector<til::rect>& bitsOn,
|
||||
const til::details::bitmap<T>& map)
|
||||
{
|
||||
Log::Comment(L"Check all bits in map.");
|
||||
@ -50,7 +50,7 @@ class BitmapTests
|
||||
{
|
||||
const til::bitmap bitmap;
|
||||
const til::size expectedSize{ 0, 0 };
|
||||
const til::rectangle expectedRect{ 0, 0, 0, 0 };
|
||||
const til::rect expectedRect{ 0, 0, 0, 0 };
|
||||
VERIFY_ARE_EQUAL(expectedSize, bitmap._sz);
|
||||
VERIFY_ARE_EQUAL(expectedRect, bitmap._rc);
|
||||
VERIFY_ARE_EQUAL(0u, bitmap._bits.size());
|
||||
@ -63,7 +63,7 @@ class BitmapTests
|
||||
TEST_METHOD(SizeConstruct)
|
||||
{
|
||||
const til::size expectedSize{ 5, 10 };
|
||||
const til::rectangle expectedRect{ 0, 0, 5, 10 };
|
||||
const til::rect expectedRect{ 0, 0, 5, 10 };
|
||||
const til::bitmap bitmap{ expectedSize };
|
||||
VERIFY_ARE_EQUAL(expectedSize, bitmap._sz);
|
||||
VERIFY_ARE_EQUAL(expectedRect, bitmap._rc);
|
||||
@ -84,7 +84,7 @@ class BitmapTests
|
||||
VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"fill", fill));
|
||||
|
||||
const til::size expectedSize{ 5, 10 };
|
||||
const til::rectangle expectedRect{ 0, 0, 5, 10 };
|
||||
const til::rect expectedRect{ 0, 0, 5, 10 };
|
||||
const til::bitmap bitmap{ expectedSize, fill };
|
||||
VERIFY_ARE_EQUAL(expectedSize, bitmap._sz);
|
||||
VERIFY_ARE_EQUAL(expectedRect, bitmap._rc);
|
||||
@ -184,7 +184,7 @@ class BitmapTests
|
||||
// 0 1 1 0
|
||||
// 0 1 1 0
|
||||
// 0 0 0 0
|
||||
map.set(til::rectangle{ til::point{ 1, 1 }, til::size{ 2, 2 } });
|
||||
map.set(til::rect{ til::point{ 1, 1 }, til::size{ 2, 2 } });
|
||||
|
||||
Log::Comment(L"1.) Move down and right");
|
||||
{
|
||||
@ -226,7 +226,7 @@ class BitmapTests
|
||||
// 0 1 1 0 0 0 0 0
|
||||
// 0 1 1 0 v --> 0 0 0 0
|
||||
// 0 0 0 0 v 0 1 1 0
|
||||
expected.set(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
expected.set(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
|
||||
actual.translate(delta);
|
||||
|
||||
@ -271,7 +271,7 @@ class BitmapTests
|
||||
// 0 1 1 0 --> 1 0 0 0
|
||||
// 0 0 0 0 0 0 0 0
|
||||
// <--<--
|
||||
expected.set(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 1 }, til::size{ 1, 2 } });
|
||||
|
||||
actual.translate(delta);
|
||||
|
||||
@ -318,7 +318,7 @@ class BitmapTests
|
||||
// 0 1 1 0 ^ 0 0 0 0
|
||||
// 0 1 1 0 --> 0 0 0 0
|
||||
// 0 0 0 0 0 0 0 0
|
||||
expected.set(til::rectangle{ til::point{ 1, 0 }, til::size{ 2, 1 } });
|
||||
expected.set(til::rect{ til::point{ 1, 0 }, til::size{ 2, 1 } });
|
||||
|
||||
actual.translate(delta);
|
||||
|
||||
@ -363,7 +363,7 @@ class BitmapTests
|
||||
// 0 1 1 0 --> 0 0 0 1
|
||||
// 0 0 0 0 0 0 0 0
|
||||
// ->->
|
||||
expected.set(til::rectangle{ til::point{ 3, 1 }, til::size{ 1, 2 } });
|
||||
expected.set(til::rect{ til::point{ 3, 1 }, til::size{ 1, 2 } });
|
||||
|
||||
actual.translate(delta);
|
||||
|
||||
@ -381,7 +381,7 @@ class BitmapTests
|
||||
// 0 1 1 0
|
||||
// 0 1 1 0
|
||||
// 0 0 0 0
|
||||
map.set(til::rectangle{ til::point{ 1, 1 }, til::size{ 2, 2 } });
|
||||
map.set(til::rect{ til::point{ 1, 1 }, til::size{ 2, 2 } });
|
||||
|
||||
Log::Comment(L"1.) Move down and right");
|
||||
{
|
||||
@ -400,8 +400,8 @@ class BitmapTests
|
||||
// 0 1 1 0 v --> 0 0 0 0 --> F F 0 0
|
||||
// 0 0 0 0 v 0 1 1 0 F F 0 1
|
||||
// ->->
|
||||
expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 2, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 2, 2 } });
|
||||
expected.set(til::point{ 3, 3 });
|
||||
|
||||
actual.translate(delta, true);
|
||||
@ -425,8 +425,8 @@ class BitmapTests
|
||||
// 0 1 1 0 F F F F
|
||||
// 0 1 1 0 v --> 0 0 0 0
|
||||
// 0 0 0 0 v 0 1 1 0
|
||||
expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
|
||||
actual.translate(delta, true);
|
||||
|
||||
@ -450,8 +450,8 @@ class BitmapTests
|
||||
// 0 1 1 0 v --> 0 0 0 0 --> 0 0 F F
|
||||
// 0 0 0 0 v 0 1 1 0 1 0 F F
|
||||
// <-<-
|
||||
expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 2, 2 }, til::size{ 2, 2 } });
|
||||
expected.set(til::point{ 0, 3 });
|
||||
|
||||
actual.translate(delta, true);
|
||||
@ -473,8 +473,8 @@ class BitmapTests
|
||||
// 0 1 1 0 --> 1 0 F F
|
||||
// 0 0 0 0 0 0 F F
|
||||
// <--<--
|
||||
expected.set(til::rectangle{ til::point{ 2, 0 }, til::size{ 2, 4 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 2 } });
|
||||
expected.set(til::rect{ til::point{ 2, 0 }, til::size{ 2, 4 } });
|
||||
expected.set(til::rect{ til::point{ 0, 1 }, til::size{ 1, 2 } });
|
||||
|
||||
actual.translate(delta, true);
|
||||
|
||||
@ -498,8 +498,8 @@ class BitmapTests
|
||||
// 0 1 1 0 --> F F F F --> F F F F
|
||||
// 0 0 0 0 F F F F F F F F
|
||||
// <-<-
|
||||
expected.set(til::rectangle{ til::point{ 2, 0 }, til::size{ 2, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 2, 0 }, til::size{ 2, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
expected.set(til::point{ 0, 0 });
|
||||
|
||||
actual.translate(delta, true);
|
||||
@ -523,8 +523,8 @@ class BitmapTests
|
||||
// 0 1 1 0 ^ 0 0 0 0
|
||||
// 0 1 1 0 --> F F F F
|
||||
// 0 0 0 0 F F F F
|
||||
expected.set(til::rectangle{ til::point{ 1, 0 }, til::size{ 2, 1 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 1, 0 }, til::size{ 2, 1 } });
|
||||
expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
|
||||
actual.translate(delta, true);
|
||||
|
||||
@ -549,8 +549,8 @@ class BitmapTests
|
||||
// 0 0 0 0 F F F F F F F F
|
||||
// ->->
|
||||
expected.set(til::point{ 3, 0 });
|
||||
expected.set(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 2 }, til::size{ 4, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 2 } });
|
||||
|
||||
actual.translate(delta, true);
|
||||
|
||||
@ -571,8 +571,8 @@ class BitmapTests
|
||||
// 0 1 1 0 --> F F 0 1
|
||||
// 0 0 0 0 F F 0 0
|
||||
// ->->
|
||||
expected.set(til::rectangle{ til::point{ 3, 1 }, til::size{ 1, 2 } });
|
||||
expected.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 4 } });
|
||||
expected.set(til::rect{ til::point{ 3, 1 }, til::size{ 1, 2 } });
|
||||
expected.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 4 } });
|
||||
|
||||
actual.translate(delta, true);
|
||||
|
||||
@ -592,8 +592,8 @@ class BitmapTests
|
||||
const til::point point{ 2, 2 };
|
||||
bitmap.set(point);
|
||||
|
||||
std::vector<til::rectangle> expectedSet;
|
||||
expectedSet.emplace_back(til::rectangle{ point });
|
||||
std::vector<til::rect> expectedSet;
|
||||
expectedSet.emplace_back(til::rect{ 2, 2, 3, 3 });
|
||||
|
||||
// Run through every bit. Only the one we set should be true.
|
||||
Log::Comment(L"Only the bit we set should be true.");
|
||||
@ -603,7 +603,7 @@ class BitmapTests
|
||||
bitmap.set_all();
|
||||
|
||||
expectedSet.clear();
|
||||
expectedSet.emplace_back(til::rectangle{ bitmap._rc });
|
||||
expectedSet.emplace_back(til::rect{ bitmap._rc });
|
||||
_checkBits(expectedSet, bitmap);
|
||||
|
||||
Log::Comment(L"Now reset them all.");
|
||||
@ -612,13 +612,13 @@ class BitmapTests
|
||||
expectedSet.clear();
|
||||
_checkBits(expectedSet, bitmap);
|
||||
|
||||
til::rectangle totalZone{ sz };
|
||||
til::rect totalZone{ sz };
|
||||
Log::Comment(L"Set a rectangle of bits and test they went on.");
|
||||
// 0 0 0 0 |1 1|0 0
|
||||
// 0 0 0 0 --\ |1 1|0 0
|
||||
// 0 0 0 0 --/ |1 1|0 0
|
||||
// 0 0 0 0 0 0 0 0
|
||||
til::rectangle setZone{ til::point{ 0, 0 }, til::size{ 2, 3 } };
|
||||
til::rect setZone{ til::point{ 0, 0 }, til::size{ 2, 3 } };
|
||||
bitmap.set(setZone);
|
||||
|
||||
expectedSet.clear();
|
||||
@ -647,11 +647,7 @@ class BitmapTests
|
||||
Log::Comment(L"2.) SetRectangle out of bounds.");
|
||||
{
|
||||
auto fn = [&]() {
|
||||
map.set(til::rectangle{ til::point{
|
||||
2,
|
||||
2,
|
||||
},
|
||||
til::size{ 10, 10 } });
|
||||
map.set(til::rect{ til::point{ 2, 2 }, til::size{ 10, 10 } });
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_INVALIDARG; });
|
||||
@ -664,11 +660,11 @@ class BitmapTests
|
||||
const til::size originalSize{ 2, 2 };
|
||||
til::bitmap bitmap{ originalSize, true };
|
||||
|
||||
std::vector<til::rectangle> expectedFillRects;
|
||||
std::vector<til::rect> expectedFillRects;
|
||||
|
||||
// 1 1
|
||||
// 1 1
|
||||
expectedFillRects.emplace_back(til::rectangle{ originalSize });
|
||||
expectedFillRects.emplace_back(til::rect{ originalSize });
|
||||
_checkBits(expectedFillRects, bitmap);
|
||||
|
||||
Log::Comment(L"Attempt resize to the same size.");
|
||||
@ -688,7 +684,7 @@ class BitmapTests
|
||||
|
||||
Log::Comment(L"Set a bit out in the new space and check it.");
|
||||
const til::point spaceBit{ 1, 2 };
|
||||
expectedFillRects.emplace_back(til::rectangle{ spaceBit });
|
||||
expectedFillRects.emplace_back(til::rect{ 1, 2, 2, 3 });
|
||||
bitmap.set(spaceBit);
|
||||
|
||||
// 1 1 0
|
||||
@ -697,7 +693,7 @@ class BitmapTests
|
||||
_checkBits(expectedFillRects, bitmap);
|
||||
|
||||
Log::Comment(L"Grow vertically and shrink horizontally at the same time. Fill any new space.");
|
||||
expectedFillRects.emplace_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 2, 1 } });
|
||||
expectedFillRects.emplace_back(til::rect{ til::point{ 0, 3 }, til::size{ 2, 1 } });
|
||||
bitmap.resize(til::size{ 2, 4 }, true);
|
||||
|
||||
// 1 1
|
||||
@ -846,19 +842,19 @@ class BitmapTests
|
||||
// 0 0 0 0 0 0 0 0
|
||||
// 0 0 0 0 --> 0 0 0 0
|
||||
// 0 0 0 0 0 0 0 0
|
||||
map.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
map.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
|
||||
// 1 1 0 0 1 1 0 0
|
||||
// 0 0 0 0 0 0|1|0
|
||||
// 0 0 0 0 --> 0 0|1|0
|
||||
// 0 0 0 0 0 0|1|0
|
||||
map.set(til::rectangle{ til::point{ 2, 1 }, til::size{ 1, 3 } });
|
||||
map.set(til::rect{ til::point{ 2, 1 }, til::size{ 1, 3 } });
|
||||
|
||||
// 1 1 0 0 1 1 0|1|
|
||||
// 0 0 1 0 0 0 1|1|
|
||||
// 0 0 1 0 --> 0 0 1 0
|
||||
// 0 0 1 0 0 0 1 0
|
||||
map.set(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 2 } });
|
||||
map.set(til::rect{ til::point{ 3, 0 }, til::size{ 1, 2 } });
|
||||
|
||||
// 1 1 0 1 1 1 0 1
|
||||
// 0 0 1 1 |1|0 1 1
|
||||
@ -879,16 +875,16 @@ class BitmapTests
|
||||
// C _ D D
|
||||
// _ _ E _
|
||||
// _ F F _
|
||||
til::some<til::rectangle, 6> expected;
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 1 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
til::some<til::rect, 6> expected;
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 1 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
|
||||
Log::Comment(L"Run the iterator and collect the runs.");
|
||||
til::some<til::rectangle, 6> actual;
|
||||
til::some<til::rect, 6> actual;
|
||||
for (auto run : map.runs())
|
||||
{
|
||||
actual.push_back(run);
|
||||
@ -912,7 +908,7 @@ class BitmapTests
|
||||
|
||||
Log::Comment(L"Set point and validate runs updated.");
|
||||
const til::point setPoint{ 2, 2 };
|
||||
expected.push_back(til::rectangle{ setPoint });
|
||||
expected.push_back(til::rect{ 2, 2, 3, 3 });
|
||||
map.set(setPoint);
|
||||
|
||||
for (auto run : map.runs())
|
||||
@ -922,10 +918,10 @@ class BitmapTests
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
Log::Comment(L"Set rectangle and validate runs updated.");
|
||||
const til::rectangle setRect{ setPoint, til::size{ 2, 2 } };
|
||||
const til::rect setRect{ setPoint, til::size{ 2, 2 } };
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 3 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 3 }, til::size{ 2, 1 } });
|
||||
map.set(setRect);
|
||||
|
||||
actual.clear();
|
||||
@ -937,10 +933,10 @@ class BitmapTests
|
||||
|
||||
Log::Comment(L"Set all and validate runs updated.");
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 3 }, til::size{ 4, 1 } });
|
||||
map.set_all();
|
||||
|
||||
actual.clear();
|
||||
@ -953,9 +949,9 @@ class BitmapTests
|
||||
Log::Comment(L"Resize and validate runs updated.");
|
||||
const til::size newSize{ 3, 3 };
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 3, 1 } });
|
||||
map.resize(newSize);
|
||||
|
||||
actual.clear();
|
||||
@ -984,19 +980,19 @@ class BitmapTests
|
||||
// 0 0 0 0 0 0 0 0
|
||||
// 0 0 0 0 --> 0 0 0 0
|
||||
// 0 0 0 0 0 0 0 0
|
||||
map.set(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
map.set(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
|
||||
// 1 1 0 0 1 1 0 0
|
||||
// 0 0 0 0 0 0|1|0
|
||||
// 0 0 0 0 --> 0 0|1|0
|
||||
// 0 0 0 0 0 0|1|0
|
||||
map.set(til::rectangle{ til::point{ 2, 1 }, til::size{ 1, 3 } });
|
||||
map.set(til::rect{ til::point{ 2, 1 }, til::size{ 1, 3 } });
|
||||
|
||||
// 1 1 0 0 1 1 0|1|
|
||||
// 0 0 1 0 0 0 1|1|
|
||||
// 0 0 1 0 --> 0 0 1 0
|
||||
// 0 0 1 0 0 0 1 0
|
||||
map.set(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 2 } });
|
||||
map.set(til::rect{ til::point{ 3, 0 }, til::size{ 1, 2 } });
|
||||
|
||||
// 1 1 0 1 1 1 0 1
|
||||
// 0 0 1 1 |1|0 1 1
|
||||
@ -1017,16 +1013,16 @@ class BitmapTests
|
||||
// C _ D D
|
||||
// _ _ E _
|
||||
// _ F F _
|
||||
til::some<til::rectangle, 6> expected;
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 3, 0 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 1 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
til::some<til::rect, 6> expected;
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 1 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 1, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } });
|
||||
|
||||
Log::Comment(L"Run the iterator and collect the runs.");
|
||||
til::some<til::rectangle, 6> actual;
|
||||
til::some<til::rect, 6> actual;
|
||||
for (auto run : map.runs())
|
||||
{
|
||||
actual.push_back(run);
|
||||
@ -1050,7 +1046,7 @@ class BitmapTests
|
||||
|
||||
Log::Comment(L"Set point and validate runs updated.");
|
||||
const til::point setPoint{ 2, 2 };
|
||||
expected.push_back(til::rectangle{ setPoint });
|
||||
expected.push_back(til::rect{ 2, 2, 3, 3 });
|
||||
map.set(setPoint);
|
||||
|
||||
for (auto run : map.runs())
|
||||
@ -1060,10 +1056,10 @@ class BitmapTests
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
Log::Comment(L"Set rectangle and validate runs updated.");
|
||||
const til::rectangle setRect{ setPoint, til::size{ 2, 2 } };
|
||||
const til::rect setRect{ setPoint, til::size{ 2, 2 } };
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 2 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 2, 3 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 2 }, til::size{ 2, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 2, 3 }, til::size{ 2, 1 } });
|
||||
map.set(setRect);
|
||||
|
||||
actual.clear();
|
||||
@ -1075,10 +1071,10 @@ class BitmapTests
|
||||
|
||||
Log::Comment(L"Set all and validate runs updated.");
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 3 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 4, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 3 }, til::size{ 4, 1 } });
|
||||
map.set_all();
|
||||
|
||||
actual.clear();
|
||||
@ -1091,9 +1087,9 @@ class BitmapTests
|
||||
Log::Comment(L"Resize and validate runs updated.");
|
||||
const til::size newSize{ 3, 3 };
|
||||
expected.clear();
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 0 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 1 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rectangle{ til::point{ 0, 2 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 3, 1 } });
|
||||
expected.push_back(til::rect{ til::point{ 0, 2 }, til::size{ 3, 1 } });
|
||||
map.resize(newSize);
|
||||
|
||||
actual.clear();
|
||||
|
||||
@ -13,103 +13,103 @@ class MathTests
|
||||
{
|
||||
TEST_CLASS(MathTests);
|
||||
|
||||
template<typename TG, typename TX = ptrdiff_t>
|
||||
using FloatType = double;
|
||||
using IntegralType = int;
|
||||
using TargetType = int;
|
||||
|
||||
static constexpr auto nan = std::numeric_limits<FloatType>::quiet_NaN();
|
||||
static constexpr auto infinity = std::numeric_limits<FloatType>::infinity();
|
||||
|
||||
template<typename TG>
|
||||
struct TestCase
|
||||
{
|
||||
TG given;
|
||||
TX expected;
|
||||
TargetType expected;
|
||||
bool throws = false;
|
||||
};
|
||||
|
||||
template<class TilMath, typename TG, typename TX, int N>
|
||||
static void _RunCases(TilMath, const std::array<TestCase<TG, TX>, N>& cases)
|
||||
template<typename TG, typename TilMath>
|
||||
static void _RunCases(TilMath, const std::initializer_list<TestCase<TG>>& cases)
|
||||
{
|
||||
for (const auto& tc : cases)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(tc.expected, TilMath::template cast<decltype(tc.expected)>(tc.given));
|
||||
if (tc.throws)
|
||||
{
|
||||
VERIFY_THROWS(TilMath::template cast<decltype(tc.expected)>(tc.given), gsl::narrowing_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_ARE_EQUAL(tc.expected, TilMath::template cast<decltype(tc.expected)>(tc.given));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(Truncating)
|
||||
{
|
||||
std::array<TestCase<long double, ptrdiff_t>, 8> cases{
|
||||
TestCase<long double, ptrdiff_t>{ 1., 1 },
|
||||
{ 1.9, 1 },
|
||||
{ -7.1, -7 },
|
||||
{ -8.5, -8 },
|
||||
{ PTRDIFF_MAX + 0.5, PTRDIFF_MAX },
|
||||
{ PTRDIFF_MIN - 0.5, PTRDIFF_MIN },
|
||||
{ INFINITY, PTRDIFF_MAX },
|
||||
{ -INFINITY, PTRDIFF_MIN },
|
||||
};
|
||||
|
||||
_RunCases(til::math::truncating, cases);
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(til::math::details::truncating_t::cast<ptrdiff_t>(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
}
|
||||
|
||||
TEST_METHOD(Ceiling)
|
||||
{
|
||||
std::array<TestCase<long double, ptrdiff_t>, 8> cases{
|
||||
TestCase<long double, ptrdiff_t>{ 1., 1 },
|
||||
{ 1.9, 2 },
|
||||
{ -7.1, -7 },
|
||||
{ -8.5, -8 },
|
||||
{ PTRDIFF_MAX + 0.5, PTRDIFF_MAX },
|
||||
{ PTRDIFF_MIN - 0.5, PTRDIFF_MIN },
|
||||
{ INFINITY, PTRDIFF_MAX },
|
||||
{ -INFINITY, PTRDIFF_MIN },
|
||||
};
|
||||
|
||||
_RunCases(til::math::ceiling, cases);
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(til::math::details::ceiling_t::cast<ptrdiff_t>(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
_RunCases<FloatType>(
|
||||
til::math::ceiling,
|
||||
{
|
||||
{ 1., 1 },
|
||||
{ 1.9, 2 },
|
||||
{ -7.1, -7 },
|
||||
{ -8.5, -8 },
|
||||
{ INT_MAX - 0.1, INT_MAX },
|
||||
{ INT_MIN - 0.1, INT_MIN },
|
||||
{ INT_MAX + 1.1, 0, true },
|
||||
{ INT_MIN - 1.1, 0, true },
|
||||
{ infinity, 0, true },
|
||||
{ -infinity, 0, true },
|
||||
{ nan, 0, true },
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(Flooring)
|
||||
{
|
||||
std::array<TestCase<long double, ptrdiff_t>, 8> cases{
|
||||
TestCase<long double, ptrdiff_t>{ 1., 1 },
|
||||
{ 1.9, 1 },
|
||||
{ -7.1, -8 },
|
||||
{ -8.5, -9 },
|
||||
{ PTRDIFF_MAX + 0.5, PTRDIFF_MAX },
|
||||
{ PTRDIFF_MIN - 0.5, PTRDIFF_MIN },
|
||||
{ INFINITY, PTRDIFF_MAX },
|
||||
{ -INFINITY, PTRDIFF_MIN },
|
||||
};
|
||||
|
||||
_RunCases(til::math::flooring, cases);
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(til::math::details::flooring_t::cast<ptrdiff_t>(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
_RunCases<FloatType>(
|
||||
til::math::flooring,
|
||||
{
|
||||
{ 1., 1 },
|
||||
{ 1.9, 1 },
|
||||
{ -7.1, -8 },
|
||||
{ -8.5, -9 },
|
||||
{ INT_MAX + 0.1, INT_MAX },
|
||||
{ INT_MIN + 0.1, INT_MIN },
|
||||
{ INT_MAX + 1.1, 0, true },
|
||||
{ INT_MIN - 1.1, 0, true },
|
||||
{ infinity, 0, true },
|
||||
{ -infinity, 0, true },
|
||||
{ nan, 0, true },
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(Rounding)
|
||||
{
|
||||
std::array<TestCase<long double, ptrdiff_t>, 8> cases{
|
||||
TestCase<long double, ptrdiff_t>{ 1., 1 },
|
||||
{ 1.9, 2 },
|
||||
{ -7.1, -7 },
|
||||
{ -8.5, -9 },
|
||||
{ PTRDIFF_MAX + 0.5, PTRDIFF_MAX },
|
||||
{ PTRDIFF_MIN - 0.5, PTRDIFF_MIN },
|
||||
{ INFINITY, PTRDIFF_MAX },
|
||||
{ -INFINITY, PTRDIFF_MIN },
|
||||
};
|
||||
|
||||
_RunCases(til::math::rounding, cases);
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(til::math::details::rounding_t::cast<ptrdiff_t>(NAN), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
_RunCases<FloatType>(
|
||||
til::math::rounding,
|
||||
{
|
||||
{ 1., 1 },
|
||||
{ 1.9, 2 },
|
||||
{ -7.1, -7 },
|
||||
{ -8.5, -9 },
|
||||
{ INT_MAX + 0.1, INT_MAX },
|
||||
{ INT_MIN - 0.1, INT_MIN },
|
||||
{ INT_MAX + 1.1, 0, true },
|
||||
{ INT_MIN - 1.1, 0, true },
|
||||
{ infinity, 0, true },
|
||||
{ -infinity, 0, true },
|
||||
{ nan, 0, true },
|
||||
});
|
||||
}
|
||||
|
||||
TEST_METHOD(NormalIntegers)
|
||||
{
|
||||
std::array<TestCase<ptrdiff_t, int>, 4> cases{
|
||||
TestCase<ptrdiff_t, int>{ 1, 1 },
|
||||
{ -1, -1 },
|
||||
{ PTRDIFF_MAX, INT_MAX },
|
||||
{ PTRDIFF_MIN, INT_MIN },
|
||||
};
|
||||
|
||||
_RunCases(til::math::rounding, cases);
|
||||
_RunCases<IntegralType>(
|
||||
til::math::rounding,
|
||||
{
|
||||
{ 1, 1 },
|
||||
{ -1, -1 },
|
||||
{ INT_MAX, INT_MAX },
|
||||
{ INT_MIN, INT_MIN },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,8 @@
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
|
||||
#include <til/spsc.h>
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
@ -16,88 +16,51 @@ class SizeTests
|
||||
TEST_METHOD(DefaultConstruct)
|
||||
{
|
||||
const til::size sz;
|
||||
VERIFY_ARE_EQUAL(0, sz._width);
|
||||
VERIFY_ARE_EQUAL(0, sz._height);
|
||||
VERIFY_ARE_EQUAL(0, sz.width);
|
||||
VERIFY_ARE_EQUAL(0, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(RawConstruct)
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(5, sz._width);
|
||||
VERIFY_ARE_EQUAL(10, sz._height);
|
||||
VERIFY_ARE_EQUAL(5, sz.width);
|
||||
VERIFY_ARE_EQUAL(10, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(RawFloatingConstruct)
|
||||
{
|
||||
const til::size sz{ til::math::rounding, 3.2f, 7.8f };
|
||||
VERIFY_ARE_EQUAL(3, sz._width);
|
||||
VERIFY_ARE_EQUAL(8, sz._height);
|
||||
}
|
||||
|
||||
TEST_METHOD(UnsignedConstruct)
|
||||
{
|
||||
Log::Comment(L"0.) Normal unsigned construct.");
|
||||
{
|
||||
const size_t width = 5;
|
||||
const size_t height = 10;
|
||||
|
||||
const til::size sz{ width, height };
|
||||
VERIFY_ARE_EQUAL(5, sz._width);
|
||||
VERIFY_ARE_EQUAL(10, sz._height);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Unsigned construct overflow on width.");
|
||||
{
|
||||
constexpr size_t width = std::numeric_limits<size_t>().max();
|
||||
const size_t height = 10;
|
||||
|
||||
auto fn = [&]() {
|
||||
til::size sz{ width, height };
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Unsigned construct overflow on height.");
|
||||
{
|
||||
constexpr size_t height = std::numeric_limits<size_t>().max();
|
||||
const size_t width = 10;
|
||||
|
||||
auto fn = [&]() {
|
||||
til::size sz{ width, height };
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
}
|
||||
VERIFY_ARE_EQUAL(3, sz.width);
|
||||
VERIFY_ARE_EQUAL(8, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(SignedConstruct)
|
||||
{
|
||||
const ptrdiff_t width = -5;
|
||||
const ptrdiff_t height = -10;
|
||||
const auto width = -5;
|
||||
const auto height = -10;
|
||||
|
||||
const til::size sz{ width, height };
|
||||
VERIFY_ARE_EQUAL(width, sz._width);
|
||||
VERIFY_ARE_EQUAL(height, sz._height);
|
||||
VERIFY_ARE_EQUAL(width, sz.width);
|
||||
VERIFY_ARE_EQUAL(height, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(MixedRawTypeConstruct)
|
||||
{
|
||||
const ptrdiff_t a = -5;
|
||||
const auto a = -5;
|
||||
const int b = -10;
|
||||
|
||||
Log::Comment(L"Case 1: ptrdiff_t/int");
|
||||
Log::Comment(L"Case 1: til::CoordType/int");
|
||||
{
|
||||
const til::size sz{ a, b };
|
||||
VERIFY_ARE_EQUAL(a, sz._width);
|
||||
VERIFY_ARE_EQUAL(b, sz._height);
|
||||
VERIFY_ARE_EQUAL(a, sz.width);
|
||||
VERIFY_ARE_EQUAL(b, sz.height);
|
||||
}
|
||||
|
||||
Log::Comment(L"Case 2: int/ptrdiff_t");
|
||||
Log::Comment(L"Case 2: int/til::CoordType");
|
||||
{
|
||||
const til::size sz{ b, a };
|
||||
VERIFY_ARE_EQUAL(b, sz._width);
|
||||
VERIFY_ARE_EQUAL(a, sz._height);
|
||||
VERIFY_ARE_EQUAL(b, sz.width);
|
||||
VERIFY_ARE_EQUAL(a, sz.height);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,8 +69,8 @@ class SizeTests
|
||||
COORD coord{ -5, 10 };
|
||||
|
||||
const til::size sz{ coord };
|
||||
VERIFY_ARE_EQUAL(coord.X, sz._width);
|
||||
VERIFY_ARE_EQUAL(coord.Y, sz._height);
|
||||
VERIFY_ARE_EQUAL(coord.X, sz.width);
|
||||
VERIFY_ARE_EQUAL(coord.Y, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(SizeConstruct)
|
||||
@ -115,8 +78,8 @@ class SizeTests
|
||||
SIZE size{ 5, -10 };
|
||||
|
||||
const til::size sz{ size };
|
||||
VERIFY_ARE_EQUAL(size.cx, sz._width);
|
||||
VERIFY_ARE_EQUAL(size.cy, sz._height);
|
||||
VERIFY_ARE_EQUAL(size.cx, sz.width);
|
||||
VERIFY_ARE_EQUAL(size.cy, sz.height);
|
||||
}
|
||||
|
||||
TEST_METHOD(Equality)
|
||||
@ -226,35 +189,35 @@ class SizeTests
|
||||
const til::size sz{ 5, 10 };
|
||||
const til::size sz2{ 23, 47 };
|
||||
|
||||
const til::size expected{ sz.width() + sz2.width(), sz.height() + sz2.height() };
|
||||
const til::size expected{ sz.width + sz2.width, sz.height + sz2.height };
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, sz + sz2);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Addition results in value that is too large (width).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ bigSize, static_cast<ptrdiff_t>(0) };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ bigSize, static_cast<til::CoordType>(0) };
|
||||
const til::size sz2{ 1, 1 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz + sz2;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Addition results in value that is too large (height).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ static_cast<ptrdiff_t>(0), bigSize };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ static_cast<til::CoordType>(0), bigSize };
|
||||
const til::size sz2{ 1, 1 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz + sz2;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,35 +228,35 @@ class SizeTests
|
||||
const til::size sz{ 5, 10 };
|
||||
const til::size sz2{ 23, 47 };
|
||||
|
||||
const til::size expected{ sz.width() - sz2.width(), sz.height() - sz2.height() };
|
||||
const til::size expected{ sz.width - sz2.width, sz.height - sz2.height };
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, sz - sz2);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Subtraction results in value that is too small (width).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ bigSize, static_cast<ptrdiff_t>(0) };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ bigSize, static_cast<til::CoordType>(0) };
|
||||
const til::size sz2{ -2, -2 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz2 - sz;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Subtraction results in value that is too small (height).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ static_cast<ptrdiff_t>(0), bigSize };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ static_cast<til::CoordType>(0), bigSize };
|
||||
const til::size sz2{ -2, -2 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz2 - sz;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,35 +267,35 @@ class SizeTests
|
||||
const til::size sz{ 5, 10 };
|
||||
const til::size sz2{ 23, 47 };
|
||||
|
||||
const til::size expected{ sz.width() * sz2.width(), sz.height() * sz2.height() };
|
||||
const til::size expected{ sz.width * sz2.width, sz.height * sz2.height };
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, sz * sz2);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Multiplication results in value that is too large (width).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ bigSize, static_cast<ptrdiff_t>(0) };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ bigSize, static_cast<til::CoordType>(0) };
|
||||
const til::size sz2{ 10, 10 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz* sz2;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Multiplication results in value that is too large (height).");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ static_cast<ptrdiff_t>(0), bigSize };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ static_cast<til::CoordType>(0), bigSize };
|
||||
const til::size sz2{ 10, 10 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz* sz2;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,7 +306,7 @@ class SizeTests
|
||||
const til::size sz{ 5, 10 };
|
||||
const float scale = 1.783f;
|
||||
|
||||
const til::size expected{ static_cast<ptrdiff_t>(ceil(5 * scale)), static_cast<ptrdiff_t>(ceil(10 * scale)) };
|
||||
const til::size expected{ static_cast<til::CoordType>(ceil(5 * scale)), static_cast<til::CoordType>(ceil(10 * scale)) };
|
||||
|
||||
const auto actual = sz.scale(til::math::ceiling, scale);
|
||||
|
||||
@ -359,7 +322,7 @@ class SizeTests
|
||||
sz.scale(til::math::ceiling, scale);
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,22 +333,22 @@ class SizeTests
|
||||
const til::size sz{ 555, 510 };
|
||||
const til::size sz2{ 23, 47 };
|
||||
|
||||
const til::size expected{ sz.width() / sz2.width(), sz.height() / sz2.height() };
|
||||
const til::size expected{ sz.width / sz2.width, sz.height / sz2.height };
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, sz / sz2);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Division by zero");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
const til::size sz{ bigSize, static_cast<ptrdiff_t>(0) };
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ bigSize, static_cast<til::CoordType>(0) };
|
||||
const til::size sz2{ 1, 1 };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz2 / sz;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,28 +379,16 @@ class SizeTests
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(Width)
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(sz._width, sz.width());
|
||||
}
|
||||
|
||||
TEST_METHOD(WidthCast)
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(static_cast<SHORT>(sz._width), sz.width<SHORT>());
|
||||
}
|
||||
|
||||
TEST_METHOD(Height)
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(sz._height, sz.height());
|
||||
VERIFY_ARE_EQUAL(static_cast<SHORT>(sz.width), sz.narrow_width<SHORT>());
|
||||
}
|
||||
|
||||
TEST_METHOD(HeightCast)
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(static_cast<SHORT>(sz._height), sz.height<SHORT>());
|
||||
VERIFY_ARE_EQUAL(static_cast<SHORT>(sz.height), sz.narrow_height<SHORT>());
|
||||
}
|
||||
|
||||
TEST_METHOD(Area)
|
||||
@ -445,19 +396,19 @@ class SizeTests
|
||||
Log::Comment(L"0.) Area of two things that should be in bounds.");
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
VERIFY_ARE_EQUAL(sz._width * sz._height, sz.area());
|
||||
VERIFY_ARE_EQUAL(sz.width * sz.height, sz.area());
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Area is out of bounds on multiplication.");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<ptrdiff_t>().max();
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<til::CoordType>().max();
|
||||
const til::size sz{ bigSize, bigSize };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz.area();
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
TEST_METHOD(AreaCast)
|
||||
@ -470,51 +421,14 @@ class SizeTests
|
||||
|
||||
Log::Comment(L"1.) Area is out of bounds on multiplication.");
|
||||
{
|
||||
constexpr ptrdiff_t bigSize = std::numeric_limits<SHORT>().max();
|
||||
constexpr til::CoordType bigSize = std::numeric_limits<SHORT>().max();
|
||||
const til::size sz{ bigSize, bigSize };
|
||||
|
||||
auto fn = [&]() {
|
||||
sz.area<SHORT>();
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(CastToCoord)
|
||||
{
|
||||
Log::Comment(L"0.) Typical situation.");
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
COORD val = sz;
|
||||
VERIFY_ARE_EQUAL(5, val.X);
|
||||
VERIFY_ARE_EQUAL(10, val.Y);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Overflow on width.");
|
||||
{
|
||||
constexpr ptrdiff_t width = std::numeric_limits<ptrdiff_t>().max();
|
||||
const ptrdiff_t height = 10;
|
||||
const til::size sz{ width, height };
|
||||
|
||||
auto fn = [&]() {
|
||||
COORD val = sz;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Overflow on height.");
|
||||
{
|
||||
constexpr ptrdiff_t height = std::numeric_limits<ptrdiff_t>().max();
|
||||
const ptrdiff_t width = 10;
|
||||
const til::size sz{ width, height };
|
||||
|
||||
auto fn = [&]() {
|
||||
COORD val = sz;
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,55 +437,55 @@ class SizeTests
|
||||
Log::Comment(L"0.) Typical situation.");
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
SIZE val = sz;
|
||||
SIZE val = sz.to_win32_size();
|
||||
VERIFY_ARE_EQUAL(5, val.cx);
|
||||
VERIFY_ARE_EQUAL(10, val.cy);
|
||||
}
|
||||
|
||||
Log::Comment(L"1.) Fit max width into SIZE (may overflow).");
|
||||
{
|
||||
constexpr ptrdiff_t width = std::numeric_limits<ptrdiff_t>().max();
|
||||
const ptrdiff_t height = 10;
|
||||
constexpr til::CoordType width = std::numeric_limits<til::CoordType>().max();
|
||||
const auto height = 10;
|
||||
const til::size sz{ width, height };
|
||||
|
||||
// On some platforms, ptrdiff_t will fit inside cx/cy
|
||||
// On some platforms, til::CoordType will fit inside cx/cy
|
||||
const bool overflowExpected = width > std::numeric_limits<decltype(SIZE::cx)>().max();
|
||||
|
||||
if (overflowExpected)
|
||||
{
|
||||
auto fn = [&]() {
|
||||
SIZE val = sz;
|
||||
SIZE val = sz.to_win32_size();
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE val = sz;
|
||||
SIZE val = sz.to_win32_size();
|
||||
VERIFY_ARE_EQUAL(width, val.cx);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Comment(L"2.) Fit max height into SIZE (may overflow).");
|
||||
{
|
||||
constexpr ptrdiff_t height = std::numeric_limits<ptrdiff_t>().max();
|
||||
const ptrdiff_t width = 10;
|
||||
constexpr til::CoordType height = std::numeric_limits<til::CoordType>().max();
|
||||
const auto width = 10;
|
||||
const til::size sz{ width, height };
|
||||
|
||||
// On some platforms, ptrdiff_t will fit inside cx/cy
|
||||
// On some platforms, til::CoordType will fit inside cx/cy
|
||||
const bool overflowExpected = height > std::numeric_limits<decltype(SIZE::cy)>().max();
|
||||
|
||||
if (overflowExpected)
|
||||
{
|
||||
auto fn = [&]() {
|
||||
SIZE val = sz;
|
||||
SIZE val = sz.to_win32_size();
|
||||
};
|
||||
|
||||
VERIFY_THROWS_SPECIFIC(fn(), wil::ResultException, [](wil::ResultException& e) { return e.GetErrorCode() == E_ABORT; });
|
||||
VERIFY_THROWS(fn(), gsl::narrowing_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
SIZE val = sz;
|
||||
SIZE val = sz.to_win32_size();
|
||||
VERIFY_ARE_EQUAL(height, val.cy);
|
||||
}
|
||||
}
|
||||
@ -582,61 +496,40 @@ class SizeTests
|
||||
Log::Comment(L"0.) Typical situation.");
|
||||
{
|
||||
const til::size sz{ 5, 10 };
|
||||
D2D1_SIZE_F val = sz;
|
||||
D2D1_SIZE_F val = sz.to_d2d_size();
|
||||
VERIFY_ARE_EQUAL(5, val.width);
|
||||
VERIFY_ARE_EQUAL(10, val.height);
|
||||
}
|
||||
|
||||
// All ptrdiff_ts fit into a float, so there's no exception tests.
|
||||
// All til::CoordTypes fit into a float, so there's no exception tests.
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct SizeTypeWith_XY
|
||||
{
|
||||
T X, Y;
|
||||
};
|
||||
template<typename T>
|
||||
struct SizeTypeWith_cxcy
|
||||
{
|
||||
T cx, cy;
|
||||
};
|
||||
template<typename T>
|
||||
struct SizeTypeWith_WidthHeight
|
||||
{
|
||||
T Width, Height;
|
||||
};
|
||||
TEST_METHOD(CastFromFloatWithMathTypes)
|
||||
{
|
||||
SizeTypeWith_XY<float> XYFloatIntegral{ 1.f, 2.f };
|
||||
SizeTypeWith_XY<float> XYFloat{ 1.6f, 2.4f };
|
||||
SizeTypeWith_cxcy<double> cxcyDoubleIntegral{ 3., 4. };
|
||||
SizeTypeWith_cxcy<double> cxcyDouble{ 3.6, 4.4 };
|
||||
SizeTypeWith_WidthHeight<double> WHDoubleIntegral{ 5., 6. };
|
||||
SizeTypeWith_WidthHeight<double> WHDouble{ 5.6, 6.4 };
|
||||
Log::Comment(L"0.) Ceiling");
|
||||
{
|
||||
{
|
||||
til::size converted{ til::math::ceiling, XYFloatIntegral };
|
||||
til::size converted{ til::math::ceiling, 1.f, 2.f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::ceiling, XYFloat };
|
||||
til::size converted{ til::math::ceiling, 1.6f, 2.4f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 2, 3 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::ceiling, cxcyDoubleIntegral };
|
||||
til::size converted{ til::math::ceiling, 3., 4. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::ceiling, cxcyDouble };
|
||||
til::size converted{ til::math::ceiling, 3.6, 4.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 4, 5 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::ceiling, WHDoubleIntegral };
|
||||
til::size converted{ til::math::ceiling, 5., 6. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::ceiling, WHDouble };
|
||||
til::size converted{ til::math::ceiling, 5.6, 6.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 6, 7 }), converted);
|
||||
}
|
||||
}
|
||||
@ -644,27 +537,27 @@ class SizeTests
|
||||
Log::Comment(L"1.) Flooring");
|
||||
{
|
||||
{
|
||||
til::size converted{ til::math::flooring, XYFloatIntegral };
|
||||
til::size converted{ til::math::flooring, 1.f, 2.f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::flooring, XYFloat };
|
||||
til::size converted{ til::math::flooring, 1.6f, 2.4f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::flooring, cxcyDoubleIntegral };
|
||||
til::size converted{ til::math::flooring, 3., 4. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::flooring, cxcyDouble };
|
||||
til::size converted{ til::math::flooring, 3.6, 4.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::flooring, WHDoubleIntegral };
|
||||
til::size converted{ til::math::flooring, 5., 6. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::flooring, WHDouble };
|
||||
til::size converted{ til::math::flooring, 5.6, 6.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
}
|
||||
@ -672,57 +565,29 @@ class SizeTests
|
||||
Log::Comment(L"2.) Rounding");
|
||||
{
|
||||
{
|
||||
til::size converted{ til::math::rounding, XYFloatIntegral };
|
||||
til::size converted{ til::math::rounding, 1.f, 2.f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::rounding, XYFloat };
|
||||
til::size converted{ til::math::rounding, 1.6f, 2.4f };
|
||||
VERIFY_ARE_EQUAL((til::size{ 2, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::rounding, cxcyDoubleIntegral };
|
||||
til::size converted{ til::math::rounding, 3., 4. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::rounding, cxcyDouble };
|
||||
til::size converted{ til::math::rounding, 3.6, 4.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 4, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::rounding, WHDoubleIntegral };
|
||||
til::size converted{ til::math::rounding, 5., 6. };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::rounding, WHDouble };
|
||||
til::size converted{ til::math::rounding, 5.6, 6.4 };
|
||||
VERIFY_ARE_EQUAL((til::size{ 6, 6 }), converted);
|
||||
}
|
||||
}
|
||||
|
||||
Log::Comment(L"3.) Truncating");
|
||||
{
|
||||
{
|
||||
til::size converted{ til::math::truncating, XYFloatIntegral };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::truncating, XYFloat };
|
||||
VERIFY_ARE_EQUAL((til::size{ 1, 2 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::truncating, cxcyDoubleIntegral };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::truncating, cxcyDouble };
|
||||
VERIFY_ARE_EQUAL((til::size{ 3, 4 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::truncating, WHDoubleIntegral };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
{
|
||||
til::size converted{ til::math::truncating, WHDouble };
|
||||
VERIFY_ARE_EQUAL((til::size{ 5, 6 }), converted);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -287,16 +287,16 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit)
|
||||
// If we're past document end,
|
||||
// set us to ONE BEFORE the document end.
|
||||
// This allows us to expand properly.
|
||||
if (bufferSize.CompareInBounds(_start, documentEnd, true) >= 0)
|
||||
if (bufferSize.CompareInBounds(_start, documentEnd.to_win32_coord(), true) >= 0)
|
||||
{
|
||||
_start = documentEnd;
|
||||
_start = documentEnd.to_win32_coord();
|
||||
bufferSize.DecrementInBounds(_start, true);
|
||||
}
|
||||
|
||||
if (unit == TextUnit_Character)
|
||||
{
|
||||
_start = buffer.GetGlyphStart(_start, documentEnd);
|
||||
_end = buffer.GetGlyphEnd(_start, true, documentEnd);
|
||||
_start = buffer.GetGlyphStart(til::point{ _start }, documentEnd).to_win32_coord();
|
||||
_end = buffer.GetGlyphEnd(til::point{ _start }, true, documentEnd).to_win32_coord();
|
||||
}
|
||||
else if (unit <= TextUnit_Word)
|
||||
{
|
||||
@ -308,10 +308,10 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit)
|
||||
{
|
||||
// expand to line
|
||||
_start.X = 0;
|
||||
if (_start.Y == documentEnd.y())
|
||||
if (_start.Y == documentEnd.y)
|
||||
{
|
||||
// we're on the last line
|
||||
_end = documentEnd;
|
||||
_end = documentEnd.to_win32_coord();
|
||||
bufferSize.IncrementInBounds(_end, true);
|
||||
}
|
||||
else
|
||||
@ -324,7 +324,7 @@ void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit)
|
||||
{
|
||||
// expand to document
|
||||
_start = bufferSize.Origin();
|
||||
_end = documentEnd;
|
||||
_end = documentEnd.to_win32_coord();
|
||||
}
|
||||
}
|
||||
|
||||
@ -859,7 +859,7 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
|
||||
|
||||
// these viewport vars are converted to the buffer coordinate space
|
||||
const auto viewport = bufferSize.ConvertToOrigin(_pData->GetViewport());
|
||||
const til::point viewportOrigin = viewport.Origin();
|
||||
const auto viewportOrigin = viewport.Origin();
|
||||
const auto viewportEnd = viewport.EndExclusive();
|
||||
|
||||
// startAnchor: the earliest COORD we will get a bounding rect for
|
||||
@ -900,8 +900,8 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
|
||||
// Convert the buffer coordinates to an equivalent range of
|
||||
// screen cells, taking line rendition into account.
|
||||
const auto lineRendition = buffer.GetLineRendition(rect.Top);
|
||||
til::rectangle r{ BufferToScreenLine(rect, lineRendition) };
|
||||
r -= viewportOrigin;
|
||||
til::rect r{ BufferToScreenLine(rect, lineRendition) };
|
||||
r -= til::point{ viewportOrigin };
|
||||
_getBoundingRect(r, coords);
|
||||
}
|
||||
}
|
||||
@ -1038,7 +1038,7 @@ try
|
||||
// If so, clamp each endpoint to the end of the document.
|
||||
constexpr auto endpoint = TextPatternRangeEndpoint::TextPatternRangeEndpoint_Start;
|
||||
const auto bufferSize{ _pData->GetTextBuffer().GetSize() };
|
||||
const COORD documentEnd = _getDocumentEnd();
|
||||
const COORD documentEnd = _getDocumentEnd().to_win32_coord();
|
||||
if (bufferSize.CompareInBounds(_start, documentEnd, true) > 0)
|
||||
{
|
||||
_start = documentEnd;
|
||||
@ -1109,7 +1109,7 @@ IFACEMETHODIMP UiaTextRangeBase::MoveEndpointByUnit(_In_ TextPatternRangeEndpoin
|
||||
auto documentEnd = bufferSize.EndExclusive();
|
||||
try
|
||||
{
|
||||
documentEnd = _getDocumentEnd();
|
||||
documentEnd = _getDocumentEnd().to_win32_coord();
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
@ -1381,20 +1381,20 @@ const til::point UiaTextRangeBase::_getDocumentEnd() const
|
||||
// - coords - vector to add the calculated coords to
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void UiaTextRangeBase::_getBoundingRect(const til::rectangle textRect, _Inout_ std::vector<double>& coords) const
|
||||
void UiaTextRangeBase::_getBoundingRect(const til::rect& textRect, _Inout_ std::vector<double>& coords) const
|
||||
{
|
||||
const til::size currentFontSize = _getScreenFontSize();
|
||||
const til::size currentFontSize{ _getScreenFontSize() };
|
||||
|
||||
POINT topLeft{ 0 };
|
||||
POINT bottomRight{ 0 };
|
||||
|
||||
// we want to clamp to a long (output type), not a short (input type)
|
||||
// so we need to explicitly say <long,long>
|
||||
topLeft.x = base::ClampMul(textRect.left(), currentFontSize.width());
|
||||
topLeft.y = base::ClampMul(textRect.top(), currentFontSize.height());
|
||||
topLeft.x = base::ClampMul(textRect.left, currentFontSize.width);
|
||||
topLeft.y = base::ClampMul(textRect.top, currentFontSize.height);
|
||||
|
||||
bottomRight.x = base::ClampMul(textRect.right(), currentFontSize.width());
|
||||
bottomRight.y = base::ClampMul(textRect.bottom(), currentFontSize.height());
|
||||
bottomRight.x = base::ClampMul(textRect.right, currentFontSize.width);
|
||||
bottomRight.y = base::ClampMul(textRect.bottom, currentFontSize.height);
|
||||
|
||||
// convert the coords to be relative to the screen instead of
|
||||
// the client window
|
||||
@ -1440,7 +1440,7 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount,
|
||||
const auto& buffer = _pData->GetTextBuffer();
|
||||
|
||||
bool success = true;
|
||||
til::point target = GetEndpoint(endpoint);
|
||||
til::point target{ GetEndpoint(endpoint) };
|
||||
const auto documentEnd{ _getDocumentEnd() };
|
||||
while (std::abs(*pAmountMoved) < std::abs(moveCount) && success)
|
||||
{
|
||||
@ -1465,7 +1465,7 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount,
|
||||
}
|
||||
}
|
||||
|
||||
SetEndpoint(endpoint, target);
|
||||
SetEndpoint(endpoint, target.to_win32_coord());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@ -1510,7 +1510,7 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount,
|
||||
{
|
||||
case MovementDirection::Forward:
|
||||
{
|
||||
if (bufferSize.CompareInBounds(nextPos, documentEnd, true) >= 0)
|
||||
if (bufferSize.CompareInBounds(nextPos, documentEnd.to_win32_coord(), true) >= 0)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
@ -1521,7 +1521,7 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount,
|
||||
}
|
||||
else if (allowBottomExclusive)
|
||||
{
|
||||
resultPos = documentEnd;
|
||||
resultPos = documentEnd.to_win32_coord();
|
||||
(*pAmountMoved)++;
|
||||
}
|
||||
else
|
||||
@ -1615,7 +1615,7 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount,
|
||||
auto documentEnd{ bufferSize.EndExclusive() };
|
||||
try
|
||||
{
|
||||
documentEnd = _getDocumentEnd();
|
||||
documentEnd = _getDocumentEnd().to_win32_coord();
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
@ -1727,7 +1727,7 @@ void UiaTextRangeBase::_moveEndpointByUnitDocument(_In_ const int moveCount,
|
||||
auto documentEnd{ bufferSize.EndExclusive() };
|
||||
try
|
||||
{
|
||||
documentEnd = _getDocumentEnd();
|
||||
documentEnd = _getDocumentEnd().to_win32_coord();
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
|
||||
@ -152,7 +152,7 @@ namespace Microsoft::Console::Types
|
||||
const Viewport _getOptimizedBufferSize() const noexcept;
|
||||
const til::point _getDocumentEnd() const;
|
||||
|
||||
void _getBoundingRect(const til::rectangle textRect, _Inout_ std::vector<double>& coords) const;
|
||||
void _getBoundingRect(const til::rect& textRect, _Inout_ std::vector<double>& coords) const;
|
||||
|
||||
void _expandToEnclosingUnit(TextUnit unit);
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<DisplayString>{{X: {_x,d}, Y: {_y,d}}}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="til::rectangle">
|
||||
<Type Name="til::rect">
|
||||
<DisplayString>{{L: {_topLeft._x}, T: {_topLeft._y}, R: {_bottomRight._x} B: {_bottomRight._y} [W: {_bottomRight._x - _topLeft._x} x H: {_bottomRight._y - _topLeft._y} -> A: {(_bottomRight._x - _topLeft._x) * (_bottomRight._y - _topLeft._y)}]}}</DisplayString>
|
||||
</Type>
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[Parameter(Position=0, ValueFromPipeline=$true)]
|
||||
[string]$TestPath = "UiaTests.csv"
|
||||
[string]$TestPath = "$PSScriptRoot/../../tools/TestTableWriter/UiaTests.csv"
|
||||
)
|
||||
|
||||
# 0. Generate a comment telling people to not modify these tests in the .cpp
|
||||
@ -24,7 +24,7 @@ $result = "// Copyright (c) Microsoft Corporation.
|
||||
# 1. Define a few helpful variables to make life easier.
|
||||
$result += "
|
||||
// Define a few helpful variables
|
||||
constexpr til::rectangle bufferSize{ 0, 0, 80, 300 };
|
||||
constexpr til::rect bufferSize{ 0, 0, 80, 300 };
|
||||
constexpr short midX{ 40 };
|
||||
constexpr short midY{ 150 };
|
||||
constexpr short midPopulatedY{ 75 };
|
||||
@ -77,7 +77,7 @@ foreach ($var in $vars)
|
||||
# i. Contains "segment" --> define point at the beginning of a text segment
|
||||
if ($segmentHeuristic)
|
||||
{
|
||||
$result += "constexpr til::point {0}{{ {1}, {2}.y() }};" -f $var, $var.Substring(0, 8), $var.Substring(9, $var.Length - $var.IndexOf("L") - 1);
|
||||
$result += "constexpr til::point {0}{{ {1}, {2}.y }};" -f $var, $var.Substring(0, 8), $var.Substring(9, $var.Length - $var.IndexOf("L") - 1);
|
||||
}
|
||||
# ii. Contains number --> requires movement
|
||||
elseif ($movementHeuristic)
|
||||
@ -125,7 +125,7 @@ foreach ($var in $vars)
|
||||
elseif ($leftHeuristic)
|
||||
{
|
||||
$standardVar = $var.Split("Left")[0]
|
||||
$result += "constexpr til::point {0}{{ bufferSize.left(), {1}.y() }};" -f $var, $standardVar;
|
||||
$result += "constexpr til::point {0}{{ bufferSize.left, {1}.y }};" -f $var, $standardVar;
|
||||
}
|
||||
$result += "`n";
|
||||
}
|
||||
@ -182,4 +182,4 @@ foreach ($test in $tests)
|
||||
}
|
||||
$result += "};`n`n"
|
||||
|
||||
$result > "..\..\src\interactivity\win32\ut_interactivity_win32\GeneratedUiaTextRangeMovementTests.g.cpp";
|
||||
$result > "$PSScriptRoot/../../src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user