From c7a798457d88d0511588b4669d4b30d2a562e3e9 Mon Sep 17 00:00:00 2001 From: Alek-ban Date: Wed, 13 May 2026 12:18:05 +0300 Subject: [PATCH] feat: ZoomPanImage make zoom and pans public --- GSS2.UI.Core/ZoomPanImage.cs | 95 +++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/GSS2.UI.Core/ZoomPanImage.cs b/GSS2.UI.Core/ZoomPanImage.cs index 081b863..1c17558 100644 --- a/GSS2.UI.Core/ZoomPanImage.cs +++ b/GSS2.UI.Core/ZoomPanImage.cs @@ -11,9 +11,6 @@ public class ZoomPanImage : Control { private Point? _lastMousePosition = null; private Dictionary? _lastTouchPositions = null; - private float _zoom = 1; - private float _panX = 0; - private float _panY = 0; public static readonly StyledProperty BackgroundProperty = AvaloniaProperty.Register(nameof(Background), defaultValue: Colors.Transparent); public Color Background @@ -39,15 +36,33 @@ public class ZoomPanImage : Control get => GetValue(ImageSourceProperty); set => SetValue(ImageSourceProperty, value); } + public static readonly StyledProperty ZoomProperty = AvaloniaProperty.Register(nameof(Zoom), defaultValue: 1); + public float Zoom + { + get => GetValue(ZoomProperty); + set => SetValue(ZoomProperty, value); + } + public static readonly StyledProperty PanXProperty = AvaloniaProperty.Register(nameof(PanX), defaultValue: 0); + public float PanX + { + get => GetValue(PanXProperty); + set => SetValue(PanXProperty, value); + } + public static readonly StyledProperty PanYProperty = AvaloniaProperty.Register(nameof(PanY), defaultValue: 0); + public float PanY + { + get => GetValue(PanYProperty); + set => SetValue(PanYProperty, value); + } public ZoomPanImage() : base() { DoubleTapped += (_, _) => { - _zoom = 1f; - _panX = 0f; - _panY = 0f; + Zoom = 1f; + PanX = 0f; + PanY = 0f; }; } @@ -65,26 +80,26 @@ public class ZoomPanImage : Control var position = ea.GetPosition(this); // Рассчитываем позицию в координатах изображения (до масштабирования) - var imageX = (position.X - Bounds.Width / 2 - _panX) / _zoom; - var imageY = (position.Y - Bounds.Height / 2 - _panY) / _zoom; + var imageX = (position.X - Bounds.Width / 2 - PanX) / Zoom; + var imageY = (position.Y - Bounds.Height / 2 - PanY) / Zoom; // Применяем масштаб float zoomFactor = ea.Delta.Y > 0 ? 1.1f : 1 / 1.1f; - _zoom *= zoomFactor; - _zoom = Math.Clamp(_zoom, 1f, 10f); - _zoom = (float)Math.Round(_zoom, 2); + Zoom *= zoomFactor; + Zoom = Math.Clamp(Zoom, 1f, 10f); + Zoom = (float)Math.Round(Zoom, 2); - if (_zoom != 1f) + if (Zoom != 1f) { // Пересчитываем смещение так, чтобы указатель остался на месте - _panX = (float)(position.X - Bounds.Width / 2 - imageX * _zoom); - _panY = (float)(position.Y - Bounds.Height / 2 - imageY * _zoom); + PanX = (float)(position.X - Bounds.Width / 2 - imageX * Zoom); + PanY = (float)(position.Y - Bounds.Height / 2 - imageY * Zoom); } else { // Если зум == 1, то возвращаем изображение к исходному смещению - _panX = 0f; - _panY = 0f; + PanX = 0f; + PanY = 0f; } } base.OnPointerWheelChanged(ea); @@ -98,9 +113,9 @@ public class ZoomPanImage : Control { if (ea.ClickCount == 2) // По двойному клику возвращаем изображение к смещение и зум к стандартным значениям { - _zoom = 1f; - _panX = 0f; - _panY = 0f; + Zoom = 1f; + PanX = 0f; + PanY = 0f; } else _lastMousePosition = ea.GetPosition(this); @@ -138,14 +153,14 @@ public class ZoomPanImage : Control { if (ea.Pointer.Type == PointerType.Mouse) { - if (_lastMousePosition is null || _zoom == 1) // Если кнопка не нажата или зум == 1, то ничего не делаем + if (_lastMousePosition is null || Zoom == 1) // Если кнопка не нажата или зум == 1, то ничего не делаем { base.OnPointerMoved(ea); return; } var position = ea.GetPosition(this); - _panX -= (float)(_lastMousePosition.Value.X - position.X); - _panY -= (float)(_lastMousePosition.Value.Y - position.Y); + PanX -= (float)(_lastMousePosition.Value.X - position.X); + PanY -= (float)(_lastMousePosition.Value.Y - position.Y); _lastMousePosition = position; } else if (ea.Pointer.Type == PointerType.Touch) @@ -163,11 +178,11 @@ public class ZoomPanImage : Control return; } - if (_lastTouchPositions.Count() == 1 && _zoom != 1) // Если есть только одно прикосновение и зум != 1, то только перемещение + if (_lastTouchPositions.Count() == 1 && Zoom != 1) // Если есть только одно прикосновение и зум != 1, то только перемещение { var position = ea.GetPosition(this); - _panX -= (float)(_lastTouchPositions[ea.Pointer.Id].X - position.X); - _panY -= (float)(_lastTouchPositions[ea.Pointer.Id].Y - position.Y); // Ось Y инвертирована + PanX -= (float)(_lastTouchPositions[ea.Pointer.Id].X - position.X); + PanY -= (float)(_lastTouchPositions[ea.Pointer.Id].Y - position.Y); // Ось Y инвертирована _lastTouchPositions[ea.Pointer.Id] = position; } else if (_lastTouchPositions.Count() == 2) // Если два прикосновения, то перемещение с приближением @@ -185,24 +200,24 @@ public class ZoomPanImage : Control var newCenter = PointHelper.Center(newPosition1, newPosition2); var zoomFactor = newDistance / lastDistance; - var newZoom = (float)(_zoom * zoomFactor); + var newZoom = (float)(Zoom * zoomFactor); newZoom = (float)Math.Clamp(newZoom, 1f, 10f); - var imageX = (newCenter.X - Bounds.Width / 2 - _panX) / _zoom; - var imageY = (newCenter.Y - Bounds.Height / 2 - _panY) / _zoom; + var imageX = (newCenter.X - Bounds.Width / 2 - PanX) / Zoom; + var imageY = (newCenter.Y - Bounds.Height / 2 - PanY) / Zoom; - _zoom = newZoom; + Zoom = newZoom; - if (_zoom > 1f) + if (Zoom > 1f) { - _panX = (float)(newCenter.X - Bounds.Width / 2 - imageX * _zoom); - _panY = (float)(newCenter.Y - Bounds.Height / 2 - imageY * _zoom); + PanX = (float)(newCenter.X - Bounds.Width / 2 - imageX * Zoom); + PanY = (float)(newCenter.Y - Bounds.Height / 2 - imageY * Zoom); } else { - _zoom = 1f; - _panX = 0f; - _panY = 0f; + Zoom = 1f; + PanX = 0f; + PanY = 0f; } } } @@ -222,14 +237,14 @@ public class ZoomPanImage : Control } var (sx, sy) = ComputeStretchScale(StretchMode, ImageSource.Size.Width, ImageSource.Size.Height); - sx *= _zoom; - sy *= _zoom; + sx *= Zoom; + sy *= Zoom; var drawWidth = ImageSource.Size.Width * sx; var drawHeight = ImageSource.Size.Height * sy; var destRect = new Rect( - (Bounds.Width - drawWidth) / 2 + _panX, - (Bounds.Height - drawHeight) / 2 + _panY, + (Bounds.Width - drawWidth) / 2 + PanX, + (Bounds.Height - drawHeight) / 2 + PanY, drawWidth, drawHeight ); @@ -299,4 +314,4 @@ public class ZoomPanImage : Control return new Rect(0, 0, imageWidth, imageHeight); } } -} \ No newline at end of file +}