mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-17 18:01:06 +03:00
Fix cursor alignment when a scrollbar axis stops overflowing
This commit is contained in:
@@ -1220,9 +1220,10 @@ class _ImagePaintState extends State<ImagePaint> {
|
|||||||
// Layout can change scroll metrics without notification. Compare against this
|
// Layout can change scroll metrics without notification. Compare against this
|
||||||
// build's fractions: a delayed refresh may already have changed the model.
|
// build's fractions: a delayed refresh may already have changed the model.
|
||||||
void _syncScrollAfterLayout(CanvasModel canvas) {
|
void _syncScrollAfterLayout(CanvasModel canvas) {
|
||||||
// Custom scrollbars also paint from scroll fractions; preserve Original's path.
|
// Both supported scrollbar view styles also paint from scroll fractions.
|
||||||
if (canvas.scrollStyle != ScrollStyle.scrolledge &&
|
if (canvas.scrollStyle != ScrollStyle.scrolledge &&
|
||||||
canvas.viewStyle.style != kRemoteViewStyleCustom) return;
|
canvas.viewStyle.style != kRemoteViewStyleCustom &&
|
||||||
|
canvas.viewStyle.style != kRemoteViewStyleOriginal) return;
|
||||||
final renderedScroll = (canvas.scrollX, canvas.scrollY);
|
final renderedScroll = (canvas.scrollX, canvas.scrollY);
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@@ -1434,11 +1435,14 @@ class CursorPaint extends StatelessWidget {
|
|||||||
// Scrollbar and edge scrolling share a layout that ignores canvas pan offsets.
|
// Scrollbar and edge scrolling share a layout that ignores canvas pan offsets.
|
||||||
final imageWidth = rect.width * c.scale;
|
final imageWidth = rect.width * c.scale;
|
||||||
final imageHeight = rect.height * c.scale;
|
final imageHeight = rect.height * c.scale;
|
||||||
// Match the integer centering in _buildCrossScrollbarFromLayout.
|
// Match the video's integer centering on each fitting axis, even if a
|
||||||
cx = (c.size.width > imageWidth ? (c.size.width - imageWidth) ~/ 2 : 0) -
|
// detached scroll controller left a stale fraction before layout sync.
|
||||||
imageWidth * c.scrollX;
|
cx = c.size.width < imageWidth
|
||||||
cy = (c.size.height > imageHeight ? (c.size.height - imageHeight) ~/ 2 : 0) -
|
? -imageWidth * c.scrollX
|
||||||
imageHeight * c.scrollY;
|
: ((c.size.width - imageWidth) ~/ 2).toDouble();
|
||||||
|
cy = c.size.height < imageHeight
|
||||||
|
? -imageHeight * c.scrollY
|
||||||
|
: ((c.size.height - imageHeight) ~/ 2).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
final image = m.image ?? preDefaultCursor.image;
|
final image = m.image ?? preDefaultCursor.image;
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ import 'cursor_test_utils.dart';
|
|||||||
const _viewport = Size(200, 160);
|
const _viewport = Size(200, 160);
|
||||||
const _hotspot = Offset(4, 9);
|
const _hotspot = Offset(4, 9);
|
||||||
const _scrollDeltas = [80.0, -20.0, 1000.0, 1000.0, -1000.0, -1000.0, 80.0, 0.0];
|
const _scrollDeltas = [80.0, -20.0, 1000.0, 1000.0, -1000.0, -1000.0, 80.0, 0.0];
|
||||||
|
const _fittingViewports = [
|
||||||
|
Size(500, 160), // Fit horizontally while vertical scrolling remains.
|
||||||
|
Size(200, 400), // Fit vertically while horizontal scrolling remains.
|
||||||
|
Size(400, 160), // Exact fit also detaches the controller.
|
||||||
|
Size(200, 320),
|
||||||
|
];
|
||||||
|
|
||||||
class _Peer extends Fake implements FfiModel {
|
class _Peer extends Fake implements FfiModel {
|
||||||
_Peer(ui.Image frame)
|
_Peer(ui.Image frame)
|
||||||
@@ -118,6 +124,7 @@ class _FFI extends Fake implements FFI {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
for (final style in [(kRemoteViewStyleOriginal, ScrollStyle.scrolledge),
|
for (final style in [(kRemoteViewStyleOriginal, ScrollStyle.scrolledge),
|
||||||
|
(kRemoteViewStyleOriginal, ScrollStyle.scrollbar),
|
||||||
(kRemoteViewStyleCustom, ScrollStyle.scrolledge),
|
(kRemoteViewStyleCustom, ScrollStyle.scrolledge),
|
||||||
(kRemoteViewStyleCustom, ScrollStyle.scrollbar)]) {
|
(kRemoteViewStyleCustom, ScrollStyle.scrollbar)]) {
|
||||||
for (final texture in [false, true]) {
|
for (final texture in [false, true]) {
|
||||||
@@ -203,17 +210,19 @@ Future<void> _checkRelayout(
|
|||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
});
|
});
|
||||||
await _mount(tester, ffi, 1);
|
await _mount(tester, ffi, 1);
|
||||||
canvas.performEdgeScroll(Vector2(20, 20));
|
|
||||||
await tester.pump();
|
|
||||||
final videoWidget = texture ? find.byType(Texture) : _paintOf(video);
|
final videoWidget = texture ? find.byType(Texture) : _paintOf(video);
|
||||||
_expectAlignment(tester, ffi, videoWidget);
|
|
||||||
for (final (viewport, dpr) in [
|
for (final (viewport, dpr) in [
|
||||||
|
for (final viewport in _fittingViewports)
|
||||||
|
...[(viewport, 1.0), (_viewport, 1.0)],
|
||||||
(const Size(160, 120), 2.0),
|
(const Size(160, 120), 2.0),
|
||||||
(const Size(195, 155), 2.0), // Clamp both existing scroll positions.
|
(const Size(195, 155), 2.0), // Clamp both existing scroll positions.
|
||||||
(const Size(240, 155), 2.0), // Detach the horizontal scroll controller.
|
(const Size(240, 155), 2.0), // Detach the horizontal scroll controller.
|
||||||
(const Size(240, 200), 2.0), // No scrolling remains.
|
(const Size(240, 200), 2.0), // No scrolling remains.
|
||||||
(_viewport, 1.0),
|
(_viewport, 1.0),
|
||||||
]) {
|
]) {
|
||||||
|
canvas.performEdgeScroll(Vector2(20, 20));
|
||||||
|
await tester.pump();
|
||||||
|
_expectAlignment(tester, ffi, videoWidget);
|
||||||
tester.view.devicePixelRatio = dpr;
|
tester.view.devicePixelRatio = dpr;
|
||||||
tester.view.physicalSize = viewport * dpr;
|
tester.view.physicalSize = viewport * dpr;
|
||||||
canvas.relayout(viewport, dpr);
|
canvas.relayout(viewport, dpr);
|
||||||
|
|||||||
Reference in New Issue
Block a user