From 4ce76d6d8ad1fcb8481c8ac13b8dd59a2484ae03 Mon Sep 17 00:00:00 2001 From: brianlagunas_cp Date: Tue, 9 Nov 2010 00:57:46 +0000 Subject: [PATCH] added new Magnifier control. It magnifies anything that it is attached to. You can attach it to any thing that is of type UIElement. To attach it use the MagnifierManager as follows. The ZoomFactor controls how far to zoom in. ZoomFactor ranges from 0.0 up to 1.0. The lower the number the deeper the zoom. 0 being the most zoomed in and 1 being normal size. It is a double so play around with values such as .009 or .2386 to get the desired effect. --- ...rderThicknessToStrokeThicknessConverter.cs | 24 +++ .../Magnifier/Converters/RadiusConverter.cs | 22 +++ .../Magnifier/Magnifier.cs | 166 ++++++++++++++++++ .../Magnifier/MagnifierAdorner.cs | 96 ++++++++++ .../Magnifier/MagnifierManager.cs | 98 +++++++++++ .../WPFToolkit.Extended/Themes/Generic.xaml | 36 +++- .../WPFToolkit.Extended.csproj | 5 + 7 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/BorderThicknessToStrokeThicknessConverter.cs create mode 100644 ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/RadiusConverter.cs create mode 100644 ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Magnifier.cs create mode 100644 ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierAdorner.cs create mode 100644 ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierManager.cs diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/BorderThicknessToStrokeThicknessConverter.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/BorderThicknessToStrokeThicknessConverter.cs new file mode 100644 index 00000000..1f672cda --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/BorderThicknessToStrokeThicknessConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Windows.Data; +using System.Windows; + +namespace Microsoft.Windows.Controls.Mag.Converters +{ + internal class BorderThicknessToStrokeThicknessConverter : IValueConverter + { + #region IValueConverter Members + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + Thickness thickness = (Thickness)value; + return (thickness.Bottom + thickness.Left + thickness.Right + thickness.Top) / 4; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/RadiusConverter.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/RadiusConverter.cs new file mode 100644 index 00000000..532a3552 --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Converters/RadiusConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Windows.Data; + +namespace Microsoft.Windows.Controls.Mag.Converters +{ + internal class RadiusConverter : IValueConverter + { + #region IValueConverter Members + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return (double)value * 2; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Magnifier.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Magnifier.cs new file mode 100644 index 00000000..2ea13e1b --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/Magnifier.cs @@ -0,0 +1,166 @@ +using System; +using System.Windows; +using System.Windows.Controls; + +namespace Microsoft.Windows.Controls +{ + public class Magnifier : Control + { + #region Properties + + #region DefaultSize + + internal Size DefaultSize + { + get + { + return new Size(2 * Radius, 2 * Radius); + } + } + + #endregion //DefaultSize + + #region MagnifierWidth + + public static readonly DependencyProperty MagnifierWidthProperty = DependencyProperty.Register("MagnifierWidth", typeof(double), typeof(Magnifier), new UIPropertyMetadata(50.0)); + internal double MagnifierWidth + { + get { return (double)GetValue(MagnifierWidthProperty); } + set { SetValue(MagnifierWidthProperty, value); } + } + + #endregion //MagnifierWidth + + #region MagnifierHeight + + public static readonly DependencyProperty MagnifierHeightProperty = DependencyProperty.Register("MagnifierHeight", typeof(double), typeof(Magnifier), new UIPropertyMetadata(50.0)); + internal double MagnifierHeight + { + get { return (double)GetValue(MagnifierHeightProperty); } + set { SetValue(MagnifierHeightProperty, value); } + } + + #endregion //MagnifierWidth + + #region Radius + + public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(Magnifier), new FrameworkPropertyMetadata(50.0, new PropertyChangedCallback(OnRadiusPropertyChanged))); + public double Radius + { + get { return (double)GetValue(RadiusProperty); } + set { SetValue(RadiusProperty, value); } + } + + private static void OnRadiusPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + Magnifier m = (Magnifier)d; + m.OnRadiusChanged(e); + } + + protected virtual void OnRadiusChanged(DependencyPropertyChangedEventArgs e) + { + ResolveViewBox(); + } + + #endregion //Radius + + #region Target + + public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(UIElement), typeof(Magnifier)); + public UIElement Target + { + get { return (UIElement)GetValue(TargetProperty); } + set { SetValue(TargetProperty, value); } + } + + #endregion //Target + + #region ViewBox + + public static readonly DependencyProperty ViewBoxProperty = DependencyProperty.Register("ViewBox", typeof(Rect), typeof(Magnifier), new FrameworkPropertyMetadata(default(Rect))); + internal Rect ViewBox + { + get { return (Rect)GetValue(ViewBoxProperty); } + set { SetValue(ViewBoxProperty, value); } + } + + #endregion //ViewBox + + #region ZoomFactor + + public static readonly DependencyProperty ZoomFactorProperty = DependencyProperty.Register("ZoomFactor", typeof(double), typeof(Magnifier), new FrameworkPropertyMetadata(0.5, OnZoomFactorPropertyChanged, OnCoerceZoomFactorProperty)); + public double ZoomFactor + { + get { return (double)GetValue(ZoomFactorProperty); } + set { SetValue(ZoomFactorProperty, value); } + } + + private static void OnZoomFactorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + Magnifier m = (Magnifier)d; + m.OnZoomFactorChanged(e); + } + + protected virtual void OnZoomFactorChanged(DependencyPropertyChangedEventArgs e) + { + ResolveViewBox(); + } + + private static object OnCoerceZoomFactorProperty(DependencyObject d, object value) + { + Magnifier m = (Magnifier)d; + return m.OnCoerceZoomFactor(value); + } + + protected virtual object OnCoerceZoomFactor(object value) + { + double zoomFactor = (double)value; + + if (zoomFactor > 1) + zoomFactor = 1; + else if (zoomFactor < 0) + zoomFactor = 0; + + return zoomFactor; + } + + #endregion //ZoomFactor + + #endregion //Properties + + #region Constructors + + /// + /// Initializes static members of the class. + /// + static Magnifier() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Magnifier), new FrameworkPropertyMetadata(typeof(Magnifier))); + } + + public Magnifier() + { + ResolveViewBox(); + } + + #endregion + + #region Methods + + private void ResolveViewBox() + { + double correction = (BorderThickness.Bottom + BorderThickness.Left + BorderThickness.Right + BorderThickness.Top == 0) ? 1 : 0; + + double width = DefaultSize.Width * ZoomFactor; + double height = DefaultSize.Height * ZoomFactor; + + MagnifierWidth = DefaultSize.Width - correction; + MagnifierHeight = DefaultSize.Height - correction; + + ViewBox = new Rect(ViewBox.Location, new Size(width, height)); + } + + #endregion //Methods + + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierAdorner.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierAdorner.cs new file mode 100644 index 00000000..2b31e80f --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierAdorner.cs @@ -0,0 +1,96 @@ +using System; +using System.Windows.Documents; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media; + +namespace Microsoft.Windows.Controls +{ + public class MagnifierAdorner : Adorner + { + #region Members + + private Magnifier _magnifier; + private Point _currentMousePosition; + + #endregion + + #region Constructors + + public MagnifierAdorner(UIElement element, Magnifier magnifier) + : base(element) + { + InputManager.Current.PostProcessInput += Current_PostProcessInput; + _magnifier = magnifier; + UpdateViewBox(); + AddVisualChild(_magnifier); + } + + #endregion + + #region Private/Internal methods + + private void Current_PostProcessInput(object sender, ProcessInputEventArgs e) + { + Point pt = Mouse.GetPosition(this); + + if (_currentMousePosition == pt) + return; + + _currentMousePosition = pt; + UpdateViewBox(); + InvalidateArrange(); + } + + internal void UpdateViewBox() + { + var viewBoxLocation = CalculateViewBoxLocation(); + _magnifier.ViewBox = new Rect(viewBoxLocation, _magnifier.ViewBox.Size); + } + + private Point CalculateViewBoxLocation() + { + double offsetX = 0, offsetY = 0; + + Point adorner = Mouse.GetPosition(this); + Point element = Mouse.GetPosition(AdornedElement); + + offsetX = element.X - adorner.X; + offsetY = element.Y - adorner.Y; + + double left = _currentMousePosition.X - ((_magnifier.ViewBox.Width / 2) + offsetX); + double top = _currentMousePosition.Y - ((_magnifier.ViewBox.Height / 2) + offsetY); + return new Point(left, top); + } + + #endregion + + #region Overrides + + protected override Visual GetVisualChild(int index) + { + return _magnifier; + } + + protected override int VisualChildrenCount + { + get { return 1; } + } + + protected override Size MeasureOverride(Size constraint) + { + _magnifier.Measure(constraint); + return base.MeasureOverride(constraint); + } + + protected override Size ArrangeOverride(Size finalSize) + { + double x = _currentMousePosition.X - (_magnifier.DefaultSize.Width / 2); + double y = _currentMousePosition.Y - (_magnifier.DefaultSize.Height / 2); + _magnifier.Arrange(new Rect(x, y, _magnifier.DefaultSize.Width, _magnifier.DefaultSize.Height)); + return base.ArrangeOverride(finalSize); + } + + #endregion + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierManager.cs b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierManager.cs new file mode 100644 index 00000000..eaaa2c7e --- /dev/null +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Magnifier/MagnifierManager.cs @@ -0,0 +1,98 @@ +using System; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Input; + +namespace Microsoft.Windows.Controls +{ + public class MagnifierManager : DependencyObject + { + #region Members + + private MagnifierAdorner _adorner; + private UIElement _element; + + #endregion //Members + + #region Properties + + public static readonly DependencyProperty CurrentProperty = DependencyProperty.RegisterAttached("Magnifier", typeof(Magnifier), typeof(UIElement), new FrameworkPropertyMetadata(null, OnMagnifierChanged)); + public static void SetMagnifier(UIElement element, Magnifier value) + { + element.SetValue(CurrentProperty, value); + } + public static Magnifier GetMagnifier(UIElement element) + { + return (Magnifier)element.GetValue(CurrentProperty); + } + + private static void OnMagnifierChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + UIElement target = d as UIElement; + + if (target == null) + throw new ArgumentException("Magnifier can only be attached to a UIElement."); + + MagnifierManager manager = new MagnifierManager(); + manager.AttachToMagnifier(target, e.NewValue as Magnifier); + } + + #endregion //Properties + + #region Event Handlers + + void Element_MouseLeave(object sender, MouseEventArgs e) + { + HideAdorner(); + } + + void Element_MouseEnter(object sender, MouseEventArgs e) + { + ShowAdorner(); + } + + #endregion //Event Handlers + + #region Methods + + private void AttachToMagnifier(UIElement element, Magnifier magnifier) + { + _element = element; + _element.MouseEnter += Element_MouseEnter; + _element.MouseLeave += Element_MouseLeave; + + magnifier.Target = _element; + + _adorner = new MagnifierAdorner(_element, magnifier); + } + + void ShowAdorner() + { + VerifyAdornerLayer(); + _adorner.Visibility = Visibility.Visible; + } + + bool VerifyAdornerLayer() + { + if (_adorner.Parent != null) + return true; + + AdornerLayer layer = AdornerLayer.GetAdornerLayer(_element); + if (layer == null) + return false; + + layer.Add(_adorner); + return true; + } + + void HideAdorner() + { + if (_adorner.Visibility == Visibility.Visible) + { + _adorner.Visibility = Visibility.Collapsed; + } + } + + #endregion //Methods + } +} diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml index b2b3f717..5694227a 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/Themes/Generic.xaml @@ -1,7 +1,8 @@ + xmlns:local="clr-namespace:Microsoft.Windows.Controls" + xmlns:magConverters="clr-namespace:Microsoft.Windows.Controls.Mag.Converters"> @@ -1106,4 +1107,37 @@ + + + + + + + + + diff --git a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj index 738ae7e2..ed35e03f 100644 --- a/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj +++ b/ExtendedWPFToolkitSolution/Src/WPFToolkit.Extended/WPFToolkit.Extended.csproj @@ -76,6 +76,11 @@ + + + + +