Reputation: 105
This highlights the entire width of each line by painting a transparent color as the backcolor on the current line. When the line switches, the original background color is restored.
So, what we want to do is:
mLastHighlight
with the index and rectangle for each applied lineHowever, when removing the highlight, the text is painted over. This does not occur when applying the highlight.
One solution would be to repaint the text back on the control after resetting the back color. though the text formatting, selection colors, font styles, hyperlinks, etc would be tedious to filter. Not very elegant.
This leads to a simpler solution, refreshing the control. Though that would cause massive flickering. Not acceptable either.
Is there an elegant solution? I'm completely baffled why this occurs.
EDIT: Edited to reflect Code Gray's response.
using System;
public class RTBHL : RichTextBox
{
private LastHighlight mLastHighlight = new LastHighlight(0, Rectangle.Empty);
private class LastHighlight
{
public int mCharIndex;
public Rectangle mRectangle;
public LastHighlight(int index, Rectangle r)
{
mCharIndex = index;
mRectangle = r;
}
}
public void PaintLineHighlight()
{
using (Graphics g = this.CreateGraphics)
{
// highlight color
Color c = Color.Beige;
// current pen color
Pen cp = new Pen(Color.Beige);
// color for removing highlight
Pen lp = new Pen(this.BackColor);
// brush for removing highlight
SolidBrush lb = new SolidBrush(this.BackColor);
// brush for applying highlight
SolidBrush cb = new SolidBrush(Color.FromArgb(64, c.R, c.G, c.B));
// index of the current line
int index = this.GetFirstCharIndexOfCurrentLine;
// rectangle to specify which region to paint too
Rectangle r = new Rectangle();
// specify dimensions
r.X = 0;
r.Y = this.GetPositionFromCharIndex(index).Y;
r.Width = this.HorizontalScrollBarWidth;
r.Height = Convert.ToInt32(this.Font.Height * this.ZoomFactor);
// this will always be true unless the current line remains the same
if (!(mLastHighlight.mCharIndex == index) && !(mLastHighlight.mRectangle == r))
{
// remove the last highlight. regardless of the brush specified, white is always applied, and the text is painted over
g.DrawRectangle(lp, mLastHighlight.mRectangle);
g.FillRectangle(lb, mLastHighlight.mRectangle);
// apply highlight to the current line
g.DrawRectangle(cp, r);
g.FillRectangle(cb, r);
}
mLastHighlight = new LastHighlight(index, r);
}
}
#region RichScrollBars
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, ref SCROLLINFO si);
[StructLayout(LayoutKind.Sequential)]
public class SCROLLINFO
{
public int cbSize;
public int fMask;
public int nMin;
public int nMax;
public int nPage;
public int nPos;
public int nTrackPos;
public SCROLLINFO()
{
this.cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
}
public SCROLLINFO(int mask, int min, int max, int page, int pos)
{
this.cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
this.fMask = mask;
this.nMin = min;
this.nMax = max;
this.nPage = page;
this.nPos = pos;
}
}
private const int SIF_ALL = 0X17;
private const int SB_HORZ = 0;
private const int SB_VERT = 1;
public int HorizontalScrollBarWidth()
{
SCROLLINFO si = new SCROLLINFO() {fMask = SIF_ALL};
GetScrollInfo(this.Handle, SB_HORZ, si);
return Math.Max(si.nMax, this.Width);
}
public int VerticalScrollBarHeight()
{
SCROLLINFO si = new SCROLLINFO() {fMask = SIF_ALL};
GetScrollInfo(this.Handle, SB_VERT, si);
return Math.Max(si.nMax, this.Height);
}
#endregion
}
Upvotes: 5
Views: 1657
Reputation: 244692
The problem here is that the code you're copying is designed for Scintilla. The SCI_*
constants are defined internally by the Scintilla headers, and the messages they refer to only have meaning to the Scintilla controls.
Sending those messages to the native Win32 rich edit control isn't going to do anything because it wasn't designed to process those messages. (Or worse, one or more of the SCI_*
constants happen to clash with one or more of the message identifiers that the rich edit control does recognize, producing some potentially interesting behavior.)
Unless you're actually using a Scintilla edit control in your project (which you said you don't want to do), that code isn't going to do anything interesting. It isn't written for the Win32 rich edit control, it's written to interface with the Scintilla control.
The Scintilla control is far more than just a wrapper around the Win32 rich edit control. It has to do a lot of custom drawing to make its magic, and all of that code is hard to get right on your own. That's why so many people use Scintilla in the first place. If you need its feature set, I highly recommend that you follow suit.
Anyway, I don't actually know if this is possible with the Win32 rich edit control. I don't think it is, but I couldn't swear to that fact. I guess you could hack it by setting the selection color, but that doesn't seem like a very good solution. Something like Daniel suggests here. I'm not a Scintilla expert, but to my untrained eyes, this looks kind of like the moral equivalent of your Scintilla-based code, but written for the Win32 rich edit control (through the .NET WinForms wrapper thereof).
Upvotes: 3