| Index: chrome/browser/chromeos/setting_level_bubble_view_views.cc
|
| diff --git a/chrome/browser/chromeos/setting_level_bubble_view_views.cc b/chrome/browser/chromeos/setting_level_bubble_view_views.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..00c45eb9233a9fa43b34ccb094a6eca4def913a3
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/setting_level_bubble_view_views.cc
|
| @@ -0,0 +1,257 @@
|
| +// 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_view_views.h"
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "chrome/browser/chromeos/login/background_view.h"
|
| +#include "chrome/browser/chromeos/login/login_utils.h"
|
| +#include "chrome/browser/chromeos/login/webui_login_display.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" // for kBackgroundColor
|
| +#include "ui/gfx/screen.h"
|
| +#include "views/widget/root_view.h"
|
| +
|
| +using base::TimeDelta;
|
| +using base::TimeTicks;
|
| +using std::max;
|
| +using std::min;
|
| +
|
| +namespace {
|
| +
|
| +// How long should the bubble be shown onscreen whenever the setting changes?
|
| +const int kBubbleShowTimeoutMs = 1000;
|
| +
|
| +// How long should the level initially take to move up or down when it changes?
|
| +// (The rate adapts to handle keyboard autorepeat.)
|
| +const int64 kInitialAnimationDurationMs = 200;
|
| +
|
| +// Horizontal position of the center of the bubble on the screen: 0 is left
|
| +// edge, 0.5 is center, 1 is right edge.
|
| +const double kBubbleXRatio = 0.5;
|
| +
|
| +// Vertical gap from the bottom of the screen in pixels.
|
| +const int kBubbleBottomGap = 30;
|
| +
|
| +// Duration between animation frames.
|
| +// Chosen to match ui::SlideAnimation's kDefaultFramerateHz.
|
| +const int kAnimationIntervalMs = 1000 / 50;
|
| +
|
| +double LimitPercent(double percent) {
|
| + return min(max(percent, 0.0), 100.0);
|
| +}
|
| +
|
| +} // 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() {
|
| +#if defined(USE_AURA)
|
| + // TODO(saintlou): Need to fix in PureViews..... how?
|
| + return WebUILoginDisplay::GetLoginWindow();
|
| +#else
|
| + 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::FindTabbedBrowser(
|
| + ProfileManager::GetDefaultProfile(),
|
| + 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 views::Widget::GetWidgetForNativeWindow(window);
|
| + else
|
| + return WebUILoginDisplay::GetLoginWindow();
|
| +#endif
|
| +}
|
| +
|
| +// SettingLevelBubbleViewViews -------------------------------------------------
|
| +// static
|
| +views::Widget* SettingLevelBubbleViewViews::ConstructSettingLevelBubble(
|
| + SkBitmap* increase_icon,
|
| + SkBitmap* decrease_icon,
|
| + SkBitmap* zero_icon,
|
| + double percent,
|
| + bool enabled) {
|
| + views::Widget* parent = GetToplevelWidget();
|
| + SettingLevelBubbleViewViews* delegate =
|
| + new SettingLevelBubbleViewViews(increase_icon, decrease_icon, zero_icon);
|
| + delegate->UpdateSettingLevel(percent, enabled);
|
| + // Construct and initialize settings.
|
| + return views::BubbleDelegateView::ConstructBubble(delegate, parent);
|
| +}
|
| +
|
| +SettingLevelBubbleViewViews::SettingLevelBubbleViewViews(
|
| + SkBitmap* increase_icon,
|
| + SkBitmap* decrease_icon,
|
| + SkBitmap* disabled_icon)
|
| + : current_percent_(-1.0),
|
| + target_percent_(-1.0),
|
| + increase_icon_(increase_icon),
|
| + decrease_icon_(decrease_icon),
|
| + disabled_icon_(disabled_icon),
|
| + current_icon_(NULL),
|
| + enabled_(false),
|
| + view_(NULL),
|
| + is_animating_(false) {
|
| +}
|
| +
|
| +SettingLevelBubbleViewViews::~SettingLevelBubbleViewViews() {
|
| + WindowClosing();
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::Init() {
|
| + SettingLevelBubbleView* view = new SettingLevelBubbleView();
|
| + view->SetIcon(current_icon_);
|
| + view->SetEnabled(enabled_);
|
| +
|
| + // Calculate the position in screen coordinates that the bubble should
|
| + // "point" at (since we use BubbleBorder::FLOAT, this position actually
|
| + // specifies the center of the bubble).
|
| + const gfx::Rect monitor_area =
|
| + gfx::Screen::GetMonitorAreaNearestWindow(
|
| + GetWidget()->GetTopLevelWidget()->GetNativeView());
|
| + const gfx::Size view_size = view->GetPreferredSize();
|
| + position_relative_to_ = gfx::Rect(
|
| + monitor_area.x() + kBubbleXRatio * monitor_area.width(),
|
| + monitor_area.bottom() - view_size.height() / 2 - kBubbleBottomGap,
|
| + 0, 0);
|
| + view->Init(current_icon_, current_percent_, enabled_);
|
| + AddChildView(view);
|
| +}
|
| +
|
| +views::BubbleBorder::ArrowLocation
|
| +SettingLevelBubbleViewViews::GetArrowLocation() const {
|
| + return views::BubbleBorder::FLOAT;
|
| +}
|
| +
|
| +SkColor SettingLevelBubbleViewViews::GetColor() const {
|
| + return Bubble::kBackgroundColor;
|
| +}
|
| +
|
| +bool SettingLevelBubbleViewViews::GetEnableAccelerator() const {
|
| + return false;
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::WindowClosing() {
|
| + StopAnimation();
|
| + current_percent_ = target_percent_;
|
| + target_time_ = TimeTicks();
|
| + last_animation_update_time_ = TimeTicks();
|
| + last_target_update_time_ = TimeTicks();
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::UpdateSettingLevel(double percent,
|
| + bool enabled) {
|
| + enabled_ = enabled;
|
| + const double old_target_percent = target_percent_;
|
| + UpdateTargetPercent(percent);
|
| + current_icon_ = increase_icon_;
|
| + if (!enabled || target_percent_ == 0)
|
| + current_icon_ = disabled_icon_;
|
| + else if (old_target_percent >= 0 && target_percent_ < old_target_percent)
|
| + current_icon_ = decrease_icon_;
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::UpdateWithoutShowingBubble(
|
| + double percent,
|
| + bool enabled) {
|
| + UpdateTargetPercent(percent);
|
| + if (view_)
|
| + view_->SetEnabled(enabled);
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::StartHideTimer() {
|
| + hide_timer_.Stop();
|
| + hide_timer_.Start(FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(kBubbleShowTimeoutMs),
|
| + this, &SettingLevelBubbleViewViews::OnHideTimeout);
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::OnHideTimeout() {
|
| + GetWidget()->Close();
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::OnAnimationTimeout() {
|
| + const TimeTicks now = TimeTicks::Now();
|
| + const int64 remaining_ms = (target_time_ - now).InMilliseconds();
|
| +
|
| + if (remaining_ms <= 0) {
|
| + current_percent_ = target_percent_;
|
| + StopAnimation();
|
| + } else {
|
| + // Figure out what fraction of the total time until we want to reach the
|
| + // target has elapsed since the last update.
|
| + const double remaining_percent = target_percent_ - current_percent_;
|
| + const int64 elapsed_ms =
|
| + (now - last_animation_update_time_).InMilliseconds();
|
| + current_percent_ +=
|
| + remaining_percent *
|
| + (static_cast<double>(elapsed_ms) / (elapsed_ms + remaining_ms));
|
| + }
|
| + last_animation_update_time_ = now;
|
| +
|
| + if (view_)
|
| + view_->SetLevel(current_percent_);
|
| +}
|
| +
|
| +
|
| +void SettingLevelBubbleViewViews::UpdateTargetPercent(double percent) {
|
| + target_percent_ = LimitPercent(percent);
|
| + const TimeTicks now = TimeTicks::Now();
|
| +
|
| + if (current_percent_ < 0.0) {
|
| + // If we're setting the level for the first time, no need to animate.
|
| + current_percent_ = target_percent_;
|
| + if (view_)
|
| + view_->SetLevel(current_percent_);
|
| + } else {
|
| + // Use the time since the last request as a hint for the duration of the
|
| + // animation. This makes us automatically adapt to the repeat rate if a key
|
| + // is being held down to change a setting (which prevents us from lagging
|
| + // behind when the key is finally released).
|
| + int64 duration_ms = kInitialAnimationDurationMs;
|
| + if (!last_target_update_time_.is_null())
|
| + duration_ms = min(kInitialAnimationDurationMs,
|
| + (now - last_target_update_time_).InMilliseconds());
|
| + target_time_ = now + TimeDelta::FromMilliseconds(duration_ms);
|
| +
|
| + if (!is_animating_) {
|
| + animation_timer_.Start(FROM_HERE,
|
| + TimeDelta::FromMilliseconds(kAnimationIntervalMs),
|
| + this,
|
| + &SettingLevelBubbleViewViews::OnAnimationTimeout);
|
| + is_animating_ = true;
|
| + last_animation_update_time_ = now;
|
| + }
|
| + }
|
| +
|
| + last_target_update_time_ = now;
|
| +}
|
| +
|
| +void SettingLevelBubbleViewViews::StopAnimation() {
|
| + animation_timer_.Stop();
|
| + is_animating_ = false;
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|