diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index 5caf35c418..f4f4f22327 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -511,6 +511,7 @@ namespace ICSharpCode.AvalonEdit.AddIn string language = this.SyntaxHighlighting != null ? this.SyntaxHighlighting.Name : null; CustomizableHighlightingColorizer.ApplyCustomizationsToDefaultElements(this, FetchCustomizations(language)); BracketHighlightRenderer.ApplyCustomizationsToRendering(this.bracketRenderer, FetchCustomizations(language)); + HighlightingOptions.ApplyToFolding(this, FetchCustomizations(language)); this.TextArea.TextView.Redraw(); // manually redraw if default elements didn't change but customized highlightings did } 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 20b1836244..0ba535891d 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/HighlightingOptions.xaml.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.ComponentModel; using System.IO; using System.Linq; @@ -10,7 +11,9 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Xml; + using ICSharpCode.AvalonEdit.Editing; +using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Rendering; @@ -32,14 +35,70 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options textEditor.Document.UndoStack.SizeLimit = 0; textEditor.Options = CodeEditorOptions.Instance; bracketHighlighter = new BracketHighlightRenderer(textEditor.TextArea.TextView); - + foldingManager = FoldingManager.Install(textEditor.TextArea); CodeEditorOptions.Instance.BindToTextEditor(textEditor); } BracketHighlightRenderer bracketHighlighter; - + FoldingManager foldingManager; List customizationList; + #region Folding + // TODO : probably move this to a separate class! + public const string FoldingControls = "Folding controls"; + public const string FoldingSelectedControls = "Selected folding controls"; + public const string FoldingTextMarkers = "Folding markers"; + + static SolidColorBrush CreateFrozenBrush(Color color) + { + SolidColorBrush brush = new SolidColorBrush(color); + brush.Freeze(); + return brush; + } + + public static void ApplyToFolding(TextEditor editor, IEnumerable customisations) + { + bool assignedFoldingMarker = false, assignedSelectedFoldingControls = false, assignedFoldingTextMarkers = false; + + editor.ClearValue(FoldingMargin.FoldingMarkerBrushProperty); + editor.ClearValue(FoldingMargin.FoldingMarkerBackgroundBrushProperty); + editor.ClearValue(FoldingMargin.SelectedFoldingMarkerBrushProperty); + editor.ClearValue(FoldingMargin.SelectedFoldingMarkerBackgroundBrushProperty); + + FoldingElementGenerator.TextBrush = FoldingElementGenerator.DefaultTextBrush; + + foreach (CustomizedHighlightingColor color in customisations) { + switch (color.Name) { + case FoldingControls: + if (assignedFoldingMarker) + continue; + assignedFoldingMarker = true; + if (color.Foreground != null) + editor.SetValue(FoldingMargin.FoldingMarkerBrushProperty, CreateFrozenBrush(color.Foreground.Value)); + if (color.Background != null) + editor.SetValue(FoldingMargin.FoldingMarkerBackgroundBrushProperty, CreateFrozenBrush(color.Background.Value)); + break; + case FoldingSelectedControls: + if (assignedSelectedFoldingControls) + continue; + assignedSelectedFoldingControls = true; + if (color.Foreground != null) + editor.SetValue(FoldingMargin.SelectedFoldingMarkerBrushProperty, CreateFrozenBrush(color.Foreground.Value)); + if (color.Background != null) + editor.SetValue(FoldingMargin.SelectedFoldingMarkerBackgroundBrushProperty, CreateFrozenBrush(color.Background.Value)); + break; + case FoldingTextMarkers: + if (assignedFoldingTextMarkers) + continue; + assignedFoldingTextMarkers = true; + if (color.Foreground != null) + FoldingElementGenerator.TextBrush = CreateFrozenBrush(color.Foreground.Value); + break; + } + } + } + #endregion + XshdSyntaxDefinition LoadBuiltinXshd(string name) { using (Stream s = typeof(HighlightingManager).Assembly.GetManifestResourceStream(name)) { @@ -193,6 +252,62 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options bracketHighlight = new CustomizedHighlightingItem(customizationList, bracketHighlight, language, canSetFont: false); bracketHighlight.PropertyChanged += item_PropertyChanged; listBox.Items.Add(bracketHighlight); + + // Create entry for "Folding controls" + IHighlightingItem foldingControls = new SimpleHighlightingItem( + FoldingControls, + ta => { + ta.Document.Text = "This" + Environment.NewLine + + "is a folding" + Environment.NewLine + + "example"; + foldingManager.CreateFolding(0, 10); + }) + { + Foreground = Colors.Gray, + Background = Colors.White + }; + foldingControls = new CustomizedHighlightingItem(customizationList, foldingControls, null, canSetFont: false); + if (language != null) + foldingControls = new CustomizedHighlightingItem(customizationList, foldingControls, language, canSetFont: false); + foldingControls.PropertyChanged += item_PropertyChanged; + listBox.Items.Add(foldingControls); + + // Create entry for "Selected folding controls" + IHighlightingItem selectedFoldingControls = new SimpleHighlightingItem( + FoldingSelectedControls, + ta => { + ta.Document.Text = "This" + Environment.NewLine + + "is a folding" + Environment.NewLine + + "example"; + foldingManager.CreateFolding(0, 10); + }) + { + Foreground = Colors.Black, + Background = Colors.White + }; + selectedFoldingControls = new CustomizedHighlightingItem(customizationList, selectedFoldingControls, null, canSetFont: false); + if (language != null) + selectedFoldingControls = new CustomizedHighlightingItem(customizationList, selectedFoldingControls, language, canSetFont: false); + selectedFoldingControls.PropertyChanged += item_PropertyChanged; + listBox.Items.Add(selectedFoldingControls); + + // Create entry for "Folding text markers" + IHighlightingItem foldingTextMarker = new SimpleHighlightingItem( + FoldingTextMarkers, + ta => { + ta.Document.Text = "This" + Environment.NewLine + + "is a folding" + Environment.NewLine + + "example"; + foldingManager.CreateFolding(0, 10).IsFolded = true; + }) + { + Foreground = Colors.Gray + }; + foldingTextMarker = new CustomizedHighlightingItem(customizationList, foldingTextMarker, null, canSetFont: false, canSetBackground: false); + if (language != null) + foldingControls = new CustomizedHighlightingItem(customizationList, foldingTextMarker, language, canSetFont: false, canSetBackground: false); + foldingTextMarker.PropertyChanged += item_PropertyChanged; + listBox.Items.Add(foldingTextMarker); } void item_PropertyChanged(object sender, PropertyChangedEventArgs e) @@ -226,8 +341,10 @@ namespace ICSharpCode.AvalonEdit.AddIn.Options if (xshd != null) { var customizationsForCurrentLanguage = customizationList.Where(c => c.Language == null || c.Language == xshd.Name); CustomizableHighlightingColorizer.ApplyCustomizationsToDefaultElements(textEditor, customizationsForCurrentLanguage); + ApplyToFolding(textEditor, customizationsForCurrentLanguage); var item = (IHighlightingItem)listBox.SelectedItem; TextView textView = textEditor.TextArea.TextView; + foldingManager.Clear(); textView.LineTransformers.Remove(colorizer); colorizer = null; if (item != null) { diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs index 5168a04100..b8251ed8de 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingElementGenerator.cs @@ -99,10 +99,10 @@ namespace ICSharpCode.AvalonEdit.Folding if (string.IsNullOrEmpty(title)) title = "..."; var p = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties); - p.SetForegroundBrush(Brushes.Gray); + p.SetForegroundBrush(textBrush); var textFormatter = TextFormatterFactory.Create(CurrentContext.TextView); var text = FormattedTextElement.PrepareText(textFormatter, title, p); - return new FoldingLineElement(foldingSection, text, foldedUntil - offset); + return new FoldingLineElement(foldingSection, text, foldedUntil - offset) { textBrush = textBrush }; } else { return null; } @@ -112,6 +112,8 @@ namespace ICSharpCode.AvalonEdit.Folding { readonly FoldingSection fs; + internal Brush textBrush; + public FoldingLineElement(FoldingSection fs, TextLine text, int documentLength) : base(text, documentLength) { this.fs = fs; @@ -119,7 +121,7 @@ namespace ICSharpCode.AvalonEdit.Folding public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context) { - return new FoldingLineTextRun(this, this.TextRunProperties); + return new FoldingLineTextRun(this, this.TextRunProperties) { textBrush = textBrush }; } protected internal override void OnMouseDown(MouseButtonEventArgs e) @@ -135,6 +137,8 @@ namespace ICSharpCode.AvalonEdit.Folding sealed class FoldingLineTextRun : FormattedTextRun { + internal Brush textBrush; + public FoldingLineTextRun(FormattedTextElement element, TextRunProperties properties) : base(element, properties) { @@ -144,9 +148,18 @@ namespace ICSharpCode.AvalonEdit.Folding { var metrics = Format(double.PositiveInfinity); Rect r = new Rect(origin.X, origin.Y - metrics.Baseline, metrics.Width, metrics.Height); - drawingContext.DrawRectangle(null, new Pen(Brushes.Gray, 1), r); + drawingContext.DrawRectangle(null, new Pen(textBrush, 1), r); base.Draw(drawingContext, origin, rightToLeft, sideways); } } + + public static readonly Brush DefaultTextBrush = Brushes.Gray; + + static Brush textBrush = DefaultTextBrush; + + public static Brush TextBrush { + get { return textBrush; } + set { textBrush = value; } + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs index 8c25c74b5d..e26a5762c3 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs @@ -27,6 +27,54 @@ namespace ICSharpCode.AvalonEdit.Folding internal const double SizeFactor = Constants.PixelPerPoint; + #region Brushes + public static readonly DependencyProperty FoldingMarkerBrushProperty = + DependencyProperty.RegisterAttached("FoldingMarkerBrush", typeof(Brush), typeof(FoldingMargin), + new FrameworkPropertyMetadata(Brushes.Gray, FrameworkPropertyMetadataOptions.Inherits, OnUpdateBrushes)); + + public Brush FoldingMarkerBrush { + get { return (Brush)GetValue(FoldingMarkerBrushProperty); } + set { SetValue(FoldingMarkerBrushProperty, value); } + } + + public static readonly DependencyProperty FoldingMarkerBackgroundBrushProperty = + DependencyProperty.RegisterAttached("FoldingMarkerBackgroundBrush", typeof(Brush), typeof(FoldingMargin), + new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.Inherits, OnUpdateBrushes)); + + public Brush FoldingMarkerBackgroundBrush { + get { return (Brush)GetValue(FoldingMarkerBackgroundBrushProperty); } + set { SetValue(FoldingMarkerBackgroundBrushProperty, value); } + } + + public static readonly DependencyProperty SelectedFoldingMarkerBrushProperty = + DependencyProperty.RegisterAttached("SelectedFoldingMarkerBrush", + typeof(Brush), typeof(FoldingMargin), + new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.Inherits, OnUpdateBrushes)); + + public Brush SelectedFoldingMarkerBrush { + get { return (Brush)GetValue(SelectedFoldingMarkerBrushProperty); } + set { SetValue(SelectedFoldingMarkerBrushProperty, value); } + } + + public static readonly DependencyProperty SelectedFoldingMarkerBackgroundBrushProperty = + DependencyProperty.RegisterAttached("SelectedFoldingMarkerBackgroundBrush", + typeof(Brush), typeof(FoldingMargin), + new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.Inherits, OnUpdateBrushes)); + + public Brush SelectedFoldingMarkerBackgroundBrush { + get { return (Brush)GetValue(SelectedFoldingMarkerBackgroundBrushProperty); } + set { SetValue(SelectedFoldingMarkerBackgroundBrushProperty, value); } + } + + static void OnUpdateBrushes(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (e.Property.Name == FoldingMarkerBrushProperty.Name) + foldingControlPen = MakeFrozenPen((Brush)e.NewValue); + if (e.Property.Name == SelectedFoldingMarkerBrushProperty.Name) + selectedFoldingControlPen = MakeFrozenPen((Brush)e.NewValue); + } + #endregion + /// protected override Size MeasureOverride(Size availableSize) { @@ -85,6 +133,7 @@ namespace ICSharpCode.AvalonEdit.Folding VisualLine = line, FoldingSection = fs }; + markers.Add(m); AddVisualChild(m); @@ -108,8 +157,8 @@ namespace ICSharpCode.AvalonEdit.Folding return markers[index]; } - static readonly Pen grayPen = MakeFrozenPen(Brushes.Gray); - static readonly Pen blackPen = MakeFrozenPen(Brushes.Black); + static Pen foldingControlPen = MakeFrozenPen((Brush)FoldingMarkerBrushProperty.DefaultMetadata.DefaultValue); + static Pen selectedFoldingControlPen = MakeFrozenPen((Brush)SelectedFoldingMarkerBrushProperty.DefaultMetadata.DefaultValue); static Pen MakeFrozenPen(Brush brush) { @@ -152,7 +201,7 @@ namespace ICSharpCode.AvalonEdit.Folding if (end < viewEndOffset && !fs.IsFolded) { int textLineNr = GetTextLineIndexFromOffset(allTextLines, end); if (textLineNr >= 0) { - endMarker[textLineNr] = grayPen; + endMarker[textLineNr] = foldingControlPen; } } if (end > maxEndOffset && fs.StartOffset < viewStartOffset) { @@ -162,12 +211,12 @@ namespace ICSharpCode.AvalonEdit.Folding if (maxEndOffset > 0) { if (maxEndOffset > viewEndOffset) { for (int i = 0; i < colors.Length; i++) { - colors[i] = grayPen; + colors[i] = foldingControlPen; } } else { int maxTextLine = GetTextLineIndexFromOffset(allTextLines, maxEndOffset); for (int i = 0; i <= maxTextLine; i++) { - colors[i] = grayPen; + colors[i] = foldingControlPen; } } } @@ -183,17 +232,17 @@ namespace ICSharpCode.AvalonEdit.Folding int endTextLineNr = GetTextLineIndexFromOffset(allTextLines, end); if (!marker.FoldingSection.IsFolded && endTextLineNr >= 0) { if (marker.IsMouseDirectlyOver) - endMarker[endTextLineNr] = blackPen; + endMarker[endTextLineNr] = selectedFoldingControlPen; else if (endMarker[endTextLineNr] == null) - endMarker[endTextLineNr] = grayPen; + endMarker[endTextLineNr] = foldingControlPen; } int startTextLineNr = GetTextLineIndexFromOffset(allTextLines, marker.FoldingSection.StartOffset); if (startTextLineNr >= 0) { for (int i = startTextLineNr + 1; i < colors.Length && i - 1 != endTextLineNr; i++) { if (marker.IsMouseDirectlyOver) - colors[i] = blackPen; + colors[i] = selectedFoldingControlPen; else if (colors[i] == null) - colors[i] = grayPen; + colors[i] = foldingControlPen; } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs index d2f68d01d3..c6b21c564c 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs @@ -53,25 +53,27 @@ namespace ICSharpCode.AvalonEdit.Folding protected override void OnRender(DrawingContext drawingContext) { - Pen blackPen = new Pen(Brushes.Black, 1); - blackPen.StartLineCap = PenLineCap.Square; - blackPen.EndLineCap = PenLineCap.Square; + FoldingMargin margin = VisualParent as FoldingMargin; + Pen activePen = new Pen(margin.SelectedFoldingMarkerBrush, 1); + Pen inactivePen = new Pen(margin.FoldingMarkerBrush, 1); + activePen.StartLineCap = inactivePen.StartLineCap = PenLineCap.Square; + activePen.EndLineCap = inactivePen.EndLineCap = PenLineCap.Square; Size pixelSize = PixelSnapHelpers.GetPixelSize(this); Rect rect = new Rect(pixelSize.Width / 2, pixelSize.Height / 2, this.RenderSize.Width - pixelSize.Width, this.RenderSize.Height - pixelSize.Height); - drawingContext.DrawRectangle(Brushes.White, - IsMouseDirectlyOver ? blackPen : new Pen(Brushes.Gray, 1), - rect); + drawingContext.DrawRectangle( + IsMouseDirectlyOver ? margin.SelectedFoldingMarkerBackgroundBrush : margin.FoldingMarkerBackgroundBrush, + IsMouseDirectlyOver ? activePen : inactivePen, rect); double middleX = rect.Left + rect.Width / 2; double middleY = rect.Top + rect.Height / 2; double space = PixelSnapHelpers.Round(rect.Width / 8, pixelSize.Width) + pixelSize.Width; - drawingContext.DrawLine(blackPen, + drawingContext.DrawLine(activePen, new Point(rect.Left + space, middleY), new Point(rect.Right - space, middleY)); if (!isExpanded) { - drawingContext.DrawLine(blackPen, + drawingContext.DrawLine(activePen, new Point(middleX, rect.Top + space), new Point(middleX, rect.Bottom - space)); }