using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using HWND = System.IntPtr;
namespace CodeRichText
{
public partial class CodeRichText : UserControl
{
private string[] keywords ={ };
private string[] dividers ={ };
public CodeRichText()
{
InitializeComponent();
UpdateLineNo();
}
[DllImport("user32")]
private static extern int SendMessage(HWND hwnd, int wMsg, int wParam, IntPtr lParam);
private const int WM_SETREDRAW = 0xB;
public string[] KeyWords
{
get { return keywords; }
set
{
keywords = value;
ColorAllText();
}
}
public string[] Dividers
{
get { return dividers; }
set
{
dividers = value;
ColorAllText();
}
}
public string CodeText
{
get { return this.richTextBoxSourceCode.Text; }
set { this.richTextBoxSourceCode.Text = value; }
}
public Font CodeFont
{
get { return this.richTextBoxSourceCode.Font; }
set { this.richTextBoxSourceCode.Font = value; }
}
public void LoadFile(string path)
{
richTextBoxSourceCode.LoadFile(path,RichTextBoxStreamType.PlainText);
}
public void SaveFile(string path)
{
richTextBoxSourceCode.SaveFile(path,RichTextBoxStreamType.PlainText);
}
private void ColorAllText()
{
if (richTextBoxSourceCode.Text == string.Empty) return;
for (int i = 0; i < richTextBoxSourceCode.Lines.Length;i++ )
ColorCurrentText(i);
}
private void ColorCurrentText(int lineNum)
{
if (richTextBoxSourceCode.Text == string.Empty) return;
string lineStr = richTextBoxSourceCode.Lines[lineNum];
int selectStart = richTextBoxSourceCode.SelectionStart;
int lineStart=0;
for(int i=0;i<lineNum;i++)
lineStart+=richTextBoxSourceCode.Lines[i].Length+1;
SendMessage(richTextBoxSourceCode.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
richTextBoxSourceCode.SelectionStart = lineStart;
richTextBoxSourceCode.SelectionLength = lineStr.Length;
richTextBoxSourceCode.SelectionColor = Color.Black;
richTextBoxSourceCode.SelectionStart = selectStart;
richTextBoxSourceCode.SelectionLength = 0;
richTextBoxSourceCode.SelectionColor = Color.Black;
string[] words = lineStr.Split(dividers,StringSplitOptions.RemoveEmptyEntries);
int lineIndex = 0;
foreach (string word in words)
{
if (IsKeyWord(word))
{
lineIndex = lineStr.IndexOf(word, lineIndex);
richTextBoxSourceCode.SelectionStart = lineStart + lineIndex;
richTextBoxSourceCode.SelectionLength = word.Length;
richTextBoxSourceCode.SelectionColor = Color.Blue;
richTextBoxSourceCode.SelectionStart = selectStart;
richTextBoxSourceCode.SelectionLength = 0;
richTextBoxSourceCode.SelectionColor = Color.Black;
lineIndex += word.Length + 1;
}
else if (IsNumber(word))
{
lineIndex = lineStr.IndexOf(word, lineIndex);
richTextBoxSourceCode.SelectionStart = lineStart + lineIndex;
richTextBoxSourceCode.SelectionLength = word.Length;
richTextBoxSourceCode.SelectionColor = Color.Tomato;
richTextBoxSourceCode.SelectionStart = selectStart;
richTextBoxSourceCode.SelectionLength = 0;
richTextBoxSourceCode.SelectionColor = Color.Black;
lineIndex += word.Length + 1;
}
}
SendMessage(richTextBoxSourceCode.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
richTextBoxSourceCode.Refresh();
}
private bool IsKeyWord(string word)
{
foreach (string s in keywords)
{
if (string.Compare(word, s) == 0)
return true;
}
return false;
}
private bool IsNumber(string word)
{
foreach (char ch in word)
{
if (!(ch >= '0' && ch <= '9'))
return false;
}
return true;
}
private void richTextBoxSourceCode_TextChanged(object sender, EventArgs e)
{
if (richTextBoxSourceCode.Text == string.Empty) return;
int lineNum = richTextBoxSourceCode.GetLineFromCharIndex(richTextBoxSourceCode.SelectionStart);
UpdateLineNo();
ColorCurrentText(lineNum);
}
private void UpdateLineNo()
{
SendMessage(richTextBoxLineNo.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
//get index of first visible char and number of first visible line
Point pos = new Point(0, 0);
int firstIndex = richTextBoxSourceCode.GetCharIndexFromPosition(pos);
int firstLine = richTextBoxSourceCode.GetLineFromCharIndex(firstIndex);
//get index of last visible char and number of last visible line
pos.X = ClientRectangle.Width;
pos.Y = ClientRectangle.Height;
int lastIndex = richTextBoxSourceCode.GetCharIndexFromPosition(pos);
int lastLine = richTextBoxSourceCode.GetLineFromCharIndex(lastIndex);
//this is the point position of last visible char, use its Y value for calculating numberLabel size
pos = richTextBoxSourceCode.GetPositionFromCharIndex(lastIndex);
//finally, update line number
StringBuilder lineNo = new StringBuilder();
for (int i = firstLine; i <= lastLine + 1; i++)
{
lineNo.Append((i + 1).ToString() + "\n");
}
richTextBoxLineNo.Text = lineNo.ToString();
SendMessage(richTextBoxLineNo.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
richTextBoxLineNo.Refresh();
}
private void CodeRichText_Scroll(object sender, ScrollEventArgs e)
{
}
private void richTextBoxSourceCode_VScroll(object sender, EventArgs e)
{
//move location of line number for amount of pixels caused by scrollbar
int d = richTextBoxSourceCode.GetPositionFromCharIndex(0).Y % (richTextBoxSourceCode.Font.Height + 1);
richTextBoxLineNo.Location = new Point(0, d);
UpdateLineNo();
}
private void richTextBoxLineNo_Enter(object sender, EventArgs e)
{
richTextBoxSourceCode.Focus();
}
private void richTextBoxSourceCode_FontChanged(object sender, EventArgs e)
{
richTextBoxLineNo.Font = new Font(richTextBoxSourceCode.Font, FontStyle.Regular);
}
}
}