AdvancedStroke implementation
[mono.git] / mcs / class / System.Drawing / System.Drawing / Pen.jvm.cs
1 //
2 // System.Drawing.Pen.cs
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Alexandre Pigolkine (pigolkine@gmx.de)
7 //   Duncan Mak (duncan@ximian.com)
8 //   Ravindra (rkumar@novell.com)
9 //
10 // (C) Ximian, Inc.  http://www.ximian.com
11 // (C) Novell, Inc.  http://www.novell.com
12 //
13
14 using System;
15 using System.Drawing.Drawing2D;
16 using System.Runtime.InteropServices;
17
18 using awt = java.awt;
19
20 namespace System.Drawing \r
21 {
22
23         public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable, awt.Stroke\r
24         {
25                 #region Member Vars
26
27                 static readonly float [] DASH_ARRAY = {4.0f,1.0f};
28                 static readonly float [] DASHDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f};
29                 static readonly float [] DASHDOTDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
30                 static readonly float [] DOT_ARRAY = {1.0f,1.0f};
31
32                 internal bool isModifiable = true;
33
34                 Brush _brush;
35                 DashStyle _dashStyle;
36                 DashCap _dashCap;
37                 LineCap _startCap;
38                 LineCap _endCap;
39
40                 LineJoin _lineJoin;
41
42                 PenAlignment _alignment;
43                 Matrix _transform;
44                 float _width;
45                 float _dashOffset;
46                 float[] _dashPattern;
47                 //float[] _compoundArray;
48
49                 float _miterLimit;
50
51                 #endregion
52
53                 #region Ctors. and Dtor
54
55                 public Pen (Brush brush) : this (brush, 1.0F)
56                 {}
57
58                 public Pen (Color color) : this (color, 1.0F)
59                 {}
60
61                 public Pen (Color color, float width) : this(new SolidBrush(color), width)
62                 {}
63
64                 public Pen (Brush brush, float width)
65                 {
66                         _brush = (Brush)brush.Clone();;
67                         _width = width;
68                         _dashStyle = DashStyle.Solid;
69                         _startCap = LineCap.Flat;
70                         _dashCap = DashCap.Flat;
71                         _endCap = LineCap.Flat;
72                         _alignment = PenAlignment.Center;
73                         _lineJoin = LineJoin.Miter;
74                         _miterLimit = 10f;
75                 }
76                 #endregion
77                 //
78                 // Properties
79                 //
80                 #region Alignment [TODO]
81                 public PenAlignment Alignment \r
82                 {
83                         get \r
84                         {
85                                 return _alignment;
86                         }
87
88                         set \r
89                         {
90                                 EnsureModifiable();
91                                 _alignment = value;
92                         }
93                 }
94                 #endregion
95
96                 #region Brush
97                 public Brush Brush \r
98                 {
99                         get \r
100                         {
101                                 return _brush;
102                         }
103
104                         set \r
105                         {
106                                 EnsureModifiable();
107                                 if (value == null)
108                                         throw new ArgumentNullException("brush");
109                                 _brush = value;
110                         }
111                 }
112                 #endregion
113
114                 #region Color
115                 public Color Color \r
116                 {
117                         get \r
118                         {
119                                 if(Brush is SolidBrush)
120                                         return ((SolidBrush)Brush).Color;
121                                 else if(Brush is HatchBrush)
122                                         return ((HatchBrush)Brush).ForegroundColor;
123                                 else
124                                         return Color.Empty;
125                         }
126
127                         set \r
128                         {
129                                 EnsureModifiable();
130                                 _brush = new SolidBrush (value);
131                         }
132                 }
133                 #endregion 
134
135                 #region CompoundArray [TODO]
136                 public float[] CompoundArray {
137                         get {
138                                 throw new NotImplementedException ();
139                         }
140                         set {
141                                 throw new NotImplementedException ();
142                         }
143                 }
144                 #endregion
145             
146                 #region CustomEndCap [TODO]
147                 public CustomLineCap CustomEndCap \r
148                 {
149                         get \r
150                         {
151                                 throw new NotImplementedException ();
152                         }
153                         // do a check for isModifiable when implementing this property
154                         set \r
155                         {
156                                 throw new NotImplementedException ();                                
157                         }
158                 }
159                 #endregion 
160
161                 #region CustomStartCap [TODO]
162                 public CustomLineCap CustomStartCap \r
163                 {
164
165                         get \r
166                         {
167                                 throw new NotImplementedException ();                                
168                         }
169
170                         // do a check for isModifiable when implementing this property
171                         set \r
172                         {
173                                 throw new NotImplementedException ();                                
174                         }
175                 }
176                 #endregion
177
178                 #region DashCap
179                 public DashCap DashCap {
180                         get {
181                                 return _dashCap;
182                         }
183
184                         set {
185                                 EnsureModifiable();
186                                 _dashCap = value;
187                         }
188                 }
189                 #endregion
190
191                 #region DashOffset
192                 public float DashOffset \r
193                 {
194
195                         get \r
196                         {
197                                 return _dashOffset;
198                         }
199
200                         set \r
201                         {
202                                 EnsureModifiable();
203                                 _dashOffset = value;
204                         }
205                 }
206                 #endregion
207
208                 #region DashPattern
209
210                 public float [] DashPattern \r
211                 {
212                         get \r
213                         {
214                                 return _dashPattern;
215                         }
216
217                         set \r
218                         {
219                                 EnsureModifiable();
220
221                                 _dashPattern = value;
222                                 DashStyle = (_dashPattern == null) ? DashStyle.Solid : DashStyle.Custom;
223                         }
224                 }
225                 #endregion
226
227                 #region DashStyle
228                 public DashStyle DashStyle \r
229                 {
230                         get \r
231                         {
232                                 return _dashStyle;
233                         }
234
235                         set \r
236                         {
237                                 EnsureModifiable();
238                                 _dashStyle = value;
239                         }
240                 }
241                 #endregion 
242
243                 #region StartCap [TODO - now allways endcap]
244
245                 public LineCap StartCap {
246                         get { 
247                                 return _startCap;
248                         }
249
250                         set {
251                                 EnsureModifiable();
252                                 _startCap = value;
253                         }
254                 }
255                 #endregion
256
257                 #region EndCap 
258                 public LineCap EndCap \r
259                 {
260                         get \r
261                         {
262                                 return _endCap;
263                         }
264
265                         set \r
266                         {
267                                 EnsureModifiable();
268
269                                 _endCap = value;
270                         }
271                 }
272                 #endregion
273  
274                 #region LineJoin [partial TODO - missed styles]
275                 public LineJoin LineJoin {
276                         get {
277                                 return _lineJoin;
278                         }
279
280                         set {
281                                 EnsureModifiable();
282                                 _lineJoin = value;
283                         }
284                 }
285
286                 #endregion
287
288                 #region MiterLimit 
289                 public float MiterLimit \r
290                 {
291
292                         get \r
293                         {
294                                 return _miterLimit;
295                         }
296
297                         set \r
298                         {
299                                 EnsureModifiable();
300
301                                 _miterLimit = value;                    
302                         }
303                             
304                 }
305                 #endregion
306
307                 #region PenType
308                 public PenType PenType \r
309                 {
310                         get \r
311                         {
312                                 if (Brush is TextureBrush)
313                                         return PenType.TextureFill;
314                                 else if (Brush is HatchBrush)
315                                         return PenType.HatchFill;
316                                 else if (Brush is LinearGradientBrush)
317                                         return PenType.LinearGradient;
318                                 else if (Brush is PathGradientBrush)
319                                         return PenType.PathGradient;
320                                 else
321                                         return PenType.SolidColor;
322                         }
323                 }
324                 #endregion
325
326                 #region Transform
327                 public Matrix Transform \r
328                 {
329                         get \r
330                         {
331                                 if (_transform == null)
332                                         _transform = new Matrix ();
333                                 return _transform;
334                         }
335                                         
336                         set \r
337                         {
338                                 EnsureModifiable();
339
340                                 _transform = value;
341                         }
342                 }
343                 #endregion
344
345                 #region Width
346                 public float Width \r
347                 {
348                         get \r
349                         {
350                                 return _width;
351                         }
352                         set \r
353                         {
354                                 EnsureModifiable();
355                                                                                                 
356                                 _width = value;
357                         }
358                 }
359                 #endregion
360
361                 #region Clone
362                 public object Clone ()
363                 {
364                         Pen clone = (Pen)MemberwiseClone();
365                         if (clone._transform != null)
366                                 clone._transform = clone._transform.Clone();
367                         if (clone._dashPattern != null)
368                                 clone._dashPattern = (float[])clone._dashPattern.Clone();
369                         return clone;
370                 }
371                 #endregion
372
373                 #region Dispose 
374                 public void Dispose ()
375                 {
376                         Dispose (true);
377                 }
378                 void Dispose (bool disposing)
379                 {
380                         if (!isModifiable && disposing)
381                                 throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
382                         // Restore the dtor if adding anything below
383                 }
384                 #endregion
385
386                 #region Transform Funcs
387                 public void MultiplyTransform (Matrix matrix)
388                 {
389                         Transform.Multiply (matrix);
390                 }
391
392                 public void MultiplyTransform (Matrix matrix, MatrixOrder order)
393                 {
394                         Transform.Multiply (matrix, order);
395                 }
396
397                 public void ResetTransform ()
398                 {
399                         Transform.Reset ();
400                 }
401
402                 public void RotateTransform (float angle)
403                 {
404                         Transform.Rotate (angle);
405                 }
406
407                 public void RotateTransform (float angle, MatrixOrder order)
408                 {
409                         Transform.Rotate (angle, order);
410                 }
411
412                 public void ScaleTransform (float sx, float sy)
413                 {
414                         Transform.Scale (sx, sy);
415                 }
416
417                 public void ScaleTransform (float sx, float sy, MatrixOrder order)
418                 {
419                         Transform.Scale (sx, sy, order);
420                 }
421
422                 public void TranslateTransform (float dx, float dy) {
423                         Transform.Translate (dx, dy);
424                 }
425
426                 public void TranslateTransform (float dx, float dy, MatrixOrder order) {
427                         Transform.Translate (dx, dy, order);
428                 }
429                 #endregion
430
431                 public void SetLineCap (LineCap startCap, LineCap endCap, DashCap dashCap)
432                 {
433                         StartCap = startCap;
434                         DashCap = dashCap;
435                         EndCap = endCap;
436                 }
437
438                 void EnsureModifiable() {
439                         if (!isModifiable)
440                                 throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
441                 }
442
443                 #region Stroke Members\r
444 \r
445                 awt.Shape awt.Stroke.createStrokedShape(awt.Shape arg_0) {\r
446                         float[] dashPattern = null;\r
447                         //spivak.BUGBUG
448                         //You will see many magic numbers above this place
449                         //behaviours of dash patterns in .NET and JAVA are not similar
450                         //also it looks like JAVA have some design flaw there.
451                         //The issue is that in java only switched on (ODD) entries are
452                         //looks to be dependent on current line with. Switched off (EVEN)
453                         //entries allways remains exact width as you specify. So we should 
454                         //do some calculations to determine actual java pattern 
455                         //Also note that ODD entries does not grow proportionally with line width
456                         //so they should be sligntly ajusted also.
457                         //Well, i know that potential perfomance of this staf could be bad, but
458                         //that is solution for now. Note, that .NET have also numerous bugs in this
459                         //region, for example they mandatory could not tolerate patternalising
460                         //lines of 1 pixel width - look will be BAD.\r
461                         switch (DashStyle) {\r
462                                 case DashStyle.Custom:\r
463                                         if (DashPattern != null) {\r
464                                                 dashPattern = new float[DashPattern.Length];\r
465                                                 for(int i = 0; i < DashPattern.Length; i++) {
466                                                         if((i & 1) == 0) {
467                                                                 if (DashPattern[i] > 1.0f)
468                                                                         dashPattern[i] = DashPattern[i] + (DashPattern[i]-1.0f) * Width / 2f;
469                                                         }
470                                                         else
471                                                                 dashPattern[i] = DashPattern[i] * Width * 2f;\r
472                                                 }\r
473                                         }\r
474                                         break;\r
475                                 case DashStyle.Dash:\r
476                                         dashPattern = DASH_ARRAY;\r
477                                         break;\r
478                                 case DashStyle.DashDot:\r
479                                         dashPattern = DASHDOT_ARRAY;\r
480                                         break;\r
481                                 case DashStyle.DashDotDot:\r
482                                         dashPattern = DASHDOTDOT_ARRAY;\r
483                                         break;\r
484                                 \r
485 //                              default:\r
486 //                              case DashStyle.Solid:\r
487 //                                      break;\r
488                         }\r
489 \r
490                         int join;
491                         switch (LineJoin) {
492                                 case LineJoin.Bevel:
493                                         join = java.awt.BasicStroke.JOIN_BEVEL;
494                                         break;
495                                 default:
496                                 case LineJoin.Miter:
497                                 case LineJoin.MiterClipped:
498                                         join = java.awt.BasicStroke.JOIN_MITER;
499                                         break;
500                                 case LineJoin.Round:
501                                         join = java.awt.BasicStroke.JOIN_ROUND;\r
502                                         break;\r
503                         }\r
504 \r
505                         // We go by End cap for now.\r
506                         int cap;\r
507                         switch (EndCap) {\r
508                                 default:\r
509                                 case LineCap.Square:
510                                 case LineCap.SquareAnchor:
511                                         cap = awt.BasicStroke.CAP_SQUARE;
512                                         break;
513                                 case LineCap.Round: 
514                                 case LineCap.RoundAnchor:
515                                         cap = awt.BasicStroke.CAP_ROUND;
516                                         break;
517                                 case LineCap.Flat:
518                                         cap = awt.BasicStroke.CAP_BUTT;
519                                         break;\r
520                         }\r
521 \r
522                         awt.Stroke stroke = StrokeFactory.CreateStroke(Width, cap, \r
523                                 join, MiterLimit, dashPattern, DashOffset,\r
524                                 _transform != null ? _transform.NativeObject : null);\r
525                         \r
526                         return stroke.createStrokedShape(arg_0);\r
527                 }\r
528 \r
529                 #endregion
530         }
531 }