Browse Source

Caret is now displayed at the correct position when using non-monospaced fonts. (but selecting with the mouse still doesn't work)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@537 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
8f8218c216
  1. 3
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs
  2. 2
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs
  3. 3
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs
  4. 2
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs
  5. 6
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs
  6. 4
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs
  7. 10
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs
  8. 256
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs

3
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs

@ -274,6 +274,9 @@ namespace ICSharpCode.TextEditor.Document
public string GetText(int offset, int length) public string GetText(int offset, int length)
{ {
#if DEBUG
if (length < 0) throw new ArgumentOutOfRangeException("length", length, "length < 0");
#endif
return textBufferStrategy.GetText(offset, length); return textBufferStrategy.GetText(offset, length);
} }
public string GetText(ISegment segment) public string GetText(ISegment segment)

2
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs

@ -167,7 +167,7 @@ namespace ICSharpCode.TextEditor
caretCreated = CreateCaret(textArea.Handle, 0, 2, textArea.TextView.FontHeight); caretCreated = CreateCaret(textArea.Handle, 0, 2, textArea.TextView.FontHeight);
break; break;
case CaretMode.OverwriteMode: case CaretMode.OverwriteMode:
caretCreated = CreateCaret(textArea.Handle, 0, (int)textArea.TextView.GetWidth(' '), textArea.TextView.FontHeight); caretCreated = CreateCaret(textArea.Handle, 0, (int)textArea.TextView.SpaceWidth, textArea.TextView.FontHeight);
break; break;
} }
} }

3
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs

@ -43,7 +43,8 @@ namespace ICSharpCode.TextEditor
public override Size Size { public override Size Size {
get { get {
return new Size((int)(textArea.TextView.GetWidth('8') * Math.Max(3, (int)Math.Log10(textArea.Document.TotalNumberOfLines) + 1)), return new Size((int)(textArea.TextView.WideSpaceWidth
* Math.Max(3, (int)Math.Log10(textArea.Document.TotalNumberOfLines) + 1)),
-1); -1);
} }
} }

