Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / Windows Forms

Storm - the world's best IDE framework for .NET

Rate me:
Please Sign up or sign in to vote.
4.96/5 (82 votes)
4 Feb 2010LGPL311 min read 274.6K   6.5K   340  
Create fast, flexible, and extensible IDE applications easily with Storm - it takes nearly no code at all!
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

using Storm.TextEditor.Win32;
using Storm.TextEditor.Win32.Enums;

namespace Storm.TextEditor.Core.Splitting
{
	[ToolboxItem(false)]
	public class SplitViewControl
		: Control
	{
		#region Fields

		private Panel vertical   = null;
		private Panel horizontal = null;
		private Panel center     = null;

		private Control upperLeft  = null;
		private Control upperRight = null;
		private Control lowerLeft  = null;
		private Control lowerRight = null;

		private Point prevPos   = new Point(0);
		private bool  firstTime = false;

		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private Container components = null;

		private SizeAction action   = SizeAction.None;
		private Point      startPos = new Point(0, 0);

		#region Events

		/// <summary>
		/// Occurs when the split view is resizing.
		/// </summary>
		public event EventHandler Resizing = null;

		/// <summary>
		/// Occurs when the top split view is hidden.
		/// </summary>
		public event EventHandler HideTop = null;

		/// <summary>
		/// Occurs when the left split view is hidden.
		/// </summary>
		public event EventHandler HideLeft = null;

		#endregion

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the distance, in pixels, between the vertical split view's left edge and the SplitViewControl's left edge.
		/// </summary>
		public int VerticalEdgeDistance
		{
			get { return vertical.Left; }
			set
			{
				vertical.Left = value;
				this.DoResize();
			}
		}

		/// <summary>
		/// Gets or sets the distance, in pixels, between the horizontal split view's top edge and the SplitViewControl's top edge.
		/// </summary>
		public int HorizontalEdgeDistance
		{
			get { return horizontal.Top; }
			set
			{
				horizontal.Top = value;
				this.DoResize();
			}
		}

		/// <summary>
		/// Gets or sets the Control that should be confined in the upper left split view.
		/// </summary>
		public Control UpperLeft
		{
			get { return upperLeft; }
			set
			{
				upperLeft = value;
				this.DoResize();
			}
		}

		/// <summary>
		/// Gets or sets the Control that should be confined in the upper right split view.
		/// </summary>
		public Control UpperRight
		{
			get { return upperRight; }
			set
			{
				upperRight = value;
				this.DoResize();
			}
		}

		/// <summary>
		/// Gets or sets the Control that should be confined in the lower left split view.
		/// </summary>
		public Control LowerLeft
		{
			get { return lowerLeft; }
			set
			{
				lowerLeft = value;
				this.DoResize();
			}
		}

		/// <summary>
		/// Gets or sets the Control that should be confined in the lower right split view.
		/// </summary>
		public Control LowerRight
		{
			get { return lowerRight; }
			set
			{
				lowerRight = value;
				this.DoResize();
			}
		}

		#endregion

		#region Methods

		#region Protected

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

			base.Dispose(disposing);
		}

		protected override void OnResize(EventArgs e)
		{
			// Update by calling DoResize.
			this.DoResize();
		}

		protected override void OnControlAdded(ControlEventArgs e)
		{
			// Update by calling DoResize.
			this.DoResize();
		}

		#endregion

		#region Private

		/// <summary>
		/// Raises the Resizing event.
		/// </summary>
		private void OnResizing()
		{
			if (this.Resizing != null)
				this.Resizing(this, new EventArgs());
		}

		/// <summary>
		/// Raises the HideLeft event.
		/// </summary>
		private void OnHideLeft()
		{
			if (this.HideLeft != null)
				this.HideLeft(this, new EventArgs());
		}

		/// <summary>
		/// Raises the HideTop event.
		/// </summary>
		private void OnHideTop()
		{
			if (this.HideTop != null)
				this.HideTop(this, new EventArgs());
		}

