SvgElement.cs 34.7 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
18
19

namespace Svg
{
    /// <summary>
    /// The base class of which all SVG elements are derived from.
    /// </summary>
    public abstract class SvgElement : ISvgElement, ISvgTransformable, ICloneable
    {
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;
davescriven's avatar
davescriven committed
45
46
47
48

        /// <summary>
        /// Gets the name of the element.
        /// </summary>
49
        protected internal string ElementName
davescriven's avatar
davescriven committed
50
        {
51
52
53
54
55
56
57
58
59
60
61
62
63
64
            get
            {
                if (string.IsNullOrEmpty(this._elementName))
                {
                    var attr = TypeDescriptor.GetAttributes(this).OfType<SvgElementAttribute>().SingleOrDefault();

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

                return this._elementName;
            }
65
            internal set { this._elementName = value; }
davescriven's avatar
davescriven committed
66
67
68
69
70
        }

        /// <summary>
        /// Gets or sets the content of the element.
        /// </summary>
Tebjan Halm's avatar
Tebjan Halm committed
71
        private string _content;
davescriven's avatar
davescriven committed
72
73
        public virtual string Content
        {
Tebjan Halm's avatar
Tebjan Halm committed
74
75
76
77
78
79
80
81
82
83
84
            get
            {
            	return _content;
            }
            set
            {
            	if(_content != null)
            	{
            		var oldVal = _content;
            		_content = value;
            		if(_content != oldVal)
tebjan's avatar
tebjan committed
85
            			OnContentChanged(new ContentEventArgs{ Content = value });
Tebjan Halm's avatar
Tebjan Halm committed
86
87
88
89
            	}
            	else
            	{
            		_content = value;
tebjan's avatar
tebjan committed
90
            		OnContentChanged(new ContentEventArgs{ Content = value });
Tebjan Halm's avatar
Tebjan Halm committed
91
92
            	}
            }
davescriven's avatar
davescriven committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
        }

        /// <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; }
        }

120
121
122
123
124
125
126
127
128
        public IEnumerable<SvgElement> Descendants()
        {
            return this.AsEnumerable().Descendants();
        }
        private IEnumerable<SvgElement> AsEnumerable()
        {
            yield return this;
        }

davescriven's avatar
davescriven committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
        /// <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; }
        }

        /// <summary>
        /// Gets the owner <see cref="SvgDocument"/>.
        /// </summary>
        public virtual SvgDocument OwnerDocument
        {
151
152
153
154
155
156
157
158
159
160
161
162
163
164
        	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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
        }

        /// <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;
            }
        }

183
184
185
186
        /// <summary>
        /// Gets a collection of custom attributes
        /// </summary>
        public SvgCustomAttributeCollection CustomAttributes
187
188
189
190
        {
            get { return this._customAttributes; }
        }

191
192
193
194
195
        /// <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
196
        {
197
            _graphicsMatrix = renderer.Transform;
198

davescriven's avatar
davescriven committed
199
200
201
202
203
204
            // Return if there are no transforms
            if (this.Transforms == null || this.Transforms.Count == 0)
            {
                return;
            }

205
            Matrix transformMatrix = renderer.Transform;
davescriven's avatar
davescriven committed
206
207
208

            foreach (SvgTransform transformation in this.Transforms)
            {
209
                transformMatrix.Multiply(transformation.Matrix);
davescriven's avatar
davescriven committed
210
211
            }

212
            renderer.Transform = transformMatrix;
davescriven's avatar
davescriven committed
213
214
        }

215
216
217
218
219
        /// <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
220
        {
221
            renderer.Transform = _graphicsMatrix;
davescriven's avatar
davescriven committed
222
223
224
            _graphicsMatrix = null;
        }

225
226
227
228
229
        /// <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
230
        {
231
            this.PushTransforms(renderer);
davescriven's avatar
davescriven committed
232
233
        }

234
235
236
237
238
        /// <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
