/// <summary> /// TODO: This does not work, since it does not take the lineHeight into account. /// </summary> /// <param name = "hdc">The DC handle onto which the painting is being done.</param> /// <param name = "x">The starting horizontal location, used to offset tabbings correctly.</param> /// <param name = "start">The starting index of the segment as-to where to begin measuring.</param> /// <param name = "length">The number of characters starting from the <see cref="start"/> that should be measured.</param> /// <param name = "info">The TextSegmentVisualInfos about wordwrappings and tabbings.</param> /// <returns></returns> public unsafe Size GetSize(IntPtr hdc, int x, int start, int length, TextSegmentVisualInfo info) { var text = this.GetText(info.TextColumnIndex); fixed(char *c = text) { var sz = new Size(); if (info.TabSplitIndexes != null) { var previousTabIndex = start; foreach (var tabSplitIndex in info.TabSplitIndexes) { if (tabSplitIndex > start && tabSplitIndex <= start + length) { var subStart = previousTabIndex; var subLength = tabSplitIndex - previousTabIndex - 1; // -1 since we are not counting this tab. if (subLength > 0) { var sizeUntilTab = Size.Empty; SafeNativeMethods.GetTextExtentPoint32(hdc, c + subStart, subLength, ref sizeUntilTab); sz.Width += sizeUntilTab.Width; } sz.Width += (staticTabWidth) - ((x + sz.Width) % staticTabWidth); previousTabIndex = tabSplitIndex; } } if (previousTabIndex < start + length) { var lastStart = previousTabIndex; var lastLength = length - (previousTabIndex - start); var sizeAfterTab = Size.Empty; SafeNativeMethods.GetTextExtentPoint32(hdc, c + lastStart, lastLength, ref sizeAfterTab); sz.Width += sizeAfterTab.Width; } } else { SafeNativeMethods.GetTextExtentPoint32(hdc, c + start, length, ref sz); } return(sz); } }
public override void Paint(IntPtr hdc, ITextSegmentStyled textSegment, ITextView textView, TextSegmentVisualInfo info, int x, int y, int lineHeight, StyleRenderInfo sri) { if (staticBrushRed == null) { staticBrushRed = new SafeHandleGDI(SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(Color.Red))); } var spaceSize = (lineHeight / 4d); var rectTop = new RECT { left = x, top = y, right = x + (lineHeight / 8), bottom = (int)(y + (lineHeight - (spaceSize))) }; var rectBottom = new RECT { left = rectTop.left, top = (int)(rectTop.bottom + (spaceSize / 2)), right = rectTop.right }; rectBottom.bottom = (int)(rectBottom.top + (spaceSize / 2)); SafeNativeMethods.FillRect(hdc, ref rectTop, staticBrushRed.DangerousGetHandle()); SafeNativeMethods.FillRect(hdc, ref rectBottom, staticBrushRed.DangerousGetHandle()); }
public override void Paint(IntPtr hdc, ITextSegmentStyled styledSegment, ITextView textView, TextSegmentVisualInfo info, int x, int y, int lineHeight, StyleRenderInfo sri) { //if (this._paintUnderline == null) //{ // this._paintUnderline = this.Settings.SpellcheckUnderlineEnabled; // Bridge.Get().GetSafe("Text.Style.Spellcheck.Underline.Enabled", true); //} if (textView.Settings.SpellcheckUnderlineEnabled == false) { return; } if (staticPenUnderline == null) { staticUnderlineColor = textView.Settings.ColorSpellcheckUnderline; // Bridge.Get().GetSafe("Text.Style.Spellcheck.Underline.Color", Color.Red); //int underlineType = Bridge.Get().GetSafe("Text.Style.Spellcheck.Underline.Type", (int) PenType.Dot); staticPenUnderline = new SafeHandleGDI(SafeNativeMethods.CreatePen((int)textView.Settings.SpellcheckUnderlineType, -1, ColorTranslator.ToWin32(staticUnderlineColor))); } var wordSize = styledSegment.Parent.GetSize(hdc, x, styledSegment.Index, styledSegment.GetLength(info.TextColumnIndex), info); var previousPen = SafeNativeMethods.SelectObject(hdc, staticPenUnderline.DangerousGetHandle()); var previousBkMode = SafeNativeMethods.SetBkMode(hdc, NativeConstants.TRANSPARENT); SafeNativeMethods.MoveToEx(hdc, x - wordSize.Width, y + lineHeight - 2, IntPtr.Zero); SafeNativeMethods.LineTo(hdc, x, y + lineHeight - 2); SafeNativeMethods.SelectObject(hdc, previousPen); SafeNativeMethods.SetBkMode(hdc, previousBkMode); }
public abstract void Paint(IntPtr hdc, ITextSegmentStyled textSegment, ITextView textView, TextSegmentVisualInfo info, int x, int y, int lineHeight, StyleRenderInfo sri);
public override void Paint(IntPtr hdc, ITextSegmentStyled textSegment, ITextView textView, TextSegmentVisualInfo info, int x, int y, int lineHeight, StyleRenderInfo sri) { var index = (int)textSegment.Object; var allSegments = sri.Get <ITextSegmentStyled[]>("speaker.segments"); if (allSegments == null) { allSegments = textView.TextDocument.TextSegmentStyledManager.GetStyledTextSegments(NameKey).ToArray(); sri.Set("speaker.segments", allSegments); } Color color; if (index == -1) { // TODO: Figure out the current speaker's index foreach (var styledSegment in allSegments) { var otherIndex = (int)styledSegment.Object; if (otherIndex == -1) { index = index == 1 ? 2 : 1; } else { index = otherIndex; } if (styledSegment == textSegment) { // We've arrived at our own row, so let's abort now. break; } } } var fill = false; switch (index) { case 1: color = Color.WhiteSmoke; break; case 2: color = Color.FromArgb(242, 255, 22); break; case 3: color = Color.FromArgb(189, 189, 255); break; case 4: color = Color.FromArgb(178, 255, 159); break; case 5: color = Color.FromArgb(255, 189, 189); break; case -2: fill = true; color = Color.FromArgb(255, 0, 0); break; default: color = Color.FromArgb(200, 200, 200); break; } if (fill) { var brush = new SafeHandleGDI(SafeNativeMethods.CreateSolidBrush(ColorTranslator.ToWin32(color))); var previousBrush = SafeNativeMethods.SelectObject(hdc, brush.DangerousGetHandle()); var previousBkMode = SafeNativeMethods.SetBkMode(hdc, NativeConstants.TRANSPARENT); var r = new RECT { top = y, right = textView.ClientSize.Width, bottom = y + lineHeight, left = info.Size.Width + 10 }; SafeNativeMethods.FillRect(hdc, ref r, brush.DangerousGetHandle()); SafeNativeMethods.SelectObject(hdc, previousBrush); SafeNativeMethods.SetBkMode(hdc, previousBkMode); } else { var pen = new SafeHandleGDI(SafeNativeMethods.CreatePen(NativeConstants.PS_SOLID, -1, ColorTranslator.ToWin32(color))); var previousPen = SafeNativeMethods.SelectObject(hdc, pen.DangerousGetHandle()); var previousBkMode = SafeNativeMethods.SetBkMode(hdc, NativeConstants.TRANSPARENT); SafeNativeMethods.MoveToEx(hdc, 1, y, IntPtr.Zero); SafeNativeMethods.LineTo(hdc, 1, y + lineHeight); SafeNativeMethods.MoveToEx(hdc, fill ? info.Size.Width : 2, y, IntPtr.Zero); SafeNativeMethods.LineTo(hdc, fill ? info.Size.Width : 2, y + lineHeight); SafeNativeMethods.SelectObject(hdc, previousPen); SafeNativeMethods.SetBkMode(hdc, previousBkMode); } }
//private const string COLUMN_SPLIT = "■"; public TextSegmentVisualInfos CalculateVisuals(ITextView textView, IntPtr hdc, int width, int lineHeight) { //var information = new TextSegmentVisualInfos(); if (staticTabWidth == -1) { unsafe { var preferredLength = textView.Settings.TabWidth; // Bridge.Get().Get<int>("Text.TabWidth"); var spaceString = new String(' ', preferredLength); fixed(char *c = spaceString) { var spaceWidth = Size.Empty; SafeNativeMethods.GetTextExtentPoint32(hdc, c, spaceString.Length, ref spaceWidth); staticTabWidth = spaceWidth.Width; } } } var newInfos = new List <TextSegmentVisualInfo>(this.Texts.Length); for (var columnIndex = 0; columnIndex < this.Texts.Length; columnIndex++) { var info = new TextSegmentVisualInfo(); newInfos.Add(info); // TODO: This should calculate visual TextSegmentVisualInfos for all text columns! //var columnIndex = 0; info.LineSplitIndexes = null; info.TabSplitIndexes = null; info.TextColumnIndex = columnIndex; var text = this.GetText(columnIndex); if (text.Length == 0) { info.LineCountVisual = 1; continue; } var oneLineSize = this.GetSize(hdc, 0, 0, text.Length, info); if (columnIndex > 0) { // If this is not the first column, we do not use wordwrapping, // since it makes things very difficult to handle. Things would become highly unstable/random. info.LineCountVisual = 1; info.Size = oneLineSize; continue; } var indexesTabs = new List <int>(); for (var i = 0; i < text.Length; i++) { if (text[i] == '\t') { indexesTabs.Add(i + 1); } } if (indexesTabs.Count > 0) { info.TabSplitIndexes = indexesTabs.ToArray(); } if (oneLineSize.Width < width) { // If all the text is on one line, it it smaller than the viewport. So no wordwrapping. info.LineCountVisual = 1; info.Size = oneLineSize; continue; } // There is wordwrapping taking place here, so we need some more advanced checks. var indexesNewlines = new List <int>(); var totalSize = new Size(); var fallbackIndex = -1; var lastNewlineIndex = 0; for (var i = 0; i <= text.Length; i++) { if (i != text.Length && Char.IsWhiteSpace(text[i]) == false) { continue; } var sizeSoFar = this.GetSize(hdc, 0, lastNewlineIndex, i - lastNewlineIndex, info); if (sizeSoFar.Width >= width) { // If there is no fallback, then the current line only has one really long word. // We will just not wordwrap it and let it go outside the text editor. Forced newline is just ugly. if (fallbackIndex != -1) { indexesNewlines.Add(fallbackIndex); lastNewlineIndex = fallbackIndex; } } else { if (sizeSoFar.Width > totalSize.Width) { totalSize.Width = sizeSoFar.Width; } } fallbackIndex = i; } if (indexesNewlines.Count > 0) { info.LineSplitIndexes = indexesNewlines.ToArray(); // +1 since the last splitting does not account for the last line. info.LineCountVisual = info.LineSplitIndexes.Length + 1; } else { info.LineCountVisual = 1; } totalSize.Height = info.LineCountVisual * lineHeight; info.Size = totalSize; } return(new TextSegmentVisualInfos(newInfos.ToArray())); }