using System;
using System.Drawing;
using System.Windows.Forms;
namespace NHunspellComponent.SupportClasses
{
public class TextBoxAPIHelper
{
private const double anInch = 14.4;
public static int GetBaselineOffsetAtCharIndex(System.Windows.Forms.TextBoxBase tb, int index)
{
System.Windows.Forms.RichTextBox rtb = tb as RichTextBox;
if (rtb == null)
{
return tb.Font.Height;
}
int lineNumber = rtb.GetLineFromCharIndex(index);
int lineIndex =
NativeMethods.SendMessageInt(rtb.Handle, NativeMethods.EM_LINEINDEX, new IntPtr(lineNumber), IntPtr.Zero).
ToInt32();
int lineLength =
NativeMethods.SendMessageInt(rtb.Handle, NativeMethods.EM_LINELENGTH, new IntPtr(lineNumber), IntPtr.Zero).
ToInt32();
NativeMethods.CHARRANGE charRange;
charRange.cpMin = lineIndex;
charRange.cpMax = lineIndex + lineLength;
// charRange.cpMin = index;
// charRange.cpMax = index + 1;
NativeMethods.RECT rect;
rect.Top = 0;
rect.Bottom = (int) anInch;
rect.Left = 0;
rect.Right = 10000000; //(int)(rtb.Width * anInch + 20);
NativeMethods.RECT rectPage;
rectPage.Top = 0;
rectPage.Bottom = (int) anInch;
rectPage.Left = 0;
rectPage.Right = 10000000; //(int)(rtb.Width * anInch + 20);
Graphics canvas = Graphics.FromHwnd(rtb.Handle);
IntPtr canvasHdc = canvas.GetHdc();
NativeMethods.FORMATRANGE formatRange;
formatRange.chrg = charRange;
formatRange.hdc = canvasHdc;
formatRange.hdcTarget = canvasHdc;
formatRange.rc = rect;
formatRange.rcPage = rectPage;
NativeMethods.SendMessage(rtb.Handle, NativeMethods.EM_FORMATRANGE, IntPtr.Zero, ref formatRange).ToInt32();
canvas.ReleaseHdc(canvasHdc);
canvas.Dispose();
return (int) ((formatRange.rc.Bottom - formatRange.rc.Top)/anInch);
}
/// <summary>
/// Returns the index of the character under the specified
/// point in the control, or the nearest character if there
/// is no character under the point.
/// </summary>
/// <param name="txt">The text box control to check.</param>
/// <param name="pt">The point to find the character for,
/// specified relative to the client area of the text box.</param>
/// <returns></returns>
internal static int CharFromPos(System.Windows.Forms.TextBoxBase txt, Point pt)
{
unchecked
{
// Convert the point into a DWord with horizontal position
// in the loword and vertical position in the hiword:
int xy = (pt.X & 0xFFFF) + ((pt.Y & 0xFFFF) << 16);
// Get the position from the text box.
int res =
NativeMethods.SendMessageInt(txt.Handle, NativeMethods.EM_CHARFROMPOS, IntPtr.Zero, new IntPtr(xy)).
ToInt32();
// the Platform SDK appears to be incorrect on this matter.
// the hiword is the line number and the loword is the index
// of the character on this line
int lineNumber = ((res & 0xFFFF) >> 16);
int charIndex = (res & 0xFFFF);
// Find the index of the first character on the line within
// the control:
int lineStartIndex = NativeMethods.SendMessageInt(txt.Handle, NativeMethods.EM_LINEINDEX,
new IntPtr(lineNumber), IntPtr.Zero).ToInt32();
// Return the combined index:
return lineStartIndex + charIndex;
}
}
/// <summary>
/// Returns the position of the specified character
/// </summary>
/// <param name="txt">The text box to find the character in.</param>
/// <param name="charIndex">The index of the character whose
/// position needs to be found.</param>
/// <returns>The position of the character relative to the client
/// area of the control.</returns>
internal static Point PosFromChar(System.Windows.Forms.TextBoxBase txt, int charIndex)
{
unchecked
{
int xy =
NativeMethods.SendMessageInt(txt.Handle, NativeMethods.EM_POSFROMCHAR, new IntPtr(charIndex), IntPtr.Zero)
.ToInt32();
return new Point(xy);
}
}
internal static int GetFirstVisibleLine(System.Windows.Forms.TextBoxBase txt)
{
return
NativeMethods.SendMessageInt(txt.Handle, NativeMethods.EM_GETFIRSTVISIBLELINE, IntPtr.Zero, IntPtr.Zero).
ToInt32();
}
// private constructor, methods are static
private TextBoxAPIHelper()
{
// intentionally left blank
}
}
}
/*internal static int GetTextWidthAtCharIndex(System.Windows.Forms.TextBoxBase tb, int index, int length)
{
System.Windows.Forms.RichTextBox rtb = tb as RichTextBox;
//TODO!
if (rtb == null) { return tb.Font.Height; }
NativeMethods.CHARRANGE charRange;
charRange.cpMin = index;
charRange.cpMax = index + length;
NativeMethods.RECT rect;
rect.Top = 0;
rect.Bottom = (int)anInch;
rect.Left = 0;
rect.Right = (int)(rtb.ClientSize.Width * anInch);
NativeMethods.RECT rectPage;
rectPage.Top = 0;
rectPage.Bottom = (int)anInch;
rectPage.Left = 0;
rectPage.Right = (int)(rtb.ClientSize.Width * anInch);
Graphics canvas = Graphics.FromHwnd(rtb.Handle);
IntPtr canvasHdc = canvas.GetHdc();
NativeMethods.FORMATRANGE formatRange;
formatRange.chrg = charRange;
formatRange.hdc = canvasHdc;
formatRange.hdcTarget = canvasHdc;
formatRange.rc = rect;
formatRange.rcPage = rectPage;
NativeMethods.SendMessage(rtb.Handle, NativeMethods.EM_FORMATRANGE, IntPtr.Zero, ref formatRange);
canvas.ReleaseHdc(canvasHdc);
canvas.Dispose();
return (int)((formatRange.rc.Right - formatRange.rc.Left) / anInch);
}
*/
/*
/// <summary>
/// Attempts to make the caret visible in a TextBox control.
/// This will not always succeed since the TextBox control
/// appears to destroy its caret fairly frequently.
/// </summary>
/// <param name="txt">The text box to show the caret in.</param>
internal static void ShowCaret(System.Windows.Forms.TextBox txt)
{
bool ret = false;
int iter = 0;
while (!ret && iter < 10)
{
ret = NativeMethods.ShowCaretAPI(txt.Handle);
iter++;
}
}
*/
/*
}
*/
/*
internal static int GetLineIndex(TextBoxBase txt, int line)
{
return NativeMethods.SendMessageInt(txt.Handle, 0xbb, new IntPtr(line), IntPtr.Zero).ToInt32();
}
*/