Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Data
Imports System.Text
Imports System.Windows.Forms

Public Class ProgressControl
    Inherits Control

    Private NO_MANAGED_BACK_BUFFER As BufferedGraphics = Nothing
    Private GraphicManager As BufferedGraphicsContext
    Private ManagedBackBuffer As BufferedGraphics

    Public Sub New()
        InitializeComponent()

        SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint, True)
        Me.DoubleBuffered = False
        AddHandler Application.ApplicationExit, AddressOf MemoryCleanup
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        GraphicManager = BufferedGraphicsManager.Current
        GraphicManager.MaximumBuffer = New Size(Me.Width + 1, Me.Height + 1)
        ManagedBackBuffer = GraphicManager.Allocate(Me.CreateGraphics(), ClientRectangle)
    End Sub

    Public Property Max() As Single
        Get
            Return maxValue
        End Get
        Set(ByVal value As Single)
            maxValue = value
        End Set
    End Property
    Private maxValue As Single

    Public Property Min() As Single
        Get
            Return minValue
        End Get
        Set(ByVal value As Single)
            minValue = value
        End Set
    End Property
    Private minValue As Single

    Public Property ShowMinMax() As Boolean
        Get
            Return showMinMaxValue
        End Get
        Set(ByVal value As Boolean)
            showMinMaxValue = value
        End Set
    End Property
    Private showMinMaxValue As Boolean

    Public Property Value() As Single
        Get
            Return valueValue
        End Get
        Set(ByVal value As Single)
            If value > Max Then value = Max
            If value < Min Then value = Min
            valueValue = value
            Me.Invalidate()
        End Set
    End Property
    Private valueValue As Single

    Public Enum VisualType
        Line
        Bar
    End Enum

    Public Property Visualisation() As VisualType
        Get
            Return visualisationValue
        End Get
        Set(ByVal value As VisualType)
            visualisationValue = value
        End Set
    End Property
    Private visualisationValue As VisualType

    Private Sub InitializeComponent()
        Me.SuspendLayout()
        ' 
        ' DoubleBufferControl
        ' 
        Me.BackColor = System.Drawing.Color.Black
        Me.ResumeLayout(False)
    End Sub

    Private Sub MemoryCleanup(ByVal sender As Object, ByVal e As EventArgs)
        If ManagedBackBuffer IsNot NO_MANAGED_BACK_BUFFER Then
            ManagedBackBuffer.Dispose()
        End If
    End Sub

    Private Sub DoubleBufferControl_Resize(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Resize
        GraphicManager.MaximumBuffer = New Size(Me.Width + 1, Me.Height + 1)
        If ManagedBackBuffer IsNot NO_MANAGED_BACK_BUFFER Then
            ManagedBackBuffer.Dispose()
        End If
        ManagedBackBuffer = GraphicManager.Allocate(Me.CreateGraphics(), ClientRectangle)
        Me.Refresh()
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs)
        ' Do nothing		
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
        Try
            DrawGraphics(ManagedBackBuffer.Graphics)
            ' paint the picture in from the back buffer into the form draw area
            ManagedBackBuffer.Render(e.Graphics)
        Catch ex As Exception
            ' Do nothing
        End Try
    End Sub

    Private drawBrushEnabled As New SolidBrush(Color.Black)
    Private drawBrushDisabled As New SolidBrush(Color.LightGray)
    Private edgePenEnabled As New Pen(Color.Black, 1)
    Private edgePenDisabled As New Pen(Color.LightGray, 1)

    Private Sub DrawGraphics(ByVal e As Graphics)
        Dim xWidth As Integer = (Value * CSng(Me.Width)) / (Max - Min)
        Dim xStart As Integer = ((0 - Min) * CSng(Me.Width)) / (Max - Min)

        Dim edgePen As Pen
        Dim drawbrush As Brush
        If Me.Enabled Then
            edgePen = edgePenEnabled
            drawbrush = drawBrushEnabled
        Else
            edgePen = edgePenDisabled
            drawbrush = drawBrushDisabled
        End If


        Dim valueStr As String = FormatNumber(Value, 2)
        Dim sf As SizeF = e.MeasureString(valueStr, Me.Font)
        If Visualisation = VisualType.Bar Then
            ' Draw background
            e.FillRectangle(Brushes.White, 0, 0, xStart, Me.Height)
            e.FillRectangle(Brushes.White, xStart + xWidth, 0, Me.Width - xStart - xWidth, Me.Height)
            ' Draw rectangle
            e.FillRectangle(drawbrush, xStart, 0, xWidth, Me.Height)

            If Me.Enabled Then
                ' Draw value string
                e.DrawString(valueStr, Me.Font, drawbrush, 0, 0)
                If ShowMinMax Then
                    ' Draw max/min string
                    e.DrawString(Min, Me.Font, drawbrush, 0, Me.Height - sf.Height)
                    e.DrawString(Max, Me.Font, drawbrush, Me.Width - e.MeasureString(Max, Me.Font).Width, Me.Height - sf.Height)
                End If
            End If
        ElseIf Visualisation = VisualType.Line Then
            ' Draw background
            e.FillRectangle(Brushes.White, 0, 0, Me.Width, Me.Height)
            If Me.Enabled Then
                ' Draw line
                e.FillRectangle(Brushes.Blue, xStart + xWidth - 1, 0, 2, Me.Height)
                ' Draw value string
                Dim sX As Integer = xStart + xWidth
                If Me.Width - sX < sf.Width Then sX = Me.Width - sf.Width
                e.DrawString(valueStr, Me.Font, drawbrush, sX, 0)
                If ShowMinMax Then
                    ' Draw max/min string
                    e.DrawString(Min, Me.Font, drawbrush, 0, Me.Height - sf.Height)
                    e.DrawString(Max, Me.Font, drawbrush, Me.Width - e.MeasureString(Max, Me.Font).Width, Me.Height - sf.Height)
                End If
            End If
        End If

        ' Draw edge
        e.DrawRectangle(edgePen, 0, 0, Me.Width - 1, Me.Height - 1)
    End Sub
End Class
