1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00
Artemis/src/Artemis.UI/Screens/Shared/PanZoomViewModel.cs
2020-06-30 20:41:46 +02:00

178 lines
5.0 KiB
C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Artemis.UI.Extensions;
using RGB.NET.Core;
using Stylet;
using Point = System.Windows.Point;
namespace Artemis.UI.Screens.Shared
{
public class PanZoomViewModel : PropertyChangedBase
{
private Point? _lastPanPosition;
private double _zoom = 1;
private double _panX;
private double _panY;
private double _canvasWidth;
private double _canvasHeight;
private bool _limitToZero;
public Point? LastPanPosition
{
get => _lastPanPosition;
set => SetAndNotify(ref _lastPanPosition, value);
}
public double Zoom
{
get => _zoom;
set
{
if (!SetAndNotify(ref _zoom, value)) return;
NotifyOfPropertyChange(nameof(ZoomPercentage));
}
}
public double ZoomPercentage
{
get => Zoom * 100;
set => SetZoomFromPercentage(value);
}
public double PanX
{
get => _panX;
set
{
if (!SetAndNotify(ref _panX, value)) return;
NotifyOfPropertyChange(nameof(BackgroundViewport));
}
}
public double PanY
{
get => _panY;
set
{
if (!SetAndNotify(ref _panY, value)) return;
NotifyOfPropertyChange(nameof(BackgroundViewport));
}
}
public double CanvasWidth
{
get => _canvasWidth;
set => SetAndNotify(ref _canvasWidth, value);
}
public double CanvasHeight
{
get => _canvasHeight;
set => SetAndNotify(ref _canvasHeight, value);
}
public bool LimitToZero
{
get => _limitToZero;
set => SetAndNotify(ref _limitToZero, value);
}
public Rect BackgroundViewport => new Rect(PanX, PanY, 20, 20);
public void ProcessMouseScroll(object sender, MouseWheelEventArgs e)
{
var relative = GetRelativeMousePosition(sender, e);
var absoluteX = relative.X * Zoom + PanX;
var absoluteY = relative.Y * Zoom + PanY;
if (e.Delta > 0)
Zoom *= 1.1;
else
Zoom *= 0.9;
// Limit to a min of 0.1 and a max of 2.5 (10% - 250% in the view)
Zoom = Math.Max(0.1, Math.Min(2.5, Zoom));
// Update the PanX/Y to enable zooming relative to cursor
if (LimitToZero)
{
PanX = Math.Min(0, absoluteX - relative.X * Zoom);
PanY = Math.Min(0, absoluteY - relative.Y * Zoom);
}
else
{
PanX = absoluteX - relative.X * Zoom;
PanY = absoluteY - relative.Y * Zoom;
}
}
public void ProcessMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
{
LastPanPosition = null;
return;
}
if (LastPanPosition == null)
LastPanPosition = e.GetPosition((IInputElement) sender);
var position = e.GetPosition((IInputElement) sender);
var delta = LastPanPosition - position;
if (LimitToZero)
{
PanX = Math.Min(0, PanX - delta.Value.X);
PanY = Math.Min(0, PanY - delta.Value.Y);
}
else
{
PanX -= delta.Value.X;
PanY -= delta.Value.Y;
}
LastPanPosition = position;
}
public void Reset()
{
Zoom = 1;
PanX = 0;
PanY = 0;
}
public Rect TransformContainingRect(Rectangle rect)
{
return TransformContainingRect(rect.ToWindowsRect(1));
}
public Rect TransformContainingRect(Rect rect)
{
// Create the same transform group the view is using
var transformGroup = new TransformGroup();
transformGroup.Children.Add(new ScaleTransform(Zoom, Zoom));
transformGroup.Children.Add(new TranslateTransform(PanX, PanY));
// Apply it to the device rect
return transformGroup.TransformBounds(rect);
}
public Point GetRelativeMousePosition(object container, MouseEventArgs e)
{
// Get the mouse position relative to the panned / zoomed panel, not very MVVM but I can't find a better way
return e.GetPosition(((Panel) container).Children[0]);
}
private void SetZoomFromPercentage(double value)
{
var newZoom = value / 100;
// Focus towards the center of the zoomed area
PanX += newZoom - Zoom;
PanY += newZoom - Zoom;
Zoom = value / 100;
}
}
}