OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/tabs/media_indicator_button_cocoa.h" | 5 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/mac/foundation_util.h" | 8 #include "base/mac/foundation_util.h" |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "base/thread_task_runner_handle.h" | 10 #include "base/thread_task_runner_handle.h" |
11 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" | 11 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" |
12 #include "content/public/browser/user_metrics.h" | 12 #include "content/public/browser/user_metrics.h" |
13 #include "ui/gfx/animation/animation.h" | 13 #include "ui/gfx/animation/animation.h" |
14 #include "ui/gfx/animation/animation_delegate.h" | 14 #include "ui/gfx/animation/animation_delegate.h" |
15 #include "ui/gfx/image/image.h" | 15 #include "ui/gfx/image/image.h" |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // The minimum required click-to-select area of an inactive tab before allowing | 19 // The minimum required click-to-select area of an inactive tab before allowing |
20 // the click-to-mute functionality to be enabled. This value is in terms of | 20 // the click-to-mute functionality to be enabled. This value is in terms of |
21 // some percentage of the MediaIndicatorButton's width. See comments in the | 21 // some percentage of the AlertIndicatorButton's width. See comments in the |
22 // updateEnabledForMuteToggle method. | 22 // updateEnabledForMuteToggle method. |
23 const int kMinMouseSelectableAreaPercent = 250; | 23 const int kMinMouseSelectableAreaPercent = 250; |
24 | 24 |
25 } // namespace | 25 } // namespace |
26 | 26 |
27 @implementation MediaIndicatorButton | 27 @implementation AlertIndicatorButton |
28 | 28 |
29 class FadeAnimationDelegate : public gfx::AnimationDelegate { | 29 class FadeAnimationDelegate : public gfx::AnimationDelegate { |
30 public: | 30 public: |
31 explicit FadeAnimationDelegate(MediaIndicatorButton* button) | 31 explicit FadeAnimationDelegate(AlertIndicatorButton* button) |
32 : button_(button) {} | 32 : button_(button) {} |
33 ~FadeAnimationDelegate() override {} | 33 ~FadeAnimationDelegate() override {} |
34 | 34 |
35 private: | 35 private: |
36 // gfx::AnimationDelegate implementation. | 36 // gfx::AnimationDelegate implementation. |
37 void AnimationProgressed(const gfx::Animation* animation) override { | 37 void AnimationProgressed(const gfx::Animation* animation) override { |
38 [button_ setNeedsDisplay:YES]; | 38 [button_ setNeedsDisplay:YES]; |
39 } | 39 } |
40 | 40 |
41 void AnimationCanceled(const gfx::Animation* animation) override { | 41 void AnimationCanceled(const gfx::Animation* animation) override { |
42 AnimationEnded(animation); | 42 AnimationEnded(animation); |
43 } | 43 } |
44 | 44 |
45 void AnimationEnded(const gfx::Animation* animation) override { | 45 void AnimationEnded(const gfx::Animation* animation) override { |
46 button_->showingMediaState_ = button_->mediaState_; | 46 button_->showingAlertState_ = button_->alertState_; |
47 [button_ setNeedsDisplay:YES]; | 47 [button_ setNeedsDisplay:YES]; |
48 [button_->animationDoneTarget_ | 48 [button_->animationDoneTarget_ |
49 performSelector:button_->animationDoneAction_]; | 49 performSelector:button_->animationDoneAction_]; |
50 } | 50 } |
51 | 51 |
52 MediaIndicatorButton* const button_; | 52 AlertIndicatorButton* const button_; |
53 | 53 |
54 DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate); | 54 DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate); |
55 }; | 55 }; |
56 | 56 |
57 @synthesize showingMediaState = showingMediaState_; | 57 @synthesize showingAlertState = showingAlertState_; |
58 | 58 |
59 - (id)init { | 59 - (id)init { |
60 if ((self = [super initWithFrame:NSZeroRect])) { | 60 if ((self = [super initWithFrame:NSZeroRect])) { |
61 mediaState_ = TAB_MEDIA_STATE_NONE; | 61 alertState_ = TabAlertState::NONE; |
62 showingMediaState_ = TAB_MEDIA_STATE_NONE; | 62 showingAlertState_ = TabAlertState::NONE; |
63 [self setEnabled:NO]; | 63 [self setEnabled:NO]; |
64 [super setTarget:self]; | 64 [super setTarget:self]; |
65 [super setAction:@selector(handleClick:)]; | 65 [super setAction:@selector(handleClick:)]; |
66 } | 66 } |
67 return self; | 67 return self; |
68 } | 68 } |
69 | 69 |
70 - (void)removeFromSuperview { | 70 - (void)removeFromSuperview { |
71 fadeAnimation_.reset(); | 71 fadeAnimation_.reset(); |
72 [super removeFromSuperview]; | 72 [super removeFromSuperview]; |
73 } | 73 } |
74 | 74 |
75 - (void)transitionToMediaState:(TabMediaState)nextState { | 75 - (void)transitionToAlertState:(TabAlertState)nextState { |
76 if (nextState == mediaState_) | 76 if (nextState == alertState_) |
77 return; | 77 return; |
78 | 78 |
79 if (nextState != TAB_MEDIA_STATE_NONE) { | 79 if (nextState != TabAlertState::NONE) { |
80 [self | 80 [self |
81 setImage:chrome::GetTabMediaIndicatorImage(nextState, 0).ToNSImage()]; | 81 setImage:chrome::GetTabAlertIndicatorImage(nextState, 0).ToNSImage()]; |
82 affordanceImage_.reset( | 82 affordanceImage_.reset( |
83 [chrome::GetTabMediaIndicatorAffordanceImage(nextState, 0) | 83 [chrome::GetTabAlertIndicatorAffordanceImage(nextState, 0) |
84 .ToNSImage() retain]); | 84 .ToNSImage() retain]); |
85 } | 85 } |
86 | 86 |
87 if ((mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING && | 87 if ((alertState_ == TabAlertState::AUDIO_PLAYING && |
88 nextState == TAB_MEDIA_STATE_AUDIO_MUTING) || | 88 nextState == TabAlertState::AUDIO_MUTING) || |
89 (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING && | 89 (alertState_ == TabAlertState::AUDIO_MUTING && |
90 nextState == TAB_MEDIA_STATE_AUDIO_PLAYING) || | 90 nextState == TabAlertState::AUDIO_PLAYING) || |
91 (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING && | 91 (alertState_ == TabAlertState::AUDIO_MUTING && |
92 nextState == TAB_MEDIA_STATE_NONE)) { | 92 nextState == TabAlertState::NONE)) { |
93 // Instant user feedback: No fade animation. | 93 // Instant user feedback: No fade animation. |
94 showingMediaState_ = nextState; | 94 showingAlertState_ = nextState; |
95 fadeAnimation_.reset(); | 95 fadeAnimation_.reset(); |
96 } else { | 96 } else { |
97 if (nextState == TAB_MEDIA_STATE_NONE) | 97 if (nextState == TabAlertState::NONE) |
98 showingMediaState_ = mediaState_; // Fading-out indicator. | 98 showingAlertState_ = alertState_; // Fading-out indicator. |
99 else | 99 else |
100 showingMediaState_ = nextState; // Fading-in to next indicator. | 100 showingAlertState_ = nextState; // Fading-in to next indicator. |
101 // gfx::Animation requires a task runner is available for the current | 101 // gfx::Animation requires a task runner is available for the current |
102 // thread. Generally, only certain unit tests would not instantiate a task | 102 // thread. Generally, only certain unit tests would not instantiate a task |
103 // runner. | 103 // runner. |
104 if (base::ThreadTaskRunnerHandle::IsSet()) { | 104 if (base::ThreadTaskRunnerHandle::IsSet()) { |
105 fadeAnimation_ = chrome::CreateTabMediaIndicatorFadeAnimation(nextState); | 105 fadeAnimation_ = chrome::CreateTabAlertIndicatorFadeAnimation(nextState); |
106 if (!fadeAnimationDelegate_) | 106 if (!fadeAnimationDelegate_) |
107 fadeAnimationDelegate_.reset(new FadeAnimationDelegate(self)); | 107 fadeAnimationDelegate_.reset(new FadeAnimationDelegate(self)); |
108 fadeAnimation_->set_delegate(fadeAnimationDelegate_.get()); | 108 fadeAnimation_->set_delegate(fadeAnimationDelegate_.get()); |
109 fadeAnimation_->Start(); | 109 fadeAnimation_->Start(); |
110 } | 110 } |
111 } | 111 } |
112 | 112 |
113 mediaState_ = nextState; | 113 alertState_ = nextState; |
114 | 114 |
115 [self updateEnabledForMuteToggle]; | 115 [self updateEnabledForMuteToggle]; |
116 | 116 |
117 // An indicator state change should be made visible immediately, instead of | 117 // An indicator state change should be made visible immediately, instead of |
118 // the user being surprised when their mouse leaves the button. | 118 // the user being surprised when their mouse leaves the button. |
119 if ([self hoverState] == kHoverStateMouseOver) | 119 if ([self hoverState] == kHoverStateMouseOver) |
120 [self setHoverState:kHoverStateNone]; | 120 [self setHoverState:kHoverStateNone]; |
121 | 121 |
122 [self setNeedsDisplay:YES]; | 122 [self setNeedsDisplay:YES]; |
123 } | 123 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 if (!image) | 181 if (!image) |
182 return; | 182 return; |
183 NSRect imageRect = NSZeroRect; | 183 NSRect imageRect = NSZeroRect; |
184 imageRect.size = [image size]; | 184 imageRect.size = [image size]; |
185 NSRect destRect = [self bounds]; | 185 NSRect destRect = [self bounds]; |
186 destRect.origin.y = | 186 destRect.origin.y = |
187 floor((NSHeight(destRect) / 2) - (NSHeight(imageRect) / 2)); | 187 floor((NSHeight(destRect) / 2) - (NSHeight(imageRect) / 2)); |
188 destRect.size = imageRect.size; | 188 destRect.size = imageRect.size; |
189 double opaqueness = | 189 double opaqueness = |
190 fadeAnimation_ ? fadeAnimation_->GetCurrentValue() : 1.0; | 190 fadeAnimation_ ? fadeAnimation_->GetCurrentValue() : 1.0; |
191 if (mediaState_ == TAB_MEDIA_STATE_NONE) | 191 if (alertState_ == TabAlertState::NONE) |
192 opaqueness = 1.0 - opaqueness; // Fading out, not in. | 192 opaqueness = 1.0 - opaqueness; // Fading out, not in. |
193 [image drawInRect:destRect | 193 [image drawInRect:destRect |
194 fromRect:imageRect | 194 fromRect:imageRect |
195 operation:NSCompositeSourceOver | 195 operation:NSCompositeSourceOver |
196 fraction:opaqueness | 196 fraction:opaqueness |
197 respectFlipped:YES | 197 respectFlipped:YES |
198 hints:nil]; | 198 hints:nil]; |
199 } | 199 } |
200 | 200 |
201 // When disabled, the superview should receive all mouse events. | 201 // When disabled, the superview should receive all mouse events. |
202 - (NSView*)hitTest:(NSPoint)aPoint { | 202 - (NSView*)hitTest:(NSPoint)aPoint { |
203 if ([self isEnabled] && ![self isHidden]) | 203 if ([self isEnabled] && ![self isHidden]) |
204 return [super hitTest:aPoint]; | 204 return [super hitTest:aPoint]; |
205 else | 205 else |
206 return nil; | 206 return nil; |
207 } | 207 } |
208 | 208 |
209 - (void)handleClick:(id)sender { | 209 - (void)handleClick:(id)sender { |
210 using base::UserMetricsAction; | 210 using base::UserMetricsAction; |
211 | 211 |
212 if (mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING) | 212 if (alertState_ == TabAlertState::AUDIO_PLAYING) |
213 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute")); | 213 content::RecordAction(UserMetricsAction("AlertIndicatorButton_Mute")); |
214 else if (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING) | 214 else if (alertState_ == TabAlertState::AUDIO_MUTING) |
215 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute")); | 215 content::RecordAction(UserMetricsAction("AlertIndicatorButton_Unmute")); |
216 else | 216 else |
217 NOTREACHED(); | 217 NOTREACHED(); |
218 | 218 |
219 [clickTarget_ performSelector:clickAction_ withObject:self]; | 219 [clickTarget_ performSelector:clickAction_ withObject:self]; |
220 } | 220 } |
221 | 221 |
222 - (void)updateEnabledForMuteToggle { | 222 - (void)updateEnabledForMuteToggle { |
223 BOOL enable = chrome::AreExperimentalMuteControlsEnabled() && | 223 BOOL enable = chrome::AreExperimentalMuteControlsEnabled() && |
224 (mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING || | 224 (alertState_ == TabAlertState::AUDIO_PLAYING || |
225 mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING); | 225 alertState_ == TabAlertState::AUDIO_MUTING); |
226 | 226 |
227 // If the tab is not the currently-active tab, make sure it is wide enough | 227 // If the tab is not the currently-active tab, make sure it is wide enough |
228 // before enabling click-to-mute. This ensures that there is enough click | 228 // before enabling click-to-mute. This ensures that there is enough click |
229 // area for the user to activate a tab rather than unintentionally muting it. | 229 // area for the user to activate a tab rather than unintentionally muting it. |
230 TabView* const tabView = base::mac::ObjCCast<TabView>([self superview]); | 230 TabView* const tabView = base::mac::ObjCCast<TabView>([self superview]); |
231 if (enable && tabView && ([tabView state] != NSOnState)) { | 231 if (enable && tabView && ([tabView state] != NSOnState)) { |
232 const int requiredWidth = | 232 const int requiredWidth = |
233 NSWidth([self frame]) * kMinMouseSelectableAreaPercent / 100; | 233 NSWidth([self frame]) * kMinMouseSelectableAreaPercent / 100; |
234 enable = ([tabView widthOfLargestSelectableRegion] >= requiredWidth); | 234 enable = ([tabView widthOfLargestSelectableRegion] >= requiredWidth); |
235 } | 235 } |
236 | 236 |
237 [self setEnabled:enable]; | 237 [self setEnabled:enable]; |
238 } | 238 } |
239 | 239 |
240 @end | 240 @end |
OLD | NEW |