239
        {
240
            this.PopTransforms(renderer);
davescriven's avatar
davescriven committed
241
242
243
244
245
246
247
248
249
        }

        /// <summary>
        /// Gets or sets the element transforms.
        /// </summary>
        /// <value>The transforms.</value>
        [SvgAttribute("transform")]
        public SvgTransformCollection Transforms
        {
250
            get { return (this.Attributes.GetAttribute<SvgTransformCollection>("transform")); }
Tebjan Halm's avatar
Tebjan Halm committed
251
252
253
254
255
256
            set 
            { 
            	var old = this.Transforms;
            	if(old != null)
            		old.TransformChanged -= Attributes_AttributeChanged;
            	value.TransformChanged += Attributes_AttributeChanged;
257
            	this.Attributes["transform"] = value; 
Tebjan Halm's avatar
Tebjan Halm committed
258
            }
davescriven's avatar
davescriven committed
259
260
261
262
263
264
265
266
267
        }

        /// <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
        {
268
            get { return this.Attributes.GetAttribute<string>("id"); }
davescriven's avatar
davescriven committed
269
270
            set
            {
tebjan's avatar
tebjan committed
271
                SetAndForceUniqueID(value, false);
272
273
            }
        }
davescriven's avatar
davescriven committed
274

tebjan's avatar
tebjan committed
275
        public void SetAndForceUniqueID(string value, bool autoForceUniqueID = true, Action<SvgElement, string, string> logElementOldIDNewID = null)
276
277
278
279
280
281
        {
            // Don't do anything if it hasn't changed
            if (string.Compare(this.ID, value) == 0)
            {
                return;
            }
davescriven's avatar
davescriven committed
282

283
284
285
286
            if (this.OwnerDocument != null)
            {
                this.OwnerDocument.IdManager.Remove(this);
            }
davescriven's avatar
davescriven committed
287

288
            this.Attributes["id"] = value;
289
290
291

            if (this.OwnerDocument != null)
            {
tebjan's avatar
tebjan committed
292
                this.OwnerDocument.IdManager.AddAndForceUniqueID(this, null, autoForceUniqueID, logElementOldIDNewID);
davescriven's avatar
davescriven committed
293
294
295
            }
        }

296
297
298
299
        /// <summary>
        /// Only used by the ID Manager
        /// </summary>
        /// <param name="newID"></param>
tebjan's avatar
tebjan committed
300
        internal void ForceUniqueID(string newID)
301
        {
302
            this.Attributes["id"] = newID;
303
304
        }

305
306
307
308
309
310
        /// <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>
311
        protected virtual void AddElement(SvgElement child, int index)
davescriven's avatar
davescriven committed
312
313
        {
        }
tebjan's avatar
tebjan committed
314
315
316
317
318
        
        /// <summary>
        /// Fired when an Element was added to the children of this Element
        /// </summary>
		public event EventHandler<ChildAddedEventArgs> ChildAdded;
davescriven's avatar
davescriven committed
319

320
321
322
323
324
        /// <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
325
326
        internal void OnElementAdded(SvgElement child, int index)
        {
327
            this.AddElement(child, index);
328
329
330
331
332
            SvgElement sibling = null;
            if(index < (Children.Count - 1))
            {
            	sibling = Children[index + 1];
            }
tebjan's avatar
tebjan committed
333
334
335
            var handler = ChildAdded;
            if(handler != null)
            {
336
            	handler(this, new ChildAddedEventArgs { NewChild = child, BeforeSibling = sibling });
tebjan's avatar
tebjan committed
337
            }
davescriven's avatar
davescriven committed
338
339
        }

340
341
342
343
344
        /// <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>
345
        protected virtual void RemoveElement(SvgElement child)
davescriven's avatar
davescriven committed
346
347
348
        {
        }

349
350
351
352
        /// <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
