1 //
2 // ShapesHistoryItem.cs
3 //
4 // Author:
5 //       Andrew Davis <andrew.3.1415@gmail.com>
6 //
7 // Copyright (c) 2013 Andrew Davis, GSoC 2013 & 2014
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 
27 using System;
28 using Pinta.Core;
29 using Cairo;
30 
31 namespace Pinta.Tools
32 {
33 	public class ShapesHistoryItem : BaseHistoryItem
34 	{
35         private BaseEditEngine ee;
36 
37 		private UserLayer userLayer;
38 
39 		private SurfaceDiff userSurfaceDiff;
40 		private ImageSurface userSurface;
41 
42 		private ShapeEngineCollection sEngines;
43 
44 		private int selectedPointIndex, selectedShapeIndex;
45 
46 		private bool redrawEverything;
47 
48 		/// <summary>
49 		/// A history item for when shapes are finalized.
50 		/// </summary>
51         /// <param name="passedEE">The EditEngine being used.</param>
52 		/// <param name="icon">The history item's icon.</param>
53 		/// <param name="text">The history item's title.</param>
54 		/// <param name="passedUserSurface">The stored UserLayer surface.</param>
55 		/// <param name="passedUserLayer">The UserLayer being modified.</param>
56 		/// <param name="passedSelectedPointIndex">The selected point's index.</param>
57 		/// <param name="passedSelectedShapeIndex">The selected point's shape index.</param>
58 		/// <param name="passedRedrawEverything">Whether every shape should be redrawn when undoing (e.g. finalization).</param>
ShapesHistoryItem(BaseEditEngine passedEE, string icon, string text, ImageSurface passedUserSurface, UserLayer passedUserLayer, int passedSelectedPointIndex, int passedSelectedShapeIndex, bool passedRedrawEverything)59         public ShapesHistoryItem(BaseEditEngine passedEE, string icon, string text, ImageSurface passedUserSurface, UserLayer passedUserLayer,
60 			int passedSelectedPointIndex, int passedSelectedShapeIndex, bool passedRedrawEverything) : base(icon, text)
61 		{
62             ee = passedEE;
63 
64 			userLayer = passedUserLayer;
65 
66 
67 			userSurfaceDiff = SurfaceDiff.Create(passedUserSurface, userLayer.Surface, true);
68 
69 			if (userSurfaceDiff == null)
70 			{
71 				userSurface = passedUserSurface;
72 			}
73 			else
74 			{
75 				(passedUserSurface as IDisposable).Dispose();
76 			}
77 
78 
79 			sEngines = BaseEditEngine.SEngines.PartialClone();
80 			selectedPointIndex = passedSelectedPointIndex;
81 			selectedShapeIndex = passedSelectedShapeIndex;
82 
83 			redrawEverything = passedRedrawEverything;
84 		}
85 
Undo()86 		public override void Undo()
87 		{
88 			Swap(redrawEverything);
89 		}
90 
Redo()91 		public override void Redo()
92 		{
93 			Swap(false);
94 		}
95 
Swap(bool redraw)96 		private void Swap(bool redraw)
97 		{
98 			// Grab the original surface
99 			ImageSurface surf = userLayer.Surface;
100 
101 			if (userSurfaceDiff != null)
102 			{
103 				userSurfaceDiff.ApplyAndSwap(surf);
104 
105 				PintaCore.Workspace.Invalidate(userSurfaceDiff.GetBounds());
106 			}
107 			else
108 			{
109 				// Undo to the "old" surface
110 				userLayer.Surface = userSurface;
111 
112 				// Store the original surface for Redo
113 				userSurface = surf;
114 
115 				//Redraw everything since surfaces were swapped.
116 				PintaCore.Workspace.Invalidate();
117 			}
118 
119             Swap (ref sEngines, ref BaseEditEngine.SEngines);
120 
121 			//Ensure that all of the shapes that should no longer be drawn have their ReEditableLayer removed from the drawing loop.
122 			foreach (ShapeEngine se in sEngines)
123 			{
124 				//Determine if it is currently in the drawing loop and should no longer be. Note: a DrawingLayer could be both removed and then
125 				//later added in the same swap operation, but this is faster than looping through each ShapeEngine in BaseEditEngine.SEngines.
126 				if (se.DrawingLayer.InTheLoop && !BaseEditEngine.SEngines.Contains(se))
127 				{
128 					se.DrawingLayer.TryRemoveLayer();
129 				}
130 			}
131 
132 			//Ensure that all of the shapes that should now be drawn have their ReEditableLayer in the drawing loop.
133 			foreach (ShapeEngine se in BaseEditEngine.SEngines)
134 			{
135 				//Determine if it is currently out of the drawing loop; if not, it should be.
136 				if (!se.DrawingLayer.InTheLoop)
137 				{
138 					se.DrawingLayer.TryAddLayer();
139 				}
140 			}
141 
142             Swap (ref selectedPointIndex, ref ee.SelectedPointIndex);
143             Swap (ref selectedShapeIndex, ref ee.SelectedShapeIndex);
144 
145 			//Determine if the currently active tool matches the shape's corresponding tool, and if not, switch to it.
146 			if (BaseEditEngine.ActivateCorrespondingTool(ee.SelectedShapeIndex, true) != null)
147 			{
148 				//The currently active tool now matches the shape's corresponding tool.
149 
150 				if (redraw)
151 				{
152 					((ShapeTool)PintaCore.Tools.CurrentTool).EditEngine.DrawAllShapes();
153 				}
154 			}
155 		}
156 
Dispose()157 		public override void Dispose()
158 		{
159 			// Free up native surface
160 			if (userSurface != null)
161 				(userSurface as IDisposable).Dispose();
162 		}
163 	}
164 }
165