/// <summary>
        /// Restore deleted objects
        /// </summary>
        public override void Undo(DrawingCanvas drawingCanvas)
        {
            // Insert all objects from cloneList to GraphicsList

            int currentIndex = 0;
            int indexToInsert;

            foreach (PropertiesGraphicsBase o in cloneList)
            {
                indexToInsert = indexes[currentIndex];

                if ( indexToInsert >=0  &&  indexToInsert <= drawingCanvas.GraphicsList.Count )   // "<=" is correct !
                {
                    drawingCanvas.GraphicsList.Insert(indexToInsert, o.CreateGraphics());
                }
                else
                {
                    // Bug: we should not be here.
                    // Add to the end anyway.
                    drawingCanvas.GraphicsList.Add(o.CreateGraphics());

                    System.Diagnostics.Trace.WriteLine("CommandDelete.Undo - incorrect index");
                }

                currentIndex++;
            }

            drawingCanvas.RefreshClip();
        }
        /// <summary>
        /// Delete objects again.
        /// </summary>
        public override void Redo(DrawingCanvas drawingCanvas)
        {
            // Delete from list all objects kept in cloneList.
            // Use object IDs for deleting, don't beleive to objects order.

            int n = drawingCanvas.GraphicsList.Count;

            for (int i = n - 1; i >= 0; i--)
            {
                bool toDelete = false;
                GraphicsBase currentObject = (GraphicsBase)drawingCanvas.GraphicsList[i];

                foreach (PropertiesGraphicsBase o in cloneList)
                {
                    if (o.ID == currentObject.Id)
                    {
                        toDelete = true;
                        break;
                    }
                }

                if (toDelete)
                {
                    drawingCanvas.GraphicsList.RemoveAt(i);
                }
            }
        }
        /// <summary>
        /// Apply new font family
        /// </summary>
        public static bool ApplyFontFamily(DrawingCanvas drawingCanvas, string value, bool addToHistory)
        {
            CommandChangeState command = new CommandChangeState(drawingCanvas);
            bool wasChange = false;

            foreach (GraphicsBase g in drawingCanvas.Selection)
            {
                GraphicsText gt = g as GraphicsText;

                if (gt != null)
                {
                    if (gt.TextFontFamilyName != value)
                    {
                        gt.TextFontFamilyName = value;
                        wasChange = true;
                    }
                }
            }

            if (wasChange  && addToHistory )
            {
                command.NewState(drawingCanvas);
                drawingCanvas.AddCommandToHistory(command);
            }

            return wasChange;
        }
        /// <summary>
        /// Add all deleted objects to GraphicsList
        /// </summary>
        public override void Undo(DrawingCanvas drawingCanvas)
        {
            foreach (PropertiesGraphicsBase o in cloneList)
            {
                drawingCanvas.GraphicsList.Add(o.CreateGraphics());
            }

            drawingCanvas.RefreshClip();
        }
        /// <summary>
        /// Set cursor and resize new object.
        /// </summary>
        public override void OnMouseMove(DrawingCanvas drawingCanvas, MouseEventArgs e)
        {
            drawingCanvas.Cursor = ToolCursor;

            if (e.LeftButton == MouseButtonState.Pressed)
            {
                drawingCanvas[drawingCanvas.Count - 1].MoveHandleTo(
                    e.GetPosition(drawingCanvas), 2);
            }
        }
 /// <summary>
 /// Add change to history.
 /// Called after finishing moving/resizing.
 /// </summary>
 public void AddChangeToHistory(DrawingCanvas drawingCanvas)
 {
     if (commandChangeState != null && wasMove)
     {
         // Keep state after moving/resizing and add command to history
         commandChangeState.NewState(drawingCanvas);
         drawingCanvas.AddCommandToHistory(commandChangeState);
         commandChangeState = null;
     }
 }
        // Create this command BEFORE applying Delete All function.
        public CommandDeleteAll(DrawingCanvas drawingCanvas)
        {
            cloneList = new List<PropertiesGraphicsBase>();

            // Make clone of the whole list.
            foreach(GraphicsBase g in drawingCanvas.GraphicsList)
            {
                cloneList.Add(g.CreateSerializedObject());
            }
        }
        /// <summary>
        /// Add new object to drawing canvas.
        /// Function is called when user left-clicks drawing canvas,
        /// and one of ToolObject-derived tools is active.
        /// </summary>
        protected static void AddNewObject(DrawingCanvas drawingCanvas, GraphicsBase o)
        {
            HelperFunctions.UnselectAll(drawingCanvas);

            o.IsSelected = true;
            o.Clip = new RectangleGeometry(new Rect(0, 0, drawingCanvas.ActualWidth, drawingCanvas.ActualHeight));

            drawingCanvas.GraphicsList.Add(o);
            drawingCanvas.CaptureMouse();
        }
        /// <summary>
        /// Add object again
        /// </summary>
        public override void Redo(DrawingCanvas drawingCanvas)
        {
            HelperFunctions.UnselectAll(drawingCanvas);

            // Create full object from the clone and add it to list
            drawingCanvas.GraphicsList.Add(newObjectClone.CreateGraphics());

            // Object created from the clone doesn't contain clip information,
            // refresh it.
            drawingCanvas.RefreshClip();
        }
        /// <summary>
        /// Create new object
        /// </summary>
        public override void OnMouseDown(DrawingCanvas drawingCanvas, MouseButtonEventArgs e)
        {
            Point p = e.GetPosition(drawingCanvas);

            AddNewObject(drawingCanvas,
                new GraphicsLine(
                p,
                new Point(p.X + 1, p.Y + 1),
                drawingCanvas.LineWidth,
                drawingCanvas.ObjectColor,
                drawingCanvas.ActualScale));
        }
        /// <summary>
        /// Left mouse is released.
        /// New object is created and resized.
        /// </summary>
        public override void OnMouseUp(DrawingCanvas drawingCanvas, MouseButtonEventArgs e)
        {
            if (drawingCanvas.Count > 0)
            {
                drawingCanvas[drawingCanvas.Count - 1].Normalize();

                drawingCanvas.AddCommandToHistory(new CommandAdd(drawingCanvas[drawingCanvas.Count - 1]));
            }

            drawingCanvas.Tool = ToolType.Pointer;
            drawingCanvas.Cursor = HelperFunctions.DefaultCursor;
            drawingCanvas.ReleaseMouseCapture();
        }
        List<int> indexes; // contains indexes of deleted items

        #endregion Fields

        #region Constructors

        // Create this command BEFORE applying Delete function.
        public CommandDelete(DrawingCanvas drawingCanvas)
        {
            cloneList = new List<PropertiesGraphicsBase>();
            indexes = new List<int>();

            // Make clone of the list selection.

            int currentIndex = 0;

            foreach (GraphicsBase g in drawingCanvas.Selection)
            {
                cloneList.Add(g.CreateSerializedObject());
                indexes.Add(currentIndex);

                currentIndex++;
            }
        }
        /// <summary>
        /// Create new object
        /// </summary>
        public override void OnMouseDown(DrawingCanvas drawingCanvas, MouseButtonEventArgs e)
        {
            Point p = e.GetPosition(drawingCanvas);

            newPolyLine = new GraphicsPolyLine(
                new Point[]
                {
                    p,
                    new Point(p.X + 1, p.Y + 1)
                },
                drawingCanvas.LineWidth,
                drawingCanvas.ObjectColor,
                drawingCanvas.ActualScale);

            AddNewObject(drawingCanvas, newPolyLine);

            lastX = p.X;
            lastY = p.Y;
        }
        /// <summary>
        /// Create textbox for in-place editing
        /// </summary>
        public void CreateTextBox(GraphicsText graphicsText, DrawingCanvas drawingCanvas)
        {
            graphicsText.IsSelected = false;  // selection marks don't look good with textbox

            // Keep old text in the case Esc is pressed while editing
            oldText = graphicsText.Text;

            // Keep reference to edited object
            editedGraphicsText = graphicsText;

            textBox = new TextBox();

            textBox.Width = graphicsText.Rectangle.Width;
            textBox.Height = graphicsText.Rectangle.Height;
            textBox.FontFamily = new FontFamily(graphicsText.TextFontFamilyName);
            textBox.FontSize = graphicsText.TextFontSize;
            textBox.FontStretch = graphicsText.TextFontStretch;
            textBox.FontStyle = graphicsText.TextFontStyle;
            textBox.FontWeight = graphicsText.TextFontWeight;
            textBox.Text = graphicsText.Text;

            textBox.AcceptsReturn = true;
            textBox.TextWrapping = TextWrapping.Wrap;

            drawingCanvas.Children.Add(textBox);

            Canvas.SetLeft(textBox, graphicsText.Rectangle.Left);
            Canvas.SetTop(textBox, graphicsText.Rectangle.Top);
            textBox.Width = textBox.Width;
            textBox.Height = textBox.Height;

            textBox.Focus();

            textBox.LostFocus += new RoutedEventHandler(textBox_LostFocus);
            textBox.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(textBox_LostKeyboardFocus);
            textBox.PreviewKeyDown += new KeyEventHandler(textBox_PreviewKeyDown);
            textBox.ContextMenu = null;     // see notes in textBox_LostKeyboardFocus

            // Initially textbox is set to the same rectangle as graphicsText.
            // After textbox loading its template is available, and we can
            // correct textbox position - see details in the textBox_Loaded function.
            textBox.Loaded += new RoutedEventHandler(textBox_Loaded);
        }
        /// <summary>
        /// Set cursor and resize new polyline
        /// </summary>
        public override void OnMouseMove(DrawingCanvas drawingCanvas, MouseEventArgs e)
        {
            drawingCanvas.Cursor = ToolCursor;

            if (e.LeftButton != MouseButtonState.Pressed)
            {
                return;
            }

            if ( ! drawingCanvas.IsMouseCaptured )
            {
                return;
            }

            if ( newPolyLine == null )
            {
                return;         // precaution
            }

            Point p = e.GetPosition(drawingCanvas);

            double distance = (p.X - lastX) * (p.X - lastX) + (p.Y - lastY) * (p.Y - lastY);

            double d = drawingCanvas.ActualScale <= 0 ?
                minDistance * minDistance :
                minDistance * minDistance / drawingCanvas.ActualScale;

            if ( distance < d)
            {
                // Distance between last two points is less than minimum -
                // move last point
                newPolyLine.MoveHandleTo(p, newPolyLine.HandleCount);
            }
            else
            {
                // Add new segment
                newPolyLine.AddPoint(p);

                lastX = p.X;
                lastY = p.Y;
            }
        }
        /// <summary>
        /// Delete added object
        /// </summary>
        public override void Undo(DrawingCanvas drawingCanvas)
        {
            // Find object to delete by its ID.
            // Don't use objects order in the list.

            GraphicsBase objectToDelete = null;

            // Remove object from the list
            foreach(GraphicsBase b in drawingCanvas.GraphicsList)
            {
                if ( b.Id == newObjectClone.ID )
                {
                    objectToDelete = b;
                    break;
                }
            }

            if ( objectToDelete != null )
            {
                drawingCanvas.GraphicsList.Remove(objectToDelete);
            }
        }
        /// <summary>
        /// Apply new color
        /// </summary>
        public static bool ApplyColor(DrawingCanvas drawingCanvas, Color value, bool addToHistory)
        {
            CommandChangeState command = new CommandChangeState(drawingCanvas);
            bool wasChange = false;

            foreach (GraphicsBase g in drawingCanvas.Selection)
            {
                if (g.ObjectColor != value)
                {
                    g.ObjectColor = value;
                    wasChange = true;
                }
            }

            if ( wasChange && addToHistory )
            {
                command.NewState(drawingCanvas);
                drawingCanvas.AddCommandToHistory(command);
            }

            return wasChange;
        }
 /// <summary>
 /// Detete All again
 /// </summary>
 public override void Redo(DrawingCanvas drawingCanvas)
 {
     drawingCanvas.GraphicsList.Clear();
 }
        /// <summary>
        /// Return true if currently active properties (line width, color etc.)
        /// can be applied to selected items.
        /// 
        /// If at least one selected object has property different from currently
        /// active property value, properties can be applied.
        /// </summary>
        public static bool CanApplyProperties(DrawingCanvas drawingCanvas)
        {
            foreach(GraphicsBase graphicsBase in drawingCanvas.GraphicsList)
            {
                if ( ! graphicsBase.IsSelected )
                {
                    continue;
                }

                // ObjectColor - used in all graphics objects
                if ( graphicsBase.ObjectColor != drawingCanvas.ObjectColor )
                {
                    return true;
                }

                GraphicsText graphicsText = graphicsBase as GraphicsText;

                if ( graphicsText == null )
                {
                    // LineWidth - used in all objects except of GraphicsText
                    if ( graphicsBase.LineWidth != drawingCanvas.LineWidth )
                    {
                        return true;
                    }
                }
                else
                {
                    // Font - for GraphicsText

                    if ( graphicsText.TextFontFamilyName != drawingCanvas.TextFontFamilyName )
                    {
                        return true;
                    }

                    if ( graphicsText.TextFontSize != drawingCanvas.TextFontSize )
                    {
                        return true;
                    }

                    if ( graphicsText.TextFontStretch != drawingCanvas.TextFontStretch )
                    {
                        return true;
                    }

                    if ( graphicsText.TextFontStyle != drawingCanvas.TextFontStyle )
                    {
                        return true;
                    }

                    if ( graphicsText.TextFontWeight != drawingCanvas.TextFontWeight )
                    {
                        return true;
                    }
                }
            }

            return false;
        }
 /// <summary>
 /// Unselect all graphic objects
 /// </summary>
 public static void UnselectAll(DrawingCanvas drawingCanvas)
 {
     for (int i = 0; i < drawingCanvas.Count; i++)
     {
         drawingCanvas[i].IsSelected = false;
     }
 }
 public abstract void OnMouseUp(DrawingCanvas drawingCanvas, MouseButtonEventArgs e);
 public abstract void OnMouseMove(DrawingCanvas drawingCanvas, MouseEventArgs e);
 public ToolText(DrawingCanvas drawingCanvas)
 {
     this.drawingCanvas = drawingCanvas;
     MemoryStream stream = new MemoryStream(DrawControl.Properties.Resources.Text);
     ToolCursor = new Cursor(stream);
 }
        /// <summary>
        /// Left mouse is released.
        /// New object is created and resized.
        /// </summary>
        public override void OnMouseUp(DrawingCanvas drawingCanvas, MouseButtonEventArgs e)
        {
            drawingCanvas.Tool = ToolType.Pointer;
            drawingCanvas.Cursor = HelperFunctions.DefaultCursor;
            drawingCanvas.ReleaseMouseCapture();

            if (drawingCanvas.Count > 0)
            {
                drawingCanvas[drawingCanvas.Count - 1].Normalize();

                GraphicsText t = drawingCanvas[drawingCanvas.Count - 1] as GraphicsText;

                if ( t != null )
                {
                    // Create textbox for editing of graphics object which is just created
                    CreateTextBox(t, drawingCanvas);
                }
            }

            // Commnnd will be added to History later, after closing
            // in-place textbox.
        }
        /// <summary>
        /// Delete all graphic objects
        /// </summary>
        public static void DeleteAll(DrawingCanvas drawingCanvas)
        {
            if (drawingCanvas.GraphicsList.Count > 0 )
            {
                drawingCanvas.AddCommandToHistory(new CommandDeleteAll(drawingCanvas));

                drawingCanvas.GraphicsList.Clear();
            }
        }
        /// <summary>
        /// Delete selected graphic objects
        /// </summary>
        public static void DeleteSelection(DrawingCanvas drawingCanvas)
        {
            CommandDelete command = new CommandDelete(drawingCanvas);
            bool wasChange = false;

            for (int i = drawingCanvas.Count - 1; i >= 0; i--)
            {
                if ( drawingCanvas[i].IsSelected )
                {
                    drawingCanvas.GraphicsList.RemoveAt(i);
                    wasChange = true;
                }
            }

            if ( wasChange )
            {
                drawingCanvas.AddCommandToHistory(command);
            }
        }
 /// <summary>
 /// Set cursor
 /// </summary>
 public override void SetCursor(DrawingCanvas drawingCanvas)
 {
     drawingCanvas.Cursor = this.toolCursor;
 }
 public abstract void SetCursor(DrawingCanvas drawingCanvas);
        /// <summary>
        /// Create new text object
        /// </summary>
        public override void OnMouseDown(DrawingCanvas drawingCanvas, MouseButtonEventArgs e)
        {
            Point p = e.GetPosition(drawingCanvas);

            AddNewObject(drawingCanvas,
                new GraphicsText(
                String.Empty,
                p.X,
                p.Y,
                p.X + 1,
                p.Y + 1,
                drawingCanvas.ObjectColor,
                drawingCanvas.TextFontSize,
                drawingCanvas.TextFontFamilyName,
                drawingCanvas.TextFontStyle,
                drawingCanvas.TextFontWeight,
                drawingCanvas.TextFontStretch,
                drawingCanvas.ActualScale));
        }
        /// <summary>
        /// Move selection to front
        /// </summary>
        public static void MoveSelectionToFront(DrawingCanvas drawingCanvas)
        {
            // Moving to front of z-order means moving
            // to the end of VisualCollection.

            // Read GraphicsList in the reverse order, and move every selected object
            // to temporary list.

            List<GraphicsBase> list = new List<GraphicsBase>();

            CommandChangeOrder command = new CommandChangeOrder(drawingCanvas);

            for(int i = drawingCanvas.Count - 1; i >= 0; i--)
            {
                if ( drawingCanvas[i].IsSelected )
                {
                    list.Insert(0, drawingCanvas[i]);
                    drawingCanvas.GraphicsList.RemoveAt(i);
                }
            }

            // Add all items from temporary list to the end of GraphicsList
            foreach(GraphicsBase g in list)
            {
                drawingCanvas.GraphicsList.Add(g);
            }

            if ( list.Count > 0 )
            {
                command.NewState(drawingCanvas);
                drawingCanvas.AddCommandToHistory(command);
            }
        }