OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/ui/search/toolbar_search_animator.h" | 5 #include "chrome/browser/ui/search/toolbar_search_animator.h" |
6 | 6 |
7 #include "chrome/browser/ui/search/search_model.h" | 7 #include "chrome/browser/ui/search/search_model.h" |
8 #include "chrome/browser/ui/search/search_types.h" | 8 #include "chrome/browser/ui/search/search_types.h" |
9 #include "chrome/browser/ui/search/toolbar_search_animator_observer.h" | 9 #include "chrome/browser/ui/search/toolbar_search_animator_observer.h" |
10 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 10 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
11 #include "chrome/browser/ui/webui/instant_ui.h" | 11 #include "chrome/browser/ui/webui/instant_ui.h" |
12 #include "ui/base/animation/multi_animation.h" | |
12 #include "ui/base/animation/slide_animation.h" | 13 #include "ui/base/animation/slide_animation.h" |
13 | 14 |
14 namespace { | 15 namespace { |
15 | 16 |
16 const int kBackgroundChangeDelayMs = 100; | 17 const int kBackgroundChangeDelayMs = 100; |
17 const int kBackgroundChangeDurationMs = 200; | 18 const int kBackgroundChangeDurationMs = 200; |
18 | 19 |
20 const int kSeparatorFadeDurationMs = 100; | |
21 | |
19 const double kMinOpacity = 0.0f; | 22 const double kMinOpacity = 0.0f; |
20 const double kMaxOpacity = 1.0f; | 23 const double kMaxOpacity = 1.0f; |
21 | 24 |
22 } // namespace | 25 } // namespace |
23 | 26 |
24 namespace chrome { | 27 namespace chrome { |
25 namespace search { | 28 namespace search { |
26 | 29 |
27 ToolbarSearchAnimator::ToolbarSearchAnimator(SearchModel* search_model) | 30 ToolbarSearchAnimator::ToolbarSearchAnimator(SearchModel* search_model) |
28 : search_model_(search_model), | 31 : search_model_(search_model) { |
29 animate_state_(ANIMATE_STATE_NONE) { | |
30 search_model_->AddObserver(this); | 32 search_model_->AddObserver(this); |
33 | |
34 ui::MultiAnimation::Parts parts; | |
35 parts.push_back(ui::MultiAnimation::Part( | |
36 kBackgroundChangeDelayMs * InstantUI::GetSlowAnimationScaleFactor(), | |
37 ui::Tween::ZERO)); | |
38 parts.push_back(ui::MultiAnimation::Part( | |
39 kBackgroundChangeDurationMs * InstantUI::GetSlowAnimationScaleFactor(), | |
40 ui::Tween::LINEAR)); | |
41 background_animation_.reset(new ui::MultiAnimation(parts)); | |
42 background_animation_->set_continuous(false); | |
43 | |
44 separator_animation_.reset(new ui::SlideAnimation(this)); | |
45 separator_animation_->SetTweenType(ui::Tween::LINEAR); | |
46 separator_animation_->SetSlideDuration( | |
47 kSeparatorFadeDurationMs * InstantUI::GetSlowAnimationScaleFactor()); | |
31 } | 48 } |
32 | 49 |
33 ToolbarSearchAnimator::~ToolbarSearchAnimator() { | 50 ToolbarSearchAnimator::~ToolbarSearchAnimator() { |
51 background_animation_->Stop(); | |
52 separator_animation_->Stop(); | |
34 search_model_->RemoveObserver(this); | 53 search_model_->RemoveObserver(this); |
35 } | 54 } |
36 | 55 |
37 void ToolbarSearchAnimator::GetCurrentBackgroundState( | 56 double ToolbarSearchAnimator::GetGradientOpacity() const { |
38 BackgroundState* background_state, | 57 if (background_animation_->is_animating()) |
39 double* search_background_opacity) const { | 58 return background_animation_->CurrentValueBetween(kMinOpacity, kMaxOpacity); |
40 // Should only be called for SEARCH mode. | 59 return search_model_->mode().is_ntp() ? kMinOpacity : kMaxOpacity; |
41 DCHECK(search_model_->mode().is_search()); | 60 } |
42 *background_state = BACKGROUND_STATE_DEFAULT; | 61 |
43 *search_background_opacity = -1.0f; | 62 double ToolbarSearchAnimator::GetSeparatorOpacity() const { |
44 switch (animate_state_) { | 63 if (separator_animation_->is_animating()) |
45 case ANIMATE_STATE_WAITING: | 64 return separator_animation_->CurrentValueBetween(kMinOpacity, kMaxOpacity); |
46 *background_state = BACKGROUND_STATE_NTP; | 65 return search_model_->mode().is_default() ? kMaxOpacity : kMinOpacity; |
47 break; | |
48 case ANIMATE_STATE_RUNNING: | |
49 *background_state = BACKGROUND_STATE_NTP_SEARCH; | |
50 *search_background_opacity = background_animation_->CurrentValueBetween( | |
51 kMinOpacity, kMaxOpacity); | |
52 break; | |
53 case ANIMATE_STATE_NONE: | |
54 break; | |
55 } | |
56 } | 66 } |
57 | 67 |
58 void ToolbarSearchAnimator::FinishAnimation(TabContents* tab_contents) { | 68 void ToolbarSearchAnimator::FinishAnimation(TabContents* tab_contents) { |
59 Reset(tab_contents); | 69 Reset(tab_contents); |
60 } | 70 } |
61 | 71 |
62 void ToolbarSearchAnimator::AddObserver( | 72 void ToolbarSearchAnimator::AddObserver( |
63 ToolbarSearchAnimatorObserver* observer) { | 73 ToolbarSearchAnimatorObserver* observer) { |
64 observers_.AddObserver(observer); | 74 observers_.AddObserver(observer); |
65 } | 75 } |
66 | 76 |
67 void ToolbarSearchAnimator::RemoveObserver( | 77 void ToolbarSearchAnimator::RemoveObserver( |
68 ToolbarSearchAnimatorObserver* observer) { | 78 ToolbarSearchAnimatorObserver* observer) { |
69 observers_.RemoveObserver(observer); | 79 observers_.RemoveObserver(observer); |
70 } | 80 } |
71 | 81 |
72 void ToolbarSearchAnimator::ModeChanged(const Mode& mode) { | 82 void ToolbarSearchAnimator::ModeChanged(const Mode& old_mode, |
73 int delay_ms = kBackgroundChangeDelayMs * | 83 const Mode& new_mode) { |
74 InstantUI::GetSlowAnimationScaleFactor(); | 84 // If mode transitions from |NTP| to |SEARCH| and we're not animating |
dhollowa
2012/08/01 22:26:23
"If the mode"...
kuan
2012/08/02 21:54:03
Done.
| |
75 if (mode.is_search() && mode.animate && | 85 // background, start fading in gradient background. |
76 animate_state_ == ANIMATE_STATE_NONE) { | 86 // TODO(kuan): check with UX folks if we need to animate from gradient to flat |
77 background_change_timer_.Start( | 87 // when mode transitions from |SEARCH| or |DEFAULT| to |NTP|. |
78 FROM_HERE, | 88 if (new_mode.animate && old_mode.is_ntp() && new_mode.is_search() && |
79 base::TimeDelta::FromMilliseconds(delay_ms), | 89 !background_animation_->is_animating()) { |
80 this, | 90 StartBackgroundChange(); |
81 &ToolbarSearchAnimator::StartBackgroundChange); | |
82 animate_state_ = ANIMATE_STATE_WAITING; | |
83 return; | 91 return; |
84 } | 92 } |
85 // For all other cases, reset |animate_state_| and stop timer or animation. | 93 |
94 // If mode transitions from non-|DEFAULT| to |DEFAULT|, fade in separator; | |
95 // if we're already fading out separator, reverse to fade it in. | |
96 // Note that if we're still fading in gradient background when this mode | |
97 // transition happens (e.g. when user quickly hits enter on the auto-completed | |
98 // query in omnibox, triggering mode to transition from |SEARCH| to | |
99 // |DEFAULT|), we should continue fading in the gradient background to its | |
100 // full course. | |
101 // TODO(kuan): however, for now, sometimes, the first auto-completed query in | |
102 // omnibox is pre-rendered and gets swapped in when chosen by user, causing | |
103 // OnTabDetached for original tab to be fired, and hence causing us to Reset, | |
104 // immediately jumping to end state of background animation. I'll look into | |
105 // this together with the above TODO for reverse background animation. | |
106 if (new_mode.animate && (new_mode.is_default() || | |
107 (separator_animation_->is_animating() && | |
108 separator_animation_->IsClosing()))) { | |
109 StartSeparatorFade(true); | |
110 return; | |
111 } | |
112 | |
113 // If mode transitions from |DEFAULT| to non-|DEFAULT|, fade out separator; | |
114 // if we're already fading in separator, reverse to fade it out. | |
115 // TODO(kuan): for now, if we're still fading in gradient background when this | |
116 // mode transition happens (e.g. when user quickly hits back button on a | |
117 // website that he/she just entered from a |SEARCH| mode, triggering mode to | |
118 // transition from |DEFAULT| to |NTP|), we'll continue fading in the gradient | |
119 // background to its full course, which is undesirable. I'll handle this | |
120 // together with the above TODO for reverse background animation. | |
121 if (new_mode.animate && (old_mode.is_default() || | |
122 (separator_animation_->is_animating() && | |
123 separator_animation_->IsShowing()))) { | |
124 StartSeparatorFade(false); | |
125 return; | |
126 } | |
127 | |
128 // For all other cases, reset animate states and stop animation(s). | |
86 // Stopping animation will jump to the end of it. | 129 // Stopping animation will jump to the end of it. |
87 Reset(NULL); | 130 Reset(NULL); |
88 } | 131 } |
89 | 132 |
90 void ToolbarSearchAnimator::AnimationProgressed( | 133 void ToolbarSearchAnimator::AnimationProgressed( |
91 const ui::Animation* animation) { | 134 const ui::Animation* animation) { |
92 DCHECK_EQ(animation, background_animation_.get()); | 135 if (animation == background_animation_.get()) { |
93 animate_state_ = ANIMATE_STATE_RUNNING; | 136 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, |
94 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | 137 OnToolbarBackgroundAnimatorProgressed()); |
95 OnToolbarBackgroundAnimatorProgressed()); | 138 return; |
139 } | |
140 | |
141 if (animation == separator_animation_.get()) { | |
142 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | |
143 OnToolbarSeparatorAnimatorProgressed()); | |
144 } | |
96 } | 145 } |
97 | 146 |
98 void ToolbarSearchAnimator::AnimationEnded(const ui::Animation* animation) { | 147 void ToolbarSearchAnimator::AnimationEnded(const ui::Animation* animation) { |
99 DCHECK_EQ(animation, background_animation_.get()); | 148 // We only get this callback when |animation| has run its full course. |
100 // Only notify observers via OnToolbarBackgroundAnimatorProgressed if the | 149 // If animation was canceled (in Reset()), we won't get an AnimationEnded() |
101 // animation has runs its full course i.e |animate_state_| is still | 150 // callback because we had cleared the animation's delegate in Reset(). |
102 // ANIMATE_STATE_RUNNING. | 151 if (animation == background_animation_.get()) { |
103 // Animation that is canceled, i.e. |animate_state_| has been set to | |
104 // ANIMATE_STATE_NONE in Reset, should notify observers via | |
105 // OnToolbarBackgroundAnimatorCanceled. | |
106 if (animate_state_ == ANIMATE_STATE_RUNNING) { | |
107 animate_state_ = ANIMATE_STATE_NONE; | |
108 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | 152 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, |
109 OnToolbarBackgroundAnimatorProgressed()); | 153 OnToolbarBackgroundAnimatorProgressed()); |
154 return; | |
155 } | |
156 | |
157 if (animation == separator_animation_.get()) { | |
158 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | |
159 OnToolbarSeparatorAnimatorProgressed()); | |
110 } | 160 } |
111 } | 161 } |
112 | 162 |
113 void ToolbarSearchAnimator::StartBackgroundChange() { | 163 void ToolbarSearchAnimator::StartBackgroundChange() { |
114 if (!background_animation_.get()) { | 164 background_animation_->set_delegate(this); |
115 background_animation_.reset(new ui::SlideAnimation(this)); | 165 background_animation_->Start(); |
116 background_animation_->SetTweenType(ui::Tween::LINEAR); | 166 } |
117 background_animation_->SetSlideDuration( | 167 |
118 kBackgroundChangeDurationMs * InstantUI::GetSlowAnimationScaleFactor()); | 168 void ToolbarSearchAnimator::StartSeparatorFade(bool show) { |
169 if (!separator_animation_->is_animating()) { | |
170 separator_animation_->set_delegate(this); | |
171 separator_animation_->Reset(show ? 0.0 : 1.0); | |
119 } | 172 } |
120 background_animation_->Reset(0.0); | 173 if (show) |
121 background_animation_->Show(); | 174 separator_animation_->Show(); |
175 else | |
176 separator_animation_->Hide(); | |
122 } | 177 } |
123 | 178 |
124 void ToolbarSearchAnimator::Reset(TabContents* tab_contents) { | 179 void ToolbarSearchAnimator::Reset(TabContents* tab_contents) { |
125 bool notify_observers = animate_state_ != ANIMATE_STATE_NONE; | 180 bool notify_background_observers = background_animation_->is_animating(); |
126 animate_state_ = ANIMATE_STATE_NONE; | 181 bool notify_separator_observers = separator_animation_->is_animating(); |
127 background_change_timer_.Stop(); | 182 |
128 // If animation is still running, stopping it will trigger AnimationEnded | 183 // Clear the animations' delegates so that we don't get AnimationEnded() |
129 // where we've prevented from notifying observers via BackgroundChanged; | 184 // callbacks. |
130 // see comments in AnimationEnded. | 185 background_animation_->set_delegate(NULL); |
131 if (background_animation_.get()) | 186 separator_animation_->set_delegate(NULL); |
132 background_animation_->Stop(); | 187 background_animation_->Stop(); |
133 if (notify_observers) { | 188 separator_animation_->Stop(); |
189 | |
190 // Notify observers of animation(s) cancelation. | |
191 if (notify_background_observers) { | |
134 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | 192 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, |
135 OnToolbarBackgroundAnimatorCanceled(tab_contents)); | 193 OnToolbarBackgroundAnimatorCanceled(tab_contents)); |
136 } | 194 } |
195 if (notify_separator_observers) { | |
196 FOR_EACH_OBSERVER(ToolbarSearchAnimatorObserver, observers_, | |
197 OnToolbarSeparatorAnimatorCanceled()); | |
198 } | |
137 } | 199 } |
138 | 200 |
139 } // namespace search | 201 } // namespace search |
140 } // namespace chrome | 202 } // namespace chrome |
OLD | NEW |