SvgElement.cs 36.5 KB
Newer Older
davescriven's avatar
davescriven committed
1
2
3
4
5
6
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Xml;
7
using System.Linq;
davescriven's avatar
davescriven committed
8
using Svg.Transforms;
9
using System.Reflection;
Tebjan Halm's avatar
Tebjan Halm committed
10
11
using System.Threading;
using System.Globalization;
davescriven's avatar
davescriven committed
12
13
14
15
16
17

namespace Svg
{
    /// <summary>
    /// The base class of which all SVG elements are derived from.
    /// </summary>
18
    public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable, ISvgNode
davescriven's avatar
davescriven committed
19
    {
20
        //optimization
21
        protected class PropertyAttributeTuple
22
        {
23
            public PropertyDescriptor Property;
24
25
            public SvgAttributeAttribute Attribute;
        }
26
27
28
29
30
31
32

        protected class EventAttributeTuple
        {
            public FieldInfo Event;
            public SvgAttributeAttribute Attribute;
        }

Tebjan Halm's avatar
Tebjan Halm committed
33
        //reflection cache
34
35
        private IEnumerable<PropertyAttributeTuple> _svgPropertyAttributes;
        private IEnumerable<EventAttributeTuple> _svgEventAttributes;
36

davescriven's avatar
davescriven committed
37
38
39
40
41
42
43
        internal SvgElement _parent;
        private string _elementName;
        private SvgAttributeCollection _attributes;
        private EventHandlerList _eventHandlers;
        private SvgElementCollection _children;
        private static readonly object _loadEventKey = new object();
        private Matrix _graphicsMatrix;
44
        private SvgCustomAttributeCollection _customAttributes;
45
        private List<ISvgNode> _nodes = new List<ISvgNode>();
davescriven's avatar
davescriven committed
46

Eric Domke's avatar
Eric Domke committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

        private Dictionary<string, SortedDictionary<int, string>> _styles = new Dictionary<string, SortedDictionary<int, string>>();
        
        public void AddStyle(string name, string value, int specificity)
        {
            SortedDictionary<int, string> rules;
            if (!_styles.TryGetValue(name, out rules))
            {
                rules = new SortedDictionary<int, string>();
                _styles[name] = rules;
            }
            while (rules.ContainsKey(specificity)) specificity++;
            rules[specificity] = value;
        }
        public void FlushStyles()
        {
            foreach (var s in _styles)
            {
                SvgElementFactory.SetPropertyValue(this, s.Key, s.Value.Last().Value, this.OwnerDocument);
            }
            _styles = null;
        }

davescriven's avatar
davescriven committed
70
71
72
        /// <summary>
        /// Gets the name of the element.
        /// </summary>
73
        protected internal string ElementName
davescriven's avatar
davescriven committed
74
        {
75
76
77
78
79
80
81
82
83
84
85
86
87
88
            get
            {
                if (string.IsNullOrEmpty(this._elementName))
                {
                    var attr = TypeDescriptor.GetAttributes(this).OfType<SvgElementAttribute>().SingleOrDefault();

                    if (attr != null)
                    {
                        this._elementName = attr.ElementName;
                    }
                }

                return this._elementName;
            }
89
            internal set { this._elementName = value; }
davescriven's avatar
davescriven committed
90
91
92
93
94
        }

        /// <summary>
        /// Gets or sets the content of the element.
        /// </summary>
Tebjan Halm's avatar
Tebjan Halm committed
95
        private string _content;
davescriven's avatar
davescriven committed
96
97
        public virtual string Content
        {
Tebjan Halm's avatar
Tebjan Halm committed
98
99
100
101
102
103
104
105
106
107
108
            get
            {
            	return _content;
            }
            set
            {
            	if(_content != null)
            	{
            		var oldVal = _content;
            		_content = value;
            		if(_content != oldVal)
tebjan's avatar
tebjan committed
109
            			OnContentChanged(new ContentEventArgs{ Content = value });
Tebjan Halm's avatar
Tebjan Halm committed
110
111
112
113
            	}
            	else
            	{
            		_content = value;
tebjan's avatar
tebjan committed
114
            		OnContentChanged(new ContentEventArgs{ Content = value });
Tebjan Halm's avatar
Tebjan Halm committed
115
116
            	}
            }
davescriven's avatar
davescriven committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
        }

        /// <summary>
        /// Gets an <see cref="EventHandlerList"/> of all events belonging to the element.
        /// </summary>
        protected virtual EventHandlerList Events
        {
            get { return this._eventHandlers; }
        }

        /// <summary>
        /// Occurs when the element is loaded.
        /// </summary>
        public event EventHandler Load
        {
            add { this.Events.AddHandler(_loadEventKey, value); }
            remove { this.Events.RemoveHandler(_loadEventKey, value); }
        }

        /// <summary>
        /// Gets a collection of all child <see cref="SvgElements"/>.
        /// </summary>
        public virtual SvgElementCollection Children
        {
            get { return this._children; }
        }

144
145
146
147
148
        public IList<ISvgNode> Nodes
        {
            get { return this._nodes; }
        }

Eric Domke's avatar
Eric Domke committed
149
150
151
152
153
154
155
156
157
        public IEnumerable<SvgElement> Descendants()
        {
            return this.AsEnumerable().Descendants();
        }
        private IEnumerable<SvgElement> AsEnumerable()
        {
            yield return this;
        }

davescriven's avatar
davescriven committed
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
        /// <summary>
        /// Gets a value to determine whether the element has children.
        /// </summary>
        public virtual bool HasChildren()
        {
            return (this.Children.Count > 0);
        }

        /// <summary>
        /// Gets the parent <see cref="SvgElement"/>.
        /// </summary>
        /// <value>An <see cref="SvgElement"/> if one exists; otherwise null.</value>
        public virtual SvgElement Parent
        {
            get { return this._parent; }
        }

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
        public IEnumerable<SvgElement> Parents
        {
            get
            {
                var curr = this;
                while (curr.Parent != null)
                {
                    curr = curr.Parent;
                    yield return curr;
                }
            }
        }
        public IEnumerable<SvgElement> ParentsAndSelf
        {
            get
            {
                var curr = this;
                yield return curr;
                while (curr.Parent != null)
                {
                    curr = curr.Parent;
                    yield return curr;
                }
            }
        }

davescriven's avatar
davescriven committed
201
202
203
204
205
        /// <summary>
        /// Gets the owner <see cref="SvgDocument"/>.
        /// </summary>
        public virtual SvgDocument OwnerDocument
        {
206
207
208
209
210
211
212
213
214
215
216
217
218
219
        	get
        	{
        		if (this is SvgDocument)
        		{
        			return this as SvgDocument;
        		}
        		else
        		{
        			if(this.Parent != null)
        				return Parent.OwnerDocument;
        			else
        				return null;
        		}
        	}
davescriven's avatar
davescriven committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
        }

        /// <summary>
        /// Gets a collection of element attributes.
        /// </summary>
        protected internal virtual SvgAttributeCollection Attributes
        {
            get
            {
                if (this._attributes == null)
                {
                    this._attributes = new SvgAttributeCollection(this);
                }

                return this._attributes;
            }
        }

238
239
240
241
        /// <summary>
        /// Gets a collection of custom attributes
        /// </summary>
        public SvgCustomAttributeCollection CustomAttributes
242
243
244
245
        {
            get { return this._customAttributes; }
        }

246
247
248
249
250
        /// <summary>
        /// Applies the required transforms to <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
        protected internal virtual void PushTransforms(SvgRenderer renderer)
davescriven's avatar
davescriven committed
251
        {
252
            _graphicsMatrix = renderer.Transform;
253

davescriven's avatar
davescriven committed
254
255
256
257
258
259
            // Return if there are no transforms
            if (this.Transforms == null || this.Transforms.Count == 0)
            {
                return;
            }

260
            Matrix transformMatrix = renderer.Transform;
davescriven's avatar
davescriven committed
261
262
263

            foreach (SvgTransform transformation in this.Transforms)
            {
264
                transformMatrix.Multiply(transformation.Matrix);
davescriven's avatar
davescriven committed
265
266
            }

267
            renderer.Transform = transformMatrix;
davescriven's avatar
davescriven committed
268
269
        }

270
271
272
273
274
        /// <summary>
        /// Removes any previously applied transforms from the specified <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> that should have transforms removed.</param>
        protected internal virtual void PopTransforms(SvgRenderer renderer)
davescriven's avatar
davescriven committed
275
        {
276
            renderer.Transform = _graphicsMatrix;
davescriven's avatar
davescriven committed
277
278
279
            _graphicsMatrix = null;
        }

280
281
282
283
284
        /// <summary>
        /// Applies the required transforms to <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
        void ISvgTransformable.PushTransforms(SvgRenderer renderer)
davescriven's avatar
davescriven committed
285
        {
286
            this.PushTransforms(renderer);
davescriven's avatar
davescriven committed
287
288
        }

289
290
291
292
293
        /// <summary>
        /// Removes any previously applied transforms from the specified <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> that should have transforms removed.</param>
        void ISvgTransformable.PopTransforms(SvgRenderer renderer)
davescriven's avatar
davescriven committed
294
        {
295
            this.PopTransforms(renderer);
davescriven's avatar
davescriven committed
296
297
298
299
300
301
302
303
304
        }

        /// <summary>
        /// Gets or sets the element transforms.
        /// </summary>
        /// <value>The transforms.</value>
        [SvgAttribute("transform")]
        public SvgTransformCollection Transforms
        {
305
            get { return (this.Attributes.GetAttribute<SvgTransformCollection>("transform")); }
Tebjan Halm's avatar
Tebjan Halm committed
306
307
308
309
310
311
            set 
            { 
            	var old = this.Transforms;
            	if(old != null)
            		old.TransformChanged -= Attributes_AttributeChanged;
            	value.TransformChanged += Attributes_AttributeChanged;
312
            	this.Attributes["transform"] = value; 
Tebjan Halm's avatar
Tebjan Halm committed
313
            }
davescriven's avatar
davescriven committed
314
315
316
317
318
319
320
321
322
        }

        /// <summary>
        /// Gets or sets the ID of the element.
        /// </summary>
        /// <exception cref="SvgException">The ID is already used within the <see cref="SvgDocument"/>.</exception>
        [SvgAttribute("id")]
        public string ID
        {
323
            get { return this.Attributes.GetAttribute<string>("id"); }
davescriven's avatar
davescriven committed
324
325
            set
            {
tebjan's avatar
tebjan committed
326
                SetAndForceUniqueID(value, false);
327
328
            }
        }
davescriven's avatar
davescriven committed
329

tebjan's avatar
tebjan committed
330
        public void SetAndForceUniqueID(string value, bool autoForceUniqueID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
331
332
333
334
335
336
        {
            // Don't do anything if it hasn't changed
            if (string.Compare(this.ID, value) == 0)
            {
                return;
            }
davescriven's avatar
davescriven committed
337

338
339
340
341
            if (this.OwnerDocument != null)
            {
                this.OwnerDocument.IdManager.Remove(this);
            }
davescriven's avatar
davescriven committed
342

343
            this.Attributes["id"] = value;
344
345
346

            if (this.OwnerDocument != null)
            {
tebjan's avatar
tebjan committed
347
                this.OwnerDocument.IdManager.AddAndForceUniqueID(this, null, autoForceUniqueID, logElementOldIDNewID);
davescriven's avatar
davescriven committed
348
349
350
            }
        }

351
352
353
354
        /// <summary>
        /// Only used by the ID Manager
        /// </summary>
        /// <param name="newID"></param>
tebjan's avatar
tebjan committed
355
        internal void ForceUniqueID(string newID)
356
        {
357
            this.Attributes["id"] = newID;
358
359
        }

360
361
362
363
364
365
        /// <summary>
        /// Called by the underlying <see cref="SvgElement"/> when an element has been added to the
        /// <see cref="Children"/> collection.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been added.</param>
        /// <param name="index">An <see cref="int"/> representing the index where the element was added to the collection.</param>
366
        protected virtual void AddElement(SvgElement child, int index)
davescriven's avatar
davescriven committed
367
368
        {
        }
tebjan's avatar
tebjan committed
369
370
371
372
373
        
        /// <summary>
        /// Fired when an Element was added to the children of this Element
        /// </summary>
		public event EventHandler<ChildAddedEventArgs> ChildAdded;
davescriven's avatar
davescriven committed
374

375
376
377
378
379
        /// <summary>
        /// Calls the <see cref="AddElement"/> method with the specified parameters.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been added.</param>
        /// <param name="index">An <see cref="int"/> representing the index where the element was added to the collection.</param>
davescriven's avatar
davescriven committed
380
381
        internal void OnElementAdded(SvgElement child, int index)
        {
382
            this.AddElement(child, index);
383
384
385
386
387
            SvgElement sibling = null;
            if(index < (Children.Count - 1))
            {
            	sibling = Children[index + 1];
            }
tebjan's avatar
tebjan committed
388
389
390
            var handler = ChildAdded;
            if(handler != null)
            {
391
            	handler(this, new ChildAddedEventArgs { NewChild = child, BeforeSibling = sibling });
tebjan's avatar
tebjan committed
392
            }
davescriven's avatar
davescriven committed
393
394
        }

395
396
397
398
399
        /// <summary>
        /// Called by the underlying <see cref="SvgElement"/> when an element has been removed from the
        /// <see cref="Children"/> collection.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
400
        protected virtual void RemoveElement(SvgElement child)
davescriven's avatar
davescriven committed
401
402
403
        {
        }

404
405
406
407
        /// <summary>
        /// Calls the <see cref="RemoveElement"/> method with the specified <see cref="SvgElement"/> as the parameter.
        /// </summary>
        /// <param name="child">The <see cref="SvgElement"/> that has been removed.</param>
davescriven's avatar
davescriven committed
408
409
        internal void OnElementRemoved(SvgElement child)
        {
410
            this.RemoveElement(child);
davescriven's avatar
davescriven committed
411
412
413
414
415
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SvgElement"/> class.
        /// </summary>
416
        public SvgElement()
davescriven's avatar
davescriven committed
417
418
419
420
        {
            this._children = new SvgElementCollection(this);
            this._eventHandlers = new EventHandlerList();
            this._elementName = string.Empty;
421
422
            this._customAttributes = new SvgCustomAttributeCollection(this);
            
Tebjan Halm's avatar
Tebjan Halm committed
423
424
            Transforms = new SvgTransformCollection();
            
425
426
427
            //subscribe to attribute events
            Attributes.AttributeChanged += Attributes_AttributeChanged;
            CustomAttributes.AttributeChanged += Attributes_AttributeChanged;
428

429
430
431
432
433
            //find svg attribute descriptions
            _svgPropertyAttributes = from PropertyDescriptor a in TypeDescriptor.GetProperties(this)
                            let attribute = a.Attributes[typeof(SvgAttributeAttribute)] as SvgAttributeAttribute
                            where attribute != null
                            select new PropertyAttributeTuple { Property = a, Attribute = attribute };
Tebjan Halm's avatar
Tebjan Halm committed
434

435
            _svgEventAttributes = from EventDescriptor a in TypeDescriptor.GetEvents(this)
436
437
                            let attribute = a.Attributes[typeof(SvgAttributeAttribute)] as SvgAttributeAttribute
                            where attribute != null
438
                            select new EventAttributeTuple { Event = a.ComponentType.GetField(a.Name, BindingFlags.Instance | BindingFlags.NonPublic), Attribute = attribute };
davescriven's avatar
davescriven committed
439

440
        }
441

442
443
444
445
446
447
        //dispatch attribute event
        void Attributes_AttributeChanged(object sender, AttributeEventArgs e)
        {
        	OnAttributeChanged(e);
        }

448
449
		public virtual void InitialiseFromXML(XmlTextReader reader, SvgDocument document)
		{
450
            throw new NotImplementedException();
451
452
453
		}


454
455
456
457
458
        /// <summary>
        /// Renders this element to the <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> that the element should use to render itself.</param>
        public void RenderElement(SvgRenderer renderer)
davescriven's avatar
davescriven committed
459
        {
460
            this.Render(renderer);
davescriven's avatar
davescriven committed
461
462
463
464
        }

        public void WriteElement(XmlTextWriter writer)
        {
Tebjan Halm's avatar
Tebjan Halm committed
465
466
467
468
            //Save previous culture and switch to invariant for writing
            var previousCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

davescriven's avatar
davescriven committed
469
            this.Write(writer);
Tebjan Halm's avatar
Tebjan Halm committed
470
471
472

            //Switch culture back
            Thread.CurrentThread.CurrentCulture = previousCulture;
davescriven's avatar
davescriven committed
473
474
475
476
477
478
479
        }

        protected virtual void WriteStartElement(XmlTextWriter writer)
        {
            if (this.ElementName != String.Empty)
            {
                writer.WriteStartElement(this.ElementName);
Tebjan Halm's avatar
Tebjan Halm committed
480
481
                if (this.ElementName == "svg")
                {
482
483
484
485
486
487
488
489
490
					foreach (var ns in SvgAttributeAttribute.Namespaces)
					{
						if (string.IsNullOrEmpty(ns.Key))
							writer.WriteAttributeString("xmlns", ns.Value);
						else
							writer.WriteAttributeString("xmlns:" + ns.Key, ns.Value);
					}
					writer.WriteAttributeString("version", "1.1");
				}
davescriven's avatar
davescriven committed
491
492
493
494
495
496
497
498
499
500
501
502
503
504
            }
            this.WriteAttributes(writer);
        }

        protected virtual void WriteEndElement(XmlTextWriter writer)
        {
            if (this.ElementName != String.Empty)
            {
                writer.WriteEndElement();
            }
        }

        protected virtual void WriteAttributes(XmlTextWriter writer)
        {
505
506
            //properties
            foreach (var attr in _svgPropertyAttributes)
507
508
509
510
511
            {
                if (attr.Property.Converter.CanConvertTo(typeof(string)))
                {
                    object propertyValue = attr.Property.GetValue(this);

512
513
514
                    var forceWrite = false;
                    if ((attr.Attribute.Name == "fill") && (Parent != null))
                    {
515
                    	if(propertyValue == SvgColourServer.NotSet) continue;
516
                    	
517
518
                        object parentValue;
                        if (TryResolveParentAttributeValue(attr.Attribute.Name, out parentValue))
519
                        {
520
521
                            if ((parentValue == propertyValue) 
                                || ((parentValue != null) &&  parentValue.Equals(propertyValue)))
522
                                continue;
523
                            
524
525
526
527
                            forceWrite = true;
                        }
                    }

528
529
                    if (propertyValue != null)
                    {
Tebjan Halm's avatar
Tebjan Halm committed
530
                        var type = propertyValue.GetType();
531
                        string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
Tebjan Halm's avatar
Tebjan Halm committed
532

533
                        if (!SvgDefaults.IsDefault(attr.Attribute.Name, value) || forceWrite)
Tebjan Halm's avatar
Tebjan Halm committed
534
                        {
535
                            writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
Tebjan Halm's avatar
Tebjan Halm committed
536
537
538
539
                        }
                    }
                    else if(attr.Attribute.Name == "fill") //if fill equals null, write 'none'
                    {
540
541
                        string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
                        writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
542
543
544
                    }
                }
            }
545

Tebjan Halm's avatar
Tebjan Halm committed
546
            
547
            //events
Tebjan Halm's avatar
Tebjan Halm committed
548
            if(AutoPublishEvents)
549
            {
550
551
552
	            foreach (var attr in _svgEventAttributes)
	            {
	                var evt = attr.Event.GetValue(this);
Eric Domke's avatar
Eric Domke committed
553

554
	                //if someone has registered publish the attribute
Tebjan Halm's avatar
Tebjan Halm committed
555
	                if (evt != null && !string.IsNullOrEmpty(this.ID))
556
557
558
559
	                {
	                    writer.WriteAttributeString(attr.Attribute.Name, this.ID + "/" + attr.Attribute.Name);
	                }
	            }
560
561
            }

562
563
564
565
566
            //add the custom attributes
            foreach (var item in this._customAttributes)
            {
                writer.WriteAttributeString(item.Key, item.Value);
            }
567
        }
Tebjan Halm's avatar
Tebjan Halm committed
568
569
        
        public bool AutoPublishEvents = true;
570

571
        private bool TryResolveParentAttributeValue(string attributeKey, out object parentAttributeValue)
572
        {
573
            parentAttributeValue = null;
574

tebjan's avatar
tebjan committed
575
            //attributeKey = char.ToUpper(attributeKey[0]) + attributeKey.Substring(1);
576
577

            var currentParent = Parent;
578
            var resolved = false;
579
580
581
582
            while (currentParent != null)
            {
                if (currentParent.Attributes.ContainsKey(attributeKey))
                {
583
584
585
                    resolved = true;
                    parentAttributeValue = currentParent.Attributes[attributeKey];
                    if (parentAttributeValue != null)
586
587
588
589
                        break;
                }
                currentParent = currentParent.Parent;
            }
590

591
            return resolved;
davescriven's avatar
davescriven committed
592
593
594
595
596
597
598
599
600
601
602
603
604
605
        }

        protected virtual void Write(XmlTextWriter writer)
        {
            if (this.ElementName != String.Empty)
            {
                this.WriteStartElement(writer);
                this.WriteChildren(writer);
                this.WriteEndElement(writer);
            }
        }

        protected virtual void WriteChildren(XmlTextWriter writer)
        {
Tebjan Halm's avatar
Tebjan Halm committed
606
607
608
609
610
            //write the content
            if(!String.IsNullOrEmpty(this.Content))
                writer.WriteString(this.Content);

            //write all children
davescriven's avatar
davescriven committed
611
612
613
614
615
616
617
            foreach (SvgElement child in this.Children)
            {
                child.Write(writer);
            }
        }

        /// <summary>
618
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
davescriven's avatar
davescriven committed
619
        /// </summary>
620
621
        /// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
        protected virtual void Render(SvgRenderer renderer)
davescriven's avatar
davescriven committed
622
        {
623
624
625
            this.PushTransforms(renderer);
            this.RenderChildren(renderer);
            this.PopTransforms(renderer);
davescriven's avatar
davescriven committed
626
627
        }

628
629
630
631
632
        /// <summary>
        /// Renders the children of this <see cref="SvgElement"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> to render the child <see cref="SvgElement"/>s to.</param>
        protected virtual void RenderChildren(SvgRenderer renderer)
davescriven's avatar
davescriven committed
633
634
635
        {
            foreach (SvgElement element in this.Children)
            {
636
                element.Render(renderer);
davescriven's avatar
davescriven committed
637
638
639
            }
        }

640
641
642
643
644
        /// <summary>
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
        void ISvgElement.Render(SvgRenderer renderer)
davescriven's avatar
davescriven committed
645
        {
646
            this.Render(renderer);
davescriven's avatar
davescriven committed
647
        }
Tebjan Halm's avatar
Tebjan Halm committed
648
649
650
651
652
653
654
655
        
        /// <summary>
        /// Recursive method to add up the paths of all children
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="path"></param>
        protected void AddPaths(SvgElement elem, GraphicsPath path)
        {
Tebjan Halm's avatar
Tebjan Halm committed
656
        	foreach(var child in elem.Children)
Tebjan Halm's avatar
Tebjan Halm committed
657
        	{
Tebjan Halm's avatar
Tebjan Halm committed
658
        		if (child is SvgVisualElement)
Tebjan Halm's avatar
Tebjan Halm committed
659
        		{
Tebjan Halm's avatar
Tebjan Halm committed
660
        			if(!(child is SvgGroup))
661
        			{
Tebjan Halm's avatar
Tebjan Halm committed
662
        				var childPath = ((SvgVisualElement)child).Path;
663
        				
Tebjan Halm's avatar
Tebjan Halm committed
664
665
666
667
668
        				if (childPath != null)
        				{
        					childPath = (GraphicsPath)childPath.Clone();
        					if(child.Transforms != null)
        						childPath.Transform(child.Transforms.GetMatrix());
669
670

                            if (childPath.PointCount > 0) path.AddPath(childPath, false);
Tebjan Halm's avatar
Tebjan Halm committed
671
        				}
672
        			}
Tebjan Halm's avatar
Tebjan Halm committed
673
        		}
Tebjan Halm's avatar
Tebjan Halm committed
674
        			
Tebjan Halm's avatar
Tebjan Halm committed
675
        		AddPaths(child, path);
Tebjan Halm's avatar
Tebjan Halm committed
676
        	}
Tebjan Halm's avatar
Tebjan Halm committed
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
        }
        
        /// <summary>
        /// Recursive method to add up the paths of all children
        /// </summary>
        /// <param name="elem"></param>
        /// <param name="path"></param>
        protected GraphicsPath GetPaths(SvgElement elem)
        {
        	var ret = new GraphicsPath();
        	
        	foreach(var child in elem.Children)
        	{
        		if (child is SvgVisualElement)
        		{
        			if(!(child is SvgGroup))
        			{
        				var childPath = ((SvgVisualElement)child).Path;
        				
        				if (childPath != null)
        				{
        					childPath = (GraphicsPath)childPath.Clone();
        					if(child.Transforms != null)
        						childPath.Transform(child.Transforms.GetMatrix());
        					
        					ret.AddPath(childPath, false);
        				}
        			}
        			else
        			{
        				var childPath = GetPaths(child);
        				if(child.Transforms != null)
        					childPath.Transform(child.Transforms.GetMatrix());
        			}
        		}
        			
        	}
Tebjan Halm's avatar
Tebjan Halm committed
714
        	
Tebjan Halm's avatar
Tebjan Halm committed
715
        	return ret;
Tebjan Halm's avatar
Tebjan Halm committed
716
        }
davescriven's avatar
davescriven committed
717

718
719
720
721
722
723
        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
davescriven's avatar
davescriven committed
724
725
726
727
        public virtual object Clone()
        {
            return this.MemberwiseClone();
        }
728
729
730
731
732
733

    	public abstract SvgElement DeepCopy();

		public virtual SvgElement DeepCopy<T>() where T : SvgElement, new()
		{
			var newObj = new T();
734
			newObj.ID = this.ID;
735
736
			newObj.Content = this.Content;
			newObj.ElementName = this.ElementName;
Eric Domke's avatar
Eric Domke committed
737

738
739
740
741
742
//			if (this.Parent != null)
	//			this.Parent.Children.Add(newObj);

			if (this.Transforms != null)
			{
743
				newObj.Transforms = this.Transforms.Clone() as SvgTransformCollection;
744
745
746
747
748
749
			}

			foreach (var child in this.Children)
			{
				newObj.Children.Add(child.DeepCopy());
			}
Eric Domke's avatar
Eric Domke committed
750

751
752
753
			foreach (var attr in this._svgEventAttributes)
			{
				var evt = attr.Event.GetValue(this);
Eric Domke's avatar
Eric Domke committed
754

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
				//if someone has registered also register here
				if (evt != null)
				{
					if(attr.Event.Name == "MouseDown")
						newObj.MouseDown += delegate {  };
					else if (attr.Event.Name == "MouseUp")
						newObj.MouseUp += delegate {  };
					else if (attr.Event.Name == "MouseOver")
						newObj.MouseOver += delegate {  };
					else if (attr.Event.Name == "MouseOut")
						newObj.MouseOut += delegate {  };
					else if (attr.Event.Name == "MouseMove")
						newObj.MouseMove += delegate {  };
					else if (attr.Event.Name == "MouseScroll")
						newObj.MouseScroll += delegate {  };
Tebjan Halm's avatar
Tebjan Halm committed
770
771
					else if (attr.Event.Name == "Click")
						newObj.Click += delegate {  };
772
773
					else if (attr.Event.Name == "Change") //text element
						(newObj as SvgText).Change += delegate {  };
774
775
				}
			}
Eric Domke's avatar
Eric Domke committed
776

777
778
779
780
781
782
783
			if(this._customAttributes.Count > 0)
			{
				foreach (var element in _customAttributes) 
				{
					newObj.CustomAttributes.Add(element.Key, element.Value);
				}
			}
Eric Domke's avatar
Eric Domke committed
784

785
			return newObj;
Tebjan Halm's avatar
Tebjan Halm committed
786
        }
Eric Domke's avatar
Eric Domke committed
787

788
789
790
791
		/// <summary>
        /// Fired when an Atrribute of this Element has changed
        /// </summary>
		public event EventHandler<AttributeEventArgs> AttributeChanged;
Eric Domke's avatar
Eric Domke committed
792

793
794
795
796
797
798
799
800
		protected void OnAttributeChanged(AttributeEventArgs args)
		{
			var handler = AttributeChanged;
			if(handler != null)
			{
				handler(this, args);
			}
		}
Eric Domke's avatar
Eric Domke committed
801

tebjan's avatar
tebjan committed
802
803
804
805
		/// <summary>
        /// Fired when an Atrribute of this Element has changed
        /// </summary>
		public event EventHandler<ContentEventArgs> ContentChanged;
Eric Domke's avatar
Eric Domke committed
806

tebjan's avatar
tebjan committed
807
808
809
810
811
812
813
814
		protected void OnContentChanged(ContentEventArgs args)
		{
			var handler = ContentChanged;
			if(handler != null)
			{
				handler(this, args);
			}
		}
Tebjan Halm's avatar
Tebjan Halm committed
815
816
817
818

        #region graphical EVENTS

        /*  
819
820
821
            	onfocusin = "<anything>"
            	onfocusout = "<anything>"
            	onactivate = "<anything>"
822
823
824
825
826
                onclick = "<anything>"
                onmousedown = "<anything>"
                onmouseup = "<anything>"
                onmouseover = "<anything>"
                onmousemove = "<anything>"
827
            	onmouseout = "<anything>" 
Tebjan Halm's avatar
Tebjan Halm committed
828
829
         */

Eric Domke's avatar
Eric Domke committed
830
#if Net4
831
832
833
        /// <summary>
        /// Use this method to provide your implementation ISvgEventCaller which can register Actions 
        /// and call them if one of the events occurs. Make sure, that your SvgElement has a unique ID.
834
        /// The SvgTextElement overwrites this and regsiters the Change event tor its text content.
835
836
        /// </summary>
        /// <param name="caller"></param>
837
        public virtual void RegisterEvents(ISvgEventCaller caller)
838
        {
Tebjan Halm's avatar
Tebjan Halm committed
839
            if (caller != null && !string.IsNullOrEmpty(this.ID))
840
841
842
            {
                var rpcID = this.ID + "/";

843
844
845
846
847
848
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onclick", CreateMouseEventAction(RaiseMouseClick));
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onmousedown", CreateMouseEventAction(RaiseMouseDown));
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onmouseup", CreateMouseEventAction(RaiseMouseUp));
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onmousemove", CreateMouseEventAction(RaiseMouseMove));
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onmouseover", CreateMouseEventAction(RaiseMouseOver));
                caller.RegisterAction<float, float, int, int, bool, bool, bool, string>(rpcID + "onmouseout", CreateMouseEventAction(RaiseMouseOut));
849
                caller.RegisterAction<int, bool, bool, bool, string>(rpcID + "onmousescroll", OnMouseScroll);
850
851
            }
        }
852
853
854
855
856
        
        /// <summary>
        /// Use this method to provide your implementation ISvgEventCaller to unregister Actions
        /// </summary>
        /// <param name="caller"></param>
857
        public virtual void UnregisterEvents(ISvgEventCaller caller)
858
        {
Tebjan Halm's avatar
Tebjan Halm committed
859
        	if (caller != null && !string.IsNullOrEmpty(this.ID))
860
861
862
863
864
865
866
        	{
        		var rpcID = this.ID + "/";

        		caller.UnregisterAction(rpcID + "onclick");
        		caller.UnregisterAction(rpcID + "onmousedown");
        		caller.UnregisterAction(rpcID + "onmouseup");
        		caller.UnregisterAction(rpcID + "onmousemove");
joreg's avatar
joreg committed
867
        		caller.UnregisterAction(rpcID + "onmousescroll");
868
869
870
871
        		caller.UnregisterAction(rpcID + "onmouseover");
        		caller.UnregisterAction(rpcID + "onmouseout");
        	}
        }
Eric Domke's avatar
Eric Domke committed
872
#endif
873

Tebjan Halm's avatar
Tebjan Halm committed
874
875
876
        [SvgAttribute("onclick")]
        public event EventHandler<MouseArg> Click;

877
878
879
880
881
        [SvgAttribute("onmousedown")]
        public event EventHandler<MouseArg> MouseDown;

        [SvgAttribute("onmouseup")]
        public event EventHandler<MouseArg> MouseUp;
882
883
        
        [SvgAttribute("onmousemove")]
884
        public event EventHandler<MouseArg> MouseMove;
885

joreg's avatar
joreg committed
886
        [SvgAttribute("onmousescroll")]
887
        public event EventHandler<MouseScrollArg> MouseScroll;
joreg's avatar
joreg committed
888
        
889
        [SvgAttribute("onmouseover")]
890
        public event EventHandler<MouseArg> MouseOver;
891
892

        [SvgAttribute("onmouseout")]
893
        public event EventHandler<MouseArg> MouseOut;
894
        
Eric Domke's avatar
Eric Domke committed
895
#if Net4
896
        protected Action<float, float, int, int, bool, bool, bool, string> CreateMouseEventAction(Action<object, MouseArg> eventRaiser)
Tebjan Halm's avatar
Tebjan Halm committed
897
        {
898
899
        	return (x, y, button, clickCount, altKey, shiftKey, ctrlKey, sessionID) =>
        		eventRaiser(this, new MouseArg { x = x, y = y, Button = button, ClickCount = clickCount, AltKey = altKey, ShiftKey = shiftKey, CtrlKey = ctrlKey, SessionID = sessionID });
900
        }
Eric Domke's avatar
Eric Domke committed
901
902
#endif

903
        //click
904
905
906
907
908
909
        protected void RaiseMouseClick(object sender, MouseArg e)
        {
        	var handler = Click;
        	if (handler != null)
        	{
        		handler(sender, e);
910
911
912
            }
        }

913
        //down
Tebjan Halm's avatar
Tebjan Halm committed
914
915
916
        protected void RaiseMouseDown(object sender, MouseArg e)
        {
        	var handler = MouseDown;
917
918
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
919
                handler(sender, e);
920
921
922
            }
        }

923
924
925
926
        //up
        protected void RaiseMouseUp(object sender, MouseArg e)
        {
        	var handler = MouseUp;
927
928
            if (handler != null)
            {
929
                handler(sender, e);
930
931
            }
        }
932
933

        protected void RaiseMouseMove(object sender, MouseArg e)
934
935
        {
        	var handler = MouseMove;
936
937
            if (handler != null)
            {
938
                handler(sender, e);
939
940
            }
        }
joreg's avatar
joreg committed
941
        
942
943
        //over
        protected void RaiseMouseOver(object sender, MouseArg args)
944
945
        {
        	var handler = MouseOver;
946
947
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
948
                handler(sender, args);
Tebjan Halm's avatar
Tebjan Halm committed
949
950
951
            }
        }

952
        //out
953
        protected void RaiseMouseOut(object sender, MouseArg args)
954
        {
955
        	var handler = MouseOut;
956
957
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
958
                handler(sender, args);
959
960
            }
        }
joreg's avatar
joreg committed
961
        
962
963
        