353
354
        internal void OnElementRemoved(SvgElement child)
        {
355
            this.RemoveElement(child);
davescriven's avatar
davescriven committed
356
357
358
359
360
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SvgElement"/> class.
        /// </summary>
361
        public SvgElement()
davescriven's avatar
davescriven committed
362
363
364
365
        {
            this._children = new SvgElementCollection(this);
            this._eventHandlers = new EventHandlerList();
            this._elementName = string.Empty;
366
367
            this._customAttributes = new SvgCustomAttributeCollection(this);
            
Tebjan Halm's avatar
Tebjan Halm committed
368
369
            Transforms = new SvgTransformCollection();
            
370
371
372
            //subscribe to attribute events
            Attributes.AttributeChanged += Attributes_AttributeChanged;
            CustomAttributes.AttributeChanged += Attributes_AttributeChanged;
373

374
375
376
377
378
            //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
379

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

385
        }
386

387
388
389
390
391
392
        //dispatch attribute event
        void Attributes_AttributeChanged(object sender, AttributeEventArgs e)
        {
        	OnAttributeChanged(e);
        }

393
394
		public virtual void InitialiseFromXML(XmlTextReader reader, SvgDocument document)
		{
395
            throw new NotImplementedException();
396
397
398
		}


399
400
401
402
403
        /// <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
404
        {
405
            this.Render(renderer);
davescriven's avatar
davescriven committed
406
407
408
409
        }

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

davescriven's avatar
davescriven committed
414
            this.Write(writer);
Tebjan Halm's avatar
Tebjan Halm committed
415
416
417

            //Switch culture back
            Thread.CurrentThread.CurrentCulture = previousCulture;
davescriven's avatar
davescriven committed
418
419
420
421
422
423
424
        }

        protected virtual void WriteStartElement(XmlTextWriter writer)
        {
            if (this.ElementName != String.Empty)
            {
                writer.WriteStartElement(this.ElementName);
Tebjan Halm's avatar
Tebjan Halm committed
425
426
                if (this.ElementName == "svg")
                {
427
428
429
430
431
432
433
434
435
					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
436
437
438
439
440
441
442
443
444
445
446
447
448
449
            }
            this.WriteAttributes(writer);
        }

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

        protected virtual void WriteAttributes(XmlTextWriter writer)
        {
450
451
            //properties
            foreach (var attr in _svgPropertyAttributes)
452
453
454
455
456
            {
                if (attr.Property.Converter.CanConvertTo(typeof(string)))
                {
                    object propertyValue = attr.Property.GetValue(this);

457
458
459
                    var forceWrite = false;
                    if ((attr.Attribute.Name == "fill") && (Parent != null))
                    {
460
                    	if(propertyValue == SvgColourServer.NotSet) continue;
461
                    	
462
463
                        object parentValue;
                        if (TryResolveParentAttributeValue(attr.Attribute.Name, out parentValue))
464
                        {
465
466
                            if ((parentValue == propertyValue) 
                                || ((parentValue != null) &&  parentValue.Equals(propertyValue)))
467
                                continue;
468
                            
469
470
471
472
                            forceWrite = true;
                        }
                    }

473
474
                    if (propertyValue != null)
                    {
Tebjan Halm's avatar
Tebjan Halm committed
475
                        var type = propertyValue.GetType();
476
                        string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
Tebjan Halm's avatar
Tebjan Halm committed
477

478
                        if (!SvgDefaults.IsDefault(attr.Attribute.Name, value) || forceWrite)
Tebjan Halm's avatar
Tebjan Halm committed
479
                        {
480
                            writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
Tebjan Halm's avatar
Tebjan Halm committed
481
482
483
484
                        }
                    }
                    else if(attr.Attribute.Name == "fill") //if fill equals null, write 'none'
                    {
485
486
                        string value = (string)attr.Property.Converter.ConvertTo(propertyValue, typeof(string));
                        writer.WriteAttributeString(attr.Attribute.NamespaceAndName, value);
487
488
489
                    }
                }
            }
490

Tebjan Halm's avatar
Tebjan Halm committed
491
            
492
            //events
Tebjan Halm's avatar
Tebjan Halm committed
493
            if(AutoPublishEvents)
494
            {
495
496
497
498
	            foreach (var attr in _svgEventAttributes)
	            {
	                var evt = attr.Event.GetValue(this);
	                
499
	                //if someone has registered publish the attribute
Tebjan Halm's avatar
Tebjan Halm committed
500
	                if (evt != null && !string.IsNullOrEmpty(this.ID))
501
502
503
504
	                {
	                    writer.WriteAttributeString(attr.Attribute.Name, this.ID + "/" + attr.Attribute.Name);
	                }
	            }
505
506
            }

507
508
509
510
511
            //add the custom attributes
            foreach (var item in this._customAttributes)
            {
                writer.WriteAttributeString(item.Key, item.Value);
            }
512
        }
Tebjan Halm's avatar
Tebjan Halm committed
513
514
        
        public bool AutoPublishEvents = true;
515

516
        private bool TryResolveParentAttributeValue(string attributeKey, out object parentAttributeValue)
517
        {
518
            parentAttributeValue = null;
519

tebjan's avatar
tebjan committed
520
            //attributeKey = char.ToUpper(attributeKey[0]) + attributeKey.Substring(1);
521
522

            var currentParent = Parent;
523
            var resolved = false;
524
525
526
527
            while (currentParent != null)
            {
                if (currentParent.Attributes.ContainsKey(attributeKey))
                {
528
529
530
                    resolved = true;
                    parentAttributeValue = currentParent.Attributes[attributeKey];
                    if (parentAttributeValue != null)
531
532
533
534
                        break;
                }
                currentParent = currentParent.Parent;
            }
535

536
            return resolved;
davescriven's avatar
davescriven committed
537
538
539
540
541
542
543
544
545
546
547
548
549
550
        }

        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
551
552
553
554
555
            //write the content
            if(!String.IsNullOrEmpty(this.Content))
                writer.WriteString(this.Content);

            //write all children
davescriven's avatar
davescriven committed
556
557
558
559
560
561
562
            foreach (SvgElement child in this.Children)
            {
                child.Write(writer);
            }
        }

        /// <summary>
