From 608e9a5b1ae3a9daabd976b25d5f4458500b9724 Mon Sep 17 00:00:00 2001 From: SebastianDevelops Date: Wed, 23 Oct 2024 01:09:32 +0200 Subject: [PATCH 1/9] Wrap lines in WPF control --- .../BooleanToScrollBarVisibilityConverter.cs | 24 ++ DiffPlex.Wpf/Controls/DiffViewer.xaml | 317 +++++++++++---- DiffPlex.Wpf/Controls/DiffViewer.xaml.cs | 26 +- DiffPlex.Wpf/Controls/Helper.cs | 98 ++++- .../Controls/InternalLinesViewer.xaml | 372 +++++++++++++----- .../Controls/InternalLinesViewer.xaml.cs | 158 +++++++- DiffPlex.Wpf/DiffWindow.xaml.cs | 6 + 7 files changed, 790 insertions(+), 211 deletions(-) create mode 100644 DiffPlex.Wpf/Controls/BooleanToScrollBarVisibilityConverter.cs diff --git a/DiffPlex.Wpf/Controls/BooleanToScrollBarVisibilityConverter.cs b/DiffPlex.Wpf/Controls/BooleanToScrollBarVisibilityConverter.cs new file mode 100644 index 00000000..cfc1be80 --- /dev/null +++ b/DiffPlex.Wpf/Controls/BooleanToScrollBarVisibilityConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using System.Windows.Controls; +using System.Windows.Data; + +namespace DiffPlex.Wpf.Controls +{ + public class BooleanToScrollBarVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool isTextWrapEnabled) + { + return isTextWrapEnabled ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Auto; + } + return ScrollBarVisibility.Auto; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/DiffPlex.Wpf/Controls/DiffViewer.xaml b/DiffPlex.Wpf/Controls/DiffViewer.xaml index 2dbeb933..b0daf797 100644 --- a/DiffPlex.Wpf/Controls/DiffViewer.xaml +++ b/DiffPlex.Wpf/Controls/DiffViewer.xaml @@ -1,62 +1,81 @@ - + - - - - - - - - - + + + + + + + + + - + - - - + + + - - + + - - + + - - + + diff --git a/DiffPlex.Wpf/Controls/InternalLinesViewer.xaml.cs b/DiffPlex.Wpf/Controls/InternalLinesViewer.xaml.cs index 2e35e263..312be704 100644 --- a/DiffPlex.Wpf/Controls/InternalLinesViewer.xaml.cs +++ b/DiffPlex.Wpf/Controls/InternalLinesViewer.xaml.cs @@ -42,6 +42,8 @@ public ScrollBarVisibility VerticalScrollBarVisibility public ContextMenu LineContextMenu { get; set; } + public bool IsTextWrapEnabled { get; set; } + public double VerticalOffset => ValueScrollViewer.VerticalOffset; public int LineNumberWidth @@ -68,7 +70,151 @@ public void Clear() ValuePanel.Children.Clear(); } - public StackPanel Add(int? number, string operation, string value, string changeType, UIElement source) + public WrapPanel Add(int? number, string operation, string value, string changeType, UIElement source) + { + if (source is DiffViewer diffViewer) + { + IsTextWrapEnabled = diffViewer.IsTextWrapEnabled; + + var panel = new WrapPanel { Orientation = Orientation.Horizontal }; + + var grid = new Grid(); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); + grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); + + var index = new TextBlock + { + Text = number.HasValue ? number.ToString() : string.Empty, + TextAlignment = TextAlignment.Right, + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(2) + }; + index.SetBinding(TextBlock.ForegroundProperty, GetBindings("LineNumberForeground", diffViewer, Foreground)); + index.SetBinding(TextBlock.BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + ApplyTextBlockProperties(index, diffViewer); + + var op = new TextBlock + { + Text = operation, + TextAlignment = TextAlignment.Center, + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(2) + }; + op.SetBinding(TextBlock.ForegroundProperty, GetBindings("ChangeTypeForeground", diffViewer, Foreground)); + op.SetBinding(TextBlock.BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + ApplyTextBlockProperties(op, diffViewer); + + Grid.SetColumn(index, 0); + Grid.SetColumn(op, 1); + grid.Children.Add(index); + grid.Children.Add(op); + + var text = new TextBlock + { + Text = value, + TextWrapping = IsTextWrapEnabled ? TextWrapping.Wrap : TextWrapping.NoWrap, + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(5, 0, 5, 0) + }; + if (!string.IsNullOrEmpty(value)) + { + text.SetBinding(TextBlock.ForegroundProperty, GetBindings(changeType + "Foreground", diffViewer, Foreground)); + text.SetBinding(TextBlock.BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + ApplyTextBlockProperties(text, diffViewer); + grid.ContextMenu = LineContextMenu; + } + + Grid.SetColumn(text, 2); + grid.Children.Add(text); + + panel.Children.Add(grid); + + ValuePanel.Children.Add(panel); + ValuePanel.CanHorizontallyScroll = false; + ValueScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; + + return panel; + } + else + { + throw new Exception("Source is not a DiffViewer"); + } + } + + public WrapPanel Add(int? number, string operation, List> value, string changeType, UIElement source) + { + if (source is DiffViewer diffViewer) + { + IsTextWrapEnabled = diffViewer.IsTextWrapEnabled; + + var index = new TextBlock + { + Text = number.HasValue ? number.ToString() : string.Empty, + TextAlignment = TextAlignment.Right, + VerticalAlignment = VerticalAlignment.Top + }; + index.SetBinding(TextBlock.ForegroundProperty, GetBindings("LineNumberForeground", diffViewer, Foreground)); + index.SetBinding(TextBlock.BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + ApplyTextBlockProperties(index, diffViewer); + NumberPanel.Children.Add(index); + + var op = new TextBlock + { + Text = operation, + TextAlignment = TextAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + }; + op.SetBinding(TextBlock.ForegroundProperty, GetBindings("ChangeTypeForeground", diffViewer, Foreground)); + op.SetBinding(TextBlock.BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + ApplyTextBlockProperties(op, diffViewer); + OperationPanel.Children.Add(op); + + var panel = new WrapPanel { Orientation = Orientation.Horizontal }; + panel.SetBinding(BackgroundProperty, GetBindings(changeType + "Background", diffViewer)); + value ??= new List>(); + foreach (var ele in value) + { + if (string.IsNullOrEmpty(ele.Key)) continue; + var text = new TextBlock + { + Text = ele.Key, + VerticalAlignment = VerticalAlignment.Top, + TextWrapping = IsTextWrapEnabled ? TextWrapping.Wrap : TextWrapping.NoWrap + }; + if (!string.IsNullOrEmpty(ele.Value)) + { + if (!string.IsNullOrEmpty(ele.Key)) + text.SetBinding(TextBlock.ForegroundProperty, GetBindings(ele.Value + "Foreground", diffViewer, Foreground)); + text.SetBinding(TextBlock.BackgroundProperty, GetBindings(ele.Value + "Background", diffViewer)); + } + + ApplyTextBlockProperties(text, diffViewer); + panel.Children.Add(text); + } + + if (panel.Children.Count == 0) + { + panel.Children.Add(new TextBlock()); + } + else + { + panel.ContextMenu = LineContextMenu; + } + + ValuePanel.Children.Add(panel); + ValuePanel.CanHorizontallyScroll = false; + ValueScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled; + + return panel; + } + else + { + throw new Exception("Source is not a DiffViewer"); + } + } + + public StackPanel AddNoWrap(int? number, string operation, string value, string changeType, UIElement source) { var index = new TextBlock { @@ -106,10 +252,13 @@ public StackPanel Add(int? number, string operation, string value, string change panel.Children.Add(text); ValuePanel.Children.Add(panel); + ValuePanel.CanHorizontallyScroll = true; + ValueScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible; + return panel; } - public StackPanel Add(int? number, string operation, List> value, string changeType, UIElement source) + public StackPanel AddNoWrap(int? number, string operation, List> value, string changeType, UIElement source) { var index = new TextBlock { @@ -162,6 +311,9 @@ public StackPanel Add(int? number, string operation, ListThe control template to set. public void SetMenuTextBoxTemlate(ControlTemplate template) => DiffView.SetMenuTextBoxTemlate(template); + + /// + /// Enables text wrapping for the text blocks in the diff viewer. + /// + public void EnableTextWrapping() + => DiffView.EnableTextWrapping(); } } From 77df546916165ee46053bbfe24cca2527452cfb6 Mon Sep 17 00:00:00 2001 From: SebastianDevelops Date: Wed, 23 Oct 2024 01:20:56 +0200 Subject: [PATCH 2/9] Added text wrapping to demo --- DiffPlex.Wpf.Demo/MainWindow.xaml | 1 + DiffPlex.Wpf.Demo/MainWindow.xaml.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/DiffPlex.Wpf.Demo/MainWindow.xaml b/DiffPlex.Wpf.Demo/MainWindow.xaml index bf0dd294..249c8dc3 100644 --- a/DiffPlex.Wpf.Demo/MainWindow.xaml +++ b/DiffPlex.Wpf.Demo/MainWindow.xaml @@ -18,6 +18,7 @@