vbAccelerator - Contents of code file: IconDragDropDemoControl.cs

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

using vbAccelerator.Components.ImageList;

namespace vbAccelerator.Controls.Demo
{
   /// <summary>
   /// Summary description for IconDragDropDemoControl.
   /// </summary>
   public class IconDragDropDemoControl : System.Windows.Forms.UserControl
   {
      /// <summary>
      /// The ImageList to draw the icons from.
      /// </summary>
      protected ImageList ils = null;
      /// <summary>
      /// Collection of items associated with the control.
      /// </summary>
      protected IconDragDropDemoControlCollection items = null;
      /// <summary>
      /// Size of items.
      /// </summary>
      protected Size itemSize = new Size(64, 50);
      /// <summary>
      /// The item we're dragging:
      /// </summary>
      protected int dragging = -1;
      /// <summary>
      /// The item that we're currently over:
      /// </summary>
      protected int dragOver = -1;
      /// <summary>
      /// An object which produces nice alpha blended drag
      /// images for the item I'm dragging:
      /// </summary>
      protected ImageListDrag ilsDrag = new ImageListDrag();
      /// <summary> 
      /// Required designer variable.
      /// </summary>
      private System.ComponentModel.Container components = null;

      #region Constructor, Dispose, Finalize
      /// <summary>
      /// Constructs a new instance of the icon drag-drop control.
      /// </summary>
      public IconDragDropDemoControl()
      {
         // This call is required by the Windows.Forms Form Designer.
         InitializeComponent();

         // Create the items collection:
         this.items = new IconDragDropDemoControlCollection(this);
      }