563
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
davescriven's avatar
davescriven committed
564
        /// </summary>
565
566
        /// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
        protected virtual void Render(SvgRenderer renderer)
davescriven's avatar
davescriven committed
567
        {
568
569
570
            this.PushTransforms(renderer);
            this.RenderChildren(renderer);
            this.PopTransforms(renderer);
davescriven's avatar
davescriven committed
571
572
        }

573
574
575
576
577
        /// <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
578
579
580
        {
            foreach (SvgElement element in this.Children)
            {
581
                element.Render(renderer);
davescriven's avatar
davescriven committed
582
583
584
            }
        }

585
586
587
588
589
        /// <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
590
        {
591
            this.Render(renderer);
davescriven's avatar
davescriven committed
592
        }
Tebjan Halm's avatar
Tebjan Halm committed
593
594
595
596
597
598
599
600
        
        /// <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
601
        	foreach(var child in elem.Children)
Tebjan Halm's avatar
Tebjan Halm committed
602
        	{
Tebjan Halm's avatar
Tebjan Halm committed
603
        		if (child is SvgVisualElement)
Tebjan Halm's avatar
Tebjan Halm committed
604
        		{
Tebjan Halm's avatar
Tebjan Halm committed
605
        			if(!(child is SvgGroup))
606
        			{
Tebjan Halm's avatar
Tebjan Halm committed
607
        				var childPath = ((SvgVisualElement)child).Path;
608
        				
Tebjan Halm's avatar
Tebjan Halm committed
609
610
611
612
613
614
615
616
        				if (childPath != null)
        				{
        					childPath = (GraphicsPath)childPath.Clone();
        					if(child.Transforms != null)
        						childPath.Transform(child.Transforms.GetMatrix());
        					
        					path.AddPath(childPath, false);
        				}
617
        			}
Tebjan Halm's avatar
Tebjan Halm committed
618
        		}
Tebjan Halm's avatar
Tebjan Halm committed
619
        			
Tebjan Halm's avatar
Tebjan Halm committed
620
        		AddPaths(child, path);
Tebjan Halm's avatar
Tebjan Halm committed
621
        	}
Tebjan Halm's avatar
Tebjan Halm committed
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
        }
        
        /// <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
