Home | History | Annotate | Download | only in chromeos
      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 
     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
     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 
     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 
     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 
    135 void SettingLevelBubble::HideBubble() {
    136   if (bubble_)
    137     bubble_->Close();
    138 }
    139 
    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 
    157 void SettingLevelBubble::OnTimeout() {
    158   HideBubble();
    159 }
    160 
    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 
    169 void SettingLevelBubble::AnimationEnded(const ui::Animation* animation) {
    170   previous_percent_ = current_percent_;
    171 }
    172 
    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