2020-03-13 01:04:43 +01:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#ifdef UNIT_TESTING
|
|
|
|
class PointTests;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|
|
|
{
|
|
|
|
class point
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
constexpr point() noexcept :
|
|
|
|
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 point(int x, int y) noexcept :
|
|
|
|
point(static_cast<ptrdiff_t>(x), static_cast<ptrdiff_t>(y))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr point(ptrdiff_t x, ptrdiff_t y) noexcept :
|
|
|
|
_x(x),
|
|
|
|
_y(y)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
til::rectangle (#4912)
## Summary of the Pull Request
Introduces convenience type `til::rectangle` which automatically implements our best practices for rectangle-related types and provides automatic conversions in/out of the relevant types.
## PR Checklist
* [x] In support of Differential Rendering #778
* [X] I work here.
* [x] Tests added/passed
* [x] I'm a core contributor.
## Detailed Description of the Pull Request / Additional comments
- Automatically converts in from anything with a Left/Top/Right/Bottom or left/top/right/bottom (Win32 `RECT`)
- Automatically converts Console type `SMALL_RECT` and shifts it from **inclusive** to **exclusive** on instantiation
- Automatically converts out to `SMALL_RECT` (converting back to **inclusive**), `RECT`, or `D2D1_RECT_F`.
- Constructs from bare integers written into source file
- Constructs from a single `til::point` as a 1x1 size rectangle with top-left corner (origin) at that point
- Constructs from a single `til::size` as a WxH size rectangle with top-left corner (origin) at 0,0
- Constructs from a `til::point` and a `til::size` representing the top-left corner and the width by height.
- Constructs from a `til::point` and another `til::point` representing the top-left corner and the **exclusive** bottom-right corner.
- Default constructs to empty
- Uses Chromium numerics for all basic math operations (+, -, *, /)
- Provides equality tests
- Provides `operator bool` to know when it's valid (has an area > 0) and `empty()` to know the contrary
- Accessors for left/top/right/bottom
- Type converting accessors (that use safe conversions and throw) for left/top/right/bottom
- Convenience methods for finding width/height (with Chromium numerics operations) and type-converting templates (with Chromium numerics conversions).
- Accessors for origin (top-left point) and the size/dimensions (as a `til::size`).
- Intersect operation on `operator &` to find where two `til::rectangle`s overlap, returned as a `til::rectangle`.
- Union operation on `operator |` to find the total area covered by two `til::rectangles`, returned as a `til::rectangle`.
- Subtract operation on `operator -` to find the area remaining after one `til::rectangle` is removed from another, returned as a `til::some<til::rectangle, 4>`.
- TAEF/WEX Output and Comparators so they will print very nicely with `VERIFY` and `Log` macros in our testing suite.
- Additional comparators, TAEF/WEX output, and tests written on `til::some` to support the Subtract operation.
- A natvis
## Validation Steps Performed
- See automated tests of functionality.
2020-03-14 18:27:47 +01:00
|
|
|
// This template will convert to size from anything that has an X and a Y field that appear convertible to an integer value
|
2020-03-13 01:04:43 +01:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
til::rectangle (#4912)
## Summary of the Pull Request
Introduces convenience type `til::rectangle` which automatically implements our best practices for rectangle-related types and provides automatic conversions in/out of the relevant types.
## PR Checklist
* [x] In support of Differential Rendering #778
* [X] I work here.
* [x] Tests added/passed
* [x] I'm a core contributor.
## Detailed Description of the Pull Request / Additional comments
- Automatically converts in from anything with a Left/Top/Right/Bottom or left/top/right/bottom (Win32 `RECT`)
- Automatically converts Console type `SMALL_RECT` and shifts it from **inclusive** to **exclusive** on instantiation
- Automatically converts out to `SMALL_RECT` (converting back to **inclusive**), `RECT`, or `D2D1_RECT_F`.
- Constructs from bare integers written into source file
- Constructs from a single `til::point` as a 1x1 size rectangle with top-left corner (origin) at that point
- Constructs from a single `til::size` as a WxH size rectangle with top-left corner (origin) at 0,0
- Constructs from a `til::point` and a `til::size` representing the top-left corner and the width by height.
- Constructs from a `til::point` and another `til::point` representing the top-left corner and the **exclusive** bottom-right corner.
- Default constructs to empty
- Uses Chromium numerics for all basic math operations (+, -, *, /)
- Provides equality tests
- Provides `operator bool` to know when it's valid (has an area > 0) and `empty()` to know the contrary
- Accessors for left/top/right/bottom
- Type converting accessors (that use safe conversions and throw) for left/top/right/bottom
- Convenience methods for finding width/height (with Chromium numerics operations) and type-converting templates (with Chromium numerics conversions).
- Accessors for origin (top-left point) and the size/dimensions (as a `til::size`).
- Intersect operation on `operator &` to find where two `til::rectangle`s overlap, returned as a `til::rectangle`.
- Union operation on `operator |` to find the total area covered by two `til::rectangles`, returned as a `til::rectangle`.
- Subtract operation on `operator -` to find the area remaining after one `til::rectangle` is removed from another, returned as a `til::some<til::rectangle, 4>`.
- TAEF/WEX Output and Comparators so they will print very nicely with `VERIFY` and `Log` macros in our testing suite.
- Additional comparators, TAEF/WEX output, and tests written on `til::some` to support the Subtract operation.
- A natvis
## Validation Steps Performed
- See automated tests of functionality.
2020-03-14 18:27:47 +01:00
|
|
|
// This template will convert to size from anything that has a x and a y field that appear convertible to an integer value
|
2020-03-13 01:04:43 +01:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// 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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:48:49 +01:00
|
|
|
// This template will convert to size from anything that has a X and a Y field that are floating-point;
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// 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"
|
2020-03-27 23:48:49 +01:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// This template will convert to size from anything that has a x and a y field that are floating-point;
|
Adjusts High DPI scaling to enable differential rendering (#5345)
## Summary of the Pull Request
- Adjusts scaling practices in `DxEngine` (and related scaling practices in `TerminalControl`) for pixel-perfect row baselines and spacing at High DPI such that differential row-by-row rendering can be applied at High DPI.
## References
- #5185
## PR Checklist
* [x] Closes #5320, closes #3515, closes #1064
* [x] I work here.
* [x] Manually tested.
* [x] No doc.
* [x] Am core contributor. Also discussed with some of them already via Teams.
## Detailed Description of the Pull Request / Additional comments
**WAS:**
- We were using implicit DPI scaling on the `ID2D1RenderTarget` and running all of our processing in DIPs (Device-Independent Pixels). That's all well and good for getting things bootstrapped quickly, but it leaves the actual scaling of the draw commands up to the discretion of the rendering target.
- When we don't get to explicitly choose exactly how many pixels tall/wide and our X/Y placement perfectly, the nature of floating point multiplication and division required to do the presentation can cause us to drift off slightly out of our control depending on what the final display resolution actually is.
- Differential drawing cannot work unless we can know the exact integer pixels that need to be copied/moved/preserved/replaced between frames to give to the `IDXGISwapChain1::Present1` method. If things spill into fractional pixels or the sizes of rows/columns vary as they are rounded up and down implicitly, then we cannot do the differential rendering.
**NOW:**
- When deciding on a font, the `DxEngine` will take the scale factor into account and adjust the proposed height of the requested font. Then the remainder of the existing code that adjusts the baseline and integer-ifies each character cell will run naturally from there. That code already works correctly to align the height at normal DPI and scale out the font heights and advances to take an exact integer of pixels.
- `TermControl` has to use the scale now, in some places, and stop scaling in other places. This has to do with how the target's nature used to be implicit and is now explicit. For instance, determining where the cursor click hits must be scaled now. And determining the pixel size of the display canvas must no longer be scaled.
- `DxEngine` will no longer attempt to scale the invalid regions per my attempts in #5185 because the cell size is scaled. So it should work the same as at 96 DPI.
- The block is removed from the `DxEngine` that was causing a full invalidate on every frame at High DPI.
- A TODO was removed from `TermControl` that was invalidating everything when the DPI changed because the underlying renderer will already do that.
## Validation Steps Performed
* [x] Check at 150% DPI. Print text, scroll text down and up, do selection.
* [x] Check at 100% DPI. Print text, scroll text down and up, do selection.
* [x] Span two different DPI monitors and drag between them.
* [x] Giant pile of tests in https://github.com/microsoft/terminal/pull/5345#issuecomment-614127648
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
2020-04-22 23:59:51 +02:00
|
|
|
// 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"
|
2020-03-27 23:48:49 +01:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
constexpr bool operator==(const point& other) const noexcept
|
|
|
|
{
|
|
|
|
return _x == other._x &&
|
|
|
|
_y == other._y;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr bool operator!=(const point& other) const noexcept
|
|
|
|
{
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 21:24:43 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
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 };
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:37:23 +01:00
|
|
|
point& operator+=(const point& other)
|
|
|
|
{
|
|
|
|
*this = *this + other;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
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 };
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:37:23 +01:00
|
|
|
point& operator-=(const point& other)
|
|
|
|
{
|
|
|
|
*this = *this - other;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
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 };
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:37:23 +01:00
|
|
|
point& operator*=(const point& other)
|
|
|
|
{
|
|
|
|
*this = *this * other;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2020-04-13 22:09:02 +02:00
|
|
|
template<typename TilMath>
|
|
|
|
point scale(TilMath, const float scale) 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);
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
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 };
|
|
|
|
}
|
|
|
|
|
2020-03-27 23:37:23 +01:00
|
|
|
point& operator/=(const point& other)
|
|
|
|
{
|
|
|
|
*this = *this / other;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
Manually pass mouse wheel messages to TermControls (#5131)
## Summary of the Pull Request
As we've learned in #979, not all touchpads are created equal. Some of them have bad drivers that makes scrolling inactive windows not work. For whatever reason, these devices think the Terminal is all one giant inactive window, so we don't get the mouse wheel events through the XAML stack. We do however get the event as a `WM_MOUSEWHEEL` on those devices (a message we don't get on devices with normally functioning trackpads).
This PR attempts to take that `WM_MOUSEWHEEL` and manually dispatch it to the `TermControl`, so we can at least scroll the terminal content.
Unfortunately, this solution is not very general purpose. This only works to scroll controls that manually implement our own `IMouseWheelListener` interface. As we add more controls, we'll need to continue manually implementing this interface, until the underlying XAML Islands bug is fixed. **I don't love this**. I'd rather have a better solution, but it seems that we can't synthesize a more general-purpose `PointerWheeled` event that could get routed through the XAML tree as normal.
## References
* #2606 and microsoft/microsoft-ui-xaml#2101 - these bugs are also tracking a similar "inactive windows" / "scaled mouse events" issue in XAML
## PR Checklist
* [x] Closes #979
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I've also added a `til::point` conversion _to_ `winrt::Windows::Foundation::Point`, and some scaling operators for `point`
## Validation Steps Performed
* It works on my HP Spectre 2017 with a synaptics trackpad
- I also made sure to test that `tmux` works in panes on this laptop
* It works on my slaptop, and DOESN'T follow this hack codepath on this machine.
2020-04-01 18:58:16 +02:00
|
|
|
template<typename T>
|
|
|
|
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));
|
|
|
|
|
|
|
|
ptrdiff_t y;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckMul(_y, scale).AssignIfValid(&y));
|
|
|
|
|
|
|
|
return point{ x, y };
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
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::CheckDiv(_x, scale).AssignIfValid(&x));
|
|
|
|
|
|
|
|
ptrdiff_t y;
|
|
|
|
THROW_HR_IF(E_ABORT, !base::CheckDiv(_y, scale).AssignIfValid(&y));
|
|
|
|
|
|
|
|
return point{ x, y };
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
constexpr ptrdiff_t x() const noexcept
|
|
|
|
{
|
|
|
|
return _x;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T x() 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WINCONTYPES_
|
|
|
|
operator COORD() const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WINDEF_
|
|
|
|
operator POINT() const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DCOMMON_H_INCLUDED
|
|
|
|
constexpr operator D2D1_POINT_2F() const noexcept
|
|
|
|
{
|
|
|
|
return D2D1_POINT_2F{ gsl::narrow_cast<float>(_x), gsl::narrow_cast<float>(_y) };
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Manually pass mouse wheel messages to TermControls (#5131)
## Summary of the Pull Request
As we've learned in #979, not all touchpads are created equal. Some of them have bad drivers that makes scrolling inactive windows not work. For whatever reason, these devices think the Terminal is all one giant inactive window, so we don't get the mouse wheel events through the XAML stack. We do however get the event as a `WM_MOUSEWHEEL` on those devices (a message we don't get on devices with normally functioning trackpads).
This PR attempts to take that `WM_MOUSEWHEEL` and manually dispatch it to the `TermControl`, so we can at least scroll the terminal content.
Unfortunately, this solution is not very general purpose. This only works to scroll controls that manually implement our own `IMouseWheelListener` interface. As we add more controls, we'll need to continue manually implementing this interface, until the underlying XAML Islands bug is fixed. **I don't love this**. I'd rather have a better solution, but it seems that we can't synthesize a more general-purpose `PointerWheeled` event that could get routed through the XAML tree as normal.
## References
* #2606 and microsoft/microsoft-ui-xaml#2101 - these bugs are also tracking a similar "inactive windows" / "scaled mouse events" issue in XAML
## PR Checklist
* [x] Closes #979
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I've also added a `til::point` conversion _to_ `winrt::Windows::Foundation::Point`, and some scaling operators for `point`
## Validation Steps Performed
* It works on my HP Spectre 2017 with a synaptics trackpad
- I also made sure to test that `tmux` works in panes on this laptop
* It works on my slaptop, and DOESN'T follow this hack codepath on this machine.
2020-04-01 18:58:16 +02:00
|
|
|
#ifdef WINRT_Windows_Foundation_H
|
|
|
|
operator winrt::Windows::Foundation::Point() const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Move ConPTY to use til::bitmap (#5024)
## Summary of the Pull Request
Moves the ConPTY drawing mechanism (`VtRenderer`) to use the fine-grained `til::bitmap` individual-dirty-bit tracking mechanism instead of coarse-grained rectangle unions to improve drawing performance by dramatically reducing the total area redrawn.
## PR Checklist
* [x] Part of #778 and #1064
* [x] I work here
* [x] Tests added and updated.
* [x] I'm a core contributor
## Detailed Description of the Pull Request / Additional comments
- Converted `GetDirtyArea()` interface from `IRenderEngine` to use a vector of `til::rectangle` instead of the `SMALL_RECT` to banhammer inclusive rectangles.
- `VtEngine` now holds and operates on the `til::bitmap` for invalidation regions. All invalidation operation functions that used to be embedded inside `VtEngine` are deleted in favor of using the ones in `til::bitmap`.
- Updated `VtEngine` tracing to use new `til::bitmap` on trace and the new `to_string()` methods detailed below.
- Comparison operators for `til::bitmap` and complementary tests.
- Fixed an issue where the dirty rectangle shortcut in `til::bitmap` was set to 0,0,0,0 by default which means that `|=` on it with each `set()` operation was stretching the rectangle from 0,0. Now it's a `std::optional` so it has no value after just being cleared and will build from whatever the first invalidated rectangle is. Complementary tests added.
- Optional run caching for `til::bitmap` in the `runs()` method since both VT and DX renderers will likely want to generate the set of runs at the beginning of a frame and refer to them over and over through that frame. Saves the iteration and creation and caches inside `til::bitmap` where the chance of invalidation of the underlying data is known best. It is still possible to iterate manually with `begin()` and `end()` from the outside without caching, if desired. Complementary tests added.
- WEX templates added for `til::bitmap` and used in tests.
- `translate()` method for `til::bitmap` which will slide the dirty points in the direction specified by a `til::point` and optionally back-fill the uncovered area as dirty. Complementary tests added.
- Moves all string generation for `til` types `size`, `point`, `rectangle`, and `some` into a `to_string` method on each object such that it can be used in both ETW tracing scenarios AND in the TAEF templates uniformly. Adds a similar method for `bitmap`.
- Add tagging to `_bitmap_const_iterator` such that it appears as a valid **Input Iterator** to STL collections and can be used in a `std::vector` constructor as a range. Adds and cleans up operators on this iterator to match the theoretical requirements for an **Input Iterator**. Complementary tests added.
- Add loose operators to `til` which will allow some basic math operations (+, -, *, /) between `til::size` and `til::point` and vice versa. Complementary tests added. Complementary tests added.
- Adds operators to `til::rectangle` to allow scaling with basic math operations (+, -, *) versus `til::size` and translation with basic math operations (+, -) against `til::point`. Complementary tests added.
- In-place variants of some operations added to assorted `til` objects. Complementary tests added.
- Update VT tests to compare invalidation against the new map structure instead of raw rectangles where possible.
## Validation Steps Performed
- Wrote additional til Unit Tests for all additional operators and functions added to the project to support this operation
- Updated the existing VT renderer tests
- Ran perf check
2020-03-23 16:57:54 +01:00
|
|
|
std::wstring to_string() const
|
|
|
|
{
|
|
|
|
return wil::str_printf<std::wstring>(L"(X:%td, Y:%td)", x(), y());
|
|
|
|
}
|
|
|
|
|
2020-03-13 01:04:43 +01:00
|
|
|
protected:
|
|
|
|
ptrdiff_t _x;
|
|
|
|
ptrdiff_t _y;
|
|
|
|
|
|
|
|
#ifdef UNIT_TESTING
|
|
|
|
friend class ::PointTests;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __WEX_COMMON_H__
|
|
|
|
namespace WEX::TestExecution
|
|
|
|
{
|
|
|
|
template<>
|
|
|
|
class VerifyOutputTraits<::til::point>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static WEX::Common::NoThrowString ToString(const ::til::point& point)
|
|
|
|
{
|
Move ConPTY to use til::bitmap (#5024)
## Summary of the Pull Request
Moves the ConPTY drawing mechanism (`VtRenderer`) to use the fine-grained `til::bitmap` individual-dirty-bit tracking mechanism instead of coarse-grained rectangle unions to improve drawing performance by dramatically reducing the total area redrawn.
## PR Checklist
* [x] Part of #778 and #1064
* [x] I work here
* [x] Tests added and updated.
* [x] I'm a core contributor
## Detailed Description of the Pull Request / Additional comments
- Converted `GetDirtyArea()` interface from `IRenderEngine` to use a vector of `til::rectangle` instead of the `SMALL_RECT` to banhammer inclusive rectangles.
- `VtEngine` now holds and operates on the `til::bitmap` for invalidation regions. All invalidation operation functions that used to be embedded inside `VtEngine` are deleted in favor of using the ones in `til::bitmap`.
- Updated `VtEngine` tracing to use new `til::bitmap` on trace and the new `to_string()` methods detailed below.
- Comparison operators for `til::bitmap` and complementary tests.
- Fixed an issue where the dirty rectangle shortcut in `til::bitmap` was set to 0,0,0,0 by default which means that `|=` on it with each `set()` operation was stretching the rectangle from 0,0. Now it's a `std::optional` so it has no value after just being cleared and will build from whatever the first invalidated rectangle is. Complementary tests added.
- Optional run caching for `til::bitmap` in the `runs()` method since both VT and DX renderers will likely want to generate the set of runs at the beginning of a frame and refer to them over and over through that frame. Saves the iteration and creation and caches inside `til::bitmap` where the chance of invalidation of the underlying data is known best. It is still possible to iterate manually with `begin()` and `end()` from the outside without caching, if desired. Complementary tests added.
- WEX templates added for `til::bitmap` and used in tests.
- `translate()` method for `til::bitmap` which will slide the dirty points in the direction specified by a `til::point` and optionally back-fill the uncovered area as dirty. Complementary tests added.
- Moves all string generation for `til` types `size`, `point`, `rectangle`, and `some` into a `to_string` method on each object such that it can be used in both ETW tracing scenarios AND in the TAEF templates uniformly. Adds a similar method for `bitmap`.
- Add tagging to `_bitmap_const_iterator` such that it appears as a valid **Input Iterator** to STL collections and can be used in a `std::vector` constructor as a range. Adds and cleans up operators on this iterator to match the theoretical requirements for an **Input Iterator**. Complementary tests added.
- Add loose operators to `til` which will allow some basic math operations (+, -, *, /) between `til::size` and `til::point` and vice versa. Complementary tests added. Complementary tests added.
- Adds operators to `til::rectangle` to allow scaling with basic math operations (+, -, *) versus `til::size` and translation with basic math operations (+, -) against `til::point`. Complementary tests added.
- In-place variants of some operations added to assorted `til` objects. Complementary tests added.
- Update VT tests to compare invalidation against the new map structure instead of raw rectangles where possible.
## Validation Steps Performed
- Wrote additional til Unit Tests for all additional operators and functions added to the project to support this operation
- Updated the existing VT renderer tests
- Ran perf check
2020-03-23 16:57:54 +01:00
|
|
|
return WEX::Common::NoThrowString(point.to_string().c_str());
|
2020-03-13 01:04:43 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
class VerifyCompareTraits<::til::point, ::til::point>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static 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
|
|
|
|
{
|
|
|
|
return &expected == &actual;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool IsLessThan(const ::til::point& expectedLess, const ::til::point& expectedGreater) = delete;
|
|
|
|
|
|
|
|
static bool IsGreaterThan(const ::til::point& expectedGreater, const ::til::point& expectedLess) = delete;
|
|
|
|
|
|
|
|
static bool IsNull(const ::til::point& object) noexcept
|
|
|
|
{
|
|
|
|
return object == til::point{};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
#endif
|