// * // * Copyright (C) 2008 Roger Alsing : http://www.RogerAlsing.com // * // * This library is free software; you can redistribute it and/or modify it // * under the terms of the GNU Lesser General Public License 2.1 or later, as // * published by the Free Software Foundation. See the included license.txt // * or http://www.gnu.org/copyleft/lesser.html for details. // * // * using System; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.Threading; using System.Windows.Forms; using Alsing.Drawing.GDI; using Alsing.Globalization; using Alsing.SourceCode; namespace Alsing.Windows.Forms.SyntaxBox.Painter { /// /// Painter class that uses GDI32 to render the content of a SyntaxBoxControl /// public class NativePainter : IPainter { private readonly EditViewControl Control; private Word BracketEnd; private Word BracketStart; private int FirstSpanRow; private RenderItems GFX; private int LastRow; private int LastSpanRow; private bool RenderCaretRowOnly; private int ResizeCount; private bool SpanFound; private int yOffset; /// /// NativePainter constructor. /// /// The control that will use the Painter public NativePainter(EditViewControl control) { Control = control; InitGraphics(); } #region IPainter Members /// /// Implementation of the IPainter Resize method /// public void Resize() { ResizeCount++; InitGraphics(); // Console.WriteLine ("painterresize {0} {1}",ResizeCount,Control.Name); } /// /// Implementation of the IPainter MeasureString method /// /// String to measure /// Size of the string in pixels public Size MeasureString(string s) { try { GFX.StringBuffer.Font = GFX.FontNormal; return GFX.StringBuffer.MeasureTabbedString(s, Control.TabSize); } catch { return new Size(0, 0); } } /// /// Implementation of the IPainter InitGraphics method. /// Initializes GDI32 backbuffers and brushes. /// public void InitGraphics() { try { if (GFX.BackgroundBrush != null) GFX.BackgroundBrush.Dispose(); if (GFX.GutterMarginBrush != null) GFX.GutterMarginBrush.Dispose(); if (GFX.LineNumberMarginBrush != null) GFX.LineNumberMarginBrush.Dispose(); if (GFX.HighLightLineBrush != null) GFX.HighLightLineBrush.Dispose(); if (GFX.LineNumberMarginBorderBrush != null) GFX.LineNumberMarginBorderBrush.Dispose(); if (GFX.GutterMarginBorderBrush != null) GFX.GutterMarginBorderBrush.Dispose(); if (GFX.OutlineBrush != null) GFX.OutlineBrush.Dispose(); GFX.BackgroundBrush = new GDIBrush(Control.BackColor); GFX.GutterMarginBrush = new GDIBrush(Control.GutterMarginColor); GFX.LineNumberMarginBrush = new GDIBrush(Control.LineNumberBackColor); GFX.HighLightLineBrush = new GDIBrush(Control.HighLightedLineColor); GFX.LineNumberMarginBorderBrush = new GDIBrush(Control.LineNumberBorderColor); GFX.GutterMarginBorderBrush = new GDIBrush(Control.GutterMarginBorderColor); GFX.OutlineBrush = new GDIBrush(Control.OutlineColor); if (GFX.FontNormal != null) GFX.FontNormal.Dispose(); if (GFX.FontBold != null) GFX.FontBold.Dispose(); if (GFX.FontItalic != null) GFX.FontItalic.Dispose(); if (GFX.FontBoldItalic != null) GFX.FontBoldItalic.Dispose(); if (GFX.FontUnderline != null) GFX.FontUnderline.Dispose(); if (GFX.FontBoldUnderline != null) GFX.FontBoldUnderline.Dispose(); if (GFX.FontItalicUnderline != null) GFX.FontItalicUnderline.Dispose(); if (GFX.FontBoldItalicUnderline != null) GFX.FontBoldItalicUnderline.Dispose(); // string font="courier new"; string font = Control.FontName; float fontsize = Control.FontSize; GFX.FontNormal = new GDIFont(font, fontsize, false, false, false, false); GFX.FontBold = new GDIFont(font, fontsize, true, false, false, false); GFX.FontItalic = new GDIFont(font, fontsize, false, true, false, false); GFX.FontBoldItalic = new GDIFont(font, fontsize, true, true, false, false); GFX.FontUnderline = new GDIFont(font, fontsize, false, false, true, false); GFX.FontBoldUnderline = new GDIFont(font, fontsize, true, false, true, false); GFX.FontItalicUnderline = new GDIFont(font, fontsize, false, true, true, false); GFX.FontBoldItalicUnderline = new GDIFont(font, fontsize, true, true, true, false); InitIMEWindow(); } catch (Exception) {} if (Control != null) { if (Control.IsHandleCreated) { if (GFX.StringBuffer != null) GFX.StringBuffer.Dispose(); if (GFX.SelectionBuffer != null) GFX.SelectionBuffer.Dispose(); if (GFX.BackBuffer != null) GFX.BackBuffer.Dispose(); GFX.StringBuffer = new GDISurface(1, 1, Control, true) {Font = GFX.FontNormal}; int h = GFX.StringBuffer.MeasureTabbedString("ABC", 0).Height + Control._SyntaxBox.RowPadding; GFX.BackBuffer = new GDISurface(Control.ClientWidth, h, Control, true) {Font = GFX.FontNormal}; GFX.SelectionBuffer = new GDISurface(Control.ClientWidth, h, Control, true) {Font = GFX.FontNormal}; Control.View.RowHeight = GFX.BackBuffer.MeasureTabbedString("ABC", 0).Height + Control._SyntaxBox.RowPadding; Control.View.CharWidth = GFX.BackBuffer.MeasureTabbedString(" ", 0).Width; } } } /// /// Implementation of the IPainter RenderAll method. /// public void RenderAll() { // Control.View.RowHeight = GFX.BackBuffer.MeasureString("ABC").Height; Control.View.CharWidth = GFX.BackBuffer.MeasureString(" ").Width; Control.InitVars(); Graphics g = Control.CreateGraphics(); RenderAll(g); g.Dispose(); } public void RenderCaret(Graphics g) { RenderCaretRowOnly = true; RenderAll(g); RenderCaretRowOnly = false; } /// /// Implementation of the IPainter RenderAll method /// /// Target Graphics object public void RenderAll(Graphics g) { try { Control.InitVars(); Control.InitScrollbars(); SetBrackets(); SetSpanIndicators(); int j = Control.View.FirstVisibleRow; int diff = j - LastRow; LastRow = j; if (Control.SmoothScroll) { if (diff == 1) { for (int i = Control.View.RowHeight; i > 0; i -= Control.SmoothScrollSpeed) { yOffset = i + Control.View.YOffset; RenderAll2(); g.Flush(); Thread.Sleep(0); } } else if (diff == -1) { for (int i = -Control.View.RowHeight; i < 0; i += Control.SmoothScrollSpeed) { yOffset = i + Control.View.YOffset; RenderAll2(); g.Flush(); Thread.Sleep(0); } } } yOffset = Control.View.YOffset; RenderAll2(); //g.Flush (); //System.Threading.Thread.Sleep (0); } catch {} } /// /// /// /// public void RenderRow(int RowIndex) { RenderRow(RowIndex, 10); } /// /// Implementation of the iPainter CharFromPixel method /// /// Screen x position in pixels /// Screen y position in pixels /// a Point where x is the column and y is the rowindex public TextPoint CharFromPixel(int X, int Y) { try { int RowIndex = Y/Control.View.RowHeight + Control.View.FirstVisibleRow; RowIndex = Math.Min(RowIndex, Control.Document.VisibleRows.Count); if (RowIndex == Control.Document.VisibleRows.Count) { RowIndex--; Row r = Control.Document.VisibleRows[RowIndex]; if (r.IsCollapsed) r = r.Expansion_EndRow; return new TextPoint(r.Text.Length, r.Index); } RowIndex = Math.Max(RowIndex, 0); Row row; if (Control.Document.VisibleRows.Count != 0) { row = Control.Document.VisibleRows[RowIndex]; RowIndex = Control.Document.IndexOf(row); } else { return new TextPoint(0, 0); } if (RowIndex == -1) return new TextPoint(-1, -1); //normal line if (!row.IsCollapsed) return ColumnFromPixel(RowIndex, X); //this.RenderRow (xtr.Index,-200); if (X < row.Expansion_PixelEnd - Control.View.FirstVisibleColumn*Control.View.CharWidth) { //start of collapsed line return ColumnFromPixel(RowIndex, X); } if (X >= row.Expansion_EndRow.Expansion_PixelStart - Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin) { //end of collapsed line return ColumnFromPixel(row.Expansion_EndRow.Index, X - row.Expansion_EndRow.Expansion_PixelStart + MeasureRow(row.Expansion_EndRow, row.Expansion_EndRow.Expansion_StartChar).Width); } //the collapsed text return new TextPoint(row.Expansion_EndChar, row.Index); } catch { Control._SyntaxBox.FontName = "Courier New"; Control._SyntaxBox.FontSize = 10; return new TextPoint(0, 0); } } public int GetMaxCharWidth() { const string s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int max = 0; foreach (char c in s) { int tmp = MeasureString(c + "").Width; if (tmp > max) max = tmp; } return max; } public void Dispose() { if (GFX.FontNormal != null) GFX.FontNormal.Dispose(); if (GFX.FontBold != null) GFX.FontBold.Dispose(); if (GFX.FontItalic != null) GFX.FontItalic.Dispose(); if (GFX.FontBoldItalic != null) GFX.FontBoldItalic.Dispose(); if (GFX.FontUnderline != null) GFX.FontUnderline.Dispose(); if (GFX.FontBoldUnderline != null) GFX.FontBoldUnderline.Dispose(); if (GFX.FontItalicUnderline != null) GFX.FontItalicUnderline.Dispose(); if (GFX.FontBoldItalicUnderline != null) GFX.FontBoldItalicUnderline.Dispose(); if (GFX.BackgroundBrush != null) GFX.BackgroundBrush.Dispose(); if (GFX.GutterMarginBrush != null) GFX.GutterMarginBrush.Dispose(); if (GFX.LineNumberMarginBrush != null) GFX.LineNumberMarginBrush.Dispose(); if (GFX.HighLightLineBrush != null) GFX.HighLightLineBrush.Dispose(); if (GFX.LineNumberMarginBorderBrush != null) GFX.LineNumberMarginBorderBrush.Dispose(); if (GFX.GutterMarginBorderBrush != null) GFX.GutterMarginBorderBrush.Dispose(); if (GFX.OutlineBrush != null) GFX.OutlineBrush.Dispose(); if (GFX.StringBuffer != null) GFX.StringBuffer.Dispose(); if (GFX.SelectionBuffer != null) GFX.SelectionBuffer.Dispose(); if (GFX.BackBuffer != null) GFX.BackBuffer.Dispose(); } #endregion private void InitIMEWindow() { if (Control.IMEWindow != null) Control.IMEWindow.SetFont(Control.FontName, Control.FontSize); } /// /// Implementation of the IPainter MeasureRow method. /// /// Row to measure /// Last char index /// The size of the row in pixels public Size MeasureRow(Row xtr, int Count) { int width = 0; int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; int xpos = Control.View.TextMargin - Control.View.ClientAreaStart; if (xtr.InQueue) { SetStringFont(false, false, false); int Padd = Math.Max(Count - xtr.Text.Length, 0); var PaddStr = new String(' ', Padd); string TotStr = xtr.Text + PaddStr; width = GFX.StringBuffer.MeasureTabbedString(TotStr.Substring(0, Count), Control.PixelTabSize).Width; } else { int CharNo = 0; int TotWidth = 0; foreach (Word w in xtr.FormattedWords) { if (w.Type == WordType.Word && w.Style != null) SetStringFont(w.Style.Bold, w.Style.Italic, w.Style.Underline); else SetStringFont(false, false, false); if (w.Text.Length + CharNo >= Count || w == xtr.FormattedWords[xtr.FormattedWords.Count - 1]) { int CharPos = Count - CharNo; int MaxChars = Math.Min(CharPos, w.Text.Length); TotWidth += GFX.StringBuffer.DrawTabbedString(w.Text.Substring(0, MaxChars), xpos + TotWidth, 0, taborig, Control.PixelTabSize).Width; width = TotWidth; break; } TotWidth += GFX.StringBuffer.DrawTabbedString(w.Text, xpos + TotWidth, 0, taborig, Control.PixelTabSize).Width; CharNo += w.Text.Length; } SetStringFont(false, false, false); int Padd = Math.Max(Count - xtr.Text.Length, 0); var PaddStr = new String(' ', Padd); width += GFX.StringBuffer.DrawTabbedString(PaddStr, xpos + TotWidth, 0, taborig, Control.PixelTabSize).Width; } return new Size(width, 0); // return GFX.BackBuffer.MeasureTabbedString (xtr.Text.Substring (0,Count),Control.PixelTabSize); } private void SetBrackets() { Span currentSpan; BracketEnd = null; BracketStart = null; Word CurrWord = Control.Caret.CurrentWord; if (CurrWord != null) { currentSpan = CurrWord.Span; if (currentSpan != null) { if (CurrWord == currentSpan.StartWord || CurrWord == currentSpan.EndWord) { if (currentSpan.EndWord != null) { BracketEnd = currentSpan.EndWord; BracketStart = currentSpan.StartWord; } } try { if (CurrWord.Pattern == null) return; if (CurrWord.Pattern.BracketType == BracketType.EndBracket) { Word w = Control.Document.GetStartBracketWord(CurrWord, CurrWord.Pattern.MatchingBracket, CurrWord.Span); BracketEnd = CurrWord; BracketStart = w; } if (CurrWord.Pattern.BracketType == BracketType.StartBracket) { Word w = Control.Document.GetEndBracketWord(CurrWord, CurrWord.Pattern.MatchingBracket, CurrWord.Span); // if(w!=null) // { BracketEnd = w; BracketStart = CurrWord; // } } } catch { } } } } private void SetSpanIndicators() { SpanFound = false; try { Span s = Control.Caret.CurrentSegment(); if (s == null || s.StartWord == null || s.StartWord.Row == null || s.EndWord == null || s.EndWord.Row == null) return; FirstSpanRow = s.StartWord.Row.Index; LastSpanRow = s.EndWord.Row.Index; SpanFound = true; } catch {} } private void RenderAll2() { try { int j = Control.View.FirstVisibleRow; if (Control.AutoListStartPos != null) { try { if (Control.AutoListVisible) { Point alP = GetTextPointPixelPos(Control.AutoListStartPos); if (alP == new Point(-1, -1)) { Control.AutoList.Visible = false; } else { alP.Y += Control.View.RowHeight + 2; alP.X += -20; alP = Control.PointToScreen(alP); Screen screen = Screen.FromPoint(new Point(Control.Right, alP.Y)); if (alP.Y + Control.AutoList.Height > screen.WorkingArea.Height) { alP.Y -= Control.View.RowHeight + 2 + Control.AutoList.Height; } if (alP.X + Control.AutoList.Width > screen.WorkingArea.Width) { alP.X -= alP.X + Control.AutoList.Width - screen.WorkingArea.Width; } Control.AutoList.Location = alP; //Control.Controls[0].Focus(); Control.Focus(); } } } catch {} } if (Control.InfoTipStartPos != null) { try { if (Control.InfoTipVisible) { Point itP = GetTextPointPixelPos(Control.InfoTipStartPos); if (itP == new Point(-1, -1)) { Control.InfoTip.Visible = false; } else { itP.Y += Control.View.RowHeight + 2; itP.X += -20; itP = Control.PointToScreen(itP); Screen screen = Screen.FromPoint(new Point(Control.Right, itP.Y)); if (itP.Y + Control.InfoTip.Height > screen.WorkingArea.Height) { itP.Y -= Control.View.RowHeight + 2 + Control.InfoTip.Height; } if (itP.X + Control.InfoTip.Width > screen.WorkingArea.Width) { itP.X -= itP.X + Control.InfoTip.Width - screen.WorkingArea.Width; } Control.InfoTip.Location = itP; Control.InfoTip.Visible = true; Debug.WriteLine("Infotip Made Visible"); } } else { Control.InfoTip.Visible = false; Debug.WriteLine("Infotip Made Invisible"); } } catch {} } for (int i = 0; i < Control.View.VisibleRowCount; i++) { if (j >= 0 && j < Control.Document.VisibleRows.Count) { Row r = Control.Document.VisibleRows[j]; if (RenderCaretRowOnly) { if (r == Control.Caret.CurrentRow) { RenderRow(Control.Document.IndexOf(r), i); } //Control.Caret.CurrentRow.expansion_EndSpan.StartRow.Index if (Control.Caret.CurrentRow.expansion_EndSpan != null && Control.Caret.CurrentRow.expansion_EndSpan.StartRow != null && Control.Caret.CurrentRow.expansion_EndSpan.StartRow == r) { RenderRow(Control.Document.IndexOf(r), i); } } else { RenderRow(Control.Document.IndexOf(r), i); } } else { if (RenderCaretRowOnly) {} else { RenderRow(Control.Document.Count, i); } } j++; } } catch { } } private void RenderRow(int RowIndex, int RowPos) { if (RowIndex >= 0 && RowIndex < Control.Document.Count) { //do keyword parse before we render the line... if (Control.Document[RowIndex].RowState == RowState.SpanParsed) { Control.Document.Parser.ParseRow(RowIndex, true); Control.Document[RowIndex].RowState = RowState.AllParsed; } } try { GDISurface bbuff = GFX.BackBuffer; bool found = false; GDIBrush bg = GFX.BackgroundBrush; try { if (RowIndex < Control.Document.Count && RowIndex >= 0) { Row r = Control.Document[RowIndex]; if (SpanFound && RowIndex >= FirstSpanRow && RowIndex <= LastSpanRow && Control._SyntaxBox.ScopeBackColor != Color.Transparent) { bg = new GDIBrush(Control._SyntaxBox.ScopeBackColor); found = true; } else if (r.BackColor != Color.Transparent) { bg = new GDIBrush(r.BackColor); found = true; } else { if (r.endSpan != null) { Span tmp = r.expansion_EndSpan; while (tmp != null) { if (tmp.spanDefinition.Transparent == false) { bg = new GDIBrush(tmp.spanDefinition.BackColor); found = true; break; } tmp = tmp.Parent; } if (!found) { tmp = r.endSpan; while (tmp != null) { if (tmp.spanDefinition.Transparent == false) { bg = new GDIBrush(tmp.spanDefinition.BackColor); found = true; break; } tmp = tmp.Parent; } } if (!found) { tmp = r.expansion_EndSpan; while (tmp != null) { if (tmp.spanDefinition.Transparent == false) { bg = new GDIBrush(tmp.spanDefinition.BackColor); found = true; break; } tmp = tmp.Parent; } } } } } } catch { } if (RowIndex == Control.Caret.Position.Y && Control.HighLightActiveLine) bbuff.Clear(GFX.HighLightLineBrush); else if (RowIndex >= 0 && RowIndex < Control.Document.Count) { if (Control.Document[RowIndex].IsCollapsed) { if (Control.Document[RowIndex].Expansion_EndRow.Index == Control.Caret.Position.Y && Control.HighLightActiveLine) bbuff.Clear(GFX.HighLightLineBrush); else bbuff.Clear(bg); } else bbuff.Clear(bg); } else bbuff.Clear(bg); //only render normal text if any part of the row is visible if (RowIndex <= Control.Selection.LogicalBounds.FirstRow || RowIndex >= Control.Selection.LogicalBounds.LastRow) { RenderText(RowIndex); } //only render selection text if the line is selected if (Control.Selection.IsValid) { if (RowIndex >= Control.Selection.LogicalBounds.FirstRow && RowIndex <= Control.Selection.LogicalBounds.LastRow) { if (Control.ContainsFocus) GFX.SelectionBuffer.Clear(Control.SelectionBackColor); else GFX.SelectionBuffer.Clear(Control.InactiveSelectionBackColor); RenderSelectedText(RowIndex); } } if (Control.ContainsFocus || Control.View.Action == EditAction.DragText) { RenderCaret(RowIndex, RowPos * Control.View.RowHeight + yOffset); } RenderSelection(RowIndex); RenderMargin(RowIndex); if (Control.Document.Folding) RenderExpansion(RowIndex); var e = new RowPaintEventArgs(); var rec = new Rectangle(0, 0, Control.Width, Control.View.RowHeight); e.Graphics = Graphics.FromHdc(bbuff.hDC); e.Bounds = rec; e.Row = null; if (RowIndex >= 0 && RowIndex < Control.Document.Count) e.Row = Control.Document[RowIndex]; Control._SyntaxBox.OnRenderRow(e); bbuff.Flush(); bbuff.RenderToControl(0, RowPos * Control.View.RowHeight + yOffset); //GFX.SelectionBuffer.RenderToControl (0,RowPos*Control.View.RowHeight+this.yOffset); if (found) bg.Dispose(); } catch { } } private void SetFont(bool bold, bool italic, bool underline, GDISurface surface) { if (bold && italic && underline) surface.Font = GFX.FontBoldItalicUnderline; else if (bold && italic) surface.Font = GFX.FontBoldItalic; else if (bold && underline) surface.Font = GFX.FontBoldUnderline; else if (bold) surface.Font = GFX.FontBold; else if (italic && underline) surface.Font = GFX.FontItalicUnderline; else if (!italic && underline) surface.Font = GFX.FontUnderline; else if (italic) surface.Font = GFX.FontItalic; else if (true) surface.Font = GFX.FontNormal; } private void SetStringFont(bool bold, bool italic, bool underline) { SetFont(bold, italic, underline, GFX.StringBuffer); } private void RenderCollapsedSelectedText(int RowIndex, int xPos) { GDISurface bbuff = GFX.SelectionBuffer; bbuff.Font = GFX.FontBold; bbuff.FontTransparent = true; bbuff.TextForeColor = Control.ContainsFocus ? Control.SelectionForeColor : Control.InactiveSelectionForeColor; //bbuff.TextForeColor =Color.DarkBlue; Row r = Control.Document[RowIndex]; string str = r.CollapsedText; xPos++; int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; GFX.StringBuffer.Font = GFX.FontBold; int wdh = GFX.StringBuffer.DrawTabbedString(str, xPos + 1, 0, taborig, Control.PixelTabSize).Width; if (Control.ContainsFocus) { bbuff.FillRect(Control.SelectionForeColor, xPos + 0, 0, wdh + 2, Control.View.RowHeight); bbuff.FillRect(Control.SelectionBackColor, xPos + 1, 1, wdh, Control.View.RowHeight - 2); } else { bbuff.FillRect(Control.InactiveSelectionForeColor, xPos + 0, 0, wdh + 2, Control.View.RowHeight); bbuff.FillRect(Control.InactiveSelectionBackColor, xPos + 1, 1, wdh, Control.View.RowHeight - 2); } wdh = bbuff.DrawTabbedString(str, xPos + 1, 0, taborig, Control.PixelTabSize).Width; //this can crash if document not fully parsed , on error resume next try { if (r.expansion_StartSpan.EndRow != null) { if (r.expansion_StartSpan.EndRow.RowState == RowState.SpanParsed) Control.Document.Parser.ParseRow(r.expansion_StartSpan.EndRow.Index, true); Word last = r.expansion_StartSpan.EndWord; xPos += Control.View.FirstVisibleColumn*Control.View.CharWidth; r.expansion_StartSpan.EndRow.Expansion_PixelStart = xPos + wdh - Control.View.TextMargin + 2; r.Expansion_PixelEnd = xPos - 1; RenderSelectedText(Control.Document.IndexOf(r.expansion_StartSpan.EndRow), r.expansion_StartSpan.EndRow.Expansion_PixelStart, last); } } catch {} } private void RenderCollapsedText(int RowIndex, int xPos) { GDISurface bbuff = GFX.BackBuffer; bbuff.Font = GFX.FontBold; bbuff.FontTransparent = true; bbuff.TextForeColor = Control.OutlineColor; Row r = Control.Document[RowIndex]; string str = r.CollapsedText; xPos++; int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; GFX.StringBuffer.Font = GFX.FontBold; int wdh = GFX.StringBuffer.DrawTabbedString(str, xPos + 1, 0, taborig, Control.PixelTabSize).Width; bbuff.FillRect(GFX.OutlineBrush, xPos + 0, 0, wdh + 2, Control.View.RowHeight); bbuff.FillRect(GFX.BackgroundBrush, xPos + 1, 1, wdh, Control.View.RowHeight - 2); wdh = bbuff.DrawTabbedString(str, xPos + 1, 0, taborig, Control.PixelTabSize).Width; //this can crash if document not fully parsed , on error resume next try { if (r.expansion_StartSpan.EndRow != null) { if (r.expansion_StartSpan.EndRow.RowState == RowState.SpanParsed) Control.Document.Parser.ParseRow(r.expansion_StartSpan.EndRow.Index, true); Word last = r.expansion_StartSpan.EndWord; xPos += Control.View.FirstVisibleColumn*Control.View.CharWidth; r.expansion_StartSpan.EndRow.Expansion_PixelStart = xPos + wdh - Control.View.TextMargin + 2; r.Expansion_PixelEnd = xPos - 1; RenderText(Control.Document.IndexOf(r.expansion_StartSpan.EndRow), r.expansion_StartSpan.EndRow.Expansion_PixelStart, last); } } catch {} } private void RenderText(int RowIndex) { RenderText(RowIndex, 0, null); } private void RenderText(int RowIndex, int XOffset, Word StartWord) { GDISurface bbuff = GFX.BackBuffer; bbuff.Font = GFX.FontNormal; bbuff.FontTransparent = true; bool DrawBreakpoint = false; if (RowIndex <= Control.Document.Count - 1) { bbuff.TextForeColor = Color.Black; Row xtr = Control.Document[RowIndex]; //if (xtr.startSpan != null) // bbuff.DrawTabbedString (xtr.startSpan.GetHashCode ().ToString (System.Globalization.CultureInfo.InvariantCulture),100,0,0,0); //bbuff.TextForeColor = Color.Black; //bbuff.DrawTabbedString (xtr.Text,(int)(Control.View.TextMargin -Control.View.ClientAreaStart),1,-Control.View.FirstVisibleColumn*Control.View.CharWidth+Control.View.TextMargin,Control.PixelTabSize); int xpos = Control.View.TextMargin - Control.View.ClientAreaStart + XOffset; int wdh = 0; int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; bool ws = Control.ShowWhitespace; bool StartDraw = false; if (StartWord == null) StartDraw = true; xtr.Expansion_StartChar = 0; xtr.Expansion_EndChar = 0; bool HasExpansion = false; foreach (Word w in xtr.FormattedWords) { if (StartDraw) { if (w.Span == xtr.expansion_StartSpan && xtr.expansion_StartSpan != null) if (xtr.expansion_StartSpan.Expanded == false) { RenderCollapsedText(RowIndex, xpos); HasExpansion = true; break; } if ((w.Type == WordType.Space || w.Type == WordType.Tab) && !DrawBreakpoint && Control.ShowTabGuides) { int xtab = xpos - (Control.View.TextMargin - Control.View.ClientAreaStart + XOffset); if ((xtab/(double) Control.PixelTabSize) == (xtab/Control.PixelTabSize)) bbuff.FillRect(Control.TabGuideColor, xpos, 0, 1, Control.View.RowHeight); } if (w.Type == WordType.Word || ws == false) { if (w.Style != null) { SetFont(w.Style.Bold, w.Style.Italic, w.Style.Underline, bbuff); bbuff.TextBackColor = w.Style.BackColor; bbuff.TextForeColor = w.Style.ForeColor; bbuff.FontTransparent = w.Style.Transparent; } else { bbuff.Font = GFX.FontNormal; bbuff.TextForeColor = Color.Black; bbuff.FontTransparent = true; } if (w.Type == WordType.Word) DrawBreakpoint = true; if (xtr.Breakpoint && DrawBreakpoint) { bbuff.TextForeColor = Control.BreakPointForeColor; bbuff.TextBackColor = Control.BreakPointBackColor; bbuff.FontTransparent = false; } if (Control.BracketMatching && (w == BracketEnd || w == BracketStart)) { bbuff.TextForeColor = Control.BracketForeColor; if (Control.BracketBackColor != Color.Transparent) { bbuff.TextBackColor = Control.BracketBackColor; bbuff.FontTransparent = false; } wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; if (Control.BracketBorderColor != Color.Transparent) { bbuff.DrawRect(Control.BracketBorderColor, xpos - 1, 0, wdh, Control.View.RowHeight - 1); } } else { wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; } //render errors if (w.HasError) { //bbuff.FillRect (Color.Red,xpos,Control.View.RowHeight-2,wdh,2); int ey = Control.View.RowHeight - 1; Color c = w.ErrorColor; for (int x = 0; x < wdh + 3; x += 4) { bbuff.DrawLine(c, new Point(xpos + x, ey), new Point(xpos + x + 2, ey - 2)); bbuff.DrawLine(c, new Point(xpos + x + 2, ey - 2), new Point(xpos + x + 4, ey)); } } } else if (w.Type == WordType.Space) { bbuff.Font = GFX.FontNormal; bbuff.TextForeColor = Control.WhitespaceColor; bbuff.FontTransparent = true; if (xtr.Breakpoint && DrawBreakpoint) { bbuff.TextForeColor = Control.BreakPointForeColor; bbuff.TextBackColor = Control.BreakPointBackColor; bbuff.FontTransparent = false; } bbuff.DrawTabbedString("·", xpos, 0, taborig, Control.PixelTabSize); wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; } else if (w.Type == WordType.Tab) { bbuff.Font = GFX.FontNormal; bbuff.TextForeColor = Control.WhitespaceColor; bbuff.FontTransparent = true; if (xtr.Breakpoint && DrawBreakpoint) { bbuff.TextForeColor = Control.BreakPointForeColor; bbuff.TextBackColor = Control.BreakPointBackColor; bbuff.FontTransparent = false; } bbuff.DrawTabbedString("»", xpos, 0, taborig, Control.PixelTabSize); wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; } if (w.Pattern != null) if (w.Pattern.IsSeparator) { bbuff.FillRect(Control.SeparatorColor, Control.View.TextMargin - 4, Control.View.RowHeight - 1, Control.View.ClientAreaWidth, 1); } xpos += wdh; } if (!StartDraw) xtr.Expansion_StartChar += w.Text.Length; if (w == StartWord) StartDraw = true; xtr.Expansion_EndChar += w.Text.Length; } if (xtr.IsCollapsed) {} else if (xtr.endSpan != null && xtr.endSpan.spanDefinition != null && xtr.endSpan.spanDefinition.Style != null) { bbuff.FillRect(xtr.endSpan.spanDefinition.Style.BackColor, xpos, 0, Control.Width - xpos, Control.View.RowHeight); } if (Control._SyntaxBox.ShowEOLMarker && !HasExpansion) { bbuff.Font = GFX.FontNormal; bbuff.TextForeColor = Control._SyntaxBox.EOLMarkerColor; bbuff.FontTransparent = true; bbuff.DrawTabbedString("¶", xpos, 0, taborig, Control.PixelTabSize); } } } private void RenderSelectedText(int RowIndex) { RenderSelectedText(RowIndex, 0, null); } private void RenderSelectedText(int RowIndex, int XOffset, Word StartWord) { GDISurface bbuff = GFX.SelectionBuffer; bbuff.Font = GFX.FontNormal; bbuff.FontTransparent = true; if (RowIndex <= Control.Document.Count - 1) { bbuff.TextForeColor = Control.ContainsFocus ? Control.SelectionForeColor : Control.InactiveSelectionForeColor; Row xtr = Control.Document[RowIndex]; //if (xtr.startSpan != null) // bbuff.DrawTabbedString (xtr.startSpan.GetHashCode ().ToString (System.Globalization.CultureInfo.InvariantCulture),100,0,0,0); //bbuff.TextForeColor = Color.Black; //bbuff.DrawTabbedString (xtr.Text,(int)(Control.View.TextMargin -Control.View.ClientAreaStart),1,-Control.View.FirstVisibleColumn*Control.View.CharWidth+Control.View.TextMargin,Control.PixelTabSize); int xpos = Control.View.TextMargin - Control.View.ClientAreaStart + XOffset; int wdh = 0; int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; bool ws = Control.ShowWhitespace; bool StartDraw = false; if (StartWord == null) StartDraw = true; xtr.Expansion_StartChar = 0; xtr.Expansion_EndChar = 0; bool HasExpansion = false; foreach (Word w in xtr.FormattedWords) { if (StartDraw) { if (w.Span == xtr.expansion_StartSpan && xtr.expansion_StartSpan != null) if (xtr.expansion_StartSpan.Expanded == false) { RenderCollapsedSelectedText(RowIndex, xpos); HasExpansion = true; break; } if (w.Type == WordType.Word || ws == false) { if (w.Style != null) { SetFont(w.Style.Bold, w.Style.Italic, w.Style.Underline, bbuff); } else { bbuff.Font = GFX.FontNormal; } wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; //render errors if (w.HasError) { //bbuff.FillRect (Color.Red,xpos,Control.View.RowHeight-2,wdh,2); int ey = Control.View.RowHeight - 1; Color c = w.ErrorColor; for (int x = 0; x < wdh + 3; x += 4) { bbuff.DrawLine(c, new Point(xpos + x, ey), new Point(xpos + x + 2, ey - 2)); bbuff.DrawLine(c, new Point(xpos + x + 2, ey - 2), new Point(xpos + x + 4, ey)); } } } else if (w.Type == WordType.Space) { bbuff.Font = GFX.FontNormal; bbuff.DrawTabbedString("·", xpos, 0, taborig, Control.PixelTabSize); wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; } else if (w.Type == WordType.Tab) { bbuff.Font = GFX.FontNormal; bbuff.DrawTabbedString("»", xpos, 0, taborig, Control.PixelTabSize); wdh = bbuff.DrawTabbedString(w.Text, xpos, 0, taborig, Control.PixelTabSize).Width; } if (w.Pattern != null) if (w.Pattern.IsSeparator) { bbuff.FillRect(Control.SeparatorColor, Control.View.TextMargin - 4, Control.View.RowHeight - 1, Control.View.ClientAreaWidth, 1); } xpos += wdh; } if (!StartDraw) xtr.Expansion_StartChar += w.Text.Length; if (w == StartWord) StartDraw = true; xtr.Expansion_EndChar += w.Text.Length; } if (xtr.IsCollapsed) {} else if (xtr.endSpan != null && xtr.endSpan.spanDefinition != null && xtr.endSpan.spanDefinition.Style != null) { GFX.BackBuffer.FillRect(xtr.endSpan.spanDefinition.Style.BackColor, xpos, 0, Control.Width - xpos, Control.View.RowHeight); } if (Control._SyntaxBox.ShowEOLMarker && !HasExpansion) { bbuff.Font = GFX.FontNormal; bbuff.TextForeColor = Control.SelectionForeColor; bbuff.FontTransparent = true; bbuff.DrawTabbedString("¶", xpos, 0, taborig, Control.PixelTabSize); } } } private void RenderCaret(int RowIndex, int ypos) { int StartRow = -1; int cr = Control.Caret.Position.Y; if (cr >= 0 && cr <= Control.Document.Count - 1) { Row r = Control.Document[cr]; if (r.expansion_EndSpan != null) { if (r.expansion_EndSpan.Expanded == false) { r = r.expansion_EndSpan.StartRow; StartRow = r.Index; } } } bool Collapsed = (RowIndex == StartRow); if (RowIndex != cr && RowIndex != StartRow) return; if (Control.View.Action == EditAction.DragText) { //drop Control.Caret Row xtr = Control.Document[cr]; int pos = MeasureRow(xtr, Control.Caret.Position.X).Width + 1; if (Collapsed) { pos += xtr.Expansion_PixelStart; pos -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } GFX.BackBuffer.InvertRect(pos + Control.View.TextMargin - Control.View.ClientAreaStart - 1, 0, 3, Control.View.RowHeight); GFX.BackBuffer.InvertRect(pos + Control.View.TextMargin - Control.View.ClientAreaStart, 1, 1, Control.View.RowHeight - 2); } else { //normal Control.Caret Row xtr = Control.Document[cr]; if (!Control.OverWrite) { int pos = Control.View.TextMargin - Control.View.ClientAreaStart; pos += MeasureRow(xtr, Control.Caret.Position.X).Width + 1; if (Collapsed) { pos += xtr.Expansion_PixelStart; pos -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } int wdh = Control.View.CharWidth/12 + 1; if (wdh < 2) wdh = 2; if (Control.Caret.Blink) { GFX.BackBuffer.InvertRect(pos, 0, wdh, Control.View.RowHeight); } if (Control.IMEWindow == null) { Control.IMEWindow = new IMEWindow(Control.Handle, Control.FontName, Control.FontSize); InitIMEWindow(); } Control.IMEWindow.Loation = new Point(pos, ypos); } else { int pos1 = MeasureRow(xtr, Control.Caret.Position.X).Width; int pos2 = MeasureRow(xtr, Control.Caret.Position.X + 1).Width; int wdh = pos2 - pos1; if (Collapsed) { pos1 += xtr.Expansion_PixelStart; pos1 -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } int pos = pos1 + Control.View.TextMargin - Control.View.ClientAreaStart; if (Control.Caret.Blink) { GFX.BackBuffer.InvertRect(pos, 0, wdh, Control.View.RowHeight); } Control.IMEWindow.Loation = new Point(pos, ypos); } } } private void RenderMargin(int RowIndex) { GDISurface bbuff = GFX.BackBuffer; if (Control.ShowGutterMargin) { bbuff.FillRect(GFX.GutterMarginBrush, 0, 0, Control.View.GutterMarginWidth, Control.View.RowHeight); bbuff.FillRect(GFX.GutterMarginBorderBrush, Control.View.GutterMarginWidth - 1, 0, 1, Control.View.RowHeight); if (RowIndex <= Control.Document.Count - 1) { Row r = Control.Document[RowIndex]; if (Control.View.RowHeight >= Control._SyntaxBox.GutterIcons.ImageSize.Height) { if (r.Bookmarked) Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, 1); if (r.Breakpoint) Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, 0); } else { int w = Control.View.RowHeight; if (r.Bookmarked) Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, w, w, 1); if (r.Breakpoint) Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, w, w, 0); } if (r.Images != null) { foreach (int i in r.Images) { if (Control.View.RowHeight >= Control._SyntaxBox.GutterIcons.ImageSize.Height) { Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, i); } else { int w = Control.View.RowHeight; Control._SyntaxBox.GutterIcons.Draw(Graphics.FromHdc(bbuff.hDC), 0, 0, w, w, i); } } } } } if (Control.ShowLineNumbers) { bbuff.FillRect(GFX.LineNumberMarginBrush, Control.View.GutterMarginWidth, 0, Control.View.LineNumberMarginWidth + 1, Control.View.RowHeight); //bbuff.FillRect (GFX.LineNumberMarginBrush ,Control.View.GutterMarginWidth+Control.View.LineNumberMarginWidth,0,1,Control.View.RowHeight); for (int j = 0; j < Control.View.RowHeight; j += 2) { bbuff.FillRect(GFX.LineNumberMarginBorderBrush, Control.View.GutterMarginWidth + Control.View.LineNumberMarginWidth, j, 1, 1); } } if (!Control.ShowLineNumbers || !Control.ShowGutterMargin) bbuff.FillRect(GFX.BackgroundBrush, Control.View.TotalMarginWidth, 0, Control.View.TextMargin - Control.View.TotalMarginWidth - 3, Control.View.RowHeight); else bbuff.FillRect(GFX.BackgroundBrush, Control.View.TotalMarginWidth + 1, 0, Control.View.TextMargin - Control.View.TotalMarginWidth - 4, Control.View.RowHeight); if (Control.ShowLineNumbers) { bbuff.Font = GFX.FontNormal; bbuff.FontTransparent = true; bbuff.TextForeColor = Control.LineNumberForeColor; if (RowIndex <= Control.Document.Count - 1) { int nw = MeasureString((RowIndex + 1).ToString(CultureInfo.InvariantCulture)).Width; bbuff.DrawTabbedString((RowIndex + 1).ToString(CultureInfo.InvariantCulture), Control.View.GutterMarginWidth + Control.View.LineNumberMarginWidth - nw - 1, 1, 0, Control.PixelTabSize); } } } private void RenderExpansion(int RowIndex) { if (Control == null) throw new NullReferenceException("Control may not be null"); if (RowIndex <= Control.Document.Count - 1) { const int yo = 4; Row xtr = Control.Document[RowIndex]; GDISurface bbuff = GFX.BackBuffer; if (xtr.endSpan != null) { if (xtr.expansion_StartSpan != null && xtr.startSpan.Parent == null) { if (!xtr.IsCollapsed) { bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 6, yo, 1, Control.View.RowHeight - yo); } } else if ((xtr.endSpan.Parent != null || xtr.expansion_EndSpan != null)) { bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 6, 0, 1, Control.View.RowHeight); } if (xtr.expansion_StartSpan != null) { bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 2, yo, 9, 9); bbuff.FillRect(GFX.BackgroundBrush, Control.View.TotalMarginWidth + 3, yo + 1, 7, 7); //render plus / minus bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 4, yo + 4, 5, 1); if (!xtr.expansion_StartSpan.Expanded) bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 6, yo + 2, 1, 5); } if (xtr.expansion_EndSpan != null) { bbuff.FillRect(GFX.OutlineBrush, Control.View.TotalMarginWidth + 7, Control.View.RowHeight - 1, 5, 1); } } // //RENDER SPAN LINES // if (SpanFound) // { // if (RowIndex==FirstSpanRow) // bbuff.FillRect (GFX.OutlineBrush,this.Control.View.TotalMarginWidth +14,0,Control.ClientWidth ,1); // // if (RowIndex==LastSpanRow) // bbuff.FillRect (GFX.OutlineBrush,this.Control.View.TotalMarginWidth +14,Control.View.RowHeight-1,Control.ClientWidth,1); // } //RENDER SPAN MARGIN if (SpanFound && Control._SyntaxBox.ScopeIndicatorColor != Color.Transparent && Control._SyntaxBox.ShowScopeIndicator) { if (RowIndex >= FirstSpanRow && RowIndex <= LastSpanRow) bbuff.FillRect(Control._SyntaxBox.ScopeIndicatorColor, Control.View.TotalMarginWidth + 14, 0, 2, Control.View.RowHeight); if (RowIndex == FirstSpanRow) bbuff.FillRect(Control._SyntaxBox.ScopeIndicatorColor, Control.View.TotalMarginWidth + 14, 0, 4, 2); if (RowIndex == LastSpanRow) bbuff.FillRect(Control._SyntaxBox.ScopeIndicatorColor, Control.View.TotalMarginWidth + 14, Control.View.RowHeight - 2, 4, 2); } } } //draws aControl.Selection.LogicalBounds row in the backbuffer private void RenderSelection(int RowIndex) { if (RowIndex <= Control.Document.Count - 1 && Control.Selection.IsValid) { Row xtr = Control.Document[RowIndex]; if (!xtr.IsCollapsed) { if ((RowIndex > Control.Selection.LogicalBounds.FirstRow) && (RowIndex < Control.Selection.LogicalBounds.LastRow)) { int width = MeasureRow(xtr, xtr.Text.Length).Width + MeasureString("¶").Width + 3; RenderBox(Control.View.TextMargin, 0, Math.Max(width - Control.View.ClientAreaStart, 0), Control.View.RowHeight); } else if ((RowIndex == Control.Selection.LogicalBounds.FirstRow) && (RowIndex == Control.Selection.LogicalBounds.LastRow)) { int start = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.FirstColumn)).Width; int width = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.LastColumn)).Width - start; RenderBox(Control.View.TextMargin + start - Control.View.ClientAreaStart, 0, width, Control.View.RowHeight); } else if (RowIndex == Control.Selection.LogicalBounds.LastRow) { int width = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.LastColumn)).Width; RenderBox(Control.View.TextMargin, 0, Math.Max(width - Control.View.ClientAreaStart, 0), Control.View.RowHeight); } else if (RowIndex == Control.Selection.LogicalBounds.FirstRow) { int start = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.FirstColumn)).Width; int width = MeasureRow(xtr, xtr.Text.Length).Width + MeasureString("¶").Width + 3 - start; RenderBox(Control.View.TextMargin + start - Control.View.ClientAreaStart, 0, width, Control.View.RowHeight); } } else { RenderCollapsedSelection(RowIndex); } } } private void RenderCollapsedSelection(int RowIndex) { Row xtr = Control.Document[RowIndex]; if ((RowIndex > Control.Selection.LogicalBounds.FirstRow) && (RowIndex < Control.Selection.LogicalBounds.LastRow)) { int width = MeasureRow(xtr, xtr.Expansion_EndChar).Width; RenderBox(Control.View.TextMargin, 0, Math.Max(width - Control.View.ClientAreaStart, 0), Control.View.RowHeight); } else if ((RowIndex == Control.Selection.LogicalBounds.FirstRow) && (RowIndex == Control.Selection.LogicalBounds.LastRow)) { int start = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.FirstColumn)).Width; int min = Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.LastColumn); min = Math.Min(min, xtr.Expansion_EndChar); int width = MeasureRow(xtr, min).Width - start; RenderBox(Control.View.TextMargin + start - Control.View.ClientAreaStart, 0, width, Control.View.RowHeight); } else if (RowIndex == Control.Selection.LogicalBounds.LastRow) { int width = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.LastColumn)).Width; RenderBox(Control.View.TextMargin, 0, Math.Max(width - Control.View.ClientAreaStart, 0), Control.View.RowHeight); } else if (RowIndex == Control.Selection.LogicalBounds.FirstRow) { int start = MeasureRow(xtr, Math.Min(xtr.Text.Length, Control.Selection.LogicalBounds.FirstColumn)).Width; int width = MeasureRow(xtr, Math.Min(xtr.Text.Length, xtr.Expansion_EndChar)).Width - start; RenderBox(Control.View.TextMargin + start - Control.View.ClientAreaStart, 0, width, Control.View.RowHeight); } if (Control.Selection.LogicalBounds.LastRow > RowIndex && Control.Selection.LogicalBounds.FirstRow <= RowIndex) { int start = xtr.Expansion_PixelEnd; int end = xtr.Expansion_EndRow.Expansion_PixelStart - start + Control.View.TextMargin; //start+=100; //end=200; RenderBox(start - Control.View.ClientAreaStart, 0, end, Control.View.RowHeight); } RowIndex = xtr.Expansion_EndRow.Index; xtr = xtr.Expansion_EndRow; if (Control.Selection.LogicalBounds.FirstRow <= RowIndex && Control.Selection.LogicalBounds.LastRow >= RowIndex) { int endchar = Control.Selection.LogicalBounds.LastRow != RowIndex ? xtr.Text.Length : Math.Min(Control.Selection.LogicalBounds.LastColumn, xtr.Text.Length); int end = MeasureRow(xtr, endchar).Width; end += xtr.Expansion_PixelStart; end -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; int start; if (Control.Selection.LogicalBounds.FirstRow == RowIndex) { int startchar = Math.Max(Control.Selection.LogicalBounds.FirstColumn, xtr.Expansion_StartChar); start = MeasureRow(xtr, startchar).Width; start += xtr.Expansion_PixelStart; start -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } else { start = MeasureRow(xtr, xtr.Expansion_StartChar).Width; start += xtr.Expansion_PixelStart; start -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } end -= start; if (Control.Selection.LogicalBounds.LastRow != RowIndex) end += 6; RenderBox(Control.View.TextMargin + start - Control.View.ClientAreaStart, 0, end, Control.View.RowHeight); } } private void RenderBox(int x, int y, int width, int height) { GFX.SelectionBuffer.RenderTo(GFX.BackBuffer, x, y, width, height, x, y); } private TextPoint ColumnFromPixel(int RowIndex, int X) { Row xtr = Control.Document[RowIndex]; X -= Control.View.TextMargin - 2 - Control.View.FirstVisibleColumn*Control.View.CharWidth; if (xtr.Count == 0) { if (Control.VirtualWhitespace && Control.View.CharWidth > 0) { return new TextPoint(X/Control.View.CharWidth, RowIndex); } return new TextPoint(0, RowIndex); } int taborig = -Control.View.FirstVisibleColumn*Control.View.CharWidth + Control.View.TextMargin; int xpos = Control.View.TextMargin - Control.View.ClientAreaStart; int CharNo = 0; int TotWidth = 0; Word Word = null; int WordStart = 0; foreach (Word w in xtr.FormattedWords) { Word = w; WordStart = TotWidth; if (w.Type == WordType.Word && w.Style != null) SetStringFont(w.Style.Bold, w.Style.Italic, w.Style.Underline); else SetStringFont(false, false, false); int tmpWidth = GFX.StringBuffer.DrawTabbedString(w.Text, xpos + TotWidth, 0, taborig, Control.PixelTabSize).Width; if (TotWidth + tmpWidth >= X) { break; } //dont do this for the last word if (w != xtr.FormattedWords[xtr.FormattedWords.Count - 1]) { TotWidth += tmpWidth; CharNo += w.Text.Length; } } //CharNo is the index in the text where 'word' starts //'Word' is the word object that contains the 'X' //'WordStart' contains the pixel start position for 'Word' if (Word != null) if (Word.Type == WordType.Word && Word.Style != null) SetStringFont(Word.Style.Bold, Word.Style.Italic, Word.Style.Underline); else SetStringFont(false, false, false); //now , lets measure each char and get a correct pos bool found = false; if (Word != null) foreach (char c in Word.Text) { int tmpWidth = GFX.StringBuffer.DrawTabbedString(c + "", xpos + WordStart, 0, taborig, Control.PixelTabSize).Width; if (WordStart + tmpWidth >= X) { found = true; break; } CharNo++; WordStart += tmpWidth; } if (!found && Control.View.CharWidth > 0 && Control.VirtualWhitespace) { int xx = X - WordStart; int cn = xx/Control.View.CharWidth; CharNo += cn; } if (CharNo < 0) CharNo = 0; return new TextPoint(CharNo, RowIndex); } private Point GetTextPointPixelPos(TextPoint tp) { Row xtr = Control.Document[tp.Y]; if (xtr.RowState == RowState.SpanParsed) Control.Document.Parser.ParseRow(xtr.Index, true); Row r = xtr.IsCollapsedEndPart ? xtr.Expansion_StartRow : xtr; int index = r.VisibleIndex; int yPos = (index - Control.View.FirstVisibleRow); if (yPos < 0 || yPos > Control.View.VisibleRowCount) return new Point(-1, -1); yPos *= Control.View.RowHeight; bool Collapsed = (xtr.IsCollapsedEndPart); int pos = MeasureRow(xtr, tp.X).Width + 1; if (Collapsed) { pos += xtr.Expansion_PixelStart; pos -= MeasureRow(xtr, xtr.Expansion_StartChar).Width; } int xPos = pos + Control.View.TextMargin - Control.View.ClientAreaStart; if (xPos < Control.View.TextMargin || xPos > Control.View.ClientAreaWidth + Control.View.TextMargin) return new Point(-1, -1); return new Point(xPos, yPos); } } }