Index: chrome/browser/ui/views/first_run_bubble_view_views.cc |
diff --git a/chrome/browser/ui/views/first_run_bubble_view_views.cc b/chrome/browser/ui/views/first_run_bubble_view_views.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cdab57bcbcdd388c7c05ae1acd6dd53891cee812 |
--- /dev/null |
+++ b/chrome/browser/ui/views/first_run_bubble_view_views.cc |
@@ -0,0 +1,542 @@ |
+// 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/ui/views/first_run_bubble_view_views.h" |
+ |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/first_run/first_run.h" |
+#include "chrome/browser/search_engines/util.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/first_run_bubble.h" |
+#include "content/browser/user_metrics.h" |
+#include "grit/chromium_strings.h" |
+#include "grit/generated_resources.h" |
+#include "grit/locale_settings.h" |
+#include "grit/theme_resources_standard.h" |
+#include "ui/base/l10n/l10n_font_util.h" |
+#include "ui/base/l10n/l10n_util.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "views/bubble/bubble_view.h" |
+#include "views/controls/button/image_button.h" |
+#include "views/controls/button/text_button.h" |
+#include "views/controls/label.h" |
+#include "views/events/event.h" |
+#include "views/focus/focus_manager.h" |
+#include "views/layout/layout_constants.h" |
+ |
+namespace { |
+ |
+// How much extra padding to put around our content over what the Bubble |
+// provides. |
+const int kBubblePadding = 4; |
+ |
+// How much extra padding to put around our content over what the Bubble |
+// provides in alternative OEM bubble. |
+const int kOEMBubblePadding = 4; |
+ |
+// Padding between parts of strings on the same line (for instance, |
+// "New!" and "Search from the address bar!" |
+const int kStringSeparationPadding = 2; |
+ |
+// Margin around close button. |
+const int kMarginRightOfCloseButton = 7; |
+ |
+} // namespace |
+ |
+// FirstRunBubbleViewViews------------------------------------------------------ |
+FirstRunBubbleViewViews::FirstRunBubbleViewViews( |
+ Profile* profile, |
+ views::Widget* parent, |
+ const gfx::Rect& position_relative_to, |
+ views::BubbleBorder::ArrowLocation arrow_location) |
+ : BubbleDelegateView(parent), |
+ profile_(profile), |
+ parent_(parent), |
+ position_relative_to_(position_relative_to), |
+ arrow_location_(arrow_location) {} |
+ |
+views::View* FirstRunBubbleViewViews::GetContentsView() { |
+ return new FirstRunBubbleView(parent_, profile_); |
+} |
+ |
+FirstRunBubbleViewViews::~FirstRunBubbleViewViews() { |
+} |
+ |
+views::BubbleBorder::ArrowLocation |
+FirstRunBubbleViewViews::GetFrameArrowLocation() { |
+ return arrow_location_; |
+} |
+ |
+SkColor FirstRunBubbleViewViews::GetFrameBackgroundColor() { |
+ return SK_ColorWHITE; |
+} |
+ |
+gfx::Rect FirstRunBubbleViewViews::GetBounds() { |
+ gfx::Size content_size = |
+ gfx::Size(views::Widget::GetLocalizedContentsSize( |
+ IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS, |
+ IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES)); |
+ return gfx::Rect(position_relative_to_.x(), |
+ position_relative_to_.y(), |
+ content_size.width() + kBubblePadding * 2, |
+ content_size.height() + kBubblePadding * 2); |
+} |
+ |
+// FirstRunBubbleView --------------------------------------------------------- |
+FirstRunBubbleView::FirstRunBubbleView(views::Widget* widget, |
+ Profile* profile) |
+ : widget_(widget), |
+ label1_(NULL), |
+ label2_(NULL), |
+ label3_(NULL), |
+ change_button_(NULL), |
+ keep_button_(NULL), |
+ profile_(profile) { |
+ const gfx::Font& font = |
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont); |
+ |
+ label1_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_TITLE)); |
+ label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); |
+ label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ AddChildView(label1_); |
+ |
+ gfx::Size ps = GetPreferredSize(); |
+ |
+ label2_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT)); |
+ label2_->SetMultiLine(true); |
+ label2_->SetFont(font); |
+ label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ label2_->SizeToFit(ps.width() - kBubblePadding * 2); |
+ AddChildView(label2_); |
+ |
+ string16 question_str = l10n_util::GetStringFUTF16( |
+ IDS_FR_BUBBLE_QUESTION, |
+ GetDefaultSearchEngineName(profile)); |
+ label3_ = new views::Label(question_str); |
+ label3_->SetMultiLine(true); |
+ label3_->SetFont(font); |
+ label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ label3_->SizeToFit(ps.width() - kBubblePadding * 2); |
+ AddChildView(label3_); |
+ |
+ std::wstring keep_str = UTF16ToWide(l10n_util::GetStringFUTF16( |
+ IDS_FR_BUBBLE_OK, |
+ GetDefaultSearchEngineName(profile))); |
+ keep_button_ = new views::NativeTextButton(this, keep_str); |
+ keep_button_->SetIsDefault(true); |
+ AddChildView(keep_button_); |
+ |
+ std::wstring change_str = |
+ UTF16ToWide(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_CHANGE)); |
+ change_button_ = new views::NativeTextButton(this, change_str); |
+ AddChildView(change_button_); |
+} |
+ |
+FirstRunBubbleView::~FirstRunBubbleView() { |
+ GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this); |
+} |
+ |
+void FirstRunBubbleView::ButtonPressed(views::Button* sender, |
+ const views::Event& event) { |
+ UserMetrics::RecordAction(UserMetricsAction("FirstRunBubbleView_Clicked")); |
+ // Do I need a delegate? |
+ // GetWidget()->client_view()->AsBubbleView()->set_animation_delegate(this); |
+ GetWidget()->client_view()->AsBubbleView()->StartFade(); |
+ GetWidget()->Close(); |
+ if (change_button_ == sender) { |
+ UserMetrics::RecordAction( |
+ UserMetricsAction("FirstRunBubbleView_ChangeButton")); |
+ |
+ Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); |
+ if (browser) { |
+ browser->OpenSearchEngineOptionsDialog(); |
+ } |
+ } |
+} |
+ |
+void FirstRunBubbleView::BubbleShown() { |
+ keep_button_->RequestFocus(); |
+} |
+ |
+void FirstRunBubbleView::Layout() { |
+ gfx::Size canvas = GetPreferredSize(); |
+ |
+ // The multiline business that follows is dirty hacks to get around |
+ // bug 1325257. |
+ label1_->SetMultiLine(false); |
+ gfx::Size pref_size = label1_->GetPreferredSize(); |
+ label1_->SetMultiLine(true); |
+ label1_->SizeToFit(canvas.width() - kBubblePadding * 2); |
+ label1_->SetBounds(kBubblePadding, kBubblePadding, |
+ canvas.width() - kBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ int next_v_space = label1_->y() + pref_size.height() + |
+ views::kRelatedControlSmallVerticalSpacing; |
+ |
+ pref_size = label2_->GetPreferredSize(); |
+ label2_->SetBounds(kBubblePadding, next_v_space, |
+ canvas.width() - kBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ next_v_space = label2_->y() + label2_->height() + |
+ views::kPanelSubVerticalSpacing; |
+ |
+ pref_size = label3_->GetPreferredSize(); |
+ label3_->SetBounds(kBubblePadding, next_v_space, |
+ canvas.width() - kBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ pref_size = change_button_->GetPreferredSize(); |
+ change_button_->SetBounds( |
+ canvas.width() - pref_size.width() - kBubblePadding, |
+ canvas.height() - pref_size.height() - views::kButtonVEdgeMargin, |
+ pref_size.width(), pref_size.height()); |
+ |
+ pref_size = keep_button_->GetPreferredSize(); |
+ keep_button_->SetBounds(change_button_->x() - pref_size.width() - |
+ views::kRelatedButtonHSpacing, change_button_->y(), |
+ pref_size.width(), pref_size.height()); |
+} |
+ |
+gfx::Size FirstRunBubbleView::GetPreferredSize() { |
+ return gfx::Size(views::Widget::GetLocalizedContentsSize( |
+ IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS, |
+ IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES)); |
+} |
+ |
+void FirstRunBubbleView::FocusWillChange(View* focused_before, |
+ View* focused_now) { |
+ if (focused_before && |
+ (focused_before->GetClassName() == |
+ views::NativeTextButton::kViewClassName)) { |
+ views::NativeTextButton* before = |
+ static_cast<views::NativeTextButton*>(focused_before); |
+ before->SetIsDefault(false); |
+ } |
+ if (focused_now && |
+ (focused_now->GetClassName() == |
+ views::NativeTextButton::kViewClassName)) { |
+ views::NativeTextButton* after = |
+ static_cast<views::NativeTextButton*>(focused_now); |
+ after->SetIsDefault(true); |
+ } |
+} |
+ |
+// FirstRunOEMBubbleViewViews -------------------------------------------------- |
+FirstRunOEMBubbleViewViews::FirstRunOEMBubbleViewViews( |
+ Profile* profile, |
+ views::Widget* parent, |
+ const gfx::Rect& position_relative_to, |
+ views::BubbleBorder::ArrowLocation arrow_location) |
+ : BubbleDelegateView(parent), |
+ profile_(profile), |
+ parent_(parent), |
+ position_relative_to_(position_relative_to), |
+ arrow_location_(arrow_location) {} |
+ |
+views::View* FirstRunOEMBubbleViewViews::GetContentsView() { |
+ return new FirstRunOEMBubbleView(parent_, profile_); |
+} |
+ |
+FirstRunOEMBubbleViewViews::~FirstRunOEMBubbleViewViews() {} |
+ |
+views::BubbleBorder::ArrowLocation |
+FirstRunOEMBubbleViewViews::GetFrameArrowLocation() { |
+ return arrow_location_; |
+} |
+ |
+SkColor FirstRunOEMBubbleViewViews::GetFrameBackgroundColor() { |
+ return SK_ColorWHITE; |
+} |
+ |
+gfx::Rect FirstRunOEMBubbleViewViews::GetBounds() { |
+ gfx::Size content_size = |
+ gfx::Size(views::Widget::GetLocalizedContentsSize( |
+ IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS, |
+ IDS_FIRSTRUNOEMBUBBLE_DIALOG_HEIGHT_LINES)); |
+ return gfx::Rect(position_relative_to_.x(), |
+ position_relative_to_.y(), |
+ content_size.width() + kOEMBubblePadding * 2, |
+ content_size.height() + kOEMBubblePadding * 2); |
+} |
+ |
+// FirstRunOEMBubbleView ------------------------------------------------------ |
+FirstRunOEMBubbleView::FirstRunOEMBubbleView(views::Widget* widget, |
+ Profile* profile) |
+ : widget_(widget), |
+ label1_(NULL), |
+ label2_(NULL), |
+ label3_(NULL), |
+ close_button_(NULL), |
+ profile_(profile) { |
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
+ const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont); |
+ |
+ label1_ = new views::Label( |
+ l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_1)); |
+ label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); |
+ label1_->SetColor(SK_ColorRED); |
+ label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ AddChildView(label1_); |
+ |
+ label2_ = new views::Label( |
+ l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_2)); |
+ label2_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); |
+ label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ AddChildView(label2_); |
+ |
+ gfx::Size ps = GetPreferredSize(); |
+ |
+ label3_ = new views::Label( |
+ l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_SUBTEXT)); |
+ label3_->SetMultiLine(true); |
+ label3_->SetFont(font); |
+ label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ label3_->SizeToFit(ps.width() - kOEMBubblePadding * 2); |
+ AddChildView(label3_); |
+ |
+ close_button_ = new views::ImageButton(this); |
+ close_button_->SetImage(views::CustomButton::BS_NORMAL, |
+ rb.GetBitmapNamed(IDR_CLOSE_BAR)); |
+ close_button_->SetImage(views::CustomButton::BS_HOT, |
+ rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); |
+ close_button_->SetImage(views::CustomButton::BS_PUSHED, |
+ rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); |
+ |
+ AddChildView(close_button_); |
+} |
+ |
+FirstRunOEMBubbleView::~FirstRunOEMBubbleView() { |
+ GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this); |
+} |
+ |
+ |
+void FirstRunOEMBubbleView::ButtonPressed(views::Button* sender, |
+ const views::Event& event) { |
+ UserMetrics::RecordAction( |
+ UserMetricsAction("FirstRunOEMBubbleView_Clicked")); |
+ GetWidget()->client_view()->AsBubbleView()->StartFade(); |
+ GetWidget()->Close(); |
+} |
+ |
+void FirstRunOEMBubbleView::BubbleShown() { |
+ RequestFocus(); |
+} |
+ |
+void FirstRunOEMBubbleView::Layout() { |
+ gfx::Size canvas = GetPreferredSize(); |
+ |
+ // First, draw the close button on the far right. |
+ gfx::Size sz = close_button_->GetPreferredSize(); |
+ close_button_->SetBounds( |
+ canvas.width() - sz.width() - kMarginRightOfCloseButton, |
+ kOEMBubblePadding, sz.width(), sz.height()); |
+ |
+ gfx::Size pref_size = label1_->GetPreferredSize(); |
+ label1_->SetBounds(kOEMBubblePadding, kOEMBubblePadding, |
+ pref_size.width() + kOEMBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ pref_size = label2_->GetPreferredSize(); |
+ label2_->SetBounds( |
+ kOEMBubblePadding * 2 + label1_->GetPreferredSize().width(), |
+ kOEMBubblePadding, canvas.width() - kOEMBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ int next_v_space = |
+ label1_->y() + pref_size.height() + |
+ views::kRelatedControlSmallVerticalSpacing; |
+ |
+ pref_size = label3_->GetPreferredSize(); |
+ label3_->SetBounds(kOEMBubblePadding, next_v_space, |
+ canvas.width() - kOEMBubblePadding * 2, |
+ pref_size.height()); |
+} |
+ |
+gfx::Size FirstRunOEMBubbleView::GetPreferredSize() { |
+ // Calculate width based on font and text. |
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
+ const gfx::Font& font = rb.GetFont( |
+ ResourceBundle::MediumFont).DeriveFont(3, gfx::Font::BOLD); |
+ gfx::Size size = gfx::Size( |
+ ui::GetLocalizedContentsWidthForFont( |
+ IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS, font), |
+ ui::GetLocalizedContentsHeightForFont( |
+ IDS_FIRSTRUNOEMBUBBLE_DIALOG_HEIGHT_LINES, font)); |
+ |
+ // WARNING: HACK. Vista and XP calculate font size differently; this means |
+ // that a dialog box correctly proportioned for XP will appear too large in |
+ // Vista. The correct thing to do is to change font size calculations in |
+ // XP or Vista so that the length of a string is calculated properly. For |
+ // now, we force Vista to show a correctly-sized box by taking account of |
+ // the difference in font size calculation. The coefficient should not be |
+ // stored in a variable because it's a hack and should go away. |
+#ifdef NEVER |
+ if (views::NativeWidgetWin::IsAeroGlassEnabled()) { |
+ size.set_width(static_cast<int>(size.width() * 0.85)); |
+ size.set_height(static_cast<int>(size.height() * 0.85)); |
+ } |
+#endif |
+ return size; |
+} |
+ |
+void FirstRunOEMBubbleView::FocusWillChange(View* focused_before, |
+ View* focused_now) { |
+ // No buttons in oem_bubble to register focus changes. |
+} |
+ |
+// FirstRunMinimalBubbleViewViews ---------------------------------------------- |
+FirstRunMinimalBubbleViewViews::FirstRunMinimalBubbleViewViews( |
+ Profile* profile, |
+ views::Widget* parent, |
+ const gfx::Rect& position_relative_to, |
+ views::BubbleBorder::ArrowLocation arrow_location) |
+ : BubbleDelegateView(parent), |
+ profile_(profile), |
+ parent_(parent), |
+ position_relative_to_(position_relative_to), |
+ arrow_location_(arrow_location) {} |
+ |
+views::View* FirstRunMinimalBubbleViewViews::GetContentsView() { |
+ return new FirstRunMinimalBubbleView(parent_, profile_); |
+} |
+ |
+FirstRunMinimalBubbleViewViews::~FirstRunMinimalBubbleViewViews() { |
+} |
+ |
+views::BubbleBorder::ArrowLocation |
+FirstRunMinimalBubbleViewViews::GetFrameArrowLocation() { |
+ return arrow_location_; |
+} |
+ |
+SkColor FirstRunMinimalBubbleViewViews::GetFrameBackgroundColor() { |
+ return SK_ColorWHITE; |
+} |
+ |
+gfx::Rect FirstRunMinimalBubbleViewViews::GetBounds() { |
+ gfx::Size content_size = |
+ gfx::Size(views::Widget::GetLocalizedContentsSize( |
+ IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS, |
+ IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_HEIGHT_LINES)); |
+ return gfx::Rect(position_relative_to_.x(), |
+ position_relative_to_.y(), |
+ content_size.width() + 2, |
+ content_size.height() + 2); |
+} |
+ |
+// FirstRunMinimalBubbleView -------------------------------------------------- |
+FirstRunMinimalBubbleView::FirstRunMinimalBubbleView( |
+ views::Widget* widget, |
+ Profile* profile) |
+ : widget_(widget), |
+ label1_(NULL), |
+ label2_(NULL), |
+ profile_(profile) { |
+ const gfx::Font& font = |
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont); |
+ |
+ label1_ = new views::Label(l10n_util::GetStringFUTF16( |
+ IDS_FR_SE_BUBBLE_TITLE, |
+ GetDefaultSearchEngineName(profile_))); |
+ label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); |
+ label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ AddChildView(label1_); |
+ |
+ gfx::Size ps = GetPreferredSize(); |
+ |
+ label2_ = new views::Label( |
+ l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT)); |
+ label2_->SetMultiLine(true); |
+ label2_->SetFont(font); |
+ label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
+ label2_->SizeToFit(ps.width() - kBubblePadding * 2); |
+ AddChildView(label2_); |
+} |
+ |
+FirstRunMinimalBubbleView::~FirstRunMinimalBubbleView() { |
+ GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this); |
+} |
+ |
+void FirstRunMinimalBubbleView::BubbleShown() { |
+ RequestFocus(); |
+} |
+ |
+void FirstRunMinimalBubbleView::Layout() { |
+ gfx::Size canvas = GetPreferredSize(); |
+ |
+ // See comments in FirstRunOEMBubbleView::Layout explaining this hack. |
+ label1_->SetMultiLine(false); |
+ gfx::Size pref_size = label1_->GetPreferredSize(); |
+ label1_->SetMultiLine(true); |
+ label1_->SizeToFit(canvas.width() - kBubblePadding * 2); |
+ label1_->SetBounds(kBubblePadding, kBubblePadding, |
+ canvas.width() - kBubblePadding * 2, |
+ pref_size.height()); |
+ |
+ int next_v_space = label1_->y() + pref_size.height() + |
+ views::kRelatedControlSmallVerticalSpacing; |
+ |
+ pref_size = label2_->GetPreferredSize(); |
+ label2_->SetBounds(kBubblePadding, next_v_space, |
+ canvas.width() - kBubblePadding * 2, |
+ pref_size.height()); |
+} |
+ |
+gfx::Size FirstRunMinimalBubbleView::GetPreferredSize() { |
+ return gfx::Size(views::Widget::GetLocalizedContentsSize( |
+ IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS, |
+ IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_HEIGHT_LINES)); |
+} |
+ |
+void FirstRunMinimalBubbleView::FocusWillChange(View* focused_before, |
+ View* focused_now) { |
+ // No buttons in minimal bubble to register focus changes. |
+} |
+ |
+ |
+// FirstRunBubble ------------------------------------------------------------- |
+// static |
+views::View* FirstRunBubble::Show( |
+ Profile* profile, |
+ views::Widget* parent, |
+ const gfx::Rect& position_relative_to, |
+ views::BubbleBorder::ArrowLocation arrow_location, |
+ FirstRun::BubbleType bubble_type) { |
+ views::Widget* bubble_widget = new views::Widget(); |
+ views::View* view = NULL; |
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_BUBBLE); |
+ params.transparent = true; |
+ switch (bubble_type) { |
+ case FirstRun::OEM_BUBBLE: |
+ params.delegate = new FirstRunOEMBubbleViewViews(profile, |
+ parent, |
+ position_relative_to, |
+ arrow_location); |
+ break; |
+ case FirstRun::LARGE_BUBBLE: |
+ params.delegate = new FirstRunBubbleViewViews(profile, |
+ parent, |
+ position_relative_to, |
+ arrow_location); |
+ |
+ break; |
+ case FirstRun::MINIMAL_BUBBLE: |
+ params.delegate = new FirstRunMinimalBubbleViewViews(profile, |
+ parent, |
+ position_relative_to, |
+ arrow_location); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ params.parent = parent->GetNativeView(); |
+ bubble_widget->Init(params); |
+ // bubble_widget->GetFocusManager()->AddFocusChangeListener(view); |
+ static_cast<FirstRunBubbleViewBase*>( |
+ params.delegate->GetContentsView())->BubbleShown(); |
+ return view; |
+} |