Click here to Skip to main content
15,895,011 members
Articles / Desktop Programming / Windows Forms

i00 Spell Check and Control Extensions - No Third Party Components Required!

Rate me:
Please Sign up or sign in to vote.
4.95/5 (117 votes)
11 Jan 2014Ms-PL16 min read 1.4M   22   266  
Simple to use, open source Spell Checker for .NET
'i00 .Net ToolStrip Color Picker
'©i00 Productions All rights reserved
'Created by Kris Bennett
'----------------------------------------------------------------------------------------------------
'All property in this file is and remains the property of i00 Productions, regardless of its usage,
'unless stated otherwise in writing from i00 Productions.
'
'i00 is not and shall not be held accountable for any damages directly or indirectly caused by the
'use or miss-use of this product.  This product is only a component and thus is intended to be used 
'as part of other software, it is not a complete software package, thus i00 Productions is not 
'responsible for any legal ramifications that software using this product breaches.

<System.ComponentModel.DefaultEvent("ColorChanged")> _
<System.Windows.Forms.Design.ToolStripItemDesignerAvailability(Windows.Forms.Design.ToolStripItemDesignerAvailability.All)> _
<System.ComponentModel.DesignerCategory("")> _
Public Class tsiColorPicker
    Inherits ToolStripDropDownItem

    Dim OrigWidth As Integer
    Dim OrigHeight As Integer

    Public Sub New()
        Using tsiSizeCheck As New ToolStripMenuItem
            OrigWidth = tsiSizeCheck.Width
            OrigHeight = tsiSizeCheck.Height
        End Using
        Resize()
        MyBase.AutoToolTip = False
        MyBase.AutoSize = False
    End Sub

    Private Sub Resize()
        MyBase.Size = MySize
    End Sub


#Region "Properties"

#Region "Custom"

    Dim mc_Persistent As Boolean = False
    <System.ComponentModel.DefaultValueAttribute(False)> _
    Public Property Persistent() As Boolean
        Get
            Return mc_Persistent
        End Get
        Set(ByVal value As Boolean)
            mc_Persistent = value
        End Set
    End Property

    Dim mc_SelectedColor As Color
    Public Property SelectedColor() As Color
        Get
            Return mc_SelectedColor
        End Get
        Set(ByVal value As Color)
            mc_SelectedColor = value
        End Set
    End Property


    Dim mc_Colors As List(Of Color)
    Public Property Colors() As List(Of Color)
        Get
            If mc_Colors Is Nothing OrElse mc_Colors.Count = 0 Then
                FillWithDefaultColors()
            End If
            Return mc_Colors
        End Get
        Set(ByVal value As List(Of Color))
            mc_Colors = value
            'should really use a watched list and call the resize after item/s gets added / removed
            Resize()
        End Set
    End Property

    Dim mc_ShowColorToolTip As Boolean = True
    <System.ComponentModel.DefaultValueAttribute(True)> _
    Public Property ShowColorToolTip() As Boolean
        Get
            Return mc_ShowColorToolTip
        End Get
        Set(ByVal value As Boolean)
            mc_ShowColorToolTip = value
        End Set
    End Property

    Dim mc_BlocksAcross As Integer = 8
    <System.ComponentModel.DefaultValueAttribute(8)> _
    Public Property BlocksAcross() As Integer
        Get
            Return mc_BlocksAcross
        End Get
        Set(ByVal value As Integer)
            mc_BlocksAcross = value
            Resize()
        End Set
    End Property

#End Region

#Region "Private Read Only Properties"

    Private ReadOnly Property BlocksHigh() As Integer
        Get
            Return ((Colors.Count - 1) \ BlocksAcross) + 1
        End Get
    End Property

    Private ReadOnly Property TextSize() As SizeF
        Get
            If Text <> "" AndAlso Me.Parent IsNot Nothing Then
                TextSize = Me.Parent.CreateGraphics.MeasureString(Text, MyBase.Font)
            End If
        End Get
    End Property

    Private ReadOnly Property MySize() As Size
        Get
            Return New Size(CInt((OrigHeight * mc_BlocksAcross) + TextSize.Width), OrigHeight * BlocksHigh)
        End Get
    End Property

#End Region

#Region "Overridden Properties"

