1 // 2 // CloneStampTool.cs 3 // 4 // Author: 5 // Jonathan Pobst <monkey@jpobst.com> 6 // 7 // Copyright (c) 2010 Jonathan Pobst 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 Mono.Unix; 30 using Gdk; 31 32 namespace Pinta.Tools 33 { 34 public class CloneStampTool : BaseBrushTool 35 { 36 private bool painting; 37 private Point origin = new Point (int.MinValue, int.MinValue); 38 private Point offset = new Point (int.MinValue, int.MinValue); 39 private Point last_point = new Point (int.MinValue, int.MinValue); 40 41 public override string Name { 42 get { return Catalog.GetString ("Clone Stamp"); } 43 } 44 public override string Icon { 45 get { return "Tools.CloneStamp.png"; } 46 } 47 public override string StatusBarText { get { return Catalog.GetString ("Ctrl-left click to set origin, left click to paint."); } } 48 49 public override Gdk.Cursor DefaultCursor { 50 get { 51 int iconOffsetX, iconOffsetY; 52 var icon = CreateIconWithShape ("Cursor.CloneStamp.png", 53 CursorShape.Ellipse, BrushWidth, 16, 26, 54 out iconOffsetX, out iconOffsetY); 55 return new Gdk.Cursor (Gdk.Display.Default, icon, iconOffsetX, iconOffsetY); 56 } 57 } 58 public override bool CursorChangesOnZoom { get { return true; } } 59 60 public override Gdk.Key ShortcutKey { get { return Gdk.Key.L; } } 61 public override int Priority { get { return 33; } } 62 protected override bool ShowAntialiasingButton { get { return true; } } 63 OnBuildToolBar(Gtk.Toolbar tb)64 protected override void OnBuildToolBar(Gtk.Toolbar tb) 65 { 66 base.OnBuildToolBar(tb); 67 68 // Change the cursor when the BrushWidth is changed. 69 brush_width.ComboBox.Changed += (sender, e) => SetCursor (DefaultCursor); 70 } 71 OnMouseDown(Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, Cairo.PointD point)72 protected override void OnMouseDown (Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, Cairo.PointD point) 73 { 74 Document doc = PintaCore.Workspace.ActiveDocument; 75 76 // We only do stuff with the left mouse button 77 if (args.Event.Button != 1) 78 return; 79 80 // Ctrl click is set origin, regular click is begin drawing 81 if (!args.Event.IsControlPressed ()) { 82 if (origin.IsNotSet ()) 83 return; 84 85 painting = true; 86 87 if (offset.IsNotSet ()) 88 offset = new Point ((int)point.X - origin.X, (int)point.Y - origin.Y); 89 90 doc.ToolLayer.Clear (); 91 doc.ToolLayer.Hidden = false; 92 93 surface_modified = false; 94 undo_surface = doc.CurrentUserLayer.Surface.Clone (); 95 } else { 96 origin = point.ToGdkPoint (); 97 } 98 } 99 OnMouseMove(object o, Gtk.MotionNotifyEventArgs args, Cairo.PointD point)100 protected override void OnMouseMove (object o, Gtk.MotionNotifyEventArgs args, Cairo.PointD point) 101 { 102 Document doc = PintaCore.Workspace.ActiveDocument; 103 104 if (!painting || offset.IsNotSet ()) 105 return; 106 107 int x = (int)point.X; 108 int y = (int)point.Y; 109 110 if (last_point.IsNotSet ()) { 111 last_point = new Point (x, y); 112 return; 113 } 114 115 using (var g = doc.CreateClippedToolContext ()) { 116 g.Antialias = UseAntialiasing ? Cairo.Antialias.Subpixel : Cairo.Antialias.None; 117 118 g.MoveTo (last_point.X, last_point.Y); 119 g.LineTo (x, y); 120 121 g.SetSource (doc.CurrentUserLayer.Surface, offset.X, offset.Y); 122 g.LineWidth = BrushWidth; 123 g.LineCap = Cairo.LineCap.Round; 124 125 g.Stroke (); 126 } 127 128 var dirty_rect = GetRectangleFromPoints (last_point, new Point (x, y)); 129 130 last_point = new Point (x, y); 131 surface_modified = true; 132 doc.Workspace.Invalidate (dirty_rect); 133 } 134 OnMouseUp(Gtk.DrawingArea canvas, Gtk.ButtonReleaseEventArgs args, Cairo.PointD point)135 protected override void OnMouseUp (Gtk.DrawingArea canvas, Gtk.ButtonReleaseEventArgs args, Cairo.PointD point) 136 { 137 Document doc = PintaCore.Workspace.ActiveDocument; 138 139 painting = false; 140 141 using (Cairo.Context g = new Cairo.Context (doc.CurrentUserLayer.Surface)) { 142 g.SetSource (doc.ToolLayer.Surface); 143 g.Paint (); 144 } 145 146 base.OnMouseUp (canvas, args, point); 147 148 offset = new Point (int.MinValue, int.MinValue); 149 last_point = new Point (int.MinValue, int.MinValue); 150 151 doc.ToolLayer.Clear (); 152 doc.ToolLayer.Hidden = true; 153 doc.Workspace.Invalidate (); 154 } 155 OnKeyDown(Gtk.DrawingArea canvas, Gtk.KeyPressEventArgs args)156 protected override void OnKeyDown (Gtk.DrawingArea canvas, Gtk.KeyPressEventArgs args) 157 { 158 base.OnKeyDown(canvas, args); 159 //note that this WONT work if user presses control key and THEN selects the tool! 160 if (args.Event.Key == Key.Control_L || args.Event.Key == Key.Control_R) { 161 Gdk.Pixbuf icon = PintaCore.Resources.GetIcon ("Cursor.CloneStampSetSource.png"); 162 Gdk.Cursor setSourceCursor = new Gdk.Cursor (Gdk.Display.Default, icon, 16, 26); 163 SetCursor(setSourceCursor); 164 } 165 } 166 OnKeyUp(Gtk.DrawingArea canvas, Gtk.KeyReleaseEventArgs args)167 protected override void OnKeyUp (Gtk.DrawingArea canvas, Gtk.KeyReleaseEventArgs args) 168 { 169 base.OnKeyUp(canvas, args); 170 if (args.Event.Key == Key.Control_L || args.Event.Key == Key.Control_R) 171 SetCursor(DefaultCursor); 172 } 173 OnDeactivated(BaseTool newTool)174 protected override void OnDeactivated(BaseTool newTool) 175 { 176 origin = new Point (int.MinValue, int.MinValue); 177 } 178 } 179 } 180