OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h" | 5 #include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h" |
6 | 6 |
7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/app/chrome_command_ids.h" | 9 #include "chrome/app/chrome_command_ids.h" |
10 #include "chrome/browser/ui/views/bubble/bubble.h" | |
10 #include "grit/generated_resources.h" | 11 #include "grit/generated_resources.h" |
11 #include "ui/base/animation/slide_animation.h" | 12 #include "ui/base/animation/slide_animation.h" |
12 #include "ui/base/keycodes/keyboard_codes.h" | 13 #include "ui/base/keycodes/keyboard_codes.h" |
13 #include "ui/base/l10n/l10n_util.h" | 14 #include "ui/base/l10n/l10n_util.h" |
14 #include "ui/base/resource/resource_bundle.h" | 15 #include "ui/base/resource/resource_bundle.h" |
15 #include "ui/gfx/canvas_skia.h" | 16 #include "ui/gfx/canvas_skia.h" |
16 #include "ui/gfx/screen.h" | 17 #include "ui/gfx/screen.h" |
18 #include "views/bubble/bubble_border.h" | |
19 #include "views/controls/button/text_button.h" | |
17 #include "views/controls/link.h" | 20 #include "views/controls/link.h" |
18 #include "views/widget/widget.h" | 21 #include "views/widget/widget.h" |
19 | 22 |
20 #if defined(OS_WIN) | 23 #if defined(OS_WIN) |
21 #include "ui/base/l10n/l10n_util_win.h" | 24 #include "ui/base/l10n/l10n_util_win.h" |
22 #endif | 25 #endif |
23 | 26 |
24 // FullscreenExitView ---------------------------------------------------------- | 27 // FullscreenExitView ---------------------------------------------------------- |
25 | 28 |
26 class FullscreenExitBubbleViews::FullscreenExitView : public views::View { | 29 namespace { |
30 // Space between the site info label and the buttons / link. | |
31 const int kMiddlePaddingPx = 30; | |
32 } // namespace | |
33 | |
34 class FullscreenExitBubbleViews::FullscreenExitView | |
35 : public views::View, | |
36 public views::ButtonListener { | |
27 public: | 37 public: |
28 FullscreenExitView(FullscreenExitBubbleViews* bubble, | 38 FullscreenExitView(FullscreenExitBubbleViews* bubble, |
29 const std::wstring& accelerator); | 39 const std::wstring& accelerator, |
40 const GURL& url, | |
41 bool ask_permission); | |
30 virtual ~FullscreenExitView(); | 42 virtual ~FullscreenExitView(); |
31 | 43 |
32 // views::View | 44 // views::View |
33 virtual gfx::Size GetPreferredSize(); | 45 virtual gfx::Size GetPreferredSize(); |
34 | 46 |
47 // views::ButtonListener | |
48 virtual void ButtonPressed(views::Button* sender, const views::Event& event); | |
49 | |
50 // Hide the accept and deny buttons, exposing the exit link. | |
51 void HideButtons(); | |
52 | |
35 private: | 53 private: |
54 string16 GetMessage(const GURL& url); | |
55 | |
36 // views::View | 56 // views::View |
37 virtual void Layout(); | 57 virtual void Layout(); |
38 virtual void OnPaint(gfx::Canvas* canvas); | 58 |
59 FullscreenExitBubbleViews* bubble_; | |
39 | 60 |
40 // Clickable hint text to show in the bubble. | 61 // Clickable hint text to show in the bubble. |
41 views::Link link_; | 62 views::Link link_; |
63 views::Label message_label_; | |
64 views::NativeTextButton* accept_button_; | |
65 views::NativeTextButton* deny_button_; | |
66 | |
67 bool show_buttons_; | |
42 }; | 68 }; |
43 | 69 |
44 FullscreenExitBubbleViews::FullscreenExitView::FullscreenExitView( | 70 FullscreenExitBubbleViews::FullscreenExitView::FullscreenExitView( |
45 FullscreenExitBubbleViews* bubble, | 71 FullscreenExitBubbleViews* bubble, |
46 const std::wstring& accelerator) { | 72 const std::wstring& accelerator, |
73 const GURL& url, | |
74 bool ask_permission) | |
75 : bubble_(bubble), | |
76 accept_button_(NULL), | |
77 deny_button_(NULL), | |
78 show_buttons_(ask_permission) { | |
79 views::BubbleBorder* bubble_border = | |
80 new views::BubbleBorder(views::BubbleBorder::NONE); | |
81 bubble_border->set_background_color(Bubble::kBackgroundColor); | |
82 set_background(new views::BubbleBackground(bubble_border)); | |
83 set_border(bubble_border); | |
84 set_focusable(false); | |
85 | |
86 message_label_.set_parent_owned(false); | |
87 message_label_.SetText(GetMessage(url)); | |
88 message_label_.SetFont(ResourceBundle::GetSharedInstance().GetFont( | |
89 ResourceBundle::MediumFont)); | |
90 | |
47 link_.set_parent_owned(false); | 91 link_.set_parent_owned(false); |
92 link_.set_collapse_when_hidden(false); | |
93 link_.set_focusable(false); | |
48 #if !defined(OS_CHROMEOS) | 94 #if !defined(OS_CHROMEOS) |
49 link_.SetText( | 95 link_.SetText( |
50 l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE, | 96 l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE, |
51 WideToUTF16(accelerator))); | 97 WideToUTF16(accelerator))); |
52 #else | 98 #else |
53 link_.SetText(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE)); | 99 link_.SetText(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE)); |
54 #endif | 100 #endif |
55 link_.set_listener(bubble); | 101 link_.set_listener(bubble); |
56 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( | 102 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( |
57 ResourceBundle::LargeFont)); | 103 ResourceBundle::MediumFont)); |
58 link_.SetBackgroundColor(SK_ColorBLACK); | 104 link_.SetPressedColor(message_label_.enabled_color()); |
Peter Kasting
2011/10/14 20:33:29
Nit: Add a comment like:
// Get the message's e
| |
59 link_.SetEnabledColor(SK_ColorWHITE); | 105 link_.SetEnabledColor(message_label_.enabled_color()); |
60 link_.SetPressedColor(SK_ColorWHITE); | 106 link_.SetVisible(false); |
107 | |
108 link_.SetBackgroundColor(background()->get_color()); | |
109 message_label_.SetBackgroundColor(background()->get_color()); | |
110 AddChildView(&message_label_); | |
61 AddChildView(&link_); | 111 AddChildView(&link_); |
112 | |
113 accept_button_ = new views::NativeTextButton(this, | |
114 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FULLSCREEN_INFOBAR_ALLOW))); | |
115 accept_button_->set_focusable(false); | |
116 AddChildView(accept_button_); | |
117 | |
118 deny_button_ = new views::NativeTextButton(this, | |
119 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FULLSCREEN_INFOBAR_DENY))); | |
120 deny_button_->set_focusable(false); | |
121 AddChildView(deny_button_); | |
122 | |
123 if (!show_buttons_) | |
124 HideButtons(); | |
125 } | |
126 | |
127 string16 FullscreenExitBubbleViews::FullscreenExitView::GetMessage( | |
128 const GURL& url) { | |
129 if (url.is_empty()) { | |
130 return l10n_util::GetStringUTF16( | |
131 IDS_FULLSCREEN_INFOBAR_USER_ENTERED_FULLSCREEN); | |
132 } | |
133 if (url.SchemeIsFile()) | |
134 return l10n_util::GetStringUTF16(IDS_FULLSCREEN_INFOBAR_FILE_PAGE_NAME); | |
135 return l10n_util::GetStringFUTF16(IDS_FULLSCREEN_INFOBAR_REQUEST_PERMISSION, | |
136 UTF8ToUTF16(url.host())); | |
62 } | 137 } |
63 | 138 |
64 FullscreenExitBubbleViews::FullscreenExitView::~FullscreenExitView() { | 139 FullscreenExitBubbleViews::FullscreenExitView::~FullscreenExitView() { |
65 } | 140 } |
66 | 141 |
142 void FullscreenExitBubbleViews::FullscreenExitView::ButtonPressed( | |
143 views::Button* sender, const views::Event& event) { | |
144 if (sender == accept_button_) | |
145 bubble_->OnAcceptFullscreen(); | |
146 else | |
147 bubble_->OnCancelFullscreen(); | |
148 } | |
149 | |
150 void FullscreenExitBubbleViews::FullscreenExitView::HideButtons() { | |
151 show_buttons_ = false; | |
152 accept_button_->SetVisible(false); | |
153 deny_button_->SetVisible(false); | |
154 link_.SetVisible(true); | |
155 } | |
156 | |
67 gfx::Size FullscreenExitBubbleViews::FullscreenExitView::GetPreferredSize() { | 157 gfx::Size FullscreenExitBubbleViews::FullscreenExitView::GetPreferredSize() { |
68 gfx::Size preferred_size(link_.GetPreferredSize()); | 158 gfx::Size link_size(link_.GetPreferredSize()); |
69 preferred_size.Enlarge(kPaddingPx * 2, kPaddingPx * 2); | 159 gfx::Size message_label_size(message_label_.GetPreferredSize()); |
70 return preferred_size; | 160 gfx::Size accept_size(accept_button_->GetPreferredSize()); |
161 gfx::Size deny_size(deny_button_->GetPreferredSize()); | |
162 gfx::Insets insets(GetInsets()); | |
163 | |
164 int buttons_width = accept_size.width() + kPaddingPx + | |
165 deny_size.width(); | |
166 int button_box_width = std::max(buttons_width, link_size.width()); | |
167 int width = kPaddingPx + message_label_size.width() + kMiddlePaddingPx + | |
168 button_box_width + kPaddingPx; | |
169 | |
170 gfx::Size result(width + insets.width(), | |
171 kPaddingPx * 2 + accept_size.height() + insets.height()); | |
172 return result; | |
71 } | 173 } |
72 | 174 |
73 void FullscreenExitBubbleViews::FullscreenExitView::Layout() { | 175 void FullscreenExitBubbleViews::FullscreenExitView::Layout() { |
74 gfx::Size link_preferred_size(link_.GetPreferredSize()); | 176 gfx::Size link_size(link_.GetPreferredSize()); |
75 link_.SetBounds(kPaddingPx, | 177 gfx::Size message_label_size(message_label_.GetPreferredSize()); |
76 height() - kPaddingPx - link_preferred_size.height(), | 178 gfx::Size accept_size(accept_button_->GetPreferredSize()); |
77 link_preferred_size.width(), link_preferred_size.height()); | 179 gfx::Size deny_size(deny_button_->GetPreferredSize()); |
78 } | 180 gfx::Insets insets(GetInsets()); |
79 | 181 |
80 void FullscreenExitBubbleViews::FullscreenExitView::OnPaint( | 182 int inner_height = height() - insets.height(); |
81 gfx::Canvas* canvas) { | 183 int button_box_x = insets.left() + kPaddingPx + |
82 // Create a round-bottomed rect to fill the whole View. | 184 message_label_size.width() + kMiddlePaddingPx; |
83 SkRect rect; | 185 int message_label_y = insets.top() + |
84 SkScalar padding = SkIntToScalar(kPaddingPx); | 186 (inner_height - message_label_size.height()) / 2; |
85 // The "-padding" top coordinate ensures that the rect is always tall enough | 187 int link_x = width() - insets.right() - kPaddingPx - |
86 // to contain the complete rounded corner radius. If we set this to 0, as the | 188 link_size.width(); |
87 // popup slides offscreen (in reality, squishes to 0 height), the corners will | 189 int link_y = insets.top() + (inner_height - link_size.height()) / 2; |
88 // flatten out as the height becomes less than the corner radius. | |
89 rect.set(0, -padding, SkIntToScalar(width()), SkIntToScalar(height())); | |
90 SkScalar rad[8] = { 0, 0, 0, 0, padding, padding, padding, padding }; | |
91 SkPath path; | |
92 path.addRoundRect(rect, rad, SkPath::kCW_Direction); | |
93 | 190 |
94 // Fill it black. | 191 message_label_.SetPosition(gfx::Point(insets.left() + kPaddingPx, |
95 SkPaint paint; | 192 message_label_y)); |
96 paint.setStyle(SkPaint::kFill_Style); | 193 link_.SetPosition(gfx::Point(link_x, link_y)); |
97 paint.setFlags(SkPaint::kAntiAlias_Flag); | 194 if (show_buttons_) { |
98 paint.setColor(SK_ColorBLACK); | 195 accept_button_->SetPosition(gfx::Point(button_box_x, insets.top() + kPadding Px)); |
99 canvas->GetSkCanvas()->drawPath(path, paint); | 196 deny_button_->SetPosition(gfx::Point( |
197 button_box_x + accept_size.width() + kPaddingPx, | |
198 insets.top() + kPaddingPx)); | |
199 } | |
100 } | 200 } |
101 | 201 |
102 // FullscreenExitBubbleViews --------------------------------------------------- | 202 // FullscreenExitBubbleViews --------------------------------------------------- |
103 | 203 |
104 FullscreenExitBubbleViews::FullscreenExitBubbleViews( | 204 FullscreenExitBubbleViews::FullscreenExitBubbleViews(views::Widget* frame, |
105 views::Widget* frame, | 205 Browser* browser, |
106 CommandUpdater::CommandUpdaterDelegate* delegate) | 206 const GURL& url, |
107 : FullscreenExitBubble(delegate), | 207 bool ask_permission) |
208 : FullscreenExitBubble(browser), | |
108 root_view_(frame->GetRootView()), | 209 root_view_(frame->GetRootView()), |
109 popup_(NULL), | 210 popup_(NULL), |
110 size_animation_(new ui::SlideAnimation(this)) { | 211 size_animation_(new ui::SlideAnimation(this)), |
212 url_(url) { | |
111 size_animation_->Reset(1); | 213 size_animation_->Reset(1); |
112 | 214 |
113 // Create the contents view. | 215 // Create the contents view. |
114 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); | 216 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); |
115 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); | 217 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); |
116 DCHECK(got_accelerator); | 218 DCHECK(got_accelerator); |
117 view_ = new FullscreenExitView( | 219 view_ = new FullscreenExitView(this, |
118 this, UTF16ToWideHack(accelerator.GetShortcutText())); | 220 UTF16ToWideHack(accelerator.GetShortcutText()), url, ask_permission); |
119 | 221 |
120 // Initialize the popup. | 222 // Initialize the popup. |
121 popup_ = new views::Widget; | 223 popup_ = new views::Widget; |
122 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 224 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
123 params.transparent = true; | 225 params.transparent = true; |
124 params.can_activate = false; | 226 params.can_activate = false; |
125 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 227 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
126 params.parent = frame->GetNativeView(); | 228 params.parent = frame->GetNativeView(); |
127 params.bounds = GetPopupRect(false); | 229 params.bounds = GetPopupRect(false); |
128 popup_->Init(params); | 230 popup_->Init(params); |
231 gfx::Size size = GetPopupRect(true).size(); | |
129 popup_->SetContentsView(view_); | 232 popup_->SetContentsView(view_); |
130 popup_->SetOpacity(static_cast<unsigned char>(0xff * kOpacity)); | 233 // We set layout manager to NULL to prevent the widget from sizing its |
234 // contents to the same size as itself. This prevents the widget contents from | |
235 // shrinking while we animate the height of the popup to give the impression | |
236 // that it is sliding off the top of the screen. | |
237 popup_->GetRootView()->SetLayoutManager(NULL); | |
238 view_->SetBounds(0, 0, size.width(), size.height()); | |
131 popup_->Show(); // This does not activate the popup. | 239 popup_->Show(); // This does not activate the popup. |
132 | 240 |
133 StartWatchingMouse(); | 241 if (!ask_permission) |
242 StartWatchingMouse(); | |
134 } | 243 } |
135 | 244 |
136 FullscreenExitBubbleViews::~FullscreenExitBubbleViews() { | 245 FullscreenExitBubbleViews::~FullscreenExitBubbleViews() { |
137 // This is tricky. We may be in an ATL message handler stack, in which case | 246 // This is tricky. We may be in an ATL message handler stack, in which case |
138 // the popup cannot be deleted yet. We also can't set the popup's ownership | 247 // the popup cannot be deleted yet. We also can't set the popup's ownership |
139 // model to NATIVE_WIDGET_OWNS_WIDGET because if the user closed the last tab | 248 // model to NATIVE_WIDGET_OWNS_WIDGET because if the user closed the last tab |
140 // while in fullscreen mode, Windows has already destroyed the popup HWND by | 249 // while in fullscreen mode, Windows has already destroyed the popup HWND by |
141 // the time we get here, and thus either the popup will already have been | 250 // the time we get here, and thus either the popup will already have been |
142 // deleted (if we set this in our constructor) or the popup will never get | 251 // deleted (if we set this in our constructor) or the popup will never get |
143 // another OnFinalMessage() call (if not, as currently). So instead, we tell | 252 // another OnFinalMessage() call (if not, as currently). So instead, we tell |
144 // the popup to synchronously hide, and then asynchronously close and delete | 253 // the popup to synchronously hide, and then asynchronously close and delete |
145 // itself. | 254 // itself. |
146 popup_->Close(); | 255 popup_->Close(); |
147 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); | 256 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); |
148 } | 257 } |
149 | 258 |
150 void FullscreenExitBubbleViews::LinkClicked( | 259 void FullscreenExitBubbleViews::LinkClicked( |
151 views::Link* source, int event_flags) { | 260 views::Link* source, int event_flags) { |
152 ToggleFullscreen(); | 261 ToggleFullscreen(); |
153 } | 262 } |
154 | 263 |
264 void FullscreenExitBubbleViews::OnAcceptFullscreen() { | |
265 AcceptFullscreen(url_); | |
266 view_->HideButtons(); | |
267 StartWatchingMouse(); | |
268 } | |
269 | |
270 void FullscreenExitBubbleViews::OnCancelFullscreen() { | |
271 CancelFullscreen(); | |
272 } | |
273 | |
155 void FullscreenExitBubbleViews::AnimationProgressed( | 274 void FullscreenExitBubbleViews::AnimationProgressed( |
156 const ui::Animation* animation) { | 275 const ui::Animation* animation) { |
157 gfx::Rect popup_rect(GetPopupRect(false)); | 276 gfx::Rect popup_rect(GetPopupRect(false)); |
158 if (popup_rect.IsEmpty()) { | 277 if (popup_rect.IsEmpty()) { |
159 popup_->Hide(); | 278 popup_->Hide(); |
160 } else { | 279 } else { |
161 popup_->SetBounds(popup_rect); | 280 popup_->SetBounds(popup_rect); |
281 view_->SetY(popup_rect.height() - view_->height()); | |
162 popup_->Show(); | 282 popup_->Show(); |
163 } | 283 } |
164 } | 284 } |
285 | |
165 void FullscreenExitBubbleViews::AnimationEnded( | 286 void FullscreenExitBubbleViews::AnimationEnded( |
166 const ui::Animation* animation) { | 287 const ui::Animation* animation) { |
167 AnimationProgressed(animation); | 288 AnimationProgressed(animation); |
168 } | 289 } |
169 | 290 |
170 void FullscreenExitBubbleViews::Hide() { | 291 void FullscreenExitBubbleViews::Hide() { |
171 size_animation_->SetSlideDuration(kSlideOutDurationMs); | 292 size_animation_->SetSlideDuration(kSlideOutDurationMs); |
172 size_animation_->Hide(); | 293 size_animation_->Hide(); |
173 } | 294 } |
174 | 295 |
(...skipping 17 matching lines...) Expand all Loading... | |
192 gfx::Point FullscreenExitBubbleViews::GetCursorScreenPoint() { | 313 gfx::Point FullscreenExitBubbleViews::GetCursorScreenPoint() { |
193 gfx::Point cursor_pos = gfx::Screen::GetCursorScreenPoint(); | 314 gfx::Point cursor_pos = gfx::Screen::GetCursorScreenPoint(); |
194 gfx::Point transformed_pos(cursor_pos); | 315 gfx::Point transformed_pos(cursor_pos); |
195 views::View::ConvertPointToView(NULL, root_view_, &transformed_pos); | 316 views::View::ConvertPointToView(NULL, root_view_, &transformed_pos); |
196 return transformed_pos; | 317 return transformed_pos; |
197 } | 318 } |
198 | 319 |
199 gfx::Rect FullscreenExitBubbleViews::GetPopupRect( | 320 gfx::Rect FullscreenExitBubbleViews::GetPopupRect( |
200 bool ignore_animation_state) const { | 321 bool ignore_animation_state) const { |
201 gfx::Size size(view_->GetPreferredSize()); | 322 gfx::Size size(view_->GetPreferredSize()); |
202 if (!ignore_animation_state) { | |
203 size.set_height(static_cast<int>(static_cast<double>(size.height()) * | |
204 size_animation_->GetCurrentValue())); | |
205 } | |
206 // NOTE: don't use the bounds of the root_view_. On linux changing window | 323 // NOTE: don't use the bounds of the root_view_. On linux changing window |
207 // size is async. Instead we use the size of the screen. | 324 // size is async. Instead we use the size of the screen. |
208 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow( | 325 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow( |
209 root_view_->GetWidget()->GetNativeView()); | 326 root_view_->GetWidget()->GetNativeView()); |
210 gfx::Point origin(screen_bounds.x() + | 327 gfx::Point origin(screen_bounds.x() + |
211 (screen_bounds.width() - size.width()) / 2, | 328 (screen_bounds.width() - size.width()) / 2, |
212 screen_bounds.y()); | 329 kPopupTopPx + screen_bounds.y()); |
330 if (!ignore_animation_state) { | |
331 int total_height = size.height() + kPopupTopPx; | |
332 int popup_bottom = size_animation_->CurrentValueBetween( | |
333 static_cast<double>(total_height), 0.0f); | |
334 int y_offset = std::min(popup_bottom, kPopupTopPx); | |
335 size.set_height(size.height() - popup_bottom + y_offset); | |
336 origin.set_y(origin.y() - y_offset); | |
337 } | |
213 return gfx::Rect(origin, size); | 338 return gfx::Rect(origin, size); |
214 } | 339 } |
OLD | NEW |