WinForms: Drag-and-drop an image region from one image viewer to another.

Code samples for VintaSoft Imaging .NET SDK. Here you can request a code sample.

Moderator: Alex

Post Reply
Alex
Site Admin
Posts: 2300
Joined: Thu Jul 10, 2008 2:21 pm

WinForms: Drag-and-drop an image region from one image viewer to another.

Post by Alex »

VintaSoftImaging.NET SDK has the Vintasoft.Imaging.UI.VisualTools.DragDropSelectionTool class that allows to drag-and-drop image region within an image viewer. This class does not allow to drag-and-drop image region between different image viewers.

This topic contains code sample that shows how to create new visual tool that allows to drag-and-drop image region between different image viewers.

Here is source codes of visual tool (AdvancedDragAndDropTool.cs file):

Code: Select all

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

using Vintasoft.Imaging;
using Vintasoft.Imaging.ImageProcessing;
using Vintasoft.Imaging.UI;
using Vintasoft.Imaging.UI.VisualTools;
using Vintasoft.Imaging.UI.VisualTools.UserInteraction;


namespace VintasoftDragDrop
{
    /// <summary>
    /// Visual tool that allows to drag image region and drop it to the same or different image viewer.
    /// </summary>
    public class AdvancedDragAndDropTool : RectangularSelectionTool
    {

        #region Constants

        /// <summary>
        /// The drag and drop effect of current visual tool.
        /// </summary>
        DragDropEffects DRAG_DROP_EFFECT = DragDropEffects.Copy | DragDropEffects.Move;

        #endregion



        #region Fields

        /// <summary>
        /// The cursor location on image.
        /// </summary>
        PointF _dragPointInImageSpace = PointF.Empty;

        /// <summary>
        /// The size of dragging image.
        /// </summary>
        RectangleF _draggingImageSize = RectangleF.Empty;

        /// <summary>
        /// Visual tool where drag-and-drop process is started.
        /// </summary>
        AdvancedDragAndDropTool _sourceTool = null;

        #endregion



        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AdvancedDragAndDropTool"/> class.
        /// </summary>
        public AdvancedDragAndDropTool()
            : base()
        {
            AdvancedDragAndDropToolTransformer advancedDragAndDropToolTransformer = new AdvancedDragAndDropToolTransformer(this);
            advancedDragAndDropToolTransformer.DraggingStarted += new EventHandler(advancedDragAndDropToolTransformer_DraggingStarted);

            TransformController = advancedDragAndDropToolTransformer;
        }

        #endregion



        #region Properties

        /// <summary>
        /// Gets the name of the visual tool.
        /// </summary>
        public override string Name
        {
            get
            {
                return "Image Drag And Drop Tool";
            }
        }

        bool _isDragging = false;
        /// <summary>
        /// Gets a value indicating whether the image is dragging.
        /// </summary>
        public bool IsDragging
        {
            get
            {
                return _isDragging;
            }
        }

        #endregion



        #region Methods

        #region PUBLIC

        /// <summary>
        /// Draws the visual tool on specified System.Drawing.Graphics.
        /// </summary>
        /// <param name="viewer">An image viewer.</param>
        /// <param name="g">A graphics where this tool must be drawn.</param>
        public override void Draw(ImageViewer viewer, Graphics g)
        {
            if (_isDragging)
            {
                if (viewer.Image == null)
                    return;

                // draw image
                Rectangle rectInControl = Rectangle.Round(viewer.RectangleToControl(GetDrawingBoxInImageSpace(viewer, _sourceTool)));
                using (VintasoftImage draggingImage = _sourceTool.GetDraggingImage())
                {
                    if (draggingImage == null)
                        return;
                    draggingImage.Draw(g, rectInControl);
                }


                // draw border
                g.DrawRectangle(Pens.Red, rectInControl);
            }
            else
                base.Draw(viewer, g);
        }

        #endregion


        #region PROTECTED

        /// <summary> 
        /// Raises the <see cref="VisualTool.Activated"/> event.
        /// </summary>
        /// <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>   
        protected override void OnActivated(EventArgs e)
        {
            base.OnActivated(e);

            this.ImageViewer.AllowDrop = true;
            this.ImageViewer.DragEnter += new DragEventHandler(imageViewer_DragEnter);
            this.ImageViewer.DragLeave += new EventHandler(ImageViewer_DragLeave);
            this.ImageViewer.DragOver += new DragEventHandler(imageViewer_DragOver);
            this.ImageViewer.DragDrop += new DragEventHandler(imageViewer_DragDrop);
        }