659
        	
Tebjan Halm's avatar
Tebjan Halm committed
660
        	return ret;
Tebjan Halm's avatar
Tebjan Halm committed
661
        }
davescriven's avatar
davescriven committed
662

663
664
665
666
667
668
        /// <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
669
670
671
672
        public virtual object Clone()
        {
            return this.MemberwiseClone();
        }
673
674
675
676
677
678

    	public abstract SvgElement DeepCopy();

		public virtual SvgElement DeepCopy<T>() where T : SvgElement, new()
		{
			var newObj = new T();
679
			newObj.ID = this.ID;
680
681
			newObj.Content = this.Content;
			newObj.ElementName = this.ElementName;
682
			
683
684
685
686
687
//			if (this.Parent != null)
	//			this.Parent.Children.Add(newObj);

			if (this.Transforms != null)
			{
688
				newObj.Transforms = this.Transforms.Clone() as SvgTransformCollection;
689
690
691
692
693
694
			}

			foreach (var child in this.Children)
			{
				newObj.Children.Add(child.DeepCopy());
			}
695
			
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
			foreach (var attr in this._svgEventAttributes)
			{
				var evt = attr.Event.GetValue(this);
				
				//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
715
716
					else if (attr.Event.Name == "Click")
						newObj.Click += delegate {  };
717
718
					else if (attr.Event.Name == "Change") //text element
						(newObj as SvgText).Change += delegate {  };
719
720
721
				}
			}
			
722
723
724
725
726
727
728
			if(this._customAttributes.Count > 0)
			{
				foreach (var element in _customAttributes) 
				{
					newObj.CustomAttributes.Add(element.Key, element.Value);
				}
			}
729
730
				
			return newObj;
Tebjan Halm's avatar
Tebjan Halm committed
731
        }
732
733
734
735
736
737
738
739
740
741
742
743
744
745
		
		/// <summary>
        /// Fired when an Atrribute of this Element has changed
        /// </summary>
		public event EventHandler<AttributeEventArgs> AttributeChanged;
		
		protected void OnAttributeChanged(AttributeEventArgs args)
		{
			var handler = AttributeChanged;
			if(handler != null)
			{
				handler(this, args);
			}
		}
tebjan's avatar
tebjan committed
746
747
748
749
750
751
752
753
754
755
756
757
758
759
		
		/// <summary>
        /// Fired when an Atrribute of this Element has changed
        /// </summary>
		public event EventHandler<ContentEventArgs> ContentChanged;
		
		protected void OnContentChanged(ContentEventArgs args)
		{
			var handler = ContentChanged;
			if(handler != null)
			{
				handler(this, args);
			}
		}
Tebjan Halm's avatar
Tebjan Halm committed
760
761
762
763

        #region graphical EVENTS

        /*  
764
765
766
            	onfocusin = "<anything>"
            	onfocusout = "<anything>"
            	onactivate = "<anything>"
767
768
769
770
771
                onclick = "<anything>"
                onmousedown = "<anything>"
                onmouseup = "<anything>"
                onmouseover = "<anything>"
                onmousemove = "<anything>"
772
            	onmouseout = "<anything>" 
Tebjan Halm's avatar
Tebjan Halm committed
773
774
         */

Eric Domke's avatar
Eric Domke committed
775
#if Net4
776
777
778
        /// <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.
779
        /// The SvgTextElement overwrites this and regsiters the Change event tor its text content.
780
781
        /// </summary>
        /// <param name="caller"></param>
782
        public virtual void RegisterEvents(ISvgEventCaller caller)
783
        {
Tebjan Halm's avatar
Tebjan Halm committed
784
            if (caller != null && !string.IsNullOrEmpty(this.ID))
785
786
787
            {
                var rpcID = this.ID + "/";

788
789
790
791
792
793
                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));
794
                caller.RegisterAction<int, bool, bool, bool, string>(rpcID + "onmousescroll", OnMouseScroll);
795
796
            }
        }
797
798
799
800
801
        
        /// <summary>
        /// Use this method to provide your implementation ISvgEventCaller to unregister Actions
        /// </summary>
        /// <param name="caller"></param>
