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