1 //
2 // BaseEffect.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 Cairo;
29 using Mono.Unix;
30 using Mono.Addins;
31 using Pinta.Core;
32 
33 [assembly: AddinRoot ("Pinta", PintaCore.ApplicationVersion)]
34 
35 namespace Pinta.Core
36 {
37 	/// <summary>
38 	/// The base class for all effects and adjustments.
39 	/// </summary>
40 	[TypeExtensionPoint]
41 	public abstract class BaseEffect
42 	{
43 		/// <summary>
44 		/// Returns the name of the effect, displayed to the user in the Adjustments/Effects menu and history pad.
45 		/// </summary>
46 		public abstract string Name { get; }
47 
48 		/// <summary>
49 		/// Returns the icon to use for the effect in the Adjustments/Effects menu and history pad.
50 		/// </summary>
51 		public virtual string Icon { get { return "Menu.Effects.Default.png"; } }
52 
53 		/// <summary>
54 		/// Returns whether this effect can display a configuration dialog to the user. (Implemented by LaunchConfiguration ().)
55 		/// </summary>
56 		public virtual bool IsConfigurable { get { return false; } }
57 
58 		/// <summary>
59 		/// Returns the keyboard shortcut for this adjustment. Only affects adjustments, not effects. Default is no shortcut.
60 		/// </summary>
61 		public virtual Gdk.Key AdjustmentMenuKey { get { return (Gdk.Key)0; } }
62 
63 		/// <summary>
64 		/// Returns the modifier(s) to the keyboard shortcut. Only affects adjustments, not effects. Default is Ctrl+Shift.
65 		/// </summary>
66 		public virtual Gdk.ModifierType AdjustmentMenuKeyModifiers { get { return Gdk.ModifierType.ControlMask | Gdk.ModifierType.ShiftMask; } }
67 
68 		/// <summary>
69 		/// Returns the menu category for an effect. Only affects effects, not adjustments. Default is "General".
70 		/// </summary>
71 		public virtual string EffectMenuCategory { get { return "General"; } }
72 
73 		/// <summary>
74 		/// The user configurable data this effect uses.
75 		/// </summary>
76 		public EffectData EffectData { get; protected set; }
77 
78 		/// <summary>
79 		/// Launches the configuration dialog for this effect/adjustment.
80 		/// </summary>
81 		/// <returns>Whether the user accepted or cancelled the configuration dialog. (true: accept, false: cancel)</returns>
LaunchConfiguration()82 		public virtual bool LaunchConfiguration ()
83 		{
84 			if (IsConfigurable)
85 				throw new NotImplementedException (string.Format ("{0} is marked as configurable, but has not implemented LaunchConfiguration", this.GetType ()));
86 
87 			return false;
88 		}
89 
90 		#region Overrideable Render Methods
91 		/// <summary>
92 		/// Performs the actual work of rendering an effect. Do not call base.Render ().
93 		/// </summary>
94 		/// <param name="src">The source surface. DO NOT MODIFY.</param>
95 		/// <param name="dst">The destination surface.</param>
96 		/// <param name="rois">An array of rectangles of interest (roi) specifying the area(s) to modify. Only these areas should be modified.</param>
Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)97 		public virtual void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)
98 		{
99 			foreach (var rect in rois)
100 				Render (src, dst, rect);
101 		}
102 
103 		/// <summary>
104 		/// Performs the actual work of rendering an effect. Do not call base.Render ().
105 		/// </summary>
106 		/// <param name="src">The source surface. DO NOT MODIFY.</param>
107 		/// <param name="dst">The destination surface.</param>
108 		/// <param name="roi">A rectangle of interest (roi) specifying the area to modify. Only these areas should be modified</param>
Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle roi)109 		protected unsafe virtual void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle roi)
110 		{
111 			ColorBgra* src_data_ptr = (ColorBgra*)src.DataPtr;
112 			int src_width = src.Width;
113 			ColorBgra* dst_data_ptr = (ColorBgra*)dst.DataPtr;
114 			int dst_width = dst.Width;
115 
116 			for (int y = roi.Y; y <= roi.GetBottom (); ++y) {
117 				ColorBgra* srcPtr = src.GetPointAddressUnchecked (src_data_ptr, src_width, roi.X, y);
118 				ColorBgra* dstPtr = dst.GetPointAddressUnchecked (dst_data_ptr, dst_width, roi.X, y);
119 				Render (srcPtr, dstPtr, roi.Width);
120 			}
121 		}
122 
123 		/// <summary>
124 		/// Performs the actual work of rendering an effect. This overload represent a single line of the image. Do not call base.Render ().
125 		/// </summary>
126 		/// <param name="src">The source surface. DO NOT MODIFY.</param>
127 		/// <param name="dst">The destination surface.</param>
128 		/// <param name="length">The number of pixels to render.</param>
Render(ColorBgra* src, ColorBgra* dst, int length)129 		protected unsafe virtual void Render (ColorBgra* src, ColorBgra* dst, int length)
130 		{
131 			while (length > 0) {
132 				*dst = Render (*src);
133 				++dst;
134 				++src;
135 				--length;
136 			}
137 		}
138 
139 		/// <summary>
140 		/// Performs the actual work of rendering an effect. This overload represent a single pixel of the image.
141 		/// </summary>
142 		/// <param name="color">The color of the source surface pixel.</param>
143 		/// <returns>The color to be used for the destination pixel.</returns>
Render(ColorBgra color)144 		protected virtual ColorBgra Render (ColorBgra color)
145 		{
146 			return color;
147 		}
148 		#endregion
149 
150 		// Effects that have any configuration state which is changed
151 		// during live preview, and this this state is stored in
152 		// non-value-type fields should override this method.
153 		// Generally this state should be stored in the effect data
154 		// class, not in the effect.
155 		/// <summary>
156 		/// Clones this effect so the live preview system has a copy that won't change while it is working.  Only override this when a MemberwiseClone is not enough.
157 		/// </summary>
158 		/// <returns>An identical copy of this effect.</returns>
Clone()159 		public virtual BaseEffect Clone ()
160 		{
161 			var effect = (BaseEffect) this.MemberwiseClone ();
162 
163 			if (effect.EffectData != null)
164 				effect.EffectData = EffectData.Clone ();
165 
166 			return effect;
167 		}
168 	}
169 
170 	/// <summary>
171 	/// Holds the user configurable data used by this effect.
172 	/// </summary>
173 	public abstract class EffectData : ObservableObject
174 	{
175 		// EffectData classes that have any state stored in non-value-type
176 		// fields must override this method, and clone those members.
177 		/// <summary>
178 		/// Clones this EffectData so the live preview system has a copy that won't change while it is working.  Only override this when a MemberwiseClone is not enough.
179 		/// </summary>
180 		/// <returns>An identical copy of this EffectData.</returns>
Clone()181 		public virtual EffectData Clone ()
182 		{
183 			return (EffectData) this.MemberwiseClone ();
184 		}
185 
186 		/// <summary>
187 		/// Fires the PropertyChanged event for this ObservableObject.
188 		/// </summary>
189 		/// <param name="propertyName">The name of the property that changed.</param>
FirePropertyChanged(string propertyName)190 		public new void FirePropertyChanged (string propertyName)
191 		{
192 			base.FirePropertyChanged (propertyName);
193 		}
194 
195 		/// <summary>
196 		/// Returns true if the current values of this EffectData do not modify the image. Returns false if current values modify the image.
197 		/// </summary>
198 		public virtual bool IsDefault { get { return false; } }
199 	}
200 }
201