Chromium Code Reviews| Index: chrome/browser/ui/views/backspace_new_shortcut_bubble.cc |
| diff --git a/chrome/browser/ui/views/backspace_new_shortcut_bubble.cc b/chrome/browser/ui/views/backspace_new_shortcut_bubble.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2fc762b827b860d6b094024e05220c209b6fcfb6 |
| --- /dev/null |
| +++ b/chrome/browser/ui/views/backspace_new_shortcut_bubble.cc |
| @@ -0,0 +1,174 @@ |
| +// Copyright 2016 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/ui/views/backspace_new_shortcut_bubble.h" |
| + |
| +#include <utility> |
| + |
| +#include "base/macros.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "build/build_config.h" |
| +#include "chrome/app/chrome_command_ids.h" |
| +#include "chrome/browser/chrome_notification_types.h" |
| +#include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h" |
| +#include "chrome/browser/ui/views/frame/top_container_view.h" |
| +#include "chrome/browser/ui/views/subtle_notification_view.h" |
| +#include "chrome/grit/generated_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/gfx/animation/animation.h" |
| +#include "ui/gfx/animation/slide_animation.h" |
| +#include "ui/gfx/geometry/rect.h" |
| +#include "ui/strings/grit/ui_strings.h" |
| +#include "ui/views/bubble/bubble_border.h" |
| +#include "ui/views/view.h" |
| +#include "ui/views/widget/widget.h" |
| + |
| +#if defined(OS_WIN) |
| +#include "ui/base/l10n/l10n_util_win.h" |
| +#endif |
|
Peter Kasting
2016/05/19 10:08:36
Doesn't seem like this is used.
Check other #incl
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + |
| +namespace { |
| + |
| +const int kPopupTopPx = 45; |
| +const int kSlideInDurationMs = 350; |
| +const int kSlideOutDurationMs = 700; |
| +const int kShowDurationMs = 3800; |
| + |
| +} |
| + |
| +BackspaceNewShortcutBubble::BackspaceNewShortcutBubble( |
| + ExclusiveAccessBubbleViewsContext* context, |
| + bool forward) |
| + : bubble_view_context_(context), |
| + popup_(nullptr), |
| + animation_(new gfx::SlideAnimation(this)) { |
| + // Initially hide the bubble. |
| + double initial_value = 0; |
| + animation_->Reset(initial_value); |
| + |
| + // Create the contents view. |
| + view_ = new SubtleNotificationView(nullptr); |
| + UpdateViewContent(forward); |
| + |
| + // Initialize the popup. |
| + popup_ = SubtleNotificationView::CreatePopupWidget( |
| + bubble_view_context_->GetBubbleParentView(), view_, false); |
| + gfx::Size size = GetPopupRect(true).size(); |
| + // Bounds are in screen coordinates. |
| + popup_->SetBounds(GetPopupRect(false)); |
| + view_->SetBounds(0, 0, size.width(), size.height()); |
|
Peter Kasting
2016/05/19 10:08:36
Nit: Can we just do view_->SetSize(size) like Upda
Matt Giuca
2016/05/23 04:22:56
Actually this was all duplicated with UpdateConten
|
| + |
| + Show(); |
| + |
| + // Do not allow the notification to hide for a few seconds. |
|
Peter Kasting
2016/05/19 10:08:36
Nit: "Wait a few seconds before hiding"? After al
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + hide_timeout_.Start(FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kShowDurationMs), this, |
| + &BackspaceNewShortcutBubble::TimerElapsed); |
| +} |
| + |
| +BackspaceNewShortcutBubble::~BackspaceNewShortcutBubble() { |
| + // 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 set the popup's ownership |
| + // model to NATIVE_WIDGET_OWNS_WIDGET because if the user closed the last tab |
| + // while in fullscreen mode, Windows has already destroyed the popup HWND by |
|
Peter Kasting
2016/05/19 10:08:36
Is this all still relevant, given that this bubble
Matt Giuca
2016/05/23 04:22:57
I have no idea what the consequences of not doing
|
| + // 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(); |
| + base::MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::UpdateContent(bool forward) { |
| + UpdateViewContent(forward); |
| + |
| + gfx::Size size = GetPopupRect(true).size(); |
|
Peter Kasting
2016/05/19 10:08:36
Nit: I'd just inline thie into the next line.
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + view_->SetSize(size); |
| + popup_->SetBounds(GetPopupRect(false)); |
| + Show(); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::UpdateBounds() { |
|
Peter Kasting
2016/05/19 10:08:36
Who calls this method? It seems unused.
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + gfx::Rect popup_rect(GetPopupRect(false)); |
| + if (!popup_rect.IsEmpty()) { |
| + popup_->SetBounds(popup_rect); |
| + view_->SetY(popup_rect.height() - view_->height()); |
| + } |
| +} |
| + |
| +void BackspaceNewShortcutBubble::UpdateViewContent(bool forward) { |
| + base::string16 exit_instruction_text; |
|
Peter Kasting
2016/05/19 10:08:36
Nit: Declare this down as close to initialization
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + // Note: The key names are parameters so that we can vary by operating system |
| + // or change the direction of the arrow as necessary (see |
| + // https://crbug.com/612685). |
| + |
| +#if defined(OS_MACOSX) |
| + // U+2318 = PLACE OF INTEREST SIGN (Mac Command symbol). |
| + base::string16 accelerator = base::WideToUTF16(L"\x2318"); |
| +#else |
| + base::string16 accelerator = l10n_util::GetStringUTF16(IDS_APP_ALT_KEY); |
| +#endif |
| + |
| + if (forward) { |
| + // U+2192 = RIGHTWARDS ARROW. |
| + exit_instruction_text = |
| + l10n_util::GetStringFUTF16(IDS_PRESS_ALT_RIGHT_TO_GO_FORWARD, |
| + accelerator, base::WideToUTF16(L"\x2192")); |
| + } else { |
| + // U+2190 = LEFTWARDS ARROW. |
| + exit_instruction_text = |
| + l10n_util::GetStringFUTF16(IDS_PRESS_ALT_LEFT_TO_GO_BACK, accelerator, |
| + base::WideToUTF16(L"\x2190")); |
| + } |
|
Peter Kasting
2016/05/19 10:08:36
Nit: Shorter:
// U+2192 = RIGHTWARDS ARROW; U+2
Matt Giuca
2016/05/23 04:22:57
Not a fan of a 5-line expression with multiple ter
|
| + view_->UpdateContent(exit_instruction_text, base::string16()); |
| +} |
| + |
| +views::View* BackspaceNewShortcutBubble::GetBrowserRootView() const { |
|
Peter Kasting
2016/05/19 10:08:36
Another unused function?
Matt Giuca
2016/05/23 04:22:57
Done.
|
| + return bubble_view_context_->GetBubbleAssociatedWidget()->GetRootView(); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::AnimationProgressed( |
| + const gfx::Animation* animation) { |
| + int opacity = animation_->CurrentValueBetween(0, 255); |
| + if (opacity == 0) { |
| + popup_->Hide(); |
| + } else { |
| + popup_->Show(); |
| + popup_->SetOpacity(opacity); |
| + } |
| +} |
| + |
| +void BackspaceNewShortcutBubble::AnimationEnded( |
| + const gfx::Animation* animation) { |
| + AnimationProgressed(animation); |
| +} |
| + |
| +gfx::Rect BackspaceNewShortcutBubble::GetPopupRect( |
| + bool ignore_animation_state) const { |
| + gfx::Size size(view_->GetPreferredSize()); |
|
Peter Kasting
2016/05/19 10:08:36
Nit: Use = rather than () where possible
Matt Giuca
2016/05/23 04:22:56
Done.
|
| + gfx::Rect widget_bounds = bubble_view_context_->GetClientAreaBoundsInScreen(); |
| + int x = widget_bounds.x() + (widget_bounds.width() - size.width()) / 2; |
| + int top_container_bottom = widget_bounds.y(); |
| + // |desired_top| is the top of the bubble area including the shadow. |
| + int desired_top = kPopupTopPx - view_->border()->GetInsets().top(); |
| + int y = top_container_bottom + desired_top; |
| + return gfx::Rect(gfx::Point(x, y), size); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::Hide() { |
| + animation_->SetSlideDuration(kSlideOutDurationMs); |
| + animation_->Hide(); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::Show() { |
| + animation_->SetSlideDuration(kSlideInDurationMs); |
| + animation_->Show(); |
| +} |
| + |
| +void BackspaceNewShortcutBubble::TimerElapsed() { |
| + Hide(); |
| +} |