SvgRectangle.cs 9.13 KB
Newer Older
davescriven's avatar
davescriven committed
1
2
3
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
4
using Svg.Transforms;
davescriven's avatar
davescriven committed
5
6
7

namespace Svg
{
8
9
10
    /// <summary>
    /// Represents and SVG rectangle that could also have reounded edges.
    /// </summary>
11
    [SvgElement("rect")]
12
    public class SvgRectangle : SvgVisualElement
davescriven's avatar
davescriven committed
13
14
15
    {
        private SvgUnit _cornerRadiusX;
        private SvgUnit _cornerRadiusY;
16
        private SvgUnit _height;
davescriven's avatar
davescriven committed
17
        private GraphicsPath _path;
18
19
20
21
        private SvgUnit _width;
        private SvgUnit _x;
        private SvgUnit _y;

22
23
24
        /// <summary>
        /// Initializes a new instance of the <see cref="SvgRectangle"/> class.
        /// </summary>
25
26
27
28
29
        public SvgRectangle()
        {
            _width = new SvgUnit(0.0f);
            _height = new SvgUnit(0.0f);
        }
davescriven's avatar
davescriven committed
30

31
32
33
        /// <summary>
        /// Gets an <see cref="SvgPoint"/> representing the top left point of the rectangle.
        /// </summary>
davescriven's avatar
davescriven committed
34
35
        public SvgPoint Location
        {
36
37
38
            get { return new SvgPoint(X, Y); }
        }

39
40
41
        /// <summary>
        /// Gets or sets the position where the left point of the rectangle should start.
        /// </summary>
davescriven's avatar
davescriven committed
42
43
44
        [SvgAttribute("x")]
        public SvgUnit X
        {
45
46
47
48
49
50
            get { return _x; }
            set
            {
                _x = value;
                IsPathDirty = true;
            }
davescriven's avatar
davescriven committed
51
52
        }

53
54
55
        /// <summary>
        /// Gets or sets the position where the top point of the rectangle should start.
        /// </summary>
davescriven's avatar
davescriven committed
56
57
58
        [SvgAttribute("y")]
        public SvgUnit Y
        {
59
60
61
62
63
64
            get { return _y; }
            set
            {
                _y = value;
                IsPathDirty = true;
            }
davescriven's avatar
davescriven committed
65
66
        }

67
68
69
        /// <summary>
        /// Gets or sets the width of the rectangle.
        /// </summary>
davescriven's avatar
davescriven committed
70
71
72
        [SvgAttribute("width")]
        public SvgUnit Width
        {
73
74
75
76
77
78
            get { return _width; }
            set
            {
                _width = value;
                IsPathDirty = true;
            }
davescriven's avatar
davescriven committed
79
80
        }

81
82
83
        /// <summary>
        /// Gets or sets the height of the rectangle.
        /// </summary>
davescriven's avatar
davescriven committed
84
85
86
        [SvgAttribute("height")]
        public SvgUnit Height
        {
87
88
89
90
91
92
            get { return _height; }
            set
            {
                _height = value;
                IsPathDirty = true;
            }
davescriven's avatar
davescriven committed
93
94
        }

95
96
97
        /// <summary>
        /// Gets or sets the X-radius of the rounded edges of this rectangle.
        /// </summary>
davescriven's avatar
davescriven committed
98
99
100
101
102
103
        [SvgAttribute("rx")]
        public SvgUnit CornerRadiusX
        {
            get
            {
                // If ry has been set and rx hasn't, use it's value
104
105
                if (_cornerRadiusX.Value == 0.0f && _cornerRadiusY.Value > 0.0f)
                    return _cornerRadiusY;
davescriven's avatar
davescriven committed
106

107
108
109
110
111
112
                return _cornerRadiusX;
            }
            set
            {
                _cornerRadiusX = value;
                IsPathDirty = true;
davescriven's avatar
davescriven committed
113
114
115
            }
        }

116
117
118
        /// <summary>
        /// Gets or sets the Y-radius of the rounded edges of this rectangle.
        /// </summary>
davescriven's avatar
davescriven committed
119
120
121
122
123
124
        [SvgAttribute("ry")]
        public SvgUnit CornerRadiusY
        {
            get
            {
                // If rx has been set and ry hasn't, use it's value
125
126
                if (_cornerRadiusY.Value == 0.0f && _cornerRadiusX.Value > 0.0f)
                    return _cornerRadiusX;
davescriven's avatar
davescriven committed
127

128
                return _cornerRadiusY;
davescriven's avatar
davescriven committed
129
130
131
            }
            set
            {
132
133
                _cornerRadiusY = value;
                IsPathDirty = true;
davescriven's avatar
davescriven committed
134
135
136
            }
        }

137
138
139
        /// <summary>
        /// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
        /// </summary>
davescriven's avatar
davescriven committed
140
141
        protected override bool RequiresSmoothRendering
        {
142
            get { return (CornerRadiusX.Value > 0 || CornerRadiusY.Value > 0); }
davescriven's avatar
davescriven committed
143
144
        }

145
146
147
148
        /// <summary>
        /// Gets the bounds of the element.
        /// </summary>
        /// <value>The bounds.</value>
davescriven's avatar
davescriven committed
149
150
        public override RectangleF Bounds
        {
151
            get { return Path.GetBounds(); }
davescriven's avatar
davescriven committed
152
153
        }

154
155
156
        /// <summary>
        /// Gets the <see cref="GraphicsPath"/> for this element.
        /// </summary>
davescriven's avatar
davescriven committed
157
158
159
160
        public override GraphicsPath Path
        {
            get
            {
161
                if (_path == null || IsPathDirty)
davescriven's avatar
davescriven committed
162
163
                {
                    // If the corners aren't to be rounded just create a rectangle
164
                    if (CornerRadiusX.Value == 0.0f && CornerRadiusY.Value == 0.0f)
davescriven's avatar
davescriven committed
165
                    {
166
167
                        var rectangle = new RectangleF(Location.ToDeviceValue(),
                            new SizeF(Width.ToDeviceValue(), Height.ToDeviceValue()));
davescriven's avatar
davescriven committed
168
169
170
171
172
173
174
175
176

                        _path = new GraphicsPath();
                        _path.StartFigure();
                        _path.AddRectangle(rectangle);
                        _path.CloseFigure();
                    }
                    else
                    {
                        _path = new GraphicsPath();
177
178
179
180
181
                        var arcBounds = new RectangleF();
                        var lineStart = new PointF();
                        var lineEnd = new PointF();
                        var width = Width.ToDeviceValue();
                        var height = Height.ToDeviceValue();
182
183
                        var rx = CornerRadiusX.ToDeviceValue() * 2;
                        var ry = CornerRadiusY.ToDeviceValue() * 2;
184
                        var location = Location.ToDeviceValue();
davescriven's avatar
davescriven committed
185
186
187
188
189
190
191
192
193
194
195

                        // Start
                        _path.StartFigure();

                        // Add first arc
                        arcBounds.Location = location;
                        arcBounds.Width = rx;
                        arcBounds.Height = ry;
                        _path.AddArc(arcBounds, 180, 90);

                        // Add first line
196
                        lineStart.X = Math.Min(location.X + rx, location.X + width * 0.5f);
davescriven's avatar
davescriven committed
197
                        lineStart.Y = location.Y;
198
                        lineEnd.X = Math.Max(location.X + width - rx, location.X + width * 0.5f);
davescriven's avatar
davescriven committed
199
200
201
202
203
204
205
206
207
                        lineEnd.Y = lineStart.Y;
                        _path.AddLine(lineStart, lineEnd);

                        // Add second arc
                        arcBounds.Location = new PointF(location.X + width - rx, location.Y);
                        _path.AddArc(arcBounds, 270, 90);

                        // Add second line
                        lineStart.X = location.X + width;
208
                        lineStart.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f);
davescriven's avatar
davescriven committed
209
                        lineEnd.X = lineStart.X;
210
                        lineEnd.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f);
davescriven's avatar
davescriven committed
211
212
213
214
215
216
217
                        _path.AddLine(lineStart, lineEnd);

                        // Add third arc
                        arcBounds.Location = new PointF(location.X + width - rx, location.Y + height - ry);
                        _path.AddArc(arcBounds, 0, 90);

                        // Add third line
218
                        lineStart.X = Math.Max(location.X + width - rx, location.X + width * 0.5f);
davescriven's avatar
davescriven committed
219
                        lineStart.Y = location.Y + height;
220
                        lineEnd.X = Math.Min(location.X + rx, location.X + width * 0.5f);
davescriven's avatar
davescriven committed
221
222
223
224
225
226
227
228
229
                        lineEnd.Y = lineStart.Y;
                        _path.AddLine(lineStart, lineEnd);

                        // Add third arc
                        arcBounds.Location = new PointF(location.X, location.Y + height - ry);
                        _path.AddArc(arcBounds, 90, 90);

                        // Add fourth line
                        lineStart.X = location.X;
230
                        lineStart.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f);
davescriven's avatar
davescriven committed
231
                        lineEnd.X = lineStart.X;
232
                        lineEnd.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f);
davescriven's avatar
davescriven committed
233
234
235
236
237
                        _path.AddLine(lineStart, lineEnd);

                        // Close
                        _path.CloseFigure();
                    }
238
                    IsPathDirty = false;
davescriven's avatar
davescriven committed
239
240
241
242
243
                }
                return _path;
            }
        }

244
245
246
247
        /// <summary>
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
        /// </summary>
        protected override void Render(SvgRenderer renderer)
davescriven's avatar
davescriven committed
248
        {
249
            if (Width.Value > 0.0f && Height.Value > 0.0f)
250
251
252
            {
                base.Render(renderer);
            }
davescriven's avatar
davescriven committed
253
        }
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271


		public override SvgElement DeepCopy()
		{
			return DeepCopy<SvgRectangle>();
		}

		public override SvgElement DeepCopy<T>()
		{
 			var newObj = base.DeepCopy<T>() as SvgRectangle;
			newObj.CornerRadiusX = this.CornerRadiusX;
			newObj.CornerRadiusY = this.CornerRadiusY;
			newObj.Height = this.Height;
			newObj.Width = this.Width;
			newObj.X = this.X;
			newObj.Y = this.Y;
			return newObj;
		}
davescriven's avatar
davescriven committed
272
273
    }
}