aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Editors/ElementEditor.cs
blob: 8dfb9000a8342368e989a40d9f6ae3ebbca82dcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Tango.Scripting.Editors.Intellisense
{
    public class StructCompletionItemPopup : CompletionItemPopupControl
    {
        static StructCompletionItemPopup()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(StructCompletionItemPopup), new FrameworkPropertyMetadata(typeof(StructCompletionItemPopup)));
        }
    }
}
/a> 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 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 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Tango.Core;
using Tango.Editors;

namespace Tango.Editors
{
    /// <summary>
    /// Represents a base class for all element editors.
    /// </summary>
    /// <seealso cref="Tango.Editors.HybridControl" />
    /// <seealso cref="Tango.Editors.IElementEditor" />
    public abstract class ElementEditor : HybridControl, IElementEditor
    {
        private Point _startPoint;
        private Point _centerPoint;
        private Vector _startVector;
        private double _initialAngle;
        private double _anglePI;
        private bool _preventMovingEvent;

        #region Events

        /// <summary>
        /// Occurs when the editor is moving.
        /// </summary>
        public event EventHandler<DragDeltaEventArgs> Moving;

        /// <summary>
        /// Occurs before editor bounds change.
        /// </summary>
        public event EventHandler BeforeBoundsChange;

        /// <summary>
        /// Occurs after editor bounds change.
        /// </summary>
        public event EventHandler AfterBoundsChange;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the editor unique identifier.
        /// </summary>
        [ParameterIgnore]
        public String ID
        {
            get { return (String)GetValue(IDProperty); }
            set { SetValue(IDProperty, value); }
        }
        public static readonly DependencyProperty IDProperty =
            DependencyProperty.Register("ID", typeof(String), typeof(ElementEditor), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets a value indicating whether the hosted element will be presented inside or outside the editor.
        /// </summary>
        [ParameterIgnore]
        public bool ElementDetached
        {
            get { return (bool)GetValue(ElementDetachedProperty); }
            set { SetValue(ElementDetachedProperty, value); }
        }
        public static readonly DependencyProperty ElementDetachedProperty =
            DependencyProperty.Register("ElementDetached", typeof(bool), typeof(ElementEditor), new PropertyMetadata(false, (d, e) => (d as ElementEditor).OnElementDetachedChanged()));

        /// <summary>
        /// Gets or sets the editor top position.
        /// </summary>
        [ParameterItem(null, null)]
        public double Top
        {
            get { return (double)GetValue(TopProperty); }
            set { SetValue(TopProperty, value); }
        }
        public static readonly DependencyProperty TopProperty =
            DependencyProperty.Register("Top", typeof(double), typeof(ElementEditor), new PropertyMetadata(0.0, (d, e) => { (d as ElementEditor).OnPositionChanged(); }, (d, e) => { return (d as ElementEditor).OnCoerceTop(e); }));

        /// <summary>
        /// Gets or sets the editor left position.
        /// </summary>
        [ParameterItem(null, null)]
        public double Left
        {
            get { return (double)GetValue(LeftProperty); }
            set { SetValue(LeftProperty, value); }
        }
        public static readonly DependencyProperty LeftProperty =
            DependencyProperty.Register("Left", typeof(double), typeof(ElementEditor), new PropertyMetadata(0.0, (d, e) => { (d as ElementEditor).OnPositionChanged(); }, (d, e) => { return (d as ElementEditor).OnCoerceLeft(e); }));

        /// <summary>
        /// Gets or sets the editor angle.
        /// </summary>
        [ParameterItem(0.0, 360.0)]
        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(ElementEditor), new PropertyMetadata(0.0));

