From 8f8218c216b6b73311a690a2deb8000c512c3804 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 4 Oct 2005 19:19:36 +0000 Subject: [PATCH] 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 --- .../Project/Src/Document/DefaultDocument.cs | 3 + .../Project/Src/Gui/Caret.cs | 2 +- .../Project/Src/Gui/GutterMargin.cs | 3 +- .../Project/Src/Gui/HRuler.cs | 2 +- .../Project/Src/Gui/TextArea.cs | 6 +- .../Project/Src/Gui/TextAreaControl.cs | 4 +- .../Project/Src/Gui/TextEditorControl.cs | 10 +- .../Project/Src/Gui/TextView.cs | 256 ++++++++++-------- 8 files changed, 157 insertions(+), 129 deletions(-) diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs index 142868126c..e8c34fb808 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/DefaultDocument.cs @@ -274,6 +274,9 @@ namespace ICSharpCode.TextEditor.Document 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); } public string GetText(ISegment segment) diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs index 2ad577612b..c17fb831c6 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/Caret.cs +++ b/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); break; 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; } } diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs index e1e4409ef4..a544b24c94 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/GutterMargin.cs @@ -43,7 +43,8 @@ namespace ICSharpCode.TextEditor public override Size Size { 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); } } diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs index b73b1567c2..b185e536c8 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/HRuler.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.TextEditor { Graphics g = e.Graphics; 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; if (num % 5 == 0) { offset = (Height * 4) / 5; diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs index bc6c2fc713..8a1eaa84e2 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextArea.cs @@ -253,12 +253,12 @@ namespace ICSharpCode.TextEditor 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) { - 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() @@ -735,7 +735,7 @@ namespace ICSharpCode.TextEditor // 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) diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs index 3c79789ce0..35832596f5 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextAreaControl.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.TextEditor int max = 0; foreach (ISegment lineSegment in Document.LineSegmentCollection) { 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; @@ -162,7 +162,7 @@ namespace ICSharpCode.TextEditor vScrollBar.SmallChange = Math.Max(0, textArea.TextView.FontHeight); 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() diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs index e6706fc756..0ea9837340 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs @@ -237,7 +237,7 @@ namespace ICSharpCode.TextEditor // 100 should be enough for everyone ...err ? float[] tabStops = new float[100]; 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); @@ -264,13 +264,13 @@ namespace ICSharpCode.TextEditor foreach (TextWord word in line.Words) { switch (word.Type) { 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) { // curTabIndent = xPos; // } break; 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) { // curTabIndent = xPos; // } @@ -298,13 +298,13 @@ namespace ICSharpCode.TextEditor foreach (TextWord word in line.Words) { switch (word.Type) { 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) { // curTabIndent = xPos; // } break; 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) { // curTabIndent = xPos; // } diff --git a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs index 677a0e1e22..13e11b850a 100644 --- a/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs +++ b/src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextView.cs @@ -32,8 +32,8 @@ namespace ICSharpCode.TextEditor public class TextView : AbstractMargin { int fontHeight; - Hashtable charWitdh = new Hashtable(); - StringFormat measureStringFormat = (StringFormat)System.Drawing.StringFormat.GenericTypographic.Clone(); + //Hashtable charWitdh = new Hashtable(); + StringFormat measureStringFormat = (StringFormat)StringFormat.GenericTypographic.Clone(); Highlight highlight; int physicalColumn = 0; // used for calculating physical column during paint @@ -95,7 +95,7 @@ namespace ICSharpCode.TextEditor public int VisibleColumnCount { 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; } + float spaceWidth; + + /// + /// Gets the width of a space character. + /// This value can be quite small in some fonts - consider using WideSpaceWidth instead. + /// + public float SpaceWidth { + get { + return spaceWidth; + } + } + + float wideSpaceWidth; + + /// + /// 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. + /// + public float WideSpaceWidth { + get { + return wideSpaceWidth; + } + } + + Font lastFont; + public void OptionsChanged() { - this.fontHeight = GetFontHeight(TextEditorProperties.Font); - if (this.charWitdh != null) { - this.charWitdh.Clear(); - } + 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 @@ -132,13 +161,12 @@ namespace ICSharpCode.TextEditor } // Just to ensure that fontHeight and char widths are always correct... - if (fontHeight != GetFontHeight(TextEditorProperties.Font)) { + if (lastFont != TextEditorProperties.Font) { OptionsChanged(); - base.TextArea.Refresh(); - return; + base.TextArea.BeginInvoke(new MethodInvoker(base.TextArea.Refresh)); } - int horizontalDelta = (int)(textArea.VirtualTop.X * GetWidth(g, ' ')); + int horizontalDelta = (int)(textArea.VirtualTop.X * SpaceWidth); if (horizontalDelta > 0) { g.SetClip(this.DrawingPosition); } @@ -221,7 +249,7 @@ namespace ICSharpCode.TextEditor LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber); HighlightColor selectionColor = textArea.Document.HighlightingStrategy.GetColorFor("Selection"); - float spaceWidth = GetWidth(g, ' '); + float spaceWidth = SpaceWidth; bool selectionBeyondEOL = selectionRange.EndColumn > currentLine.Length || ColumnRange.WholeColumn.Equals(selectionRange); if (TextEditorProperties.ShowEOLMarker) { @@ -339,7 +367,7 @@ namespace ICSharpCode.TextEditor HighlightColor tabMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("TabMarkers"); HighlightColor spaceMarkerColor = textArea.Document.HighlightingStrategy.GetColorFor("SpaceMarkers"); - float spaceWidth = GetWidth(g, ' '); + float spaceWidth = SpaceWidth; LineSegment currentLine = textArea.Document.GetLineSegment(lineNumber); @@ -377,14 +405,10 @@ namespace ICSharpCode.TextEditor List markers = Document.MarkerStrategy.GetMarkers(currentLine.Offset + wordOffset); foreach (TextMarker marker in markers) { if (marker.TextMarkerType == TextMarkerType.SolidBlock) { -// if (unselectedBackgroundBrush != null) { -// unselectedBackgroundBrush.Dispose(); -// } unselectedBackgroundBrush = BrushRegistry.GetBrush(marker.Color); break; } } - // Clear old marker arrary // TODO: cut the word if startColumn or endColimn is in the word; @@ -427,11 +451,13 @@ namespace ICSharpCode.TextEditor case TextWordType.Tab: - int oldPhysicalColumn = physicalColumn; physicalColumn += TextEditorProperties.TabIndent; physicalColumn = (physicalColumn / TextEditorProperties.TabIndent) * TextEditorProperties.TabIndent; - float tabWidth = (physicalColumn - oldPhysicalColumn) * spaceWidth; - RectangleF tabRectangle = new RectangleF(physicalXPos, lineRectangle.Y, (float)Math.Ceiling(tabWidth), lineRectangle.Height); + // go to next tabstop + 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; if (ColumnRange.WholeColumn.Equals(selectionRange) || logicalColumn >= selectionRange.StartColumn && logicalColumn <= selectionRange.EndColumn - 1) { @@ -458,7 +484,7 @@ namespace ICSharpCode.TextEditor } } - physicalXPos += tabWidth; + physicalXPos = physicalTabEnd; ++logicalColumn; break; @@ -521,9 +547,6 @@ namespace ICSharpCode.TextEditor wordBackgroundBrush); } } -// if (markerBrush != null) { -// markerBrush.Dispose(); -// } foreach (TextMarker marker in markers) { if (marker.TextMarkerType != TextMarkerType.SolidBlock) { DrawMarker(g, marker, new RectangleF(lastPos, lineRectangle.Y, (physicalXPos - lastPos), lineRectangle.Height)); @@ -541,55 +564,24 @@ namespace ICSharpCode.TextEditor logicalColumn += word.Length; 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; } + //int num; + float DrawDocumentWord(Graphics g, string word, Point position, Font font, Color foreColor, Brush backBrush) { if (word == null || word.Length == 0) { return 0f; } -// TextFormatFlags flags = TextFormatFlags.NoOverhangPadding | -// TextFormatFlags.NoPrefix | -// TextFormatFlags.NoFullWidthCharacterBreak | -// TextFormatFlags.NoClipping | -// 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, + 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, @@ -600,37 +592,30 @@ namespace ICSharpCode.TextEditor measureStringFormat); 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; - for (int i = 0; i < text.Length; ++i) { - width += GetWidth(text[i]); - } - return width; + if (word == null || word.Length == 0) + return 0; + // return g.MeasureString(word, font, 32768, measureStringFormat).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) - { - if (!charWitdh.ContainsKey(ch)) { - charWitdh.Add(ch, g.MeasureString(ch.ToString(), TextEditorProperties.Font, 2000, measureStringFormat).Width); - } - return (float)charWitdh[ch]; - } + #region Conversion Functions + static Dictionary> fontBoundCharWidth = new Dictionary>(); - Dictionary> fontBoundCharWidth = new Dictionary>(); public float GetWidth(char ch, Font font) { if (!fontBoundCharWidth.ContainsKey(font)) { @@ -644,22 +629,13 @@ namespace ICSharpCode.TextEditor 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) { if (!fontBoundCharWidth.ContainsKey(font)) { fontBoundCharWidth.Add(font, new Dictionary()); } 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]; } @@ -699,7 +675,7 @@ namespace ICSharpCode.TextEditor /// 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 logicalLine = Document.GetFirstLogicalLine(clickedVisualLine); Point pos = GetLogicalColumn(logicalLine, xPos); @@ -717,7 +693,7 @@ namespace ICSharpCode.TextEditor public Point GetLogicalColumn(int firstLogicalLine, int xPos) { - float spaceWidth = GetWidth(' '); + float spaceWidth = SpaceWidth; LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null; if (line == null) { return new Point((int)(xPos / spaceWidth), firstLogicalLine); @@ -765,7 +741,7 @@ namespace ICSharpCode.TextEditor paintPos += (column - oldColumn) * spaceWidth; break; default: - paintPos += GetWidth(ch); + paintPos += GetWidth(ch, TextEditorProperties.Font); ++column; break; } @@ -784,7 +760,7 @@ namespace ICSharpCode.TextEditor /// 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 logicalLine = Document.GetFirstLogicalLine(clickedVisualLine); return GetFoldMarkerFromColumn(logicalLine, xPos); @@ -792,7 +768,7 @@ namespace ICSharpCode.TextEditor FoldMarker GetFoldMarkerFromColumn(int firstLogicalLine, int xPos) { - float spaceWidth = GetWidth(' '); + float spaceWidth = SpaceWidth; LineSegment line = firstLogicalLine < Document.TotalNumberOfLines ? Document.GetLineSegment(firstLogicalLine) : null; if (line == null) { return null; @@ -840,7 +816,7 @@ namespace ICSharpCode.TextEditor paintPos += (column - oldColumn) * spaceWidth; break; default: - paintPos += GetWidth(ch); + paintPos += GetWidth(ch, TextEditorProperties.Font); ++column; 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; int tabIndent = Document.TextEditorProperties.TabIndent; + LineSegment currentLine = Document.GetLineSegment(logicalLine); + List 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) { char ch; - LineSegment line = Document.GetLineSegment(logicalLine); if (j >= line.Length) { ch = ' '; } else { ch = Document.GetCharAt(line.Offset + j); } + switch (ch) { case '\t': int oldColumn = column; @@ -878,19 +900,20 @@ namespace ICSharpCode.TextEditor ++column; TextWord word = line.GetWord(j); if (word == null || word.Font == null) { - drawingPos += GetWidth(ch); + drawingPos += GetWidth(ch, TextEditorProperties.Font); } else { drawingPos += GetWidth(ch, word.Font); } break; } } + //*/ return drawingPos; } public int GetDrawingXPos(int logicalLine, int logicalColumn) { - float spaceWidth = GetWidth(' '); + float spaceWidth = SpaceWidth; List foldings = Document.FoldingManager.GetTopLevelFoldedFoldings(); int i; FoldMarker f = null; @@ -906,9 +929,10 @@ namespace ICSharpCode.TextEditor int column = 0; int tabIndent = Document.TextEditorProperties.TabIndent; float drawingPos; + Graphics g = textArea.CreateGraphics(); // if no folding is interresting 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); } @@ -930,7 +954,7 @@ namespace ICSharpCode.TextEditor firstFolding = i + 1; 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); } @@ -938,13 +962,13 @@ namespace ICSharpCode.TextEditor drawingPos = 0; for (i = firstFolding; i <= lastFolding; ++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; 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); } #endregion @@ -976,7 +1000,7 @@ namespace ICSharpCode.TextEditor 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, new RectangleF(x, y, width, fontHeight)); @@ -993,7 +1017,7 @@ namespace ICSharpCode.TextEditor } 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), xpos, lineRectangle.Top,