📄 textview.cs
字号:
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Mike Kr黦er" email="mike@icsharpcode.net"/>
// <version value="$version"/>
// </file>
using System;
using System.Diagnostics;
using System.Collections;
using System.IO;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.TextEditor
{
/// <summary>
/// This class paints the textarea.
/// </summary>
public class TextView : AbstractMargin
{
int fontHeight;
Hashtable charWitdh = new Hashtable();
StringFormat measureStringFormat = (StringFormat)System.Drawing.StringFormat.GenericTypographic.Clone();
Highlight highlight;
int physicalColumn = 0; // used for calculating physical column during paint
public void Dispose()
{
measureStringFormat.Dispose();
}
public Highlight Highlight {
get {
return highlight;
}
set {
highlight = value;
}
}
public override Cursor Cursor {
get {
return Cursors.IBeam;
}
}
public int FirstPhysicalLine {
get {
return textArea.VirtualTop.Y / fontHeight;
}
}
public int LineHeightRemainder {
get {
return textArea.VirtualTop.Y % fontHeight;
}
}
/// <summary>Gets the first visible <b>logical</b> line.</summary>
public int FirstVisibleLine {
get {
return textArea.Document.GetFirstLogicalLine(textArea.VirtualTop.Y / fontHeight);
}
set {
if (FirstVisibleLine != value) {
textArea.VirtualTop = new Point(textArea.VirtualTop.X, textArea.Document.GetVisibleLine(value) * fontHeight);
}
}
}
public int VisibleLineDrawingRemainder {
get {
return textArea.VirtualTop.Y % fontHeight;
}
}
public int FontHeight {
get {
return fontHeight;
}
}
public int VisibleLineCount {
get {
return 1 + DrawingPosition.Height / fontHeight;
}
}
public int VisibleColumnCount {
get {
return (int)(DrawingPosition.Width / GetWidth(' ')) - 1;
}
}
public TextView(TextArea textArea) : base(textArea)
{
measureStringFormat.LineAlignment = StringAlignment.Near;
measureStringFormat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces |
StringFormatFlags.FitBlackBox |
StringFormatFlags.NoWrap |
StringFormatFlags.NoClip;
OptionsChanged();
}
static int GetFontHeight(Font font)
{
int h = font.Height;
return (h < 16) ? h + 1 : h;
}
public void OptionsChanged()
{
this.fontHeight = GetFontHeight(TextEditorProperties.Font);
if (this.charWitdh != null) {
this.charWitdh.Clear();
}
}
#region Paint functions
public override void Paint(Graphics g, Rectangle rect)
{
if (rect.Width <= 0 || rect.Height <= 0) {
return;
}
// Just to ensure that fontHeight and char widths are always correct...
if (fontHeight != GetFontHeight(TextEditorProperties.Font)) {
OptionsChanged();
base.TextArea.Refresh();
return;
}
int horizontalDelta = (int)(textArea.VirtualTop.X * GetWidth(g, ' '));
if (horizontalDelta > 0) {
g.SetClip(this.DrawingPosition);
}
for (int y = 0; y < (DrawingPosition.Height + VisibleLineDrawingRemainder) / fontHeight + 1; ++y) {
Rectangle lineRectangle = new Rectangle(DrawingPosition.X - horizontalDelta,
DrawingPosition.Top + y * fontHeight - VisibleLineDrawingRemainder,
DrawingPosition.Width + horizontalDelta,
fontHeight);
if (rect.IntersectsWith(lineRectangle)) {
// Console.WriteLine("first visible line is {0}. logical line", FirstVisibleLine);
int fvl = textArea.Document.GetVisibleLine(FirstVisibleLine);
// Console.WriteLine("first visible line is {0}. visible line", fvl);
// Console.WriteLine("paint {0}. visible line", fvl + y);
int currentLine = textArea.Document.GetFirstLogicalLine(textArea.Document.GetVisibleLine(FirstVisibleLine) + y);
// Console.WriteLine("logical line : " + currentLine);
PaintDocumentLine(g, currentLine, lineRectangle);
}
}
if (horizontalDelta > 0) {
g.ResetClip();
}
}
void PaintDocumentLine(Graphics g, int lineNumber, Rectangle lineRectangle)
{
Debug.Assert(lineNumber >= 0);
Brush bgColorBrush = GetBgColorBrush(lineNumber);
Brush backgroundBrush = textArea.Enabled ? bgColorBrush : SystemBrushes.InactiveBorder;
if (lineNumber >= textArea.Document.TotalNumberOfLines) {
g.FillRectangle(backgroundBrush, lineRectangle);
if (TextEditorProperties.ShowInvalidLines) {
DrawInvalidLineMarker(g, lineRectangle.Left, lineRectangle.Top);
}
if (TextEditorProperties.ShowVerticalRuler) {
DrawVerticalRuler(g, lineRectangle);
}
// bgColorBrush.Dispose();
return;
}
float physicalXPos = lineRectangle.X;
// there can't be a folding wich starts in an above line and ends here, because the line is a new one,
// there must be a return before this line.
int column = 0;
physicalColumn = 0;
if (TextEditorProperties.EnableFolding) {
while (true) {
ArrayList starts = textArea.Document.FoldingManager.GetFoldedFoldingsWithStartAfterColumn(lineNumber, column - 1);
if (starts == null || starts.Count <= 0) {
if (lineNumber < textArea.Document.TotalNumberOfLines) {
physicalXPos = PaintLinePart(g, lineNumber, column, textArea.Document.GetLineSegment(lineNumber).Length, lineRectangle, physicalXPos);
}
break;
}
// search the first starting folding
FoldMarker firstFolding = (FoldMarker)starts[0];
foreach (FoldMarker fm in starts) {
if (fm.StartColumn < firstFolding.StartColumn) {
firstFolding = fm;
}
}
starts.Clear();
physicalXPos = PaintLinePart(g, lineNumber, column, firstFolding.StartColumn, lineRectangle, physicalXPos);
column = firstFolding.EndColumn;
lineNumber = firstFolding.EndLine;
ColumnRange selectionRange2 = textArea.SelectionManager.GetSelectionAtLine(lineNumber);
bool drawSelected = ColumnRange.WholeColumn.Equals(selectionRange2) || firstFolding.StartColumn >= selectionRange2.StartColumn && firstFolding.EndColumn <= selectionRange2.EndColumn;
physicalXPos = PaintFoldingText(g, lineNumber, physicalXPos, lineRectangle, firstFolding.FoldText, drawSelected);
}
} else {
physicalXPos = PaintLinePart(g, lineNumber, 0, textArea.Document.GetLineSegment(lineNumber).Length, lineRectangle, physicalXPos);
}
if (lineNumber < textArea.Document.TotalNumberOfLines) {
// Paint things after end of line
ColumnRange selectionRange = textArea.SelectionManager.GetSelectionAtLine(lineNumber);
LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber);
HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
float spaceWidth = GetWidth(g, ' ');
bool selectionBeyondEOL = selectionRange.EndColumn > currentLine.Length || ColumnRange.WholeColumn.Equals(selectionRange);
if (TextEditorProperties.ShowEOLMarker) {
HighlightColor eolMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("EOLMarkers");
physicalXPos += DrawEOLMarker(g, eolMarkerColor.Color, selectionBeyondEOL ? bgColorBrush : backgroundBrush, physicalXPos, lineRectangle.Y);
} else {
if (selectionBeyondEOL) {
g.FillRectangle(BrushRegistry.GetBrush(selectionColor.BackgroundColor), new RectangleF(physicalXPos, lineRectangle.Y, spaceWidth, lineRectangle.Height));
physicalXPos += spaceWidth;
}
}
Brush fillBrush = selectionBeyondEOL && TextEditorProperties.AllowCaretBeyondEOL ? bgColorBrush : backgroundBrush;
g.FillRectangle(fillBrush,
new RectangleF(physicalXPos, lineRectangle.Y, lineRectangle.Width - physicalXPos + lineRectangle.X, lineRectangle.Height));
}
if (TextEditorProperties.ShowVerticalRuler) {
DrawVerticalRuler(g, lineRectangle);
}
// bgColorBrush.Dispose();
}
bool DrawLineMarkerAtLine(int lineNumber)
{
return lineNumber == base.textArea.Caret.Line && textArea.MotherTextAreaControl.TextEditorProperties.LineViewerStyle == LineViewerStyle.FullRow;
}
Brush GetBgColorBrush(int lineNumber)
{
if (DrawLineMarkerAtLine(lineNumber)) {
HighlightColor caretLine = textArea.Document.HighlightingStrategy.GetColorFor("CaretMarker");
return BrushRegistry.GetBrush(caretLine.Color);
}
HighlightBackground background = (HighlightBackground)textArea.Document.HighlightingStrategy.GetColorFor("DefaultBackground");
Color bgColor = background.BackgroundColor;
if (textArea.MotherTextAreaControl.TextEditorProperties.UseCustomLine == true)
{
bgColor = textArea.Document.CustomLineManager.GetCustomColor(lineNumber, bgColor);
}
return BrushRegistry.GetBrush(bgColor);
}
float PaintFoldingText(Graphics g, int lineNumber, float physicalXPos, Rectangle lineRectangle, string text, bool drawSelected)
{
// TODO: get font and color from the highlighting file
HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
Brush bgColorBrush = drawSelected ? BrushRegistry.GetBrush(selectionColor.BackgroundColor) : GetBgColorBrush(lineNumber);
Brush backgroundBrush = textArea.Enabled ? bgColorBrush : SystemBrushes.InactiveBorder;
float wordWidth = g.MeasureString(text, textArea.Font, Int32.MaxValue, measureStringFormat).Width;
RectangleF rect = new RectangleF(physicalXPos, lineRectangle.Y, wordWidth, lineRectangle.Height - 1);
g.FillRectangle(backgroundBrush, rect);
physicalColumn += text.Length;
g.DrawString(text,
textArea.Font,
BrushRegistry.GetBrush(drawSelected ? selectionColor.Color : Color.Gray),
rect,
measureStringFormat);
g.DrawRectangle(BrushRegistry.GetPen(drawSelected ? Color.DarkGray : Color.Gray), rect.X, rect.Y, rect.Width, rect.Height);
// Bugfix for the problem - of overdrawn right rectangle lines.
float ceiling = (float)Math.Ceiling(physicalXPos + wordWidth);
if (ceiling - (physicalXPos + wordWidth) < 0.5) {
++ceiling;
}
return ceiling;
}
void DrawMarker(Graphics g, TextMarker marker, RectangleF drawingRect)
{
float drawYPos = drawingRect.Bottom - 1;
switch (marker.TextMarkerType) {
case TextMarkerType.Underlined:
g.DrawLine(BrushRegistry.GetPen(marker.Color), drawingRect.X, drawYPos, drawingRect.Right, drawYPos);
break;
case TextMarkerType.WaveLine:
// Console.WriteLine("Drawing wave in {0}", drawingRect);
int reminder = ((int)drawingRect.X) % 6;
for (float i = drawingRect.X - reminder; i < drawingRect.Right + reminder; i+= 6) {
g.DrawLine(BrushRegistry.GetPen(marker.Color), i, drawYPos + 3 - 4, i + 3, drawYPos + 1 - 4);
g.DrawLine(BrushRegistry.GetPen(marker.Color), i + 3, drawYPos + 1 - 4, i + 6, drawYPos + 3 - 4);
}
break;
case TextMarkerType.SolidBlock:
g.FillRectangle(BrushRegistry.GetBrush(marker.Color), drawingRect);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -