textview.cs
来自「SharpDevelop2.0.0 c#开发免费工具」· CS 代码 · 共 1,093 行 · 第 1/3 页
CS
1,093 行
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 1436 $</version>
// </file>
using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
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, IDisposable
{
int fontHeight;
//Hashtable charWitdh = new Hashtable();
StringFormat measureStringFormat = (StringFormat)StringFormat.GenericTypographic.Clone();
Highlight highlight;
int physicalColumn = 0; // used for calculating physical column during paint
public void Dispose()
{
measureCache.Clear();
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 / WideSpaceWidth) - 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;
}
float spaceWidth;
/// <summary>
/// Gets the width of a space character.
/// This value can be quite small in some fonts - consider using WideSpaceWidth instead.
/// </summary>
public float SpaceWidth {
get {
return spaceWidth;
}
}
float wideSpaceWidth;
/// <summary>
/// Gets the width of a 'wide space' (=one quarter of a tab, if tab is set to 4 spaces).
/// On monospaced fonts, this is the same value as spaceWidth.
/// </summary>
public float WideSpaceWidth {
get {
return wideSpaceWidth;
}
}
Font lastFont;
public void OptionsChanged()
{
this.lastFont = TextEditorProperties.Font;
this.fontHeight = GetFontHeight(lastFont);
// use mininum width - in some fonts, space has no width but kerning is used instead
// -> DivideByZeroException
this.spaceWidth = Math.Max(GetWidth(' ', lastFont), 1);
// tab should have the width of 4*'x'
this.wideSpaceWidth = Math.Max(spaceWidth, GetWidth('x', lastFont));
}
#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 (lastFont != TextEditorProperties.Font) {
OptionsChanged();
base.TextArea.BeginInvoke(new MethodInvoker(base.TextArea.Refresh));
}
int horizontalDelta = (int)(textArea.VirtualTop.X * WideSpaceWidth);
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)) {
int fvl = textArea.Document.GetVisibleLine(FirstVisibleLine);
int currentLine = textArea.Document.GetFirstLogicalLine(textArea.Document.GetVisibleLine(FirstVisibleLine) + y);
PaintDocumentLine(g, currentLine, lineRectangle);
}
}
DrawMarkerDraw(g);
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) {
List<FoldMarker> 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");
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, WideSpaceWidth, lineRectangle.Height));
physicalXPos += WideSpaceWidth;
}
}
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("Default");
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 = MeasureStringWidth(g, text, textArea.Font);
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;
}
struct MarkerToDraw {
internal TextMarker marker;
internal RectangleF drawingRect;
public MarkerToDraw(TextMarker marker, RectangleF drawingRect)
{
this.marker = marker;
this.drawingRect = drawingRect;
}
}
List<MarkerToDraw> markersToDraw = new List<MarkerToDraw>();
void DrawMarker(Graphics g, TextMarker marker, RectangleF drawingRect)
{
// draw markers later so they can overdraw the following text
markersToDraw.Add(new MarkerToDraw(marker, drawingRect));
}
void DrawMarkerDraw(Graphics g)
{
foreach (MarkerToDraw m in markersToDraw) {
TextMarker marker = m.marker;
RectangleF drawingRect = m.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:
int reminder = ((int)drawingRect.X) % 6;
for (float i = (int)drawingRect.X - reminder; i < drawingRect.Right; i += 6) {
g.DrawLine(BrushRegistry.GetPen(marker.Color), i, drawYPos + 3 - 4, i + 3, drawYPos + 1 - 4);
if (i + 3 < drawingRect.Right) {
g.DrawLine(BrushRegistry.GetPen(marker.Color), i + 3, drawYPos + 1 - 4, i + 6, drawYPos + 3 - 4);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?