#Region "Hidden Properties"

    <System.ComponentModel.Browsable(False)> _
    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public Overrides Property TextAlign() As System.Drawing.ContentAlignment
        Get
            Return MyBase.TextAlign
        End Get
        Set(ByVal value As System.Drawing.ContentAlignment)
            MyBase.TextAlign = value
        End Set
    End Property

    <System.ComponentModel.Browsable(False)> _
    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public Overrides Property TextDirection() As System.Windows.Forms.ToolStripTextDirection
        Get
            Return MyBase.TextDirection
        End Get
        Set(ByVal value As System.Windows.Forms.ToolStripTextDirection)
            MyBase.TextDirection = value
        End Set
    End Property

    <System.ComponentModel.Browsable(False)> _
    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public Overrides Property Size() As System.Drawing.Size
        Get
            Return MySize
        End Get
        Set(ByVal value As System.Drawing.Size)

        End Set
    End Property

    <System.ComponentModel.Browsable(False)> _
    <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
    Public Overrides Property Image() As System.Drawing.Image
        Get
            Return Nothing
        End Get
        Set(ByVal value As System.Drawing.Image)

        End Set
    End Property

    <System.ComponentModel.Browsable(False)> _
    Public Overrides Property DisplayStyle() As System.Windows.Forms.ToolStripItemDisplayStyle
        Get
            Return ToolStripItemDisplayStyle.None
        End Get
        Set(ByVal value As System.Windows.Forms.ToolStripItemDisplayStyle)

        End Set
    End Property

    <System.ComponentModel.Browsable(False)> _
    Overrides ReadOnly Property CanSelect() As Boolean
        Get
            Return False
        End Get
    End Property

#End Region

    Public Overrides ReadOnly Property HasDropDownItems() As Boolean
        Get
            Return mc_Persistent
        End Get
    End Property

    Public Overrides Property Text() As String
        Get
            Return MyBase.Text
        End Get
        Set(ByVal value As String)
            MyBase.Text = value
            Resize()
        End Set
    End Property

#End Region

#End Region

    Public Shared DefaultColors() As Color = New Color() {Color.Black, Color.FromArgb(153, 51, 0), Color.FromArgb(51, 51, 0), Color.FromArgb(0, 51, 0), Color.FromArgb(0, 51, 102), Color.Navy, Color.FromArgb(51, 51, 153), Color.FromArgb(51, 51, 51), _
                                             Color.Maroon, Color.FromArgb(255, 102, 0), Color.Olive, Color.Green, Color.Teal, Color.Blue, Color.FromArgb(102, 102, 153), Color.Gray, _
                                             Color.Red, Color.FromArgb(255, 153, 0), Color.FromArgb(153, 204, 0), Color.FromArgb(51, 153, 102), Color.FromArgb(51, 204, 204), Color.FromArgb(51, 102, 255), Color.Purple, Color.FromArgb(153, 153, 153), _
                                             Color.Fuchsia, Color.FromArgb(255, 204, 0), Color.Yellow, Color.Lime, Color.Aqua, Color.FromArgb(0, 204, 255), Color.FromArgb(153, 51, 102), Color.Silver, _
                                             Color.FromArgb(255, 153, 204), Color.FromArgb(255, 204, 153), Color.FromArgb(255, 255, 153), Color.FromArgb(204, 255, 204), Color.FromArgb(204, 255, 255), Color.FromArgb(153, 204, 255), Color.FromArgb(204, 153, 255), Color.White}

    Private Sub FillWithDefaultColors()
        mc_Colors = New List(Of Color)
        mc_Colors.AddRange(DefaultColors)
    End Sub

    Dim Tooltip As New ToolTip

    Private Sub tsiColorPickerItem_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
        Tooltip.Dispose()
    End Sub

    Private Sub tsiColorPickerItem_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
        Tooltip.Hide(Me.Parent)
        If PaintHoverColor <> -1 Then
            RaiseEvent HoverOverColor(Me, New ColorEventArgs)
            PaintHoverColor = -1
            Me.Invalidate()
        End If
    End Sub

    Public Class ColorEventArgs
        Inherits EventArgs
        Public Color As Color
    End Class

    Public Event HoverOverColor(ByVal sender As Object, ByVal e As ColorEventArgs)

    Private Sub tsiColorPickerItem_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Dim LastColorNo As Integer = PaintHoverColor
        PaintHoverColor = GetColorIndexAtLocation(e.Location)
        If LastColorNo <> PaintHoverColor Then
            'color has changed
            If PaintHoverColor = -1 Then
                RaiseEvent HoverOverColor(Me, New ColorEventArgs)
                Tooltip.Hide(Me.Parent)
            Else
                RaiseEvent HoverOverColor(Me, New ColorEventArgs With {.Color = Colors(PaintHoverColor)})
                If ShowColorToolTip Then
                    Dim TipLocation = GetColorRectFromIndex(PaintHoverColor).Location
                    Dim ts = TextSize
                    TipLocation.X += MyBase.Bounds.Left + CInt(ts.Width)
                    TipLocation.Y += MyBase.Bounds.Top + Cursors.Arrow.Size.Height
                    Dim NiceColor As Color = GetClosestKnownColor(Colors(PaintHoverColor))
                    If NiceColor.IsEmpty = False Then
                        Dim ColorName As String = NiceColor.Name