		/// <summary>
		/// Contains logic for updating the visible Controls in the SplitViewControl.
		/// </summary>
		private void DoResize()
		{
			int newHeight = this.Height;
			int newWidth = this.Width;

			if (newHeight != 0 && newWidth != 0)
			{
				this.SuspendLayout();

				this.Resize2();
				this.OnResizing();

				if (horizontal.Top < 15)
				{
					horizontal.Top = 0 - horizontal.Height;
					this.OnHideTop();
				}

				if (vertical.Left < 15)
				{
					vertical.Left = 0 - vertical.Width;
					this.OnHideLeft();
				}

				horizontal.Width = this.Width;
				vertical.Height  = this.Height;

				horizontal.SendToBack();
				vertical.SendToBack();

				horizontal.BackColor = SystemColors.Control;
				vertical.BackColor   = SystemColors.Control;

				int rightLeft     = vertical.Left + vertical.Width;
				int rightLowerTop = horizontal.Top + horizontal.Height;
				int rightWidth    = this.Width - rightLeft;
				int lowerHeight   = this.Height - rightLowerTop;
				int upperHeight   = horizontal.Top;
				int leftWidth     = vertical.Left;

				if (lowerRight != null)
				{
					lowerRight.BringToFront();
					lowerRight.SetBounds(rightLeft, rightLowerTop, rightWidth, lowerHeight);
				}
				if (upperRight != null)
				{
					upperRight.BringToFront();
					upperRight.SetBounds(rightLeft, 0, rightWidth, upperHeight);
				}

				if (lowerLeft != null)
				{
					lowerLeft.BringToFront();
					lowerLeft.SetBounds(0, rightLowerTop, leftWidth, lowerHeight);
				}

				if (upperLeft != null)
				{
					upperLeft.BringToFront();
					upperLeft.SetBounds(0, 0, leftWidth, upperHeight);
				}

				this.ResumeLayout();
			}
		}

		private void OnHorizontalMouseDown(object sender, MouseEventArgs e)
		{
			action = SizeAction.SizeH;
			startPos = new Point(e.X, e.Y);

			horizontal.BringToFront();
			horizontal.BackColor = SystemColors.ControlDark;

			firstTime = true;
		}

		private void OnVerticalMouseDown(object sender, MouseEventArgs e)
		{
			action = SizeAction.SizeV;
			startPos = new Point(e.X, e.Y);

			vertical.BringToFront();
			vertical.BackColor = SystemColors.ControlDark;

			firstTime = true;
		}

		private void OnCenterMouseDown(object sender, MouseEventArgs e)
		{
			action = SizeAction.SizeA;
			startPos = new Point(e.X, e.Y);

			vertical.BringToFront();
			horizontal.BringToFront();

			vertical.BackColor = SystemColors.ControlDark;
			horizontal.BackColor = SystemColors.ControlDark;

			firstTime = true;
		}

		private void OnHorizontalMouseUp(object sender, MouseEventArgs e)
		{
			int x = 0;
			int y = startPos.Y - e.Y;
			this.Resize(x, y);

			action = SizeAction.None;
			this.DoResize();	// Update
		}

		private void OnVerticalMouseUp(object sender, MouseEventArgs e)
		{
			int x = startPos.X - e.X;
			int y = 0;
			this.Resize(x, y);

			action = SizeAction.None;
			this.DoResize();	// Update.
		}

		private void OnCenterMouseUp(object sender, MouseEventArgs e)
		{
			int x = startPos.X - e.X;
			int y = startPos.Y - e.Y;
			this.Resize(x, y);

			action = SizeAction.None;
			this.DoResize();	// Update.
		}

		private void OnHorizontalMouseMove(object sender, MouseEventArgs e)
		{
			if (action == SizeAction.SizeH && e.Button == MouseButtons.Left)
			{
				Point start;
				int x = e.X;
				int y = e.Y;

				if (y + horizontal.Top > Height - 4)
					y = Height - 4 - horizontal.Top;
				if (y + horizontal.Top < 0)
					y = 0 - horizontal.Top;

				if (firstTime == false)
				{
					start = this.PointToScreen(this.Location);
					start.Y += prevPos.Y + horizontal.Location.Y;
					ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, this.Width, 3), Color.Black);
				}
				else
					firstTime = false;

