Click here to Skip to main content
15,898,134 members
Articles / Programming Languages / Visual Basic

Status List - Vista Style

Rate me:
Please Sign up or sign in to vote.
4.52/5 (12 votes)
31 Mar 2007CPOL1 min read 59.8K   2.3K   90  
A progress list for displaying the status of various tasks
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms.Design
Imports System.Drawing.Drawing2D

<Designer(GetType(StatusListDesigner))> _
Public Class StatusList

#Region " Declarations "

	 Private _Items As New StatusCollection(Me)	' The StatusItem Collection
	 Private highlightedItem As StatusItem	' The currently selected item in the designer
	 Private _FailedImage As Image ' the pending image
	 Private _CompleteImage As Image	' the complete image
	 Private _imageSize As Size = New Size(12, 12) ' the image size
	 Const _pad As Int16 = 3	' the padding between the outer bounds and the image/text
	 Private Indent As Int16 = 30
	 Private _ShowTitle As Boolean = True
	 Private _LineColor As Color = Color.Green

#End Region

#Region " Properties "

	 <Category("Appearance")> _
	 Public Property LineColor() As Color
		  Get
				Return _LineColor
		  End Get
		  Set(ByVal value As Color)
				_LineColor = value
				Me.DrawItems()
		  End Set
	 End Property

	 <Category("Appearance")> _
	 Public Property ShowTitle() As Boolean
		  Get
				Return _ShowTitle
		  End Get
		  Set(ByVal value As Boolean)
				_ShowTitle = value
				Me.DrawItems()
		  End Set
	 End Property

	 <Category("Custom Properties"), Browsable(False), Description("The padding between the outer bounds and the image/text")> _
	 Public ReadOnly Property Pad() As Int16
		  Get
				Return _pad
		  End Get
	 End Property

	 <Category("Custom Properties"), Description("The default image size")> _
	 Public Property ImageSize() As Size
		  Get
				Return _imageSize
		  End Get
		  Set(ByVal value As Size)
				If value.Width < 12 Or value.Height < 12 Then
					 MsgBox("Minimum size is  '12, 12'")
					 Exit Property
				End If

				_imageSize = value
				Me.DrawItems()
		  End Set
	 End Property

	 Public Overrides Property Font() As System.Drawing.Font
		  Get
				Return MyBase.Font
		  End Get
		  Set(ByVal value As System.Drawing.Font)
				MyBase.Font = value
				Me.DrawItems()
		  End Set
	 End Property

	 <Category("Custom Properties"), Description("The image used for pending items")> _
	 Public Property FailedImage() As Image
		  Get
				Return _FailedImage
		  End Get
		  Set(ByVal value As Image)
				_FailedImage = value
				Me.DrawItems()
		  End Set
	 End Property

	 <Category("Custom Properties"), Description("The image used for completed items")> _
	 Public Property CompleteImage() As Image
		  Get
				Return _completeImage
		  End Get
		  Set(ByVal value As Image)
				_completeImage = value
				Me.DrawItems()
		  End Set
	 End Property

	 <Browsable(True), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Category("Data"), Description("Returns a collection of all the status items")> _
	 Public Property Items() As StatusCollection
		  Get
				Return _Items
		  End Get
		  Set(ByVal value As StatusCollection)
				_Items = value
				Me.DrawItems()
		  End Set
	 End Property

#End Region