StartOver:
                        Dim Match = System.Text.RegularExpressions.Regex.Match(ColorName, "(?<!\s|^)[A-Z]")
                        If Match.Success Then
                            'do this letter
                            ColorName = Left(ColorName, Match.Index) & " " & Mid(ColorName, Match.Index + 1)
                            GoTo StartOver
                        End If
                        Tooltip.Show(ColorName, Me.Parent, TipLocation) 'New Point(Me.Bounds.Right, Me.Bounds.Y))
                    End If
                End If
            End If
            Me.Invalidate()
        End If
    End Sub

#Region "Cloest Color Matching"

    Public Shared Function GetClosestKnownColor(ByVal Color As Color) As Color
        'find the closest color...
        If Color.IsKnownColor Then
            Return Color
        Else
            Dim ColorMatches = (From xItem In [Enum].GetNames(GetType(KnownColor)) Select Color.FromKnownColor(DirectCast([Enum].Parse(GetType(KnownColor), xItem), KnownColor))).ToArray
            Dim ColorMatchesWithCloseness = (From xItem In ColorMatches Where xItem.IsSystemColor = False AndAlso (IsRightColorTone(xItem, Color) OrElse ColorCloseness(xItem, Color) < 25) Select New With {.Color = xItem, .Closeness = ColorCloseness(xItem, Color)}).ToArray
            ColorMatchesWithCloseness = (From xItem In ColorMatchesWithCloseness Order By xItem.Closeness Ascending).ToArray
            If ColorMatchesWithCloseness.Count > 0 Then
                Return ColorMatchesWithCloseness.FirstOrDefault.Color
            Else
                Return Color.Empty
            End If
        End If
    End Function

    Private Class ObjectHolder
        Public theObject As Object
        Public Sub New(ByVal theObject As Object)
            Me.theObject = theObject
        End Sub
    End Class

    Private Shared Function ColorCloseness(ByVal Color1 As Color, ByVal Color2 As Color) As Integer
        Return Math.Abs(CInt(Color1.A) - CInt(Color2.A)) + Math.Abs(CInt(Color1.R) - CInt(Color2.R)) + Math.Abs(CInt(Color1.G) - CInt(Color2.G)) + Math.Abs(CInt(Color1.B) - CInt(Color2.B))
    End Function

    Private Shared Function IsRightColorTone(ByVal Color1 As Color, ByVal Color2 As Color) As Boolean
        Dim arrColor1 = New ObjectHolder() {New ObjectHolder(Color1.R), New ObjectHolder(Color1.G), New ObjectHolder(Color1.B)}
        Dim arrColor2 = New ObjectHolder() {New ObjectHolder(Color2.R), New ObjectHolder(Color2.G), New ObjectHolder(Color2.B)}
        'find the majors
        Dim MaxColors1 = Join((From xItem In arrColor1 Where Val(xItem.theObject) = arrColor1.Max(Function(b As ObjectHolder) Val(b.theObject)) Select CStr(Array.IndexOf(arrColor1, xItem))).ToArray, ";")
        Dim MaxColors2 = Join((From xItem In arrColor2 Where Val(xItem.theObject) = arrColor2.Max(Function(b As ObjectHolder) Val(b.theObject)) Select CStr(Array.IndexOf(arrColor2, xItem))).ToArray, ";")
        If MaxColors1 = MaxColors2 Then
            'good sofar...
        Else
            Return False
        End If
        'find the minors
        Dim MinColors1 = Join((From xItem In arrColor1 Where Val(xItem.theObject) = arrColor1.Min(Function(b As ObjectHolder) Val(b.theObject)) Select CStr(Array.IndexOf(arrColor1, xItem))).ToArray, ";")
        Dim MinColors2 = Join((From xItem In arrColor2 Where Val(xItem.theObject) = arrColor2.Min(Function(b As ObjectHolder) Val(b.theObject)) Select CStr(Array.IndexOf(arrColor2, xItem))).ToArray, ";")
        If MinColors1 = MinColors2 Then
            'good sofar...
        Else
            Return False
        End If
        Return True
    End Function