        //scroll
964
        protected void OnMouseScroll(int scroll, bool ctrlKey, bool shiftKey, bool altKey, string sessionID)
joreg's avatar
joreg committed
965
        {
966
        	RaiseMouseScroll(this, new MouseScrollArg { Scroll = scroll, AltKey = altKey, ShiftKey = shiftKey, CtrlKey = ctrlKey, SessionID = sessionID});
joreg's avatar
joreg committed
967
968
        }
        
969
        protected void RaiseMouseScroll(object sender, MouseScrollArg e)
joreg's avatar
joreg committed
970
        {
971
        	var handler = MouseScroll;
joreg's avatar
joreg committed
972
973
            if (handler != null)
            {
974
                handler(sender, e);
joreg's avatar
joreg committed
975
976
            }
        }
977
        
Tebjan Halm's avatar
Tebjan Halm committed
978
979
        #endregion graphical EVENTS
    }
980
    
Tebjan Halm's avatar
Tebjan Halm committed
981
982
983
984
985
986
    public class SVGArg : EventArgs
    {
    	public string SessionID;
    }
    	
    
987
988
989
    /// <summary>
    /// Describes the Attribute which was set
    /// </summary>
Tebjan Halm's avatar
Tebjan Halm committed
990
    public class AttributeEventArgs : SVGArg
991
992
993
994
    {
    	public string Attribute;
    	public object Value;
    }
tebjan's avatar
tebjan committed
995
    
tebjan's avatar
tebjan committed
996
997
998
999
1000
    /// <summary>
    /// Content of this whas was set
    /// </summary>
    public class ContentEventArgs : SVGArg
    {