Imports System.ComponentModel

Public Class Gauge
  Inherits System.Windows.Forms.UserControl

#Region " Windows Form Designer generated code "

  Public Sub New()
    If MyBase.Height < 50 Then
      MyBase.Height = 50
    End If
    If MyBase.Width < 90 Then
      MyBase.Width = 90
    End If
    mTall = MyBase.Height * 0.9
    mTopSide = (MyBase.Height - mTall) / 2  ' location of the top edge of the gauge
    mLeftSide = MyBase.Width * 0.5          ' Location of the left edge of the gauge
    mWide = MyBase.Width * 0.4              ' The width of the gauge
    mMin = 0
    mMax = 100
    mCurrent = 50

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

    'Add any initialization after the InitializeComponent() call

  End Sub

  'UserControl1 overrides dispose to clean up the component list.
  Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
      If Not (components Is Nothing) Then
        components.Dispose()
      End If
    End If
    MyBase.Dispose(disposing)
  End Sub

  'Required by the Windows Form Designer
  Private components As System.ComponentModel.IContainer

  'NOTE: The following procedure is required by the Windows Form Designer
  'It can be modified using the Windows Form Designer.  
  'Do not modify it using the code editor.
  <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
    components = New System.ComponentModel.Container()
  End Sub

#End Region

  '================== Data Members =====================
  Private mMin As Double          'Minimum gauge value
  Private mMax As Double          'Maximum gauge value
  Private mDanger As Double       'Redline dangervalue
  Private mCaution As Double      'Yellowline cautionary value
  Private mRange As Double        'The range of gauge values
  Private mCurrent As Double      'Current gauge value
  Private mTick As Double         'A tick mark on the scale

  Private mGap As Integer         'The range between tick marks
  Private mTall As Integer        'How tall is the gauge
  Private mWide As Integer        'How wide is the gauge
  Private mLeftSide As Integer    'Where is the left side of the gauge
  Private mTopSide As Integer     'Where is the top of the gauge


  '================== The Property Procedures =====================
  <Description("The minimum gauge value"), _
  Category("Appearance")> _
  Property Minimum() As Double    ' Minimum
    Get
      Return mMin
    End Get
    Set(ByVal Value As Double)
      mMin = Value
    End Set

  End Property

  <Description("The maximum gauge value"), _
  Category("Appearance")> _
  Property Maximum() As Double      ' Maximum
    Get
      Return mMax
    End Get
    Set(ByVal Value As Double)
      mMax = Value
    End Set

  End Property

  <Description("The gauge danger value where the color changes to red"), _
  Category("Appearance")> _
  Property Danger() As Double       ' The redline danger value
    Get
      Return mDanger
    End Get
    Set(ByVal Value As Double)
      mDanger = Value
    End Set
  End Property

  <Description("The gauge caution value where the color changes to yellow"), _
  Category("Appearance")> _
  Property Caution() As Double      ' The yellowline cautionary value
    Get
      Return mCaution
    End Get
    Set(ByVal Value As Double)
      mCaution = Value
    End Set
  End Property

  <Description("The gauge height"), _
  Category("Appearance")> _
  Property Tall() As Integer          ' How tall is the gauage?
    Get
      Return mTall
    End Get
    Set(ByVal Value As Integer)
      mTall = Value
    End Set
  End Property

  <Description("The gauge width"), _
  Category("Appearance")> _
  Property Wide() As Integer          ' How wide is the gauage?
    Get
      Return mWide
    End Get
    Set(ByVal Value As Integer)
      mWide = Value
    End Set
  End Property

  <Description("The left edge location of the gauge"), _
  Category("Appearance")> _
  Property LeftSide() As Integer        ' Where is the left side of the gauge on 
    Get                                 ' the form?
      Return mLeftSide
    End Get
    Set(ByVal Value As Integer)
      mLeftSide = Value
    End Set
  End Property

  <Description("The top edge location of the gauge"), _
  Category("Appearance")> _
  Property TopSide() As Integer        ' Where is the top of the gauge on 
    Get                                 ' the form?
      Return mTopSide
    End Get
    Set(ByVal Value As Integer)
      mTopSide = Value
    End Set
  End Property

  <Description("The present value of the gauge"), _
  Category("Data")> _
  Property Current() As Double        ' Where is the top of the gauge on 
    Get                               ' the form?
      Return mCurrent
    End Get
    Set(ByVal Value As Double)
      mCurrent = Value
    End Set
  End Property

  '==================== Methods ========================
  Private Sub SetGaugeParameters()
    ' Purpose:  This subroutine sets some of the parameters that are 
    '           used by the gauage.
    '
    ' Argument list:
    '   none
    '
    ' Return value:
    '   n/a
    '
    If mCurrent > mMax Then         ' Value too large?
      mCurrent = mMax
    End If

    If mCurrent < mMin Then
      mCurrent = mMin
    End If
    mRange = mMax - mMin            ' Find the gauge range of values
    mTick = mRange / 5.0            ' Find where tick marks should start
    mGap = mTall / 5                ' Find the gaps between tick marks

  End Sub

  Private Sub Gauge_Resize(ByVal sender As Object, ByVal e As _
              System.EventArgs) Handles MyBase.Resize
    Dim ControlWidth As Integer = Me.ClientRectangle.Width
    Dim ControlHeight As Integer = Me.ClientRectangle.Height

    If ControlHeight < 50 Then        ' Set a minimum control height
      ControlHeight = 50
      Me.Height = 50
    End If

    If ControlWidth < 50 Then       ' Set a minimum control width
      ControlWidth = 50
      Me.Width = ControlWidth
    End If

    mTall = Me.Height * 0.9
    mTopSide = (Me.Height - mTall) / 2  ' location of the top edge of the gauge
    mLeftSide = Me.Width * 0.05         ' Location of the left edge of the gauge
    mWide = Me.Width * 0.2              ' The width of the gauge

    Invalidate()

  End Sub

  Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    ' Purpose:  This subroutine overrides the OnPaint() event to draw
    '           the gauge
    '
    ' Argument list:
    '   e             the paint event arguments
    '
    ' Return value:
    '   n/a
    '
    ' CAUTION:  As written, this code assumes there are valid values
    '           for mTop, mLeftSide, mTall, and mWide. No checks are
    '           performed.

    Dim Canvas As Graphics = e.Graphics
    Dim MyPen As Pen = New Pen(Color.Black)
    Dim MyBrush As SolidBrush = New SolidBrush(Color.Green)
    Dim MyStyle As FontStyle = FontStyle.Regular
    Dim MyFont As Font = New Font("Microsoft Sans Serif", 8, MyStyle)
    Dim NumberOffset As Integer, buff As String
    Dim TickOffset As Integer, TopOffset As Integer, TickValues As Double
    Dim i As Integer

    SetGaugeParameters()                  ' Calculate some initial values

    If mCaution <> 0 Or mDanger <> 0 Then ' have they set yellow or red lines?
      If mCurrent >= mCaution Then        ' See if value requires a color change
        MyBrush.Color = Color.Yellow
      End If
      If mCurrent >= mDanger Then
        MyBrush.Color = Color.Red
      End If
    End If

    ' Draw a rectangle and then fill it with a background color
    Canvas.DrawRectangle(MyPen, mLeftSide, mTopSide, mWide, mTall)
    Canvas.FillRectangle(MyBrush, mLeftSide + 1, mTopSide + 1, mWide - 1, mTall - 1)

    MyBrush.Color = Color.Black        ' Reset brush color for numbers

    TickOffset = mWide + mLeftSide
    TickValues = mMax
    NumberOffset = MyFont.GetHeight(Canvas) / 2

    For i = 0 To 4                        ' Draw the tick marks and values
      TopOffset = mTopSide + i * mGap     ' First, draw tick marks
      Canvas.DrawLine(MyPen, TickOffset, TopOffset, TickOffset + 3, TopOffset)
      buff = Format(TickValues - mTick * i, ".00")    ' Now draw scale values
      Canvas.DrawString(buff, MyFont, MyBrush, TickOffset + 5, TopOffset - NumberOffset)
    Next i

    ' Need this because of possible rounding errors for pixel values when drawing
    ' the minimum value tick mark. It draw the minimum tick and value
    Canvas.DrawLine(MyPen, TickOffset, mTopSide + mTall, TickOffset + 3, mTopSide + mTall)
    Canvas.DrawString(CStr(mMin), MyFont, MyBrush, TickOffset + 5, mTopSide + mTall - NumberOffset)

    ' Now draw a filled rectange for the UNUSED portion of the gauge
    ' using a white brush
    MyBrush.Color = Color.White
    ' This determines how "deep" to draw the new rectangle. The adjustments
    ' by +/- 1 pixel is so we don't overwrite the guage border
    i = (1.0 - mCurrent / mRange) * mTall + (mMin / mRange) * mTall - 1
    Canvas.FillRectangle(MyBrush, mLeftSide + 1, mTopSide + 1, mWide - 1, i)

  End Sub



End Class
