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

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

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

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

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

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

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

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

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

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

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

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

135
136
137
        /// <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
138
139
        protected override bool RequiresSmoothRendering
        {
140
            get { return (CornerRadiusX.Value > 0 || CornerRadiusY.Value > 0); }
davescriven's avatar
davescriven committed
141
142
        }

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

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

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

                        // Start
                        _path.StartFigure();

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

                        // Add first line
194
                        lineStart.X = location.X + rx;
davescriven's avatar
davescriven committed
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
                        lineStart.Y = location.Y;
                        lineEnd.X = location.X + width - rx;
                        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;
                        lineStart.Y = location.Y + ry;
                        lineEnd.X = lineStart.X;
                        lineEnd.Y = location.Y + height - ry;
                        _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
                        lineStart.X = location.X + width - rx;
                        lineStart.Y = location.Y + height;
                        lineEnd.X = location.X + rx;
                        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;
                        lineStart.Y = location.Y + height - ry;
                        lineEnd.X = lineStart.X;
                        lineEnd.Y = location.Y + ry;
                        _path.AddLine(lineStart, lineEnd);

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

242
243
244
245
        /// <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
246
        {
247
            if (Width.Value > 0.0f && Height.Value > 0.0f)
248
249
250
            {
                base.Render(renderer);
            }
davescriven's avatar
davescriven committed
251
252
253
        }
    }
}