PageRenderTime 114ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Core/SurfaceBoxRendererList.cs

https://bitbucket.org/tuldok89/openpdn
C# | 411 lines | 327 code | 62 blank | 22 comment | 56 complexity | 95c0d4d4611d937449e7cb2d7dfb7626 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using System;
  10. using System.Drawing;
  11. using System.Linq;
  12. using System.Windows.Forms;
  13. namespace PaintDotNet
  14. {
  15. public sealed class SurfaceBoxRendererList
  16. {
  17. private SurfaceBoxRenderer[] _list;
  18. private SurfaceBoxRenderer[] _topList;
  19. private Size _sourceSize;
  20. private Size _destinationSize;
  21. private readonly object _lockObject = new object();
  22. public object SyncRoot
  23. {
  24. get
  25. {
  26. return _lockObject;
  27. }
  28. }
  29. public ScaleFactor ScaleFactor { get; private set; }
  30. public SurfaceBoxRenderer[][] Renderers
  31. {
  32. get
  33. {
  34. return new[] { _list, _topList };
  35. }
  36. }
  37. private void ComputeScaleFactor()
  38. {
  39. ScaleFactor = new ScaleFactor(DestinationSize.Width, SourceSize.Width);
  40. }
  41. public Point SourceToDestination(Point pt)
  42. {
  43. return ScaleFactor.ScalePoint(pt);
  44. }
  45. public RectangleF SourceToDestination(Rectangle rect)
  46. {
  47. return ScaleFactor.ScaleRectangle((RectangleF)rect);
  48. }
  49. public Point DestinationToSource(Point pt)
  50. {
  51. return ScaleFactor.UnscalePoint(pt);
  52. }
  53. public void Add(SurfaceBoxRenderer addMe, bool alwaysOnTop)
  54. {
  55. SurfaceBoxRenderer[] startList = alwaysOnTop ? _topList : _list;
  56. var listPlusOne = new SurfaceBoxRenderer[startList.Length + 1];
  57. for (int i = 0; i < startList.Length; ++i)
  58. {
  59. listPlusOne[i] = startList[i];
  60. }
  61. listPlusOne[listPlusOne.Length - 1] = addMe;
  62. if (alwaysOnTop)
  63. {
  64. _topList = listPlusOne;
  65. }
  66. else
  67. {
  68. _list = listPlusOne;
  69. }
  70. Invalidate();
  71. }
  72. public void Remove(SurfaceBoxRenderer removeMe)
  73. {
  74. if (_list.Length == 0 && _topList.Length == 0)
  75. {
  76. throw new InvalidOperationException("zero items left, can't remove anything");
  77. }
  78. bool found = false;
  79. if (_list.Length > 0)
  80. {
  81. var listSubOne = new SurfaceBoxRenderer[_list.Length - 1];
  82. bool foundHere = false;
  83. int dstIndex = 0;
  84. foreach (SurfaceBoxRenderer t in _list)
  85. {
  86. if (t == removeMe)
  87. {
  88. if (foundHere)
  89. {
  90. throw new ArgumentException("removeMe appeared multiple times in the list");
  91. }
  92. foundHere = true;
  93. }
  94. else
  95. {
  96. if (dstIndex == _list.Length - 1)
  97. {
  98. // was not found
  99. }
  100. else
  101. {
  102. listSubOne[dstIndex] = t;
  103. ++dstIndex;
  104. }
  105. }
  106. }
  107. if (foundHere)
  108. {
  109. _list = listSubOne;
  110. found = true;
  111. }
  112. }
  113. if (_topList.Length > 0)
  114. {
  115. var topListSubOne = new SurfaceBoxRenderer[_topList.Length - 1];
  116. int topDstIndex = 0;
  117. bool foundHere = false;
  118. foreach (SurfaceBoxRenderer t in _topList)
  119. {
  120. if (t == removeMe)
  121. {
  122. if (found || foundHere)
  123. {
  124. throw new ArgumentException("removeMe appeared multiple times in the list");
  125. }
  126. foundHere = true;
  127. }
  128. else
  129. {
  130. if (topDstIndex == _topList.Length - 1)
  131. {
  132. // was not found
  133. }
  134. else
  135. {
  136. topListSubOne[topDstIndex] = t;
  137. ++topDstIndex;
  138. }
  139. }
  140. }
  141. if (foundHere)
  142. {
  143. _topList = topListSubOne;
  144. found = true;
  145. }
  146. }
  147. if (!found)
  148. {
  149. throw new ArgumentException("removeMe was not found", "removeMe");
  150. }
  151. Invalidate();
  152. }
  153. private void OnDestinationSizeChanged()
  154. {
  155. InvalidateLookups();
  156. if (_destinationSize.Width == 0 || _sourceSize.Width == 0) return;
  157. ComputeScaleFactor();
  158. foreach (SurfaceBoxRenderer t in _list)
  159. {
  160. t.OnDestinationSizeChanged();
  161. }
  162. foreach (SurfaceBoxRenderer t in _topList)
  163. {
  164. t.OnDestinationSizeChanged();
  165. }
  166. }
  167. public Size DestinationSize
  168. {
  169. get
  170. {
  171. return _destinationSize;
  172. }
  173. set
  174. {
  175. if (_destinationSize == value) return;
  176. _destinationSize = value;
  177. OnDestinationSizeChanged();
  178. }
  179. }
  180. private void OnSourceSizeChanged()
  181. {
  182. InvalidateLookups();
  183. if (_destinationSize.Width == 0 || _sourceSize.Width == 0) return;
  184. ComputeScaleFactor();
  185. foreach (SurfaceBoxRenderer t in _list)
  186. {
  187. t.OnSourceSizeChanged();
  188. }
  189. foreach (SurfaceBoxRenderer t in _topList)
  190. {
  191. t.OnSourceSizeChanged();
  192. }
  193. }
  194. public Size SourceSize
  195. {
  196. get
  197. {
  198. return _sourceSize;
  199. }
  200. set
  201. {
  202. if (_sourceSize == value) return;
  203. _sourceSize = value;
  204. OnSourceSizeChanged();
  205. }
  206. }
  207. public int[] Dst2SrcLookupX
  208. {
  209. get
  210. {
  211. lock (SyncRoot)
  212. {
  213. CreateD2SLookupX();
  214. }
  215. return _d2SLookupX;
  216. }
  217. }
  218. private int[] _d2SLookupX; // maps from destination->source coordinates
  219. private void CreateD2SLookupX()
  220. {
  221. if (_d2SLookupX != null && _d2SLookupX.Length == DestinationSize.Width + 1) return;
  222. _d2SLookupX = new int[DestinationSize.Width + 1];
  223. for (int x = 0; x < _d2SLookupX.Length; ++x)
  224. {
  225. var pt = new Point(x, 0);
  226. Point surfacePt = DestinationToSource(pt);
  227. // Sometimes the scale factor is slightly different on one axis than
  228. // on another, simply due to accuracy. So we have to clamp this value to
  229. // be within bounds.
  230. _d2SLookupX[x] = Utility.Clamp(surfacePt.X, 0, SourceSize.Width - 1);
  231. }
  232. }
  233. public int[] Dst2SrcLookupY
  234. {
  235. get
  236. {
  237. lock (SyncRoot)
  238. {
  239. CreateD2SLookupY();
  240. }
  241. return _d2SLookupY;
  242. }
  243. }
  244. private int[] _d2SLookupY; // maps from destination->source coordinates
  245. private void CreateD2SLookupY()
  246. {
  247. if (_d2SLookupY != null && _d2SLookupY.Length == DestinationSize.Height + 1) return;
  248. _d2SLookupY = new int[DestinationSize.Height + 1];
  249. for (int y = 0; y < _d2SLookupY.Length; ++y)
  250. {
  251. var pt = new Point(0, y);
  252. Point surfacePt = DestinationToSource(pt);
  253. // Sometimes the scale factor is slightly different on one axis than
  254. // on another, simply due to accuracy. So we have to clamp this value to
  255. // be within bounds.
  256. _d2SLookupY[y] = Utility.Clamp(surfacePt.Y, 0, SourceSize.Height - 1);
  257. }
  258. }
  259. public int[] Src2DstLookupX
  260. {
  261. get
  262. {
  263. lock (SyncRoot)
  264. {
  265. CreateS2DLookupX();
  266. }
  267. return _s2DLookupX;
  268. }
  269. }
  270. private int[] _s2DLookupX; // maps from source->destination coordinates
  271. private void CreateS2DLookupX()
  272. {
  273. if (_s2DLookupX != null && _s2DLookupX.Length == SourceSize.Width + 1) return;
  274. _s2DLookupX = new int[SourceSize.Width + 1];
  275. for (int x = 0; x < _s2DLookupX.Length; ++x)
  276. {
  277. var pt = new Point(x, 0);
  278. Point clientPt = SourceToDestination(pt);
  279. // Sometimes the scale factor is slightly different on one axis than
  280. // on another, simply due to accuracy. So we have to clamp this value to
  281. // be within bounds.
  282. _s2DLookupX[x] = Utility.Clamp(clientPt.X, 0, DestinationSize.Width - 1);
  283. }
  284. }
  285. public int[] Src2DstLookupY
  286. {
  287. get
  288. {
  289. lock (SyncRoot)
  290. {
  291. CreateS2DLookupY();
  292. }
  293. return _s2DLookupY;
  294. }
  295. }
  296. private int[] _s2DLookupY; // maps from source->destination coordinates
  297. private void CreateS2DLookupY()
  298. {
  299. if (_s2DLookupY != null && _s2DLookupY.Length == SourceSize.Height + 1) return;
  300. _s2DLookupY = new int[SourceSize.Height + 1];
  301. for (int y = 0; y < _s2DLookupY.Length; ++y)
  302. {
  303. var pt = new Point(0, y);
  304. Point clientPt = SourceToDestination(pt);
  305. // Sometimes the scale factor is slightly different on one axis than
  306. // on another, simply due to accuracy. So we have to clamp this value to
  307. // be within bounds.
  308. _s2DLookupY[y] = Utility.Clamp(clientPt.Y, 0, DestinationSize.Height - 1);
  309. }
  310. }
  311. public void InvalidateLookups()
  312. {
  313. _s2DLookupX = null;
  314. _s2DLookupY = null;
  315. _d2SLookupX = null;
  316. _d2SLookupY = null;
  317. }
  318. public void Render(Surface dst, Point offset)
  319. {
  320. foreach (SurfaceBoxRenderer sbr in _list.Where(sbr => sbr.Visible))
  321. {
  322. sbr.Render(dst, offset);
  323. }
  324. foreach (SurfaceBoxRenderer sbr in _topList.Where(sbr => sbr.Visible))
  325. {
  326. sbr.Render(dst, offset);
  327. }
  328. }
  329. public event InvalidateEventHandler Invalidated;
  330. public void Invalidate(Rectangle rect)
  331. {
  332. if (Invalidated != null)
  333. {
  334. Invalidated(this, new InvalidateEventArgs(rect));
  335. }
  336. }
  337. public void Invalidate()
  338. {
  339. Invalidate(SurfaceBoxRenderer.MaxBounds);
  340. }
  341. public SurfaceBoxRendererList(Size sourceSize, Size destinationSize)
  342. {
  343. _list = new SurfaceBoxRenderer[0];
  344. _topList = new SurfaceBoxRenderer[0];
  345. _sourceSize = sourceSize;
  346. _destinationSize = destinationSize;
  347. }
  348. }
  349. }