Click here to Skip to main content
15,891,828 members
Articles / DevOps / Load Testing

NHunspell Component for Visual Studio

Rate me:
Please Sign up or sign in to vote.
4.90/5 (31 votes)
1 Sep 2013CPOL6 min read 113.9K   4.1K   46  
NHunspell component example for WindowsForms
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using NHunspellComponent.Spelling.Interfaces;
using NHunspellComponent.SupportClasses;

namespace TestingApplication
{
   public class CustomPaintRichText : RichTextBox, IUnderlineableSpellingControl
   {
      public Dictionary<int, int> underlinedSections;
      public Dictionary<int, int> protectedSections;
      public Dictionary<int, int> ignoredSections;

      public Dictionary<int, int> UnderlinedSections
      {
         get
         {
            if (underlinedSections == null)
               underlinedSections = new Dictionary<int, int>();
            return underlinedSections;
         }
         set { underlinedSections = value; }
      }

      public Dictionary<int, int> ProtectedSections
      {
         set { protectedSections = value; }
      }

      public Dictionary<int, int> IgnoredSections
      {
         set { ignoredSections = value; }
      }

      #region ISpellingControl Members

      private bool spellingEnabled;
      private bool spellingAutoEnabled;
      private bool isPassWordProtected;

      public bool IsSpellingEnabled
      {
         get { return spellingEnabled; }
         set { spellingEnabled = value; }
      }

      public bool IsSpellingAutoEnabled
      {
         get { return spellingAutoEnabled; }
         set
         {
            spellingAutoEnabled = value;
            if (!spellingEnabled) spellingEnabled = value;
         }
      }

      public bool IsPassWordProtected
      {
         get { return isPassWordProtected; }
         set { isPassWordProtected = value; }
      }

      #endregion

      /// <summary>
      /// This is called when the textbox is being redrawn.
      /// When it is, for the textbox to get refreshed, call it's default
      /// paint method and then call our method
      /// </summary>
      /// <param name="m">The windows message</param>
      /// <remarks></remarks>
      protected override void WndProc(ref System.Windows.Forms.Message m)
      {
         switch (m.Msg)
         {
            case 15:
               //This is the WM_PAINT message
               //Invalidate the textBoxBase so that it gets refreshed properly
               this.Invalidate();

               //call the default win32 Paint method for the TextBoxBase first
               base.WndProc(ref m);

               //now use our code to draw the extra stuff
               if (!this.ReadOnly && IsSpellingAutoEnabled)
               {
                  this.CustomPaint();
               }
               break;
            default:
               base.WndProc(ref m);
               break;
         }
      }

      public void CustomPaint()
      {
         Bitmap tmpBitmap;
         Graphics textBoxGraphics;
         Graphics bufferGraphics;

         //Create a bitmap with the same dimensions as the textbox
         tmpBitmap = new Bitmap(this.Width, this.Height);

         //Create the graphics object from this bitmpa...this is where we will draw the lines to start with
         bufferGraphics = Graphics.FromImage(tmpBitmap);
         bufferGraphics.Clip = new Region(this.ClientRectangle);

         //Get the graphics object for the textbox.  We use this to draw the bufferGraphics
         textBoxGraphics = Graphics.FromHwnd(this.Handle);

         // clear the graphics buffer
         bufferGraphics.Clear(Color.Transparent);

         foreach (int wordStart in UnderlinedSections.Keys)
         {
            if (ignoredSections != null && ignoredSections.ContainsKey(wordStart))
            {
               continue;
            }

            int wordEndIndex = wordStart + UnderlinedSections[wordStart] - 1;
            Point start = this.GetPositionFromCharIndex(wordStart);
            Point end = this.GetPositionFromCharIndex(wordEndIndex);

            int curIndex = wordStart;
            int safetyDrewOnce = -1;
            if (curIndex < Text.Length)
               do
               {
                  start = this.GetPositionFromCharIndex(curIndex);
                  //Determine the first line of waves to draw
                  while (curIndex <= wordEndIndex)
                  {
                     if (curIndex < Text.Length && this.GetPositionFromCharIndex(curIndex).Y == start.Y)
                     {
                        curIndex += 1;
                     }
                     else
                     {
                        curIndex--;
                        break;
                     }
                  }
                  end = this.GetPositionFromCharIndex(curIndex);

                  // The position above now points to the top left corner of the character.
                  // We need to account for the character height so the underlines go
                  // to the right place.
                  end.X += 1;
                  int yOffset = TextBoxAPIHelper.GetBaselineOffsetAtCharIndex(this, wordStart);
                  start.Y += yOffset;
                  end.Y += yOffset;

                  //Add a new wavy line using the starting and ending point
                  DrawWave(bufferGraphics, start, end);
                  if (safetyDrewOnce != curIndex)
                  {
                     safetyDrewOnce = curIndex;
                  }
                  else
                  {
                     break;
                  }
                  curIndex += 1;
               } //TODO: something with indeces
                  //Replace words in text with empty words.
               while (curIndex <= wordEndIndex);
         }
         // Now we just draw our internal buffer on top of the TextBox.
         // Everything should be at the right place.
         textBoxGraphics.DrawImageUnscaled(tmpBitmap, 0, 0);
      }

      /// <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 void DrawWave(Graphics graphics, Point StartOfLine, Point EndOfLine)
      {
         //correction to draw line closer to text
         StartOfLine.Y--;
         EndOfLine.Y--;

         Pen newPen = Pens.Red;

         if ((EndOfLine.X - StartOfLine.X) > 4)
         {
            ArrayList pl = new ArrayList();
            for (int i = StartOfLine.X; i <= (EndOfLine.X - 2); i += 4)
            {
               pl.Add(new Point(i, StartOfLine.Y));
               pl.Add(new Point(i + 2, StartOfLine.Y + 2));
            }

            Point[] p = (Point[]) pl.ToArray(typeof (Point));
            graphics.DrawLines(newPen, p);
         }
         else
         {
            graphics.DrawLine(newPen, StartOfLine, EndOfLine);
         }
      }

      public void AddUnderlinedSection(int s, int l)
      {
         if (UnderlinedSections.ContainsKey(s))
         {
            underlinedSections.Remove(s);
         }
         underlinedSections.Add(s, l);
      }

      public void RemoveWordFromUnderliningList(int wordStart)
      {
         if (underlinedSections.ContainsKey(wordStart))
         {
            underlinedSections.Remove(wordStart);
            //this.Invalidate();
         }
      }

      protected override void OnMouseDown(MouseEventArgs e)
      {
         if (e.Button == MouseButtons.Right)
         {
            int position = this.GetCharIndexFromPosition(e.Location);
            if (position == Text.Length - 1)
            {
               position++;
            }
            if (position < this.SelectionStart ||
                position > this.SelectionStart + this.SelectionLength)
            {
               this.Select(position, 0);
            }
         }
         base.OnMouseDown(e);
      }

      internal void AddToIgnoreList(int start, int length)
      {
         if (ignoredSections != null && ignoredSections.ContainsKey(start))
         {
            ignoredSections.Remove(start);
         }
         if (ignoredSections != null)
            ignoredSections.Add(start, length);
      }
   }
}

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 Code Project Open License (CPOL)


Written By
Software Developer
Ukraine Ukraine
"a man can do no more than he can" (proverb)
Don't you think there are a lot of things you couldn't do couple of years before but now you can? Things didn't change, but the only thing that changed is belief in yourself.

Comments and Discussions