				start = this.PointToScreen(this.Location);
				start.Y += y + horizontal.Location.Y;
				ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, this.Width, 3), Color.Black);

				prevPos = new Point(x, y);
			}
		}

		private void OnVerticalMouseMove(object sender, MouseEventArgs e)
		{
			if (action == SizeAction.SizeV && e.Button == MouseButtons.Left)
			{
				Point start;
				int x = e.X;
				int y = e.Y;

				if (x + vertical.Left > Width - 4)
					x = Width - 4 - vertical.Left;
				if (x + vertical.Left < 0)
					x = 0 - vertical.Left;

				if (firstTime == false)
				{
					start = this.PointToScreen(this.Location);
					start.X += prevPos.X + vertical.Location.X;
					ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, 3, this.Height), Color.Black);
				}
				else
					firstTime = false;

				start = this.PointToScreen(this.Location);
				start.X += x + vertical.Location.X;
				ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, 3, this.Height), Color.Black);

				prevPos = new Point(x, y);
			}
		}

		private void OnCenterMouseMove(object sender, MouseEventArgs e)
		{
			if (action == SizeAction.SizeA && e.Button == MouseButtons.Left)
			{
				Point start;
				int x = e.X - center.Width / 2;
				int y = e.Y - center.Height / 2;

				if (firstTime == false)
				{
					start = this.PointToScreen(this.Location);
					start.X += prevPos.X + vertical.Location.X;
					ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, 3, this.Height), Color.Black);

					start = this.PointToScreen(this.Location);
					start.Y += prevPos.Y + horizontal.Location.Y;
					ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, this.Width, 3), SystemColors.ControlDark);
				}
				else
					firstTime = false;

				start = this.PointToScreen(this.Location);
				start.X += x + vertical.Location.X;
				ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, 3, this.Height), Color.Black);

				start = this.PointToScreen(this.Location);
				start.Y += y + horizontal.Location.Y;
				ControlPaint.FillReversibleRectangle(new Rectangle(start.X, start.Y, this.Width, 3), SystemColors.ControlDark);

				prevPos = new Point(x, y);
			}
		}

		private new void Resize(int x, int y)
		{
			this.SuspendLayout();

			int xx = vertical.Left - x;
			int yy = horizontal.Top - y;

			if (xx < 0)
				xx = 0;

			if (yy < 0)
				yy = 0;

			if (yy > this.Height - horizontal.Height - SystemInformation.VerticalScrollBarWidth * 3)
				yy = this.Height - horizontal.Height - SystemInformation.VerticalScrollBarWidth * 3;


			if (xx > this.Width - vertical.Width - SystemInformation.VerticalScrollBarWidth * 3)
				xx = this.Width - vertical.Width - SystemInformation.VerticalScrollBarWidth * 3;

			if (xx != vertical.Left)
				vertical.Left = xx;

			if (yy != horizontal.Top)
				horizontal.Top = yy;

			int centerY = (horizontal.Top + horizontal.Height / 2) - center.Height / 2;
			int centerX = (vertical.Left + vertical.Width / 2) - center.Width / 2;

			center.Location = new Point(centerX, centerY);
			this.ResumeLayout();
			this.Invalidate();

			try
			{
				if (upperLeft != null)
					upperLeft.Refresh();

				if (upperLeft != null)
					upperLeft.Refresh();

				if (upperLeft != null)
					upperLeft.Refresh();

				if (upperLeft != null)
					upperLeft.Refresh();
			}
			catch
			{
			}

			this.OnResizing();
		}

		private void Resize2()
		{
			int xx = vertical.Left;
			int yy = horizontal.Top;

			if (xx < 0)
				xx = 0;

			if (yy < 0)
				yy = 0;

			if (yy > this.Height - horizontal.Height - SystemInformation.VerticalScrollBarWidth * 3)
			{
				yy = this.Height - horizontal.Height - SystemInformation.VerticalScrollBarWidth * 3;
				if (yy != horizontal.Top)
					horizontal.Top = yy;
			}

			if (xx > this.Width - vertical.Width - SystemInformation.VerticalScrollBarWidth * 3)
			{
				xx = this.Width - vertical.Width - SystemInformation.VerticalScrollBarWidth * 3;
				if (xx != vertical.Left)
					vertical.Left = xx;
			}

			int centerY = (horizontal.Top + horizontal.Height / 2) - center.Height / 2;
			int centerX = (vertical.Left + vertical.Width / 2) - center.Width / 2;

			center.Location = new Point(centerX, centerY);
		}

		private void OnCenterDoubleClick(object sender, EventArgs e)
		{
			horizontal.Top = -100;
			vertical.Left = -100;
			this.DoResize();
		}

		private void OnVerticalDoubleClick(object sender, EventArgs e)
		{
			vertical.Left = -100;
			this.DoResize();
		}

		private void OnHorizontalDoubleClick(object sender, EventArgs e)
		{
			horizontal.Top = -100;
			this.DoResize();
		}

		#endregion

		#region Public

		/// <summary>
		/// Splits the horizontal split view 50 percent.
		/// </summary>
		public void SplitHorizontalHalf()
		{
			horizontal.Top = Height / 2;
			this.DoResize();
		}

		/// <summary>
		/// Splits the vertical split view 50 percent.
		/// </summary>
		public void SplitVerticalHalf()
		{
			vertical.Left = Width / 2;
			this.DoResize();
		}

		/// <summary>
		/// Resets the split views.
		/// </summary>
		public void ResetSplitview()
		{
			vertical.Left = 0;
			horizontal.Top = 0;
			this.DoResize();
		}

		/// <summary>
		/// Start dragging the horizontal splitter.
		/// </summary>
		public void InvokeMouseDownHorizontal()
		{
			IntPtr hwnd = horizontal.Handle;
			NativeUser32Api.SendMessage(hwnd, (int)WindowMessage.WM_LBUTTONDOWN, 0, 0);
		}

		/// <summary>
		/// Start dragging the vertical splitter.
		/// </summary>
		public void InvokeMouseDownVertical()
		{
			IntPtr hwnd = vertical.Handle;
			NativeUser32Api.SendMessage(hwnd, (int)WindowMessage.WM_LBUTTONDOWN, 0, 0);
		}

		#endregion

		#endregion

		/// <summary>
		/// Initializes a new instance of SplitViewControl.
		/// </summary>
		public SplitViewControl()
		{
			// Required by the Windows Forms Designer.
			InitializeComponent();

			this.SetStyle(ControlStyles.ContainerControl, true);

			this.DoResize();
			this.Resize(0, 0);
		}

		#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()
		{
			vertical = new System.Windows.Forms.Panel();
			horizontal = new System.Windows.Forms.Panel();
			center = new System.Windows.Forms.Panel();
			SuspendLayout();
			// 
			// Vertical
			// 
			vertical.BackColor = System.Drawing.SystemColors.Control;
			vertical.Cursor = System.Windows.Forms.Cursors.VSplit;
			vertical.Name = "Vertical";
			vertical.Size = new System.Drawing.Size(4, 264);
			vertical.TabIndex = 0;
			vertical.MouseUp += new System.Windows.Forms.MouseEventHandler(OnVerticalMouseUp);
			vertical.DoubleClick += new System.EventHandler(OnVerticalDoubleClick);
			vertical.MouseMove += new System.Windows.Forms.MouseEventHandler(OnVerticalMouseMove);
			vertical.MouseDown += new System.Windows.Forms.MouseEventHandler(OnVerticalMouseDown);
			// 
			// Horizontal
			// 
			horizontal.BackColor = System.Drawing.SystemColors.Control;
			horizontal.Cursor = System.Windows.Forms.Cursors.HSplit;
			horizontal.Name = "Horizontal";
			horizontal.Size = new System.Drawing.Size(320, 4);
			horizontal.TabIndex = 1;
			horizontal.MouseUp += new System.Windows.Forms.MouseEventHandler(OnHorizontalMouseUp);
			horizontal.DoubleClick += new System.EventHandler(OnHorizontalDoubleClick);
			horizontal.MouseMove += new System.Windows.Forms.MouseEventHandler(OnHorizontalMouseMove);
			horizontal.MouseDown += new System.Windows.Forms.MouseEventHandler(OnHorizontalMouseDown);
			// 
			// Center
			// 
			center.BackColor = System.Drawing.SystemColors.Control;
			center.Cursor = System.Windows.Forms.Cursors.SizeAll;
			center.Location = new System.Drawing.Point(146, 69);
			center.Name = "Center";
			center.Size = new System.Drawing.Size(24, 24);
			center.TabIndex = 2;
			center.MouseUp += new System.Windows.Forms.MouseEventHandler(OnCenterMouseUp);
			center.DoubleClick += new System.EventHandler(OnCenterDoubleClick);
			center.MouseMove += new System.Windows.Forms.MouseEventHandler(OnCenterMouseMove);
			center.MouseDown += new System.Windows.Forms.MouseEventHandler(OnCenterMouseDown);
			// 
			// SplitViewControl
			// 
			BackColor = System.Drawing.Color.Magenta;
			Controls.AddRange(new System.Windows.Forms.Control[]
				{
					center,
					horizontal,
					vertical
				});
			Size = new System.Drawing.Size(200, 200);
			ResumeLayout(false);
		}

		#endregion
	}
}

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 GNU Lesser General Public License (LGPLv3)



Comments and Discussions