|
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.