802
        public virtual void UnregisterEvents(ISvgEventCaller caller)
803
        {
Tebjan Halm's avatar
Tebjan Halm committed
804
        	if (caller != null && !string.IsNullOrEmpty(this.ID))
805
806
807
808
809
810
811
        	{
        		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
812
        		caller.UnregisterAction(rpcID + "onmousescroll");
813
814
815
816
        		caller.UnregisterAction(rpcID + "onmouseover");
        		caller.UnregisterAction(rpcID + "onmouseout");
        	}
        }
Eric Domke's avatar
Eric Domke committed
817
#endif
818

Tebjan Halm's avatar
Tebjan Halm committed
819
820
821
        [SvgAttribute("onclick")]
        public event EventHandler<MouseArg> Click;

822
823
824
825
826
        [SvgAttribute("onmousedown")]
        public event EventHandler<MouseArg> MouseDown;

        [SvgAttribute("onmouseup")]
        public event EventHandler<MouseArg> MouseUp;
827
828
        
        [SvgAttribute("onmousemove")]
829
        public event EventHandler<MouseArg> MouseMove;
830

joreg's avatar
joreg committed
831
        [SvgAttribute("onmousescroll")]
832
        public event EventHandler<MouseScrollArg> MouseScroll;
joreg's avatar
joreg committed
833
        
834
        [SvgAttribute("onmouseover")]
835
        public event EventHandler<MouseArg> MouseOver;
836
837

        [SvgAttribute("onmouseout")]
838
        public event EventHandler<MouseArg> MouseOut;
Eric Domke's avatar
Eric Domke committed
839
840

#if Net4
841
        protected Action<float, float, int, int, bool, bool, bool, string> CreateMouseEventAction(Action<object, MouseArg> eventRaiser)
Tebjan Halm's avatar
Tebjan Halm committed
842
        {
843
844
        	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 });
845
        }
Eric Domke's avatar
Eric Domke committed
846
#endif
847
        
848
        //click
849
850
851
852
853
854
        protected void RaiseMouseClick(object sender, MouseArg e)
        {
        	var handler = Click;
        	if (handler != null)
        	{
        		handler(sender, e);
855
856
857
            }
        }

858
        //down
Tebjan Halm's avatar
Tebjan Halm committed
859
860
861
        protected void RaiseMouseDown(object sender, MouseArg e)
        {
        	var handler = MouseDown;
862
863
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
864
                handler(sender, e);
865
866
867
            }
        }

868
869
870
871
        //up
        protected void RaiseMouseUp(object sender, MouseArg e)
        {
        	var handler = MouseUp;
872
873
            if (handler != null)
            {
874
                handler(sender, e);
875
876
            }
        }
877
878

        protected void RaiseMouseMove(object sender, MouseArg e)
879
880
        {
        	var handler = MouseMove;
881
882
            if (handler != null)
            {
883
                handler(sender, e);
884
885
            }
        }
joreg's avatar
joreg committed
886
        
887
888
        //over
        protected void RaiseMouseOver(object sender, MouseArg args)
889
890
        {
        	var handler = MouseOver;
891
892
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
893
                handler(sender, args);
Tebjan Halm's avatar
Tebjan Halm committed
894
895
896
            }
        }

897
        //out
898
        protected void RaiseMouseOut(object sender, MouseArg args)
899
        {
900
        	var handler = MouseOut;
901
902
            if (handler != null)
            {
Tebjan Halm's avatar
Tebjan Halm committed
903
                handler(sender, args);
904
905
            }
        }
joreg's avatar
joreg committed
906
        
907
908
        
        //scroll
909
        protected void OnMouseScroll(int scroll, bool ctrlKey, bool shiftKey, bool altKey, string sessionID)
joreg's avatar
joreg committed
910
        {
911
        	RaiseMouseScroll(this, new MouseScrollArg { Scroll = scroll, AltKey = altKey, ShiftKey = shiftKey, CtrlKey = ctrlKey, SessionID = sessionID});
joreg's avatar
joreg committed
912
913
        }
        
