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 |