2005-10-04 Zoltan Varga <vargaz@freemail.hu>
[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 using geom = java.awt.geom;
20
21 namespace System.Drawing \r
22 {
23
24         public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable, awt.Stroke\r
25         {
26                 #region Member Vars
27
28                 static readonly float [] DASH_ARRAY = {4.0f,1.0f};
29                 static readonly float [] DASHDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f};
30                 static readonly float [] DASHDOTDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
31                 static readonly float [] DOT_ARRAY = {1.0f,1.0f};
32
33                 internal bool isModifiable = true;
34
35                 Brush _brush;
36                 DashStyle _dashStyle;
37                 DashCap _dashCap;
38                 LineCap _startCap;
39                 LineCap _endCap;
40
41                 LineJoin _lineJoin;
42
43                 PenAlignment _alignment;
44                 Matrix _transform;
45                 float _width;
46                 float _dashOffset;
47                 float[] _dashPattern;
48                 //float[] _compoundArray;
49
50                 float _miterLimit;
51
52                 #endregion
53
54                 #region Ctors. and Dtor
55
56                 public Pen (Brush brush) : this (brush, 1.0F)
57                 {}
58
59                 public Pen (Color color) : this (color, 1.0F)
60                 {}
61
62                 public Pen (Color color, float width) : this(new SolidBrush(color), width)
63                 {}
64
65                 public Pen (Brush brush, float width)
66                 {
67                         _brush = (Brush)brush.Clone();;
68                         _width = width;
69                         _dashStyle = DashStyle.Solid;
70                         _startCap = LineCap.Flat;
71                         _dashCap = DashCap.Flat;
72                         _endCap = LineCap.Flat;
73                         _alignment = PenAlignment.Center;
74                         _lineJoin = LineJoin.Miter;
75                         _miterLimit = 10f;
76                         _transform = new Matrix();
77                 }
78                 #endregion
79                 //
80                 // Properties
81                 //
82                 #region Alignment [TODO]
83                 public PenAlignment Alignment \r
84                 {
85                         get \r
86                         {
87                                 return _alignment;
88                         }
89
90                         set \r
91                         {
92                                 EnsureModifiable();
93                                 _alignment = value;
94                         }
95                 }
96                 #endregion
97
98                 #region Brush
99                 public Brush Brush \r
100                 {
101                         get \r
102                         {
103                                 return _brush;
104                         }
105
106                         set \r
107                         {
108                                 EnsureModifiable();
109                                 if (value == null)
110                                         throw new ArgumentNullException("brush");
111                                 _brush = value;
112                         }
113                 }
114                 #endregion
115
116                 #region Color
117                 public Color Color \r
118                 {
119                         get \r
120                         {
121                                 if(Brush is SolidBrush)
122                                         return ((SolidBrush)Brush).Color;
123                                 else if(Brush is HatchBrush)
124                                         return ((HatchBrush)Brush).ForegroundColor;
125                                 else
126                                         return Color.Empty;
127                         }
128
129                         set \r
130                         {
131                                 EnsureModifiable();
132                                 _brush = new SolidBrush (value);
133                         }
134                 }
135                 #endregion 
136
137                 #region CompoundArray [TODO]
138                 public float[] CompoundArray {
139                         get {
140                                 throw new NotImplementedException ();
141                         }
142                         set {
143                                 throw new NotImplementedException ();
144                         }
145                 }
146                 #endregion
147             
148                 #region CustomEndCap [TODO]
149                 public CustomLineCap CustomEndCap \r
150                 {
151                         get \r
152                         {
153                                 throw new NotImplementedException ();
154                         }
155                         // do a check for isModifiable when implementing this property
156                         set \r
157                         {
158                                 throw new NotImplementedException ();                                
159                         }
160                 }
161                 #endregion 
162
163                 #region CustomStartCap [TODO]
164                 public CustomLineCap CustomStartCap \r
165                 {
166
167                         get \r
168                         {
169                                 throw new NotImplementedException ();                                
170                         }
171
172                         // do a check for isModifiable when implementing this property
173                         set \r
174                         {
175                                 throw new NotImplementedException ();                                
176                         }
177                 }
178                 #endregion
179
180                 #region DashCap
181                 public DashCap DashCap {
182                         get {
183                                 return _dashCap;
184                         }
185
186                         set {
187                                 EnsureModifiable();
188                                 _dashCap = value;
189                         }
190                 }
191                 #endregion
192
193                 #region DashOffset
194                 public float DashOffset \r
195                 {
196
197                         get \r
198                         {
199                                 return _dashOffset;
200                         }
201
202                         set \r
203                         {
204                                 EnsureModifiable();
205                                 _dashOffset = value;
206                         }
207                 }
208                 #endregion
209
210                 #region DashPattern
211
212                 public float [] DashPattern \r
213                 {
214                         get \r
215                         {
216                                 return _dashPattern;
217                         }
218
219                         set \r
220                         {
221                                 EnsureModifiable();
222
223                                 _dashPattern = value;
224                                 DashStyle = (_dashPattern == null) ? DashStyle.Solid : DashStyle.Custom;
225                         }
226                 }
227                 #endregion
228
229                 #region DashStyle
230                 public DashStyle DashStyle \r
231                 {
232                         get \r
233                         {
234                                 return _dashStyle;
235                         }
236
237                         set \r
238                         {
239                                 EnsureModifiable();
240                                 _dashStyle = value;
241                         }
242                 }
243                 #endregion 
244
245                 #region StartCap [TODO - now allways endcap]
246
247                 public LineCap StartCap {
248                         get { 
249                                 return _startCap;
250                         }
251
252                         set {
253                                 EnsureModifiable();
254                                 _startCap = value;
255                         }
256                 }
257                 #endregion
258
259                 #region EndCap 
260                 public LineCap EndCap \r
261                 {
262                         get \r
263                         {
264                                 return _endCap;
265                         }
266
267                         set \r
268                         {
269                                 EnsureModifiable();
270
271                                 _endCap = value;
272                         }
273                 }
274                 #endregion
275  
276                 #region LineJoin [partial TODO - missed styles]
277                 public LineJoin LineJoin {
278                         get {
279                                 return _lineJoin;
280                         }
281
282                         set {
283                                 EnsureModifiable();
284                                 _lineJoin = value;
285                         }
286                 }
287
288                 #endregion
289
290                 #region MiterLimit 
291                 public float MiterLimit \r
292                 {
293
294                         get \r
295                         {
296                                 return _miterLimit;
297                         }
298
299                         set \r
300                         {
301                                 EnsureModifiable();
302
303                                 _miterLimit = value;                    
304                         }
305                             
306                 }
307                 #endregion
308
309                 #region PenType
310                 public PenType PenType \r
311                 {
312                         get \r
313                         {
314                                 if (Brush is TextureBrush)
315                                         return PenType.TextureFill;
316                                 else if (Brush is HatchBrush)
317                                         return PenType.HatchFill;
318                                 else if (Brush is LinearGradientBrush)
319                                         return PenType.LinearGradient;
320                                 else if (Brush is PathGradientBrush)
321                                         return PenType.PathGradient;
322                                 else
323                                         return PenType.SolidColor;
324                         }
325                 }
326                 #endregion
327
328                 #region Transform
329                 public Matrix Transform \r
330                 {
331                         get \r
332                         {
333                                 return _transform.Clone();
334                         }
335                                         
336                         set \r
337                         {
338                                 EnsureModifiable();
339
340                                 value.CopyTo(_transform);
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                 internal double GetSquaredTransformedWidth(geom.AffineTransform coordsTransform) {
444                         geom.AffineTransform transform = _transform.NativeObject;
445                         double A = transform.getScaleX();       // m00
446                         double B = transform.getShearY();       // m10
447                         double C = transform.getShearX();       // m01
448                         double D = transform.getScaleY();       // m11
449
450                         double K = coordsTransform.getScaleX(); // m00
451                         double L = coordsTransform.getShearY(); // m10
452                         double M = coordsTransform.getShearX(); // m01
453                         double N = coordsTransform.getScaleY(); // m11
454
455                         double AD = A*D, BC = B*C, KN = K*N, LM = L*M;
456                         double KN_LM = KN-LM;
457                         return Math.Abs(Width*Width * (AD*KN_LM - BC*KN_LM));
458                 }
459
460                 internal awt.Stroke GetNativeObject(geom.AffineTransform outputTransform, bool fitPen) {
461                         return GetNativeObject(null, outputTransform, fitPen);
462                 }
463                 /// <summary>\r
464                 /// \r
465                 /// </summary>\r
466                 /// <param name="outputTransform">transform which will be applied on the final shape</param>\r
467                 /// <param name="fitPen">ensure the shape will wide enough to be visible</param>\r
468                 /// <returns></returns>
469                 internal awt.Stroke GetNativeObject(geom.AffineTransform penTransform, geom.AffineTransform outputTransform, bool fitPen) {
470                         float[] dashPattern = null;\r
471 \r
472                         switch (DashStyle) {\r
473                                 case DashStyle.Custom:\r
474                                         if (DashPattern != null) {\r
475                                                 dashPattern = new float[DashPattern.Length];\r
476                                                 for(int i = 0; i < DashPattern.Length; i++) {
477
478                                                         if (EndCap == LineCap.Flat)
479                                                                 dashPattern[i] = DashPattern[i] * Width;
480                                                         else {
481                                                                 if ((i & 1) == 0)
482                                                                         // remove the size of caps from the opaque parts
483                                                                         dashPattern[i] = (DashPattern[i] * Width) - Width;
484                                                                 else
485                                                                         // add the size of caps to the transparent parts
486                                                                         dashPattern[i] = (DashPattern[i] * Width) + Width;
487                                                         }
488                                                 }\r
489                                         }\r
490                                         break;\r
491                                 case DashStyle.Dash:\r
492                                         dashPattern = DASH_ARRAY;\r
493                                         break;\r
494                                 case DashStyle.DashDot:\r
495                                         dashPattern = DASHDOT_ARRAY;\r
496                                         break;\r
497                                 case DashStyle.DashDotDot:\r
498                                         dashPattern = DASHDOTDOT_ARRAY;\r
499                                         break;\r
500                                 \r
501                                         //                              default:\r
502                                         //                              case DashStyle.Solid:\r
503                                         //                                      break;\r
504                         }\r
505 \r
506                         int join;
507                         switch (LineJoin) {
508                                 case LineJoin.Bevel:
509                                         join = java.awt.BasicStroke.JOIN_BEVEL;
510                                         break;
511                                 default:
512                                 case LineJoin.Miter:
513                                 case LineJoin.MiterClipped:
514                                         join = java.awt.BasicStroke.JOIN_MITER;
515                                         break;
516                                 case LineJoin.Round:
517                                         join = java.awt.BasicStroke.JOIN_ROUND;\r
518                                         break;\r
519                         }\r
520 \r
521                         // We go by End cap for now.\r
522                         int cap;\r
523                         switch (EndCap) {\r
524                                 default:\r
525                                 case LineCap.Square:
526                                 case LineCap.SquareAnchor:
527                                         cap = awt.BasicStroke.CAP_SQUARE;
528                                         break;
529                                 case LineCap.Round: 
530                                 case LineCap.RoundAnchor:
531                                         cap = awt.BasicStroke.CAP_ROUND;
532                                         break;
533                                 case LineCap.Flat:
534                                         cap = awt.BasicStroke.CAP_BUTT;
535                                         break;\r
536                         }\r
537 \r
538                         geom.AffineTransform penT = _transform.NativeObject;\r
539                         if (penTransform != null && !penTransform.isIdentity()) {\r
540                                 penT = (geom.AffineTransform)penT.clone();\r
541                                 penT.concatenate(penTransform);\r
542                         }\r
543 \r
544                         return StrokeFactory.CreateStroke(Width, cap, \r
545                                 join, MiterLimit, dashPattern, DashOffset,\r
546                                 penT, outputTransform, fitPen);
547                 }
548
549                 #region Stroke Members\r
550 \r
551                 awt.Shape awt.Stroke.createStrokedShape(awt.Shape arg_0) {\r
552                         return GetNativeObject(null, false).createStrokedShape(arg_0);\r
553                 }\r
554 \r
555                 #endregion
556         }
557 }