Example #1
0
        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);
            }
        }