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); }
/// <summary> /// TODO: Make this threaded and make the text control not editable meanwhile /// </summary> public bool SearchAndApplyTo(ITextView textView, ITextSegment textSegment, int index, int length, bool changeWasFinalizer, int textColumnIndex) { var foundOne = false; var canSkip = false; var previousWasWhitespace = false; var textLine = textSegment as TextLine; var textStyles = new List <TextStyleBase>(textView.GetTextStyles()); string previousStyleType = null; var previousStyleIndex = -1; if (textLine == null) { return(false); } for (var i = index; i <= index + length && i < textSegment.GetLength(textColumnIndex); i++) { #region If whitespace found, enable word-jump-search and only search on first char per word var isWhitespace = i < index + length && Char.IsWhiteSpace(textSegment.GetText(textColumnIndex)[i]); if (canSkip) { if (isWhitespace == false) { if (previousWasWhitespace == false) { continue; } } else { previousWasWhitespace = true; continue; // Don't need to search on a whitespace. } } else if (isWhitespace) { canSkip = true; previousWasWhitespace = true; continue; // Don't need to search on a whitespace. } previousWasWhitespace = false; #endregion ITextSegmentStyled newStyledTextSegment = null; for (var s = 0; s < textStyles.Count; s++) { if (textStyles[s].UpdateOnlyOnFinalizingChange && changeWasFinalizer == false) { continue; } newStyledTextSegment = textStyles[s].FindStyledTextSegment(textView, textSegment, this.TextHandler, i, -1, textColumnIndex); if (newStyledTextSegment != null) { //textStyles.RemoveAt(s); break; } } if (newStyledTextSegment == null) { continue; } var found = false; foreach (var existingStyle in GetAll(textLine, i, newStyledTextSegment.Style.NameKey)) { if (existingStyle.Style.NameKey == newStyledTextSegment.Style.NameKey) { if (newStyledTextSegment.Index == existingStyle.Index && newStyledTextSegment.GetLength(textColumnIndex) == existingStyle.GetLength(textColumnIndex)) { found = true; break; } this.RemoveTextSegment(existingStyle); break; } } if (found == false) { foundOne = true; // TODO: Make this line actually work. (NOTE: what did I mean here? ;D) this.AddManualTextSegment(newStyledTextSegment, textLine.Index + newStyledTextSegment.Index, textColumnIndex); } if (previousStyleType != newStyledTextSegment.Style.NameKey && previousStyleIndex != newStyledTextSegment.Index) { // Decrease it so that we stay on the same location, in case there are several styles overlapping on the same spot. i--; } previousStyleType = newStyledTextSegment.Style.NameKey; previousStyleIndex = newStyledTextSegment.Index; } return(foundOne); }
/// <summary> /// /// </summary> /// <param name="textView"></param> /// <param name="textLine"></param> /// <param name="relativeIndex">Relative index is the index before the new character, so text[relativeIndex] is the <see cref="c"/>.</param> /// <param name="c"></param> /// <param name="alterTextStyleIndexes"></param> /// <param name="length"></param> /// <param name="textColumnIndex"></param> private void ModifyStyledTextSegments(ITextView textView, TextLine textLine, int relativeIndex, char c, bool alterTextStyleIndexes, int length, int textColumnIndex) { var isErase = c == '\0' && length <= 0; if (isErase) { length *= -1; } IEnumerable <ITextSegmentStyled> befores = null; IEnumerable <ITextSegmentStyled> afters = null; var startSearch = Math.Max(0, relativeIndex - 1); const bool foundMatch = false; if (alterTextStyleIndexes) { var offsetCount = 0; for (var n = 0; n < textLine.StyledTextSegments.Count - offsetCount; n++) { if (textLine.StyledTextSegments[n].Index > textLine.GetLength(textColumnIndex)) { // The style starts after the end of the line, which is silly and should be filtered out. textLine.StyledTextSegments[n].TextLine = null; n--; } else if (isErase && textLine.StyledTextSegments[n].Style.Type == TextStyleType.Automatic && textLine.StyledTextSegments[n].Index >= relativeIndex && textLine.StyledTextSegments[n].Index + textLine.StyledTextSegments[n].GetLength(textColumnIndex) <= relativeIndex + length) { // The whole styled text segment was inside the removed range of text. // It does not exist anymore and is automatically eligible for removing. textLine.StyledTextSegments[n].TextLine = null; n--; } else if (textLine.StyledTextSegments[n].Style.Type == TextStyleType.Automatic && textLine.StyledTextSegments[n].Contains(relativeIndex, length, isErase, true)) { if (befores == null) { // This will search from the character before the change, the character before a new addition, // or the character before the character that was removed. befores = this.FindStyles(textView, textLine, startSearch, textColumnIndex); // If a new addition, we search from the character after the change (so "pol<new space>ice" will search on "i" and not <new space>). // When removing we only need to search from where the removal took place. var afterSearchIdx = isErase == false?Math.Min(textLine.GetLength(textColumnIndex), startSearch + 2) : startSearch + 1; afters = this.FindStyles(textView, textLine, afterSearchIdx, textColumnIndex); } var current = textLine.StyledTextSegments[n]; if (befores != null || afters != null) { ITextSegmentStyled before = null; ITextSegmentStyled after = null; if (befores != null) { foreach (var b in befores) { if (b.Style.NameKey == current.Style.NameKey) { before = b; break; } } } if (afters != null) { foreach (var a in afters) { if (a.Style.NameKey == current.Style.NameKey) { after = a; break; } } } if (before == null) { if (after == null) { // The styled text segment is no more since it is no longer found. current.TextLine = null; n--; continue; } before = after; after = null; } else if (after != null && before.Object != null && before.Object.Equals(after.Object)) { after = null; } if (before.Index == current.Index && before.GetLength(textColumnIndex) == current.GetLength(textColumnIndex) && ((before.Object != null && before.Object.Equals(current.Object)) || before.Object == null && current.Object == null)) { continue; // No change was done. Just don't do any changes. } //foundMatch = true; if (before.Contains(current.Index, current.GetLength(textColumnIndex), true, true)) { current.TextLine = null; n--; } ((TextAnchor)before).TextLine = textLine; offsetCount++; if (after != null) { ((TextAnchor)after).TextLine = textLine; offsetCount++; } } else { // The styled text segment is no more since it is no longer found. current.TextLine = null; n--; } } else if (textLine.StyledTextSegments[n].Index > relativeIndex) { if (isErase) { textLine.StyledTextSegments[n].Index -= length; } else { textLine.StyledTextSegments[n].Index += length; } } } } if (foundMatch == false) { #if DEBUG var foundOne = #endif this.TextSegmentStyledManager.SearchAndApplyTo(textView, textLine, startSearch, 1, CharacterIsFinalizer(c), textColumnIndex); } }