addf2366b9277767f2422b551c25870ed6c8360a
[mono.git] / mcs / class / System.Drawing / System.Drawing.Drawing2D / PathGradientBrush.cs
1 //
2 // System.Drawing.Drawing2D.PathGradientBrush.cs
3 //
4 // Authors:
5 //   Dennis Hayes (dennish@Raytek.com)
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //   Ravindra (rkumar@novell.com)
8 //
9 // Copyright (C) 2002/3 Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004,2006 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.ComponentModel;
33
34 namespace System.Drawing.Drawing2D {
35
36         [MonoTODO ("libgdiplus/cairo doesn't support path gradients - unless it can be mapped to a radial gradient")]
37         public sealed class PathGradientBrush : Brush {
38
39                 internal PathGradientBrush (IntPtr native)
40                 {
41                         SetNativeBrush (native);
42                 }
43
44                 public PathGradientBrush (GraphicsPath path)
45                 {
46                         if (path == null)
47                                 throw new ArgumentNullException ("path");
48
49                         IntPtr nativeObject;
50                         Status status = GDIPlus.GdipCreatePathGradientFromPath (path.nativePath, out nativeObject);
51                         GDIPlus.CheckStatus (status);
52                         SetNativeBrush (nativeObject);
53                 }
54
55                 public PathGradientBrush (Point [] points) : this (points, WrapMode.Clamp)
56                 {
57                 }
58
59                 public PathGradientBrush (PointF [] points) : this (points, WrapMode.Clamp)
60                 {
61                 }
62
63                 public PathGradientBrush (Point [] points, WrapMode wrapMode)
64                 {
65                         if (points == null)
66                                 throw new ArgumentNullException ("points");
67                         if ((wrapMode < WrapMode.Tile) || (wrapMode > WrapMode.Clamp))
68                                 throw new InvalidEnumArgumentException ("WrapMode");
69
70                         IntPtr nativeObject;
71                         Status status = GDIPlus.GdipCreatePathGradientI (points, points.Length, wrapMode, out nativeObject);
72                         GDIPlus.CheckStatus (status);
73                         SetNativeBrush (nativeObject);
74                 }
75
76                 public PathGradientBrush (PointF [] points, WrapMode wrapMode)
77                 {
78                         if (points == null)
79                                 throw new ArgumentNullException ("points");
80                         if ((wrapMode < WrapMode.Tile) || (wrapMode > WrapMode.Clamp))
81                                 throw new InvalidEnumArgumentException ("WrapMode");
82
83                         IntPtr nativeObject;
84                         Status status = GDIPlus.GdipCreatePathGradient (points, points.Length, wrapMode, out nativeObject);
85                         GDIPlus.CheckStatus (status);
86                         SetNativeBrush (nativeObject);
87                 }
88
89                 // Properties
90
91                 public Blend Blend {
92                         get {
93                                 int count;
94                                 Status status = GDIPlus.GdipGetPathGradientBlendCount (NativeBrush, out count);
95                                 GDIPlus.CheckStatus (status);
96                                 float [] factors = new float [count];
97                                 float [] positions = new float [count];
98                                 status = GDIPlus.GdipGetPathGradientBlend (NativeBrush, factors, positions, count);
99                                 GDIPlus.CheckStatus (status);
100
101                                 Blend blend = new Blend ();
102                                 blend.Factors = factors;
103                                 blend.Positions = positions;
104
105                                 return blend;
106                         }
107                         set {
108                                 // no null check, MS throws a NullReferenceException here
109                                 int count;
110                                 float [] factors = value.Factors;
111                                 float [] positions = value.Positions;
112                                 count = factors.Length;
113
114                                 if (count == 0 || positions.Length == 0)
115                                         throw new ArgumentException ("Invalid Blend object. It should have at least 2 elements in each of the factors and positions arrays.");
116
117                                 if (count != positions.Length)
118                                         throw new ArgumentException ("Invalid Blend object. It should contain the same number of factors and positions values.");
119
120                                 if (positions [0] != 0.0F)
121                                         throw new ArgumentException ("Invalid Blend object. The positions array must have 0.0 as its first element.");
122
123                                 if (positions [count - 1] != 1.0F)
124                                         throw new ArgumentException ("Invalid Blend object. The positions array must have 1.0 as its last element.");
125
126                                 Status status = GDIPlus.GdipSetPathGradientBlend (NativeBrush, factors, positions, count);
127                                 GDIPlus.CheckStatus (status);
128                         }
129                 }
130
131                 public Color CenterColor {
132                         get {
133                                 int centerColor;
134                                 Status status = GDIPlus.GdipGetPathGradientCenterColor (NativeBrush, out centerColor);
135                                 GDIPlus.CheckStatus (status);
136                                 return Color.FromArgb (centerColor);
137                         }
138                         set {
139                                 Status status = GDIPlus.GdipSetPathGradientCenterColor (NativeBrush, value.ToArgb ());
140                                 GDIPlus.CheckStatus (status);
141                         }
142                 }
143
144                 public PointF CenterPoint {
145                         get {
146                                 PointF center;
147                                 Status status = GDIPlus.GdipGetPathGradientCenterPoint (NativeBrush, out center);
148                                 GDIPlus.CheckStatus (status);
149
150                                 return center;
151                         }
152                         set {
153                                 PointF center = value;
154                                 Status status = GDIPlus.GdipSetPathGradientCenterPoint (NativeBrush, ref center);
155                                 GDIPlus.CheckStatus (status);
156                         }
157                 }
158
159                 public PointF FocusScales {
160                         get {
161                                 float xScale;
162                                 float yScale;
163                                 Status status = GDIPlus.GdipGetPathGradientFocusScales (NativeBrush, out xScale, out yScale);
164                                 GDIPlus.CheckStatus (status);
165
166                                 return new PointF (xScale, yScale);
167                         }
168                         set {
169                                 Status status = GDIPlus.GdipSetPathGradientFocusScales (NativeBrush, value.X, value.Y);
170                                 GDIPlus.CheckStatus (status);
171                         }
172                 }
173
174                 public ColorBlend InterpolationColors {
175                         get {
176                                 int count;
177                                 Status status = GDIPlus.GdipGetPathGradientPresetBlendCount (NativeBrush, out count);
178                                 GDIPlus.CheckStatus (status);
179                                 // if no failure, then the "managed" minimum is 1
180                                 if (count < 1)
181                                         count = 1;
182
183                                 int [] intcolors = new int [count];
184                                 float [] positions = new float [count];
185                                 // status would fail if we ask points or types with a < 2 count
186                                 if (count > 1) {
187                                         status = GDIPlus.GdipGetPathGradientPresetBlend (NativeBrush, intcolors, positions, count);
188                                         GDIPlus.CheckStatus (status);
189                                 }
190
191                                 ColorBlend interpolationColors = new ColorBlend ();
192                                 Color [] colors = new Color [count];
193                                 for (int i = 0; i < count; i++)
194                                         colors [i] = Color.FromArgb (intcolors [i]);
195                                 interpolationColors.Colors = colors;
196                                 interpolationColors.Positions = positions;
197
198                                 return interpolationColors;
199                         }
200                         set {
201                                 // no null check, MS throws a NullReferenceException here
202                                 int count;
203                                 Color [] colors = value.Colors;
204                                 float [] positions = value.Positions;
205                                 count = colors.Length;
206
207                                 if (count == 0 || positions.Length == 0)
208                                         throw new ArgumentException ("Invalid ColorBlend object. It should have at least 2 elements in each of the colors and positions arrays.");
209
210                                 if (count != positions.Length)
211                                         throw new ArgumentException ("Invalid ColorBlend object. It should contain the same number of positions and color values.");
212
213                                 if (positions [0] != 0.0F)
214                                         throw new ArgumentException ("Invalid ColorBlend object. The positions array must have 0.0 as its first element.");
215
216                                 if (positions [count - 1] != 1.0F)
217                                         throw new ArgumentException ("Invalid ColorBlend object. The positions array must have 1.0 as its last element.");
218
219                                 int [] blend = new int [colors.Length];
220                                 for (int i = 0; i < colors.Length; i++)
221                                         blend [i] = colors [i].ToArgb ();
222
223                                 Status status = GDIPlus.GdipSetPathGradientPresetBlend (NativeBrush, blend, positions, count);
224                                 GDIPlus.CheckStatus (status);
225                         }
226                 }
227
228                 public RectangleF Rectangle {
229                         get {
230                                 RectangleF rect;
231                                 Status status = GDIPlus.GdipGetPathGradientRect (NativeBrush, out rect);
232                                 GDIPlus.CheckStatus (status);
233
234                                 return rect;
235                         }
236                 }
237
238                 public Color [] SurroundColors {
239                         get {
240                                 int count;
241                                 Status status = GDIPlus.GdipGetPathGradientSurroundColorCount (NativeBrush, out count);
242                                 GDIPlus.CheckStatus (status);
243
244                                 int [] intcolors = new int [count];
245                                 status = GDIPlus.GdipGetPathGradientSurroundColorsWithCount (NativeBrush, intcolors, ref count);
246                                 GDIPlus.CheckStatus (status);
247
248                                 Color [] colors = new Color [count];
249                                 for (int i = 0; i < count; i++)
250                                         colors [i] = Color.FromArgb (intcolors [i]);
251
252                                 return colors;
253                         }
254                         set {
255                                 // no null check, MS throws a NullReferenceException here
256                                 int count = value.Length;
257                                 int [] colors = new int [count];
258                                 for (int i = 0; i < count; i++)
259                                         colors [i] = value [i].ToArgb ();
260
261                                 Status status = GDIPlus.GdipSetPathGradientSurroundColorsWithCount (NativeBrush, colors, ref count);
262                                 GDIPlus.CheckStatus (status);
263                         }
264                 }
265
266                 public Matrix Transform {
267                         get {
268                                 Matrix matrix = new Matrix ();
269                                 Status status = GDIPlus.GdipGetPathGradientTransform (NativeBrush, matrix.nativeMatrix);
270                                 GDIPlus.CheckStatus (status);
271
272                                 return matrix;
273                         }
274                         set {
275                                 if (value == null)
276                                         throw new ArgumentNullException ("Transform");
277
278                                 Status status = GDIPlus.GdipSetPathGradientTransform (NativeBrush, value.nativeMatrix);
279                                 GDIPlus.CheckStatus (status);
280                         }
281                 }
282
283                 public WrapMode WrapMode {
284                         get {
285                                 WrapMode wrapMode;
286                                 Status status = GDIPlus.GdipGetPathGradientWrapMode (NativeBrush, out wrapMode);
287                                 GDIPlus.CheckStatus (status);
288
289                                 return wrapMode;
290                         }
291                         set {
292                                 if ((value < WrapMode.Tile) || (value > WrapMode.Clamp))
293                                         throw new InvalidEnumArgumentException ("WrapMode");
294
295                                 Status status = GDIPlus.GdipSetPathGradientWrapMode (NativeBrush, value);
296                                 GDIPlus.CheckStatus (status);
297                         }
298                 }
299
300                 // Methods
301
302                 public void MultiplyTransform (Matrix matrix)
303                 {
304                         MultiplyTransform (matrix, MatrixOrder.Prepend);
305                 }
306
307                 public void MultiplyTransform (Matrix matrix, MatrixOrder order)
308                 {
309                         if (matrix == null)
310                                 throw new ArgumentNullException ("matrix");
311
312                         Status status = GDIPlus.GdipMultiplyPathGradientTransform (NativeBrush, matrix.nativeMatrix, order);
313                         GDIPlus.CheckStatus (status);
314                 }
315
316                 public void ResetTransform ()
317                 {
318                         Status status = GDIPlus.GdipResetPathGradientTransform (NativeBrush);
319                         GDIPlus.CheckStatus (status);
320                 }
321
322                 public void RotateTransform (float angle)
323                 {
324                         RotateTransform (angle, MatrixOrder.Prepend);
325                 }
326
327                 public void RotateTransform (float angle, MatrixOrder order)
328                 {
329                         Status status = GDIPlus.GdipRotatePathGradientTransform (NativeBrush, angle, order);
330                         GDIPlus.CheckStatus (status);
331                 }
332
333                 public void ScaleTransform (float sx, float sy)
334                 {
335                         ScaleTransform (sx, sy, MatrixOrder.Prepend);
336                 }
337
338                 public void ScaleTransform (float sx, float sy, MatrixOrder order)
339                 {
340                         Status status = GDIPlus.GdipScalePathGradientTransform (NativeBrush, sx, sy, order);
341                         GDIPlus.CheckStatus (status);
342                 }
343
344                 public void SetBlendTriangularShape (float focus)
345                 {
346                         SetBlendTriangularShape (focus, 1.0F);
347                 }
348
349                 public void SetBlendTriangularShape (float focus, float scale)
350                 {
351                         if (focus < 0 || focus > 1 || scale < 0 || scale > 1)
352                                 throw new ArgumentException ("Invalid parameter passed.");
353
354                         Status status = GDIPlus.GdipSetPathGradientLinearBlend (NativeBrush, focus, scale);
355                         GDIPlus.CheckStatus (status);
356                 }
357
358                 public void SetSigmaBellShape (float focus)
359                 {
360                         SetSigmaBellShape (focus, 1.0F);
361                 }
362
363                 public void SetSigmaBellShape (float focus, float scale)
364                 {
365                         if (focus < 0 || focus > 1 || scale < 0 || scale > 1)
366                                 throw new ArgumentException ("Invalid parameter passed.");
367
368                         Status status = GDIPlus.GdipSetPathGradientSigmaBlend (NativeBrush, focus, scale);
369                         GDIPlus.CheckStatus (status);
370                 }
371
372                 public void TranslateTransform (float dx, float dy)
373                 {
374                         TranslateTransform (dx, dy, MatrixOrder.Prepend);
375                 }
376
377                 public void TranslateTransform (float dx, float dy, MatrixOrder order)
378                 {
379                         Status status = GDIPlus.GdipTranslatePathGradientTransform (NativeBrush, dx, dy, order);
380                         GDIPlus.CheckStatus (status);
381                 }
382
383                 public override object Clone ()
384                 {
385                         IntPtr clonePtr;
386                         Status status = GDIPlus.GdipCloneBrush (NativeBrush, out clonePtr);
387                         GDIPlus.CheckStatus (status);
388
389                         PathGradientBrush clone = new PathGradientBrush (clonePtr);
390                         return clone;
391                 }
392         }
393 }