Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C# 4.0

Writing a P2P Snippet sharing Extension for Visual Studio 2010 (VSX 2010)

Rate me:
Please Sign up or sign in to vote.
4.50/5 (6 votes)
31 Mar 2010GPL311 min read 36.4K   332   21  
CodeXchange is a simple Visual Studio extension which allows you to create, edit and share snippets with your peers without leaving the Visual Studio 2010 IDE.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Imaging;

namespace Sand.Services.CodeXchange.Client.Controls
{
	/// <summary>
	/// Panel control with a themeable header that can expand and collapse
	/// </summary>
	public class ExplorerGroup : Panel 
	{
		/// <summary>
		/// Event raised when the control expands or collapses
		/// </summary>
		public event EventHandler ExpandedChanged;

		private const int CHEVRON_X_PADDING = 22;
		private const int CHEVRON_Y_PADDING = 4;

		private bool m_Expanded = true;
		private bool m_MosueIsOverTitle = false;
		private int m_PanelHeight;

		private string m_Title = string.Empty;
		private Bitmap m_Icon = null;

		private System.ComponentModel.IContainer components;
		protected System.Windows.Forms.Label TitleLabel;


		public ExplorerGroup()
		{
			components = new System.ComponentModel.Container();

			InitializeComponent();
		}


		[Category("Appearance"), Description("The text contained in the control")]
		[Browsable(true)]
		public override string Text
		{
			get
			{
				return m_Title;
			}
			set
			{
				m_Title = value;
				Refresh();
			}
		}


		[Category("Appearance"), Description("Determines whether the panel's contents are shown or not")]
		[DefaultValue (true)]
		[Browsable(true)]
		public bool Expanded
		{
			get
			{
				return m_Expanded;
			}
			set
			{
				m_Expanded = value;
				OnExpandedChanged();
			}
		}

		[Category("Appearance"), Description("")]
		[Browsable(true)]
		public Bitmap Icon
		{
			get
			{
				return m_Icon;
			}
			set
			{
				m_Icon = value;
				Refresh();
			}
		}

		/// <summary>
		/// Updates the display to reflect the current expansion state
		/// </summary>
		private void ChangeExpansionDisplay()
		{
			if ( m_Expanded )
				Height = m_PanelHeight;
			else
			{
				m_PanelHeight = Height;
				Height = TitleLabel.Height;
			}
		}

		private Rectangle HeaderBounds
		{
			get
			{
				return new Rectangle( 0, 0, TitleLabel.Bounds.Width, TitleLabel.Bounds.Height );
			}
		}

		/// <summary>
		/// Called in order to raise the ExpandedChanged event
		/// </summary>
		protected void OnExpandedChanged()
		{		
			ChangeExpansionDisplay();

			if ( ExpandedChanged != null )
				ExpandedChanged( this, EventArgs.Empty );

			Refresh();
		}

		private void DrawChevrons(Graphics g, int x, int y, int offset)
		{
			// Determine the orientation of the pseudo-button
			if (!Expanded)
			{
				DrawChevron(g, x + offset + 1, y + 1*offset, -offset);
				DrawChevron(g, x + offset + 1, y + 2*offset, -offset);
			}
			else
			{
				DrawChevron(g, x + offset + 1, y + 2*offset, offset);
				DrawChevron(g, x + offset + 1, y + 3*offset, offset);
			}   
		}

		private void DrawChevron(Graphics g, int x, int y, int offset)
		{
			Pen p = new Pen(Color.White);
			Point[] points = { new Point(x, y),
								 new Point(x+Math.Abs(offset), y-offset),
								 new Point(x+2*Math.Abs(offset), y)
							 };
			g.DrawLines(p, points);
			p.Dispose();
		}

		/// <summary>
		/// Draws the header portion of the control
		/// </summary>
		/// <param name="graphics">Graphics object used for painting</param>
		protected void DrawHeader( Graphics graphics )
		{
			int x = TitleLabel.Bounds.Right - CHEVRON_X_PADDING;
			int y = TitleLabel.Bounds.Top + CHEVRON_Y_PADDING;

			Rectangle rect = new Rectangle( x, y, 12, 12 );
			Rectangle rect1 = new Rectangle(  x + ( rect.Width / 3 ) - 2, y + 3, 12, 12 );

			DrawChevrons ( graphics , 
				rect1.X , 
				rect1.Y , 
				rect1.Width / 4);

			DrawChevronEdge( graphics );
			DrawHeaderIcon ( graphics );
			DrawHeaderTitle ( graphics );

			if (m_MosueIsOverTitle)
			{
				TitleLabel.BackColor = System.Drawing.SystemColors.ActiveCaption;
			}
			else
			{
				TitleLabel.BackColor = System.Drawing.SystemColors.AppWorkspace;
			}
		}