#End Region

    Dim PaintHoverColor As Integer = -1

    Private Function GetColorIndexAtLocation(ByVal Location As Point) As Integer
        GetColorIndexAtLocation = -1
        Dim ts = TextSize
        If Location.X < CInt(ts.Width) Then
            'over left margin
        Else
            GetColorIndexAtLocation = CInt((Int(Location.Y / OrigHeight) * BlocksAcross) + (Int((Location.X - CInt(ts.Width)) / OrigHeight)))
            If GetColorIndexAtLocation < Colors.Count Then
                'all good
            Else
                GetColorIndexAtLocation = -1
            End If
        End If
    End Function

    Private Function GetColorRectFromIndex(ByVal Index As Integer) As Rectangle
        Dim x = Index Mod BlocksAcross
        Dim y As Integer = CInt(Int((Index - x) / mc_BlocksAcross))
        Return New Rectangle((x * OrigHeight), (y * OrigHeight), OrigHeight, OrigHeight)
    End Function

    Public Event ColorChanged(ByVal sender As Object, ByVal e As EventArgs)

    Private Sub tsiColorPicker_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        Dim ColorIndex = GetColorIndexAtLocation(e.Location)
        If ColorIndex = -1 Then
            'did not click a color
        Else
            Me.SelectedColor = Colors(ColorIndex)
            RaiseEvent ColorChanged(Me, EventArgs.Empty)
        End If
    End Sub

    Private Sub tsiColorPickerItem_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim ts = TextSize
        If ts.Width <> 0 Then
            'draw the text
            Using sb As New SolidBrush(Me.ForeColor)
                e.Graphics.DrawString(Me.Text, Me.Font, sb, 0, (Me.Height - ts.Height) / 2)
            End Using
            e.Graphics.TranslateTransform(CInt(ts.Width), 0)
        End If

        'draw each color 
        Dim ColorBorderSize As Integer = CInt(OrigHeight * 0.33)

        Dim MaxY = BlocksHigh - 1
        For y = 0 To MaxY
            For x = 0 To BlocksAcross - 1
                Dim ColorNo = (mc_BlocksAcross * y) + x
                If ColorNo < Colors.Count Then
                    Dim Color = Colors(ColorNo)
                    Dim Rect = New RectangleF(CSng((x * OrigHeight) + (ColorBorderSize / 2)), CSng((y * OrigHeight) + (ColorBorderSize / 2)), OrigHeight - ColorBorderSize, OrigHeight - ColorBorderSize)

                    If PaintHoverColor = ColorNo OrElse Color = mc_SelectedColor Then
                        'draw selection rectangle
                        'had to create a new object to call DrawItemCheck on as otherwise it draws the item at the full height
                        Using tsi As New ToolStripButton
                            tsi.AutoSize = False
                            tsi.Width = OrigHeight
                            tsi.Height = OrigHeight
                            tsi.Select()
                            Using b As New Bitmap(tsi.Width, tsi.Height)
                                Using g = Graphics.FromImage(b)
                                    Me.Parent.Renderer.DrawButtonBackground(New ToolStripItemRenderEventArgs(g, tsi))
                                    If Color <> mc_SelectedColor Then
                                        'alpha image
                                        b.Filters.Alpha()
                                    Else
                                        'just draw
                                    End If
                                    e.Graphics.DrawImage(b, New PointF(CInt(Rect.X - (ColorBorderSize / 2)), CInt(Rect.Y - (ColorBorderSize / 2))))
                                End Using
                            End Using
                        End Using
                    End If

                    Using sb As New SolidBrush(Color)
                        e.Graphics.FillRectangle(sb, Rect)
                    End Using

                    If PaintHoverColor <> ColorNo AndAlso Color <> mc_SelectedColor Then
                        'draw border
                        Using p As New Pen(AlphaColor(Color.FromKnownColor(KnownColor.MenuText), 63))
                            e.Graphics.DrawRectangle(p, Rect.X, Rect.Y, Rect.Width, Rect.Height)
                        End Using
                    End If
                End If
            Next
        Next
        e.Graphics.ResetTransform()
    End Sub

    Public Shared Function AlphaColor(ByVal theColor As Color, Optional ByVal AlphaLevel As Byte = 255) As Color
        AlphaColor = Color.FromArgb(AlphaLevel, theColor.R, theColor.G, theColor.B)
    End Function

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 Microsoft Public License (Ms-PL)


Written By
i00
Software Developer (Senior) i00 Productions
Australia Australia
I hope you enjoy my code. It's yours to use for free, but if you do wish to say thank you then a donation is always appreciated.
You can donate here.

Comments and Discussions