/// <summary>
 /// Creates a new DockEventArgs object.
 /// </summary>
 /// <param name="point">The point where to dock the window.</param>
 /// <param name="dockType">The needed target container type.</param>
 /// <param name="release">The state of the dock process. True, if dock is finally performed.</param>
 public DockEventArgs(Point point, DockContainerType dockType, bool release)
 {
     this.point = point;
     this.dockType = dockType;
     this.release = release;
     this.target = null;
 }
        /// <summary>
        /// Invokes the drag event and adjusts the size and location if a valid docking position was received.
        /// This method is only used by explicit drag windows (see flag).
        /// </summary>
        internal void MoveWindow()
        {
            if ((this.DragWindow != null) && isDragWindow)
            {
                dragTarget = null;

                DockEventArgs e = new DockEventArgs(new Point(MousePosition.X, MousePosition.Y), this.dockType, false);
                this.DragWindow(this, e);

                dragTarget = e.Target;

                if (dragTarget != null)
                {
                    this.Size = dragTarget.Size;

                    if (dragTarget.Parent != null)
                        this.Location = dragTarget.RectangleToScreen(dragTarget.ClientRectangle).Location;
                    else
                        this.Location = dragTarget.Location;
                }
            }
        }
        /// <summary>
        /// Retrieves a container that matches a specific mouse location, when a window is dragged.
        /// </summary>
        /// <param name="type">The target container type.</param>
        /// <param name="pt">The target position.</param>
        /// <returns>A valid container or null, if no suitable container was found.</returns>
        protected DockContainer GetTarget(Size srcSize, DockContainerType type, Point pt)
        {
            // Prepare rectangles.
            Rectangle rcClient = RectangleToScreen(this.ClientRectangle);
            Rectangle rcDock = new Rectangle(rcClient.Left+this.DockPadding.Left,
                rcClient.Top+this.DockPadding.Top,
                rcClient.Width-this.DockPadding.Left-this.DockPadding.Right,
                rcClient.Height-this.DockPadding.Top-this.DockPadding.Bottom);

            // Test on split.
            if (rcDock.Contains(pt))
            {
                DockContainer cont = null;

                if (pt.X-rcDock.Left <= dockBorder)
                {
                    // Split left.
                    cont = new DockContainer();
                    cont.DockType = type;
                    cont.Dock = DockStyle.Left;
                    if (srcSize.Width > this.Width/2)
                        cont.Width = this.Width/2;
                    else
                        cont.Width = srcSize.Width;
                    cont.Height = this.Height;
                    cont.Location = new Point(rcClient.X, rcClient.Y);
                }
                else if (rcDock.Right-pt.X <= dockBorder)
                {
                    // Split right.
                    cont = new DockContainer();
                    cont.DockType = type;
                    cont.Dock = DockStyle.Right;
                    if (srcSize.Width > this.Width/2)
                        cont.Width = this.Width/2;
                    else
                        cont.Width = srcSize.Width;
                    cont.Height = this.Height;
                    cont.Location = new Point(rcClient.X+this.Width-cont.Width, rcClient.Y);
                }
                else if (pt.Y-rcDock.Top <= dockBorder)
                {
                    // Split top.
                    cont = new DockContainer();
                    cont.DockType = type;
                    cont.Dock = DockStyle.Top;
                    if (srcSize.Height > this.Height/2)
                        cont.Height = this.Height/2;
                    else
                        cont.Height = srcSize.Height;
                    cont.Width = this.Width;
                    cont.Location = new Point(rcClient.X, rcClient.Y);
                }
                else if (rcDock.Bottom-pt.Y <= dockBorder)
                {
                    // Split bottom.
                    cont = new DockContainer();
                    cont.DockType = type;
                    cont.Dock = DockStyle.Bottom;
                    if (srcSize.Height > this.Height/2)
                        cont.Height = this.Height/2;
                    else
                        cont.Height = srcSize.Height;
                    cont.Width = this.Width;
                    cont.Location = new Point(rcClient.X, rcClient.Y+this.Height-cont.Height);
                }

                return cont;
            }

            // Test on add to own panel list.
            if (rcClient.Contains(pt))
            {
                if ((pt.Y <= rcClient.Top+this.DockPadding.Top) && (dockType == type))
                    return this;
                else if ((dockType == type) && (dockType == DockContainerType.ToolWindow) && (panelList.Count > 1) && (pt.Y > rcClient.Top+this.Height-this.DockPadding.Bottom))
                    return this;
            }

            return null;
        }
        public DockContainer GetNextChild(DockContainerType type, DockContainer last)
        {
            DockContainer ret = null;

            foreach (DockContainer cont in containerList)
            {
                ret = cont.GetNextChild(type, last);
                if (ret != null)
                    return ret;
            }

            if ((containerList.Count == 0) && (dockType == type) && (this != last))
                ret = last;

            return ret;
        }
        /// <summary>
        /// The DragWindow event handler for dockable windows.
        /// Used to enable a DockWindow to send its position changes to this container.
        /// Calls recursively all DragWindow event handlers of the child containers.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">An DockEventArgs that contains the docking data.</param>
        public void DragWindow(object sender, DockEventArgs e)
        {
            try
            {
                // First, check if the given point is in the current tree.
                if (!HitTest(e.Point))
                    return;

                // Then, check if the container is dockable at all.
                if (e.DockType == DockContainerType.None)
                    return;

                // Then test all containers.
                foreach (DockContainer c in containerList)
                {
                    c.DragWindow(sender, e);
                    if (e.Target != null)
                        return;
                }

                if (containerList.Count != 0)
                    return;

                // Then test itself.
                DockWindow wnd = sender as DockWindow;
                e.Target = GetTarget(wnd.Size, e.DockType, e.Point);
                if ((e.Target != null) && (e.Release))
                {
                    if (panelList.Contains(wnd.ControlContainer) && (panelList.Count == 1))
                    {
                        e.Target = this;
                        return;
                    }

                    // Dock the container, if needed.
                    if (!containerList.Contains(e.Target) && (e.Target != this))
                    {
                        // Create new container and fill it with own panels or containers.
                        DockContainer cont = new DockContainer();
                        cont.removeable = removeable;
                        removeable = true;
                        cont.DockBorder = dockBorder;
                        cont.DockType = dockType;

                        disableOnControlRemove = true;
                        while (containerList.Count > 0)
                            cont.Controls.Add(containerList[0] as DockContainer);
                        disableOnControlRemove = false;

                        containerList.Add(cont);

                        DockPanel temp = ActivePanel;
                        while (panelList.Count > 0)
                            cont.Controls.Add(panelList[0] as DockPanel);
                        cont.ActivePanel = temp;

                        this.Controls.Add(cont);
                        cont.Dock = DockStyle.Fill;

                        // Add the container to the list object.
                        containerList.Add(e.Target);
                        this.Controls.Add(e.Target);
                    }

                    // Add the panel.
                    e.Target.AddPanel(wnd, e.Point);

                    // Set focus.
                    this.TopLevelControl.BringToFront();
                    this.TopLevelControl.Invalidate(true);
                    e.Target.ActivePanel.Focus();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        /// <summary>
        /// The MouseUp event handler of the drag panel.
        /// Used to handle resizing of the container.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">A MouseEventArgs that contains the mouse data.</param>
        private void dragPanel_MouseUp(object sender, MouseEventArgs e)
        {
            // If resizing, release dummy and set new size.
            if (resizing)
            {
                resizing = false;

                // Release dummy.
                Parent.Controls.Remove(dragDummy);
                Parent.Invalidate();
                dragDummy.Dispose();
                dragDummy = null;

                // Set new size according to the actual state.
                ptStart = new Point(e.X+dragPanel.Left, e.Y+dragPanel.Top);

                if (this.Dock == DockStyle.Left)
                {
                    if (ptStart.X < dockBorder*3)
                        ptStart.X = dockBorder*3;
                    else if (ptStart.X > this.Parent.Width-dockBorder*3)
                        ptStart.X = this.Parent.Width-dockBorder*3;
                }
                else if (this.Dock == DockStyle.Right)
                {
                    if (ptStart.X > this.Width-dockBorder*3)
                        ptStart.X = this.Width-dockBorder*3;
                    else if (ptStart.X < this.Width-this.Parent.Width+dockBorder*3)
                        ptStart.X = this.Width-this.Parent.Width+dockBorder*3;
                }
                else if (this.Dock == DockStyle.Top)
                {
                    if (ptStart.Y < dockBorder*3)
                        ptStart.Y = dockBorder*3;
                    else if (ptStart.Y > this.Parent.Height-dockBorder*3)
                        ptStart.Y = this.Parent.Height-dockBorder*3;
                }
                else if (this.Dock == DockStyle.Bottom)
                {
                    if (ptStart.Y > this.Height-dockBorder*3)
                        ptStart.Y = this.Height-dockBorder*3;
                    else if (ptStart.Y < this.Height-this.Parent.Height+dockBorder*3)
                        ptStart.Y = this.Height-this.Parent.Height+dockBorder*3;
                }

                switch (this.Dock)
                {
                    case DockStyle.Left:
                        if (ptStart.X < 40)
                            this.Width = 40;
                        else
                            this.Width = ptStart.X;
                        break;
                    case DockStyle.Right:
                        int x = 0;

                        if (this.Width - ptStart.X < 40)
                            x = this.Width - 40;
                        else
                            x = ptStart.X;

                        this.Location = new Point(this.Location.X+x, this.Location.Y);
                        this.Width -= x;
                        break;
                    case DockStyle.Top:
                        if (ptStart.Y < 60)
                            this.Height = 60;
                        else
                            this.Height = ptStart.Y;
                        break;
                    case DockStyle.Bottom:
                        int y = 0;

                        if (this.Height - ptStart.Y < 60)
                            y = this.Height - 60;
                        else
                            y = ptStart.Y;

                        this.Location = new Point(this.Location.X, this.Location.Y+y);
                        this.Height -= y;
                        break;
                }
            }
        }
        /// <summary>
        /// The MouseDown event handler of the drag panel.
        /// Used to handle resizing of the container.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">A MouseEventArgs that contains the mouse data.</param>
        private void dragPanel_MouseDown(object sender, MouseEventArgs e)
        {
            // Copy last point.
            ptStart = new Point(e.X+dragPanel.Left, e.Y+dragPanel.Top);

            // Create dummy container.
            dragDummy = new DockContainer();
            dragDummy.isDragContainer = true;

            // Set size and location.
            if ((this.Dock == DockStyle.Left) || (this.Dock == DockStyle.Right))
            {
                dragDummy.Location = new Point(this.Location.X+ptStart.X-2, this.Location.Y);
                dragDummy.Size = new Size(4, this.Height);
            }
            else
            {
                dragDummy.Location = new Point(this.Location.X, this.Location.Y+ptStart.Y-2);
                dragDummy.Size = new Size(this.Width, 4);
            }

            // Add container to parent and resizing flag.
            Parent.Controls.Add(dragDummy);
            dragDummy.BringToFront();
            resizing = true;
        }
 /// <summary>
 /// Removes a child container from the internal list and disposes it.
 /// The other container will be transferred back to the host container at the call of the OnControlRemoved method.
 /// </summary>
 /// <param name="cont">The DockContainer that is to be removed.</param>
 protected void RemoveContainer(DockContainer cont)
 {
     if (this.Controls.Contains(cont))
     {
         this.Controls.Remove(cont);
         cont.Dispose();
         cont = null;
     }
 }