Browse Source
Fix #2298: Allow to change the DecompilerTextView's font size through scrolling.
pull/2536/head
Fix #2298: Allow to change the DecompilerTextView's font size through scrolling.
pull/2536/head

11 changed files with 846 additions and 3 deletions
-
209ILSpy/Controls/CollapsiblePanel.cs
-
73ILSpy/Controls/ZoomButtons.cs
-
196ILSpy/Controls/ZoomScrollViewer.cs
-
128ILSpy/Controls/ZoomScrollViewer.xaml
-
65ILSpy/Images/ZoomIn.svg
-
27ILSpy/Images/ZoomIn.xaml
-
57ILSpy/Images/ZoomOut.svg
-
20ILSpy/Images/ZoomOut.xaml
-
35ILSpy/TextView/DecompilerTextView.xaml
-
38ILSpy/TextView/ZoomLevelToTextFormattingModeConverter.cs
-
1ILSpy/Themes/generic.xaml
@ -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 |
|||
{ |
|||
/// <summary>
|
|||
/// Allows animated collapsing of the content of this panel.
|
|||
/// </summary>
|
|||
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))); |
|||
|
|||
/// <summary>
|
|||
/// The duration in milliseconds of the animation.
|
|||
/// </summary>
|
|||
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)); |
|||
|
|||
/// <summary>
|
|||
/// Value between 0 and 1 specifying how far the animation currently is.
|
|||
/// </summary>
|
|||
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)); |
|||
|
|||
/// <summary>
|
|||
/// Value between 0 and 1 specifying how far the animation currently is.
|
|||
/// </summary>
|
|||
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)); |
|||
|
|||
/// <summary>
|
|||
/// Value between 0 and 1 specifying how far the animation currently is.
|
|||
/// </summary>
|
|||
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; |
|||
} |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,128 @@ |
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:Controls="clr-namespace:ICSharpCode.ILSpy.Controls"> |
|||
|
|||
<Style TargetType="{x:Type Controls:ZoomScrollViewer}"> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Controls:ZoomScrollViewer}"> |
|||
<Grid Background="{TemplateBinding Panel.Background}"> |
|||
<Grid.ColumnDefinitions> |
|||
<ColumnDefinition Width="Auto" /> |
|||
<ColumnDefinition Width="*" /> |
|||
<ColumnDefinition Width="Auto" /> |
|||
</Grid.ColumnDefinitions> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="*" /> |
|||
<RowDefinition Height="Auto" /> |
|||
</Grid.RowDefinitions> |
|||
<Controls:SelfCollapsingPanel Grid.Column="0" Grid.Row="1" CollapseOrientation="Horizontal" CanCollapse="{Binding Path=ComputedZoomButtonCollapsed, Mode=OneWay, RelativeSource={RelativeSource Mode=TemplatedParent}}"> |
|||
<Controls:ZoomButtons x:Name="zoomButtons" Value="{Binding Path=CurrentZoom, RelativeSource={RelativeSource Mode=TemplatedParent}}" Minimum="{TemplateBinding MinimumZoom}" Maximum="{TemplateBinding MaximumZoom}" /> |
|||
</Controls:SelfCollapsingPanel> |
|||
<Rectangle Grid.Column="2" Grid.Row="1" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> |
|||
<ScrollContentPresenter Name="PART_Presenter" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Margin="{TemplateBinding Control.Padding}" Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"> |
|||
<ScrollContentPresenter.LayoutTransform> |
|||
<ScaleTransform ScaleX="{Binding Path=CurrentZoom, RelativeSource={RelativeSource Mode=TemplatedParent}}" ScaleY="{Binding Path=CurrentZoom, RelativeSource={RelativeSource Mode=TemplatedParent}}"/> |
|||
</ScrollContentPresenter.LayoutTransform> |
|||
</ScrollContentPresenter> |
|||
<ScrollBar Name="PART_VerticalScrollBar" Grid.Column="2" Grid.Row="0" Minimum="0" Maximum="{TemplateBinding ScrollableHeight}" ViewportSize="{TemplateBinding ViewportHeight}" Value="{TemplateBinding VerticalOffset}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" /> |
|||
<ScrollBar Name="PART_HorizontalScrollBar" Orientation="Horizontal" Grid.Column="1" Grid.Row="1" Minimum="0" Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" Value="{TemplateBinding HorizontalOffset}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" /> |
|||
</Grid> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<!-- Template for CollapsiblePanel --> |
|||
<Style TargetType="{x:Type Controls:CollapsiblePanel}"> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="Controls:CollapsiblePanel"> |
|||
<ControlTemplate.Resources> |
|||
<Controls:CollapsiblePanelProgressToVisibilityConverter x:Key="visibilityConverter"/> |
|||
</ControlTemplate.Resources> |
|||
<Border |
|||
BorderThickness="{TemplateBinding Border.BorderThickness}" |
|||
BorderBrush="{TemplateBinding Border.BorderBrush}" |
|||
Background="{TemplateBinding Panel.Background}" |
|||
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" |
|||
Name="PART_Border" |
|||
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=AnimationProgress, Converter={StaticResource visibilityConverter}}" |
|||
> |
|||
<Border.LayoutTransform> |
|||
<ScaleTransform ScaleX="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=AnimationProgressX}" |
|||
ScaleY="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=AnimationProgressY}"/> |
|||
</Border.LayoutTransform> |
|||
<ContentPresenter |
|||
Margin="{TemplateBinding Control.Padding}" |
|||
Content="{TemplateBinding ContentControl.Content}" |
|||
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" |
|||
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" |
|||
HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" |
|||
VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" |
|||
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> |
|||
</Border> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style x:Key="ZoomButtonStyle" |
|||
TargetType="RepeatButton"> |
|||
<Setter Property="Delay" Value="0" /> |
|||
<Setter Property="Focusable" Value="False" /> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="RepeatButton"> |
|||
<ContentPresenter /> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsMouseOver" Value="True"> |
|||
<Setter Property="Opacity" Value="1" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type Controls:ZoomButtons}"> |
|||
<Setter Property="Minimum" Value="0.2"/> |
|||
<Setter Property="Maximum" Value="10"/> |
|||
<Setter Property="Value" Value="1"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Controls:ZoomButtons}"> |
|||
<Border Background="{TemplateBinding Background}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}"> |
|||
<StackPanel Orientation="Horizontal" |
|||
Background="#3000"> |
|||
<RepeatButton x:Name="uxPlus" |
|||
Width="16" Height="16" Padding="0" BorderThickness="0" |
|||
Style="{StaticResource ZoomButtonStyle}"> |
|||
<Image Source="{Controls:XamlResource Images/ZoomIn}" |
|||
Stretch="Uniform"/> |
|||
</RepeatButton> |
|||
<RepeatButton x:Name="uxMinus" |
|||
Width="16" Height="16" Padding="0" BorderThickness="0" |
|||
Style="{StaticResource ZoomButtonStyle}"> |
|||
<Image Source="{Controls:XamlResource Images/ZoomOut}" |
|||
Stretch="Uniform" /> |
|||
</RepeatButton> |
|||
<RepeatButton x:Name="uxReset" |
|||
Width="16" Height="16" Padding="0" BorderThickness="0" |
|||
Style="{StaticResource ZoomButtonStyle}"> |
|||
<Border Background="#5000"> |
|||
<TextBlock Foreground="White" |
|||
HorizontalAlignment="Center" |
|||
VerticalAlignment="Center">1</TextBlock> |
|||
</Border> |
|||
</RepeatButton> |
|||
</StackPanel> |
|||
</Border> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
</ResourceDictionary> |
@ -0,0 +1,65 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|||
<svg |
|||
viewBox="0 0 16 16" |
|||
version="1.1" |
|||
id="svg8" |
|||
sodipodi:docname="ZoomIn.svg" |
|||
inkscape:version="1.1 (c68e22c387, 2021-05-23)" |
|||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
|||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
xmlns:svg="http://www.w3.org/2000/svg"> |
|||
<defs |
|||
id="defs12" /> |
|||
<sodipodi:namedview |
|||
id="namedview10" |
|||
pagecolor="#ffffff" |
|||
bordercolor="#666666" |
|||
borderopacity="1.0" |
|||
inkscape:pageshadow="2" |
|||
inkscape:pageopacity="0.0" |
|||
inkscape:pagecheckerboard="0" |
|||
showgrid="false" |
|||
inkscape:zoom="52" |
|||
inkscape:cx="8" |
|||
inkscape:cy="7.7211538" |
|||
inkscape:window-width="1920" |
|||
inkscape:window-height="1017" |
|||
inkscape:window-x="2552" |
|||
inkscape:window-y="605" |
|||
inkscape:window-maximized="1" |
|||
inkscape:current-layer="svg8" /> |
|||
<style |
|||
id="style2">.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style> |
|||
<path |
|||
class="icon-canvas-transparent" |
|||
d="M16 16H0V0h16v16z" |
|||
id="canvas" /> |
|||
<path |
|||
class="icon-vs-out" |
|||
d="M16 5.833a5.84 5.84 0 0 1-5.833 5.833 5.688 5.688 0 0 1-2.913-.8L2.56 15.559a1.494 1.494 0 0 1-2.121.002 1.501 1.501 0 0 1 0-2.121l4.694-4.695a5.69 5.69 0 0 1-.8-2.911C4.333 2.617 6.95 0 10.167 0S16 2.617 16 5.833z" |
|||
id="outline" /> |
|||
<path |
|||
class="icon-vs-fg" |
|||
d="M14 5.833a3.837 3.837 0 0 1-3.833 3.833c-2.114 0-3.833-1.72-3.833-3.833S8.053 2 10.167 2A3.838 3.838 0 0 1 14 5.833z" |
|||
id="iconFg" /> |
|||
<path |
|||
class="icon-vs-bg" |
|||
d="M10.167 1a4.84 4.84 0 0 0-4.834 4.833c0 1.152.422 2.197 1.097 3.028l-5.284 5.285a.5.5 0 0 0 .708.708l5.284-5.285c.832.676 1.877 1.098 3.029 1.098 2.665 0 4.833-2.168 4.833-4.833S12.832 1 10.167 1zm0 8.667c-2.114 0-3.833-1.72-3.833-3.833S8.053 2 10.167 2C12.28 2 14 3.72 14 5.833s-1.72 3.834-3.833 3.834z" |
|||
id="iconBg" /> |
|||
<rect |
|||
style="fill:#424242;fill-opacity:1" |
|||
id="rect884" |
|||
width="4.6153846" |
|||
height="0.88461536" |
|||
x="7.8649998" |
|||
y="5.3461561" /> |
|||
<rect |
|||
style="fill:#424242;fill-opacity:1" |
|||
id="rect4051" |
|||
width="4.6153846" |
|||
height="0.88461536" |
|||
x="3.4807715" |
|||
y="-10.615" |
|||
transform="rotate(90)" /> |
|||
</svg> |
@ -0,0 +1,27 @@ |
|||
<DrawingGroup xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<DrawingGroup.Transform> |
|||
<TranslateTransform X="0" Y="10.615" /> |
|||
</DrawingGroup.Transform> |
|||
<DrawingGroup.Children> |
|||
<GeometryDrawing Geometry="F1 M16,16z M0,0z M16,16L0,16 0,0 16,0 16,16z"> |
|||
<GeometryDrawing.Brush> |
|||
<SolidColorBrush Color="#FFF6F6F6" Opacity="0" /> |
|||
</GeometryDrawing.Brush> |
|||
</GeometryDrawing> |
|||
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1 M16,16z M0,0z M16,5.833A5.84,5.84,0,0,1,10.167,11.666A5.688,5.688,0,0,1,7.254,10.866L2.56,15.559A1.494,1.494,0,0,1,0.439,15.561A1.501,1.501,0,0,1,0.439,13.44L5.133,8.745A5.69,5.69,0,0,1,4.333,5.834C4.333,2.617 6.95,0 10.167,0 13.384,0 16,2.617 16,5.833z" /> |
|||
<GeometryDrawing Brush="#FFF0EFF1" Geometry="F1 M16,16z M0,0z M14,5.833A3.837,3.837,0,0,1,10.167,9.666C8.053,9.666 6.334,7.946 6.334,5.833 6.334,3.72 8.053,2 10.167,2A3.838,3.838,0,0,1,14,5.833z" /> |
|||
<GeometryDrawing Brush="#FF424242" Geometry="F1 M16,16z M0,0z M10.167,1A4.84,4.84,0,0,0,5.333,5.833C5.333,6.985,5.755,8.03,6.43,8.861L1.146,14.146A0.5,0.5,0,0,0,1.854,14.854L7.138,9.569C7.97,10.245 9.015,10.667 10.167,10.667 12.832,10.667 15,8.499 15,5.834 15,3.169 12.832,1 10.167,1z M10.167,9.667C8.053,9.667 6.334,7.947 6.334,5.834 6.334,3.721 8.053,2 10.167,2 12.28,2 14,3.72 14,5.833 14,7.946 12.28,9.667 10.167,9.667z" /> |
|||
<GeometryDrawing Brush="#FF424242"> |
|||
<GeometryDrawing.Geometry> |
|||
<RectangleGeometry RadiusX="0" RadiusY="0" Rect="7.865,5.3462,4.6154,0.8846" /> |
|||
</GeometryDrawing.Geometry> |
|||
</GeometryDrawing> |
|||
<DrawingGroup Transform="6.12303176911189E-17,1,-1,6.12303176911189E-17,0,0"> |
|||
<GeometryDrawing Brush="#FF424242"> |
|||
<GeometryDrawing.Geometry> |
|||
<RectangleGeometry RadiusX="0" RadiusY="0" Rect="3.4808,-10.615,4.6154,0.8846" /> |
|||
</GeometryDrawing.Geometry> |
|||
</GeometryDrawing> |
|||
</DrawingGroup> |
|||
</DrawingGroup.Children> |
|||
</DrawingGroup> |
@ -0,0 +1,57 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|||
<svg |
|||
viewBox="0 0 16 16" |
|||
version="1.1" |
|||
id="svg8" |
|||
sodipodi:docname="ZoomOut.svg" |
|||
inkscape:version="1.1 (c68e22c387, 2021-05-23)" |
|||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
|||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
xmlns:svg="http://www.w3.org/2000/svg"> |
|||
<defs |
|||
id="defs12" /> |
|||
<sodipodi:namedview |
|||
id="namedview10" |
|||
pagecolor="#ffffff" |
|||
bordercolor="#666666" |
|||
borderopacity="1.0" |
|||
inkscape:pageshadow="2" |
|||
inkscape:pageopacity="0.0" |
|||
inkscape:pagecheckerboard="0" |
|||
showgrid="false" |
|||
inkscape:zoom="52" |
|||
inkscape:cx="8" |
|||
inkscape:cy="7.7211538" |
|||
inkscape:window-width="1920" |
|||
inkscape:window-height="1017" |
|||
inkscape:window-x="2552" |
|||
inkscape:window-y="605" |
|||
inkscape:window-maximized="1" |
|||
inkscape:current-layer="svg8" /> |
|||
<style |
|||
id="style2">.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style> |
|||
<path |
|||
class="icon-canvas-transparent" |
|||
d="M16 16H0V0h16v16z" |
|||
id="canvas" /> |
|||
<path |
|||
class="icon-vs-out" |
|||
d="M16 5.833a5.84 5.84 0 0 1-5.833 5.833 5.688 5.688 0 0 1-2.913-.8L2.56 15.559a1.494 1.494 0 0 1-2.121.002 1.501 1.501 0 0 1 0-2.121l4.694-4.695a5.69 5.69 0 0 1-.8-2.911C4.333 2.617 6.95 0 10.167 0S16 2.617 16 5.833z" |
|||
id="outline" /> |
|||
<path |
|||
class="icon-vs-fg" |
|||
d="M14 5.833a3.837 3.837 0 0 1-3.833 3.833c-2.114 0-3.833-1.72-3.833-3.833S8.053 2 10.167 2A3.838 3.838 0 0 1 14 5.833z" |
|||
id="iconFg" /> |
|||
<path |
|||
class="icon-vs-bg" |
|||
d="M10.167 1a4.84 4.84 0 0 0-4.834 4.833c0 1.152.422 2.197 1.097 3.028l-5.284 5.285a.5.5 0 0 0 .708.708l5.284-5.285c.832.676 1.877 1.098 3.029 1.098 2.665 0 4.833-2.168 4.833-4.833S12.832 1 10.167 1zm0 8.667c-2.114 0-3.833-1.72-3.833-3.833S8.053 2 10.167 2C12.28 2 14 3.72 14 5.833s-1.72 3.834-3.833 3.834z" |
|||
id="iconBg" /> |
|||
<rect |
|||
style="fill:#424242;fill-opacity:1" |
|||
id="rect884" |
|||
width="4.6153846" |
|||
height="0.88461536" |
|||
x="7.8649998" |
|||
y="5.3461561" /> |
|||
</svg> |
@ -0,0 +1,20 @@ |
|||
<DrawingGroup xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
|||
<DrawingGroup.Transform> |
|||
<TranslateTransform X="0" Y="10.615" /> |
|||
</DrawingGroup.Transform> |
|||
<DrawingGroup.Children> |
|||
<GeometryDrawing Geometry="F1 M16,16z M0,0z M16,16L0,16 0,0 16,0 16,16z"> |
|||
<GeometryDrawing.Brush> |
|||
<SolidColorBrush Color="#FFF6F6F6" Opacity="0" /> |
|||
</GeometryDrawing.Brush> |
|||
</GeometryDrawing> |
|||
<GeometryDrawing Brush="#FFF6F6F6" Geometry="F1 M16,16z M0,0z M16,5.833A5.84,5.84,0,0,1,10.167,11.666A5.688,5.688,0,0,1,7.254,10.866L2.56,15.559A1.494,1.494,0,0,1,0.439,15.561A1.501,1.501,0,0,1,0.439,13.44L5.133,8.745A5.69,5.69,0,0,1,4.333,5.834C4.333,2.617 6.95,0 10.167,0 13.384,0 16,2.617 16,5.833z" /> |
|||
<GeometryDrawing Brush="#FFF0EFF1" Geometry="F1 M16,16z M0,0z M14,5.833A3.837,3.837,0,0,1,10.167,9.666C8.053,9.666 6.334,7.946 6.334,5.833 6.334,3.72 8.053,2 10.167,2A3.838,3.838,0,0,1,14,5.833z" /> |
|||
<GeometryDrawing Brush="#FF424242" Geometry="F1 M16,16z M0,0z M10.167,1A4.84,4.84,0,0,0,5.333,5.833C5.333,6.985,5.755,8.03,6.43,8.861L1.146,14.146A0.5,0.5,0,0,0,1.854,14.854L7.138,9.569C7.97,10.245 9.015,10.667 10.167,10.667 12.832,10.667 15,8.499 15,5.834 15,3.169 12.832,1 10.167,1z M10.167,9.667C8.053,9.667 6.334,7.947 6.334,5.834 6.334,3.721 8.053,2 10.167,2 12.28,2 14,3.72 14,5.833 14,7.946 12.28,9.667 10.167,9.667z" /> |
|||
<GeometryDrawing Brush="#FF424242"> |
|||
<GeometryDrawing.Geometry> |
|||
<RectangleGeometry RadiusX="0" RadiusY="0" Rect="7.865,5.3462,4.6154,0.8846" /> |
|||
</GeometryDrawing.Geometry> |
|||
</GeometryDrawing> |
|||
</DrawingGroup.Children> |
|||
</DrawingGroup> |
@ -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(); |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue