| Index: chrome/browser/views/fullscreen_exit_bubble.cc
|
| ===================================================================
|
| --- chrome/browser/views/fullscreen_exit_bubble.cc (revision 0)
|
| +++ chrome/browser/views/fullscreen_exit_bubble.cc (revision 0)
|
| @@ -0,0 +1,219 @@
|
| +// Copyright (c) 2009 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/views/fullscreen_exit_bubble.h"
|
| +
|
| +#include "chrome/app/chrome_dll_resource.h"
|
| +#include "chrome/common/l10n_util.h"
|
| +#include "chrome/common/resource_bundle.h"
|
| +#include "chrome/views/root_view.h"
|
| +#include "grit/generated_resources.h"
|
| +
|
| +
|
| +// FullscreenExitView ----------------------------------------------------------
|
| +
|
| +class FullscreenExitBubble::FullscreenExitView : public views::View {
|
| + public:
|
| + FullscreenExitView(FullscreenExitBubble* bubble,
|
| + views::WidgetWin* popup,
|
| + const std::wstring& accelerator);
|
| + virtual ~FullscreenExitView();
|
| +
|
| + // views::View
|
| + virtual gfx::Size GetPreferredSize();
|
| +
|
| + private:
|
| + static const int kPaddingPixels; // Number of pixels around all sides of link
|
| +
|
| + // views::View
|
| + virtual void Layout();
|
| + virtual void Paint(ChromeCanvas* canvas);
|
| +
|
| + // Handle to the HWND that contains us.
|
| + views::WidgetWin* popup_;
|
| +
|
| + // Clickable hint text to show in the bubble.
|
| + views::Link link_;
|
| +};
|
| +
|
| +const int FullscreenExitBubble::FullscreenExitView::kPaddingPixels = 8;
|
| +
|
| +FullscreenExitBubble::FullscreenExitView::FullscreenExitView(
|
| + FullscreenExitBubble* bubble,
|
| + views::WidgetWin* popup,
|
| + const std::wstring& accelerator)
|
| + : popup_(popup) {
|
| + AddChildView(&link_);
|
| + link_.SetParentOwned(false);
|
| + link_.SetText(l10n_util::GetStringF(IDS_EXIT_FULLSCREEN_MODE, accelerator));
|
| + link_.SetController(bubble);
|
| + link_.SetFont(ResourceBundle::GetSharedInstance().GetFont(
|
| + ResourceBundle::LargeFont));
|
| + link_.SetNormalColor(SK_ColorWHITE);
|
| + link_.SetHighlightedColor(SK_ColorWHITE);
|
| +}
|
| +
|
| +FullscreenExitBubble::FullscreenExitView::~FullscreenExitView() {
|
| +}
|
| +
|
| +gfx::Size FullscreenExitBubble::FullscreenExitView::GetPreferredSize() {
|
| + gfx::Size preferred_size(link_.GetPreferredSize());
|
| + preferred_size.Enlarge(kPaddingPixels * 2, kPaddingPixels * 2);
|
| + return preferred_size;
|
| +}
|
| +
|
| +void FullscreenExitBubble::FullscreenExitView::Layout() {
|
| + gfx::Size link_preferred_size(link_.GetPreferredSize());
|
| + link_.SetBounds(kPaddingPixels,
|
| + height() - kPaddingPixels - link_preferred_size.height(),
|
| + link_preferred_size.width(), link_preferred_size.height());
|
| +}
|
| +
|
| +void FullscreenExitBubble::FullscreenExitView::Paint(ChromeCanvas* canvas) {
|
| + // Create a round-bottomed rect to fill the whole View.
|
| + CRect parent_rect;
|
| + SkRect rect;
|
| + SkScalar padding = SkIntToScalar(kPaddingPixels);
|
| + // The "-padding" top coordinate ensures that the rect is always tall enough
|
| + // to contain the complete rounded corner radius. If we set this to 0, as the
|
| + // popup slides offscreen (in reality, squishes to 0 height), the corners will
|
| + // flatten out as the height becomes less than the corner radius.
|
| + rect.set(0, -padding, SkIntToScalar(width()), SkIntToScalar(height()));
|
| + SkScalar rad[8] = { 0, 0, 0, 0, padding, padding, padding, padding };
|
| + SkPath path;
|
| + path.addRoundRect(rect, rad, SkPath::kCW_Direction);
|
| +
|
| + // Fill it black.
|
| + SkPaint paint;
|
| + paint.setStyle(SkPaint::kFill_Style);
|
| + paint.setFlags(SkPaint::kAntiAlias_Flag);
|
| + paint.setColor(SK_ColorBLACK);
|
| + canvas->drawPath(path, paint);
|
| +}
|
| +
|
| +
|
| +// FullscreenExitBubble --------------------------------------------------------
|
| +
|
| +const double FullscreenExitBubble::kOpacity = 0.7;
|
| +const int FullscreenExitBubble::kInitialDelayMs = 2300;
|
| +const int FullscreenExitBubble::kPositionCheckHz = 10;
|
| +const int FullscreenExitBubble::kSlideInRegionHeightPx = 4;
|
| +const int FullscreenExitBubble::kSlideInDurationMs = 350;
|
| +const int FullscreenExitBubble::kSlideOutDurationMs = 700;
|
| +
|
| +FullscreenExitBubble::FullscreenExitBubble(
|
| + views::Widget* frame,
|
| + CommandUpdater::CommandUpdaterDelegate* delegate)
|
| + : root_view_(frame->GetRootView()),
|
| + delegate_(delegate),
|
| + popup_(new views::WidgetWin()),
|
| + size_animation_(new SlideAnimation(this)) {
|
| + size_animation_->Reset(1);
|
| +
|
| + // Create the contents view.
|
| + views::Accelerator accelerator(0, false, false, false);
|
| + bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator);
|
| + DCHECK(got_accelerator);
|
| + view_ = new FullscreenExitView(this, popup_, accelerator.GetShortcutText());
|
| +
|
| + // Initialize the popup.
|
| + popup_->set_delete_on_destroy(false);
|
| + popup_->set_window_style(WS_POPUP);
|
| + popup_->set_window_ex_style(WS_EX_LAYERED | WS_EX_TOOLWINDOW |
|
| + l10n_util::GetExtendedTooltipStyles());
|
| + popup_->SetLayeredAlpha(static_cast<int>(0xff * kOpacity));
|
| + popup_->Init(frame->GetHWND(), GetPopupRect(false), false);
|
| + popup_->SetContentsView(view_);
|
| + popup_->Show();
|
| +
|
| + // Start the initial delay timer.
|
| + initial_delay_.Start(base::TimeDelta::FromMilliseconds(kInitialDelayMs), this,
|
| + &FullscreenExitBubble::AfterInitialDelay);
|
| +}
|
| +
|
| +FullscreenExitBubble::~FullscreenExitBubble() {
|
| + // This is tricky. We may be in an ATL message handler stack, in which case
|
| + // the popup cannot be deleted yet. We also can't blindly use
|
| + // set_delete_on_destroy(true) on the popup to delete it when it closes,
|
| + // because if the user closed the last tab while in fullscreen mode, Windows
|
| + // has already destroyed the popup HWND by the time we get here, and thus
|
| + // either the popup will already have been deleted (if we set this in our
|
| + // constructor) or the popup will never get another OnFinalMessage() call (if
|
| + // not, as currently). So instead, we tell the popup to synchronously hide,
|
| + // and then asynchronously close and delete itself.
|
| + popup_->Close();
|
| + MessageLoop::current()->DeleteSoon(FROM_HERE, popup_);
|
| +}
|
| +
|
| +void FullscreenExitBubble::LinkActivated(views::Link* source, int event_flags) {
|
| + delegate_->ExecuteCommand(IDC_FULLSCREEN);
|
| +}
|
| +
|
| +void FullscreenExitBubble::AnimationProgressed(
|
| + const Animation* animation) {
|
| + gfx::Rect popup_rect(GetPopupRect(false));
|
| + if (popup_rect.IsEmpty()) {
|
| + popup_->Hide();
|
| + } else {
|
| + popup_->MoveWindow(popup_rect.x(), popup_rect.y(), popup_rect.width(),
|
| + popup_rect.height());
|
| + popup_->Show();
|
| + }
|
| +}
|
| +void FullscreenExitBubble::AnimationEnded(
|
| + const Animation* animation) {
|
| + AnimationProgressed(animation);
|
| +}
|
| +
|
| +void FullscreenExitBubble::AfterInitialDelay() {
|
| + // Check the mouse position immediately and every 50 ms afterwards.
|
| + CheckMousePosition();
|
| + mouse_position_checker_.Start(
|
| + base::TimeDelta::FromMilliseconds(1000 / kPositionCheckHz), this,
|
| + &FullscreenExitBubble::CheckMousePosition);
|
| +}
|
| +
|
| +void FullscreenExitBubble::CheckMousePosition() {
|
| + // Desired behavior:
|
| + //
|
| + // +------------+-----------------------------+------------+
|
| + // | _ _ _ _ | Exit full screen mode (F11) | _ _ _ _ | Slide-in region
|
| + // | _ _ _ _ \_____________________________/ _ _ _ _ | Neutral region
|
| + // | | Slide-out region
|
| + // : :
|
| + //
|
| + // * If the mouse is in the slide-in region, we show the popup.
|
| + // * If the mouse is in the slide-out region, we hide the popup.
|
| + // * If the mouse is in the neutral region, we do nothing, except if the popup
|
| + // is currently sliding out, in which case we show it again. This
|
| + // facilitates users correcting us if they try to mouse horizontally towards
|
| + // the popup and unintentionally drop too low.
|
| +
|
| + POINT cursor_pos;
|
| + GetCursorPos(&cursor_pos);
|
| + gfx::Point transformed_pos(cursor_pos);
|
| + views::View::ConvertPointToView(NULL, root_view_, &transformed_pos);
|
| + gfx::Rect trigger_rect(GetPopupRect(true));
|
| + if (!root_view_->HitTest(transformed_pos) ||
|
| + (cursor_pos.y >= trigger_rect.bottom())) {
|
| + size_animation_->SetSlideDuration(kSlideOutDurationMs);
|
| + size_animation_->Hide();
|
| + } else if ((cursor_pos.y < kSlideInRegionHeightPx) ||
|
| + (size_animation_->GetCurrentValue() != 0)) {
|
| + size_animation_->SetSlideDuration(kSlideInDurationMs);
|
| + size_animation_->Show();
|
| + }
|
| +}
|
| +
|
| +gfx::Rect FullscreenExitBubble::GetPopupRect(
|
| + bool ignore_animation_state) const {
|
| + gfx::Size size(view_->GetPreferredSize());
|
| + if (!ignore_animation_state) {
|
| + size.set_height(static_cast<int>(static_cast<double>(size.height()) *
|
| + size_animation_->GetCurrentValue()));
|
| + }
|
| + gfx::Point origin((root_view_->width() - size.width()) / 2, 0);
|
| + views::View::ConvertPointToScreen(root_view_, &origin);
|
| + return gfx::Rect(origin, size);
|
| +}
|
|
|
| Property changes on: chrome\browser\views\fullscreen_exit_bubble.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|