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 @@ + + + + +