2
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.TextEditor
{ {
Graphics g = e.Graphics; Graphics g = e.Graphics;
int num = 0; int num = 0;
for (float x = textArea.TextView.DrawingPosition.Left; x < textArea.TextView.DrawingPosition.Right; x += textArea.TextView.GetWidth(' ')) { for (float x = textArea.TextView.DrawingPosition.Left; x < textArea.TextView.DrawingPosition.Right; x += textArea.TextView.SpaceWidth) {
int offset = (Height * 2) / 3; int offset = (Height * 2) / 3;
if (num % 5 == 0) { if (num % 5 == 0) {
offset = (Height * 4) / 5; offset = (Height * 4) / 5;

6
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs

@ -253,12 +253,12 @@ namespace ICSharpCode.TextEditor
public void SetDesiredColumn() public void SetDesiredColumn()
{ {
Caret.DesiredColumn = TextView.GetDrawingXPos(Caret.Line, Caret.Column) + (int)(VirtualTop.X * textView.GetWidth(' ')); Caret.DesiredColumn = TextView.GetDrawingXPos(Caret.Line, Caret.Column) + (int)(VirtualTop.X * textView.SpaceWidth);
} }
public void SetCaretToDesiredColumn(int caretLine) public void SetCaretToDesiredColumn(int caretLine)
{ {
Caret.Position = textView.GetLogicalColumn(Caret.Line, Caret.DesiredColumn + (int)(VirtualTop.X * textView.GetWidth(' '))); Caret.Position = textView.GetLogicalColumn(Caret.Line, Caret.DesiredColumn + (int)(VirtualTop.X * textView.SpaceWidth));
} }
public void OptionsChanged() public void OptionsChanged()
@ -735,7 +735,7 @@ namespace ICSharpCode.TextEditor
// return; // return;
// } // }
InvalidateLines((int)(xPos * this.TextView.GetWidth(' ')), lineBegin, lineEnd); InvalidateLines((int)(xPos * this.TextView.SpaceWidth), lineBegin, lineEnd);
} }
void InvalidateLines(int xPos, int lineBegin, int lineEnd) void InvalidateLines(int xPos, int lineBegin, int lineEnd)

4
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.TextEditor
int max = 0; int max = 0;
foreach (ISegment lineSegment in Document.LineSegmentCollection) { foreach (ISegment lineSegment in Document.LineSegmentCollection) {
if(Document.FoldingManager.IsLineVisible(Document.GetLineNumberForOffset(lineSegment.Offset))) { if(Document.FoldingManager.IsLineVisible(Document.GetLineNumberForOffset(lineSegment.Offset))) {
max = Math.Max(lineSegment.Length, max); max = Math.Max(max, textArea.TextView.GetVisualColumn(Document.GetLineNumberForOffset(lineSegment.Offset),lineSegment.Length));
} }
} }
hScrollBar.Minimum = 0; hScrollBar.Minimum = 0;
@ -162,7 +162,7 @@ namespace ICSharpCode.TextEditor
vScrollBar.SmallChange = Math.Max(0, textArea.TextView.FontHeight); vScrollBar.SmallChange = Math.Max(0, textArea.TextView.FontHeight);
hScrollBar.LargeChange = Math.Max(0, textArea.TextView.VisibleColumnCount - 1); hScrollBar.LargeChange = Math.Max(0, textArea.TextView.VisibleColumnCount - 1);
hScrollBar.SmallChange = Math.Max(0, (int)textArea.TextView.GetWidth(' ')); hScrollBar.SmallChange = Math.Max(0, (int)textArea.TextView.SpaceWidth);
} }
public void OptionsChanged() public void OptionsChanged()

10
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs

@ -237,7 +237,7 @@ namespace ICSharpCode.TextEditor
// 100 should be enough for everyone ...err ? // 100 should be enough for everyone ...err ?
float[] tabStops = new float[100]; float[] tabStops = new float[100];
for (int i = 0; i < tabStops.Length; ++i) { for (int i = 0; i < tabStops.Length; ++i) {
tabStops[i] = TabIndent * primaryTextArea.TextArea.TextView.GetWidth(' '); tabStops[i] = TabIndent * primaryTextArea.TextArea.TextView.SpaceWidth;
} }
printingStringFormat.SetTabStops(0, tabStops); printingStringFormat.SetTabStops(0, tabStops);
@ -264,13 +264,13 @@ namespace ICSharpCode.TextEditor
foreach (TextWord word in line.Words) { foreach (TextWord word in line.Words) {
switch (word.Type) { switch (word.Type) {
case TextWordType.Space: case TextWordType.Space:
Advance(ref xPos, ref yPos, maxWidth, primaryTextArea.TextArea.TextView.GetWidth(' '), fontHeight); Advance(ref xPos, ref yPos, maxWidth, primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
// if (!gotNonWhitespace) { // if (!gotNonWhitespace) {
// curTabIndent = xPos; // curTabIndent = xPos;
// } // }
break; break;
case TextWordType.Tab: case TextWordType.Tab:
Advance(ref xPos, ref yPos, maxWidth, TabIndent * primaryTextArea.TextArea.TextView.GetWidth(' '), fontHeight); Advance(ref xPos, ref yPos, maxWidth, TabIndent * primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
// if (!gotNonWhitespace) { // if (!gotNonWhitespace) {
// curTabIndent = xPos; // curTabIndent = xPos;
// } // }
@ -298,13 +298,13 @@ namespace ICSharpCode.TextEditor
foreach (TextWord word in line.Words) { foreach (TextWord word in line.Words) {
switch (word.Type) { switch (word.Type) {
case TextWordType.Space: case TextWordType.Space:
Advance(ref xPos, ref yPos, margin.Width, primaryTextArea.TextArea.TextView.GetWidth(' '), fontHeight); Advance(ref xPos, ref yPos, margin.Width, primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
// if (!gotNonWhitespace) { // if (!gotNonWhitespace) {
// curTabIndent = xPos; // curTabIndent = xPos;
// } // }
break; break;
case TextWordType.Tab: case TextWordType.Tab:
Advance(ref xPos, ref yPos, margin.Width, TabIndent * primaryTextArea.TextArea.TextView.GetWidth(' '), fontHeight); Advance(ref xPos, ref yPos, margin.Width, TabIndent * primaryTextArea.TextArea.TextView.SpaceWidth, fontHeight);
// if (!gotNonWhitespace) { // if (!gotNonWhitespace) {
// curTabIndent = xPos; // curTabIndent = xPos;
// } // }

256
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs

@ -32,8 +32,8 @@ namespace ICSharpCode.TextEditor
public class TextView : AbstractMargin public class TextView : AbstractMargin
{ {
int fontHeight; int fontHeight;
Hashtable charWitdh = new Hashtable(); //Hashtable charWitdh = new Hashtable();
StringFormat measureStringFormat = (StringFormat)System.Drawing.StringFormat.GenericTypographic.Clone(); StringFormat measureStringFormat = (StringFormat)StringFormat.GenericTypographic.Clone();
Highlight highlight; Highlight highlight;
int physicalColumn = 0; // used for calculating physical column during paint int physicalColumn = 0; // used for calculating physical column during paint
@ -95,7 +95,7 @@ namespace ICSharpCode.TextEditor
public int VisibleColumnCount { public int VisibleColumnCount {
get { get {
return (int)(DrawingPosition.Width / GetWidth(' ')) - 1; return (int)(DrawingPosition.Width / SpaceWidth) - 1;
} }
} }
@ -116,12 +116,41 @@ namespace ICSharpCode.TextEditor
return (h < 16) ? h + 1 : h; 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() public void OptionsChanged()
{ {
this.fontHeight = GetFontHeight(TextEditorProperties.Font); this.lastFont = TextEditorProperties.Font;
if (this.charWitdh != null) { this.fontHeight = GetFontHeight(lastFont);
this.charWitdh.Clear(); // 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 #region Paint functions
@ -132,13 +161,12 @@ namespace ICSharpCode.TextEditor
} }
// Just to ensure that fontHeight and char widths are always correct... // Just to ensure that fontHeight and char widths are always correct...
if (fontHeight != GetFontHeight(TextEditorProperties.Font)) { if (lastFont != TextEditorProperties.Font) {
OptionsChanged(); OptionsChanged();
base.TextArea.Refresh(); base.TextArea.BeginInvoke(new MethodInvoker(base.TextArea.Refresh));
return;
} }
int horizontalDelta = (int)(textArea.VirtualTop.X * GetWidth(g, ' ')); int horizontalDelta = (int)(textArea.VirtualTop.X * SpaceWidth);
if (horizontalDelta > 0) { if (horizontalDelta > 0) {
g.SetClip(this.DrawingPosition); g.SetClip(this.DrawingPosition);
} }
@ -221,7 +249,7 @@ namespace ICSharpCode.TextEditor
LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber); LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber);
HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection"); HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection");
float spaceWidth = GetWidth(g, ' '); float spaceWidth = SpaceWidth;
bool selectionBeyondEOL = selectionRange.EndColumn > currentLine.Length || ColumnRange.WholeColumn.Equals(selectionRange); bool selectionBeyondEOL = selectionRange.EndColumn > currentLine.Length || ColumnRange.WholeColumn.Equals(selectionRange);
if (TextEditorProperties.ShowEOLMarker) { if (TextEditorProperties.ShowEOLMarker) {
@ -339,7 +367,7 @@ namespace ICSharpCode.TextEditor
HighlightColor tabMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("TabMarkers"); HighlightColor tabMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("TabMarkers");
HighlightColor spaceMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("SpaceMarkers"); HighlightColor spaceMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("SpaceMarkers");
float spaceWidth = GetWidth(g, ' '); float spaceWidth = SpaceWidth;
LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber); LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber);
@ -377,14 +405,10 @@ namespace ICSharpCode.TextEditor
List<TextMarker> markers = Document.MarkerStrategy.GetMarkers(currentLine.Offset + wordOffset); List<TextMarker> markers = Document.MarkerStrategy.GetMarkers(currentLine.Offset + wordOffset);
foreach (TextMarker marker in markers) { foreach (TextMarker marker in markers) {
if (marker.TextMarkerType == TextMarkerType.SolidBlock) { if (marker.TextMarkerType == TextMarkerType.SolidBlock) {
// if (unselectedBackgroundBrush != null) {
// unselectedBackgroundBrush.Dispose();
// }
unselectedBackgroundBrush = BrushRegistry.GetBrush(marker.Color); unselectedBackgroundBrush = BrushRegistry.GetBrush(marker.Color);
break; break;
} }
} }
// Clear old marker arrary
// TODO: cut the word if startColumn or endColimn is in the word; // TODO: cut the word if startColumn or endColimn is in the word;
@ -427,11 +451,13 @@ namespace ICSharpCode.TextEditor
case TextWordType.Tab: case TextWordType.Tab:
int oldPhysicalColumn = physicalColumn;
physicalColumn += TextEditorProperties.TabIndent; physicalColumn += TextEditorProperties.TabIndent;
physicalColumn = (physicalColumn / TextEditorProperties.TabIndent) * TextEditorProperties.TabIndent; physicalColumn = (physicalColumn / TextEditorProperties.TabIndent) * TextEditorProperties.TabIndent;
float tabWidth = (physicalColumn - oldPhysicalColumn) * spaceWidth; // go to next tabstop
RectangleF tabRectangle = new RectangleF(physicalXPos, lineRectangle.Y, (float)Math.Ceiling(tabWidth), lineRectangle.Height); float physicalTabEnd = (int)((physicalXPos + MinTabWidth - drawingPosition.Left) / WideSpaceWidth / TextEditorProperties.TabIndent)
* WideSpaceWidth * TextEditorProperties.TabIndent + drawingPosition.Left;
physicalTabEnd += WideSpaceWidth * TextEditorProperties.TabIndent;
RectangleF tabRectangle = new RectangleF(physicalXPos, lineRectangle.Y, (float)Math.Ceiling(physicalTabEnd - physicalXPos), lineRectangle.Height);
Color tabMarkerForeColor = tabMarkerColor.Color; Color tabMarkerForeColor = tabMarkerColor.Color;
if (ColumnRange.WholeColumn.Equals(selectionRange) || logicalColumn >= selectionRange.StartColumn && logicalColumn <= selectionRange.EndColumn - 1) { if (ColumnRange.WholeColumn.Equals(selectionRange) || logicalColumn >= selectionRange.StartColumn && logicalColumn <= selectionRange.EndColumn - 1) {
@ -458,7 +484,7 @@ namespace ICSharpCode.TextEditor
} }
} }
physicalXPos += tabWidth; physicalXPos = physicalTabEnd;
++logicalColumn; ++logicalColumn;
break; break;
@ -521,9 +547,6 @@ namespace ICSharpCode.TextEditor
wordBackgroundBrush); wordBackgroundBrush);
} }
} }
// if (markerBrush != null) {
// markerBrush.Dispose();
// }
foreach (TextMarker marker in markers) { foreach (TextMarker marker in markers) {
if (marker.TextMarkerType != TextMarkerType.SolidBlock) { if (marker.TextMarkerType != TextMarkerType.SolidBlock) {
DrawMarker(g, marker, new RectangleF(lastPos, lineRectangle.Y, (physicalXPos - lastPos), lineRectangle.Height)); DrawMarker(g, marker, new RectangleF(lastPos, lineRectangle.Y, (physicalXPos - lastPos), lineRectangle.Height));
@ -541,55 +564,24 @@ namespace ICSharpCode.TextEditor
logicalColumn += word.Length; logicalColumn += word.Length;
break; break;
} }
//markers.Clear();
} }
} }
// if (bgColorBrush != null) {
// bgColorBrush.Dispose();
// bgColorBrush = null;
// }
//
// if (selectionBackgroundBrush != null) {
// selectionBackgroundBrush.Dispose();
// selectionBackgroundBrush = null;
// }
//
// if (unselectedBackgroundBrush != null) {
// unselectedBackgroundBrush.Dispose();
// unselectedBackgroundBrush = null;
// }
return physicalXPos; return physicalXPos;
} }
//int num;
float DrawDocumentWord(Graphics g, string word, Point position, Font font, Color foreColor, Brush backBrush) float DrawDocumentWord(Graphics g, string word, Point position, Font font, Color foreColor, Brush backBrush)
{ {
if (word == null || word.Length == 0) { if (word == null || word.Length == 0) {
return 0f; return 0f;
} }
// TextFormatFlags flags = TextFormatFlags.NoOverhangPadding | float wordWidth = MeasureStringWidth(g, word, font);
// TextFormatFlags.NoPrefix |
// TextFormatFlags.NoFullWidthCharacterBreak | //num = ++num % 3;
// TextFormatFlags.NoClipping | g.FillRectangle(backBrush, //num == 0 ? Brushes.LightBlue : num == 1 ? Brushes.LightGreen : Brushes.Yellow,
// TextFormatFlags.PreserveGraphicsClipping |
// TextFormatFlags.PrefixOnly |
// TextFormatFlags.SingleLine;
// Size wordSize = TextRenderer.MeasureText(word, font, Size.Empty, flags);
//
// if (DrawingPosition.Left < position.X + DrawingPosition.X) {
// TextRenderer.DrawText(g,
// word,
// font,
// position,
// foreColor,
// ((SolidBrush)backBrush).Color,
// flags
// );
// }
float wordWidth = g.MeasureString(word, font, 32768, measureStringFormat).Width;
g.FillRectangle(backBrush,
new RectangleF(position.X, position.Y, (float)Math.Ceiling(wordWidth + 1), FontHeight)); new RectangleF(position.X, position.Y, (float)Math.Ceiling(wordWidth + 1), FontHeight));
g.DrawString(word, g.DrawString(word,
@ -600,37 +592,30 @@ namespace ICSharpCode.TextEditor
measureStringFormat); measureStringFormat);
return wordWidth; return wordWidth;
} }
#endregion
#region Conversion Functions
public float GetWidth(char ch)
{
if (!charWitdh.ContainsKey(ch)) {
using (Graphics g = textArea.CreateGraphics()) {
return GetWidth(g, ch);
}
}
return (float)charWitdh[ch];
}
public float GetWidth(string text) float MeasureStringWidth(Graphics g, string word, Font font)
{ {
float width = 0; if (word == null || word.Length == 0)
for (int i = 0; i < text.Length; ++i) { return 0;
width += GetWidth(text[i]); // return g.MeasureString(word, font, 32768, measureStringFormat).Width;
}
return width; // 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);
return regions[0].GetBounds(g).Right;
} }
#endregion
public float GetWidth(Graphics g, char ch) #region Conversion Functions
{ static Dictionary<Font, Dictionary<char, float>> fontBoundCharWidth = new Dictionary<Font, Dictionary<char, float>>();
if (!charWitdh.ContainsKey(ch)) {
charWitdh.Add(ch, g.MeasureString(ch.ToString(), TextEditorProperties.Font, 2000, measureStringFormat).Width);
}
return (float)charWitdh[ch];
}
Dictionary<Font, Dictionary<char, float>> fontBoundCharWidth = new Dictionary<Font, Dictionary<char, float>>();
public float GetWidth(char ch, Font font) public float GetWidth(char ch, Font font)
{ {
if (!fontBoundCharWidth.ContainsKey(font)) { if (!fontBoundCharWidth.ContainsKey(font)) {
@ -644,22 +629,13 @@ namespace ICSharpCode.TextEditor
return (float)fontBoundCharWidth[font][ch]; return (float)fontBoundCharWidth[font][ch];
} }
public float GetWidth(string text, Font font)
{
float width = 0;
for (int i = 0; i < text.Length; ++i) {
width += GetWidth(text[i], font);
}
return width;
}
public float GetWidth(Graphics g, char ch, Font font) public float GetWidth(Graphics g, char ch, Font font)
{ {
if (!fontBoundCharWidth.ContainsKey(font)) { if (!fontBoundCharWidth.ContainsKey(font)) {
fontBoundCharWidth.Add(font, new Dictionary<char, float>()); fontBoundCharWidth.Add(font, new Dictionary<char, float>());
} }
if (!fontBoundCharWidth[font].ContainsKey(ch)) { if (!fontBoundCharWidth[font].ContainsKey(ch)) {
fontBoundCharWidth[font].Add(ch, g.MeasureString(ch.ToString(), font, 2000, measureStringFormat).Width); fontBoundCharWidth[font].Add(ch, MeasureStringWidth(g, ch.ToString(), font));
} }
return (float)fontBoundCharWidth[font][ch]; return (float)fontBoundCharWidth[font][ch];
} }
@ -699,7 +675,7 @@ namespace ICSharpCode.TextEditor
/// </summary> /// </summary>
public Point GetLogicalPosition(int xPos, int yPos) public Point GetLogicalPosition(int xPos, int yPos)
{ {
xPos += (int)(textArea.VirtualTop.X * GetWidth(' ')); xPos += (int)(textArea.VirtualTop.X * SpaceWidth);
int clickedVisualLine = Math.Max(0, (yPos + this.textArea.VirtualTop.Y) / fontHeight); int clickedVisualLine = Math.Max(0, (yPos + this.textArea.VirtualTop.Y) / fontHeight);
int logicalLine = Document.GetFirstLogicalLine(clickedVisualLine); int logicalLine = Document.GetFirstLogicalLine(clickedVisualLine);
Point pos = GetLogicalColumn(logicalLine, xPos); Point pos = GetLogicalColumn(logicalLine, xPos);
@ -717,7 +693,7 @@ namespace ICSharpCode.TextEditor
public Point GetLogicalColumn(int firstLogicalLine, int xPos) public Point GetLogicalColumn(int firstLogicalLine, int xPos)
{ {
float spaceWidth = GetWidth(' '); float spaceWidth = SpaceWidth;
LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null; LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null;
if (line == null) { if (line == null) {
return new Point((int)(xPos / spaceWidth), firstLogicalLine); return new Point((int)(xPos / spaceWidth), firstLogicalLine);
@ -765,7 +741,7 @@ namespace ICSharpCode.TextEditor
paintPos += (column - oldColumn) * spaceWidth; paintPos += (column - oldColumn) * spaceWidth;
break; break;
default: default:
paintPos += GetWidth(ch); paintPos += GetWidth(ch, TextEditorProperties.Font);
++column; ++column;
break; break;
} }
@ -784,7 +760,7 @@ namespace ICSharpCode.TextEditor
/// </summary> /// </summary>
public FoldMarker GetFoldMarkerFromPosition(int xPos, int yPos) public FoldMarker GetFoldMarkerFromPosition(int xPos, int yPos)
{ {
xPos += (int)(textArea.VirtualTop.X * GetWidth(' ')); xPos += (int)(textArea.VirtualTop.X * SpaceWidth);
int clickedVisualLine = (yPos + this.textArea.VirtualTop.Y) / fontHeight; int clickedVisualLine = (yPos + this.textArea.VirtualTop.Y) / fontHeight;
int logicalLine = Document.GetFirstLogicalLine(clickedVisualLine); int logicalLine = Document.GetFirstLogicalLine(clickedVisualLine);
return GetFoldMarkerFromColumn(logicalLine, xPos); return GetFoldMarkerFromColumn(logicalLine, xPos);
@ -792,7 +768,7 @@ namespace ICSharpCode.TextEditor
FoldMarker GetFoldMarkerFromColumn(int firstLogicalLine, int xPos) FoldMarker GetFoldMarkerFromColumn(int firstLogicalLine, int xPos)
{ {
float spaceWidth = GetWidth(' '); float spaceWidth = SpaceWidth;
LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null; LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null;
if (line == null) { if (line == null) {
return null; return null;
@ -840,7 +816,7 @@ namespace ICSharpCode.TextEditor
paintPos += (column - oldColumn) * spaceWidth; paintPos += (column - oldColumn) * spaceWidth;
break; break;
default: default:
paintPos += GetWidth(ch); paintPos += GetWidth(ch, TextEditorProperties.Font);
++column; ++column;
break; break;
} }
@ -854,19 +830,65 @@ namespace ICSharpCode.TextEditor
} }
} }
float CountColumns(ref int column, int start, int end, int logicalLine) const float MinTabWidth = 4;
float CountColumns(ref int column, int start, int end, int logicalLine, Graphics g)
{ {
float spaceWidth = GetWidth(' '); if (start > end) throw new ArgumentException("start > end");
float spaceWidth = SpaceWidth;
float drawingPos = 0; float drawingPos = 0;
int tabIndent = Document.TextEditorProperties.TabIndent; int tabIndent = Document.TextEditorProperties.TabIndent;
LineSegment currentLine = Document.GetLineSegment(logicalLine);
List<TextWord> words = currentLine.Words;
if (words == null) return 0;
int wordCount = words.Count;
int wordOffset = 0;
for (int i = 0; i < wordCount; i++) {
TextWord word = words[i];
if (wordOffset >= end)
break;
if (wordOffset + word.Length < start)
continue;
switch (word.Type) {
case TextWordType.Space:
++column;
drawingPos += spaceWidth;
break;
case TextWordType.Tab:
int oldColumn = column;
column += tabIndent;
column = (column / tabIndent) * tabIndent;
// go to next tab position
drawingPos = (int)((drawingPos + MinTabWidth) / tabIndent / WideSpaceWidth) * tabIndent * WideSpaceWidth;
drawingPos += tabIndent * WideSpaceWidth;
break;
case TextWordType.Word:
if (word.Length == 1) {
++column;
drawingPos += GetWidth(g, word.Word[0], word.Font ?? TextEditorProperties.Font);
} else {
int wordStart = Math.Max(wordOffset, start);
int wordLength = Math.Min(wordOffset + word.Length, end) - wordStart;
column += wordLength;
drawingPos += MeasureStringWidth(g, Document.GetText(currentLine.Offset + wordStart, wordLength), word.Font ?? TextEditorProperties.Font);
}
break;
}
wordOffset += word.Length;
}
for (int j = currentLine.Length; j < end; j++) {
++column;
drawingPos += SpaceWidth;
}
/* OLD Code (does not work for fonts like Verdana)
for (int j = start; j < end; ++j) { for (int j = start; j < end; ++j) {
char ch; char ch;
LineSegment line = Document.GetLineSegment(logicalLine);
if (j >= line.Length) { if (j >= line.Length) {
ch = ' '; ch = ' ';
} else { } else {
ch = Document.GetCharAt(line.Offset + j); ch = Document.GetCharAt(line.Offset + j);
} }
switch (ch) { switch (ch) {
case '\t': case '\t':
int oldColumn = column; int oldColumn = column;
@ -878,19 +900,20 @@ namespace ICSharpCode.TextEditor
++column; ++column;
TextWord word = line.GetWord(j); TextWord word = line.GetWord(j);
if (word == null || word.Font == null) { if (word == null || word.Font == null) {
drawingPos += GetWidth(ch); drawingPos += GetWidth(ch, TextEditorProperties.Font);
} else { } else {
drawingPos += GetWidth(ch, word.Font); drawingPos += GetWidth(ch, word.Font);
} }
break; break;
} }
} }
//*/
return drawingPos; return drawingPos;
} }
public int GetDrawingXPos(int logicalLine, int logicalColumn) public int GetDrawingXPos(int logicalLine, int logicalColumn)
{ {
float spaceWidth = GetWidth(' '); float spaceWidth = SpaceWidth;
List<FoldMarker> foldings = Document.FoldingManager.GetTopLevelFoldedFoldings(); List<FoldMarker> foldings = Document.FoldingManager.GetTopLevelFoldedFoldings();
int i; int i;
FoldMarker f = null; FoldMarker f = null;
@ -906,9 +929,10 @@ namespace ICSharpCode.TextEditor
int column = 0; int column = 0;
int tabIndent = Document.TextEditorProperties.TabIndent; int tabIndent = Document.TextEditorProperties.TabIndent;
float drawingPos; float drawingPos;
Graphics g = textArea.CreateGraphics();
// if no folding is interresting // if no folding is interresting
if (f == null || !(f.StartLine < logicalLine || f.StartLine == logicalLine && f.StartColumn < logicalColumn)) { if (f == null || !(f.StartLine < logicalLine || f.StartLine == logicalLine && f.StartColumn < logicalColumn)) {
drawingPos = CountColumns(ref column, 0, logicalColumn, logicalLine); drawingPos = CountColumns(ref column, 0, logicalColumn, logicalLine, g);
return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth); return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth);
} }
@ -930,7 +954,7 @@ namespace ICSharpCode.TextEditor
firstFolding = i + 1; firstFolding = i + 1;
if (lastFolding < firstFolding) { if (lastFolding < firstFolding) {
drawingPos = CountColumns(ref column, 0, logicalColumn, logicalLine); drawingPos = CountColumns(ref column, 0, logicalColumn, logicalLine, g);
return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth); return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth);
} }
@ -938,13 +962,13 @@ namespace ICSharpCode.TextEditor
drawingPos = 0; drawingPos = 0;
for (i = firstFolding; i <= lastFolding; ++i) { for (i = firstFolding; i <= lastFolding; ++i) {
f = (FoldMarker)foldings[i]; f = (FoldMarker)foldings[i];
drawingPos += CountColumns(ref column, foldEnd, f.StartColumn, f.StartLine); drawingPos += CountColumns(ref column, foldEnd, f.StartColumn, f.StartLine, g);
foldEnd = f.EndColumn; foldEnd = f.EndColumn;
column += f.FoldText.Length; column += f.FoldText.Length;
drawingPos += GetWidth(f.FoldText); drawingPos += MeasureStringWidth(g, f.FoldText, TextEditorProperties.Font);
} }
drawingPos += CountColumns(ref column, foldEnd, logicalColumn, logicalLine); drawingPos += CountColumns(ref column, foldEnd, logicalColumn, logicalLine, g);
g.Dispose();
return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth); return (int)(drawingPos - textArea.VirtualTop.X * spaceWidth);
} }
#endregion #endregion
@ -976,7 +1000,7 @@ namespace ICSharpCode.TextEditor
float DrawEOLMarker(Graphics g, Color color, Brush backBrush, float x, float y) float DrawEOLMarker(Graphics g, Color color, Brush backBrush, float x, float y)
{ {
float width = GetWidth(g, '\u00B6'); float width = GetWidth('\u00B6', TextEditorProperties.Font);
g.FillRectangle(backBrush, g.FillRectangle(backBrush,
new RectangleF(x, y, width, fontHeight)); new RectangleF(x, y, width, fontHeight));
@ -993,7 +1017,7 @@ namespace ICSharpCode.TextEditor
} }
HighlightColor vRulerColor = textArea.Document.HighlightingStrategy.GetColorFor("VRuler"); HighlightColor vRulerColor = textArea.Document.HighlightingStrategy.GetColorFor("VRuler");
int xpos = (int)(drawingPosition.Left + GetWidth(g, ' ') * (TextEditorProperties.VerticalRulerRow - textArea.VirtualTop.X)); int xpos = (int)(drawingPosition.Left + SpaceWidth * (TextEditorProperties.VerticalRulerRow - textArea.VirtualTop.X));
g.DrawLine(BrushRegistry.GetPen(vRulerColor.Color), g.DrawLine(BrushRegistry.GetPen(vRulerColor.Color),
xpos, xpos,
lineRectangle.Top, lineRectangle.Top,

Loading…
Cancel
Save