        /// <summary>
        /// Gets or sets the corners brush.
        /// </summary>
        [ParameterIgnore]
        public Brush CornersBrush
        {
            get { return (Brush)GetValue(CornersBrushProperty); }
            set { SetValue(CornersBrushProperty, value); }
        }
        public static readonly DependencyProperty CornersBrushProperty =
            DependencyProperty.Register("CornersBrush", typeof(Brush), typeof(ElementEditor), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets the editor inner content.
        /// </summary>
        [ParameterIgnore]
        public FrameworkElement InnerContent
        {
            get { return (FrameworkElement)GetValue(InnerContentProperty); }
            set { SetValue(InnerContentProperty, value); }
        }
        public static readonly DependencyProperty InnerContentProperty =
            DependencyProperty.Register("InnerContent", typeof(FrameworkElement), typeof(FrameworkElementEditor), new PropertyMetadata(null));

        /// <summary>
        /// Gets an bind-able observable collection of the component properties.
        /// </summary>
        [ParameterIgnore]
        public ReadOnlyObservableCollection<ParameterItem> Parameters
        {
            get { return (ReadOnlyObservableCollection<ParameterItem>)GetValue(ParametersProperty); }
            set { SetValue(ParametersProperty, value); }
        }
        public static readonly DependencyProperty ParametersProperty =
            DependencyProperty.Register("Parameters", typeof(ReadOnlyObservableCollection<ParameterItem>), typeof(ElementEditor), new PropertyMetadata(null));

        /// <summary>
        /// Gets or sets an optional attached element for editors mirroring mode.
        /// </summary>
        [ParameterIgnore]
        public IElementEditor AttachedEditor
        {
            get { return (IElementEditor)GetValue(AttachedEditorProperty); }
            set { SetValue(AttachedEditorProperty, value); }
        }
        public static readonly DependencyProperty AttachedEditorProperty =
            DependencyProperty.Register("AttachedEditor", typeof(IElementEditor), typeof(ElementEditor), new PropertyMetadata(null,(d,e) => (d as ElementEditor).OnAttachedEditorChanged()));

        /// <summary>
        /// Gets the hosted element.
        /// </summary>
        [ParameterIgnore]
        public abstract Object HostedElement { get; }

        protected int _zIndex;
        /// <summary>
        /// Gets or sets the editor Z-index.
        /// </summary>
        public virtual int ZIndex
        {
            get
            {
                return Canvas.GetZIndex(this as UIElement);
            }
            set
            {
                _zIndex = value;
                Canvas.SetZIndex(this as UIElement, value);
                RaisePropertyChanged(nameof(ZIndex));
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ElementEditor"/> class.
        /// </summary>
        public ElementEditor()
        {
            ID = Guid.NewGuid().ToString();
            Parameters = new ReadOnlyObservableCollection<ParameterItem>(GetEditorParameters());
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Gets the collection of <see cref="T:Tango.Editors.AnimationSetup" /> for the current editor and element properties.
        /// </summary>
        /// <param name="duration">The animation duration.</param>
        /// <param name="animationSetupMode">The animation setup mode.</param>
        /// <returns></returns>
        /// <remarks>
        /// The returned collection of animation setups can be inserted into a <see cref="T:WpfVideoTools.Timeline.TimelineControl" />.
        /// </remarks>
        public virtual List<AnimationSetup> GetAnimationSetups(TimeSpan duration, AnimationSetupMode animationSetupMode = AnimationSetupMode.Linear)
        {
            List<AnimationSetup> setups = new List<AnimationSetup>();

            setups.Add(GetPropertyAnimationSetup(TopProperty, duration, animationSetupMode));
            setups.Add(GetPropertyAnimationSetup(LeftProperty, duration, animationSetupMode));
            setups.Add(GetPropertyAnimationSetup(WidthProperty, duration, animationSetupMode));
            setups.Add(GetPropertyAnimationSetup(HeightProperty, duration, animationSetupMode));
            setups.Add(GetPropertyAnimationSetup(AngleProperty, duration, animationSetupMode));

            return setups;
        }

        /// <summary>
        /// Sets the editor bounds.
        /// </summary>
        /// <param name="bounds">The bounds.</param>
        public virtual void SetBounds(Rect bounds)
        {
            Top = bounds.Top;
            Left = bounds.Left;
            Width = bounds.Width;
            Height = bounds.Height;
        }

        /// <summary>
        /// Gets the editor bounds.
        /// </summary>
        /// <returns></returns>
        public virtual Rect GetBounds()
        {
            return new Rect(Left, Top, Width, Height);
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Determines whether the control key is down.
        /// </summary>
        protected bool IsCtrlDown()
        {
            return Keyboard.IsKeyDown(Key.LeftCtrl);
        }

        #endregion

        #region Virtual Methods

        /// <summary>
        /// Invoked when the attached editor has changed.
        /// </summary>
        protected virtual void OnAttachedEditorChanged()
        {

        }

        /// <summary>
        /// Gets the editor parameters.
        /// </summary>
        /// <returns></returns>
        protected virtual ObservableCollection<ParameterItem> GetEditorParameters()
        {
            var parameters = this.CreateParametersCollection(ParameterItemMode.Binding);
            parameters.Add(this.CreateParameterItem("Width", new ParameterItemAttribute(null, null), parameters.Max(x => x.Index + 1), ParameterItemMode.Binding));
            parameters.Add(this.CreateParameterItem("Height", new ParameterItemAttribute(null, null), parameters.Max(x => x.Index + 1), ParameterItemMode.Binding));
            var angle = parameters.Single(x => x.Name == "Angle");
            parameters.Remove(angle);
            parameters.Add(angle);
            return parameters;
        }

        /// <summary>
        /// Gets the property animation setup.
        /// </summary>
        /// <param name="dependencyProperty">The dependency property.</param>
        /// <param name="duration">The duration.</param>
        /// <param name="animationSetupMode">The animation setup mode.</param>
        /// <returns></returns>
        protected virtual AnimationSetup GetPropertyAnimationSetup(DependencyProperty dependencyProperty, TimeSpan duration, AnimationSetupMode animationSetupMode)
        {
            return GetPropertyAnimationSetup(this, dependencyProperty, duration, animationSetupMode);
        }

        /// <summary>
        /// Gets the property animation setup.
        /// </summary>
        /// <param name="dependencyObject">The dependency object.</param>
        /// <param name="dependencyProperty">The dependency property.</param>
        /// <param name="duration">The duration.</param>
        /// <param name="animationSetupMode">The animation setup mode.</param>
        /// <returns></returns>
        protected virtual AnimationSetup GetPropertyAnimationSetup(DependencyObject dependencyObject, DependencyProperty dependencyProperty, TimeSpan duration, AnimationSetupMode animationSetupMode)
        {
            if (animationSetupMode == AnimationSetupMode.Linear && (dependencyProperty.PropertyType == typeof(double) || dependencyProperty.PropertyType == typeof(Point)))
            {
                if (dependencyProperty.PropertyType == typeof(double))
                {
                    DoubleAnimation ani = new DoubleAnimation((double)dependencyObject.GetValue(dependencyProperty), duration);
                    return new AnimationSetup(ani, dependencyObject, dependencyProperty);
                }
                else
                {
                    PointAnimation ani = new PointAnimation((Point)dependencyObject.GetValue(dependencyProperty), duration);
                    return new AnimationSetup(ani, dependencyObject, dependencyProperty);
                }
            }
            else
            {
                ObjectAnimationUsingKeyFrames ani = new ObjectAnimationUsingKeyFrames();
                ani.KeyFrames.Add(new DiscreteObjectKeyFrame(dependencyObject.GetValue(dependencyProperty), TimeSpan.FromSeconds(0)));
                return new AnimationSetup(ani, dependencyObject, dependencyProperty);
            }
        }

        /// <summary>
        /// Called when the position has changed.
        /// </summary>
        protected virtual void OnPositionChanged()
        {
            Canvas.SetTop(this, Top);
            Canvas.SetLeft(this, Left);
        }

        /// <summary>
        /// Drags the editor.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void MoveDrag(object sender, DragDeltaEventArgs e)
        {
            BeginAnimation(LeftProperty, null);
            BeginAnimation(TopProperty, null);

            Point dragDelta = this.RenderTransform.Transform(new Point(e.HorizontalChange, e.VerticalChange));

            Left += dragDelta.X;
            Top += dragDelta.Y;

            if (!_preventMovingEvent)
            {
                if (Moving != null) Moving(this, e);
            }
        }

        /// <summary>
        /// Called when editor dragging has started.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragStartedEventArgs"/> instance containing the event data.</param>
        protected virtual void DragStarted(object sender, DragStartedEventArgs e)
        {
            _initialAngle = Angle;
            _centerPoint = this.TranslatePoint(new Point(Width * RenderTransformOrigin.X, Height * RenderTransformOrigin.Y), this.Parent as FrameworkElement);
            _startPoint = Mouse.GetPosition(this.Parent as FrameworkElement);
            _startVector = Point.Subtract(_startPoint, _centerPoint);

            _anglePI = Angle * Math.PI / 180.0;

            OnBeforeBoundsChange();
        }

        /// <summary>
        /// Called when the editor dragging has completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragCompletedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnDragEnded(object sender, DragCompletedEventArgs e)
        {
            OnAfterBoundsChange();
        }

        /// <summary>
        /// Drags the editor left side. 
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragLeft(object sender, DragDeltaEventArgs e)
        {
            BeginAnimation(LeftProperty, null);
            BeginAnimation(WidthProperty, null);
            BeginAnimation(TopProperty, null);

            var deltaHorizontal = Math.Min(e.HorizontalChange, ActualWidth - MinWidth);
            if (Width - deltaHorizontal > 0)
            {
                Top = Top + deltaHorizontal * Math.Sin(_anglePI) - RenderTransformOrigin.X * deltaHorizontal * Math.Sin(_anglePI);
                Left = Left + deltaHorizontal * Math.Cos(_anglePI) + (RenderTransformOrigin.X * deltaHorizontal * (1 - Math.Cos(_anglePI)));
                Width -= deltaHorizontal;
            }
        }

        /// <summary>
        /// Drags the editor right side.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragRight(object sender, DragDeltaEventArgs e)
        {
            BeginAnimation(LeftProperty, null);
            BeginAnimation(WidthProperty, null);
            BeginAnimation(TopProperty, null);

            var deltaHorizontal = Math.Min(-e.HorizontalChange, ActualWidth - MinWidth);

            if (Width - deltaHorizontal > 0)
            {
                Top = Top - this.RenderTransformOrigin.X * deltaHorizontal * Math.Sin(_anglePI);
                Left = Left + (deltaHorizontal * this.RenderTransformOrigin.X * (1 - Math.Cos(_anglePI)));
                Width -= deltaHorizontal;
            }
        }

        /// <summary>
        /// Drags the editor top.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragTop(object sender, DragDeltaEventArgs e)
        {
            BeginAnimation(TopProperty, null);
            BeginAnimation(LeftProperty, null);
            BeginAnimation(HeightProperty, null);

            var deltaVertical = Math.Min(e.VerticalChange, ActualHeight - MinHeight);

            if (Height - deltaVertical > 0)
            {
                Top = Top + deltaVertical * Math.Cos(-_anglePI) + (RenderTransformOrigin.Y * deltaVertical * (1 - Math.Cos(-_anglePI)));
                Left = Left + deltaVertical * Math.Sin(-_anglePI) - (RenderTransformOrigin.Y * deltaVertical * Math.Sin(-_anglePI));
                Height -= deltaVertical;
            }
        }

        /// <summary>
        /// Drags the editor bottom.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragBottom(object sender, DragDeltaEventArgs e)
        {
            BeginAnimation(TopProperty, null);
            BeginAnimation(LeftProperty, null);
            BeginAnimation(HeightProperty, null);

            var deltaVertical = Math.Min(-e.VerticalChange, ActualHeight - MinHeight);

            if (Height - deltaVertical > 0)
            {
                Top = Top + (RenderTransformOrigin.Y * deltaVertical * (1 - Math.Cos(-_anglePI)));
                Left = Left - deltaVertical * RenderTransformOrigin.Y * Math.Sin(-_anglePI);
                Height -= deltaVertical;
            }
        }

        /// <summary>
        /// Drags the top left corner.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragTopLeft(object sender, DragDeltaEventArgs e)
        {
            //if (!IsCtrlDown())
            //{
                DragLeft(sender, e);
                DragTop(sender, e);
            //}
            //else
            //{
            //    DragAngle(sender, e);
            //}
        }

        /// <summary>
        /// Drags the top right corner.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragTopRight(object sender, DragDeltaEventArgs e)
        {
            //if (!IsCtrlDown())
            //{
                DragRight(sender, e);
                DragTop(sender, e);
            //}
            //else
            //{
            //    DragAngle(sender, e);
            //}
        }

        /// <summary>
        /// Drags the bottom right corner.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragBottomRight(object sender, DragDeltaEventArgs e)
        {
            //if (!IsCtrlDown())
            //{
                DragRight(sender, e);
                DragBottom(sender, e);
            //}
            //else
            //{
            //    DragAngle(sender, e);
            //}
        }

        /// <summary>
        /// Drags the bottom left corner.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragBottomLeft(object sender, DragDeltaEventArgs e)
        {
            //if (!IsCtrlDown())
            //{
                DragLeft(sender, e);
                DragBottom(sender, e);
            //}
            //else
            //{
            //    DragAngle(sender, e);
            //}
        }

        /// <summary>
        /// Drags the editor angle.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="DragDeltaEventArgs"/> instance containing the event data.</param>
        protected virtual void DragAngle(object sender, DragDeltaEventArgs e)
        {
            Point currentPoint = Mouse.GetPosition(this.Parent as FrameworkElement);
            Vector deltaVector = Point.Subtract(currentPoint, _centerPoint);
            double angle = Vector.AngleBetween(_startVector, deltaVector);
            BeginAnimation(AngleProperty, null);
            Angle = _initialAngle + angle;
        }

        /// <summary>
        /// Raises the <see cref="BeforeBoundsChange"/> event.
        /// </summary>
        protected virtual void OnBeforeBoundsChange()
        {
            if (BeforeBoundsChange != null) BeforeBoundsChange(this, new EventArgs());
        }

        /// <summary>
        /// Raises the <see cref="AfterBoundsChange"/> event.
        /// </summary>
        protected virtual void OnAfterBoundsChange()
        {
            if (AfterBoundsChange != null) AfterBoundsChange(this, new EventArgs());
        }

        /// <summary>
        /// Called before the top property changes.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected virtual object OnCoerceTop(object value)
        {
            return value;
        }

        /// <summary>
        /// Called before the left property changes.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected virtual object OnCoerceLeft(object value)
        {
            return value;
        }

        /// <summary>
        /// Called when the editor detached property has changed.
        /// </summary>
        protected virtual void OnElementDetachedChanged()
        {
            //Do Nothing ?
        }

        #endregion

        #region Override Methods

        /// <summary>
        /// Invoked when an unhandled <see cref="E:System.Windows.Input.Mouse.MouseDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. This event data reports details about the mouse button that was pressed and the handled state.</param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            if (!Keyboard.IsKeyDown(Key.LeftShift))
            {
                e.Handled = true;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Moves the editor by the specified delta arguments.
        /// </summary>
        /// <param name="e">The <see cref="DragDeltaEventArgs" /> instance containing the event data.</param>
        public void PushMove(DragDeltaEventArgs e)
        {
            _preventMovingEvent = true;
            MoveDrag(this, e);
            _preventMovingEvent = false;
        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
        public abstract IElementEditor Clone();


        #endregion

        #region IConfigurable Members

        /// <summary>
        /// Gets a configuration object representing the configurable properties. This configuration can be serialized to a stream or file, and later be loaded and applied to the configurable object.
        /// </summary>
        /// <returns></returns>
        public virtual IConfiguration GetConfiguration()
        {
            ElementEditorConfiguration config = new ElementEditorConfiguration();
            config.ConfigurableType = this.GetType();
            config.ID = ID;
            config.ElementDetached = ElementDetached;
            config.BackgroundBrushString = Background != null ? Background.ConvertToString() : null;
            config.Left = Left;
            config.Top = Top;
            config.Width = Width;
            config.Height = Height;
            config.Angle = Angle;
            return config;
        }

        /// <summary>
        /// Applies the specified configuration with an optional animation if supported by the configurable type.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="animation">The animation.</param>
        public virtual void SetConfiguration(IConfiguration configuration, ConfigurationAnimation animation)
        {
            if (!(configuration is ElementEditorConfiguration))
            {
                throw new InvalidConfigurationException();
            }

            var config = configuration as ElementEditorConfiguration;

            ID = config.ID;
            ElementDetached = config.ElementDetached;

            try
            {
                if (config.BackgroundBrushString != null)
                {
                    Background = config.BackgroundBrushString.ToBrush();
                }
            }
            catch
            { }

            this.StartDoubleAnimation(LeftProperty, animation, config.Left);
            this.StartDoubleAnimation(TopProperty, animation, config.Top);
            this.StartDoubleAnimation(WidthProperty, animation, config.Width);
            this.StartDoubleAnimation(HeightProperty, animation, config.Height);
            this.StartDoubleAnimation(AngleProperty, animation, config.Angle);
        }

        #endregion
    }
}