/src/Core/SurfaceBoxRendererList.cs
C# | 411 lines | 327 code | 62 blank | 22 comment | 56 complexity | 95c0d4d4611d937449e7cb2d7dfb7626 MD5 | raw file
- /////////////////////////////////////////////////////////////////////////////////
- // Paint.NET //
- // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
- // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
- // See src/Resources/Files/License.txt for full licensing and attribution //
- // details. //
- // . //
- /////////////////////////////////////////////////////////////////////////////////
-
- using System;
- using System.Drawing;
- using System.Linq;
- using System.Windows.Forms;
-
- namespace PaintDotNet
- {
- public sealed class SurfaceBoxRendererList
- {
- private SurfaceBoxRenderer[] _list;
- private SurfaceBoxRenderer[] _topList;
- private Size _sourceSize;
- private Size _destinationSize;
- private readonly object _lockObject = new object();
-
- public object SyncRoot
- {
- get
- {
- return _lockObject;
- }
- }
-
- public ScaleFactor ScaleFactor { get; private set; }
-
- public SurfaceBoxRenderer[][] Renderers
- {
- get
- {
- return new[] { _list, _topList };
- }
- }
-
- private void ComputeScaleFactor()
- {
- ScaleFactor = new ScaleFactor(DestinationSize.Width, SourceSize.Width);
- }
-
- public Point SourceToDestination(Point pt)
- {
- return ScaleFactor.ScalePoint(pt);
- }
-
- public RectangleF SourceToDestination(Rectangle rect)
- {
- return ScaleFactor.ScaleRectangle((RectangleF)rect);
- }
-
- public Point DestinationToSource(Point pt)
- {
- return ScaleFactor.UnscalePoint(pt);
- }
-
- public void Add(SurfaceBoxRenderer addMe, bool alwaysOnTop)
- {
- SurfaceBoxRenderer[] startList = alwaysOnTop ? _topList : _list;
- var listPlusOne = new SurfaceBoxRenderer[startList.Length + 1];
-
- for (int i = 0; i < startList.Length; ++i)
- {
- listPlusOne[i] = startList[i];
- }
-
- listPlusOne[listPlusOne.Length - 1] = addMe;
-
- if (alwaysOnTop)
- {
- _topList = listPlusOne;
- }
- else
- {
- _list = listPlusOne;
- }
-
- Invalidate();
- }
-
- public void Remove(SurfaceBoxRenderer removeMe)
- {
- if (_list.Length == 0 && _topList.Length == 0)
- {
- throw new InvalidOperationException("zero items left, can't remove anything");
- }
- bool found = false;
-
- if (_list.Length > 0)
- {
- var listSubOne = new SurfaceBoxRenderer[_list.Length - 1];
- bool foundHere = false;
- int dstIndex = 0;
-
- foreach (SurfaceBoxRenderer t in _list)
- {
- if (t == removeMe)
- {
- if (foundHere)
- {
- throw new ArgumentException("removeMe appeared multiple times in the list");
- }
- foundHere = true;
- }
- else
- {
- if (dstIndex == _list.Length - 1)
- {
- // was not found
- }
- else
- {
- listSubOne[dstIndex] = t;
- ++dstIndex;
- }
- }
- }
-
- if (foundHere)
- {
- _list = listSubOne;
- found = true;
- }
- }
-
- if (_topList.Length > 0)
- {
- var topListSubOne = new SurfaceBoxRenderer[_topList.Length - 1];
- int topDstIndex = 0;
- bool foundHere = false;
-
- foreach (SurfaceBoxRenderer t in _topList)
- {
- if (t == removeMe)
- {
- if (found || foundHere)
- {
- throw new ArgumentException("removeMe appeared multiple times in the list");
- }
- foundHere = true;
- }
- else
- {
- if (topDstIndex == _topList.Length - 1)
- {
- // was not found
- }
- else
- {
- topListSubOne[topDstIndex] = t;
- ++topDstIndex;
- }
- }
- }
-
- if (foundHere)
- {
- _topList = topListSubOne;
- found = true;
- }
- }
-
- if (!found)
- {
- throw new ArgumentException("removeMe was not found", "removeMe");
- }
-
- Invalidate();
- }
-
- private void OnDestinationSizeChanged()
- {
- InvalidateLookups();
-
- if (_destinationSize.Width == 0 || _sourceSize.Width == 0) return;
- ComputeScaleFactor();
-
- foreach (SurfaceBoxRenderer t in _list)
- {
- t.OnDestinationSizeChanged();
- }
-
- foreach (SurfaceBoxRenderer t in _topList)
- {
- t.OnDestinationSizeChanged();
- }
- }
-
- public Size DestinationSize
- {
- get
- {
- return _destinationSize;
- }
-
- set
- {
- if (_destinationSize == value) return;
- _destinationSize = value;
- OnDestinationSizeChanged();
- }
- }
-
- private void OnSourceSizeChanged()
- {
- InvalidateLookups();
-
- if (_destinationSize.Width == 0 || _sourceSize.Width == 0) return;
- ComputeScaleFactor();
-
- foreach (SurfaceBoxRenderer t in _list)
- {
- t.OnSourceSizeChanged();
- }
-
- foreach (SurfaceBoxRenderer t in _topList)
- {
- t.OnSourceSizeChanged();
- }
- }
-
- public Size SourceSize
- {
- get
- {
- return _sourceSize;
- }
-
- set
- {
- if (_sourceSize == value) return;
- _sourceSize = value;
- OnSourceSizeChanged();
- }
- }
-
- public int[] Dst2SrcLookupX
- {
- get
- {
- lock (SyncRoot)
- {
- CreateD2SLookupX();
- }
-
- return _d2SLookupX;
- }
- }
-
- private int[] _d2SLookupX; // maps from destination->source coordinates
- private void CreateD2SLookupX()
- {
- if (_d2SLookupX != null && _d2SLookupX.Length == DestinationSize.Width + 1) return;
- _d2SLookupX = new int[DestinationSize.Width + 1];
-
- for (int x = 0; x < _d2SLookupX.Length; ++x)
- {
- var pt = new Point(x, 0);
- Point surfacePt = DestinationToSource(pt);
-
- // Sometimes the scale factor is slightly different on one axis than
- // on another, simply due to accuracy. So we have to clamp this value to
- // be within bounds.
- _d2SLookupX[x] = Utility.Clamp(surfacePt.X, 0, SourceSize.Width - 1);
- }
- }
-
- public int[] Dst2SrcLookupY
- {
- get
- {
- lock (SyncRoot)
- {
- CreateD2SLookupY();
- }
-
- return _d2SLookupY;
- }
- }
-
- private int[] _d2SLookupY; // maps from destination->source coordinates
- private void CreateD2SLookupY()
- {
- if (_d2SLookupY != null && _d2SLookupY.Length == DestinationSize.Height + 1) return;
- _d2SLookupY = new int[DestinationSize.Height + 1];
-
- for (int y = 0; y < _d2SLookupY.Length; ++y)
- {
- var pt = new Point(0, y);
- Point surfacePt = DestinationToSource(pt);
-
- // Sometimes the scale factor is slightly different on one axis than
- // on another, simply due to accuracy. So we have to clamp this value to
- // be within bounds.
- _d2SLookupY[y] = Utility.Clamp(surfacePt.Y, 0, SourceSize.Height - 1);
- }
- }
-
- public int[] Src2DstLookupX
- {
- get
- {
- lock (SyncRoot)
- {
- CreateS2DLookupX();
- }
-
- return _s2DLookupX;
- }
- }
-
- private int[] _s2DLookupX; // maps from source->destination coordinates
- private void CreateS2DLookupX()
- {
- if (_s2DLookupX != null && _s2DLookupX.Length == SourceSize.Width + 1) return;
- _s2DLookupX = new int[SourceSize.Width + 1];
-
- for (int x = 0; x < _s2DLookupX.Length; ++x)
- {
- var pt = new Point(x, 0);
- Point clientPt = SourceToDestination(pt);
-
- // Sometimes the scale factor is slightly different on one axis than
- // on another, simply due to accuracy. So we have to clamp this value to
- // be within bounds.
- _s2DLookupX[x] = Utility.Clamp(clientPt.X, 0, DestinationSize.Width - 1);
- }
- }
-
- public int[] Src2DstLookupY
- {
- get
- {
- lock (SyncRoot)
- {
- CreateS2DLookupY();
- }
-
- return _s2DLookupY;
- }
- }
-
- private int[] _s2DLookupY; // maps from source->destination coordinates
- private void CreateS2DLookupY()
- {
- if (_s2DLookupY != null && _s2DLookupY.Length == SourceSize.Height + 1) return;
- _s2DLookupY = new int[SourceSize.Height + 1];
-
- for (int y = 0; y < _s2DLookupY.Length; ++y)
- {
- var pt = new Point(0, y);
- Point clientPt = SourceToDestination(pt);
-
- // Sometimes the scale factor is slightly different on one axis than
- // on another, simply due to accuracy. So we have to clamp this value to
- // be within bounds.
- _s2DLookupY[y] = Utility.Clamp(clientPt.Y, 0, DestinationSize.Height - 1);
- }
- }
-
- public void InvalidateLookups()
- {
- _s2DLookupX = null;
- _s2DLookupY = null;
- _d2SLookupX = null;
- _d2SLookupY = null;
- }
-
- public void Render(Surface dst, Point offset)
- {
- foreach (SurfaceBoxRenderer sbr in _list.Where(sbr => sbr.Visible))
- {
- sbr.Render(dst, offset);
- }
-
- foreach (SurfaceBoxRenderer sbr in _topList.Where(sbr => sbr.Visible))
- {
- sbr.Render(dst, offset);
- }
- }
-
- public event InvalidateEventHandler Invalidated;
-
- public void Invalidate(Rectangle rect)
- {
- if (Invalidated != null)
- {
- Invalidated(this, new InvalidateEventArgs(rect));
- }
- }
-
- public void Invalidate()
- {
- Invalidate(SurfaceBoxRenderer.MaxBounds);
- }
-
- public SurfaceBoxRendererList(Size sourceSize, Size destinationSize)
- {
- _list = new SurfaceBoxRenderer[0];
- _topList = new SurfaceBoxRenderer[0];
- _sourceSize = sourceSize;
- _destinationSize = destinationSize;
- }
- }
- }