        /// <summary>
        /// Raises the <see cref="VisualTool.Deactivated"/> event.
        /// </summary>
        /// <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
        protected override void OnDeactivated(EventArgs e)
        {
            base.OnDeactivated(e);

            this.ImageViewer.AllowDrop = false;
            this.ImageViewer.DragEnter -= new DragEventHandler(imageViewer_DragEnter);
            this.ImageViewer.DragLeave -= new EventHandler(ImageViewer_DragLeave);
            this.ImageViewer.DragOver -= new DragEventHandler(imageViewer_DragOver);
            this.ImageViewer.DragDrop -= new DragEventHandler(imageViewer_DragDrop);
        }

        #endregion


        #region PRIVATE

        /// <summary>
        /// Handles the DraggingStarted event of the advancedDragAndDropToolTransformer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void advancedDragAndDropToolTransformer_DraggingStarted(object sender, EventArgs e)
        {
            // get location of drag point
            _dragPointInImageSpace = GetCursorPositionInImageSpace(ImageViewer);
            // get size of dragging image
            _draggingImageSize = GetDrawingBox(ImageViewer);
            _sourceTool = this;

            // start new interaction (dragging and dropping)
            DragDropEffects effects = this.ImageViewer.DoDragDrop(this, DragDropEffects.Move);
        }

        /// <summary>
        /// Handles the DragEnter event of the imageViewer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
        private void imageViewer_DragEnter(object sender, DragEventArgs e)
        {
            if (ImageViewer.Image != null)
            {
                _sourceTool = (AdvancedDragAndDropTool)e.Data.GetData(typeof(AdvancedDragAndDropTool));
                if (_sourceTool != null)
                {
                    _isDragging = true;
                    e.Effect = DRAG_DROP_EFFECT;
                }
            }
        }

        /// <summary>
        /// Handles the DragLeave event of the ImageViewer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void ImageViewer_DragLeave(object sender, EventArgs e)
        {
            _isDragging = false;
            Rectangle = Rectangle.Empty;

            InvalidateViewer();
        }

        /// <summary>
        /// Handles the DragOver event of the imageViewer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
        private void imageViewer_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(AdvancedDragAndDropTool)) &&
                e.Effect == (DRAG_DROP_EFFECT))
                Rectangle = GetDrawingBoxInImageSpace(ImageViewer, _sourceTool);
        }

        /// <summary>
        /// Handles the DragDrop event of the imageViewer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DragEventArgs"/> instance containing the event data.</param>
        private void imageViewer_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(AdvancedDragAndDropTool)) &&
                e.Effect == (DRAG_DROP_EFFECT))
            {
                Rectangle droppingRectInImageSpace = GetDrawingBoxInImageSpace(ImageViewer, _sourceTool);
                if (droppingRectInImageSpace.IsEmpty)
                    return;

                using (VintasoftImage draggingImage = _sourceTool.GetDraggingImage())
                {
                    if (draggingImage == null)
                        return;

                    int offsetX = 0;
                    int offsetY = 0;

                    if (droppingRectInImageSpace.X < 0)
                    {
                        offsetX = -droppingRectInImageSpace.X;
                        droppingRectInImageSpace.X = 0;
                    }

                    if (droppingRectInImageSpace.Y < 0)
                    {
                        offsetY = -droppingRectInImageSpace.Y;
                        droppingRectInImageSpace.Y = 0;
                    }

                    if (offsetX != 0 || offsetY != 0)
                        draggingImage.Crop(new Rectangle(offsetX, offsetY, draggingImage.Width - offsetX, draggingImage.Height - offsetY));

                    OverlayCommand overlayCommand = new OverlayCommand(draggingImage, Point.Round(droppingRectInImageSpace.Location));
                    overlayCommand.ExecuteInPlace(ImageViewer.Image);
                }
                _isDragging = false;

                InvalidateViewer();
            }
        }

        /// <summary>
        /// Calculates drawing box in image space.
        /// </summary>
        /// <param name="viewer">Image viewer.</param>
        /// <param name="tool">Current visual tool.</param>
        /// <param name="mouseLocationInScreen">Mouse position in screen coordinates.</param>
        private Rectangle GetDrawingBoxInImageSpace(ImageViewer viewer, AdvancedDragAndDropTool tool)
        {
            if (viewer.Image == null)
                return Rectangle.Empty;

            int offsetXInControl = (int)Math.Round(tool._dragPointInImageSpace.X - tool._draggingImageSize.X);
            int offsetYInControl = (int)Math.Round(tool._dragPointInImageSpace.Y - tool._draggingImageSize.Y);
            Point mousePositionInImage = GetCursorPositionInImageSpace(viewer);

            return new Rectangle(
                mousePositionInImage.X - offsetXInControl,
                mousePositionInImage.Y - offsetYInControl,
                (int)Math.Round(tool._draggingImageSize.Width),
                (int)Math.Round(tool._draggingImageSize.Height));
        }

        /// <summary>
        /// Gets position of the cursor in image space.
        /// </summary>
        /// <param name="viewer">Image viewer.</param>
        private Point GetCursorPositionInImageSpace(ImageViewer viewer)
        {
            Point mouseLocationInClient = viewer.FindForm().PointToClient(Cursor.Position);
            Point mouseLocationInControl = new Point(mouseLocationInClient.X - viewer.Location.X,
                mouseLocationInClient.Y - viewer.Location.Y);
            return viewer.PointToImage(mouseLocationInControl);
        }

        /// <summary>
        /// Gets the image region that should be dragged.
        /// </summary>
        private VintasoftImage GetDraggingImage()
        {
            VintasoftImage img = ImageViewer.Image;
            if (img.IsProcessing)
            {
                this.TryFinishInteraction();
                if (img.IsProcessing)
                    return null;
            }
            Rectangle imageRect = new Rectangle(0, 0, img.Width, img.Height);
            Rectangle drawingBox = Rectangle.Round(_draggingImageSize);
            drawingBox.Intersect(imageRect);
            CropCommand cropCommand = new CropCommand(drawingBox);
            return cropCommand.Execute(img);
        }

        #endregion

        #endregion

    }
}
Here is source codes of transformer of visual tool (AdvancedDragAndDropToolTransformer.cs file):