		protected void DrawHeaderTitle( Graphics graphics )
		{
			using (Brush brush = new SolidBrush (System.Drawing.SystemColors.ActiveCaptionText))
			{
				Font font = new Font (Font.FontFamily , Font.Size , FontStyle.Bold);

				if (m_Icon != null)
				{
					graphics.DrawString (
						m_Title ,
						font ,
						brush , 
						20 , 
						4 , 
						StringFormat.GenericDefault);
				}
				else
				{
					graphics.DrawString (
						m_Title , 
						font , 
						brush , 
						4 , 
						4 , 
						StringFormat.GenericDefault);
				}
			}
		}

		protected void DrawHeaderIcon( Graphics graphics )
		{
			if (m_Icon != null)
				graphics.DrawImage (m_Icon , 4 , 4);
		}

		/// <summary>
		/// Draw a faint rectangle around the chevron if the mouse if currently over the title bar
		/// </summary>
		/// <param name="graphics">Graphics object used for painting</param>
		private void DrawChevronEdge( Graphics graphics )
		{
			if( m_MosueIsOverTitle )
			{
				Rectangle bounds = TitleLabel.Bounds;

				int x = bounds.Right - CHEVRON_X_PADDING;
				int y = bounds.Top + CHEVRON_Y_PADDING;

				Pen lightPen = new Pen( SystemColors.ControlLightLight );
				Pen darkPen = new Pen( Color.DarkGray );

				Rectangle rect = new Rectangle( x, y, 18 , 16);

				graphics.DrawLine( lightPen, x, y, x, y + rect.Height );
				graphics.DrawLine( lightPen, x, y, x + rect.Width, y );

				graphics.DrawLine( darkPen, x + rect.Width, y, x + rect.Width, y + rect.Height );
				graphics.DrawLine( darkPen, x + rect.Width, y + rect.Height, x, y + rect.Height );
			}		
		}

		#region Constituent Control Events
		private void TitleLabel_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if( e.Button == MouseButtons.Left && TitleLabel.Bounds.Contains( e.X, e.Y ) )
				Expanded = !Expanded;			
		}

		private void CollapsiblePanel_MouseLeave(object sender, System.EventArgs e)
		{
			TitleLabel.Cursor = Cursors.Default;
			m_MosueIsOverTitle = false;
			TitleLabel.Refresh();
		}

		private void TitleLabel_MouseLeave(object sender, System.EventArgs e)
		{
			TitleLabel.Cursor = Cursors.Default;
			m_MosueIsOverTitle = false;
			TitleLabel.Refresh();	
		}

		private void TitleLabel_MouseEnter(object sender, System.EventArgs e)
		{
			TitleLabel.Cursor = Cursors.Hand;
			m_MosueIsOverTitle = true;
			TitleLabel.Refresh();		
		}

		private void TitleLabel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			//when the title is painted do the cutom rendering 
			DrawHeader( e.Graphics );
		}		
		#endregion

		#region Windows Form Designer generated code
		private void InitializeComponent()
		{
			this.TitleLabel = new System.Windows.Forms.Label();
			this.SuspendLayout();
			// 
			// TitleLabel
			// 
			this.TitleLabel.BackColor = System.Drawing.SystemColors.AppWorkspace;
			this.TitleLabel.Cursor = System.Windows.Forms.Cursors.Default;
			this.TitleLabel.Dock = System.Windows.Forms.DockStyle.Top;
			this.TitleLabel.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.TitleLabel.ForeColor = System.Drawing.SystemColors.HighlightText;
			this.TitleLabel.Location = new System.Drawing.Point(17, 17);
			this.TitleLabel.Name = "TitleLabel";
			this.TitleLabel.Size = new System.Drawing.Size(200, 24);
			this.TitleLabel.TabIndex = 0;
			this.TitleLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.TitleLabel.Paint += new System.Windows.Forms.PaintEventHandler(this.TitleLabel_Paint);
			this.TitleLabel.MouseEnter += new System.EventHandler(this.TitleLabel_MouseEnter);
			this.TitleLabel.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TitleLabel_MouseUp);
			this.TitleLabel.MouseLeave += new System.EventHandler(this.TitleLabel_MouseLeave);
			// 
			// ExplorerGroup
			// 
			this.Controls.Add(this.TitleLabel);
			this.MouseLeave += new System.EventHandler(this.CollapsiblePanel_MouseLeave);
			this.ResumeLayout(false);

		}
		#endregion

		#region Disposer
		/// <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

	}
}

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 General Public License (GPLv3)


Written By
Software Developer
Spain Spain
Hi! I'm 22 years old. I live in a sunny mediterranian city called Barcelona.

I am a big fan of .NET and have been working with c# for a few years now.

Comments and Discussions