SvgRectangle.cs 8.39 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>
10
    [SvgElement("rect")]
11
    public class SvgRectangle : SvgVisualElement
davescriven's avatar
davescriven committed
12
13
14
    {
        private SvgUnit _cornerRadiusX;
        private SvgUnit _cornerRadiusY;
15
        private SvgUnit _height;
davescriven's avatar
davescriven committed
16
        private GraphicsPath _path;
17
18
19
20
        private SvgUnit _width;
        private SvgUnit _x;
        private SvgUnit _y;

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

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

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

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

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

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

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

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

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

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

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

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

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

                        _path = new GraphicsPath();
                        _path.StartFigure();
                        _path.AddRectangle(rectangle);
                        _path.CloseFigure();
                    }
                    else
                    {
                        _path = new GraphicsPath();
176
177
178
179
180
181
182
183
                        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
184
185
186
187
188
189
190
191
192
193
194

                        // Start
                        _path.StartFigure();

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

                        // Add first line
195
                        lineStart.X = location.X + rx;
davescriven's avatar
davescriven committed
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
236
                        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();
                    }
237
                    IsPathDirty = false;
davescriven's avatar
davescriven committed
238
239
240
241
242
                }
                return _path;
            }
        }

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