|
@@ -3,98 +3,92 @@ using PixiEditor.Models.DataHolders;
|
|
|
using PixiEditor.Models.Events;
|
|
|
using PixiEditor.Models.Layers;
|
|
|
using PixiEditor.Models.Position;
|
|
|
-using PixiEditor.Models.Tools;
|
|
|
+using PixiEditor.Models.Tools;
|
|
|
using PixiEditor.Models.Tools.Tools;
|
|
|
-using PixiEditor.Models.Tools.ToolSettings.Settings;
|
|
|
-using PixiEditor.ViewModels;
|
|
|
using PixiEditor.ViewModels.SubViewModels.Main;
|
|
|
using SkiaSharp;
|
|
|
using System;
|
|
|
-using System.Collections.Generic;
|
|
|
using System.Collections.ObjectModel;
|
|
|
using System.Diagnostics;
|
|
|
-using System.Linq;
|
|
|
using System.Windows;
|
|
|
-using System.Windows.Input;
|
|
|
-
|
|
|
+
|
|
|
namespace PixiEditor.Models.Controllers
|
|
|
{
|
|
|
[DebuggerDisplay("{Documents.Count} Document(s)")]
|
|
|
public class BitmapManager : NotifyableObject
|
|
|
{
|
|
|
- private readonly ToolsViewModel _tools;
|
|
|
-
|
|
|
- private int previewLayerSize;
|
|
|
- private Document activeDocument;
|
|
|
- private Coordinates? startPosition = null;
|
|
|
- private int halfSize;
|
|
|
- private SKColor _highlightColor;
|
|
|
- private PenTool _highlightPen;
|
|
|
- private bool hideReferenceLayer;
|
|
|
- private bool onlyReferenceLayer;
|
|
|
-
|
|
|
- public BitmapManager(ToolsViewModel tools)
|
|
|
- {
|
|
|
- _tools = tools;
|
|
|
-
|
|
|
- MouseController = new MouseMovementController();
|
|
|
- MouseController.StartedRecordingChanges += MouseController_StartedRecordingChanges;
|
|
|
- MouseController.MousePositionChanged += Controller_MousePositionChanged;
|
|
|
- MouseController.StoppedRecordingChanges += MouseController_StoppedRecordingChanges;
|
|
|
- MouseController.OnMouseDown += MouseController_OnMouseDown;
|
|
|
- MouseController.OnMouseUp += MouseController_OnMouseUp;
|
|
|
- MouseController.OnMouseDownCoordinates += MouseController_OnMouseDownCoordinates;
|
|
|
- BitmapOperations = new BitmapOperationsUtility(this, tools);
|
|
|
- ReadonlyToolUtility = new ReadonlyToolUtility();
|
|
|
- DocumentChanged += BitmapManager_DocumentChanged;
|
|
|
- _highlightPen = new PenTool(this)
|
|
|
- {
|
|
|
- AutomaticallyResizeCanvas = false
|
|
|
- };
|
|
|
- _highlightColor = new SKColor(0, 0, 0, 77);
|
|
|
- }
|
|
|
+ private ToolSessionController ToolSessionController { get; set; }
|
|
|
+ public ICanvasInputTarget InputTarget => ToolSessionController;
|
|
|
+ public BitmapOperationsUtility BitmapOperations { get; set; }
|
|
|
|
|
|
- public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
|
|
|
-
|
|
|
- public MouseMovementController MouseController { get; set; }
|
|
|
-
|
|
|
- public Layer ActiveLayer => ActiveDocument.ActiveLayer;
|
|
|
-
|
|
|
- public SKColor PrimaryColor { get; set; }
|
|
|
+ public ObservableCollection<Document> Documents { get; set; } = new ObservableCollection<Document>();
|
|
|
|
|
|
- public BitmapOperationsUtility BitmapOperations { get; set; }
|
|
|
-
|
|
|
- public ReadonlyToolUtility ReadonlyToolUtility { get; set; }
|
|
|
-
|
|
|
-#nullable enable
|
|
|
+ private Document activeDocument;
|
|
|
public Document ActiveDocument
|
|
|
{
|
|
|
get => activeDocument;
|
|
|
set
|
|
|
{
|
|
|
activeDocument?.UpdatePreviewImage();
|
|
|
- Document? oldDoc = activeDocument;
|
|
|
+ Document oldDoc = activeDocument;
|
|
|
activeDocument = value;
|
|
|
RaisePropertyChanged(nameof(ActiveDocument));
|
|
|
DocumentChanged?.Invoke(this, new DocumentChangedEventArgs(value, oldDoc));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#nullable disable
|
|
|
- public ObservableCollection<Document> Documents { get; set; } = new ObservableCollection<Document>();
|
|
|
+ public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
|
|
|
+ public event EventHandler StopUsingTool;
|
|
|
+
|
|
|
+ public Layer ActiveLayer => ActiveDocument.ActiveLayer;
|
|
|
+
|
|
|
+ public SKColor PrimaryColor { get; set; }
|
|
|
|
|
|
+ private bool hideReferenceLayer;
|
|
|
public bool HideReferenceLayer
|
|
|
{
|
|
|
get => hideReferenceLayer;
|
|
|
set => SetProperty(ref hideReferenceLayer, value);
|
|
|
}
|
|
|
|
|
|
+ private bool onlyReferenceLayer;
|
|
|
public bool OnlyReferenceLayer
|
|
|
{
|
|
|
get => onlyReferenceLayer;
|
|
|
set => SetProperty(ref onlyReferenceLayer, value);
|
|
|
}
|
|
|
|
|
|
+ private readonly ToolsViewModel _tools;
|
|
|
+
|
|
|
+ private int previewLayerSize;
|
|
|
+ private int halfSize;
|
|
|
+ private SKColor _highlightColor;
|
|
|
+ private PenTool _highlightPen;
|
|
|
+
|
|
|
+ private ToolSession activeSession = null;
|
|
|
+
|
|
|
+
|
|
|
+ public BitmapManager(ToolsViewModel tools)
|
|
|
+ {
|
|
|
+ _tools = tools;
|
|
|
+
|
|
|
+ ToolSessionController = new ToolSessionController();
|
|
|
+ ToolSessionController.SessionStarted += OnSessionStart;
|
|
|
+ ToolSessionController.SessionEnded += OnSessionEnd;
|
|
|
+ ToolSessionController.PixelMousePositionChanged += OnPixelMousePositionChange;
|
|
|
+ ToolSessionController.PreciseMousePositionChanged += OnPreciseMousePositionChange;
|
|
|
+ ToolSessionController.KeyStateChanged += (_, _) => UpdateActionDisplay();
|
|
|
+ BitmapOperations = new BitmapOperationsUtility(this, tools);
|
|
|
+
|
|
|
+ DocumentChanged += BitmapManager_DocumentChanged;
|
|
|
+
|
|
|
+ _highlightPen = new PenTool(this)
|
|
|
+ {
|
|
|
+ AutomaticallyResizeCanvas = false
|
|
|
+ };
|
|
|
+ _highlightColor = new SKColor(0, 0, 0, 77);
|
|
|
+ }
|
|
|
+
|
|
|
public void CloseDocument(Document document)
|
|
|
{
|
|
|
int nextIndex = 0;
|
|
@@ -107,41 +101,91 @@ namespace PixiEditor.Models.Controllers
|
|
|
Documents.Remove(document);
|
|
|
ActiveDocument = nextIndex >= 0 ? Documents[nextIndex] : null;
|
|
|
document.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void UpdateActionDisplay()
|
|
|
+ {
|
|
|
+ _tools.ActiveTool?.UpdateActionDisplay(ToolSessionController.IsCtrlDown, ToolSessionController.IsShiftDown, ToolSessionController.IsAltDown);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnSessionStart(object sender, ToolSession e)
|
|
|
+ {
|
|
|
+ activeSession = e;
|
|
|
+
|
|
|
+ ActiveDocument.PreviewLayer.Reset();
|
|
|
+ ExecuteTool();
|
|
|
}
|
|
|
|
|
|
- public void ExecuteTool(Coordinates newPosition, bool clickedOnCanvas)
|
|
|
- {
|
|
|
- Tool activeTool = _tools.ActiveTool;
|
|
|
-
|
|
|
- if (activeTool.CanStartOutsideCanvas && !clickedOnCanvas)
|
|
|
+ private void OnSessionEnd(object sender, ToolSession e)
|
|
|
+ {
|
|
|
+ activeSession = null;
|
|
|
+
|
|
|
+ if (e.Tool is BitmapOperationTool operationTool && operationTool.RequiresPreviewLayer)
|
|
|
{
|
|
|
- return;
|
|
|
+ BitmapOperations.ApplyPreviewLayer();
|
|
|
}
|
|
|
|
|
|
- if (startPosition == null)
|
|
|
+ ActiveDocument.PreviewLayer.Reset();
|
|
|
+ HighlightPixels(MousePositionConverter.CurrentCoordinates);
|
|
|
+ StopUsingTool?.Invoke(this, EventArgs.Empty);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnPreciseMousePositionChange(object sender, (double, double) e)
|
|
|
+ {
|
|
|
+ if (activeSession == null || !activeSession.Tool.RequiresPreciseMouseData)
|
|
|
+ return;
|
|
|
+ ExecuteTool();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnPixelMousePositionChange(object sender, MouseMovementEventArgs e)
|
|
|
+ {
|
|
|
+ if (activeSession != null)
|
|
|
{
|
|
|
- activeTool.OnStart(newPosition);
|
|
|
- startPosition = newPosition;
|
|
|
+ if (activeSession.Tool.RequiresPreciseMouseData)
|
|
|
+ return;
|
|
|
+ ExecuteTool();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ HighlightPixels(e.NewPosition);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ExecuteTool()
|
|
|
+ {
|
|
|
+ if (activeSession == null)
|
|
|
+ throw new Exception("Can't execute tool's Use outside a session");
|
|
|
|
|
|
- if (activeTool is BitmapOperationTool operationTool)
|
|
|
+ if (activeSession.Tool is BitmapOperationTool operationTool)
|
|
|
{
|
|
|
- BitmapOperations.ExecuteTool(newPosition, MouseController.LastMouseMoveCoordinates, operationTool);
|
|
|
+ BitmapOperations.UseTool(activeSession.MouseMovement, operationTool, PrimaryColor);
|
|
|
}
|
|
|
- else if (activeTool is ReadonlyTool readonlyTool)
|
|
|
+ else if (activeSession.Tool is ReadonlyTool readonlyTool)
|
|
|
{
|
|
|
- ActiveDocument.PreviewLayer.Reset();
|
|
|
- ReadonlyToolUtility.ExecuteTool(
|
|
|
- MouseController.LastMouseMoveCoordinates,
|
|
|
- readonlyTool);
|
|
|
+ readonlyTool.Use(activeSession.MouseMovement);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- throw new InvalidOperationException($"'{activeTool.GetType().Name}' is either not a Tool or can't inherit '{nameof(Tool)}' directly.\nChanges the base type to either '{nameof(BitmapOperationTool)}' or '{nameof(ReadonlyTool)}'");
|
|
|
+ throw new InvalidOperationException($"'{activeSession.Tool.GetType().Name}' is either not a Tool or can't inherit '{nameof(Tool)}' directly.\nChanges the base type to either '{nameof(BitmapOperationTool)}' or '{nameof(ReadonlyTool)}'");
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- public void HighlightPixels(Coordinates newPosition)
|
|
|
+ }
|
|
|
+
|
|
|
+ private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
|
|
|
+ {
|
|
|
+ e.NewDocument?.GeneratePreviewLayer();
|
|
|
+ if (e.OldDocument != e.NewDocument)
|
|
|
+ ToolSessionController.ForceStopActiveSessionIfAny();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void UpdateHighlightIfNecessary(bool forceHide = false)
|
|
|
+ {
|
|
|
+ if (activeSession != null)
|
|
|
+ return;
|
|
|
+ HighlightPixels(forceHide ? new(-1, -1) : ToolSessionController.LastPixelPosition);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void HighlightPixels(Coordinates newPosition)
|
|
|
{
|
|
|
if (ActiveDocument == null || ActiveDocument.Layers.Count == 0 || _tools.ActiveTool.HideHighlight)
|
|
|
{
|
|
@@ -150,6 +194,15 @@ namespace PixiEditor.Models.Controllers
|
|
|
|
|
|
var previewLayer = ActiveDocument.PreviewLayer;
|
|
|
|
|
|
+ if (newPosition.X > ActiveDocument.Width
|
|
|
+ || newPosition.Y > ActiveDocument.Height
|
|
|
+ || newPosition.X < 0 || newPosition.Y < 0)
|
|
|
+ {
|
|
|
+ previewLayer.Reset();
|
|
|
+ previewLayerSize = -1;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (_tools.ToolSize != previewLayerSize || previewLayer.IsReset)
|
|
|
{
|
|
|
previewLayerSize = _tools.ToolSize;
|
|
@@ -160,97 +213,12 @@ namespace PixiEditor.Models.Controllers
|
|
|
|
|
|
previewLayer.Offset = new Thickness(0, 0, 0, 0);
|
|
|
_highlightPen.Draw(previewLayer, cords, cords, _highlightColor, _tools.ToolSize);
|
|
|
-
|
|
|
- AdjustOffset(newPosition, previewLayer);
|
|
|
-
|
|
|
}
|
|
|
-
|
|
|
- previewLayer.InvokeLayerBitmapChange();
|
|
|
-
|
|
|
AdjustOffset(newPosition, previewLayer);
|
|
|
-
|
|
|
- if (newPosition.X > ActiveDocument.Width
|
|
|
- || newPosition.Y > ActiveDocument.Height
|
|
|
- || newPosition.X < 0 || newPosition.Y < 0)
|
|
|
- {
|
|
|
- previewLayer.Reset();
|
|
|
- previewLayerSize = -1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
|
|
|
- {
|
|
|
- e.NewDocument?.GeneratePreviewLayer();
|
|
|
- }
|
|
|
|
|
|
- private void Controller_MousePositionChanged(object sender, MouseMovementEventArgs e)
|
|
|
- {
|
|
|
- Tool activeTool = _tools.ActiveTool;
|
|
|
-
|
|
|
- if (activeTool == null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- activeTool.OnMouseMove(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
|
|
|
- if (!MaybeExecuteTool(e.NewPosition) && MouseController.LeftMouseState == MouseButtonState.Released)
|
|
|
- {
|
|
|
- HighlightPixels(e.NewPosition);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void MouseController_OnMouseDown(object sender, MouseEventArgs e)
|
|
|
- {
|
|
|
- _tools.ActiveTool.OnMouseDown(e);
|
|
|
- }
|
|
|
-
|
|
|
- private void MouseController_OnMouseUp(object sender, MouseEventArgs e)
|
|
|
- {
|
|
|
- _tools.ActiveTool.OnMouseUp(e);
|
|
|
- }
|
|
|
- private void MouseController_OnMouseDownCoordinates(object sender, MouseMovementEventArgs e)
|
|
|
- {
|
|
|
- MaybeExecuteTool(e.NewPosition);
|
|
|
- }
|
|
|
-
|
|
|
- private bool MaybeExecuteTool(Coordinates newPosition)
|
|
|
- {
|
|
|
- if (MouseController.LeftMouseState == MouseButtonState.Pressed && !IsDraggingViewport() && ActiveDocument != null)
|
|
|
- {
|
|
|
- ExecuteTool(newPosition, MouseController.ClickedOnCanvas);
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- private bool IsDraggingViewport()
|
|
|
- {
|
|
|
- return _tools.ActiveTool is MoveViewportTool;
|
|
|
- }
|
|
|
-
|
|
|
- private void MouseController_StartedRecordingChanges(object sender, EventArgs e)
|
|
|
- {
|
|
|
- _tools.ActiveTool.OnRecordingLeftMouseDown(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
|
|
|
- if (ActiveDocument != null)
|
|
|
- {
|
|
|
- ActiveDocument.PreviewLayer.Reset();
|
|
|
- }
|
|
|
+ previewLayer.InvokeLayerBitmapChange();
|
|
|
}
|
|
|
|
|
|
- private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
|
|
|
- {
|
|
|
- Tool selectedTool = _tools.ActiveTool;
|
|
|
- selectedTool.OnStoppedRecordingMouseUp(new MouseEventArgs(Mouse.PrimaryDevice, (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()));
|
|
|
- if (selectedTool is BitmapOperationTool operationTool && operationTool.RequiresPreviewLayer)
|
|
|
- {
|
|
|
- BitmapOperations.ApplyPreviewLayer();
|
|
|
- }
|
|
|
-
|
|
|
- HighlightPixels(MousePositionConverter.CurrentCoordinates);
|
|
|
-
|
|
|
- startPosition = null;
|
|
|
- }
|
|
|
-
|
|
|
private void AdjustOffset(Coordinates newPosition, Layer previewLayer)
|
|
|
{
|
|
|
Coordinates start = newPosition - halfSize;
|