protected override void OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);

            m_movingMouse = false;
            if (m_resizing != ComponentResizeMode.None)
            {
                m_resizingComponent.ResetConnections();
                m_resizingComponent.ApplyConnections(Document);
                DrawConnections();

                UndoAction undoAction = new UndoAction(UndoCommand.ModifyComponents, "Move component", new Component[] { m_resizingComponent });
                undoAction.AddData("before", m_undoManagerBeforeData);
                Dictionary<Component, string> afterDictionary = new Dictionary<Component, string>(1);
                afterDictionary.Add(m_resizingComponent, m_resizingComponent.SerializeToString());
                undoAction.AddData("after", afterDictionary);
                UndoManager.AddAction(undoAction);
                m_undoManagerBeforeData = new Dictionary<Component, string>();
            }
            m_resizing = ComponentResizeMode.None;
            this.Cursor = System.Windows.Input.Cursors.Arrow;
            m_resizingComponent = null;

            if (m_placingComponent)
            {
                Component newComponent = Component.Create(NewComponentData);
                ComponentHelper.SizeComponent(newComponent, m_mouseDownPos, e.GetPosition(this));

                // Flip if necessary
                if (newComponent.Orientation == Orientation.Horizontal && newComponent.Description.CanFlip)
                {
                    if (m_mouseDownPos.X > e.GetPosition(this).X)
                        newComponent.IsFlipped = true;
                    else
                        newComponent.IsFlipped = false;
                }
                else if (newComponent.Description.CanFlip)
                {
                    if (m_mouseDownPos.Y > e.GetPosition(this).Y)
                        newComponent.IsFlipped = true;
                    else
                        newComponent.IsFlipped = false;
                }

                Document.Elements.Add(newComponent);
                newComponent.ApplyConnections(Document);
                DrawConnections();
                m_placingComponent = false;

                UndoAction undoAction = new UndoAction(UndoCommand.AddComponents, "Add component", new Component[] { newComponent });
                UndoManager.AddAction(undoAction);

                RemoveVisualChild(m_elementVisuals[m_tempComponent]);
                RemoveLogicalChild(m_elementVisuals[m_tempComponent]);
                m_elementVisuals.Remove(m_tempComponent);
                m_tempComponent = null;
            }
            else if (m_selectedComponents.Count > 0)
            {
                Dictionary<Component, string> afterData = new Dictionary<Component, string>();

                foreach (Component component in m_selectedComponents)
                {
                    string afterDataString = component.SerializeToString();
                    if (afterDataString == m_undoManagerBeforeData[component])
                        break;

                    afterData.Add(component, afterDataString);
                }

                if (afterData.Count > 0)
                {
                    UndoAction undoAction = new UndoAction(UndoCommand.ModifyComponents, "move", m_selectedComponents.ToArray());
                    undoAction.AddData("before", m_undoManagerBeforeData);
                    undoAction.AddData("after", afterData);
                    UndoManager.AddAction(undoAction);
                    m_undoManagerBeforeData = new Dictionary<Component, string>();
                }
            }
            else if (m_selectionBox)
            {
                using (DrawingContext dc = m_selectedVisual.RenderOpen())
                {
                    enclosingRect = Rect.Empty;

                    VisualTreeHelper.HitTest(this, new HitTestFilterCallback(delegate(DependencyObject testObject)
                    {
                        if (testObject is CircuitElementDrawingVisual)
                            return HitTestFilterBehavior.ContinueSkipChildren;
                        else
                            return HitTestFilterBehavior.ContinueSkipSelf;
                    }),
                    new HitTestResultCallback(delegate(HitTestResult result)
                    {
                        m_selectedComponents.Add((result.VisualHit as CircuitElementDrawingVisual).CircuitElement as Component);

                        if (result.VisualHit is CircuitElementDrawingVisual)
                        {
                            Rect rect = VisualTreeHelper.GetContentBounds(result.VisualHit as Visual);
                            dc.PushTransform(new TranslateTransform((result.VisualHit as CircuitElementDrawingVisual).Offset.X, (result.VisualHit as CircuitElementDrawingVisual).Offset.Y));
                            dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(100, 0, 0, 100)), null, rect);
                            dc.Pop();

                            if (enclosingRect.IsEmpty)
                            {
                                rect.Offset((result.VisualHit as CircuitElementDrawingVisual).Offset.X, (result.VisualHit as CircuitElementDrawingVisual).Offset.Y);
                                enclosingRect = rect;
                            }
                            else
                            {
                                rect.Offset((result.VisualHit as CircuitElementDrawingVisual).Offset.X, (result.VisualHit as CircuitElementDrawingVisual).Offset.Y);
                                enclosingRect.Union(rect);
                            }
                        }

                        return HitTestResultBehavior.Continue;
                    }), new GeometryHitTestParameters(new RectangleGeometry(new Rect(m_mouseDownPos, e.GetPosition(this)))));

                    dc.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Black, 1d), enclosingRect);
                }

                m_selectionBox = false;
            }
        }
        protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
        {
            base.OnMouseLeave(e);

            if (m_resizing != ComponentResizeMode.None)
            {
                m_resizingComponent.ResetConnections();
                m_resizingComponent.ApplyConnections(Document);
                DrawConnections();

                UndoAction undoAction = new UndoAction(UndoCommand.ModifyComponents, "Move component", new Component[] { m_resizingComponent });
                undoAction.AddData("before", m_undoManagerBeforeData);
                Dictionary<Component, string> afterDictionary = new Dictionary<Component, string>(1);
                afterDictionary.Add(m_resizingComponent, m_resizingComponent.SerializeToString());
                undoAction.AddData("after", afterDictionary);
                UndoManager.AddAction(undoAction);
                m_undoManagerBeforeData = new Dictionary<Component, string>();

                m_resizing = ComponentResizeMode.None;
                this.Cursor = System.Windows.Input.Cursors.Arrow;
            }

            m_selectionBox = false;
            m_placingComponent = false;
        }
        protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            Point mousePos = e.GetPosition(this);
            m_mouseDownPos = mousePos;

            Rect resizingRect1 = Rect.Empty;
            Rect resizingRect2 = Rect.Empty;
            if (m_resizingComponent != null && m_resizingComponent.Orientation == Orientation.Horizontal && m_resizingComponent.Description.CanResize)
            {
                // Resizing a horizontal component
                resizingRect1 = new Rect(m_resizingComponent.Location.X + m_elementVisuals[m_resizingComponent].ContentBounds.X - 2d, m_resizingComponent.Location.Y + m_elementVisuals[m_resizingComponent].ContentBounds.Top + m_elementVisuals[m_resizingComponent].ContentBounds.Height / 2 - 3d, 6d, 6d);
                resizingRect2 = new Rect(m_resizingComponent.Location.X + m_elementVisuals[m_resizingComponent].ContentBounds.Right - 4d, m_resizingComponent.Location.Y + m_elementVisuals[m_resizingComponent].ContentBounds.Top + m_elementVisuals[m_resizingComponent].ContentBounds.Height / 2 - 3d, 6d, 6d);
            }
            else if (m_resizingComponent != null && m_resizingComponent.Description.CanResize)
            {
                // Resizing a vertical component
                resizingRect1 = new Rect(m_resizingComponent.Location.X + m_elementVisuals[m_resizingComponent].ContentBounds.Left + m_elementVisuals[m_resizingComponent].ContentBounds.Width / 2 - 3d, m_resizingComponent.Location.Y + m_elementVisuals[m_resizingComponent].ContentBounds.Y - 2d, 6d, 6d);
                resizingRect2 = new Rect(m_resizingComponent.Location.X + m_elementVisuals[m_resizingComponent].ContentBounds.Left + m_elementVisuals[m_resizingComponent].ContentBounds.Width / 2 - 3d, m_resizingComponent.Location.Y + m_elementVisuals[m_resizingComponent].ContentBounds.Bottom - 4d, 6d, 6d);
            }

            if (NewComponentData == null && (resizingRect1.IntersectsWith(new Rect(mousePos, new Size(1, 1))) || resizingRect2.IntersectsWith(new Rect(mousePos, new Size(1, 1)))))
            {
                // Enter resizing mode

                m_undoManagerBeforeData[m_resizingComponent] = m_resizingComponent.SerializeToString();

                if (resizingRect1.IntersectsWith(new Rect(mousePos, new Size(1, 1))))
                {
                    if (m_resizingComponent.Orientation == Orientation.Horizontal)
                    {
                        m_resizing = ComponentResizeMode.Left;
                        m_resizeComponentOriginalStartEnd = new Point(m_resizingComponent.Location.X + m_resizingComponent.Size, m_resizingComponent.Location.Y);
                    }
                    else
                    {
                        m_resizing = ComponentResizeMode.Top;
                        m_resizeComponentOriginalStartEnd = new Point(m_resizingComponent.Location.X, m_resizingComponent.Location.Y + m_resizingComponent.Size);
                    }
                }
                else
                {
                    if (m_resizingComponent.Orientation == Orientation.Horizontal)
                    {
                        m_resizing = ComponentResizeMode.Right;
                        m_resizeComponentOriginalStartEnd = new Point(m_resizingComponent.Location.X, m_resizingComponent.Location.Y);
                    }
                    else
                    {
                        m_resizing = ComponentResizeMode.Bottom;
                        m_resizeComponentOriginalStartEnd = new Point(m_resizingComponent.Location.X, m_resizingComponent.Location.Y);
                    }
                }
            }
            else if (m_selectedComponents.Count == 0)
            {
                bool foundHit = false;

                if (NewComponentData == null)
                {
                    // Check if user is selecting a component

                    VisualTreeHelper.HitTest(this, new HitTestFilterCallback(delegate(DependencyObject testObject)
                    {
                        if (testObject is CircuitElementDrawingVisual)
                            return HitTestFilterBehavior.ContinueSkipChildren;
                        else
                            return HitTestFilterBehavior.ContinueSkipSelf;
                    }),
                    new HitTestResultCallback(delegate(HitTestResult result)
                    {
                        if (result.VisualHit is CircuitElementDrawingVisual)
                        {
                            m_selectedComponents.Add((result.VisualHit as CircuitElementDrawingVisual).CircuitElement as Component);
                            m_undoManagerBeforeData.Add((result.VisualHit as CircuitElementDrawingVisual).CircuitElement as Component, ((result.VisualHit as CircuitElementDrawingVisual).CircuitElement as Component).SerializeToString());
                            m_originalOffsets.Add((result.VisualHit as CircuitElementDrawingVisual).CircuitElement as Component, (result.VisualHit as CircuitElementDrawingVisual).Offset);
                            ComponentInternalMousePos = new Point(mousePos.X - m_selectedComponents[0].Location.X, mousePos.Y - m_selectedComponents[0].Location.Y);

                            using (DrawingContext dc = m_selectedVisual.RenderOpen())
                            {
                                Pen stroke = new Pen(Brushes.Gray, 1d);
                                Rect rect = VisualTreeHelper.GetContentBounds(result.VisualHit as Visual);
                                dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(100, 0, 0, 100)), stroke, Rect.Inflate(rect, new Size(2, 2)));
                            }
                            m_selectedVisual.Offset = m_selectedComponents[0].Location;
                            m_originalSelectedVisualOffset = m_selectedVisual.Offset;

                            List<Component> removedItems = new List<Component>();
                            List<Component> addedItems = new List<Component>();
                            addedItems.Add(m_selectedComponents[0]);
                            RaiseEvent(new SelectionChangedEventArgs(Selector.SelectionChangedEvent, removedItems, addedItems));
                        }

                        foundHit = true;

                        return HitTestResultBehavior.Stop;
                    }), new PointHitTestParameters(e.GetPosition(this)));
                }

                m_movingMouse = foundHit;

                if (!foundHit)
                {
                    if (NewComponentData != null)
                    {
                        m_placingComponent = true;
                        m_tempComponent = Component.Create(NewComponentData);
                        m_elementVisuals.Add(m_tempComponent, new CircuitElementDrawingVisual(m_tempComponent));
                        AddVisualChild(m_elementVisuals[m_tempComponent]);
                        AddLogicalChild(m_elementVisuals[m_tempComponent]);

                        ComponentHelper.SizeComponent(m_tempComponent, m_mouseDownPos, e.GetPosition(this));
                        m_elementVisuals[m_tempComponent].Offset = m_tempComponent.Location;
                        m_elementVisuals[m_tempComponent].UpdateVisual();
                    }
                    else
                    {
                        // Selection box
                        m_originalOffsets.Clear();
                        m_selectedComponents.Clear();
                        m_selectedVisual.Offset = new Vector();
                        m_selectionBox = true;
                    }
                }
            }
            else if (enclosingRect.IntersectsWith(new Rect(e.GetPosition(this), new Size(1, 1))))
            {
                m_movingMouse = true;
                m_originalOffsets.Clear();
                m_undoManagerBeforeData.Clear();
                foreach (Component component in m_selectedComponents)
                {
                    m_originalOffsets.Add(component, component.Location);
                    m_undoManagerBeforeData.Add(component, component.SerializeToString());
                }

                using (var dc = m_selectedVisual.RenderOpen())
                    dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(100, 0, 0, 100)), new Pen(Brushes.Gray, 1d), new Rect(0, 0, enclosingRect.Width, enclosingRect.Height));

                m_selectedVisual.Offset = new Vector(enclosingRect.X, enclosingRect.Y);
                m_originalSelectedVisualOffset = m_selectedVisual.Offset;
            }
            else
            {
                List<Component> removedItems = new List<Component>(m_selectedComponents);

                m_selectedComponents.Clear();
                m_originalOffsets.Clear();
                m_undoManagerBeforeData.Clear();

                enclosingRect = Rect.Empty;

                using (DrawingContext dc = m_selectedVisual.RenderOpen())
                {
                }

                RaiseEvent(new SelectionChangedEventArgs(Selector.SelectionChangedEvent, removedItems, new List<Component>()));
            }
        }
        void DocumentChanged()
        {
            if (Document == null)
                return;

            m_resizing = ComponentResizeMode.None;
            m_resizingComponent = null;

            this.Width = Document.Size.Width;
            this.Height = Document.Size.Height;

            RenderBackground();

            foreach (CircuitDiagram.Elements.ICircuitElement element in Document.Elements)
            {
                m_elementVisuals.Add(element, new CircuitElementDrawingVisual(element));

                AddVisualChild(m_elementVisuals[element]);
                AddLogicalChild(m_elementVisuals[element]);
                m_elementVisuals[element].UpdateVisual();
                element.Updated += new EventHandler(Component_Updated);
            }
        }