914
        protected void RaiseMouseScroll(object sender, MouseScrollArg e)
joreg's avatar
joreg committed
915
        {
916
        	var handler = MouseScroll;
joreg's avatar
joreg committed
917
918
            if (handler != null)
            {
919
                handler(sender, e);
joreg's avatar
joreg committed
920
921
            }
        }
922
        
Tebjan Halm's avatar
Tebjan Halm committed
923
924
925
        #endregion graphical EVENTS

    }
926
    
Tebjan Halm's avatar
Tebjan Halm committed
927
928
929
930
931
932
    public class SVGArg : EventArgs
    {
    	public string SessionID;
    }
    	
    
933
934
935
    /// <summary>
    /// Describes the Attribute which was set
    /// </summary>
Tebjan Halm's avatar
Tebjan Halm committed
936
    public class AttributeEventArgs : SVGArg
937
938
939
940
    {
    	public string Attribute;
    	public object Value;
    }
tebjan's avatar
tebjan committed
941
    
tebjan's avatar
tebjan committed
942
943
944
945
946
947
948
949
    /// <summary>
    /// Content of this whas was set
    /// </summary>
    public class ContentEventArgs : SVGArg
    {
    	public string Content;
    }
    
tebjan's avatar
tebjan committed
950
951
952
953
954
955
    /// <summary>
    /// Describes the Attribute which was set
    /// </summary>
    public class ChildAddedEventArgs : SVGArg
    {
    	public SvgElement NewChild;
956
    	public SvgElement BeforeSibling;
tebjan's avatar
tebjan committed
957
    }
Tebjan Halm's avatar
Tebjan Halm committed
958

Eric Domke's avatar
Eric Domke committed
959
#if Net4
960
961
962
    //deriving class registers event actions and calls the actions if the event occurs
    public interface ISvgEventCaller
    {
963
        void RegisterAction(string rpcID, Action action);
964
965
966
967
        void RegisterAction<T1>(string rpcID, Action<T1> action);
        void RegisterAction<T1, T2>(string rpcID, Action<T1, T2> action);
        void RegisterAction<T1, T2, T3>(string rpcID, Action<T1, T2, T3> action);
        void RegisterAction<T1, T2, T3, T4>(string rpcID, Action<T1, T2, T3, T4> action);
Tebjan Halm's avatar
Tebjan Halm committed
968
        void RegisterAction<T1, T2, T3, T4, T5>(string rpcID, Action<T1, T2, T3, T4, T5> action);
969
970
971
        void RegisterAction<T1, T2, T3, T4, T5, T6>(string rpcID, Action<T1, T2, T3, T4, T5, T6> action);
        void RegisterAction<T1, T2, T3, T4, T5, T6, T7>(string rpcID, Action<T1, T2, T3, T4, T5, T6, T7> action);
        void RegisterAction<T1, T2, T3, T4, T5, T6, T7, T8>(string rpcID, Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
972
        void UnregisterAction(string rpcID);
973
    }
Eric Domke's avatar
Eric Domke committed
974
#endif
975

Tebjan Halm's avatar
Tebjan Halm committed
976
977
978
    /// <summary>
    /// Represents the state of the mouse at the moment the event occured.
    /// </summary>
Tebjan Halm's avatar
Tebjan Halm committed
979
    public class MouseArg : SVGArg
Tebjan Halm's avatar
Tebjan Halm committed
980
981
982
983
984
    {
        public float x;
        public float y;

        /// <summary>
985
        /// 1 = left, 2 = middle, 3 = right
Tebjan Halm's avatar
Tebjan Halm committed
986
        /// </summary>
987
        public int Button;
988
        
989
990
991
        /// <summary>
        /// Amount of mouse clicks, e.g. 2 for double click
        /// </summary>
992
        public int ClickCount = -1;
993
994
995
996
997
998
999
1000
        
        /// <summary>
        /// Alt modifier key pressed
        /// </summary>
        public bool AltKey;
        
        /// <summary>
        /// Shift modifier key pressed