AdvancedStroke implementation
[mono.git] / mcs / class / System.Drawing / System.Drawing / Pen.jvm.cs
index fb9665916f6cc00d9c920b28bfe7558086d2e622..15a2ac5abaf469f3de7c90f13f8cec92498406ab 100755 (executable)
 using System;
 using System.Drawing.Drawing2D;
 using System.Runtime.InteropServices;
-using java.awt;
 
-namespace System.Drawing 
+using awt = java.awt;
+
+namespace System.Drawing \r
 {
 
-       public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable 
+       public sealed class Pen : MarshalByRefObject, ICloneable, IDisposable, awt.Stroke\r
        {
                #region Member Vars
-               java.awt.BasicStroke nativeObject;
+
+               static readonly float [] DASH_ARRAY = {4.0f,1.0f};
+               static readonly float [] DASHDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f};
+               static readonly float [] DASHDOTDOT_ARRAY = {4.0f,1.0f,1.0f,1.0f,1.0f,1.0f};
+               static readonly float [] DOT_ARRAY = {1.0f,1.0f};
+
                internal bool isModifiable = true;
-               Brush brush;
-               DashStyle _ds = DashStyle.Solid; 
+
+               Brush _brush;
+               DashStyle _dashStyle;
+               DashCap _dashCap;
+               LineCap _startCap;
+               LineCap _endCap;
+
+               LineJoin _lineJoin;
+
                PenAlignment _alignment;
                Matrix _transform;
-               #endregion
+               float _width;
+               float _dashOffset;
+               float[] _dashPattern;
+               //float[] _compoundArray;
 
-               #region Internals
-               internal Pen (java.awt.BasicStroke p)
-               {
-                       nativeObject = p;
-               }
+               float _miterLimit;
 
-               internal java.awt.BasicStroke NativeObject
-               {
-                       get
-                       {
-                               return nativeObject;
-                       }
-                       set
-                       {
-                               nativeObject=value;
-                       }
-               }
                #endregion
 
                #region Ctors. and Dtor
-//             ~Pen ()
-//             {
-//                     Dispose (false);
-//             }
 
                public Pen (Brush brush) : this (brush, 1.0F)
-               {
-               }
+               {}
 
                public Pen (Color color) : this (color, 1.0F)
-               {
-               }
+               {}
 
-               public Pen (Color color, float width)                   
-               {
-                       brush = new SolidBrush(color);
-                       nativeObject = new java.awt.BasicStroke(width);
-               }
+               public Pen (Color color, float width) : this(new SolidBrush(color), width)
+               {}
 
                public Pen (Brush brush, float width)
                {
-                       brush = (Brush)brush.Clone();
-                       nativeObject = new java.awt.BasicStroke(width);
+                       _brush = (Brush)brush.Clone();;
+                       _width = width;
+                       _dashStyle = DashStyle.Solid;
+                       _startCap = LineCap.Flat;
+                       _dashCap = DashCap.Flat;
+                       _endCap = LineCap.Flat;
+                       _alignment = PenAlignment.Center;
+                       _lineJoin = LineJoin.Miter;
+                       _miterLimit = 10f;
                }
                #endregion
                //
                // Properties
                //
                #region Alignment [TODO]
-               public PenAlignment Alignment 
+               public PenAlignment Alignment \r
                {
-                       get 
+                       get \r
                        {
                                return _alignment;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (!isModifiable)
-                                       throw new ArgumentException ("Pen is not modifiable");
+                               EnsureModifiable();
                                _alignment = value;
                        }
                }
                #endregion
 
                #region Brush
-               public Brush Brush 
+               public Brush Brush \r
                {
-                       get 
+                       get \r
                        {
-                               return brush;
+                               return _brush;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (isModifiable) 
-                               {
-                                       brush = value;
-                               }
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+                               if (value == null)
+                                       throw new ArgumentNullException("brush");
+                               _brush = value;
                        }
                }
                #endregion
 
                #region Color
-               public Color Color 
+               public Color Color \r
                {
-                       get 
+                       get \r
                        {
-                               if(brush is SolidBrush)
-                                       return ((SolidBrush)brush).Color;
-                               else if(brush is HatchBrush)
-                                       return ((HatchBrush)brush).ForegroundColor;
+                               if(Brush is SolidBrush)
+                                       return ((SolidBrush)Brush).Color;
+                               else if(Brush is HatchBrush)
+                                       return ((HatchBrush)Brush).ForegroundColor;
                                else
                                        return Color.Empty;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (isModifiable) 
-                               {
-                                       brush = new SolidBrush (value);
-                               }
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+                               _brush = new SolidBrush (value);
                        }
                }
                #endregion 
+
+               #region CompoundArray [TODO]
+               public float[] CompoundArray {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+                       set {
+                               throw new NotImplementedException ();
+                       }
+               }
+               #endregion
             
                #region CustomEndCap [TODO]
-               public CustomLineCap CustomEndCap 
+               public CustomLineCap CustomEndCap \r
                {
-                       get 
+                       get \r
                        {
                                throw new NotImplementedException ();
                        }
                        // do a check for isModifiable when implementing this property
-                       set 
+                       set \r
                        {
                                throw new NotImplementedException ();                                
                        }
                }
                #endregion 
 
-               #region CustoStartCap [TODO]
-               public CustomLineCap CustomStartCap 
+               #region CustomStartCap [TODO]
+               public CustomLineCap CustomStartCap \r
                {
 
-                       get 
+                       get \r
                        {
                                throw new NotImplementedException ();                                
                        }
 
                        // do a check for isModifiable when implementing this property
-                       set 
+                       set \r
                        {
                                throw new NotImplementedException ();                                
                        }
                }
                #endregion
 
-               #region DashCap [TODO, now - allways flat]
-               public DashCap DashCap 
-               {
-                       get 
-                       {
-                               //TODO
-                               return DashCap.Flat;
+               #region DashCap
+               public DashCap DashCap {
+                       get {
+                               return _dashCap;
                        }
 
-                       set 
-                       {
-                               
+                       set {
+                               EnsureModifiable();
+                               _dashCap = value;
                        }
                }
                #endregion
 
                #region DashOffset
-               public float DashOffset 
+               public float DashOffset \r
                {
 
-                       get 
+                       get \r
                        {
-                               return nativeObject.getDashPhase();
+                               return _dashOffset;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (isModifiable)
-                                       nativeObject = new java.awt.BasicStroke(
-                                               nativeObject.getLineWidth(),
-                                               nativeObject.getEndCap(),
-                                               nativeObject.getLineJoin(),
-                                               nativeObject.getMiterLimit(),
-                                               nativeObject.getDashArray(),
-                                               value);
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+                               _dashOffset = value;
                        }
                }
                #endregion
 
                #region DashPattern
 
-               //spivak.BUGBUG
-               //You will see many magic numbers above this place
-               //behaviours of dash patterns in .NET and JAVA are not similar
-               //also it looks like JAVA have some design flaw there.
-               //The issue is that in java only switched on (ODD) entries are
-               //looks to be dependent on current line with. Switched off (EVEN)
-               //entries allways remains exact width as you specify. So we should 
-               //do some calculations to determine actual java pattern 
-               //Also note that ODD entries does not grow proportionally with line width
-               //so they should be sligntly ajusted also.
-               //Well, i know that potential perfomance of this staf could be bad, but
-               //that is solution for now. Note, that .NET have also numerous bugs in this
-               //region, for example they mandatory could not tolerate patternalising
-               //lines of 1 pixel width - look will be BAD.
-
-               internal void SetDashPattern(float [] patt,DashStyle s)
+               public float [] DashPattern \r
                {
-                       if(patt == null)
+                       get \r
                        {
-                               nativeObject = new java.awt.BasicStroke(
-                                       nativeObject.getLineWidth(),
-                                       nativeObject.getEndCap(),
-                                       nativeObject.getLineJoin(),
-                                       nativeObject.getMiterLimit(),
-                                       null,
-                                       nativeObject.getDashPhase());
-                                       _ds = DashStyle.Solid;
-                       }
-                       else
-                       {
-                               float [] temp = new float[patt.Length];
-                               patt.CopyTo(temp,0);
-                               float w = nativeObject.getLineWidth();
-                               int i;
-                               for(i = 0;i<temp.Length;i+=2)
-                                       if(temp[i] > 1.0f)
-                                               temp[i] = temp[i] + (temp[i]-1.0f) * w / (float)2;
-
-                               for(i = 1;i<temp.Length;i+=2)
-                                       temp[i] *= nativeObject.getLineWidth() * (float)2;
-
-                               nativeObject = new java.awt.BasicStroke(
-                                       nativeObject.getLineWidth(),
-                                       nativeObject.getEndCap(),
-                                       nativeObject.getLineJoin(),
-                                       nativeObject.getMiterLimit(),
-                                       temp,
-                                       nativeObject.getDashPhase());
-                               _ds = DashStyle.Custom;
+                               return _dashPattern;
                        }
 
-               }
-
-               public float [] DashPattern 
-               {
-                       get 
+                       set \r
                        {
-                               float w = nativeObject.getLineWidth();
-                               float [] temp = nativeObject.getDashArray();
-                               for(int i = 0;i<temp.Length;i+=2)
-                                       if(temp[i] > 1.0f)
-                                               temp[i] -= (temp[i] - 1.0f) / w * (float)2;
-
-                               for(int i = 1;i<temp.Length;i+=2)
-                                       temp[i] /= w * 2;
+                               EnsureModifiable();
 
-                               return temp; 
-                       }
-
-                       set 
-                       {
-                               
-                               if (isModifiable) 
-                                       SetDashPattern(value,DashStyle.Custom);
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               _dashPattern = value;
+                               DashStyle = (_dashPattern == null) ? DashStyle.Solid : DashStyle.Custom;
                        }
                }
                #endregion
 
                #region DashStyle
-               public DashStyle DashStyle 
+               public DashStyle DashStyle \r
                {
-                       get 
+                       get \r
                        {
-                               return _ds;
+                               return _dashStyle;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (isModifiable)
-                               {
-                                       if (value == DashStyle.Solid)
-                                               SetDashPattern(null,value);
-                                       else if (value == DashStyle.Dash)
-                                               SetDashPattern(System.Drawing.Drawing2D.DashAttribs.DASH_ARRAY,value);
-                                       else if (value == DashStyle.DashDot)
-                                               SetDashPattern(System.Drawing.Drawing2D.DashAttribs.DASHDOT_ARRAY,value);
-                                       else if (value == DashStyle.DashDotDot)
-                                               SetDashPattern(System.Drawing.Drawing2D.DashAttribs.DASHDOTDOT_ARRAY,value);
-                                       else if (value == DashStyle.Dot)
-                                               SetDashPattern(System.Drawing.Drawing2D.DashAttribs.DOT_ARRAY,value);
-                                       else
-                                               throw new ArgumentOutOfRangeException();
-                               }
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+                               _dashStyle = value;
                        }
                }
                #endregion 
 
                #region StartCap [TODO - now allways endcap]
 
-               public LineCap StartCap 
-               {
-                       get 
-                       {
-                               //TODO
-                return EndCap;           
+               public LineCap StartCap {
+                       get { 
+                               return _startCap;
                        }
 
-                       set 
-                       {
-                               EndCap = value;
+                       set {
+                               EnsureModifiable();
+                               _startCap = value;
                        }
                }
                #endregion
 
                #region EndCap 
-               public LineCap EndCap 
+               public LineCap EndCap \r
                {
-                       get 
+                       get \r
                        {
-                               int cup = nativeObject.getEndCap();
-                               if(cup == BasicStroke.CAP_ROUND)
-                                       return LineCap.Round;
-                               else if(cup == BasicStroke.CAP_BUTT)
-                                       return LineCap.Flat;
-                               else if(cup == BasicStroke.CAP_SQUARE)
-                                       return LineCap.Square;
-                               else 
-                                       return LineCap.Custom;
-                       }
-
-                       set 
+                               return _endCap;
+                       }
+
+                       set \r
                        {
-                               int cap;
-                               if((value == LineCap.Square) ||
-                                       (value == LineCap.SquareAnchor))
-                                       cap = BasicStroke.CAP_SQUARE;
-                               else if ((value == LineCap.Round) || 
-                                       (value == LineCap.RoundAnchor))
-                                       cap = BasicStroke.CAP_ROUND;
-                               else if ((value == LineCap.Flat))
-                                       cap = BasicStroke.CAP_BUTT;
-                               else
-                                       //TODO:default
-                                       cap = BasicStroke.CAP_SQUARE;                                            
+                               EnsureModifiable();
+
+                               _endCap = value;
                        }
                }
                #endregion
  
                #region LineJoin [partial TODO - missed styles]
-               public LineJoin LineJoin 
-               {
-                       //TODO:missed styles
-
-                       get 
-                       {
-
-                               int join = nativeObject.getLineJoin();
-                               if(join == java.awt.BasicStroke.JOIN_BEVEL)
-                                       return LineJoin.Bevel;
-                               else if(join == java.awt.BasicStroke.JOIN_MITER)
-                                       return LineJoin.Miter;
-                               else if(join == java.awt.BasicStroke.JOIN_ROUND)
-                                       return LineJoin.Round;
-                               else
-                                       throw new ArgumentOutOfRangeException();
+               public LineJoin LineJoin {
+                       get {
+                               return _lineJoin;
                        }
 
-                       set 
-                       {
-                               if (isModifiable)
-                               {
-                                       int join = 0;
-                                       if (value ==  LineJoin.Bevel)
-                                               join = java.awt.BasicStroke.JOIN_BEVEL;
-                                       if ((value ==  LineJoin.Miter) || (value==LineJoin.MiterClipped))
-                                               join = java.awt.BasicStroke.JOIN_MITER;
-                                       if (value ==  LineJoin.Round)
-                                               join = java.awt.BasicStroke.JOIN_ROUND;
-
-                                       nativeObject = new java.awt.BasicStroke(
-                                               nativeObject.getLineWidth(),
-                                               nativeObject.getEndCap(),
-                                               join,
-                                               nativeObject.getMiterLimit(),
-                                               nativeObject.getDashArray(),
-                                               nativeObject.getDashPhase());
-                               }
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                       set {
+                               EnsureModifiable();
+                               _lineJoin = value;
                        }
                }
+
                #endregion
 
                #region MiterLimit 
-               public float MiterLimit 
+               public float MiterLimit \r
                {
 
-                       get 
+                       get \r
                        {
-                               return nativeObject.getMiterLimit();
+                               return _miterLimit;
                        }
 
-                       set 
+                       set \r
                        {
-                               if (isModifiable)
-                                       nativeObject = new java.awt.BasicStroke(
-                                               nativeObject.getLineWidth(),
-                                               nativeObject.getEndCap(),
-                                               nativeObject.getLineJoin(),
-                                               value,
-                                               nativeObject.getDashArray(),
-                                               nativeObject.getDashPhase());                                                                   
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+
+                               _miterLimit = value;                    
                        }
                            
                }
                #endregion
 
                #region PenType
-               public PenType PenType 
+               public PenType PenType \r
                {
-
-                       get 
+                       get \r
                        {
-                               if (brush is TextureBrush)
+                               if (Brush is TextureBrush)
                                        return PenType.TextureFill;
-                               else if (brush is HatchBrush)
+                               else if (Brush is HatchBrush)
                                        return PenType.HatchFill;
-                               else if (brush is LinearGradientBrush)
+                               else if (Brush is LinearGradientBrush)
                                        return PenType.LinearGradient;
-                               else if (brush is PathGradientBrush)
+                               else if (Brush is PathGradientBrush)
                                        return PenType.PathGradient;
                                else
                                        return PenType.SolidColor;
@@ -468,44 +323,37 @@ namespace System.Drawing
                }
                #endregion
 
-               #region Transform [TODO]
-               public Matrix Transform 
+               #region Transform
+               public Matrix Transform \r
                {
-                       get 
+                       get \r
                        {
                                if (_transform == null)
                                        _transform = new Matrix ();
                                return _transform;
                        }
                                        
-                       set 
+                       set \r
                        {
-                               if (!isModifiable)
-                    throw new ArgumentException ("Pen is not modifiable");
+                               EnsureModifiable();
+
                                _transform = value;
                        }
                }
                #endregion
 
                #region Width
-               public float Width 
+               public float Width \r
                {
-                       get 
+                       get \r
                        {
-                               return nativeObject.getLineWidth();
+                               return _width;
                        }
-                       set 
+                       set \r
                        {
-                               if (isModifiable)
-                                       nativeObject = new java.awt.BasicStroke(
-                                               value,
-                                               nativeObject.getEndCap(),
-                                               nativeObject.getLineJoin(),
-                                               nativeObject.getMiterLimit(),
-                                               nativeObject.getDashArray(),
-                                               nativeObject.getDashPhase());                                                                                                           
-                               else
-                                       throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+                               EnsureModifiable();
+                                                                                               
+                               _width = value;
                        }
                }
                #endregion
@@ -513,13 +361,12 @@ namespace System.Drawing
                #region Clone
                public object Clone ()
                {
-                       Pen p = new Pen (nativeObject);
-                       p.isModifiable = isModifiable;
-                       p.brush = brush;
-                       p._ds = _ds;
-                       p._alignment = _alignment;
-                       p._transform = _transform;
-                       return p;
+                       Pen clone = (Pen)MemberwiseClone();
+                       if (clone._transform != null)
+                               clone._transform = clone._transform.Clone();
+                       if (clone._dashPattern != null)
+                               clone._dashPattern = (float[])clone._dashPattern.Clone();
+                       return clone;
                }
                #endregion
 
@@ -536,7 +383,7 @@ namespace System.Drawing
                }
                #endregion
 
-               #region Transform Funcs [TODO]
+               #region Transform Funcs
                public void MultiplyTransform (Matrix matrix)
                {
                        Transform.Multiply (matrix);
@@ -580,9 +427,105 @@ namespace System.Drawing
                        Transform.Translate (dx, dy, order);
                }
                #endregion
+
                public void SetLineCap (LineCap startCap, LineCap endCap, DashCap dashCap)
                {
-                       throw new NotImplementedException();
+                       StartCap = startCap;
+                       DashCap = dashCap;
+                       EndCap = endCap;
                }
+
+               void EnsureModifiable() {
+                       if (!isModifiable)
+                               throw new ArgumentException ("You may not change this Pen because it does not belong to you.");
+               }
+
+               #region Stroke Members\r
+\r
+               awt.Shape awt.Stroke.createStrokedShape(awt.Shape arg_0) {\r
+                       float[] dashPattern = null;\r
+                       //spivak.BUGBUG
+                       //You will see many magic numbers above this place
+                       //behaviours of dash patterns in .NET and JAVA are not similar
+                       //also it looks like JAVA have some design flaw there.
+                       //The issue is that in java only switched on (ODD) entries are
+                       //looks to be dependent on current line with. Switched off (EVEN)
+                       //entries allways remains exact width as you specify. So we should 
+                       //do some calculations to determine actual java pattern 
+                       //Also note that ODD entries does not grow proportionally with line width
+                       //so they should be sligntly ajusted also.
+                       //Well, i know that potential perfomance of this staf could be bad, but
+                       //that is solution for now. Note, that .NET have also numerous bugs in this
+                       //region, for example they mandatory could not tolerate patternalising
+                       //lines of 1 pixel width - look will be BAD.\r
+                       switch (DashStyle) {\r
+                               case DashStyle.Custom:\r
+                                       if (DashPattern != null) {\r
+                                               dashPattern = new float[DashPattern.Length];\r
+                                               for(int i = 0; i < DashPattern.Length; i++) {
+                                                       if((i & 1) == 0) {
+                                                               if (DashPattern[i] > 1.0f)
+                                                                       dashPattern[i] = DashPattern[i] + (DashPattern[i]-1.0f) * Width / 2f;
+                                                       }
+                                                       else
+                                                               dashPattern[i] = DashPattern[i] * Width * 2f;\r
+                                               }\r
+                                       }\r
+                                       break;\r
+                               case DashStyle.Dash:\r
+                                       dashPattern = DASH_ARRAY;\r
+                                       break;\r
+                               case DashStyle.DashDot:\r
+                                       dashPattern = DASHDOT_ARRAY;\r
+                                       break;\r
+                               case DashStyle.DashDotDot:\r
+                                       dashPattern = DASHDOTDOT_ARRAY;\r
+                                       break;\r
+                               \r
+//                             default:\r
+//                             case DashStyle.Solid:\r
+//                                     break;\r
+                       }\r
+\r
+                       int join;
+                       switch (LineJoin) {
+                               case LineJoin.Bevel:
+                                       join = java.awt.BasicStroke.JOIN_BEVEL;
+                                       break;
+                               default:
+                               case LineJoin.Miter:
+                               case LineJoin.MiterClipped:
+                                       join = java.awt.BasicStroke.JOIN_MITER;
+                                       break;
+                               case LineJoin.Round:
+                                       join = java.awt.BasicStroke.JOIN_ROUND;\r
+                                       break;\r
+                       }\r
+\r
+                       // We go by End cap for now.\r
+                       int cap;\r
+                       switch (EndCap) {\r
+                               default:\r
+                               case LineCap.Square:
+                               case LineCap.SquareAnchor:
+                                       cap = awt.BasicStroke.CAP_SQUARE;
+                                       break;
+                               case LineCap.Round: 
+                               case LineCap.RoundAnchor:
+                                       cap = awt.BasicStroke.CAP_ROUND;
+                                       break;
+                               case LineCap.Flat:
+                                       cap = awt.BasicStroke.CAP_BUTT;
+                                       break;\r
+                       }\r
+\r
+                       awt.Stroke stroke = StrokeFactory.CreateStroke(Width, cap, \r
+                               join, MiterLimit, dashPattern, DashOffset,\r
+                               _transform != null ? _transform.NativeObject : null);\r
+                       \r
+                       return stroke.createStrokedShape(arg_0);\r
+               }\r
+\r
+               #endregion
        }
 }