Add project files.
This commit is contained in:
98
Nodify/Editor/Utilities/AlignmentExtensions.cs
Normal file
98
Nodify/Editor/Utilities/AlignmentExtensions.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace Nodify
|
||||
{
|
||||
internal static class AlignmentExtensions
|
||||
{
|
||||
public static void Align(this IEnumerable<ItemContainer> values, Alignment alignment, ItemContainer? relativeTo)
|
||||
{
|
||||
var containers = values as IReadOnlyCollection<ItemContainer> ?? values.ToList();
|
||||
switch (alignment)
|
||||
{
|
||||
case Alignment.Top:
|
||||
AlignTop(containers, relativeTo);
|
||||
break;
|
||||
|
||||
case Alignment.Left:
|
||||
AlignLeft(containers, relativeTo);
|
||||
break;
|
||||
|
||||
case Alignment.Bottom:
|
||||
AlignBottom(containers, relativeTo);
|
||||
break;
|
||||
|
||||
case Alignment.Right:
|
||||
AlignRight(containers, relativeTo);
|
||||
break;
|
||||
|
||||
case Alignment.Middle:
|
||||
AlignMiddle(containers, relativeTo);
|
||||
break;
|
||||
|
||||
case Alignment.Center:
|
||||
AlignCenter(containers, relativeTo);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(alignment), alignment, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignTop(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double top = instigator?.Location.Y ?? containers.Min(x => x.Location.Y);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(c.Location.X, top);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignLeft(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double left = instigator?.Location.X ?? containers.Min(x => x.Location.X);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(left, c.Location.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignBottom(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double bottom = instigator != null ? instigator.Location.Y + instigator.ActualHeight : containers.Max(x => x.Location.Y + x.ActualHeight);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(c.Location.X, bottom - c.ActualHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignRight(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double right = instigator != null ? instigator.Location.X + instigator.ActualWidth : containers.Max(x => x.Location.X + x.ActualWidth);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(right - c.ActualWidth, c.Location.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignMiddle(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double mid = instigator != null ? instigator.Location.Y + instigator.ActualHeight / 2 : containers.Average(c => c.Location.Y + c.ActualHeight / 2);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(c.Location.X, mid - c.ActualHeight / 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AlignCenter(IReadOnlyCollection<ItemContainer> containers, ItemContainer? instigator)
|
||||
{
|
||||
double center = instigator != null ? instigator.Location.X + instigator.ActualWidth / 2 : containers.Average(c => c.Location.X + c.ActualWidth / 2);
|
||||
foreach (var c in containers)
|
||||
{
|
||||
c.Location = new Point(center - c.ActualWidth / 2, c.Location.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Nodify/Editor/Utilities/DraggingOptimized.cs
Normal file
90
Nodify/Editor/Utilities/DraggingOptimized.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Nodify
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the RenderTransform to preview the container position and commits the position changes at the end of the operation.
|
||||
/// </summary>
|
||||
internal sealed class DraggingOptimized : IDraggingStrategy
|
||||
{
|
||||
private readonly uint _gridCellSize;
|
||||
private readonly List<ItemContainer> _selectedContainers;
|
||||
private Vector _dragAccumulator = new Vector(0, 0);
|
||||
|
||||
public Vector Offset { get; private set; }
|
||||
public IReadOnlyCollection<ItemContainer> Containers => _selectedContainers;
|
||||
|
||||
public DraggingOptimized(IEnumerable<ItemContainer> containers, uint gridCellSize)
|
||||
{
|
||||
_gridCellSize = gridCellSize;
|
||||
_selectedContainers = containers.Where(c => c.IsDraggable).ToList();
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
var r = (TranslateTransform)container.RenderTransform;
|
||||
|
||||
r.X = 0;
|
||||
r.Y = 0;
|
||||
|
||||
container.OnPreviewLocationChanged(container.Location);
|
||||
}
|
||||
|
||||
_selectedContainers.Clear();
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
var r = (TranslateTransform)container.RenderTransform;
|
||||
|
||||
Point result = container.Location + new Vector(r.X, r.Y);
|
||||
|
||||
// Correct the final position
|
||||
if (NodifyEditor.EnableSnappingCorrection && (r.X != 0 || r.Y != 0))
|
||||
{
|
||||
result.X = (int)result.X / _gridCellSize * _gridCellSize;
|
||||
result.Y = (int)result.Y / _gridCellSize * _gridCellSize;
|
||||
}
|
||||
|
||||
container.Location = result;
|
||||
|
||||
r.X = 0;
|
||||
r.Y = 0;
|
||||
}
|
||||
|
||||
_selectedContainers.Clear();
|
||||
}
|
||||
|
||||
public void Update(Vector change)
|
||||
{
|
||||
_dragAccumulator += change;
|
||||
var delta = new Vector((int)_dragAccumulator.X / _gridCellSize * _gridCellSize, (int)_dragAccumulator.Y / _gridCellSize * _gridCellSize);
|
||||
_dragAccumulator -= delta;
|
||||
|
||||
if (delta.X != 0 || delta.Y != 0)
|
||||
{
|
||||
Offset += delta;
|
||||
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
var r = (TranslateTransform)container.RenderTransform;
|
||||
|
||||
r.X += delta.X; // Snapping without correction
|
||||
r.Y += delta.Y; // Snapping without correction
|
||||
|
||||
container.OnPreviewLocationChanged(container.Location + new Vector(r.X, r.Y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Nodify/Editor/Utilities/DraggingSimple.cs
Normal file
80
Nodify/Editor/Utilities/DraggingSimple.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace Nodify
|
||||
{
|
||||
internal interface IDraggingStrategy
|
||||
{
|
||||
IReadOnlyCollection<ItemContainer> Containers { get; }
|
||||
Vector Offset { get; }
|
||||
void Update(Vector change);
|
||||
void End();
|
||||
void Abort();
|
||||
}
|
||||
|
||||
internal sealed class DraggingSimple : IDraggingStrategy
|
||||
{
|
||||
private readonly uint _gridCellSize;
|
||||
private readonly List<ItemContainer> _selectedContainers;
|
||||
private Vector _dragAccumulator = new Vector(0, 0);
|
||||
|
||||
public Vector Offset { get; private set; }
|
||||
public IReadOnlyCollection<ItemContainer> Containers => _selectedContainers;
|
||||
|
||||
public DraggingSimple(IEnumerable<ItemContainer> containers, uint gridCellSize)
|
||||
{
|
||||
_gridCellSize = gridCellSize;
|
||||
_selectedContainers = containers.Where(c => c.IsDraggable).ToList();
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
container.Location -= Offset;
|
||||
}
|
||||
|
||||
_selectedContainers.Clear();
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
Point result = container.Location;
|
||||
|
||||
// Correct the final position
|
||||
if (NodifyEditor.EnableSnappingCorrection)
|
||||
{
|
||||
result.X = (int)result.X / _gridCellSize * _gridCellSize;
|
||||
result.Y = (int)result.Y / _gridCellSize * _gridCellSize;
|
||||
}
|
||||
|
||||
container.Location = result;
|
||||
}
|
||||
|
||||
_selectedContainers.Clear();
|
||||
}
|
||||
|
||||
public void Update(Vector change)
|
||||
{
|
||||
_dragAccumulator += change;
|
||||
var delta = new Vector((int)_dragAccumulator.X / _gridCellSize * _gridCellSize, (int)_dragAccumulator.Y / _gridCellSize * _gridCellSize);
|
||||
_dragAccumulator -= delta;
|
||||
|
||||
if (delta.X != 0 || delta.Y != 0)
|
||||
{
|
||||
Offset += delta;
|
||||
|
||||
for (var i = 0; i < _selectedContainers.Count; i++)
|
||||
{
|
||||
ItemContainer container = _selectedContainers[i];
|
||||
container.Location = new Point(container.Location.X + delta.X, container.Location.Y + delta.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
118
Nodify/Editor/Utilities/PushItemsStrategy.cs
Normal file
118
Nodify/Editor/Utilities/PushItemsStrategy.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace Nodify
|
||||
{
|
||||
internal interface IPushStrategy
|
||||
{
|
||||
Rect Start(Point position);
|
||||
Rect Push(Vector amount);
|
||||
Rect End();
|
||||
Rect Cancel();
|
||||
Rect GetPushedArea();
|
||||
}
|
||||
|
||||
internal abstract class BasePushStrategy : IPushStrategy
|
||||
{
|
||||
private const double _minOffset = 2;
|
||||
private double _actualOffset;
|
||||
private double _initialPosition;
|
||||
|
||||
protected readonly NodifyEditor Editor;
|
||||
protected const double OffscreenOffset = 100d;
|
||||
|
||||
public BasePushStrategy(NodifyEditor editor)
|
||||
{
|
||||
Editor = editor;
|
||||
}
|
||||
|
||||
public Rect Start(Point position)
|
||||
{
|
||||
var containers = GetFilteredContainers(position);
|
||||
Editor.BeginDragging(containers);
|
||||
|
||||
_initialPosition = GetInitialPosition(position);
|
||||
_actualOffset = 0;
|
||||
|
||||
return CalculatePushedArea(_initialPosition, _actualOffset);
|
||||
}
|
||||
|
||||
public Rect Push(Vector amount)
|
||||
{
|
||||
var offset = GetPushOffset(amount);
|
||||
Editor.UpdateDragging(offset);
|
||||
|
||||
_actualOffset += offset.X;
|
||||
_actualOffset += offset.Y;
|
||||
|
||||
double newPosition = _actualOffset >= 0 ? _initialPosition : Editor.SnapToGrid(_initialPosition + _actualOffset);
|
||||
double newOffset = Math.Max(_minOffset, Editor.SnapToGrid(_actualOffset));
|
||||
|
||||
return CalculatePushedArea(newPosition, newOffset);
|
||||
}
|
||||
|
||||
public Rect End()
|
||||
{
|
||||
Editor.EndDragging();
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
public Rect Cancel()
|
||||
{
|
||||
Editor.CancelDragging();
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<ItemContainer> GetFilteredContainers(Point position);
|
||||
protected abstract double GetInitialPosition(Point position);
|
||||
protected abstract Vector GetPushOffset(Vector offset);
|
||||
protected abstract Rect CalculatePushedArea(double position, double offset);
|
||||
public abstract Rect GetPushedArea();
|
||||
}
|
||||
|
||||
internal sealed class HorizontalPushStrategy : BasePushStrategy
|
||||
{
|
||||
public HorizontalPushStrategy(NodifyEditor editor) : base(editor)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<ItemContainer> GetFilteredContainers(Point position)
|
||||
=> Editor.ItemContainers.Where(item => item.Location.X >= position.X);
|
||||
|
||||
protected override double GetInitialPosition(Point position)
|
||||
=> position.X;
|
||||
|
||||
protected override Vector GetPushOffset(Vector offset)
|
||||
=> new Vector(offset.X, 0d);
|
||||
|
||||
protected override Rect CalculatePushedArea(double position, double offset)
|
||||
=> new Rect(position, Editor.ViewportLocation.Y - OffscreenOffset, offset, Editor.ViewportSize.Height + OffscreenOffset * 2);
|
||||
|
||||
public override Rect GetPushedArea()
|
||||
=> CalculatePushedArea(Editor.PushedArea.X, Editor.PushedArea.Width);
|
||||
}
|
||||
|
||||
internal sealed class VerticalPushStrategy : BasePushStrategy
|
||||
{
|
||||
public VerticalPushStrategy(NodifyEditor editor) : base(editor)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<ItemContainer> GetFilteredContainers(Point position)
|
||||
=> Editor.ItemContainers.Where(item => item.Location.Y >= position.Y);
|
||||
|
||||
protected override double GetInitialPosition(Point position)
|
||||
=> position.Y;
|
||||
|
||||
protected override Vector GetPushOffset(Vector offset)
|
||||
=> new Vector(0d, offset.Y);
|
||||
|
||||
protected override Rect CalculatePushedArea(double position, double offset)
|
||||
=> new Rect(Editor.ViewportLocation.X - OffscreenOffset, position, Editor.ViewportSize.Width + OffscreenOffset * 2, offset);
|
||||
|
||||
public override Rect GetPushedArea()
|
||||
=> CalculatePushedArea(Editor.PushedArea.Y, Editor.PushedArea.Height);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user