diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs index a7d18c4533..38e6f58f88 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CustomizableHighlightingColorizer.cs @@ -22,6 +22,7 @@ namespace ICSharpCode.AvalonEdit.AddIn { public const string DefaultTextAndBackground = "Default text/background"; public const string SelectedText = "Selected text"; + public const string NonPrintableCharacters = "Non-printable characters"; public static void ApplyCustomizationsToDefaultElements(TextEditor textEditor, IEnumerable customizations) { @@ -30,8 +31,10 @@ namespace ICSharpCode.AvalonEdit.AddIn textEditor.TextArea.ClearValue(TextArea.SelectionBorderProperty); textEditor.TextArea.ClearValue(TextArea.SelectionBrushProperty); textEditor.TextArea.ClearValue(TextArea.SelectionForegroundProperty); + textEditor.TextArea.TextView.ClearValue(TextView.NonPrintableCharacterBrushProperty); bool assignedDefaultText = false; bool assignedSelectedText = false; + bool assignedNonPrintableCharacter = false; foreach (CustomizedHighlightingColor color in customizations) { switch (color.Name) { case DefaultTextAndBackground: @@ -54,7 +57,7 @@ namespace ICSharpCode.AvalonEdit.AddIn pen.Freeze(); textEditor.TextArea.SelectionBorder = pen; SolidColorBrush back = new SolidColorBrush(color.Background.Value); - back.Opacity = 0.7; + back.Opacity = 0.7; // TODO : remove this constant, let the use choose the opacity. back.Freeze(); textEditor.TextArea.SelectionBrush = back; } @@ -62,6 +65,14 @@ namespace ICSharpCode.AvalonEdit.AddIn textEditor.TextArea.SelectionForeground = CreateFrozenBrush(color.Foreground.Value); } break; + case NonPrintableCharacters: + if (assignedNonPrintableCharacter) + continue; + assignedNonPrintableCharacter = true; + + if (color.Foreground != null) + textEditor.TextArea.TextView.NonPrintableCharacterBrush = CreateFrozenBrush(color.Foreground.Value); + break; } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs index 97758bd9ce..ccd7d833fa 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs @@ -139,6 +139,21 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options selectedText.PropertyChanged += item_PropertyChanged; listBox.Items.Add(selectedText); + // Create entry for "Non-printable characters" + IHighlightingItem nonPrintChars = new SimpleHighlightingItem( + CustomizableHighlightingColorizer.NonPrintableCharacters, + ta => { + ta.Document.Text = " \r \r\n \n"; + }) + { + Foreground = Colors.LightGray + }; + nonPrintChars = new CustomizedHighlightingItem(customizationList, nonPrintChars, null, canSetFont: false, canSetBackground: false); + if (language != null) + nonPrintChars = new CustomizedHighlightingItem(customizationList, nonPrintChars, language, canSetFont: false); + nonPrintChars.PropertyChanged += item_PropertyChanged; + listBox.Items.Add(nonPrintChars); + // Create entry for "Bracket highlight" IHighlightingItem bracketHighlight = new SimpleHighlightingItem( BracketHighlightRenderer.BracketHighlight, @@ -157,7 +172,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options }; bracketHighlight = new CustomizedHighlightingItem(customizationList, bracketHighlight, null, canSetFont: false); if (language != null) - selectedText = new CustomizedHighlightingItem(customizationList, bracketHighlight, language, canSetFont: false); + bracketHighlight = new CustomizedHighlightingItem(customizationList, bracketHighlight, language, canSetFont: false); bracketHighlight.PropertyChanged += item_PropertyChanged; listBox.Items.Add(bracketHighlight); } @@ -203,6 +218,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options textView.LineTransformers.Add(colorizer); } textEditor.Select(0, 0); + bracketHighlighter.SetHighlight(null); item.ShowExample(textEditor.TextArea); } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs index dea23c35d7..e81afbb22e 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs @@ -54,7 +54,7 @@ namespace ICSharpCode.AvalonEdit.Rendering } else { return null; } - return new NewLineTextElement(CurrentContext.TextView.cachedElements.GetSimpleLightGrayText(newlineText, CurrentContext)); + return new NewLineTextElement(CurrentContext.TextView.cachedElements.GetTextForNonPrintableCharacter(newlineText, CurrentContext)); } sealed class NewLineTextElement : FormattedTextElement diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs index da1aacbc45..3d26e7c9b9 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs @@ -88,9 +88,9 @@ namespace ICSharpCode.AvalonEdit.Rendering { char c = CurrentContext.Document.GetCharAt(offset); if (ShowSpaces && c == ' ') { - return new SpaceTextElement(CurrentContext.TextView.cachedElements.GetSimpleLightGrayText("\u00B7", CurrentContext)); + return new SpaceTextElement(CurrentContext.TextView.cachedElements.GetTextForNonPrintableCharacter("\u00B7", CurrentContext)); } else if (ShowTabs && c == '\t') { - return new TabTextElement(CurrentContext.TextView.cachedElements.GetSimpleLightGrayText("\u00BB", CurrentContext)); + return new TabTextElement(CurrentContext.TextView.cachedElements.GetTextForNonPrintableCharacter("\u00BB", CurrentContext)); } else if (ShowBoxForControlCharacters && char.IsControl(c)) { var p = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties); p.SetForegroundBrush(Brushes.White); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs index 6be172d646..b615748b15 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs @@ -366,6 +366,17 @@ namespace ICSharpCode.AvalonEdit.Rendering } #endregion + #region Brushes + public static readonly DependencyProperty NonPrintableCharacterBrushProperty = + DependencyProperty.Register("NonPrintableCharacterBrush", typeof(Brush), typeof(TextView), + new FrameworkPropertyMetadata(Brushes.LightGray)); + + public Brush NonPrintableCharacterBrush { + get { return (Brush)GetValue(NonPrintableCharacterBrushProperty); } + set { SetValue(NonPrintableCharacterBrushProperty, value); } + } + #endregion + #region Redraw methods / VisualLine invalidation /// /// Causes the text editor to regenerate all visual lines. @@ -1660,7 +1671,8 @@ namespace ICSharpCode.AvalonEdit.Rendering || e.Property == Control.FontSizeProperty || e.Property == Control.FontStretchProperty || e.Property == Control.FontStyleProperty - || e.Property == Control.FontWeightProperty) + || e.Property == Control.FontWeightProperty + || e.Property == TextView.NonPrintableCharacterBrushProperty) { RecreateCachedElements(); InvalidateWideSpaceWidthAndDefaultLineHeight(); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextViewCachedElements.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextViewCachedElements.cs index c6f21fb312..b76a8a7be8 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextViewCachedElements.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextViewCachedElements.cs @@ -12,28 +12,28 @@ namespace ICSharpCode.AvalonEdit.Rendering sealed class TextViewCachedElements : IDisposable { TextFormatter formatter; - Dictionary simpleLightGrayTexts; + Dictionary nonPrintableCharacterTexts; - public TextLine GetSimpleLightGrayText(string text, ITextRunConstructionContext context) + public TextLine GetTextForNonPrintableCharacter(string text, ITextRunConstructionContext context) { - if (simpleLightGrayTexts == null) - simpleLightGrayTexts = new Dictionary(); + if (nonPrintableCharacterTexts == null) + nonPrintableCharacterTexts = new Dictionary(); TextLine textLine; - if (!simpleLightGrayTexts.TryGetValue(text, out textLine)) { + if (!nonPrintableCharacterTexts.TryGetValue(text, out textLine)) { var p = new VisualLineElementTextRunProperties(context.GlobalTextRunProperties); - p.SetForegroundBrush(Brushes.LightGray); + p.SetForegroundBrush(context.TextView.NonPrintableCharacterBrush); if (formatter == null) formatter = TextFormatterFactory.Create(context.TextView); textLine = FormattedTextElement.PrepareText(formatter, text, p); - simpleLightGrayTexts[text] = textLine; + nonPrintableCharacterTexts[text] = textLine; } return textLine; } public void Dispose() { - if (simpleLightGrayTexts != null) { - foreach (TextLine line in simpleLightGrayTexts.Values) + if (nonPrintableCharacterTexts != null) { + foreach (TextLine line in nonPrintableCharacterTexts.Values) line.Dispose(); } if (formatter != null)