// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/setting_level_bubble.h" #include <gdk/gdk.h> #include "base/timer.h" #include "chrome/browser/chromeos/login/background_view.h" #include "chrome/browser/chromeos/login/login_utils.h" #include "chrome/browser/chromeos/setting_level_bubble_view.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/bubble/bubble.h" #include "views/widget/root_view.h" namespace { const int kBubbleShowTimeoutSec = 2; const int kAnimationDurationMs = 200; // Horizontal relative position: 0 - leftmost, 0.5 - center, 1 - rightmost. const double kBubbleXRatio = 0.5; // Vertical gap from the bottom of the screen in pixels. const int kBubbleBottomGap = 30; int LimitPercent(int percent) { if (percent < 0) percent = 0; else if (percent > 100) percent = 100; return percent; } } // namespace namespace chromeos { // Temporary helper routine. Tries to first return the widget from the // most-recently-focused normal browser window, then from a login // background, and finally NULL if both of those fail. // TODO(glotov): remove this in favor of enabling Bubble class act // without |parent| specified. crosbug.com/4025 static views::Widget* GetToplevelWidget() { GtkWindow* window = NULL; // We just use the default profile here -- this gets overridden as needed // in Chrome OS depending on whether the user is logged in or not. Browser* browser = BrowserList::FindBrowserWithType( ProfileManager::GetDefaultProfile(), Browser::TYPE_NORMAL, true); // match_incognito if (browser) { window = GTK_WINDOW(browser->window()->GetNativeHandle()); } else { // Otherwise, see if there's a background window that we can use. BackgroundView* background = LoginUtils::Get()->GetBackgroundView(); if (background) window = GTK_WINDOW(background->GetNativeWindow()); } if (!window) return NULL; views::NativeWidget* native_widget = views::NativeWidget::GetNativeWidgetForNativeWindow(window); return native_widget->GetWidget(); } SettingLevelBubble::SettingLevelBubble(SkBitmap* increase_icon, SkBitmap* decrease_icon, SkBitmap* zero_icon) : previous_percent_(-1), current_percent_(-1), increase_icon_(increase_icon), decrease_icon_(decrease_icon), zero_icon_(zero_icon), bubble_(NULL), view_(NULL), animation_(this) { animation_.SetSlideDuration(kAnimationDurationMs); animation_.SetTweenType(ui::Tween::LINEAR); } void SettingLevelBubble::ShowBubble(int percent) { percent = LimitPercent(percent); if (previous_percent_ == -1) previous_percent_ = percent; current_percent_ = percent; SkBitmap* icon = increase_icon_; if (current_percent_ == 0) icon = zero_icon_; else if (current_percent_ < previous_percent_) icon = decrease_icon_; if (!bubble_) { views::Widget* widget = GetToplevelWidget(); if (widget == NULL) return; DCHECK(view_ == NULL); view_ = new SettingLevelBubbleView; view_->Init(icon, previous_percent_); // Calculate position of the bubble. gfx::Rect bounds = widget->GetClientAreaScreenBounds(); const gfx::Size view_size = view_->GetPreferredSize(); // Note that (x, y) is the point of the center of the bubble. const int x = view_size.width() / 2 + kBubbleXRatio * (bounds.width() - view_size.width()); const int y = bounds.height() - view_size.height() / 2 - kBubbleBottomGap; bubble_ = Bubble::ShowFocusless(widget, // parent gfx::Rect(x, y, 0, 20), BubbleBorder::FLOAT, view_, // contents this, // delegate true); // show while screen is locked } else { DCHECK(view_); timeout_timer_.Stop(); view_->SetIcon(icon); } if (animation_.is_animating()) animation_.End(); animation_.Reset(); animation_.Show(); timeout_timer_.Start(base::TimeDelta::FromSeconds(kBubbleShowTimeoutSec), this, &SettingLevelBubble::OnTimeout); } void SettingLevelBubble::HideBubble() { if (bubble_) bubble_->Close(); } void SettingLevelBubble::UpdateWithoutShowingBubble(int percent) { percent = LimitPercent(percent); previous_percent_ = animation_.is_animating() ? animation_.GetCurrentValue() : current_percent_; if (previous_percent_ < 0) previous_percent_ = percent; current_percent_ = percent; if (animation_.is_animating()) animation_.End(); animation_.Reset(); animation_.Show(); } void SettingLevelBubble::OnTimeout() { HideBubble(); } void SettingLevelBubble::BubbleClosing(Bubble* bubble, bool) { DCHECK(bubble == bubble_); timeout_timer_.Stop(); animation_.Stop(); bubble_ = NULL; view_ = NULL; } void SettingLevelBubble::AnimationEnded(const ui::Animation* animation) { previous_percent_ = current_percent_; } void SettingLevelBubble::AnimationProgressed(const ui::Animation* animation) { if (view_) { view_->Update( ui::Tween::ValueBetween(animation->GetCurrentValue(), previous_percent_, current_percent_)); } } } // namespace chromeos