Return backed up TemplateURL on default search change
[chromium-blink-merge.git] / chrome / browser / chromeos / setting_level_bubble.cc
blob2f3b9edb656896fed4ecb56cb9d51de02f712939
1 // Copyright (c) 2011 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.
5 #include "chrome/browser/chromeos/setting_level_bubble.h"
7 #include <algorithm>
9 #include "chrome/browser/chromeos/login/background_view.h"
10 #include "chrome/browser/chromeos/login/base_login_display_host.h"
11 #include "chrome/browser/chromeos/login/login_display_host.h"
12 #include "chrome/browser/chromeos/login/login_utils.h"
13 #include "chrome/browser/chromeos/login/webui_login_display.h"
14 #include "chrome/browser/chromeos/setting_level_bubble_view.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/views/window.h"
20 #include "ui/gfx/screen.h"
21 #include "ui/views/bubble/bubble_delegate.h"
22 #include "ui/views/layout/fill_layout.h"
23 #include "ui/views/widget/root_view.h"
25 using base::TimeDelta;
26 using base::TimeTicks;
27 using std::max;
28 using std::min;
30 namespace {
32 // How long should the bubble be shown onscreen whenever the setting changes?
33 const int kBubbleShowTimeoutMs = 1000;
35 // How long should the level initially take to move up or down when it changes?
36 // (The rate adapts to handle keyboard autorepeat.)
37 const int64 kInitialAnimationDurationMs = 200;
39 // Horizontal position of the center of the bubble on the screen: 0 is left
40 // edge, 0.5 is center, 1 is right edge.
41 const double kBubbleXRatio = 0.5;
43 // Vertical gap from the bottom of the screen in pixels.
44 const int kBubbleBottomGap = 30;
46 // Duration between animation frames.
47 // Chosen to match ui::SlideAnimation's kDefaultFramerateHz.
48 const int kAnimationIntervalMs = 1000 / 50;
50 double LimitPercent(double percent) {
51 return min(max(percent, 0.0), 100.0);
54 } // namespace
56 namespace chromeos {
58 // SettingLevelBubbleDelegateView ----------------------------------------------
59 class SettingLevelBubbleDelegateView : public views::BubbleDelegateView {
60 public:
61 // BubbleDelegate overrides:
62 virtual gfx::Rect GetAnchorRect() OVERRIDE;
64 // Create the bubble delegate view.
65 SettingLevelBubbleDelegateView();
66 virtual ~SettingLevelBubbleDelegateView();
68 SettingLevelBubbleView* view() { return view_; }
70 protected:
71 // BubbleDelegate overrides:
72 virtual void Init() OVERRIDE;
74 private:
75 SettingLevelBubbleView* view_;
77 DISALLOW_COPY_AND_ASSIGN(SettingLevelBubbleDelegateView);
80 gfx::Rect SettingLevelBubbleDelegateView::GetAnchorRect() {
81 gfx::Size view_size = GetPreferredSize();
82 // Calculate the position in screen coordinates that the bubble should
83 // "point" at (since we use BubbleBorder::FLOAT, this position actually
84 // specifies the center of the bubble).
85 gfx::Rect monitor_area = gfx::Screen::GetMonitorAreaNearestWindow(NULL);
86 return (gfx::Rect(
87 monitor_area.x() + kBubbleXRatio * monitor_area.width(),
88 monitor_area.bottom() - view_size.height() / 2 - kBubbleBottomGap, 0, 0));
91 SettingLevelBubbleDelegateView::SettingLevelBubbleDelegateView()
92 : BubbleDelegateView(NULL, views::BubbleBorder::FLOAT),
93 view_(NULL) {
94 set_close_on_esc(false);
95 set_use_focusless(true);
98 SettingLevelBubbleDelegateView::~SettingLevelBubbleDelegateView() {
99 view_ = NULL;
102 void SettingLevelBubbleDelegateView::Init() {
103 SetLayoutManager(new views::FillLayout());
104 view_ = new SettingLevelBubbleView();
105 AddChildView(view_);
108 // SettingLevelBubble ----------------------------------------------------------
109 void SettingLevelBubble::ShowBubble(double percent, bool enabled) {
110 hide_timer_.Stop();
112 // Set up target percent and icon.
113 const double old_target_percent = target_percent_;
114 UpdateTargetPercent(percent);
115 SkBitmap* current_icon = increase_icon_;
116 if (!enabled || target_percent_ == 0)
117 current_icon = disabled_icon_;
118 else if (old_target_percent >= 0 && target_percent_ < old_target_percent)
119 current_icon = decrease_icon_;
121 if (!view_) {
122 view_ = CreateView();
123 view_->Init(current_icon, percent, enabled);
124 } else {
125 // Reset fade sequence, if the bubble is already fading.
126 SettingLevelBubbleDelegateView* delegate =
127 static_cast<SettingLevelBubbleDelegateView*>
128 (view_->GetWidget()->widget_delegate());
129 delegate->ResetFade();
130 view_->SetIcon(current_icon);
131 view_->SetEnabled(enabled);
133 view_->GetWidget()->Show();
134 // When the timer runs out, start the fade sequence.
135 hide_timer_.Start(FROM_HERE,
136 base::TimeDelta::FromMilliseconds(kBubbleShowTimeoutMs),
137 this, &SettingLevelBubble::OnHideTimeout);
140 void SettingLevelBubble::HideBubble() {
141 hide_timer_.Stop();
142 if (view_) {
143 view_->GetWidget()->Close();
144 view_ = NULL;
148 void SettingLevelBubble::UpdateWithoutShowingBubble(double percent,
149 bool enabled) {
150 UpdateTargetPercent(percent);
151 if (view_)
152 view_->SetEnabled(enabled);
155 SettingLevelBubble::SettingLevelBubble(SkBitmap* increase_icon,
156 SkBitmap* decrease_icon,
157 SkBitmap* disabled_icon)
158 : current_percent_(-1.0),
159 target_percent_(-1.0),
160 increase_icon_(increase_icon),
161 decrease_icon_(decrease_icon),
162 disabled_icon_(disabled_icon),
163 view_(NULL),
164 is_animating_(false) {
167 SettingLevelBubble::~SettingLevelBubble() {
168 view_ = NULL;
171 void SettingLevelBubble::OnWidgetClosing(views::Widget* widget) {
172 if (view_ && view_->GetWidget() == widget) {
173 view_->GetWidget()->RemoveObserver(this);
174 view_ = NULL;
176 // Update states.
177 current_percent_ = target_percent_;
178 target_time_ = TimeTicks();
179 last_animation_update_time_ = TimeTicks();
180 last_target_update_time_ = TimeTicks();
181 hide_timer_.Stop();
182 StopAnimation();
185 SettingLevelBubbleView* SettingLevelBubble::CreateView() {
186 SettingLevelBubbleDelegateView* delegate = new SettingLevelBubbleDelegateView;
187 views::Widget* widget = browser::CreateViewsBubbleAboveLockScreen(delegate);
188 widget->AddObserver(this);
189 // Hold on to the content view.
190 return delegate->view();
193 void SettingLevelBubble::OnHideTimeout() {
194 // Start fading away.
195 if (view_) {
196 SettingLevelBubbleDelegateView* delegate =
197 static_cast<SettingLevelBubbleDelegateView*>
198 (view_->GetWidget()->widget_delegate());
199 delegate->StartFade(false);
203 void SettingLevelBubble::OnAnimationTimeout() {
204 const TimeTicks now = TimeTicks::Now();
205 const int64 remaining_ms = (target_time_ - now).InMilliseconds();
207 if (remaining_ms <= 0) {
208 current_percent_ = target_percent_;
209 StopAnimation();
210 } else {
211 // Figure out what fraction of the total time until we want to reach the
212 // target has elapsed since the last update.
213 const double remaining_percent = target_percent_ - current_percent_;
214 const int64 elapsed_ms =
215 (now - last_animation_update_time_).InMilliseconds();
216 current_percent_ +=
217 remaining_percent *
218 (static_cast<double>(elapsed_ms) / (elapsed_ms + remaining_ms));
220 last_animation_update_time_ = now;
222 if (view_)
223 view_->SetLevel(current_percent_);
226 void SettingLevelBubble::UpdateTargetPercent(double percent) {
227 target_percent_ = LimitPercent(percent);
228 const TimeTicks now = TimeTicks::Now();
230 if (current_percent_ < 0.0) {
231 // If we're setting the level for the first time, no need to animate.
232 current_percent_ = target_percent_;
233 if (view_)
234 view_->SetLevel(current_percent_);
235 } else {
236 // Use the time since the last request as a hint for the duration of the
237 // animation. This makes us automatically adapt to the repeat rate if a key
238 // is being held down to change a setting (which prevents us from lagging
239 // behind when the key is finally released).
240 int64 duration_ms = kInitialAnimationDurationMs;
241 if (!last_target_update_time_.is_null())
242 duration_ms = min(kInitialAnimationDurationMs,
243 (now - last_target_update_time_).InMilliseconds());
244 target_time_ = now + TimeDelta::FromMilliseconds(duration_ms);
246 if (!is_animating_) {
247 animation_timer_.Start(FROM_HERE,
248 TimeDelta::FromMilliseconds(kAnimationIntervalMs),
249 this,
250 &SettingLevelBubble::OnAnimationTimeout);
251 is_animating_ = true;
252 last_animation_update_time_ = now;
256 last_target_update_time_ = now;
259 void SettingLevelBubble::StopAnimation() {
260 animation_timer_.Stop();
261 is_animating_ = false;
264 } // namespace chromeos