      /// <summary> 
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if(components != null)
            {
               components.Dispose();
            }
         }
         base.Dispose( disposing );
      }
      #endregion

      #region Component Designer generated code
      /// <summary> 
      /// Required method for Designer support - do not modify 
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
         components = new System.ComponentModel.Container();
      }
      #endregion

      
      #region Events etc
      /// <summary>
      /// Raises the mouse down message and checks whether the
      /// mouse down event is using the left mouse button over
      /// an icon.
      /// </summary>
      /// <param name="e"></param>
      protected override void OnMouseDown(MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Left)
         {
            int i = this.items.HitTest(new Point(e.X, e.Y));
            if (i > -1)
            {
               this.dragOver = i;
               this.dragging = i;
               IconDragDropDemoControlItem item = this.items[i];
               string caption = item.Caption;
               ilsDrag.Imagelist = ils;
               ilsDrag.StartDrag(item.IconIndex, -8, -8);
               
               this.DoDragDrop((object)item, DragDropEffects.Move);

               ilsDrag.CompleteDrag();
            }
         }
         base.OnMouseDown(e);
      }

      /// <summary>
      /// Raises the DragDrop event and checks if the item can
      /// be inserted.
      /// </summary>
      /// <param name="e"></param>
      protected override void OnDragDrop(DragEventArgs e)
      {
      
         // Raise the event:
         base.OnDragDrop(e);

         if (e.Data.GetDataPresent(typeof(IconDragDropDemoControlItem)))
         {
            // See where we are:
            Point pt = this.PointToClient(new Point(e.X, e.Y));
            int i = this.items.HitTest(pt);
            // What to do:
            if (i != -1)
            {
               // swap the item we're dragging with i (assuming
               // they're different):
               IconDragDropDemoControlItem item = 
                  (IconDragDropDemoControlItem)e.Data.GetData(
                     typeof(IconDragDropDemoControlItem));
               if (!item.Equals(this.items[i]))
               {
                  this.items.Remove(item);
                  this.items.Insert(i, item);
               }
            }
         }
      }

      /// <summary>
      /// Raises the DragOver event and checks whether
      /// the item can be dropped at the specified position.
      /// </summary>
      /// <param name="e">The details associated with the
      /// DragOver event.</param>
      protected override void OnDragOver(DragEventArgs e)
      {
         // Raise the DragOver event
         base.OnDragOver(e);

         if (e.Data.GetDataPresent(typeof(IconDragDropDemoControlItem)))
         {

            // note -  a real implementation of this sort
            // of thing would actually be checking if we're 
            // between items as well as over them.

            // Find where the cursor is and see 
            // if it's over an item in the control:
            Point pt = Cursor.Position;
            pt = this.PointToClient(pt);
            int i = this.items.HitTest(pt);

            if (i != -1) // over an item
            {            
               // if over a different item, then update
               // the display:
               if (i != this.dragOver)
               {
                  this.dragOver = i;
                  this.Invalidate();
               }
               e.Effect = DragDropEffects.Move;
            }
            else // not over an item
            {
               // if not already displaying over an item,
               // then update the display:
               if (i != -1)
               {
                  this.dragOver = -1;
                  this.Invalidate();
               }
               e.Effect = DragDropEffects.None;
            }
         }
      }

      /// <summary>
      /// Raises the GiveFeedback event and displays the 
      /// customised drag image.
      /// </summary>
      /// <param name="e">The details associated with the
      /// GiveFeedback event.</param>
      protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
      {
         // Raise the GiveFeedback event
         base.OnGiveFeedback(e);

         // Draw the drag image:         
         ilsDrag.DragDrop();
      }

      /// <summary>
      /// Raises the Paint event and renders the control.
      /// </summary>
      /// <param name="e">The details of the Paint event
      /// to be be performed.</param>
      protected override void OnPaint(PaintEventArgs e)
      {
         // ask the items collection to draw itself:
         this.items.Draw(
            e.Graphics, 
            this.ils, 
            this.ClientRectangle,
            this.itemSize);
      }
      #endregion
      
      
      #region API
      /// <summary>
      /// Gets/sets the size of each item in the control.
      /// </summary>
      public Size ItemSize
      {
         get
         {
            return this.itemSize;
         }
         set
         {
            this.itemSize = value;
            Invalidate();
         }
      }
      /// <summary>
      /// Items contained within this control.
      /// </summary>
      public IconDragDropDemoControlCollection Items
      {
         get
         {
            return this.items;
         }
      }

      /// <summary>
      /// Gets/sets the ImageList used to render this control.
      /// </summary>
      public ImageList ImageList
      {
         // #if Bitch
         // Whoever wrote the ImageList class should be shot.
         // This isn't a good design, and I say that even though
         // I used to have to work with the Collection
         // object in VB Classic.
         // #endif Bitch
         get
         {
            return this.ils;
         }
         set
         {
            this.ils = value;
         }
      }

      /// <summary>
      /// Used by the items and the item collection which belong
      /// to this control to notify it that something needs to be
      /// redrawn.
      /// </summary>
      public void ItemChanged()
      {
         // redraw
         this.Invalidate();
      }

      #endregion
   }

   /// <summary>
   /// Manages the collection of <code>IconDragDropDemoControlItem</code>
   /// objects to shown in the <code>IconDragDropDemoControl</code>.
   /// </summary>
   public class IconDragDropDemoControlCollection : CollectionBase
   {
      /// <summary>
      /// The owning control for this item collection.
      /// </summary>
      protected IconDragDropDemoControl owner = null;

      /// <summary>
      /// Tests whether the specified point is over an item
      /// in the control or not.
      /// </summary>
      /// <param name="pt">The point to test, relative to the
      /// client area of the control.</param>
      /// <returns>The 0-based index of the item in the control
      /// that contains the point, or -1 if no item is found.</returns>
      public virtual int HitTest(Point pt)
      {
         int index = -1;
         for (int itemIndex = 0; itemIndex < this.InnerList.Count; itemIndex++)
         {
            if
             (((IconDragDropDemoControlItem)this.InnerList[itemIndex]).HitTest(p
            t))
            {
               index = itemIndex;
               break;
            }
         }
         return index;
      }

      /// <summary>
      /// Draws the items in the collection onto the 
      /// specified graphics object.
      /// </summary>
      /// <param name="gfx">The graphics object to draw onto.</param>
      /// <param name="ils">The ImageList to source images from.</param>
      /// <param name="bounds">The bounding rectangle of the client 
      /// area of the control.</param>
      /// <param name="itemSize">The size for each item.</param>
      public virtual void Draw(
         Graphics gfx,
         ImageList ils,
         Rectangle bounds,
         Size itemSize
         )
      {
         int x = 2;
         int y = 2;

         foreach (IconDragDropDemoControlItem item in this.InnerList)
         {
            Rectangle itemBounds = new Rectangle(
               new Point(x, y), itemSize);

            item.Draw(gfx, ils, itemBounds);

            x += itemSize.Width;
            if (x + itemSize.Width > bounds.Width)
            {
               x = 2;
               y += itemSize.Height;
            }
         }

      }

      /// <summary>
      /// Returns the <code>IconDragDropDemoControlItem</code>
      /// at the specified 0-based index.
      /// </summary>
      public IconDragDropDemoControlItem this[int index]
      {
         get
         {
            return (IconDragDropDemoControlItem)this.InnerList[index];
         }
      }

      /// <summary>
      /// Returns the 0-based index of the specified 
      /// <code>IconDragDropDemoControlItem</code> object in the collection,
      /// if it exists, or -1 otherwise.
      /// </summary>
      /// <param name="item">The item to find the index for.</param>
      /// <returns>The 0-based index of the item if it exists, or -1
       otherwise.</returns>
      public int IndexOf(IconDragDropDemoControlItem item)
      {
         return this.InnerList.IndexOf(item);
      }

      /// <summary>
      /// Adds a new <code>IconDragDropDemoControlItem</code> to the control.
      /// </summary>
      /// <param name="item">The item to add.</param>
      public void Add(IconDragDropDemoControlItem item)
      {
         this.InnerList.Add(item);
         item.Owner = owner;
         owner.ItemChanged();
      }

      /// <summary>
      /// Inserts a new <code>IconDragDropDemoControlItem</code> to the control.
      /// </summary>
      /// <param name="index">The index to insert at.</param>
      /// <param name="item">The item to add.</param>
      public void Insert(int index, IconDragDropDemoControlItem item)
      {
         this.InnerList.Insert(index, item);
         owner.ItemChanged();
      }

      /// <summary>
      /// Removes the specified <code>IconDragDropDemoControlItem</code>
      /// from the control.
      /// </summary>
      /// <param name="item">The item to remove.</param>
      public void Remove(IconDragDropDemoControlItem item)
      {
         this.InnerList.Remove(item);
         owner.ItemChanged();
      }

      /// <summary>
      /// Constructs a new instance of this object for the specified
      /// <code>IconDragDropDemoControl</code>.
      /// </summary>
      /// <param name="owner">The owning control for this collection.</param>
      public IconDragDropDemoControlCollection(
         IconDragDropDemoControl owner
         )
      {
         this.owner = owner;
      }

   }

   /// <summary>
   /// Represents an item in the <code>IconDragDropDemoControl</code>.
   /// Items have an icon and a caption and are displayed in a grid within
   /// the control.
   /// </summary>
   public class IconDragDropDemoControlItem
   {
      /// <summary>
      /// The icon index for the item.
      /// </summary>
      protected int iconIndex = -1;
      /// <summary>
      /// The caption for the item.
      /// </summary>
      protected string caption = "";
      /// <summary>
      /// User-defined data to associate with the item.
      /// </summary>
      protected object tag = null;
      /// <summary>
      /// The last rectangle in which this item was drawn.
      /// </summary>
      protected Rectangle rect = new Rectangle(0,0,0,0);
      /// <summary>
      /// The owning control for this item.
      /// </summary>
      protected IconDragDropDemoControl owner = null;

      /// <summary>
      /// Returns the caption of this item.
      /// </summary>
      public override string ToString()
      {
         return this.caption;
      }

      /// <summary>
      /// Draws this item on the specified graphics object
      /// with the specified bounds.
      /// </summary>
      /// <param name="gfx">Graphics object to draw on.</param>
      /// <param name="ils">ImageList to source icon from.</param>
      /// <param name="bounds">Bounds within which to draw.</param>
      public virtual void Draw(
         Graphics gfx,
         ImageList ils,
         Rectangle bounds
         )
      {
         // Draw the item:
         Rectangle iconRect = new Rectangle(
            bounds.Left + (bounds.Width - ils.ImageSize.Width)/2, bounds.Top +
             2, 
            ils.ImageSize.Width, ils.ImageSize.Height);
         if (this.iconIndex >= 0 && this.iconIndex < ils.Images.Count)
         {
            ils.Draw(gfx, iconRect.Location, this.iconIndex);
         }

         // Draw the caption:
         if (this.owner != null)
         {
            RectangleF textRect = new RectangleF(
               bounds.X + 1, bounds.Y + ils.ImageSize.Height + 4, 
               bounds.Width, bounds.Height - (ils.ImageSize.Height + 4 + 2));
            StringFormat fmt = new StringFormat(StringFormatFlags.LineLimit | 
               ((this.owner.RightToLeft == RightToLeft.Yes) ?
                StringFormatFlags.DirectionRightToLeft : 0));
            fmt.Alignment = StringAlignment.Center;
            gfx.DrawString(this.caption, this.owner.Font,
             SystemBrushes.WindowText,
               textRect, fmt);
            fmt.Dispose();
         }

         // Store the position we drew at for hittesting purposes:
         this.rect = new Rectangle(bounds.Location, bounds.Size);
      }
      
      /// <summary>
      /// Checks whether the specified point falls within
      /// the boundaries of this item or not.
      /// </summary>
      /// <param name="pt">Point to check.</param>
      /// <returns>True if point within the item,
      /// False otherwise.</returns>
      public virtual bool HitTest(Point pt)
      {
         return this.rect.Contains(pt);
      }
         
      /// <summary>
      /// Gets/sets the caption for this item.
      /// </summary>
      public virtual string Caption
      {
         get
         {
            return this.caption;
         }
         set
         {
            this.caption = value;
            notifyOwner();
         }
      }

      /// <summary>
      /// Gets/sets the IconIndex for this item.
      /// </summary>
      public virtual int IconIndex
      {
         get
         {
            return this.iconIndex;
         }
         set
         {
            this.iconIndex = value;
            notifyOwner();
         }
      }

      /// <summary>
      /// Gets/sets the user-defined data associated with this item.
      /// </summary>
      public virtual object Tag
      {
         get
         {
            return this.tag;
         }
         set
         {
            this.tag = value;
         }
      }

      /// <summary>
      /// Gets/sets the owning control for this item.
      /// </summary>
      public IconDragDropDemoControl Owner
      {
         get
         {
            return this.owner;
         }
         set
         {
            this.owner = value;
            notifyOwner();
         }
      }

      private void notifyOwner()
      {
         if (this.owner != null)
         {
            owner.ItemChanged();
         }
      }

      /// <summary>
      /// Constructs a new instance of an IconDragDropDemoControl
      /// item with the specified caption and icon.
      /// </summary>
      /// <param name="caption">The caption to show.</param>
      /// <param name="iconIndex">The 0-based icon index to use, or -1
      /// if no icon should be used.</param>
      public IconDragDropDemoControlItem(
         string caption,
         int iconIndex
         )
      {
         this.caption = caption;
         this.iconIndex = iconIndex;         
      }
   }
}