Skip to content

Commit d915645

Browse files
committed
Merge remote-tracking branch 'ButchersBoy/master'
Conflicts: MaterialDesignThemes.Wpf/Ripple.cs MaterialDesignThemes.Wpf/Themes/Generic.xaml
1 parent 0ff0813 commit d915645

File tree

2 files changed

+114
-210
lines changed

2 files changed

+114
-210
lines changed

MaterialDesignThemes.Wpf/Ripple.cs

Lines changed: 61 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
namespace MaterialDesignThemes.Wpf
2020
{
21-
[TemplatePart(Name = PartBubbleEllipse, Type = typeof(Ellipse))]
21+
[TemplateVisualState(GroupName = "CommonStates", Name = TemplateStateNormal)]
22+
[TemplateVisualState(GroupName = "CommonStates", Name = TemplateStateMousePressed)]
2223
public class Ripple : ContentControl
2324
{
24-
public const string PartBubbleEllipse = "PART_BubbleEllipse";
25-
26-
private BubbleStoryboardController _bubbleStoryboardController;
25+
public const string TemplateStateNormal = "Normal";
26+
public const string TemplateStateMousePressed = "MousePressed";
2727

2828
static Ripple()
2929
{
@@ -32,250 +32,111 @@ static Ripple()
3232

3333
public Ripple()
3434
{
35-
MouseMove += OnMouseMove;
36-
}
37-
38-
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
39-
{
40-
var position = e.GetPosition(this);
41-
MouseLeftButtonDownX = position.X;
42-
MouseLeftButtonDownY = position.Y;
43-
44-
this.ReleaseMouseCapture();
45-
46-
base.OnPreviewMouseLeftButtonDown(e);
47-
}
48-
49-
private void OnMouseMove(object sender, MouseEventArgs mouseEventArgs)
50-
{
51-
var position = mouseEventArgs.GetPosition(this);
52-
MouseX = position.X;
53-
MouseY = position.Y;
54-
}
55-
56-
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
57-
"IsActive", typeof(bool), typeof(Ripple), new FrameworkPropertyMetadata(false, IsActivePropertyChangedCallback));
58-
59-
public bool IsActive
60-
{
61-
get { return (bool)GetValue(IsActiveProperty); }
62-
set { SetValue(IsActiveProperty, value); }
35+
SizeChanged += OnSizeChanged;
6336
}
6437

65-
public override void OnApplyTemplate()
38+
private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
6639
{
67-
base.OnApplyTemplate();
68-
69-
_bubbleStoryboardController = new BubbleStoryboardController(this);
40+
double radius = Math.Sqrt(Math.Pow(sizeChangedEventArgs.NewSize.Width, 2) + Math.Pow(sizeChangedEventArgs.NewSize.Height, 2));
41+
RippleSize = 2 * radius * RippleSizeMultiplier;
7042
}
7143

72-
private void StartBubbleAnimation()
73-
{
74-
_bubbleStoryboardController.Add();
75-
}
44+
public static readonly DependencyProperty FeedbackProperty = DependencyProperty.Register(
45+
"Feedback", typeof(Brush), typeof(Ripple), new PropertyMetadata(default(Brush)));
7646

77-
private void StopBubbleAnimation()
47+
public Brush Feedback
7848
{
79-
_bubbleStoryboardController.Remove();
49+
get { return (Brush)GetValue(FeedbackProperty); }
50+
set { SetValue(FeedbackProperty, value); }
8051
}
8152

82-
private static void IsActivePropertyChangedCallback(
83-
DependencyObject dependencyObject,
84-
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
53+
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
8554
{
86-
var box = dependencyObject as Ripple;
87-
if (box == null) return;
55+
var point = e.GetPosition(this);
8856

89-
bool isActive = (bool)dependencyPropertyChangedEventArgs.NewValue;
57+
RippleX = point.X - RippleSize / 2;
58+
RippleY = point.Y - RippleSize / 2;
9059

91-
if (isActive)
92-
{
93-
box.StartBubbleAnimation();
94-
}
95-
else
96-
{
97-
box.StopBubbleAnimation();
98-
}
60+
base.OnPreviewMouseLeftButtonDown(e);
9961
}
10062

101-
public static readonly DependencyProperty FeedbackProperty = DependencyProperty.Register(
102-
"Feedback", typeof(Brush), typeof(Ripple), new PropertyMetadata(default(Brush)));
63+
public static readonly DependencyProperty RippleSizeMultiplierProperty = DependencyProperty.Register(
64+
"RippleSizeMultiplier", typeof(double), typeof(Ripple), new PropertyMetadata(1.0));
10365

104-
public Brush Feedback
66+
public double RippleSizeMultiplier
10567
{
106-
get { return (Brush)GetValue(FeedbackProperty); }
107-
set { SetValue(FeedbackProperty, value); }
68+
get { return (double)GetValue(RippleSizeMultiplierProperty); }
69+
set { SetValue(RippleSizeMultiplierProperty, value); }
10870
}
10971

110-
private static readonly DependencyPropertyKey MouseXPropertyKey =
72+
private static readonly DependencyPropertyKey RippleSizePropertyKey =
11173
DependencyProperty.RegisterReadOnly(
112-
"MouseX", typeof(double), typeof(Ripple),
74+
"RippleSize", typeof(double), typeof(Ripple),
11375
new PropertyMetadata(default(double)));
11476

115-
public static readonly DependencyProperty MouseXProperty =
116-
MouseXPropertyKey.DependencyProperty;
77+
public static readonly DependencyProperty RippleSizeProperty =
78+
RippleSizePropertyKey.DependencyProperty;
11779

118-
public double MouseX
80+
public double RippleSize
11981
{
120-
get { return (double)GetValue(MouseXProperty); }
121-
private set { SetValue(MouseXPropertyKey, value); }
82+
get { return (double)GetValue(RippleSizeProperty); }
83+
private set { SetValue(RippleSizePropertyKey, value); }
12284
}
12385

124-
private static readonly DependencyPropertyKey MouseYPropertyKey =
86+
private static readonly DependencyPropertyKey RippleXPropertyKey =
12587
DependencyProperty.RegisterReadOnly(
126-
"MouseY", typeof(double), typeof(Ripple),
88+
"RippleX", typeof(double), typeof(Ripple),
12789
new PropertyMetadata(default(double)));
12890

129-
public static readonly DependencyProperty MouseYProperty =
130-
MouseYPropertyKey.DependencyProperty;
91+
public static readonly DependencyProperty RippleXProperty =
92+
RippleXPropertyKey.DependencyProperty;
13193

132-
public double MouseY
94+
public double RippleX
13395
{
134-
get { return (double)GetValue(MouseYProperty); }
135-
private set { SetValue(MouseYPropertyKey, value); }
96+
get { return (double)GetValue(RippleXProperty); }
97+
private set { SetValue(RippleXPropertyKey, value); }
13698
}
13799

138-
private static readonly DependencyPropertyKey MouseLeftButtonDownXPropertyKey =
100+
private static readonly DependencyPropertyKey RippleYPropertyKey =
139101
DependencyProperty.RegisterReadOnly(
140-
"MouseLeftButtonDownX", typeof(double), typeof(Ripple),
102+
"RippleY", typeof(double), typeof(Ripple),
141103
new PropertyMetadata(default(double)));
142104

143-
public static readonly DependencyProperty MouseLeftButtonDownXProperty =
144-
MouseLeftButtonDownXPropertyKey.DependencyProperty;
105+
public static readonly DependencyProperty RippleYProperty =
106+
RippleYPropertyKey.DependencyProperty;
145107

146-
public double MouseLeftButtonDownX
108+
public double RippleY
147109
{
148-
get { return (double)GetValue(MouseLeftButtonDownXProperty); }
149-
private set { SetValue(MouseLeftButtonDownXPropertyKey, value); }
110+
get { return (double)GetValue(RippleYProperty); }
111+
private set { SetValue(RippleYPropertyKey, value); }
150112
}
151113

152-
private static readonly DependencyPropertyKey MouseLeftButtonDownYPropertyKey =
153-
DependencyProperty.RegisterReadOnly(
154-
"MouseLeftButtonDownY", typeof(double), typeof(Ripple),
155-
new PropertyMetadata(default(double)));
156-
157-
public static readonly DependencyProperty MouseLeftButtonDownYProperty =
158-
MouseLeftButtonDownYPropertyKey.DependencyProperty;
114+
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
115+
"IsActive", typeof(bool), typeof(Ripple), new FrameworkPropertyMetadata(false, IsActivePropertyChangedCallback));
159116

160-
public double MouseLeftButtonDownY
117+
public bool IsActive
161118
{
162-
get { return (double)GetValue(MouseLeftButtonDownYProperty); }
163-
private set { SetValue(MouseLeftButtonDownYPropertyKey, value); }
119+
get { return (bool)GetValue(IsActiveProperty); }
120+
set { SetValue(IsActiveProperty, value); }
164121
}
165122

166-
167-
private sealed class BubbleStoryboardController
123+
private static void IsActivePropertyChangedCallback(
124+
DependencyObject dependencyObject,
125+
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
168126
{
169-
private readonly Ripple _ripple;
170-
private readonly Ellipse _ellipse;
171-
private readonly TimeSpan _fadeOutDuration = TimeSpan.FromMilliseconds(200);
172-
private readonly TimeSpan _bubbleDuration = TimeSpan.FromMilliseconds(400);
173-
174-
private volatile Storyboard _currentBubbleStoryboard;
175-
private volatile Storyboard _currentFadeOutStoryboard;
176-
177-
public BubbleStoryboardController(Ripple ripple)
178-
{
179-
_ripple = ripple;
180-
_ellipse = _ripple.Template.FindName(PartBubbleEllipse, _ripple) as Ellipse;
181-
182-
if (_ellipse == null) throw new InvalidOperationException();
183-
}
184-
public void Add()
185-
{
186-
_currentFadeOutStoryboard?.Remove();
187-
_currentBubbleStoryboard?.Remove();
188-
189-
_currentBubbleStoryboard = CreateBubbleStoryboard();
190-
_currentBubbleStoryboard.Begin();
191-
}
192-
193-
public void Remove()
194-
{
195-
_currentFadeOutStoryboard?.Remove();
196-
197-
var fadeOutStoryboard = CreateFadeOutStoryboard();
198-
var bubbleStoryboardLocalCopy = _currentBubbleStoryboard;
199-
200-
fadeOutStoryboard.Completed += delegate
201-
{
202-
fadeOutStoryboard.Remove();
203-
bubbleStoryboardLocalCopy?.Remove();
204-
};
205-
206-
_currentFadeOutStoryboard = fadeOutStoryboard;
207-
_currentFadeOutStoryboard.Begin();
208-
}
209-
210-
private Storyboard CreateFadeOutStoryboard()
211-
{
212-
Storyboard resultStorybaord = new Storyboard();
213-
214-
DoubleAnimation opacityAnimation = new DoubleAnimation
215-
{
216-
To = 0
217-
};
218-
SetupAnimation(opacityAnimation, _fadeOutDuration, "(UIElement.Opacity)");
219-
220-
resultStorybaord.Children.Add(opacityAnimation);
221-
222-
return resultStorybaord;
223-
}
224-
225-
private Storyboard CreateBubbleStoryboard()
226-
{
227-
Storyboard resultStorybaord = new Storyboard();
228-
229-
DoubleAnimation opacityAnimation = new DoubleAnimation
230-
{
231-
To = 0.26,
232-
};
233-
SetupAnimation(opacityAnimation, _bubbleDuration, "(UIElement.Opacity)");
234-
235-
double h = Math.Max(_ripple.MouseLeftButtonDownX, _ripple.ActualWidth - _ripple.MouseLeftButtonDownX);
236-
double w = Math.Max(_ripple.MouseLeftButtonDownY, _ripple.ActualHeight - _ripple.MouseLeftButtonDownY);
237-
double diameter = 2 * Math.Sqrt(h * h + w * w);
238-
239-
DoubleAnimation widthAnimation = new DoubleAnimation
240-
{
241-
To = diameter
242-
};
243-
SetupAnimation(widthAnimation, _bubbleDuration, "(FrameworkElement.Width)");
244-
245-
DoubleAnimation heightAnimation = new DoubleAnimation
246-
{
247-
To = diameter
248-
};
249-
SetupAnimation(heightAnimation, _bubbleDuration, "(FrameworkElement.Height)");
250-
251-
DoubleAnimation translateXAnimation = new DoubleAnimation
252-
{
253-
To = -diameter / 2
254-
};
255-
SetupAnimation(translateXAnimation, _bubbleDuration, "(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)");
127+
var box = dependencyObject as Ripple;
128+
if (box == null) return;
256129

257-
DoubleAnimation translateYAnimation = new DoubleAnimation
258-
{
259-
To = -diameter / 2
260-
};
261-
SetupAnimation(translateYAnimation, _bubbleDuration, "(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)");
130+
bool isActive = (bool)dependencyPropertyChangedEventArgs.NewValue;
262131

263-
resultStorybaord.Children.Add(opacityAnimation);
264-
resultStorybaord.Children.Add(widthAnimation);
265-
resultStorybaord.Children.Add(heightAnimation);
266-
resultStorybaord.Children.Add(translateXAnimation);
267-
resultStorybaord.Children.Add(translateYAnimation);
132+
VisualStateManager.GoToState(box, isActive ? TemplateStateMousePressed : TemplateStateNormal, true);
133+
}
268134

269-
return resultStorybaord;
270-
}
135+
public override void OnApplyTemplate()
136+
{
137+
base.OnApplyTemplate();
271138

272-
private void SetupAnimation(AnimationTimeline animation, TimeSpan duration, string propertyPath)
273-
{
274-
animation.AccelerationRatio = 0.25;
275-
animation.Duration = new Duration(duration);
276-
Storyboard.SetTarget(animation, _ellipse);
277-
Storyboard.SetTargetProperty(animation, new PropertyPath(propertyPath));
278-
}
139+
VisualStateManager.GoToState(this, TemplateStateNormal, false);
279140
}
280141
}
281142
}

0 commit comments

Comments
 (0)