From 728d516a611a18f611f85b40971616e445c8dffd Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Wed, 3 Nov 2021 19:27:01 +0100 Subject: [PATCH] Fix #2298: Allow to change the DecompilerTextView's font size through scrolling. --- ILSpy/Controls/CollapsiblePanel.cs | 209 ++++++++++++++++++ ILSpy/Controls/ZoomButtons.cs | 73 ++++++ ILSpy/Controls/ZoomScrollViewer.cs | 196 ++++++++++++++++ ILSpy/Controls/ZoomScrollViewer.xaml | 128 +++++++++++ ILSpy/Images/ZoomIn.svg | 65 ++++++ ILSpy/Images/ZoomIn.xaml | 27 +++ ILSpy/Images/ZoomOut.svg | 57 +++++ ILSpy/Images/ZoomOut.xaml | 20 ++ ILSpy/TextView/DecompilerTextView.xaml | 35 ++- .../ZoomLevelToTextFormattingModeConverter.cs | 38 ++++ ILSpy/Themes/generic.xaml | 1 + 11 files changed, 846 insertions(+), 3 deletions(-) create mode 100644 ILSpy/Controls/CollapsiblePanel.cs create mode 100644 ILSpy/Controls/ZoomButtons.cs create mode 100644 ILSpy/Controls/ZoomScrollViewer.cs create mode 100644 ILSpy/Controls/ZoomScrollViewer.xaml create mode 100644 ILSpy/Images/ZoomIn.svg create mode 100644 ILSpy/Images/ZoomIn.xaml create mode 100644 ILSpy/Images/ZoomOut.svg create mode 100644 ILSpy/Images/ZoomOut.xaml create mode 100644 ILSpy/TextView/ZoomLevelToTextFormattingModeConverter.cs diff --git a/ILSpy/Controls/CollapsiblePanel.cs b/ILSpy/Controls/CollapsiblePanel.cs new file mode 100644 index 000000000..ef2f3a9c3 --- /dev/null +++ b/ILSpy/Controls/CollapsiblePanel.cs @@ -0,0 +1,209 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media.Animation; +using System.Windows.Threading; + +namespace ICSharpCode.ILSpy.Controls +{ + /// + /// Allows animated collapsing of the content of this panel. + /// + public class CollapsiblePanel : ContentControl + { + static CollapsiblePanel() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(typeof(CollapsiblePanel))); + FocusableProperty.OverrideMetadata(typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(false)); + } + + public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register( + "IsCollapsed", typeof(bool), typeof(CollapsiblePanel), + new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsCollapsedChanged))); + + public bool IsCollapsed { + get { return (bool)GetValue(IsCollapsedProperty); } + set { SetValue(IsCollapsedProperty, value); } + } + + public static readonly DependencyProperty CollapseOrientationProperty = + DependencyProperty.Register("CollapseOrientation", typeof(Orientation), typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(Orientation.Vertical)); + + public Orientation CollapseOrientation { + get { return (Orientation)GetValue(CollapseOrientationProperty); } + set { SetValue(CollapseOrientationProperty, value); } + } + + public static readonly DependencyProperty DurationProperty = DependencyProperty.Register( + "Duration", typeof(TimeSpan), typeof(CollapsiblePanel), + new UIPropertyMetadata(TimeSpan.FromMilliseconds(250))); + + /// + /// The duration in milliseconds of the animation. + /// + public TimeSpan Duration { + get { return (TimeSpan)GetValue(DurationProperty); } + set { SetValue(DurationProperty, value); } + } + + protected internal static readonly DependencyProperty AnimationProgressProperty = DependencyProperty.Register( + "AnimationProgress", typeof(double), typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(1.0)); + + /// + /// Value between 0 and 1 specifying how far the animation currently is. + /// + protected internal double AnimationProgress { + get { return (double)GetValue(AnimationProgressProperty); } + set { SetValue(AnimationProgressProperty, value); } + } + + protected internal static readonly DependencyProperty AnimationProgressXProperty = DependencyProperty.Register( + "AnimationProgressX", typeof(double), typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(1.0)); + + /// + /// Value between 0 and 1 specifying how far the animation currently is. + /// + protected internal double AnimationProgressX { + get { return (double)GetValue(AnimationProgressXProperty); } + set { SetValue(AnimationProgressXProperty, value); } + } + + protected internal static readonly DependencyProperty AnimationProgressYProperty = DependencyProperty.Register( + "AnimationProgressY", typeof(double), typeof(CollapsiblePanel), + new FrameworkPropertyMetadata(1.0)); + + /// + /// Value between 0 and 1 specifying how far the animation currently is. + /// + protected internal double AnimationProgressY { + get { return (double)GetValue(AnimationProgressYProperty); } + set { SetValue(AnimationProgressYProperty, value); } + } + + static void OnIsCollapsedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((CollapsiblePanel)d).SetupAnimation((bool)e.NewValue); + } + + void SetupAnimation(bool isCollapsed) + { + if (this.IsLoaded) + { + // If the animation is already running, calculate remaining portion of the time + double currentProgress = AnimationProgress; + if (!isCollapsed) + { + currentProgress = 1.0 - currentProgress; + } + + DoubleAnimation animation = new DoubleAnimation(); + animation.To = isCollapsed ? 0.0 : 1.0; + animation.Duration = TimeSpan.FromSeconds(Duration.TotalSeconds * currentProgress); + animation.FillBehavior = FillBehavior.HoldEnd; + + this.BeginAnimation(AnimationProgressProperty, animation); + if (CollapseOrientation == Orientation.Horizontal) + { + this.BeginAnimation(AnimationProgressXProperty, animation); + this.AnimationProgressY = 1.0; + } + else + { + this.AnimationProgressX = 1.0; + this.BeginAnimation(AnimationProgressYProperty, animation); + } + } + else + { + this.AnimationProgress = isCollapsed ? 0.0 : 1.0; + this.AnimationProgressX = (CollapseOrientation == Orientation.Horizontal) ? this.AnimationProgress : 1.0; + this.AnimationProgressY = (CollapseOrientation == Orientation.Vertical) ? this.AnimationProgress : 1.0; + } + } + } + + sealed class CollapsiblePanelProgressToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is double) + return (double)value > 0 ? Visibility.Visible : Visibility.Collapsed; + else + return Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } + + public class SelfCollapsingPanel : CollapsiblePanel + { + public static readonly DependencyProperty CanCollapseProperty = + DependencyProperty.Register("CanCollapse", typeof(bool), typeof(SelfCollapsingPanel), + new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnCanCollapseChanged))); + + public bool CanCollapse { + get { return (bool)GetValue(CanCollapseProperty); } + set { SetValue(CanCollapseProperty, value); } + } + + static void OnCanCollapseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + SelfCollapsingPanel panel = (SelfCollapsingPanel)d; + if ((bool)e.NewValue) + { + if (!panel.HeldOpenByMouse) + panel.IsCollapsed = true; + } + else + { + panel.IsCollapsed = false; + } + } + + bool HeldOpenByMouse { + get { return IsMouseOver || IsMouseCaptureWithin; } + } + + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseLeave(e); + if (CanCollapse && !HeldOpenByMouse) + IsCollapsed = true; + } + + protected override void OnLostMouseCapture(MouseEventArgs e) + { + base.OnLostMouseCapture(e); + if (CanCollapse && !HeldOpenByMouse) + IsCollapsed = true; + } + } +} diff --git a/ILSpy/Controls/ZoomButtons.cs b/ILSpy/Controls/ZoomButtons.cs new file mode 100644 index 000000000..428fa6848 --- /dev/null +++ b/ILSpy/Controls/ZoomButtons.cs @@ -0,0 +1,73 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ICSharpCode.ILSpy.Controls +{ + public class ZoomButtons : RangeBase + { + static ZoomButtons() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ZoomButtons), + new FrameworkPropertyMetadata(typeof(ZoomButtons))); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + var uxPlus = (ButtonBase)Template.FindName("uxPlus", this); + var uxMinus = (ButtonBase)Template.FindName("uxMinus", this); + var uxReset = (ButtonBase)Template.FindName("uxReset", this); + + if (uxPlus != null) + uxPlus.Click += OnZoomInClick; + if (uxMinus != null) + uxMinus.Click += OnZoomOutClick; + if (uxReset != null) + uxReset.Click += OnResetClick; + } + + const double ZoomFactor = 1.1; + + void OnZoomInClick(object sender, EventArgs e) + { + SetCurrentValue(ValueProperty, ZoomScrollViewer.RoundToOneIfClose(this.Value * ZoomFactor)); + } + + void OnZoomOutClick(object sender, EventArgs e) + { + SetCurrentValue(ValueProperty, ZoomScrollViewer.RoundToOneIfClose(this.Value / ZoomFactor)); + } + + void OnResetClick(object sender, EventArgs e) + { + SetCurrentValue(ValueProperty, 1.0); + } + } +} diff --git a/ILSpy/Controls/ZoomScrollViewer.cs b/ILSpy/Controls/ZoomScrollViewer.cs new file mode 100644 index 000000000..dff54789c --- /dev/null +++ b/ILSpy/Controls/ZoomScrollViewer.cs @@ -0,0 +1,196 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ICSharpCode.ILSpy.Controls +{ + public class ZoomScrollViewer : ScrollViewer + { + static ZoomScrollViewer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(typeof(ZoomScrollViewer))); + } + + public static readonly DependencyProperty CurrentZoomProperty = + DependencyProperty.Register("CurrentZoom", typeof(double), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CalculateZoomButtonCollapsed, CoerceZoom)); + + public double CurrentZoom { + get { return (double)GetValue(CurrentZoomProperty); } + set { SetValue(CurrentZoomProperty, value); } + } + + static object CoerceZoom(DependencyObject d, object baseValue) + { + var zoom = (double)baseValue; + ZoomScrollViewer sv = (ZoomScrollViewer)d; + return Math.Max(sv.MinimumZoom, Math.Min(sv.MaximumZoom, zoom)); + } + + public static readonly DependencyProperty MinimumZoomProperty = + DependencyProperty.Register("MinimumZoom", typeof(double), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(0.2)); + + public double MinimumZoom { + get { return (double)GetValue(MinimumZoomProperty); } + set { SetValue(MinimumZoomProperty, value); } + } + + public static readonly DependencyProperty MaximumZoomProperty = + DependencyProperty.Register("MaximumZoom", typeof(double), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(5.0)); + + public double MaximumZoom { + get { return (double)GetValue(MaximumZoomProperty); } + set { SetValue(MaximumZoomProperty, value); } + } + + public static readonly DependencyProperty MouseWheelZoomProperty = + DependencyProperty.Register("MouseWheelZoom", typeof(bool), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(true)); + + public bool MouseWheelZoom { + get { return (bool)GetValue(MouseWheelZoomProperty); } + set { SetValue(MouseWheelZoomProperty, value); } + } + + public static readonly DependencyProperty AlwaysShowZoomButtonsProperty = + DependencyProperty.Register("AlwaysShowZoomButtons", typeof(bool), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(false, CalculateZoomButtonCollapsed)); + + public bool AlwaysShowZoomButtons { + get { return (bool)GetValue(AlwaysShowZoomButtonsProperty); } + set { SetValue(AlwaysShowZoomButtonsProperty, value); } + } + + static readonly DependencyPropertyKey ComputedZoomButtonCollapsedPropertyKey = + DependencyProperty.RegisterReadOnly("ComputedZoomButtonCollapsed", typeof(bool), typeof(ZoomScrollViewer), + new FrameworkPropertyMetadata(true)); + + public static readonly DependencyProperty ComputedZoomButtonCollapsedProperty = ComputedZoomButtonCollapsedPropertyKey.DependencyProperty; + + public bool ComputedZoomButtonCollapsed { + get { return (bool)GetValue(ComputedZoomButtonCollapsedProperty); } + private set { SetValue(ComputedZoomButtonCollapsedPropertyKey, value); } + } + + static void CalculateZoomButtonCollapsed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ZoomScrollViewer z = d as ZoomScrollViewer; + if (z != null) + z.ComputedZoomButtonCollapsed = (z.AlwaysShowZoomButtons == false) && (z.CurrentZoom == 1.0); + } + + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + if (!e.Handled && Keyboard.Modifiers == ModifierKeys.Control && MouseWheelZoom) + { + double oldZoom = CurrentZoom; + double newZoom = RoundToOneIfClose(CurrentZoom * Math.Pow(1.001, e.Delta)); + newZoom = Math.Max(this.MinimumZoom, Math.Min(this.MaximumZoom, newZoom)); + + // adjust scroll position so that mouse stays over the same virtual coordinate + ContentPresenter presenter = Template.FindName("PART_Presenter", this) as ContentPresenter; + Vector relMousePos; + if (presenter != null) + { + Point mousePos = e.GetPosition(presenter); + relMousePos = new Vector(mousePos.X / presenter.ActualWidth, mousePos.Y / presenter.ActualHeight); + } + else + { + relMousePos = new Vector(0.5, 0.5); + } + + Point scrollOffset = new Point(this.HorizontalOffset, this.VerticalOffset); + Vector oldHalfViewport = new Vector(this.ViewportWidth / 2, this.ViewportHeight / 2); + Vector newHalfViewport = oldHalfViewport / newZoom * oldZoom; + Point oldCenter = scrollOffset + oldHalfViewport; + Point virtualMousePos = scrollOffset + new Vector(relMousePos.X * this.ViewportWidth, relMousePos.Y * this.ViewportHeight); + + // As newCenter, we want to choose a point between oldCenter and virtualMousePos. The more we zoom in, the closer + // to virtualMousePos. We'll create the line x = oldCenter + lambda * (virtualMousePos-oldCenter). + // On this line, we need to choose lambda between -1 and 1: + // -1 = zoomed out completely + // 0 = zoom unchanged + // +1 = zoomed in completely + // But the zoom factor (newZoom/oldZoom) we have is in the range [0,+Infinity]. + + // Basically, I just played around until I found a function that maps this to [-1,1] and works well. + // "f" is squared because otherwise the mouse simply stays over virtualMousePos, but I wanted virtualMousePos + // to move towards the middle -> squaring f causes lambda to be closer to 1, giving virtualMousePos more weight + // then oldCenter. + + double f = Math.Min(newZoom, oldZoom) / Math.Max(newZoom, oldZoom); + double lambda = 1 - f * f; + if (oldZoom > newZoom) + lambda = -lambda; + + Debug.Print("old: " + oldZoom + ", new: " + newZoom); + + Point newCenter = oldCenter + lambda * (virtualMousePos - oldCenter); + scrollOffset = newCenter - newHalfViewport; + + SetCurrentValue(CurrentZoomProperty, newZoom); + + this.ScrollToHorizontalOffset(scrollOffset.X); + this.ScrollToVerticalOffset(scrollOffset.Y); + + e.Handled = true; + } + base.OnMouseWheel(e); + } + + internal static double RoundToOneIfClose(double val) + { + if (Math.Abs(val - 1.0) < 0.001) + return 1.0; + else + return val; + } + } + + sealed class IsNormalZoomConverter : IValueConverter + { + public static readonly IsNormalZoomConverter Instance = new IsNormalZoomConverter(); + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (parameter is bool && (bool)parameter) + return true; + return ((double)value) == 1.0; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/ILSpy/Controls/ZoomScrollViewer.xaml b/ILSpy/Controls/ZoomScrollViewer.xaml new file mode 100644 index 000000000..4c72e7eab --- /dev/null +++ b/ILSpy/Controls/ZoomScrollViewer.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy/Images/ZoomIn.svg b/ILSpy/Images/ZoomIn.svg new file mode 100644 index 000000000..e57d1d9fd --- /dev/null +++ b/ILSpy/Images/ZoomIn.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + diff --git a/ILSpy/Images/ZoomIn.xaml b/ILSpy/Images/ZoomIn.xaml new file mode 100644 index 000000000..693be3b62 --- /dev/null +++ b/ILSpy/Images/ZoomIn.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy/Images/ZoomOut.svg b/ILSpy/Images/ZoomOut.svg new file mode 100644 index 000000000..5a7e7bd20 --- /dev/null +++ b/ILSpy/Images/ZoomOut.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + diff --git a/ILSpy/Images/ZoomOut.xaml b/ILSpy/Images/ZoomOut.xaml new file mode 100644 index 000000000..48120672e --- /dev/null +++ b/ILSpy/Images/ZoomOut.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ILSpy/TextView/DecompilerTextView.xaml b/ILSpy/TextView/DecompilerTextView.xaml index 6539eee2d..66960f102 100644 --- a/ILSpy/TextView/DecompilerTextView.xaml +++ b/ILSpy/TextView/DecompilerTextView.xaml @@ -2,9 +2,11 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" - xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit" - xmlns:folding="clr-namespace:ICSharpCode.AvalonEdit.Folding;assembly=ICSharpCode.AvalonEdit" - xmlns:styles="urn:TomsToolbox.Wpf.Styles"> + xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" + xmlns:local="clr-namespace:ICSharpCode.ILSpy.TextView" + xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit" + xmlns:folding="clr-namespace:ICSharpCode.AvalonEdit.Folding;assembly=ICSharpCode.AvalonEdit" + xmlns:styles="urn:TomsToolbox.Wpf.Styles"> @@ -47,6 +49,33 @@ + + + + + + + + + + diff --git a/ILSpy/TextView/ZoomLevelToTextFormattingModeConverter.cs b/ILSpy/TextView/ZoomLevelToTextFormattingModeConverter.cs new file mode 100644 index 000000000..4f565e8be --- /dev/null +++ b/ILSpy/TextView/ZoomLevelToTextFormattingModeConverter.cs @@ -0,0 +1,38 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +using System; +using System.Windows.Data; +using System.Windows.Media; + +namespace ICSharpCode.ILSpy.TextView +{ + sealed class ZoomLevelToTextFormattingModeConverter : IValueConverter + { + public static readonly ZoomLevelToTextFormattingModeConverter Instance = new ZoomLevelToTextFormattingModeConverter(); + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return ((double)value) == 1.0 ? TextFormattingMode.Display : (object)TextFormattingMode.Ideal; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/ILSpy/Themes/generic.xaml b/ILSpy/Themes/generic.xaml index a6ba3bd07..de0378c65 100644 --- a/ILSpy/Themes/generic.xaml +++ b/ILSpy/Themes/generic.xaml @@ -4,6 +4,7 @@ xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"> +