• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/chromeos/setting_level_bubble.h"
6 
7 #include <gdk/gdk.h>
8 
9 #include "base/timer.h"
10 #include "chrome/browser/chromeos/login/background_view.h"
11 #include "chrome/browser/chromeos/login/login_utils.h"
12 #include "chrome/browser/chromeos/setting_level_bubble_view.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_list.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/views/bubble/bubble.h"
18 #include "views/widget/root_view.h"
19 
20 namespace {
21 
22 const int kBubbleShowTimeoutSec = 2;
23 const int kAnimationDurationMs = 200;
24 
25 // Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost.
26 const double kBubbleXRatio = 0.5;
27 
28 // Vertical gap from the bottom of the screen in pixels.
29 const int kBubbleBottomGap = 30;
30 
LimitPercent(int percent)31 int LimitPercent(int percent) {
32   if (percent < 0)
33     percent = 0;
34   else if (percent > 100)
35     percent = 100;
36   return percent;
37 }
38 
39 }  // namespace
40 
41 namespace chromeos {
42 
43 // Temporary helper routine. Tries to first return the widget from the
44 // most-recently-focused normal browser window, then from a login
45 // background, and finally NULL if both of those fail.
46 // TODO(glotov): remove this in favor of enabling Bubble class act
47 // without |parent| specified. crosbug.com/4025
GetToplevelWidget()48 static views::Widget* GetToplevelWidget() {
49   GtkWindow* window = NULL;
50 
51   // We just use the default profile here -- this gets overridden as needed
52   // in Chrome OS depending on whether the user is logged in or not.
53   Browser* browser =
54       BrowserList::FindBrowserWithType(
55           ProfileManager::GetDefaultProfile(),
56           Browser::TYPE_NORMAL,
57           true);  // match_incognito
58   if (browser) {
59     window = GTK_WINDOW(browser->window()->GetNativeHandle());
60   } else {
61     // Otherwise, see if there's a background window that we can use.
62     BackgroundView* background = LoginUtils::Get()->GetBackgroundView();
63     if (background)
64       window = GTK_WINDOW(background->GetNativeWindow());
65   }
66 
67   if (!window)
68     return NULL;
69 
70   views::NativeWidget* native_widget =
71       views::NativeWidget::GetNativeWidgetForNativeWindow(window);
72   return native_widget->GetWidget();
73 }
74 
SettingLevelBubble(SkBitmap * increase_icon,SkBitmap * decrease_icon,SkBitmap * zero_icon)75 SettingLevelBubble::SettingLevelBubble(SkBitmap* increase_icon,
76                                        SkBitmap* decrease_icon,
77                                        SkBitmap* zero_icon)
78     : previous_percent_(-1),
79       current_percent_(-1),
80       increase_icon_(increase_icon),
81       decrease_icon_(decrease_icon),
82       zero_icon_(zero_icon),
83       bubble_(NULL),
84       view_(NULL),
85       animation_(this) {
86   animation_.SetSlideDuration(kAnimationDurationMs);
87   animation_.SetTweenType(ui::Tween::LINEAR);
88 }
89 
ShowBubble(int percent)90 void SettingLevelBubble::ShowBubble(int percent) {
91   percent = LimitPercent(percent);
92   if (previous_percent_ == -1)
93     previous_percent_ = percent;
94   current_percent_ = percent;
95 
96   SkBitmap* icon = increase_icon_;
97   if (current_percent_ == 0)
98     icon = zero_icon_;
99   else if (current_percent_ < previous_percent_)
100     icon = decrease_icon_;
101 
102   if (!bubble_) {
103     views::Widget* widget = GetToplevelWidget();
104     if (widget == NULL)
105       return;
106     DCHECK(view_ == NULL);
107     view_ = new SettingLevelBubbleView;
108     view_->Init(icon, previous_percent_);
109     // Calculate position of the bubble.
110     gfx::Rect bounds = widget->GetClientAreaScreenBounds();
111     const gfx::Size view_size = view_->GetPreferredSize();
112     // Note that (x, y) is the point of the center of the bubble.
113     const int x = view_size.width() / 2 +
114         kBubbleXRatio * (bounds.width() - view_size.width());
115     const int y = bounds.height() - view_size.height() / 2 - kBubbleBottomGap;
116     bubble_ = Bubble::ShowFocusless(widget,  // parent
117                                     gfx::Rect(x, y, 0, 20),
118                                     BubbleBorder::FLOAT,
119                                     view_,  // contents
120                                     this,   // delegate
121                                     true);  // show while screen is locked
122   } else {
123     DCHECK(view_);
124     timeout_timer_.Stop();
125     view_->SetIcon(icon);
126   }
127   if (animation_.is_animating())
128     animation_.End();
129   animation_.Reset();
130   animation_.Show();
131   timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec),
132                        this, &SettingLevelBubble::OnTimeout);
133 }
134 
HideBubble()135 void SettingLevelBubble::HideBubble() {
136   if (bubble_)
137     bubble_->Close();
138 }
139 
UpdateWithoutShowingBubble(int percent)140 void SettingLevelBubble::UpdateWithoutShowingBubble(int percent) {
141   percent = LimitPercent(percent);
142 
143   previous_percent_ =
144       animation_.is_animating() ?
145       animation_.GetCurrentValue() :
146       current_percent_;
147   if (previous_percent_ < 0)
148     previous_percent_ = percent;
149   current_percent_ = percent;
150 
151   if (animation_.is_animating())
152     animation_.End();
153   animation_.Reset();
154   animation_.Show();
155 }
156 
OnTimeout()157 void SettingLevelBubble::OnTimeout() {
158   HideBubble();
159 }
160 
BubbleClosing(Bubble * bubble,bool)161 void SettingLevelBubble::BubbleClosing(Bubble* bubble, bool) {
162   DCHECK(bubble == bubble_);
163   timeout_timer_.Stop();
164   animation_.Stop();
165   bubble_ = NULL;
166   view_ = NULL;
167 }
168 
AnimationEnded(const ui::Animation * animation)169 void SettingLevelBubble::AnimationEnded(const ui::Animation* animation) {
170   previous_percent_ = current_percent_;
171 }
172 
AnimationProgressed(const ui::Animation * animation)173 void SettingLevelBubble::AnimationProgressed(const ui::Animation* animation) {
174   if (view_) {
175     view_->Update(
176         ui::Tween::ValueBetween(animation->GetCurrentValue(),
177                                 previous_percent_,
178                                 current_percent_));
179   }
180 }
181 
182 }  // namespace chromeos
183