textview.cs
来自「SharpDevelop2.0.0 c#开发免费工具」· CS 代码 · 共 1,093 行 · 第 1/3 页
CS
1,093 行
}
break;
case TextMarkerType.SolidBlock:
g.FillRectangle(BrushRegistry.GetBrush(marker.Color), drawingRect);
break;
}
}
markersToDraw.Clear();
}
/// <summary>
/// Get the marker brush (for solid block markers) at a given position.
/// </summary>
/// <param name="offset">The offset.</param>
/// <param name="length">The length.</param>
/// <param name="markers">All markers that have been found.</param>
/// <returns>The Brush or null when no marker was found.</returns>
Brush GetMarkerBrushAt(int offset, int length, ref Color foreColor, out IList<TextMarker> markers)
{
markers = Document.MarkerStrategy.GetMarkers(offset, length);
foreach (TextMarker marker in markers) {
if (marker.TextMarkerType == TextMarkerType.SolidBlock) {
if (marker.OverrideForeColor) {
foreColor = marker.ForeColor;
}
return BrushRegistry.GetBrush(marker.Color);
}
}
return null;
}
float PaintLinePart(Graphics g, int lineNumber, int startColumn, int endColumn, Rectangle lineRectangle, float physicalXPos)
{
bool drawLineMarker = DrawLineMarkerAtLine(lineNumber);
Brush backgroundBrush = textArea.Enabled ? GetBgColorBrush(lineNumber) : SystemBrushes.InactiveBorder;
HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
ColumnRange selectionRange = textArea.SelectionManager.GetSelectionAtLine(lineNumber);
HighlightColor tabMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("TabMarkers");
HighlightColor spaceMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("SpaceMarkers");
LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber);
Brush selectionBackgroundBrush = BrushRegistry.GetBrush(selectionColor.BackgroundColor);
if (currentLine.Words == null) {
return physicalXPos;
}
int currentWordOffset = 0; // we cannot use currentWord.Offset because it is not set on space words
TextWord currentWord;
TextWord nextCurrentWord = null;
for (int wordIdx = 0; wordIdx < currentLine.Words.Count; wordIdx++) {
currentWord = currentLine.Words[wordIdx];
if (currentWordOffset < startColumn) {
// TODO: maybe we need to split at startColumn when we support fold markers
// inside words
currentWordOffset += currentWord.Length;
continue;
}
repeatDrawCurrentWord:
//physicalXPos += 10; // leave room between drawn words - useful for debugging the drawing code
if (currentWordOffset >= endColumn || physicalXPos >= lineRectangle.Right) {
break;
}
int currentWordEndOffset = currentWordOffset + currentWord.Length - 1;
TextWordType currentWordType = currentWord.Type;
IList<TextMarker> markers;
Color wordForeColor;
if (currentWordType == TextWordType.Space)
wordForeColor = spaceMarkerColor.Color;
else if (currentWordType == TextWordType.Tab)
wordForeColor = tabMarkerColor.Color;
else
wordForeColor = currentWord.Color;
Brush wordBackBrush = GetMarkerBrushAt(currentLine.Offset + currentWordOffset, currentWord.Length, ref wordForeColor, out markers);
// It is possible that we have to split the current word because a marker/the selection begins/ends inside it
if (currentWord.Length > 1) {
int splitPos = int.MaxValue;
if (highlight != null) {
// split both before and after highlight
if (highlight.OpenBrace.Y == lineNumber) {
if (highlight.OpenBrace.X >= currentWordOffset && highlight.OpenBrace.X <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, highlight.OpenBrace.X - currentWordOffset);
}
}
if (highlight.CloseBrace.Y == lineNumber) {
if (highlight.CloseBrace.X >= currentWordOffset && highlight.CloseBrace.X <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, highlight.CloseBrace.X - currentWordOffset);
}
}
if (splitPos == 0) {
splitPos = 1; // split after highlight
}
}
if (endColumn < currentWordEndOffset) { // split when endColumn is reached
splitPos = Math.Min(splitPos, endColumn - currentWordOffset);
}
if (selectionRange.StartColumn > currentWordOffset && selectionRange.StartColumn <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, selectionRange.StartColumn - currentWordOffset);
} else if (selectionRange.EndColumn > currentWordOffset && selectionRange.EndColumn <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, selectionRange.EndColumn - currentWordOffset);
}
foreach (TextMarker marker in markers) {
int markerColumn = marker.Offset - currentLine.Offset;
int markerEndColumn = marker.EndOffset - currentLine.Offset + 1; // make end offset exclusive
if (markerColumn > currentWordOffset && markerColumn <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, markerColumn - currentWordOffset);
} else if (markerEndColumn > currentWordOffset && markerEndColumn <= currentWordEndOffset) {
splitPos = Math.Min(splitPos, markerEndColumn - currentWordOffset);
}
}
if (splitPos != int.MaxValue) {
if (nextCurrentWord != null)
throw new ApplicationException("split part invalid: first part cannot be splitted further");
nextCurrentWord = TextWord.Split(ref currentWord, splitPos);
goto repeatDrawCurrentWord; // get markers for first word part
}
}
// get colors from selection status:
if (ColumnRange.WholeColumn.Equals(selectionRange) || (selectionRange.StartColumn <= currentWordOffset
&& selectionRange.EndColumn > currentWordEndOffset))
{
// word is completely selected
wordBackBrush = selectionBackgroundBrush;
if (selectionColor.HasForeground) {
wordForeColor = selectionColor.Color;
}
} else if (drawLineMarker) {
wordBackBrush = backgroundBrush;
}
if (wordBackBrush == null) { // use default background if no other background is set
if (currentWord.SyntaxColor != null && currentWord.SyntaxColor.HasBackground)
wordBackBrush = BrushRegistry.GetBrush(currentWord.SyntaxColor.BackgroundColor);
else
wordBackBrush = backgroundBrush;
}
RectangleF wordRectangle;
if (currentWord.Type == TextWordType.Space) {
++physicalColumn;
wordRectangle = new RectangleF(physicalXPos, lineRectangle.Y, (float)Math.Ceiling(SpaceWidth), lineRectangle.Height);
g.FillRectangle(wordBackBrush, wordRectangle);
if (TextEditorProperties.ShowSpaces) {
DrawSpaceMarker(g, wordForeColor, physicalXPos, lineRectangle.Y);
}
physicalXPos += SpaceWidth;
} else if (currentWord.Type == TextWordType.Tab) {
physicalColumn += TextEditorProperties.TabIndent;
physicalColumn = (physicalColumn / TextEditorProperties.TabIndent) * TextEditorProperties.TabIndent;
// go to next tabstop
float physicalTabEnd = (int)((physicalXPos + MinTabWidth - lineRectangle.X)
/ WideSpaceWidth / TextEditorProperties.TabIndent)
* WideSpaceWidth * TextEditorProperties.TabIndent + lineRectangle.X;
physicalTabEnd += WideSpaceWidth * TextEditorProperties.TabIndent;
wordRectangle = new RectangleF(physicalXPos, lineRectangle.Y, (float)Math.Ceiling(physicalTabEnd - physicalXPos), lineRectangle.Height);
g.FillRectangle(wordBackBrush, wordRectangle);
if (TextEditorProperties.ShowTabs) {
DrawTabMarker(g, wordForeColor, physicalXPos, lineRectangle.Y);
}
physicalXPos = physicalTabEnd;
} else {
float wordWidth = DrawDocumentWord(g,
currentWord.Word,
new Point((int)physicalXPos, lineRectangle.Y),
currentWord.Font,
wordForeColor,
wordBackBrush);
wordRectangle = new RectangleF(physicalXPos, lineRectangle.Y, wordWidth, lineRectangle.Height);
physicalXPos += wordWidth;
}
foreach (TextMarker marker in markers) {
if (marker.TextMarkerType != TextMarkerType.SolidBlock) {
DrawMarker(g, marker, wordRectangle);
}
}
// draw bracket highlight
if (highlight != null) {
if (highlight.OpenBrace.Y == lineNumber && highlight.OpenBrace.X == currentWordOffset ||
highlight.CloseBrace.Y == lineNumber && highlight.CloseBrace.X == currentWordOffset) {
DrawBracketHighlight(g, new Rectangle((int)wordRectangle.X, lineRectangle.Y, (int)wordRectangle.Width - 1, lineRectangle.Height - 1));
}
}
currentWordOffset += currentWord.Length;
if (nextCurrentWord != null) {
currentWord = nextCurrentWord;
nextCurrentWord = null;
goto repeatDrawCurrentWord;
}
}
if (physicalXPos < lineRectangle.Right && endColumn >= currentLine.Length) {
// draw markers at line end
IList<TextMarker> markers = Document.MarkerStrategy.GetMarkers(currentLine.Offset + currentLine.Length);
foreach (TextMarker marker in markers) {
if (marker.TextMarkerType != TextMarkerType.SolidBlock) {
DrawMarker(g, marker, new RectangleF(physicalXPos, lineRectangle.Y, WideSpaceWidth, lineRectangle.Height));
}
}
}
return physicalXPos;
}
float DrawDocumentWord(Graphics g, string word, Point position, Font font, Color foreColor, Brush backBrush)
{
if (word == null || word.Length == 0) {
return 0f;
}
if (word.Length > MaximumWordLength) {
float width = 0;
for (int i = 0; i < word.Length; i += MaximumWordLength) {
Point pos = position;
pos.X += (int)width;
if (i + MaximumWordLength < word.Length)
width += DrawDocumentWord(g, word.Substring(i, MaximumWordLength), pos, font, foreColor, backBrush);
else
width += DrawDocumentWord(g, word.Substring(i, word.Length - i), pos, font, foreColor, backBrush);
}
return width;
}
float wordWidth = MeasureStringWidth(g, word, font);
//num = ++num % 3;
g.FillRectangle(backBrush, //num == 0 ? Brushes.LightBlue : num == 1 ? Brushes.LightGreen : Brushes.Yellow,
new RectangleF(position.X, position.Y, (float)Math.Ceiling(wordWidth + 1), FontHeight));
g.DrawString(word,
font,
BrushRegistry.GetBrush(foreColor),
position.X,
position.Y,
measureStringFormat);
return wordWidth;
}
struct WordFontPair {
string word;
Font font;
public WordFontPair(string word, Font font) {
this.word = word;
this.font = font;
}
public override bool Equals(object obj) {
WordFontPair myWordFontPair = (WordFontPair)obj;
if (!word.Equals(myWordFontPair.word)) return false;
return font.Equals(myWordFontPair.font);
}
public override int GetHashCode() {
return word.GetHashCode() ^ font.GetHashCode();
}
}
Dictionary<WordFontPair, float> measureCache = new Dictionary<WordFontPair, float>();
// split words after 1000 characters. Fixes GDI+ crash on very longs words, for example
// a 100 KB Base64-file without any line breaks.
const int MaximumWordLength = 1000;
float MeasureStringWidth(Graphics g, string word, Font font)
{
float width;
if (word == null || word.Length == 0)
return 0;
if (word.Length > MaximumWordLength) {
width = 0;
for (int i = 0; i < word.Length; i += MaximumWordLength) {
if (i + MaximumWordLength < word.Length)
width += MeasureStringWidth(g, word.Substring(i, MaximumWordLength), font);
else
width += MeasureStringWidth(g, word.Substring(i, word.Length - i), font);
}
return width;
}
if (measureCache.TryGetValue(new WordFontPair(word, font), out width)) {
return width;
}
if (measureCache.Count > 1000) {
measureCache.Clear();
}
// This code here provides better results than MeasureString!
// Example line that is measured wrong:
// txt.GetPositionFromCharIndex(txt.SelectionStart)
// (Verdana 10, highlighting makes GetP... bold) -> note the space between 'x' and '('
// this also fixes "jumping" characters when selecting in non-monospace fonts
Rectangle rect = new Rectangle(0, 0, 32768, 1000);
CharacterRange[] ranges = { new CharacterRange(0, word.Length) };
Region[] regions = new Region[1];
measureStringFormat.SetMeasurableCharacterRanges (ranges);
regions = g.MeasureCharacterRanges (word, font, rect, measureStringFormat);
width = regions[0].GetBounds(g).Right;
measureCache.Add(new WordFontPair(word, font), width);
return width;
}
#endregion
#region Conversion Functions
Dictionary<Font, Dictionary<char, float>> fontBoundCharWidth = new Dictionary<Font, Dictionary<char, float>>();
public float GetWidth(char ch, Font font)
{
if (!fontBoundCharWidth.ContainsKey(font)) {
fontBoundCharWidth.Add(font, new Dictionary<char, float>());
}
if (!fontBoundCharWidth[font].ContainsKey(ch)) {
using (Graphics g = textArea.CreateGraphics()) {
return GetWidth(g, ch, font);
}
}
return (float)fontBoundCharWidth[font][ch];
}
public float GetWidth(Graphics g, char ch, Font font)
{
if (!fontBoundCharWidth.ContainsKey(font)) {
fontBoundCharWidth.Add(font, new Dictionary<char, float>());
}
if (!fontBoundCharWidth[font].ContainsKey(ch)) {
//Console.WriteLine("Calculate character width: " + ch);
fontBoundCharWidth[font].Add(ch, MeasureStringWidth(g, ch.ToString(), font));
}
return (float)fontBoundCharWidth[font][ch];
}
public int GetVisualColumn(int logicalLine, int logicalColumn)
{
int column = 0;
using (Graphics g = textArea.CreateGraphics()) {
CountColumns(ref column, 0, logicalColumn, logicalLine, g);
}
return column;
}
public int GetVisualColumnFast(LineSegment line, int logicalColumn)
{
int lineOffset = line.Offset;
int tabIndent = Document.TextEditorProperties.TabIndent;
int guessedColumn = 0;
for (int i = 0; i < logicalColumn; ++i) {
char ch;
if (i >= line.Length) {
ch = ' ';
} else {
ch = Document.GetCharAt(lineOffset + i);
}
switch (ch) {
case '\t':
guessedColumn += tabIndent;
guessedColumn = (guessedColumn / tabIndent) * tabIndent;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?