Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: chrome/browser/ui/views/first_run_bubble_view_views.cc

Issue 8265005: first run bubble using the views/bubble api. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/first_run_bubble_view_views.h"
6
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/first_run/first_run.h"
9 #include "chrome/browser/search_engines/util.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/browser_list.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/views/first_run_bubble.h"
14 #include "content/browser/user_metrics.h"
15 #include "grit/chromium_strings.h"
16 #include "grit/generated_resources.h"
17 #include "grit/locale_settings.h"
18 #include "grit/theme_resources_standard.h"
19 #include "ui/base/l10n/l10n_font_util.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "views/bubble/bubble_view.h"
23 #include "views/controls/button/image_button.h"
24 #include "views/controls/button/text_button.h"
25 #include "views/controls/label.h"
26 #include "views/events/event.h"
27 #include "views/focus/focus_manager.h"
28 #include "views/layout/layout_constants.h"
29
30 namespace {
31
32 // How much extra padding to put around our content over what the Bubble
33 // provides.
34 const int kBubblePadding = 4;
35
36 // How much extra padding to put around our content over what the Bubble
37 // provides in alternative OEM bubble.
38 const int kOEMBubblePadding = 4;
39
40 // Padding between parts of strings on the same line (for instance,
41 // "New!" and "Search from the address bar!"
42 const int kStringSeparationPadding = 2;
43
44 // Margin around close button.
45 const int kMarginRightOfCloseButton = 7;
46
47 } // namespace
48
49 // FirstRunBubbleViewViews------------------------------------------------------
50 FirstRunBubbleViewViews::FirstRunBubbleViewViews(
51 Profile* profile,
52 views::Widget* parent,
53 const gfx::Rect& position_relative_to,
54 views::BubbleBorder::ArrowLocation arrow_location)
55 : BubbleDelegateView(parent),
56 profile_(profile),
57 parent_(parent),
58 position_relative_to_(position_relative_to),
59 arrow_location_(arrow_location) {}
60
61 views::View* FirstRunBubbleViewViews::GetContentsView() {
62 return new FirstRunBubbleView(parent_, profile_);
63 }
64
65 FirstRunBubbleViewViews::~FirstRunBubbleViewViews() {
66 }
67
68 views::BubbleBorder::ArrowLocation
69 FirstRunBubbleViewViews::GetFrameArrowLocation() {
70 return arrow_location_;
71 }
72
73 SkColor FirstRunBubbleViewViews::GetFrameBackgroundColor() {
74 return SK_ColorWHITE;
75 }
76
77 gfx::Rect FirstRunBubbleViewViews::GetBounds() {
78 gfx::Size content_size =
79 gfx::Size(views::Widget::GetLocalizedContentsSize(
80 IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS,
81 IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES));
82 return gfx::Rect(position_relative_to_.x(),
83 position_relative_to_.y(),
84 content_size.width() + kBubblePadding * 2,
85 content_size.height() + kBubblePadding * 2);
86 }
87
88 // FirstRunBubbleView ---------------------------------------------------------
89 FirstRunBubbleView::FirstRunBubbleView(views::Widget* widget,
90 Profile* profile)
91 : widget_(widget),
92 label1_(NULL),
93 label2_(NULL),
94 label3_(NULL),
95 change_button_(NULL),
96 keep_button_(NULL),
97 profile_(profile) {
98 const gfx::Font& font =
99 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont);
100
101 label1_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_TITLE));
102 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD));
103 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
104 AddChildView(label1_);
105
106 gfx::Size ps = GetPreferredSize();
107
108 label2_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT));
109 label2_->SetMultiLine(true);
110 label2_->SetFont(font);
111 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
112 label2_->SizeToFit(ps.width() - kBubblePadding * 2);
113 AddChildView(label2_);
114
115 string16 question_str = l10n_util::GetStringFUTF16(
116 IDS_FR_BUBBLE_QUESTION,
117 GetDefaultSearchEngineName(profile));
118 label3_ = new views::Label(question_str);
119 label3_->SetMultiLine(true);
120 label3_->SetFont(font);
121 label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
122 label3_->SizeToFit(ps.width() - kBubblePadding * 2);
123 AddChildView(label3_);
124
125 std::wstring keep_str = UTF16ToWide(l10n_util::GetStringFUTF16(
126 IDS_FR_BUBBLE_OK,
127 GetDefaultSearchEngineName(profile)));
128 keep_button_ = new views::NativeTextButton(this, keep_str);
129 keep_button_->SetIsDefault(true);
130 AddChildView(keep_button_);
131
132 std::wstring change_str =
133 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_CHANGE));
134 change_button_ = new views::NativeTextButton(this, change_str);
135 AddChildView(change_button_);
136 }
137
138 FirstRunBubbleView::~FirstRunBubbleView() {
139 GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this);
140 }
141
142 void FirstRunBubbleView::ButtonPressed(views::Button* sender,
143 const views::Event& event) {
144 UserMetrics::RecordAction(UserMetricsAction("FirstRunBubbleView_Clicked"));
145 // Do I need a delegate?
146 // GetWidget()->client_view()->AsBubbleView()->set_animation_delegate(this);
147 GetWidget()->client_view()->AsBubbleView()->StartFade();
148 GetWidget()->Close();
149 if (change_button_ == sender) {
150 UserMetrics::RecordAction(
151 UserMetricsAction("FirstRunBubbleView_ChangeButton"));
152
153 Browser* browser = BrowserList::GetLastActiveWithProfile(profile_);
154 if (browser) {
155 browser->OpenSearchEngineOptionsDialog();
156 }
157 }
158 }
159
160 void FirstRunBubbleView::BubbleShown() {
161 keep_button_->RequestFocus();
162 }
163
164 void FirstRunBubbleView::Layout() {
165 gfx::Size canvas = GetPreferredSize();
166
167 // The multiline business that follows is dirty hacks to get around
168 // bug 1325257.
169 label1_->SetMultiLine(false);
170 gfx::Size pref_size = label1_->GetPreferredSize();
171 label1_->SetMultiLine(true);
172 label1_->SizeToFit(canvas.width() - kBubblePadding * 2);
173 label1_->SetBounds(kBubblePadding, kBubblePadding,
174 canvas.width() - kBubblePadding * 2,
175 pref_size.height());
176
177 int next_v_space = label1_->y() + pref_size.height() +
178 views::kRelatedControlSmallVerticalSpacing;
179
180 pref_size = label2_->GetPreferredSize();
181 label2_->SetBounds(kBubblePadding, next_v_space,
182 canvas.width() - kBubblePadding * 2,
183 pref_size.height());
184
185 next_v_space = label2_->y() + label2_->height() +
186 views::kPanelSubVerticalSpacing;
187
188 pref_size = label3_->GetPreferredSize();
189 label3_->SetBounds(kBubblePadding, next_v_space,
190 canvas.width() - kBubblePadding * 2,
191 pref_size.height());
192
193 pref_size = change_button_->GetPreferredSize();
194 change_button_->SetBounds(
195 canvas.width() - pref_size.width() - kBubblePadding,
196 canvas.height() - pref_size.height() - views::kButtonVEdgeMargin,
197 pref_size.width(), pref_size.height());
198
199 pref_size = keep_button_->GetPreferredSize();
200 keep_button_->SetBounds(change_button_->x() - pref_size.width() -
201 views::kRelatedButtonHSpacing, change_button_->y(),
202 pref_size.width(), pref_size.height());
203 }
204
205 gfx::Size FirstRunBubbleView::GetPreferredSize() {
206 return gfx::Size(views::Widget::GetLocalizedContentsSize(
207 IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS,
208 IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES));
209 }
210
211 void FirstRunBubbleView::FocusWillChange(View* focused_before,
212 View* focused_now) {
213 if (focused_before &&
214 (focused_before->GetClassName() ==
215 views::NativeTextButton::kViewClassName)) {
216 views::NativeTextButton* before =
217 static_cast<views::NativeTextButton*>(focused_before);
218 before->SetIsDefault(false);
219 }
220 if (focused_now &&
221 (focused_now->GetClassName() ==
222 views::NativeTextButton::kViewClassName)) {
223 views::NativeTextButton* after =
224 static_cast<views::NativeTextButton*>(focused_now);
225 after->SetIsDefault(true);
226 }
227 }
228
229 // FirstRunOEMBubbleViewViews --------------------------------------------------
230 FirstRunOEMBubbleViewViews::FirstRunOEMBubbleViewViews(
231 Profile* profile,
232 views::Widget* parent,
233 const gfx::Rect& position_relative_to,
234 views::BubbleBorder::ArrowLocation arrow_location)
235 : BubbleDelegateView(parent),
236 profile_(profile),
237 parent_(parent),
238 position_relative_to_(position_relative_to),
239 arrow_location_(arrow_location) {}
240
241 views::View* FirstRunOEMBubbleViewViews::GetContentsView() {
242 return new FirstRunOEMBubbleView(parent_, profile_);
243 }
244
245 FirstRunOEMBubbleViewViews::~FirstRunOEMBubbleViewViews() {}
246
247 views::BubbleBorder::ArrowLocation
248 FirstRunOEMBubbleViewViews::GetFrameArrowLocation() {
249 return arrow_location_;
250 }
251
252 SkColor FirstRunOEMBubbleViewViews::GetFrameBackgroundColor() {
253 return SK_ColorWHITE;
254 }
255
256 gfx::Rect FirstRunOEMBubbleViewViews::GetBounds() {
257 gfx::Size content_size =
258 gfx::Size(views::Widget::GetLocalizedContentsSize(
259 IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS,
260 IDS_FIRSTRUNOEMBUBBLE_DIALOG_HEIGHT_LINES));
261 return gfx::Rect(position_relative_to_.x(),
262 position_relative_to_.y(),
263 content_size.width() + kOEMBubblePadding * 2,
264 content_size.height() + kOEMBubblePadding * 2);
265 }
266
267 // FirstRunOEMBubbleView ------------------------------------------------------
268 FirstRunOEMBubbleView::FirstRunOEMBubbleView(views::Widget* widget,
269 Profile* profile)
270 : widget_(widget),
271 label1_(NULL),
272 label2_(NULL),
273 label3_(NULL),
274 close_button_(NULL),
275 profile_(profile) {
276 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
277 const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont);
278
279 label1_ = new views::Label(
280 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_1));
281 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD));
282 label1_->SetColor(SK_ColorRED);
283 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
284 AddChildView(label1_);
285
286 label2_ = new views::Label(
287 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_2));
288 label2_->SetFont(font.DeriveFont(3, gfx::Font::BOLD));
289 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
290 AddChildView(label2_);
291
292 gfx::Size ps = GetPreferredSize();
293
294 label3_ = new views::Label(
295 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_SUBTEXT));
296 label3_->SetMultiLine(true);
297 label3_->SetFont(font);
298 label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
299 label3_->SizeToFit(ps.width() - kOEMBubblePadding * 2);
300 AddChildView(label3_);
301
302 close_button_ = new views::ImageButton(this);
303 close_button_->SetImage(views::CustomButton::BS_NORMAL,
304 rb.GetBitmapNamed(IDR_CLOSE_BAR));
305 close_button_->SetImage(views::CustomButton::BS_HOT,
306 rb.GetBitmapNamed(IDR_CLOSE_BAR_H));
307 close_button_->SetImage(views::CustomButton::BS_PUSHED,
308 rb.GetBitmapNamed(IDR_CLOSE_BAR_P));
309
310 AddChildView(close_button_);
311 }
312
313 FirstRunOEMBubbleView::~FirstRunOEMBubbleView() {
314 GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this);
315 }
316
317
318 void FirstRunOEMBubbleView::ButtonPressed(views::Button* sender,
319 const views::Event& event) {
320 UserMetrics::RecordAction(
321 UserMetricsAction("FirstRunOEMBubbleView_Clicked"));
322 GetWidget()->client_view()->AsBubbleView()->StartFade();
323 GetWidget()->Close();
324 }
325
326 void FirstRunOEMBubbleView::BubbleShown() {
327 RequestFocus();
328 }
329
330 void FirstRunOEMBubbleView::Layout() {
331 gfx::Size canvas = GetPreferredSize();
332
333 // First, draw the close button on the far right.
334 gfx::Size sz = close_button_->GetPreferredSize();
335 close_button_->SetBounds(
336 canvas.width() - sz.width() - kMarginRightOfCloseButton,
337 kOEMBubblePadding, sz.width(), sz.height());
338
339 gfx::Size pref_size = label1_->GetPreferredSize();
340 label1_->SetBounds(kOEMBubblePadding, kOEMBubblePadding,
341 pref_size.width() + kOEMBubblePadding * 2,
342 pref_size.height());
343
344 pref_size = label2_->GetPreferredSize();
345 label2_->SetBounds(
346 kOEMBubblePadding * 2 + label1_->GetPreferredSize().width(),
347 kOEMBubblePadding, canvas.width() - kOEMBubblePadding * 2,
348 pref_size.height());
349
350 int next_v_space =
351 label1_->y() + pref_size.height() +
352 views::kRelatedControlSmallVerticalSpacing;
353
354 pref_size = label3_->GetPreferredSize();
355 label3_->SetBounds(kOEMBubblePadding, next_v_space,
356 canvas.width() - kOEMBubblePadding * 2,
357 pref_size.height());
358 }
359
360 gfx::Size FirstRunOEMBubbleView::GetPreferredSize() {
361 // Calculate width based on font and text.
362 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
363 const gfx::Font& font = rb.GetFont(
364 ResourceBundle::MediumFont).DeriveFont(3, gfx::Font::BOLD);
365 gfx::Size size = gfx::Size(
366 ui::GetLocalizedContentsWidthForFont(
367 IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS, font),
368 ui::GetLocalizedContentsHeightForFont(
369 IDS_FIRSTRUNOEMBUBBLE_DIALOG_HEIGHT_LINES, font));
370
371 // WARNING: HACK. Vista and XP calculate font size differently; this means
372 // that a dialog box correctly proportioned for XP will appear too large in
373 // Vista. The correct thing to do is to change font size calculations in
374 // XP or Vista so that the length of a string is calculated properly. For
375 // now, we force Vista to show a correctly-sized box by taking account of
376 // the difference in font size calculation. The coefficient should not be
377 // stored in a variable because it's a hack and should go away.
378 #ifdef NEVER
379 if (views::NativeWidgetWin::IsAeroGlassEnabled()) {
380 size.set_width(static_cast<int>(size.width() * 0.85));
381 size.set_height(static_cast<int>(size.height() * 0.85));
382 }
383 #endif
384 return size;
385 }
386
387 void FirstRunOEMBubbleView::FocusWillChange(View* focused_before,
388 View* focused_now) {
389 // No buttons in oem_bubble to register focus changes.
390 }
391
392 // FirstRunMinimalBubbleViewViews ----------------------------------------------
393 FirstRunMinimalBubbleViewViews::FirstRunMinimalBubbleViewViews(
394 Profile* profile,
395 views::Widget* parent,
396 const gfx::Rect& position_relative_to,
397 views::BubbleBorder::ArrowLocation arrow_location)
398 : BubbleDelegateView(parent),
399 profile_(profile),
400 parent_(parent),
401 position_relative_to_(position_relative_to),
402 arrow_location_(arrow_location) {}
403
404 views::View* FirstRunMinimalBubbleViewViews::GetContentsView() {
405 return new FirstRunMinimalBubbleView(parent_, profile_);
406 }
407
408 FirstRunMinimalBubbleViewViews::~FirstRunMinimalBubbleViewViews() {
409 }
410
411 views::BubbleBorder::ArrowLocation
412 FirstRunMinimalBubbleViewViews::GetFrameArrowLocation() {
413 return arrow_location_;
414 }
415
416 SkColor FirstRunMinimalBubbleViewViews::GetFrameBackgroundColor() {
417 return SK_ColorWHITE;
418 }
419
420 gfx::Rect FirstRunMinimalBubbleViewViews::GetBounds() {
421 gfx::Size content_size =
422 gfx::Size(views::Widget::GetLocalizedContentsSize(
423 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS,
424 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_HEIGHT_LINES));
425 return gfx::Rect(position_relative_to_.x(),
426 position_relative_to_.y(),
427 content_size.width() + 2,
428 content_size.height() + 2);
429 }
430
431 // FirstRunMinimalBubbleView --------------------------------------------------
432 FirstRunMinimalBubbleView::FirstRunMinimalBubbleView(
433 views::Widget* widget,
434 Profile* profile)
435 : widget_(widget),
436 label1_(NULL),
437 label2_(NULL),
438 profile_(profile) {
439 const gfx::Font& font =
440 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont);
441
442 label1_ = new views::Label(l10n_util::GetStringFUTF16(
443 IDS_FR_SE_BUBBLE_TITLE,
444 GetDefaultSearchEngineName(profile_)));
445 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD));
446 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
447 AddChildView(label1_);
448
449 gfx::Size ps = GetPreferredSize();
450
451 label2_ = new views::Label(
452 l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT));
453 label2_->SetMultiLine(true);
454 label2_->SetFont(font);
455 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
456 label2_->SizeToFit(ps.width() - kBubblePadding * 2);
457 AddChildView(label2_);
458 }
459
460 FirstRunMinimalBubbleView::~FirstRunMinimalBubbleView() {
461 GetWidget()->GetFocusManager()->RemoveFocusChangeListener(this);
462 }
463
464 void FirstRunMinimalBubbleView::BubbleShown() {
465 RequestFocus();
466 }
467
468 void FirstRunMinimalBubbleView::Layout() {
469 gfx::Size canvas = GetPreferredSize();
470
471 // See comments in FirstRunOEMBubbleView::Layout explaining this hack.
472 label1_->SetMultiLine(false);
473 gfx::Size pref_size = label1_->GetPreferredSize();
474 label1_->SetMultiLine(true);
475 label1_->SizeToFit(canvas.width() - kBubblePadding * 2);
476 label1_->SetBounds(kBubblePadding, kBubblePadding,
477 canvas.width() - kBubblePadding * 2,
478 pref_size.height());
479
480 int next_v_space = label1_->y() + pref_size.height() +
481 views::kRelatedControlSmallVerticalSpacing;
482
483 pref_size = label2_->GetPreferredSize();
484 label2_->SetBounds(kBubblePadding, next_v_space,
485 canvas.width() - kBubblePadding * 2,
486 pref_size.height());
487 }
488
489 gfx::Size FirstRunMinimalBubbleView::GetPreferredSize() {
490 return gfx::Size(views::Widget::GetLocalizedContentsSize(
491 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS,
492 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_HEIGHT_LINES));
493 }
494
495 void FirstRunMinimalBubbleView::FocusWillChange(View* focused_before,
496 View* focused_now) {
497 // No buttons in minimal bubble to register focus changes.
498 }
499
500
501 // FirstRunBubble -------------------------------------------------------------
502 // static
503 views::View* FirstRunBubble::Show(
504 Profile* profile,
505 views::Widget* parent,
506 const gfx::Rect& position_relative_to,
507 views::BubbleBorder::ArrowLocation arrow_location,
508 FirstRun::BubbleType bubble_type) {
509 views::Widget* bubble_widget = new views::Widget();
510 views::View* view = NULL;
511 views::Widget::InitParams params(views::Widget::InitParams::TYPE_BUBBLE);
512 params.transparent = true;
513 switch (bubble_type) {
514 case FirstRun::OEM_BUBBLE:
515 params.delegate = new FirstRunOEMBubbleViewViews(profile,
516 parent,
517 position_relative_to,
518 arrow_location);
519 break;
520 case FirstRun::LARGE_BUBBLE:
521 params.delegate = new FirstRunBubbleViewViews(profile,
522 parent,
523 position_relative_to,
524 arrow_location);
525
526 break;
527 case FirstRun::MINIMAL_BUBBLE:
528 params.delegate = new FirstRunMinimalBubbleViewViews(profile,
529 parent,
530 position_relative_to,
531 arrow_location);
532 break;
533 default:
534 NOTREACHED();
535 }
536 params.parent = parent->GetNativeView();
537 bubble_widget->Init(params);
538 // bubble_widget->GetFocusManager()->AddFocusChangeListener(view);
539 static_cast<FirstRunBubbleViewBase*>(
540 params.delegate->GetContentsView())->BubbleShown();
541 return view;
542 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698