OLD | NEW |
| (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/theme_install_bubble_view.h" | |
6 | |
7 #include "base/utf_string_conversions.h" | |
8 #include "chrome/common/chrome_notification_types.h" | |
9 #include "content/browser/tab_contents/tab_contents.h" | |
10 #include "content/public/browser/notification_service.h" | |
11 #include "grit/generated_resources.h" | |
12 #include "ui/base/l10n/l10n_util.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "ui/gfx/canvas_skia.h" | |
15 #include "views/widget/widget.h" | |
16 | |
17 namespace { | |
18 | |
19 // The roundedness of the edges of our bubble. | |
20 static const int kBubbleCornerRadius = 4; | |
21 | |
22 // Padding around text in popup box. | |
23 static const int kTextHorizPadding = 90; | |
24 static const int kTextVertPadding = 45; | |
25 | |
26 // Multiple loads can be started at once. Only show one bubble, and keep | |
27 // track of number of loads happening. Close bubble when num_loads < 1. | |
28 static int num_loads_extant_ = 0; | |
29 | |
30 } // namespace | |
31 | |
32 ThemeInstallBubbleView::ThemeInstallBubbleView(TabContents* tab_contents) | |
33 : popup_(NULL) { | |
34 if (!tab_contents) | |
35 Close(); | |
36 | |
37 text_ = l10n_util::GetStringUTF16(IDS_THEME_LOADING_TITLE); | |
38 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
39 gfx::Font font(rb.GetFont(ResourceBundle::LargeFont)); | |
40 SetFont(font); | |
41 | |
42 // We can't check for the size of tab_contents before we've generated | |
43 // the string and the font that determine the size of the bubble. | |
44 tab_contents->GetContainerBounds(&tab_contents_bounds_); | |
45 if (tab_contents_bounds_.height() < GetPreferredSize().height()) | |
46 Close(); | |
47 | |
48 // Close when theme has been installed. | |
49 registrar_.Add( | |
50 this, | |
51 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, | |
52 content::NotificationService::AllBrowserContextsAndSources()); | |
53 | |
54 // Close when we are installing an extension, not a theme. | |
55 registrar_.Add( | |
56 this, | |
57 chrome::NOTIFICATION_NO_THEME_DETECTED, | |
58 content::NotificationService::AllSources()); | |
59 registrar_.Add( | |
60 this, | |
61 chrome::NOTIFICATION_EXTENSION_INSTALLED, | |
62 content::NotificationService::AllSources()); | |
63 registrar_.Add( | |
64 this, | |
65 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, | |
66 content::NotificationService::AllSources()); | |
67 | |
68 // Don't let the bubble overlap the confirm dialog. | |
69 registrar_.Add( | |
70 this, | |
71 chrome::NOTIFICATION_EXTENSION_WILL_SHOW_CONFIRM_DIALOG, | |
72 content::NotificationService::AllSources()); | |
73 | |
74 popup_ = new views::Widget; | |
75 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | |
76 params.transparent = true; | |
77 params.accept_events = false; | |
78 params.parent = tab_contents->GetNativeView(); | |
79 popup_->Init(params); | |
80 popup_->SetContentsView(this); | |
81 popup_->SetOpacity(0xCC); | |
82 Reposition(); | |
83 popup_->Show(); | |
84 | |
85 SchedulePaint(); | |
86 } | |
87 | |
88 ThemeInstallBubbleView::~ThemeInstallBubbleView() { | |
89 num_loads_extant_ = 0; | |
90 } | |
91 | |
92 gfx::Size ThemeInstallBubbleView::GetPreferredSize() { | |
93 return gfx::Size(views::Label::font().GetStringWidth(text_) + | |
94 kTextHorizPadding, | |
95 ResourceBundle::GetSharedInstance().GetFont( | |
96 ResourceBundle::LargeFont).GetHeight() + kTextVertPadding); | |
97 } | |
98 | |
99 void ThemeInstallBubbleView::Reposition() { | |
100 if (!popup_) | |
101 Close(); | |
102 | |
103 gfx::Size size = GetPreferredSize(); | |
104 int mid_x = tab_contents_bounds_.x() + | |
105 (tab_contents_bounds_.right() - tab_contents_bounds_.x()) / 2; | |
106 | |
107 int x = base::i18n::IsRTL() ? | |
108 mid_x + size.width() / 2 : mid_x - size.width() / 2; | |
109 int y = static_cast<int>(tab_contents_bounds_.y() + | |
110 (tab_contents_bounds_.bottom() - tab_contents_bounds_.y()) / 2 - | |
111 size.height() / 2); | |
112 | |
113 popup_->SetBounds(gfx::Rect(x, y, size.width(), size.height())); | |
114 } | |
115 | |
116 void ThemeInstallBubbleView::OnPaint(gfx::Canvas* canvas) { | |
117 SkScalar rad[8]; | |
118 for (int i = 0; i < 8; ++i) | |
119 rad[i] = SkIntToScalar(kBubbleCornerRadius); | |
120 | |
121 SkPaint paint; | |
122 paint.setStyle(SkPaint::kFill_Style); | |
123 paint.setFlags(SkPaint::kAntiAlias_Flag); | |
124 paint.setColor(SK_ColorBLACK); | |
125 | |
126 SkRect rect; | |
127 rect.set(0, 0, | |
128 SkIntToScalar(width()), | |
129 SkIntToScalar(height())); | |
130 SkPath path; | |
131 path.addRoundRect(rect, rad, SkPath::kCW_Direction); | |
132 canvas->GetSkCanvas()->drawPath(path, paint); | |
133 | |
134 int text_width = views::Label::font().GetStringWidth(text_); | |
135 gfx::Rect body_bounds(kTextHorizPadding / 2, 0, text_width, height()); | |
136 body_bounds.set_x(GetMirroredXForRect(body_bounds)); | |
137 | |
138 SkColor text_color = SK_ColorWHITE; | |
139 canvas->DrawStringInt(text_, | |
140 views::Label::font(), | |
141 text_color, | |
142 body_bounds.x(), | |
143 body_bounds.y(), | |
144 body_bounds.width(), | |
145 body_bounds.height()); | |
146 } | |
147 | |
148 void ThemeInstallBubbleView::Close() { | |
149 --num_loads_extant_; | |
150 if (!popup_) { | |
151 num_loads_extant_ = 0; | |
152 return; | |
153 } | |
154 if (num_loads_extant_ < 1) { | |
155 registrar_.RemoveAll(); | |
156 popup_->Close(); | |
157 } | |
158 } | |
159 | |
160 void ThemeInstallBubbleView::Observe( | |
161 int type, | |
162 const content::NotificationSource& source, | |
163 const content::NotificationDetails& details) { | |
164 Close(); | |
165 } | |
166 | |
167 // static | |
168 void ThemeInstallBubbleView::Show(TabContents* tab_contents) { | |
169 ++num_loads_extant_; | |
170 if (num_loads_extant_ < 2) | |
171 new ThemeInstallBubbleView(tab_contents); | |
172 } | |
OLD | NEW |