<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6809728426512042634</id><updated>2011-04-21T20:31:53.001-07:00</updated><title type='text'>Developer Voodoo</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devoodoo.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6809728426512042634/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://devoodoo.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Josh</name><uri>http://www.blogger.com/profile/04928254582051909079</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6809728426512042634.post-4641674440818931186</id><published>2009-05-28T17:15:00.000-07:00</published><updated>2009-05-28T17:35:12.316-07:00</updated><title type='text'>WPF FishEyePanel Port to Silverlight 2</title><content type='html'>This is a quick port of a WPF FishEye Panel control to Silverlight 2.&lt;br /&gt;&lt;br /&gt;-Josh&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:78%;"&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows;&lt;br /&gt;using System.Windows.Controls;&lt;br /&gt;using System.Windows.Data;&lt;br /&gt;using System.Windows.Documents;&lt;br /&gt;using System.Windows.Input;&lt;br /&gt;using System.Windows.Media;&lt;br /&gt;using System.Windows.Media.Imaging;&lt;br /&gt;using System.Windows.Shapes;&lt;br /&gt;using System.Windows.Media.Animation;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;namespace FishEye&lt;br /&gt;{&lt;br /&gt;/// &lt;summary&gt;&lt;br /&gt;/// FishEyePanel&lt;br /&gt;/// &lt;/summary&gt;&lt;br /&gt;public class FishEyePanel : Panel&lt;br /&gt;{&lt;br /&gt;enum AnimateState { None, Up, Down };&lt;br /&gt;public FishEyePanel()&lt;br /&gt;{&lt;br /&gt;this.Background = new SolidColorBrush( Color.FromArgb( 0, 0, 0, 0 ) );&lt;br /&gt;this.MouseMove += new MouseEventHandler(FishEyePanel_MouseMove);&lt;br /&gt;this.MouseEnter += new MouseEventHandler(FishEyePanel_MouseEnter);&lt;br /&gt;this.MouseLeave += new MouseEventHandler(FishEyePanel_MouseLeave);&lt;br /&gt;this.LostMouseCapture += new MouseEventHandler( FishEyePanel_LostMouseCapture );&lt;br /&gt;}&lt;br /&gt;public double Magnification&lt;br /&gt;{&lt;br /&gt;get { return (double)GetValue(MagnificationProperty); }&lt;br /&gt;set { SetValue(MagnificationProperty, value); }&lt;br /&gt;}&lt;br /&gt;// Using a DependencyProperty as the backing store for Magnification. This enables animation, styling, binding, etc...&lt;br /&gt;public static readonly DependencyProperty MagnificationProperty =&lt;br /&gt;DependencyProperty.Register("Magnification", typeof(double), typeof(FishEyePanel), new PropertyMetadata(2d));&lt;br /&gt;public int AnimationMilliseconds&lt;br /&gt;{&lt;br /&gt;get { return (int)GetValue(AnimationMillisecondsProperty); }&lt;br /&gt;set { SetValue(AnimationMillisecondsProperty, value); }&lt;br /&gt;}&lt;br /&gt;// Using a DependencyProperty as the backing store for AnimationMilliseconds. This enables animation, styling, binding, etc...&lt;br /&gt;public static readonly DependencyProperty AnimationMillisecondsProperty =&lt;br /&gt;DependencyProperty.Register("AnimationMilliseconds", typeof(int), typeof(FishEyePanel), new PropertyMetadata(125));&lt;br /&gt;// If set true we scale different sized children to a constant width&lt;br /&gt;public bool ScaleToFit&lt;br /&gt;{&lt;br /&gt;get { return (bool)GetValue(ScaleToFitProperty); }&lt;br /&gt;set { SetValue(ScaleToFitProperty, value); }&lt;br /&gt;}&lt;br /&gt;// Using a DependencyProperty as the backing store for ScaleToFit. This enables animation, styling, binding, etc...&lt;br /&gt;public static readonly DependencyProperty ScaleToFitProperty =&lt;br /&gt;DependencyProperty.Register("ScaleToFit", typeof(bool), typeof(FishEyePanel), new PropertyMetadata(true));&lt;br /&gt;private bool animating = false;&lt;br /&gt;private Size ourSize;&lt;br /&gt;private double totalChildWidth = 0;&lt;br /&gt;private bool wasMouseOver = false;&lt;br /&gt;Point MousePosition = new Point();&lt;br /&gt;void FishEyePanel_MouseMove(object sender, MouseEventArgs e)&lt;br /&gt;{&lt;br /&gt;this.IsMouseOver = true;&lt;br /&gt;//Debug.WriteLine( "move" );&lt;br /&gt;MousePosition = e.GetPosition( this );&lt;br /&gt;if (!animating)&lt;br /&gt;this.InvalidateArrange();&lt;br /&gt;}&lt;br /&gt;void FishEyePanel_MouseEnter(object sender, MouseEventArgs e)&lt;br /&gt;{&lt;br /&gt;this.IsMouseOver = true;&lt;br /&gt;this.InvalidateArrange();&lt;br /&gt;}&lt;br /&gt;void FishEyePanel_MouseLeave(object sender, MouseEventArgs e)&lt;br /&gt;{&lt;br /&gt;this.IsMouseOver = false;&lt;br /&gt;this.InvalidateArrange();&lt;br /&gt;}&lt;br /&gt;void FishEyePanel_LostMouseCapture( object sender, MouseEventArgs e )&lt;br /&gt;{&lt;br /&gt;this.IsMouseOver = false;&lt;br /&gt;this.InvalidateArrange();&lt;br /&gt;}&lt;br /&gt;bool _isMouseOver = false;&lt;br /&gt;public bool IsMouseOver&lt;br /&gt;{&lt;br /&gt;get&lt;br /&gt;{&lt;br /&gt;return _isMouseOver;&lt;br /&gt;}&lt;br /&gt;set&lt;br /&gt;{&lt;br /&gt;_isMouseOver = value;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;protected override Size MeasureOverride(Size availableSize)&lt;br /&gt;{&lt;br /&gt;Size idealSize = new Size(0, 0);&lt;br /&gt;// Allow children as much room as they want - then scale them&lt;br /&gt;Size size = new Size(Double.PositiveInfinity, Double.PositiveInfinity);&lt;br /&gt;foreach (UIElement child in Children)&lt;br /&gt;{&lt;br /&gt;child.Measure(size);&lt;br /&gt;idealSize.Width += child.DesiredSize.Width;&lt;br /&gt;idealSize.Height = Math.Max(idealSize.Height, child.DesiredSize.Height);&lt;br /&gt;}&lt;br /&gt;// EID calls us with infinity, but framework doesn't like us to return infinity&lt;br /&gt;if (double.IsInfinity(availableSize.Height)  double.IsInfinity(availableSize.Width))&lt;br /&gt;return idealSize;&lt;br /&gt;else&lt;br /&gt;return availableSize;&lt;br /&gt;}&lt;br /&gt;protected override Size ArrangeOverride(Size finalSize)&lt;br /&gt;{&lt;br /&gt;if (this.Children == null  this.Children.Count == 0)&lt;br /&gt;return finalSize;&lt;br /&gt;ourSize = finalSize;&lt;br /&gt;totalChildWidth = 0;&lt;br /&gt;foreach (UIElement child in this.Children)&lt;br /&gt;{&lt;br /&gt;// If this is the first time we've seen this child, add our transforms&lt;br /&gt;if (child.RenderTransform as TransformGroup == null)&lt;br /&gt;{&lt;br /&gt;child.RenderTransformOrigin = new Point(0, 0.5);&lt;br /&gt;TransformGroup group = new TransformGroup();&lt;br /&gt;child.RenderTransform = group;&lt;br /&gt;group.Children.Add(new ScaleTransform());&lt;br /&gt;group.Children.Add(new TranslateTransform());&lt;br /&gt;}&lt;br /&gt;child.Arrange(new Rect(0, 0, child.DesiredSize.Width, child.DesiredSize.Height));&lt;br /&gt;totalChildWidth += child.DesiredSize.Width;&lt;br /&gt;}&lt;br /&gt;AnimateAll();&lt;br /&gt;return finalSize;&lt;br /&gt;}&lt;br /&gt;void AnimateAll()&lt;br /&gt;{&lt;br /&gt;if (this.Children == null  this.Children.Count == 0)&lt;br /&gt;return;&lt;br /&gt;animating = true;&lt;br /&gt;double childWidth = ourSize.Width / this.Children.Count;&lt;br /&gt;// If the children can fit without scaling down, just leave them at they're original scale.&lt;br /&gt;// Otherwise, calculate the scale factor.&lt;br /&gt;double overallScaleFactor = 1;&lt;br /&gt;if( ourSize.Width &lt; totalChildWidth )&lt;br /&gt;{&lt;br /&gt;overallScaleFactor = ourSize.Width / totalChildWidth;&lt;br /&gt;}&lt;br /&gt;UIElement prevChild = null;&lt;br /&gt;UIElement theChild = null;&lt;br /&gt;UIElement nextChild = null;&lt;br /&gt;double widthSoFar = 0;&lt;br /&gt;double theChildX = 0;&lt;br /&gt;double ratio = 0;&lt;br /&gt;if (this.IsMouseOver)&lt;br /&gt;{&lt;br /&gt;double x = MousePosition.X;&lt;br /&gt;foreach (UIElement child in this.Children)&lt;br /&gt;{&lt;br /&gt;if( theChild == null )&lt;br /&gt;{&lt;br /&gt;theChildX = widthSoFar;&lt;br /&gt;}&lt;br /&gt;widthSoFar += (ScaleToFit ? childWidth : child.DesiredSize.Width * overallScaleFactor);&lt;br /&gt;if( x &lt; widthSoFar &amp;amp;&amp;amp; theChild == null )&lt;br /&gt;{&lt;br /&gt;theChild = child;&lt;br /&gt;}&lt;br /&gt;if( theChild == null )&lt;br /&gt;{&lt;br /&gt;prevChild = child;&lt;br /&gt;}&lt;br /&gt;if (nextChild == null &amp;amp;&amp;amp; theChild != child &amp;amp;&amp;amp; theChild != null)&lt;br /&gt;{&lt;br /&gt;nextChild = child;&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;if (theChild != null)&lt;br /&gt;ratio = (x - theChildX) / (ScaleToFit ? childWidth : (theChild.DesiredSize.Width * overallScaleFactor)); // Range 0-1 of where the mouse is inside the child&lt;br /&gt;}&lt;br /&gt;// These next few lines took two of us hours to write!&lt;br /&gt;double mag = Magnification;&lt;br /&gt;double extra = 0;&lt;br /&gt;if (theChild != null)&lt;br /&gt;extra += (mag - 1);&lt;br /&gt;if (prevChild == null)&lt;br /&gt;extra += (ratio * (mag - 1));&lt;br /&gt;else if (nextChild == null)&lt;br /&gt;extra += ((mag - 1) * (1 - ratio));&lt;br /&gt;else&lt;br /&gt;extra += (mag - 1);&lt;br /&gt;double prevScale = this.Children.Count * (1 + ((mag - 1) * (1 - ratio))) / (this.Children.Count + extra);&lt;br /&gt;double theScale = (mag * this.Children.Count) / (this.Children.Count + extra);&lt;br /&gt;double nextScale = this.Children.Count * (1 + ((mag - 1) * ratio)) / (this.Children.Count + extra);&lt;br /&gt;double otherScale = this.Children.Count / (this.Children.Count + extra); // Applied to all non-interesting children&lt;br /&gt;// Adjust for different sized children - we overmagnify large children, so shrink the others&lt;br /&gt;if (!ScaleToFit &amp;amp;&amp;amp; this.IsMouseOver)&lt;br /&gt;{&lt;br /&gt;double bigWidth = 0;&lt;br /&gt;double actualWidth = 0;&lt;br /&gt;if (prevChild != null)&lt;br /&gt;{&lt;br /&gt;bigWidth += prevScale * prevChild.DesiredSize.Width * overallScaleFactor;&lt;br /&gt;actualWidth += prevChild.DesiredSize.Width;&lt;br /&gt;}&lt;br /&gt;if (theChild != null)&lt;br /&gt;{&lt;br /&gt;bigWidth += theScale * theChild.DesiredSize.Width * overallScaleFactor;&lt;br /&gt;actualWidth += theChild.DesiredSize.Width;&lt;br /&gt;}&lt;br /&gt;if (nextChild != null)&lt;br /&gt;{&lt;br /&gt;bigWidth += nextScale * nextChild.DesiredSize.Width * overallScaleFactor;&lt;br /&gt;actualWidth += nextChild.DesiredSize.Width;&lt;br /&gt;}&lt;br /&gt;double w = (totalChildWidth - actualWidth) * overallScaleFactor * otherScale;&lt;br /&gt;otherScale *= (ourSize.Width - bigWidth) / w;&lt;br /&gt;}&lt;br /&gt;widthSoFar = 0;&lt;br /&gt;double duration = 0;&lt;br /&gt;if (wasMouseOver != this.IsMouseOver)&lt;br /&gt;duration = AnimationMilliseconds;&lt;br /&gt;foreach (UIElement child in this.Children)&lt;br /&gt;{&lt;br /&gt;double scale = otherScale;&lt;br /&gt;if (child == prevChild)&lt;br /&gt;{&lt;br /&gt;scale = prevScale;&lt;br /&gt;}&lt;br /&gt;else if (child == theChild)&lt;br /&gt;{&lt;br /&gt;scale = theScale;&lt;br /&gt;}&lt;br /&gt;else if (child == nextChild)&lt;br /&gt;{&lt;br /&gt;scale = nextScale;&lt;br /&gt;}&lt;br /&gt;if (ScaleToFit)&lt;br /&gt;{&lt;br /&gt;// Now scale each individual child so it is a standard width&lt;br /&gt;scale *= childWidth / child.DesiredSize.Width;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;// Apply overall scale so all children fit our width&lt;br /&gt;scale *= overallScaleFactor;&lt;br /&gt;}&lt;br /&gt;AnimateTo(child, 0, widthSoFar, (ourSize.Height - child.DesiredSize.Height) / 2, scale, duration);&lt;br /&gt;widthSoFar += child.DesiredSize.Width * scale;&lt;br /&gt;}&lt;br /&gt;wasMouseOver = this.IsMouseOver;&lt;br /&gt;}&lt;br /&gt;private void AnimateTo(UIElement child, double r, double x, double y, double s, double duration)&lt;br /&gt;{&lt;br /&gt;TransformGroup group = (TransformGroup)child.RenderTransform;&lt;br /&gt;ScaleTransform scale = (ScaleTransform)group.Children[0];&lt;br /&gt;TranslateTransform trans = (TranslateTransform)group.Children[1];&lt;br /&gt;if (duration == 0)&lt;br /&gt;{&lt;br /&gt;trans.X = x;&lt;br /&gt;trans.Y = y;&lt;br /&gt;scale.ScaleX = s;&lt;br /&gt;scale.ScaleY = s;&lt;br /&gt;animation_Completed(null, null);&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;trans.BeginAnimation(TranslateTransform.XProperty, MakeAnimation(x, duration, animation_Completed));&lt;br /&gt;trans.BeginAnimation(TranslateTransform.YProperty, MakeAnimation(y, duration));&lt;br /&gt;scale.BeginAnimation(ScaleTransform.ScaleXProperty, MakeAnimation(s, duration));&lt;br /&gt;scale.BeginAnimation(ScaleTransform.ScaleYProperty, MakeAnimation(s, duration));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;private DoubleAnimation MakeAnimation(double to, double duration)&lt;br /&gt;{&lt;br /&gt;return MakeAnimation(to, duration, null);&lt;br /&gt;}&lt;br /&gt;private DoubleAnimation MakeAnimation(double to, double duration, EventHandler endEvent)&lt;br /&gt;{&lt;br /&gt;DoubleAnimation anim = new DoubleAnimation();&lt;br /&gt;anim.To = to;&lt;br /&gt;anim.Duration = TimeSpan.FromMilliseconds(duration);&lt;br /&gt;if (endEvent != null)&lt;br /&gt;anim.Completed += endEvent;&lt;br /&gt;return anim;&lt;br /&gt;}&lt;br /&gt;void animation_Completed(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;animating = false;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;public static class Extention&lt;br /&gt;{&lt;br /&gt;public static void BeginAnimation( this Transform obj, DependencyProperty property, DoubleAnimation animation )&lt;br /&gt;{&lt;br /&gt;var storyboard = new Storyboard();&lt;br /&gt;storyboard.Children.Add( animation );&lt;br /&gt;Storyboard.SetTarget( storyboard, obj );&lt;br /&gt;Storyboard.SetTargetProperty( storyboard, new PropertyPath( property ) );&lt;br /&gt;storyboard.Begin();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6809728426512042634-4641674440818931186?l=devoodoo.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devoodoo.blogspot.com/feeds/4641674440818931186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devoodoo.blogspot.com/2009/05/wpf-fisheyepanel-port-to-silverlight-2.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6809728426512042634/posts/default/4641674440818931186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6809728426512042634/posts/default/4641674440818931186'/><link rel='alternate' type='text/html' href='http://devoodoo.blogspot.com/2009/05/wpf-fisheyepanel-port-to-silverlight-2.html' title='WPF FishEyePanel Port to Silverlight 2'/><author><name>Josh</name><uri>http://www.blogger.com/profile/04928254582051909079</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
