2 // System.Drawing.Pen.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Alexandre Pigolkine (pigolkine@gmx.de)
7 // Duncan Mak (duncan@ximian.com)
8 // Ravindra (rkumar@novell.com)
10 // (C) Ximian, Inc. http://www.ximian.com
11 // (C) Novell, Inc. http://www.novell.com
15 using System.Drawing.Drawing2D;
16 using System.Runtime.InteropServices;
19 using geom = java.awt.geom;
21 namespace System.Drawing
\r
24 public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable, awt.Stroke
\r
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};
33 internal bool isModifiable = true;
43 PenAlignment _alignment;
48 //float[] _compoundArray;
54 #region Ctors. and Dtor
56 public Pen (Brush brush) : this (brush, 1.0F)
59 public Pen (Color color) : this (color, 1.0F)
62 public Pen (Color color, float width) : this(new SolidBrush(color), width)
65 public Pen (Brush brush, float width)
67 _brush = (Brush)brush.Clone();;
69 _dashStyle = DashStyle.Solid;
70 _startCap = LineCap.Flat;
71 _dashCap = DashCap.Flat;
72 _endCap = LineCap.Flat;
73 _alignment = PenAlignment.Center;
74 _lineJoin = LineJoin.Miter;
76 _transform = new Matrix();
82 #region Alignment [TODO]
83 public PenAlignment Alignment
\r
110 throw new ArgumentNullException("brush");
117 public Color Color
\r
121 if(Brush is SolidBrush)
122 return ((SolidBrush)Brush).Color;
123 else if(Brush is HatchBrush)
124 return ((HatchBrush)Brush).ForegroundColor;
132 _brush = new SolidBrush (value);
137 #region CompoundArray [TODO]
139 public float[] CompoundArray {
141 throw new NotImplementedException ();
144 throw new NotImplementedException ();
149 #region CustomEndCap [TODO]
151 public CustomLineCap CustomEndCap
\r
155 throw new NotImplementedException ();
157 // do a check for isModifiable when implementing this property
160 throw new NotImplementedException ();
165 #region CustomStartCap [TODO]
167 public CustomLineCap CustomStartCap
\r
171 throw new NotImplementedException ();
174 // do a check for isModifiable when implementing this property
177 throw new NotImplementedException ();
184 public DashCap DashCap {
197 public float DashOffset
\r
215 public float [] DashPattern
\r
219 return (float [])_dashPattern.Clone();
226 _dashPattern = value;
227 DashStyle = (_dashPattern == null) ? DashStyle.Solid : DashStyle.Custom;
233 public DashStyle DashStyle
\r
248 #region StartCap [TODO - now allways endcap]
250 public LineCap StartCap {
264 public LineCap EndCap
\r
280 #region LineJoin [partial TODO - missed styles]
282 public LineJoin LineJoin {
296 public float MiterLimit
\r
315 public PenType PenType
\r
319 if (Brush is TextureBrush)
320 return PenType.TextureFill;
321 else if (Brush is HatchBrush)
322 return PenType.HatchFill;
323 else if (Brush is LinearGradientBrush)
324 return PenType.LinearGradient;
325 else if (Brush is PathGradientBrush)
326 return PenType.PathGradient;
328 return PenType.SolidColor;
334 public Matrix Transform
\r
338 return _transform.Clone();
345 value.CopyTo(_transform);
351 public float Width
\r
367 public object Clone ()
369 Pen clone = (Pen)MemberwiseClone();
370 if (clone._transform != null)
371 clone._transform = clone._transform.Clone();
372 if (clone._dashPattern != null)
373 clone._dashPattern = (float[])clone._dashPattern.Clone();
379 public void Dispose ()
383 void Dispose (bool disposing)
385 if (!isModifiable && disposing)
386 throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
387 // Restore the dtor if adding anything below
391 #region Transform Funcs
392 public void MultiplyTransform (Matrix matrix)
394 _transform.Multiply (matrix);
397 public void MultiplyTransform (Matrix matrix, MatrixOrder order)
399 _transform.Multiply (matrix, order);
402 public void ResetTransform ()
407 public void RotateTransform (float angle)
409 _transform.Rotate (angle);
412 public void RotateTransform (float angle, MatrixOrder order)
414 _transform.Rotate (angle, order);
417 public void ScaleTransform (float sx, float sy)
419 _transform.Scale (sx, sy);
422 public void ScaleTransform (float sx, float sy, MatrixOrder order)
424 _transform.Scale (sx, sy, order);
427 public void TranslateTransform (float dx, float dy) {
428 _transform.Translate (dx, dy);
431 public void TranslateTransform (float dx, float dy, MatrixOrder order) {
432 _transform.Translate (dx, dy, order);
436 public void SetLineCap (LineCap startCap, LineCap endCap, DashCap dashCap)
443 void EnsureModifiable() {
445 throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
448 internal double GetSquaredTransformedWidth(geom.AffineTransform coordsTransform) {
449 geom.AffineTransform transform = _transform.NativeObject;
450 double A = transform.getScaleX(); // m00
451 double B = transform.getShearY(); // m10
452 double C = transform.getShearX(); // m01
453 double D = transform.getScaleY(); // m11
455 double K = coordsTransform.getScaleX(); // m00
456 double L = coordsTransform.getShearY(); // m10
457 double M = coordsTransform.getShearX(); // m01
458 double N = coordsTransform.getScaleY(); // m11
460 double AD = A*D, BC = B*C, KN = K*N, LM = L*M;
461 double KN_LM = KN-LM;
462 return Math.Abs(Width*Width * (AD*KN_LM - BC*KN_LM));
466 internal bool CanCreateBasicStroke {
468 if (!_transform.IsIdentity)
471 //FIXME: add more logic when more features will
477 internal awt.Stroke GetNativeObject(geom.AffineTransform outputTransform, PenFit penFit) {
478 return GetNativeObject(null, outputTransform, penFit);
483 /// <param name="outputTransform">transform which will be applied on the final shape</param>
\r
484 /// <param name="fitPen">ensure the shape will wide enough to be visible</param>
\r
485 /// <returns></returns>
486 internal awt.Stroke GetNativeObject(geom.AffineTransform penTransform, geom.AffineTransform outputTransform, PenFit penFit) {
487 float[] dashPattern = null;
\r
489 switch (DashStyle) {
\r
490 case DashStyle.Custom:
\r
491 if (_dashPattern != null) {
\r
492 dashPattern = new float[_dashPattern.Length];
\r
493 for(int i = 0; i < _dashPattern.Length; i++) {
495 if (EndCap == LineCap.Flat)
496 dashPattern[i] = _dashPattern[i] * Width;
499 // remove the size of caps from the opaque parts
500 dashPattern[i] = (_dashPattern[i] * Width) - Width;
501 if (_dashPattern[i] < 0)
505 // add the size of caps to the transparent parts
506 dashPattern[i] = (_dashPattern[i] * Width) + Width;
511 case DashStyle.Dash:
\r
512 dashPattern = DASH_ARRAY;
\r
514 case DashStyle.DashDot:
\r
515 dashPattern = DASHDOT_ARRAY;
\r
517 case DashStyle.DashDotDot:
\r
518 dashPattern = DASHDOTDOT_ARRAY;
\r
522 // case DashStyle.Solid:
\r
529 join = java.awt.BasicStroke.JOIN_BEVEL;
533 case LineJoin.MiterClipped:
534 join = java.awt.BasicStroke.JOIN_MITER;
537 join = java.awt.BasicStroke.JOIN_ROUND;
\r
541 // We go by End cap for now.
\r
546 case LineCap.SquareAnchor:
547 cap = awt.BasicStroke.CAP_SQUARE;
550 case LineCap.RoundAnchor:
551 cap = awt.BasicStroke.CAP_ROUND;
554 cap = awt.BasicStroke.CAP_BUTT;
558 geom.AffineTransform penT = _transform.NativeObject;
\r
559 if (penTransform != null && !penTransform.isIdentity()) {
\r
560 penT = (geom.AffineTransform)penT.clone();
\r
561 penT.concatenate(penTransform);
\r
564 return StrokeFactory.CreateStroke(Width, cap,
\r
565 join, MiterLimit, dashPattern, DashOffset,
\r
566 penT, outputTransform, penFit);
569 #region Stroke Members
\r
571 awt.Shape awt.Stroke.createStrokedShape(awt.Shape arg_0) {
\r
572 return GetNativeObject(null, PenFit.NotThin).createStrokedShape(arg_0);
\r