#Region " Methods "

	 Friend Sub DrawItems()
		  ' ----------------------------
		  ' This methods calculates the layout of all the status items, designating them certain bounds, to stop overflow
		  ' ----------------------------

		  Dim item As StatusItem ' The current item
		  Dim y As Int16 = 0	' Y-Axis position of the current item
		  Dim itemSize As Size ' The size of the current item

		  Dim g As Graphics = Me.CreateGraphics

		  If Not Me.ShowTitle Then
				y = 0
		  Else
				y = g.MeasureString(Me.Text, New Font(Me.Font, FontStyle.Bold)).Height + Pad * 5
		  End If

		  Try
				For Each item In Items
					 ' Measure the string size 
					 itemSize = New Size(g.MeasureString(item.Text, New Font(Me.Font, FontStyle.Bold)).Width - 4, g.MeasureString(item.Text, New Font(Me.Font, FontStyle.Bold)).Height)

					 ' Check if the image height is larger than the current height
					 If ImageSize.Height > itemSize.Height Then
						  ' If it is, resize the control to accommodate it
						  itemSize.Height = ImageSize.Height
					 End If

					 ' Set the bounds of the control to the width of the image, text and associated padding for nicer viewing
					 'item.Bounds = New Rectangle(Pad, y, ImageSize.Width + (Pad * 3) + itemSize.Width + (Pad * 2), (itemSize.Height + Pad * 2))
					 item.Bounds = New Rectangle(Indent, y, itemSize.Width + Pad * 2, itemSize.Height + Pad * 2)
					 If item.Text = "" Then
						  item.Bounds.Width = 10
					 End If

					 ' Set the Y-Axis position of the next item
					 y = item.Bounds.Bottom + 2
				Next
		  Catch ex As Exception
		  End Try

		  g.Dispose()

		  'Mark the control as invalid so it gets redrawn
		  Invalidate()
	 End Sub

	 Public Shadows Property Text() As String
		  Get
				Return MyBase.Text
		  End Get
		  Set(ByVal value As String)
				MyBase.Text = value
				Me.DrawItems()
		  End Set
	 End Property

	 Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
		  MyBase.OnResize(e)

		  ' If the control is resized, re-calculate the items and make the control invalid
		  Me.DrawItems()
	 End Sub

	 Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
		  ' ----------------------------
		  ' This method performs all the painting of the items, text and images.
		  ' ----------------------------
		  e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
		  e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit

		  If Me.ShowTitle Then
				e.Graphics.DrawString(Me.Text, New Font(Me.Font, FontStyle.Bold), New SolidBrush(Me.ForeColor), 0, 0)

				Dim y As Int16 = e.Graphics.MeasureString(Me.Text, New Font(Me.Font, FontStyle.Bold)).Height + Pad * 2
				Dim lin As New LinearGradientBrush(New Point(Pad, 0), New Point(Me.Width - Pad, 0), LineColor, Color.FromArgb(0, LineColor))
				e.Graphics.DrawLine(New Pen(lin), Pad, y, Me.Width - Pad, y)
		  End If

		  ' ----------------------------------------------
		  ' This methods needs to be cleaned up...  Please don't judge just yet!
		  ' ----------------------------------------------

		  Dim item As StatusItem ' The current item	
		  Dim b As Brush = Nothing	' The current brush
		  Dim wrct As Rectangle	' The current item bounds
		  Dim yOffSet As Int16 = 0	' The offSet of each item on the Y-Axis

		  For Each item In Items
				'Create brush from button colour
				If Not (b Is Nothing) Then b.Dispose()
				b = New SolidBrush(Color.FromArgb(180, Color.SteelBlue))

				'Fill rectangle with this colour
				wrct = item.Bounds

				If item.Text = "" And Me.DesignMode Then
					 Dim p As New Pen(Color.Black)
					 p.DashStyle = DashStyle.Dot
					 e.Graphics.DrawRectangle(p, wrct)
				End If

				Select Case item.Status
					 Case StatusItem.CurrentStatus.Complete
						  e.Graphics.DrawImage(Me.CompleteImage, New Rectangle(0, wrct.Top, 24, 24))
					 Case StatusItem.CurrentStatus.Failed
						  e.Graphics.DrawImage(Me.FailedImage, New Rectangle(0, wrct.Top, 24, 24))
					 Case StatusItem.CurrentStatus.Pending
						  e.Graphics.DrawString(item.Text, Me.Font, New SolidBrush(Me.ForeColor), wrct.Left + Pad, wrct.Top + Pad)
					 Case StatusItem.CurrentStatus.Running
						  Dim wid, range As Double
						  range = item.Maximum - item.Minimum
						  wid = (item.Maximum - (item.Maximum - item.Value)) / range

						  wrct.Inflate(-1, 0)
						  e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(255, 227, 247, 255)), wrct.Left, wrct.Top, CInt(wrct.Width * wid), wrct.Height)
						  e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(255, 185, 233, 252)), wrct.Left, wrct.Bottom - CInt(wrct.Height * 0.55), CInt(wrct.Width * wid), wrct.Height - CInt(wrct.Height * 0.55) + 1)
						  wrct.Inflate(1, 0)

						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 147, 201, 227)), wrct.Left + 1, wrct.Top, wrct.Right - 1, wrct.Top)
						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 147, 201, 227)), wrct.Left + 1, wrct.Bottom, wrct.Right - 1, wrct.Bottom)
						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 136, 203, 235)), wrct.Left, wrct.Top + 1, wrct.Left, wrct.Bottom - 1)
						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 105, 187, 227)), wrct.Left, wrct.Bottom - CInt(wrct.Height * 0.55), wrct.Left, wrct.Bottom - 1)
						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 136, 203, 235)), wrct.Right, wrct.Top + 1, wrct.Right, wrct.Bottom - 1)
						  e.Graphics.DrawLine(New Pen(Color.FromArgb(255, 105, 187, 227)), wrct.Right, wrct.Bottom - CInt(wrct.Height * 0.55), wrct.Right, wrct.Bottom - 1)

						  Dim h As Int16 = e.Graphics.MeasureString(wid * 100 & "%", New Font(Me.Font.Name, 7, FontStyle.Regular)).Height
						  e.Graphics.DrawString(wid * 100 & "%", New Font(Me.Font.Name, 7, FontStyle.Regular), New SolidBrush(Me.ForeColor), 0, wrct.Bottom - CInt(wrct.Height / 2) - h / 2)
				End Select

				e.Graphics.DrawString(item.Text, Me.Font, New SolidBrush(Color.FromArgb(220, Me.ForeColor)), wrct.Left + Pad, wrct.Top + Pad)

				If highlightedItem Is item Then
					 wrct.Inflate(-1, -1)
					 e.Graphics.DrawRectangle(New Pen(b, 2), wrct)
				End If
		  Next
	 End Sub

	 Friend Sub OnSelectionChanged()
		  ' ----------------------------
		  ' This methods is called by the StatusLabel control when a selection has changed in design mode
		  ' ----------------------------

		  Dim item As StatusItem
		  Dim newHighlightedItem As StatusItem = Nothing
		  Dim s As ISelectionService = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)

		  'See if the primary selection is one of our buttons
		  For Each item In Items
				If s.PrimarySelection Is item Then
					 newHighlightedItem = item
					 Exit For
				End If
		  Next

		  'Apply if necessary
		  If Not newHighlightedItem Is highlightedItem Then
				highlightedItem = newHighlightedItem
				Invalidate()
		  End If
	 End Sub

	 Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
		  ' ----------------------------
		  ' This methods checks the MouseDown event within the control and determines whether an item was selected, and if so, which one
		  ' ----------------------------

		  Dim wrct As Rectangle	' The current item bounds
		  Dim s As ISelectionService ' Selection service
		  Dim a As ArrayList	' array of selected items
		  Dim item As StatusItem ' the current item

		  If DesignMode Then
				For Each item In Items
					 ' Get the current item bounds
					 wrct = item.Bounds
					 If wrct.Contains(e.X, e.Y) Then
						  ' if the current item has mouse down focus, add it to the array and exit the loop
						  s = DirectCast(GetService(GetType(ISelectionService)), ISelectionService)
						  a = New ArrayList()
						  a.Add(item)
						  s.SetSelectedComponents(a)
						  Exit For
					 End If
				Next
		  End If

		  ' Perform any additional tasks here
		  MyBase.OnMouseDown(e)
	 End Sub

#End Region

	 Public Sub New()
		  ' This call is required by the Windows Form Designer.
		  InitializeComponent()

		  ' Initialisations go here...
		  SetStyle(ControlStyles.AllPaintingInWmPaint, True)
		  SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
		  SetStyle(ControlStyles.ResizeRedraw, True)
		  SetStyle(ControlStyles.SupportsTransparentBackColor, True)

		  ' IMPORTANT!!! This declares the New Collection
		  _Items = New StatusCollection(Me)

		  ' Set the default size of the control
		  Me.Size = New Size(200, 100)
	 End Sub
End Class

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
Software Developer uSoftware
Australia Australia
Shaps currently works as the Senior Networks Administrator for a small IT company in Australia. He is also involved in various software developments, for Windows, Windows Mobile, iPhone, Mac and occasionally the web. His central focus in this area, is User Interface design.

If he had spare time, he'd play some tunes, read a book or visit the gym. Until then, he writes small applications for the iPhone that help improve his productivity at work.

Comments and Discussions