Code: Select all

/// <summary>
/// An interactive transformer that allows to select image region in image viewer and
/// starts drag-and-drop operation when image region is moved.
/// </summary>
private class AdvancedDragAndDropToolTransformer : RectangularObjectTransformer
{

    #region Fields

    /// <summary>
    /// Drag-and-drop visual tool.
    /// </summary>
    AdvancedDragAndDropTool _tool = null;

    #endregion



    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="AdvancedDragAndDropToolTransformer"/> class.
    /// </summary>
    /// <param name="interactiveObject">An interative object.</param>
    internal AdvancedDragAndDropToolTransformer(IRectangularInteractiveObject interactiveObject)
        : base(interactiveObject)
    {
        if (interactiveObject is AdvancedDragAndDropTool)
            _tool = (AdvancedDragAndDropTool)interactiveObject;
    }

    #endregion



    #region Properties

    /// <summary>
    /// Gets a value indicating whether controller is visible.
    /// </summary>
    public override bool IsVisible
    {
        get
        {
            if (_tool != null)
                return !_tool.IsDragging;
            else
                return true;
        }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Performs an interaction between user and interaction area of interactive object.
    /// </summary>
    /// <param name="args">An interaction event args.</param>
    protected override void PerformInteraction(InteractionEventArgs args)
    {
        // if visual tool interacts with selection
        if (args.Area == MoveArea)
        {
            switch (args.Action)
            {
                // if selection is moving
                case InteractionAreaAction.Move:
                    OnDraggingStarted();
                    return;

                // if interaction with selection is canceled
                case InteractionAreaAction.Cancel:
                    args.InteractionFinished = true;
                    return;
            }
        }

        base.PerformInteraction(args);
    }

    /// <summary>
    /// Raises the <see cref="AdvancedDragAndDropToolTransformer.DraggingStarted"/> event.
    /// </summary>
    private void OnDraggingStarted()
    {
        if (DraggingStarted != null)
            DraggingStarted(this, EventArgs.Empty);
    }

    #endregion



    #region Events

    /// <summary>
    /// Occurs when dragging is started.
    /// </summary>
    public event EventHandler DraggingStarted;

    #endregion

}
And here is sources codes of a form with 2 image viewers (Form1.cs file):

Code: Select all

using System;
using System.Windows.Forms;
using Vintasoft.Imaging;

namespace VintasoftDragDrop
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }



        private void Form1_Load(object sender, EventArgs e)
        {
            imageViewer1.SizeMode = Vintasoft.Imaging.UI.ImageSizeMode.BestFit;
            imageViewer1.Image = new VintasoftImage("apple.jpg");
            imageViewer1.VisualTool = new AdvancedDragAndDropTool();

            imageViewer2.SizeMode = Vintasoft.Imaging.UI.ImageSizeMode.BestFit;
            imageViewer2.Image = new VintasoftImage("apple.jpg");
            imageViewer2.VisualTool = new AdvancedDragAndDropTool();
        }

    }
}

You can combine work of the AdvancedDragAndDropTool and AnnotationDragAndDropTool (viewtopic.php?f=24&t=2255) classes if you need drag-and-drop an image region or annotation from one image viewer to another.
Here is a code snippet that shows how to do this:

Code: Select all

imageViewer1.VisualTool = new CompositeVisualTool(
       imageViewer1.AnnotationVisualTool,
       new AnnotationDragAndDropTool(),
       new AdvancedDragAndDropTool());

imageViewer2.VisualTool = new CompositeVisualTool(
       imageViewer2.AnnotationVisualTool,
       new AnnotationDragAndDropTool(),
       new AdvancedDragAndDropTool());
Post Reply