Click here to Skip to main content
15,895,746 members
Articles / Containers / Docker

SVG Artiste - An SVG Editor

Rate me:
Please Sign up or sign in to vote.
4.69/5 (23 votes)
3 Aug 2010CPOL14 min read 96.3K   15.4K   93  
A Vector based tool to create and edit SVG images
/***************************************************************************
 *   CopyRight (C) 2009 by Cristinel Mazarine                              *
 *   Author:   Cristinel Mazarine                                          *
 *   Contact:  cristinel@osec.ro                                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the Crom Free License as published by           *
 *   the SC Crom-Osec SRL; version 1 of the License                        *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   Crom Free License for more details.                                   *
 *                                                                         *
 *   You should have received a copy of the Crom Free License along with   *
 *   this program; if not, write to the contact@osec.ro                    *
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Crom.Controls.Docking
{
   /// <summary>
   /// Helper class which provide information about forms
   /// </summary>
   internal class FormWrapper : Disposable
   {
      #region Fields

      private IntPtr                   _hostHandle             = IntPtr.Zero;
      private Control                  _host                   = null;
      private Control[]                _keepLast               = null;
      private Control[]                _keepFirst              = null;
      private List<Control>            _ignoreOnGetFromPoint   = new List<Control>();

      #endregion Fields

      #region Instance

      /// <summary>
      /// Light-constructor
      /// </summary>
      /// <param name="control">constructor</param>
      private FormWrapper(Control control)
      {
         _hostHandle = control.Handle;
         _host       = control;
         _keepFirst  = new Control[0];
         _keepLast   = new Control[0];
      }

      /// <summary>
      /// Default constructor
      /// </summary>
      /// <param name="window">window object</param>
      /// <param name="keepFirstCount">number of controls to keep first</param>
      /// <param name="keepLastCount">number of controls to keep last</param>
      public FormWrapper(IWin32Window window, int keepFirstCount, int keepLastCount)
      {
         _hostHandle = window.Handle;
         _keepFirst  = new Control[keepFirstCount];
         _keepLast   = new Control[keepLastCount];

         // Just for now only allow .Net control
         // TODO: implement bounds change detection for any window
         _host = window as Control;
         if (_host == null)
         {
            throw new ArgumentException("In this version are allowed only .NET controls as hosts for docking");
         }
         _host.SizeChanged     += OnHostSizeChanged;
         _host.Move            += OnHostMoved;
         _host.VisibleChanged  += OnHostVisibleChanged;
      }

      #endregion Instance

      #region Public section

      /// <summary>
      /// Event raised when form size was changed
      /// </summary>
      public event EventHandler SizeChanged;

      /// <summary>
      /// Event raised when form was moved
      /// </summary>
      public event EventHandler Move;

      /// <summary>
      /// Event raised when form visibility was changed
      /// </summary>
      public event EventHandler VisibleChanged;

      /// <summary>
      /// Checks if the form is visible
      /// </summary>
      public bool Visible
      {
         get
         {
            ValidateNotDisposed();

            return _host.Visible;// IsWindowVisible(_hostHandle);
         }
      }

      /// <summary>
      /// Accessor for the form handle
      /// </summary>
      public IntPtr Handle
      {
         get
         {
            ValidateNotDisposed();

            return _hostHandle;
         }
      }

      /// <summary>
      /// Accessor for the form text
      /// </summary>
      public string Text
      {
         get
         {
            ValidateNotDisposed();

            return _host.Text;
         }
         set
         {
            ValidateNotDisposed();

            _host.Text = value;
         }
      }

      /// <summary>
      /// Accessor for the form width
      /// </summary>
      public int Width
      {
         get
         {
            ValidateNotDisposed();

            return _host.Width;
         }
      }

      /// <summary>
      /// Accessor for the form height
      /// </summary>
      public int Height
      {
         get
         {
            ValidateNotDisposed();

            return _host.Height;
         }
      }

      /// <summary>
      /// Accessor for host client size
      /// </summary>
      public Size ClientSize
      {
         get { return _host.ClientSize; }
      }

      /// <summary>
      /// Rectangle to screen coordinates
      /// </summary>
      /// <param name="clientRectangle">client rectangle</param>
      /// <returns>rectangle in screen coordinates</returns>
      public Rectangle RectangleToScreen(Rectangle clientRectangle)
      {
         return _host.RectangleToScreen(clientRectangle);
      }

      /// <summary>
      /// Rectangle to client coordinates
      /// </summary>
      /// <param name="screenRectangle">screen rectangle</param>
      /// <returns>rectangle in client coordinates</returns>
      public Rectangle RectangleToClient(Rectangle screenRectangle)
      {
         return _host.RectangleToClient(screenRectangle);
      }

      /// <summary>
      /// Converts a screen location into client location
      /// </summary>
      /// <param name="screenLocation">screen location</param>
      /// <returns>client location</returns>
      public Point PointToClient(Point screenLocation)
      {
         return _host.PointToClient(screenLocation);
      }

      /// <summary>
      /// Client rectangle in screen coordinates
      /// </summary>
      public Rectangle ScreenClientRectangle
      {
         get
         {
            return _host.RectangleToScreen(_host.ClientRectangle);
         }
      }

      /// <summary>
      /// Gets the count of child controls
      /// </summary>
      public int ControlsCount
      {
         get { return _host.Controls.Count; }
      }

      /// <summary>
      /// Gets the child control at given index
      /// </summary>
      /// <param name="index">zero based index</param>
      /// <returns>child control at given index</returns>
      public Control GetControlAt(int index)
      {
         return _host.Controls[index];
      }

      /// <summary>
      /// Add control to host
      /// </summary>
      /// <param name="control">control to add</param>
      public void AddLast(Control control)
      {
         _host.Controls.Add(control);

         int index = GetFirstIndex(KeepLast, control);

         SetChildIndex(control, index);
      }

      /// <summary>
      /// Add control to host
      /// </summary>
      /// <param name="control">control to add</param>
      public void AddFirst(Control control)
      {
         int index = GetLastIndex(KeepFirst, control);

         _host.Controls.Add(control);
         SetChildIndex(control, index);
      }

      /// <summary>
      /// Move the control first
      /// </summary>
      /// <param name="controlToMove">control to be moved first</param>
      public void MoveFirst(Control controlToMove)
      {
         int index = GetLastIndex(KeepFirst, controlToMove);

         SetChildIndex(controlToMove, index);
      }

      /// <summary>
      /// Move the control last in zorder 
      /// </summary>
      /// <param name="controlToMove">form to be moved last</param>
      public void MoveLast(Control controlToMove)
      {
         int index = GetFirstIndex(KeepLast, controlToMove);

         SetChildIndex(controlToMove, index);
      }

      /// <summary>
      /// Remove form from host
      /// </summary>
      /// <param name="form">form</param>
      public void Remove(Control form)
      {
         _host.Controls.Remove(form);
      }

      /// <summary>
      /// Get ZOrder index
      /// </summary>
      /// <param name="form">form for which ZOrder is requested</param>
      /// <returns>ZOrder index</returns>
      public int GetZOrderIndex(Control form)
      {
         return _host.Controls.GetChildIndex(form);
      }

      /// <summary>
      /// Check if the host contains this control
      /// </summary>
      /// <param name="control">control</param>
      /// <returns>true if the host contains control</returns>
      public bool Contains(Control control)
      {
         return _host.Controls.Contains(control);
      }

      /// <summary>
      /// Gets the child leaf window found at given screen location
      /// </summary>
      /// <param name="screenPoint">point in screen coordinates</param>
      /// <param name="ignored">control to be ignored from search</param>
      /// <returns>found dockable container</returns>
      public DockableContainer GetLeafDockedContainerFromPoint(Point screenPoint, Control ignored)
      {
         for (int childIndex = 0; childIndex < ControlsCount; childIndex++)
         {
            Control child = GetControlAt(childIndex);

            if (child == ignored)
            {
               continue;
            }

            if (child.Visible == false)
            {
               continue;
            }

            DockableContainer container = child as DockableContainer;
            if (container == null)
            {
               continue;
            }

            if (container.RectangleToScreen(container.ClientRectangle).Contains(screenPoint) == false)
            {
               continue;
            }

            if (container.SingleChild != null)
            {
               if (container.SingleChild.IsDocked == false)
               {
                  continue;
               }

               return container;
            }

            return GetLeafDockedContainerFromPoint(container, screenPoint);
         }

         return null;
      }



      /// <summary>
      /// Gets the fill rectangle based on a point
      /// </summary>
      /// <param name="screenPoint">point in screen coordinates</param>
      /// <returns>rectangle from point</returns>
      public static Rectangle GetFillRectangleFromPoint(Point screenPoint, Control underPoint, FormWrapper host)
      {
         if (underPoint == null)
         {
            if (host != null)
            {
               return GetFillScreenRectangle(host);
            }

            return new Rectangle();
         }

         Rectangle result  = GetFillScreenRectangle(underPoint);
         if (result.Contains(screenPoint) == false)
         {
            return new Rectangle();
         }

         return result;
      }


      /// <summary>
      /// GEt fill screen rectangle
      /// </summary>
      /// <param name="wrapper">wrapper</param>
      /// <returns></returns>
      public static Rectangle GetFillScreenRectangle(FormWrapper wrapper)
      {
         Rectangle clientArea  = wrapper.RectangleToClient(GetScreenClientRectangle(wrapper._host));

         int x1 = clientArea.Left;
         int x2 = clientArea.Right;
         int y1 = clientArea.Top;
         int y2 = clientArea.Bottom;

         for (int index = 0; index < wrapper.ControlsCount; index++)
         {
            Control control  = wrapper.GetControlAt(index);
            if (control.Dock == DockStyle.None || control.Visible == false)
            {
               continue;
            }

            if (control.Dock == DockStyle.Left)
            {
               x1 = Math.Max(x1, control.Right);
            }
            else if (control.Dock == DockStyle.Right)
            {
               x2 = Math.Min(x2, control.Left);
            }
            else if (control.Dock == DockStyle.Top)
            {
               y1 = Math.Max(y1, control.Bottom);
            }
            else if (control.Dock == DockStyle.Bottom)
            {
               y2 = Math.Min(y2, control.Top);
            }
         }

         if (x2 <= x1 || y2 <= y1)
         {
            return new Rectangle();
         }

         Rectangle result = new Rectangle(x1, y1, x2 - x1, y2 - y1);

         return wrapper.RectangleToScreen(result);
      }

      /// <summary>
      /// Get the fill rectangle of the control in screen coordinates
      /// </summary>
      /// <param name="window">window</param>
      /// <returns>fill screen rectangle</returns>
      public static Rectangle GetFillScreenRectangle(Control window)
      {
         FormWrapper wrapper = new FormWrapper(window);
         return GetFillScreenRectangle(wrapper);
      }


      /// <summary>
      /// Gets the client rectangle of given form
      /// </summary>
      /// <param name="form">form object</param>
      /// <returns>client rectangle for given form</returns>
      public static Rectangle GetScreenClientRectangle(Control form)
      {
         return form.RectangleToScreen(form.ClientRectangle);
      }

      /// <summary>
      /// Form from point
      /// </summary>
      /// <param name="screenPoint">screen point</param>
      /// <returns>form</returns>
      public static Control FromPoint(Point screenPoint)
      {
         IntPtr handle = WindowFromPoint(screenPoint);
         if (handle == null)
         {
            return null;
         }

         try
         {
            Control control = Control.FromHandle(handle);
            return control;
         }
         catch { }

         return null;
      }

      /// <summary>
      /// Gets the margins of the control
      /// </summary>
      /// <param name="control">control</param>
      /// <returns>margins</returns>
      public static Margins GetMargins(Control control)
      {
         Margins margins  = new Margins();

         if (control != null)
         {
            WindowInfo info = new WindowInfo();
            info.cbSize = Marshal.SizeOf(info);

            if (GetWindowInfo(control.Handle, ref info) == false)
            {
               throw new InvalidOperationException();
            }

            margins.Left   = info.rcClient.left    - info.rcWindow.left;
            margins.Right  = info.rcWindow.right   - info.rcClient.right;
            margins.Top    = info.rcClient.top     - info.rcWindow.top;
            margins.Bottom = info.rcWindow.bottom  - info.rcClient.bottom;
         }

         return margins;
      }

      /// <summary>
      /// Get the container bounds inside host
      /// </summary>
      /// <param name="container">container</param>
      /// <returns>bounds relative to host</returns>
      public Rectangle GetBoundsInHost(Control control)
      {
         Rectangle bounds = control.Bounds;
         Control parent   = control.Parent;

         while (parent != null)
         {
            if (parent.Handle == Handle)
            {
               return bounds;
            }

            bounds.X += parent.Left;
            bounds.Y += parent.Top;

            parent = parent.Parent;
         }

         throw new InvalidOperationException("The control should be parented inside host");
      }

      /// <summary>
      /// Accessor for the controls to keep last
      /// </summary>
      public Control[] KeepLast
      {
         get { return _keepLast; }
      }

      /// <summary>
      /// Accessor for the controls to keep first
      /// </summary>
      public Control[] KeepFirst
      {
         get { return _keepFirst; }
      }


      /// <summary>
      /// Add control to the list of controls ignored when getting child from point
      /// </summary>
      /// <param name="control">control to ignore</param>
      public void AddToIgnoreOnGetChildFromPoint(Control control)
      {
         if (_ignoreOnGetFromPoint.Contains(control) == false)
         {
            _ignoreOnGetFromPoint.Add(control);
         }
      }

      #endregion Public section

      #region Protected section

      /// <summary>
      /// Dispose current instance
      /// </summary>
      /// <param name="fromIDisposableDispose">call from IDisposable.Dispose</param>
      protected override void Dispose(bool fromIDisposableDispose)
      {
         if (fromIDisposableDispose)
         {
            _host.SizeChanged     -= OnHostSizeChanged;
            _host.Move            -= OnHostMoved;
            _host.VisibleChanged  -= OnHostVisibleChanged;
         }

         _host = null;
      }

      #endregion Protected section

      #region Private section
      #region API

      /// <summary>
      /// Rect
      /// </summary>
      [StructLayout(LayoutKind.Sequential)]
      public struct Rect
      {
          public int left;
          public int top;
          public int right;
          public int bottom;
      };

      /// <summary>
      /// Titlebar info
      /// </summary>
      [StructLayout(LayoutKind.Sequential)]
      private struct TitlebarInfo
      {
         public int  cbSize;
         public Rect rcTitleBar;
         public int childBar0;
         public int childBar1;
         public int childBar2;
         public int childBar3;
         public int childBar4;
         public int childBar5;
      };

      /// <summary>
      /// Window info
      /// </summary>
      [StructLayout(LayoutKind.Sequential)]
      private struct WindowInfo
      {
         public int cbSize;
         public Rect rcWindow;
         public Rect rcClient;
         public int dwStyle;
         public int dwExStyle;
         public int dwWindowStatus;
         public int cxWindowBorders;
         public int cyWindowBorders;
         public short atomWindowType;
         public short wCreatorVersion;
      }

      [DllImport("user32")]
      private static extern bool GetTitleBarInfo(IntPtr hWnd, ref TitlebarInfo info);

      [DllImport("user32")]
      private static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo info);

      [DllImport("user32")]
      private static extern bool IsWindowVisible(IntPtr hWnd);

      [DllImport("user32")]
      private static extern IntPtr WindowFromPoint(Point screenPoint);

      #endregion API

      /// <summary>
      /// On host moved
      /// </summary>
      /// <param name="sender">sender of the event</param>
      /// <param name="e">event argument</param>
      private void OnHostMoved(object sender, EventArgs e)
      {
         if (Move != null)
         {
            Move(this, EventArgs.Empty);
         }
      }

      /// <summary>
      /// On host size changed
      /// </summary>
      /// <param name="sender">sender of the event</param>
      /// <param name="e">event argument</param>
      private void OnHostSizeChanged(object sender, EventArgs e)
      {
         if (SizeChanged != null)
         {
            SizeChanged(this, EventArgs.Empty);
         }
      }

      /// <summary>
      /// On host visibility changed
      /// </summary>
      /// <param name="sender">sender of the event</param>
      /// <param name="e">event argument</param>
      private void OnHostVisibleChanged(object sender, EventArgs e)
      {
         if (VisibleChanged != null)
         {
            VisibleChanged(this, EventArgs.Empty);
         }
      }

      ///// <summary>
      ///// Gets the child leaf window found at given screen location
      ///// </summary>
      ///// <param name="screenPoint">point in screen coordinates</param>
      ///// <param name="parent">parent inside which the child is searched</param>
      ///// <param name="validate">handler to validate if child is included in search</param>
      ///// <param name="containedExcluded">flag indicating that parent contained excluded</param>
      ///// <returns>rectangle from point</returns>
      //private static Control ChildLeafFromPoint(Point screenPoint, FormWrapper parent, ExtractControlHandler validate, out bool containedExcluded)
      //{
      //   containedExcluded = false;

      //   if (parent == null)
      //   {
      //      return null;
      //   }

      //   for (int childIndex = 0; childIndex < parent.ControlsCount; childIndex++)
      //   {
      //      Control child = parent.GetControlAt(childIndex);
      //      if (IgnoreOnGetFromPoint(parent, child))
      //      {
      //         continue;
      //      }

      //      if (child.RectangleToScreen(child.ClientRectangle).Contains(screenPoint) == false)
      //      {
      //         continue;
      //      }

      //      if (validate(child) == false)
      //      {
      //         containedExcluded = true;
      //         continue;
      //      }

      //      FormWrapper childWrapper    = new FormWrapper(child);
      //      bool childContainedExcluded = false;
      //      Control found = ChildLeafFromPoint(screenPoint, childWrapper, validate, out childContainedExcluded);
      //      if (childContainedExcluded)
      //      {
      //         continue;
      //      }

      //      if (found != null)
      //      {
      //         return found;
      //      }

      //      return child;
      //   }

      //   return null;
      //}

      /// <summary>
      /// Check if should ignore the child on get from point
      /// </summary>
      /// <param name="parent">parent</param>
      /// <param name="child">child</param>
      /// <returns></returns>
      private static bool IgnoreOnGetFromPoint(FormWrapper parent, Control child)
      {
         if (child == null)
         {
            return true;
         }

         if (child.Visible == false)
         {
            return true;
         }

         Control control = child;
         while (control != null)
         {
            if (parent._ignoreOnGetFromPoint.Contains(control))
            {
               return true;
            }

            control = control.Parent;
         }

         return false;
      }

      /// <summary>
      /// Get first index of the controls
      /// </summary>
      /// <param name="controls">controls array</param>
      /// <param name="match">control that should be checked for a match in controls list</param>
      /// <returns>first index</returns>
      private int GetFirstIndex(Control[] controls, Control match)
      {
         int firstIndex = _host.Controls.Count - 1;
         if (controls != null)
         {
            for (int index = controls.Length - 1; index >= 0; index--)
            {
               Control control = controls[index];
               if (control == null)
               {
                  continue;
               }

               if (control == match)
               {
                  break;
               }

               firstIndex--;
            }
         }

         return firstIndex;
      }

      /// <summary>
      /// Get last index of the controls
      /// </summary>
      /// <param name="controls">controls array</param>
      /// <param name="match">control that should be checked for a match in controls list</param>
      /// <returns>last index</returns>
      private int GetLastIndex(Control[] controls, Control match)
      {
         int lastIndex = 0;
         if (controls != null)
         {
            for (int index = 0; index < controls.Length; index++)
            {
               Control control = controls[index];
               if (control == null)
               {
                  continue;
               }

               if (control == match)
               {
                  break;
               }

               lastIndex++;
            }
         }

         return lastIndex;
      }


      /// <summary>
      /// Set child index
      /// </summary>
      /// <param name="controlToMove">control to move</param>
      /// <param name="index">index</param>
      private void SetChildIndex(Control controlToMove, int newIndex)
      {
         _host.Controls.SetChildIndex(controlToMove, newIndex);

         int orderIndex = 0;
         for (int index = 0; index < KeepFirst.Length; index++)
         {
            if (KeepFirst[index] == null)
            {
               continue;
            }

            _host.Controls.SetChildIndex(KeepFirst[index], orderIndex);

            orderIndex++;
         }

         orderIndex = _host.Controls.Count - 1;
         for (int index = KeepLast.Length - 1; index >= 0; index--)
         {
            if (KeepLast[index] == null)
            {
               continue;
            }

            _host.Controls.SetChildIndex(KeepLast[index], orderIndex);

            orderIndex--;
         }
      }

      /// <summary>
      /// Get dock container from point
      /// </summary>
      /// <param name="parentContainer">parent container</param>
      /// <param name="screenPoint">screen point</param>
      /// <returns>leaf dock container under given screen point</returns>
      private DockableContainer GetLeafDockedContainerFromPoint(DockableContainer parentContainer, Point screenPoint)
      {
         if (parentContainer.SingleChild != null)
         {
            return parentContainer;
         }

         if (parentContainer.LeftPane != null)
         {
            if (parentContainer.LeftPane.RectangleToScreen(parentContainer.LeftPane.ClientRectangle).Contains(screenPoint))
            {
               return GetLeafDockedContainerFromPoint(parentContainer.LeftPane, screenPoint);
            }
            else if (parentContainer.RightPane.RectangleToScreen(parentContainer.RightPane.ClientRectangle).Contains(screenPoint))
            {
               return GetLeafDockedContainerFromPoint(parentContainer.RightPane, screenPoint);
            }

            // Mouse over splitter
            return null;
         }

         if (parentContainer.TopPane != null)
         {
            if (parentContainer.TopPane.RectangleToScreen(parentContainer.TopPane.ClientRectangle).Contains(screenPoint))
            {
               return GetLeafDockedContainerFromPoint(parentContainer.TopPane, screenPoint);
            }
            else if (parentContainer.BottomPane.RectangleToScreen(parentContainer.BottomPane.ClientRectangle).Contains(screenPoint))
            {
               return GetLeafDockedContainerFromPoint(parentContainer.BottomPane, screenPoint);
            }

            // Mouse over splitter
            return null;
         }

         // Mouse over splitter
         return null;
      }

      #endregion Private section
   }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
Singapore Singapore
He is a Microsoft technology enthusiast, who wish to create applications which others find useful.He loves making small tools and getting involved in architecting bigger systems.

He is currently working as a professional developer in a software development firm in .Net technologies.

He likes reading technical blogs, contributing to opensource and most importantly, enjoying life.

His ambition is to be an impressive software maker.

Comments and Discussions