RECOMMENDED CHANGES:
Here are some modifications that I'm recommending for the i00SpellCheck project inside the SpellCheck solution:
First, not a change to the project itself, but a useful tip: The spell-checker checks the entire text box or rich text box. There's no way to restrict the spell-check to a highlighted (selected) region. To do so, you need to create a second text-box/rich-text-box--say, one unattached to any form--transfer the selected text of the first text box into it (using SelectedText/SelectedRtf of the first text-box/rich-text-box and Text/Rtf of the second), spell-check on the second one, then paste the result back into the first text-box. For instance:
Dim rtb As RichTextBox = New RichTextBox()
rtb.SelectedRtf = RichTextBox1.SelectedRtf
Dim iSpellCheckDialog = _
TryCast(rtb.SpellCheck, i00SpellCheck.SpellCheckControlBase.iSpellCheckDialog)
If iSpellCheckDialog IsNot Nothing Then
iSpellCheckDialog.ShowDialog()
RichTextBox1.SelectionProtected = False
rtb.SelectAll() : RichTextBox1.SelectedRtf = rtb.SelectedRtf
End If
Now for the changes:
1. With selection "Change All" in the spell-check dialog, all subsequent unrecognized words are replaced, wily-nilly, with the first item in each word's suggestion list, even if arbitrary replacement text or another list entry is specified in "Change To:", even if only all occurrences of 1 word is desired for change. To make it so that subsequent occurrences only of the current misspelled word are replaced, and with the contents of the txtChangeTo text (if it isn't empty), I suggest making the following changes to the following changes to SpellCheckDialog.vb:
Dim NewTextForChangeAll, OldTextForChangeAll As String
Private Sub StartChangeAll()
btnAdd.Enabled = False
ChangeingAll = True
If mt_ChangeAll IsNot Nothing AndAlso mt_ChangeAll.IsAlive Then
mt_ChangeAll.Abort()
End If
Dim SelectedWord = Me.SelectedWord
NewTextForChangeAll = txtChangeTo.Text
OldTextForChangeAll = SelectedWord.OrigWord
If SelectedWord IsNot Nothing Then
SelectedWord.Selected = False
End If
ShowHideSuggestions(False)
btnChangeAll.Enabled = False
mt_ChangeAll = New System.Threading.Thread(AddressOf ChangeAll)
mt_ChangeAll.Name = "Spell Check - Change all"
mt_ChangeAll.IsBackground = True
mt_ChangeAll.Start()
End Sub
Private Sub ChangeAll()
Dim WordErrors = (From xItem In HtmlSpellCheck1.Words Where (xItem.SpellCheckState = HTMLSpellCheck.SpellCheckDialogWords.SpellCheckStates.Case OrElse xItem.SpellCheckState = HTMLSpellCheck.SpellCheckDialogWords.SpellCheckStates.Error))
For Each item In WordErrors.ToArray
If String.Compare(item.NewWord, OldTextForChangeAll, True) = 0 Then
Dim Suggestions = GetSuggestions(item.NewWord)
If Suggestions.Count > 0 Then
If String.IsNullOrEmpty(NewTextForChangeAll) Then
item.NewWord = Suggestions.First
Else
item.NewWord = NewTextForChangeAll
End If
item.SpellCheckState = HTMLSpellCheck.SpellCheckDialogWords.SpellCheckStates.OK
If SelectedWord() Is item Then
HtmlSpellCheck1_SelectionChanged(HtmlSpellCheck1, New HTMLSpellCheck.HTMLWordEventArgs() With {.Word = item})
End If
End If
End If
Next
btnRevertAll.SafeInvoke(Function(x As Button) InlineAssignHelper(x.Enabled, True))
If HtmlSpellCheck1.mt_SpellCheck IsNot Nothing AndAlso HtmlSpellCheck1.mt_SpellCheck.IsAlive Then
Else
Dim btnChangeAllEnabled = (From xItem In HtmlSpellCheck1.Words Where (xItem.SpellCheckState = HTMLSpellCheck.SpellCheckDialogWords.SpellCheckStates.Case OrElse xItem.SpellCheckState = HTMLSpellCheck.SpellCheckDialogWords.SpellCheckStates.Error)).Count > 0
ChangeingAll = False
If btnChangeAllEnabled = True Then
btnChangeAll.SafeInvoke(Function(x As Button) InlineAssignHelper(x.Enabled, btnChangeAllEnabled))
btnSkip_Click(btnSkip, EventArgs.Empty)
Else
CompleteSpellCheck()
End If
End If
End Sub
2. To allow the programmer to keep the standard menu from being automatically added to a text-box's/rich-text-box's context menu, add the following to Extension.vb:
Friend IncludeStandardItems As Boolean = True
<System.Runtime.CompilerServices.Extension()> _
Public Sub IncludeOrExcludeStandardMenu(ByVal sender As Control, _
Optional ByVal Include As Boolean = True)
IncludeStandardItems = Include
End Sub
Then change extTextBoxContextMenu.vb as follows:
Public Sub AddStandardItems(ByVal ContextMenuStrip As ContextMenuStrip)
If Not IncludeStandardItems Then
Exit Sub
End If
RaiseEvent PreAddingMenuItems(Me, EventArgs.Empty)
If ContextMenuStrip.Items.Count > 0 Then
ContextMenuStrip.Items.Add(New StandardToolStripSeparator)
End If
Undo = New StandardToolStripMenuItem("&Undo", My.Resources.Undo)
ContextMenuStrip.Items.Add(Undo)
Dim RichTextBox = TryCast(TextBox, RichTextBox)
If RichTextBox IsNot Nothing Then
Redo = New StandardToolStripMenuItem("&Redo", My.Resources.Redo)
ContextMenuStrip.Items.Add(Redo)
Redo.Enabled = RichTextBox.CanRedo
End If
ContextMenuStrip.Items.Add(New StandardToolStripSeparator)
If System.Threading.Thread.CurrentThread.GetApartmentState = Threading.ApartmentState.STA Then
Cut = New StandardToolStripMenuItem("Cu&t", My.Resources.Cut)
ContextMenuStrip.Items.Add(Cut)
Copy = New StandardToolStripMenuItem("&Copy", My.Resources.Copy)
ContextMenuStrip.Items.Add(Copy)
Paste = New StandardToolStripMenuItem("&Paste", My.Resources.Paste)
ContextMenuStrip.Items.Add(Paste)
Cut.Enabled = TextBox.SelectionLength > 0
Copy.Enabled = TextBox.SelectionLength > 0
Paste.Enabled = Clipboard.GetText <> ""
End If
Delete = New StandardToolStripMenuItem("&Delete", My.Resources.Delete)
ContextMenuStrip.Items.Add(Delete)
ContextMenuStrip.Items.Add(New StandardToolStripSeparator)
SelectAll = New StandardToolStripMenuItem("Select &All", My.Resources.SelectAll)
ContextMenuStrip.Items.Add(SelectAll)
Undo.Enabled = TextBox.CanUndo
Delete.Enabled = TextBox.SelectionLength > 0
SelectAll.Enabled = TextBox.SelectionLength <> Len(TextBox.Text)
RaiseEvent PostAddingMenuItems(Me, EventArgs.Empty)
End Sub
Now, calling Me.IncludeOrExcludeStandardMenu(False) before Me.EnableControlExtensions() will suppress the auto-addition of the standard menu. (The default parameter value for the new procedure is True to allow auto-addition.)
3. The spell check won't recognize valid words which are broken by hidden (syllable) hyphens (ChrW(173)). To rectify that, I would make the following changes:
First, add the following to iDictionary.vb:
Public Shared Function RemoveHyphens(ByVal Word As String) As String
Return Word.Replace(ChrW(173), "")
End Function
Then add the following statement
Word = Dictionary.RemoveHyphens(Word)
in the following places:
a. in front of the 1st statement of the following procedures: SpellCheckWord and SpellCheckSuggestions (both in iDictionary.vb); AddItems (in Menu.vb); DictionaryIgnoreWord, DictionaryUnIgnoreWord, DictionaryAddWord, and DictionaryRemoveWord (all in SpellCheckControlBase.vb); and, finally,
b. in the following place in SpellCheckDialog.vb:
Private Sub btnAdd_ClickDropdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.ClickDropdown
Dim theSelectedWord = SelectedWord()
If theSelectedWord IsNot Nothing Then
Dim Word As String = txtChangeTo.Text
If ChangeToChanged = False Then
Word = theSelectedWord.NewWord
End If
Word = Dictionary.RemoveHyphens(Word)
tsiAddCaseSensitive.Text = "Case sensitive: " & Word
tsiAddCaseInsensitive.Text = "Case insensitive: " & LCase(Word)
tsiAddCaseSensitive.Visible = Word <> LCase(Word)
cmsAdd.Show(btnAdd, New Point(0, btnAdd.Height))
End If
End Sub
4. Also, you might want to set StartPosition for the SpellCheckDialog form to CenterScreen.
5. I also recommend the following changes in order to ensure that i00SpellCheck's recognition of numbers and works breaks is more similar to (although not identical to) Microsoft Word's. First make the following changes in the "Word Breaks" and "For words with 's" regions of Formatting.vb--changing RemoveWordBreaks and RemoveApoS as follows (and removing the WordBreakChrs array and associated "escaping" procedure):
#Region "Word Breaks"
Private Const FastOption As RegexOptions = _
RegexOptions.Compiled Or RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase
Private Const HyphenChar As String = ChrW(173), _
SingleQuoteChars As String = "'`" & ChrW(1370) & ChrW(1371) & ChrW(1372) _
& ChrW(8216) & ChrW(8217) & ChrW(8219) & ChrW(8242) _
& ChrW(11788) & ChrW(11789) & ChrW(65040) & ChrW(65287), _
SingleQuoteTest As String = "[" & SingleQuoteChars & "]", _
AmpersandChars As String = "&﹠&&", _
AmpersandTest As String = "[" & AmpersandChars & "]", _
NumberSignChars As String = "#﹟#♯", _
NumberSignTest As String = "[" & NumberSignChars & "]", _
PercentPermilleChars As String = "%‰﹪‱%٪؉؊", _
PercentPermilleTest As String = "[" & PercentPermilleChars & "]"
Private Const ApoSTest As String = SingleQuoteTest & "s(?![\p{L}\d])"
Private Const WordBreakCharTest As String = "(?<![\p{L}\d])'|'(?!\p{L})" _
& "|(?<![\p{L}\d\p{Sc}])&(?![\p{L}\d\p{Sc}])" _
& "|(?<![\p{L}\d])[#™℠]|[#™℠](?![\p{L}\d])" _
& "|(?<![\p{Sc}%\p{L}\d])[\p{Sc}%](?![\p{Sc}%\p{L}\d])" _
& "|(?<![\p{L}\d])[©®℗]|[\s\r\n\t\v\f]" _
& "|(?<!(^|[^\p{L}\d])\d+E)[+\-]|[+\-](?!\d+($|[^\p{L}\d]))" _
& "|[\p{P}\p{Sm}\^~≈-[" & HyphenChar & "'&#™℠\p{Sc}%©®℗+\-]]"
Private Shared ReadOnly reReplaceWordBreakChars As Regex = _
New Regex(WordBreakCharTest, FastOption), _
reReplaceSingleQuotes As Regex = New Regex(SingleQuoteTest, FastOption), _
reReplaceAmpersands As Regex = New Regex(AmpersandTest, FastOption), _
reReplaceNumberSigns As Regex = New Regex(NumberSignTest, FastOption), _
reReplacePercentPermille As Regex = New Regex(PercentPermilleTest, FastOption), _
reRemoveTrailingApoS As Regex = New Regex(ApoSTest, FastOption)
Public Shared Function RemoveWordBreaks(ByVal Text As String) As String
If Text <> "" Then
Text = reReplaceSingleQuotes.Replace(Text, "'")
Text = reReplaceAmpersands.Replace(Text, "&")
Text = reReplaceNumberSigns.Replace(Text, "#")
Text = reReplacePercentPermille.Replace(Text, "%")
Text = reReplaceWordBreakChars.Replace(Text, " ")
End If
Return Text
End Function
#End Region
#Region "For words with 's"
Friend Shared Function RemoveApoS(ByVal text As String) As String
Return _
reRemoveTrailingApoS.Replace(text, "")
End Function
#End Region
Then change the code in the SpellCheckWordNonUser procedure of FlatFileSpellCheck.vb as follows:
#Region "Check that Word is in the Dictionary"
Private Const FastOption As RegexOptions = _
RegexOptions.Compiled Or RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase
Private Const PercentPermilleChars As String = "%‰﹪‱%٪؉؊", _
PercentPermilleTest As String = "[" & PercentPermilleChars & "]", _
SpecialChars As String = "\p{Sc}" & PercentPermilleChars, _
SpecialCharsTest As String = "[" & SpecialChars & "]", _
NumericText As String = "[^" & SpecialChars & "]+", _
ValidNumberTest As String = "^(" & NumericText & "|\p{Sc}?" & NumericText & "\p{Sc}?" _
& "|" & NumericText & PercentPermilleTest & "?)$"
Private ReadOnly reCheckValidNumber As Regex = New Regex(ValidNumberTest, FastOption), _
reRemoveSpecialChars As Regex = New Regex(SpecialCharsTest, FastOption)
Public Overrides Function SpellCheckWordNonUser(ByVal Word As String) _
As Dictionary.SpellCheckWordError
If Word = "" Then
Return SpellCheckWordError.OK
End If
Dim theWord = Word
Dim OldWord = theWord
theWord = Dictionary.Formatting.RemoveApoS(theWord)
Dim NumericWord = theWord
If reCheckValidNumber.IsMatch(NumericWord) Then
NumericWord = reRemoveSpecialChars.Replace(NumericWord, "")
If IsNumeric(NumericWord) Then
Return SpellCheckWordError.OK
End If
End If
Dim DicWords = IndexedDictionary.Item(Word)
If DicWords Is Nothing Then
Return SpellCheckWordError.SpellError
End If
DicWords = (From xItem In DicWords Where LCase(xItem) = LCase(theWord)).ToList
If DicWords.Count = 0 Then
Return SpellCheckWordError.SpellError
End If
For Each iDicWord In DicWords
Dim WordCaseOK = Formatting.CaseOK(Word, iDicWord)
If WordCaseOK Then
Return SpellCheckWordError.OK
End If
Next
Return SpellCheckWordError.CaseError
End Function
#End Region
6.There are also issues with RichTextBox's which contain hidden text (text marked as "invisible" using RTF code "\v text\v0") whenever the platform of the host project of this DLL is .NET Framework 4.7 or higher: The Text, SelectedText, and SelectionLength properties return different values than they do for earlier .NET platforms, ignoring the invisible text. (There are also issues with proper function of methods that convert between point-on-control and character-index when the end of a document isn't padded with enough "visible" but undisplayed characters--like optional "syllable" hyphens"--to compensate for the earlier marked-as-invisible text. Weird!) In order to ensure that the spell-check dialog properly locates and (when asked) replaces misspelled text in a rich-text box containing invisible text, regardless of target platform, do the following:
Add the following extension methods to the Extension.vb file:
#Region "Extended Text Reading"
<System.Runtime.CompilerServices.Extension()> _
Public Function FullSelectionLength(TextBox As TextBoxBase) As Integer
If TypeOf TextBox IsNot RichTextBox Then
Return TextBox.SelectionLength
End If
Dim RichTextBox As RichTextBox = DirectCast(TextBox, RichTextBox)
Dim TypeRTB As Type = RichTextBox.GetType
Dim fi As FieldInfo = _
TypeRTB.GetField("curSelStart", _
BindingFlags.Instance Or BindingFlags.NonPublic)
Dim nCurSelStart As Integer = CType(fi.GetValue(RichTextBox), Integer)
fi = TypeRTB.GetField("curSelEnd", _
BindingFlags.Instance Or BindingFlags.NonPublic)
Dim nCurSelEnd As Integer = _
Math.Min(CType(fi.GetValue(RichTextBox), Integer), RichTextBox.TextLength)
If nCurSelStart = -1 AndAlso nCurSelEnd = -1 Then
Return 0
Else
Return _
nCurSelEnd - nCurSelStart
End If
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function ExtendedText(TextBox As TextBoxBase, _
Optional SelectionOnly As Boolean = False) As String
If TypeOf TextBox IsNot RichTextBox Then
If SelectionOnly Then
Return TextBox.SelectedText
Else
Return TextBox.Text
End If
End If
Dim RichTextBox As RichTextBox = DirectCast(TextBox, RichTextBox)
Dim TypeRTB As Type = RichTextBox.GetType
Dim prop As PropertyInfo = _
TypeRTB.GetProperty("WindowText", _
BindingFlags.Instance Or BindingFlags.NonPublic)
Dim Text As String = _
CType(prop.GetValue(RichTextBox, {}), String).Replace(ControlChars.Cr, "")
If SelectionOnly Then
Dim fi As FieldInfo = _
TypeRTB.GetField("curSelStart", _
BindingFlags.Instance Or BindingFlags.NonPublic)
Dim nCurSelStart As Integer = CType(fi.GetValue(RichTextBox), Integer)
fi = TypeRTB.GetField("curSelEnd", _
BindingFlags.Instance Or BindingFlags.NonPublic)
Dim nCurSelEnd As Integer = _
Math.Min(CType(fi.GetValue(RichTextBox), Integer), Text.Length)
If (nCurSelStart = -1 AndAlso nCurSelEnd = -1) _
OrElse nCurSelStart = nCurSelEnd Then
Text = ""
Else
Text = Text.Substring(nCurSelStart, nCurSelEnd - nCurSelStart)
End If
End If
Return Text
End Function
#End Region
Then, in every other ".vb" code file in the "i00SpellCheck" project, replace all "reading" occurrences (those inside an expression) of Text, SelectedText, and SelectionLength properties that are attached to TextBoxBase-type variables--specifically, to TextBox and parentTextBox--with ExtendedText (aka. all text), ExtendedText(True) (aka. selected text), and FullSelectionLength, respectively. Do not replace occurrences of these properties that are "writing" (on the left-hand-side of an assignment statement) or attached to variables of other objects--particularly those that don't derive from TextBoxBase! These changes should affect the following files: clsRTBHighlight.vb, Drawing.vb, extTextBoxChangeCase.vb, extTextBoxCommon.vb, extTextBoxContextMenu.vb, Menu.vb, and Misc.vb.
(Note that these fixes don't necessarily guarantee that spell-check via squiggly lines and a context menu for a misspelled word will display and function correctly when there's invisible text. More changes will be needed to finesse that.)
7. You might also want to make the following change to SetUpControl within TextBox.vb, in order to ensure that i00SpellCheck words with controls that derive from TextBox and RichTextBox:
Region "Test Harness"
Public Function SetupControl(ByVal Control As System.Windows.Forms.Control) As Control Implements iTestHarness.SetupControl
If TypeOf Control Is TextBox Then
Dim TextBox = DirectCast(Control, TextBox)
TextBox.Font = New System.Drawing.Font("Microsoft Sans Serif", 12)
TextBox.Multiline = True
TextBox.ScrollBars = ScrollBars.Vertical
TextBox.AppendText(If(TextBox.Text = "", "", vbCrLf & vbCrLf) & "Ths is a standrd text field that uses a dictionary to spel check the its contents ... as you can se errors are underlnied in red!")
TextBox.SelectionStart = 0
TextBox.SelectionLength = 0
Return TextBox
ElseIf TypeOf Control Is RichTextBox Then
Dim RichTextBox = DirectCast(Control, RichTextBox)
RichTextBox.Font = New System.Drawing.Font("Microsoft Sans Serif", 15.75!)
Dim StartIndex = RichTextBox.TextLength
RichTextBox.AppendText(If(RichTextBox.Text = "", "", vbCrLf & vbCrLf) & "i00SpellCheck has built in support for RichTextBoxes!" & vbCrLf & _
"The quic brown fox junped ovr the lazy dog!" & vbCrLf & _
"You can right click to see spelling suggestions for words and to add/ignore/remove words from the dictionary." & vbCrLf & _
"If you ignre a word you can hold ctrl down to underlne all ignored words!" & vbCrLf & _
"The initial dictionary may take a little while to load ... it holds more than 150 000 words!")
Dim HighlightKeyWordFormat As New extTextBoxCommon.HighlightKeyWordFormat
HighlightKeyWordFormat.Color = Color.Red
extTextBoxCommon.HighlightKeyWord(RichTextBox, "Rich", HighlightKeyWordFormat, RichTextBoxFinds.None, StartIndex)
HighlightKeyWordFormat.Color = Color.Green
extTextBoxCommon.HighlightKeyWord(RichTextBox, "Text", HighlightKeyWordFormat, RichTextBoxFinds.None, StartIndex)
HighlightKeyWordFormat.Color = Color.Blue
extTextBoxCommon.HighlightKeyWord(RichTextBox, "Boxes", HighlightKeyWordFormat, RichTextBoxFinds.None, StartIndex)
HighlightKeyWordFormat.Color = Color.FromKnownColor(KnownColor.HotTrack)
extTextBoxCommon.HighlightKeyWord(RichTextBox, "i00SpellCheck", HighlightKeyWordFormat, RichTextBoxFinds.None, StartIndex)
HighlightKeyWordFormat.Color = Color.Empty
HighlightKeyWordFormat.Font = New Font(RichTextBox.Font.Name, CSng(RichTextBox.Font.Size * 1.5), FontStyle.Bold)
extTextBoxCommon.HighlightKeyWord(RichTextBox, "RichTextBoxes!", HighlightKeyWordFormat, RichTextBoxFinds.None, StartIndex)
RichTextBox.Select(0, 0)
RichTextBox.ClearUndo()
Return RichTextBox
Else
Return Nothing
End If
End Function
#End Region
8. Finally, here's a bug (!!) in the Drawing.vb source file which can cause an application to crash (!!) when the "character index" at the upper-left or lower-right of a TextBox/RichTextBox is -1. The error is in the CustomPaint procedure, and is corrected as follows:
#Region "Painting"
Private Sub CustomPaint()
If OKToDraw = False OrElse parentTextBox.ClientSize.Width = 0 Then Exit Sub
Dim TextHeight As Integer = System.Windows.Forms.TextRenderer.MeasureText("Ag", parentTextBox.Font).Height
Dim BufferWidth As Integer = System.Windows.Forms.TextRenderer.MeasureText("--", parentTextBox.Font).Width
'for drawing underlines below the textbox drawing bounds when on a single line text box
Dim bHeight = parentTextBox.ClientSize.Height
If DrawOverlayForm IsNot Nothing Then
bHeight = DrawOverlayForm.Height
End If
Using b As New Bitmap(parentTextBox.ClientSize.Width, bHeight)
Using g = Graphics.FromImage(b)
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
'Using sb As New SolidBrush(Color.FromArgb(127, Color.Blue))
' g.FillRectangle(sb, New RectangleF(0, 0, parentTextBox.Width, parentTextBox.Height))
'End Using
Dim FromChar = parentTextBox.GetCharIndexFromPosition(New Point(0, 0))
If FromChar < 0 Then
FromChar = 0
End If
Dim ToChar = parentTextBox.GetCharIndexFromPosition(New Point(parentTextBox.ClientRectangle.Width - 1, parentTextBox.ClientRectangle.Height - 1))
If ToChar < 0 Then
ToChar = 0
End If
Dim theText As String = Dictionary.Formatting.RemoveWordBreaks(parentTextBox.Text)
Dim LetterIndex = FromChar
Dim LeftSide = Left(theText, FromChar)
LeftSide = LeftSide.Split(" "c).Last
Dim RightSide = Right(theText, Len(theText) - ToChar)
RightSide = RightSide.Split(" "c).First
FromChar -= Len(LeftSide) : ToChar += Len(RightSide)
Dim VisibleText As String = Mid(theText, FromChar + 1, ToChar - FromChar)
'If parentTextBox.Multiline = False Then
'g.TranslateTransform(-System.Windows.Forms.TextRenderer.MeasureText(LeftSide, parentTextBox.Font).Width, -5)
'End If
Dim NewWords As New Dictionary(Of String, Dictionary.SpellCheckWordError)
If Trim(VisibleText) <> "" Then
Dim words = Replace(Replace(VisibleText, vbCr, " "), vbLf, " ").Split(" "c)
For iWord = LBound(words) To UBound(words)
If words(iWord) <> "" Then
Dim P1 = parentTextBox.GetPositionFromCharIndex(LetterIndex)
Dim P1OffsetPlus As Integer = 0
If iWord = 0 AndAlso P1.X >= parentTextBox.ClientSize.Width Then
P1OffsetPlus = 1
P1.X = 0
End If
If P1.Y < parentTextBox.Height Then
Dim WordState As Dictionary.SpellCheckWordError = Dictionary.SpellCheckWordError.SpellError
If dictCache.ContainsKey(words(iWord)) Then
'load from cache
WordState = dictCache(words(iWord))
Else
''item is not in the dict cache
If NewWords.ContainsKey(words(iWord)) = False Then
NewWords.Add(words(iWord), Dictionary.SpellCheckWordError.OK)
End If
WordState = Dictionary.SpellCheckWordError.OK
End If
If WordState = Dictionary.SpellCheckWordError.OK Then
Else
If WordState = Dictionary.SpellCheckWordError.Ignore Then
If DrawIgnored() = False Then GoTo ContinueFor
End If
Dim P2 = parentTextBox.GetPositionFromCharIndex(LetterIndex + Len(words(iWord)))
If LeftSide <> "" AndAlso iWord = 0 Then
Dim NormalStringWidth = g.MeasureString(Mid(words(iWord), Len(LeftSide) + 1 + P1OffsetPlus), parentTextBox.Font).Width
Dim XOffsetDiff = g.MeasureString("-" & Mid(words(iWord), Len(LeftSide) + 1 + P1OffsetPlus) & "-", parentTextBox.Font).Width - NormalStringWidth
P2.X = CInt(parentTextBox.GetPositionFromCharIndex(LetterIndex + P1OffsetPlus).X + (NormalStringWidth - XOffsetDiff))
End If
If P2.X = 0 Then
'we are the last char ... :(
P2 = parentTextBox.GetPositionFromCharIndex(LetterIndex + Len(words(iWord)) - 1)
P2.X += System.Windows.Forms.TextRenderer.MeasureText("-" & Right(words(iWord), 1) & "-", parentTextBox.Font).Width - BufferWidth
End If
Dim LineHeight As Integer = extTextBoxCommon.GetLineHeightFromCharPosition(parentTextBox, LetterIndex, RTBContents)
'P1.Y += LineHeight
P2.Y = P1.Y + LineHeight
'P2.Y = P1.Y
Dim e = New SpellCheckCustomPaintEventArgs With {.Graphics = g, .Word = words(iWord), .Bounds = New Rectangle(P1.X, P1.Y, P2.X - P1.X, P2.Y - P1.Y), .WordState = WordState}
OnSpellCheckErrorPaint(e)
If e.DrawDefault Then
Select Case WordState
Case Dictionary.SpellCheckWordError.Ignore
Using p As New Pen(Settings.IgnoreColor)
g.DrawLine(p, P1.X, P2.Y + 1, P2.X, P2.Y + 1)
End Using
Case Dictionary.SpellCheckWordError.CaseError
DrawingFunctions.DrawWave(g, P1, P2, Settings.CaseMistakeColor)
Case Dictionary.SpellCheckWordError.SpellError
DrawingFunctions.DrawWave(g, P1, P2, Settings.MistakeColor)
End Select
End If
End If
End If
End If
ContinueFor:
If LeftSide <> "" AndAlso iWord = 0 Then
LetterIndex -= Len(LeftSide)
End If
LetterIndex += 1 + Len(words(iWord))
Next
End If
Draw:
If DrawOverlayForm IsNot Nothing Then
DrawOverlayForm.SetBitmap(b, 255)
Else
Dim textBoxGraphics = Graphics.FromHwnd(parentTextBox.Handle)
textBoxGraphics.DrawImageUnscaled(b, 0, 0)
End If
If NewWords.Count > 0 Then
AddWordsToCache(NewWords)
End If
End Using
End Using
End Sub
#End Region
Now re-build the i00SpellCheck project.
PS. You might also want to create a separate, extra solution with only that project. Simply load in the SpellCheck.sln solution, exclude the 11 projects other than i00SpellCheck and save a new solution with a different name, say i00SpellCheck.sln. (Be sure when opening the project alone, though, to click on the new i00SpellCheck.sln file because clicking on the i00SpellCheck.vbproj file will open the entire SpellCheck.sln solution with all 12 projects!)
modified 12-Oct-21 2:02am.
|