Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: chrome/browser/ui/cocoa/tabs/media_indicator_button_cocoa.mm

Issue 1827083004: UI: Rename MediaState to AlertState (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bluetooth-tab-indicator
Patch Set: Keep gypi ordered Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #import "chrome/browser/ui/cocoa/tabs/media_indicator_button_cocoa.h"
6
7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/macros.h"
10 #include "base/thread_task_runner_handle.h"
11 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
12 #include "content/public/browser/user_metrics.h"
13 #include "ui/gfx/animation/animation.h"
14 #include "ui/gfx/animation/animation_delegate.h"
15 #include "ui/gfx/image/image.h"
16
17 namespace {
18
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
21 // some percentage of the MediaIndicatorButton's width. See comments in the
22 // updateEnabledForMuteToggle method.
23 const int kMinMouseSelectableAreaPercent = 250;
24
25 } // namespace
26
27 @implementation MediaIndicatorButton
28
29 class FadeAnimationDelegate : public gfx::AnimationDelegate {
30 public:
31 explicit FadeAnimationDelegate(MediaIndicatorButton* button)
32 : button_(button) {}
33 ~FadeAnimationDelegate() override {}
34
35 private:
36 // gfx::AnimationDelegate implementation.
37 void AnimationProgressed(const gfx::Animation* animation) override {
38 [button_ setNeedsDisplay:YES];
39 }
40
41 void AnimationCanceled(const gfx::Animation* animation) override {
42 AnimationEnded(animation);
43 }
44
45 void AnimationEnded(const gfx::Animation* animation) override {
46 button_->showingMediaState_ = button_->mediaState_;
47 [button_ setNeedsDisplay:YES];
48 [button_->animationDoneTarget_
49 performSelector:button_->animationDoneAction_];
50 }
51
52 MediaIndicatorButton* const button_;
53
54 DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate);
55 };
56
57 @synthesize showingMediaState = showingMediaState_;
58
59 - (id)init {
60 if ((self = [super initWithFrame:NSZeroRect])) {
61 mediaState_ = TAB_MEDIA_STATE_NONE;
62 showingMediaState_ = TAB_MEDIA_STATE_NONE;
63 [self setEnabled:NO];
64 [super setTarget:self];
65 [super setAction:@selector(handleClick:)];
66 }
67 return self;
68 }
69
70 - (void)removeFromSuperview {
71 fadeAnimation_.reset();
72 [super removeFromSuperview];
73 }
74
75 - (void)transitionToMediaState:(TabMediaState)nextState {
76 if (nextState == mediaState_)
77 return;
78
79 if (nextState != TAB_MEDIA_STATE_NONE) {
80 [self
81 setImage:chrome::GetTabMediaIndicatorImage(nextState, 0).ToNSImage()];
82 affordanceImage_.reset(
83 [chrome::GetTabMediaIndicatorAffordanceImage(nextState, 0)
84 .ToNSImage() retain]);
85 }
86
87 if ((mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING &&
88 nextState == TAB_MEDIA_STATE_AUDIO_MUTING) ||
89 (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
90 nextState == TAB_MEDIA_STATE_AUDIO_PLAYING) ||
91 (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
92 nextState == TAB_MEDIA_STATE_NONE)) {
93 // Instant user feedback: No fade animation.
94 showingMediaState_ = nextState;
95 fadeAnimation_.reset();
96 } else {
97 if (nextState == TAB_MEDIA_STATE_NONE)
98 showingMediaState_ = mediaState_; // Fading-out indicator.
99 else
100 showingMediaState_ = nextState; // Fading-in to next indicator.
101 // gfx::Animation requires a task runner is available for the current
102 // thread. Generally, only certain unit tests would not instantiate a task
103 // runner.
104 if (base::ThreadTaskRunnerHandle::IsSet()) {
105 fadeAnimation_ = chrome::CreateTabMediaIndicatorFadeAnimation(nextState);
106 if (!fadeAnimationDelegate_)
107 fadeAnimationDelegate_.reset(new FadeAnimationDelegate(self));
108 fadeAnimation_->set_delegate(fadeAnimationDelegate_.get());
109 fadeAnimation_->Start();
110 }
111 }
112
113 mediaState_ = nextState;
114
115 [self updateEnabledForMuteToggle];
116
117 // An indicator state change should be made visible immediately, instead of
118 // the user being surprised when their mouse leaves the button.
119 if ([self hoverState] == kHoverStateMouseOver)
120 [self setHoverState:kHoverStateNone];
121
122 [self setNeedsDisplay:YES];
123 }
124
125 - (void)setTarget:(id)aTarget {
126 NOTREACHED(); // See class-level comments.
127 }
128
129 - (void)setAction:(SEL)anAction {
130 NOTREACHED(); // See class-level comments.
131 }
132
133 - (void)setAnimationDoneTarget:(id)target withAction:(SEL)action {
134 animationDoneTarget_ = target;
135 animationDoneAction_ = action;
136 }
137
138 - (void)setClickTarget:(id)target withAction:(SEL)action {
139 clickTarget_ = target;
140 clickAction_ = action;
141 }
142
143 - (void)mouseDown:(NSEvent*)theEvent {
144 // Do not handle this left-button mouse event if any modifier keys are being
145 // held down. Instead, the Tab should react (e.g., selection or drag start).
146 if ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask) {
147 [self setHoverState:kHoverStateNone]; // Turn off hover.
148 [[self nextResponder] mouseDown:theEvent];
149 return;
150 }
151 [super mouseDown:theEvent];
152 }
153
154 - (void)mouseEntered:(NSEvent*)theEvent {
155 // If any modifier keys are being held down, do not turn on hover.
156 if ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask) {
157 [self setHoverState:kHoverStateNone];
158 return;
159 }
160 [super mouseEntered:theEvent];
161 }
162
163 - (void)mouseMoved:(NSEvent*)theEvent {
164 // If any modifier keys are being held down, turn off hover.
165 if ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask) {
166 [self setHoverState:kHoverStateNone];
167 return;
168 }
169 [super mouseMoved:theEvent];
170 }
171
172 - (void)rightMouseDown:(NSEvent*)theEvent {
173 // All right-button mouse events should be handled by the Tab.
174 [self setHoverState:kHoverStateNone]; // Turn off hover.
175 [[self nextResponder] rightMouseDown:theEvent];
176 }
177
178 - (void)drawRect:(NSRect)dirtyRect {
179 NSImage* image = ([self hoverState] == kHoverStateNone || ![self isEnabled]) ?
180 [self image] : affordanceImage_.get();
181 if (!image)
182 return;
183 NSRect imageRect = NSZeroRect;
184 imageRect.size = [image size];
185 NSRect destRect = [self bounds];
186 destRect.origin.y =
187 floor((NSHeight(destRect) / 2) - (NSHeight(imageRect) / 2));
188 destRect.size = imageRect.size;
189 double opaqueness =
190 fadeAnimation_ ? fadeAnimation_->GetCurrentValue() : 1.0;
191 if (mediaState_ == TAB_MEDIA_STATE_NONE)
192 opaqueness = 1.0 - opaqueness; // Fading out, not in.
193 [image drawInRect:destRect
194 fromRect:imageRect
195 operation:NSCompositeSourceOver
196 fraction:opaqueness
197 respectFlipped:YES
198 hints:nil];
199 }
200
201 // When disabled, the superview should receive all mouse events.
202 - (NSView*)hitTest:(NSPoint)aPoint {
203 if ([self isEnabled] && ![self isHidden])
204 return [super hitTest:aPoint];
205 else
206 return nil;
207 }
208
209 - (void)handleClick:(id)sender {
210 using base::UserMetricsAction;
211
212 if (mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING)
213 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute"));
214 else if (mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING)
215 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute"));
216 else
217 NOTREACHED();
218
219 [clickTarget_ performSelector:clickAction_ withObject:self];
220 }
221
222 - (void)updateEnabledForMuteToggle {
223 BOOL enable = chrome::AreExperimentalMuteControlsEnabled() &&
224 (mediaState_ == TAB_MEDIA_STATE_AUDIO_PLAYING ||
225 mediaState_ == TAB_MEDIA_STATE_AUDIO_MUTING);
226
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
229 // area for the user to activate a tab rather than unintentionally muting it.
230 TabView* const tabView = base::mac::ObjCCast<TabView>([self superview]);
231 if (enable && tabView && ([tabView state] != NSOnState)) {
232 const int requiredWidth =
233 NSWidth([self frame]) * kMinMouseSelectableAreaPercent / 100;
234 enable = ([tabView widthOfLargestSelectableRegion] >= requiredWidth);
235 }
236
237 [self setEnabled:enable];
238 }
239
240 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698