Imports System.Windows.Forms
Imports System.Drawing
Imports System.Reflection
Imports System.IO
<ToolboxBitmap(GetType(NHunspellToolTip), "tooltipspellcheck.bmp")> _
Public Class NHunspellToolTip
Inherits ToolTip
Private bufferGraphics As Graphics
Private myBitmap As Bitmap
Private toolTipGraphics As Graphics
Private mySpellCheckControl As SpellCheckControl
Public Sub New()
Me.OwnerDraw = True
Dim obj As Object = FromAssembly()
mySpellCheckControl = New SpellCheckControl(obj)
End Sub
Private Shared Function FromAssembly() As Object
Dim a As Assembly = Assembly.Load(My.Resources.NHunspell)
Dim type_l As Type = a.GetType("NHunspell.Hunspell")
Dim types(1) As Type
types(0) = GetType(String)
types(1) = GetType(String)
Dim ctor As ConstructorInfo = type_l.GetConstructor(types)
Dim USdic, USaff As String
Dim callingDir As String = Path.GetDirectoryName(Assembly.GetCallingAssembly.Location)
'Set the paths for the dic and aff files
USdic = callingDir & "\SpellCheck\en_US.dic"
USaff = callingDir & "\SpellCheck\en_US.aff"
'Check if the spell check directory already exists. If not, add it
If Not Directory.Exists(callingDir & "\SpellCheck") Then
Directory.CreateDirectory(callingDir & "\SpellCheck")
Dim newDirInfo As New DirectoryInfo(callingDir & "\SpellCheck")
newDirInfo.Attributes = FileAttributes.Hidden
End If
'Check if the spell check files already exist. If not, add it
If Not File.Exists(USaff) Then
Try
File.WriteAllBytes(USaff, My.Resources.en_US)
Catch ex As Exception
MessageBox.Show("Error writing en_US.aff file!" & vbNewLine & ex.Message)
End Try
End If
If Not File.Exists(USdic) Then
Try
File.WriteAllBytes(USdic, My.Resources.en_US_dic)
Catch ex As Exception
MessageBox.Show("Error writing en_US.dic file!" & vbNewLine & ex.Message)
End Try
End If
Dim params(1) As Object
params(0) = USaff
params(1) = USdic
Dim result As Object = Nothing
CreateNewHunspell:
Try
result = ctor.Invoke(params)
Catch ex As Exception
If TypeOf ex.InnerException Is System.DllNotFoundException Then
'Get where the dll is supposed to be
Dim DLLpath As String = Trim(Strings.Mid(ex.InnerException.Message, InStr(ex.InnerException.Message, "DLL not found:") + 14))
Dim DLLName As String = Path.GetFileName(DLLpath)
'Find out which DLL is missing
If DLLName = "Hunspellx64.dll" Then
'Copy the dll to the directory
Try
File.WriteAllBytes(DLLpath, My.Resources.Hunspellx64)
Catch ex2 As Exception
MessageBox.Show("Error writing Hunspellx64.dll" & vbNewLine & ex2.Message)
End Try
'Try again
GoTo CreateNewHunspell
ElseIf DLLName = "Hunspellx86.dll" Then 'x86 dll
'Copy the dll to the directory
Try
File.WriteAllBytes(DLLpath, My.Resources.Hunspellx86)
Catch ex3 As Exception
MessageBox.Show("Error writing Hunspellx86.dll" & vbNewLine & ex3.Message)
End Try
'Try again
GoTo CreateNewHunspell
ElseIf DLLName = "NHunspell.dll" Then
Try
File.WriteAllBytes(DLLpath, My.Resources.NHunspell)
Catch ex4 As Exception
MessageBox.Show("Error writing NHunspell.dll" & vbNewLine & ex4.Message)
End Try
Else
MessageBox.Show(ex.Message & ex.StackTrace)
End If
Else
MessageBox.Show("SpellChecker cannot be created." & vbNewLine & "Spell checking will be disabled." & _
vbNewLine & vbNewLine & ex.Message & ex.StackTrace)
Return Nothing
End If
End Try
Return result
End Function
Private Sub NHunspellToolTip_Draw(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawToolTipEventArgs) _
Handles Me.Draw
e.DrawBackground()
mySpellCheckControl.SetText(e.ToolTipText)
'Now we do the custom drawing
myBitmap = New Bitmap(e.Bounds.Width, e.Bounds.Height)
bufferGraphics = Graphics.FromImage(myBitmap)
bufferGraphics.Clip = New Region(e.Bounds)
Dim currentRange As CharacterRange
For Each currentRange In mySpellCheckControl.GetSpellingErrorRanges
Dim startPoint, endPoint As Point
Dim bottom, left, right As Integer
'Determine which line the current word is on
Dim lastNewline As Integer = 1
For i = 1 To currentRange.First
If Mid(e.ToolTipText, i, 1) = vbLf Then
lastNewline = i + 1
End If
Next
'Get the text of the line to the end of the word
Dim lineToEndofWord As String = Mid(e.ToolTipText, lastNewline, _
((currentRange.First - lastNewline) + currentRange.Length + 1))
'Figure out how wide and tall the text before this is word is
'Measure the text starting from the beginning to the end of the word to get the borrom coordinates
Dim newSize As SizeF = TextRenderer.MeasureText(Microsoft.VisualBasic.Strings.Left(e.ToolTipText, _
(currentRange.First + currentRange.Length)), _
e.Font, e.Bounds.Size, TextFormatFlags.Left)
bottom = newSize.Height - 2
'Now measure the text from the beginning of the current line to the end of the word to get the right coordinates
newSize = TextRenderer.MeasureText(lineToEndofWord, e.Font, e.Bounds.Size, TextFormatFlags.Left)
right = newSize.Width
endPoint = New Point(right, bottom)
'Now we can backtrack and find out how wide that text is
newSize = TextRenderer.MeasureText(Mid(e.ToolTipText, currentRange.First + 1, currentRange.Length), _
e.Font, e.Bounds.Size, TextFormatFlags.Left)
left = right - newSize.Width
startPoint = New Point(left, bottom)
startPoint.X += 2
endPoint.X -= 4
DrawWave(startPoint, endPoint)
Next
toolTipGraphics = e.Graphics
toolTipGraphics.DrawImageUnscaled(myBitmap, 0, 0)
e.DrawBorder()
Dim stringFlags As New StringFormat()
stringFlags.Alignment = StringAlignment.Near
stringFlags.LineAlignment = StringAlignment.Near
TextRenderer.DrawText(e.Graphics, e.ToolTipText, e.Font, e.Bounds, Color.Black, flags:=TextFormatFlags.Left)
End Sub
''' <summary>
''' Draws the wavy red line given a starting point and an ending point
''' </summary>
''' <param name="StartOfLine">A Point representing the starting point</param>
''' <param name="EndOfLine">A Point representing the ending point</param>
''' <remarks></remarks>
Private Sub DrawWave(ByVal StartOfLine As Point, ByVal EndOfLine As Point)
Dim newPen As Pen = Pens.Red
If (EndOfLine.X - StartOfLine.X) > 4 Then
Dim pl As New ArrayList
For i = StartOfLine.X To (EndOfLine.X - 2) Step 4
pl.Add(New Point(i, StartOfLine.Y))
pl.Add(New Point(i + 2, StartOfLine.Y + 2))
Next
Dim p() As Point = CType(pl.ToArray(GetType(Point)), Point())
bufferGraphics.DrawLines(newPen, p)
Else
bufferGraphics.DrawLine(newPen, StartOfLine, EndOfLine)
End If
End Sub
End Class