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 class FullscreenExitBubbleViews::FullscreenExitView : public views::View, |
| 30 public views::ButtonListener { |
27 public: | 31 public: |
28 FullscreenExitView(FullscreenExitBubbleViews* bubble, | 32 FullscreenExitView(FullscreenExitBubbleViews* bubble, |
29 const std::wstring& accelerator); | 33 const std::wstring& accelerator, |
| 34 const GURL& url, |
| 35 bool show_buttons); |
30 virtual ~FullscreenExitView(); | 36 virtual ~FullscreenExitView(); |
31 | 37 |
32 // views::View | 38 // views::View |
33 virtual gfx::Size GetPreferredSize(); | 39 virtual gfx::Size GetPreferredSize(); |
34 | 40 |
| 41 // views::ButtonListener |
| 42 virtual void ButtonPressed(views::Button* sender, const views::Event& event); |
| 43 |
| 44 virtual void HideButtons(); |
| 45 |
35 private: | 46 private: |
| 47 // Space between the site info label and the buttons / link. |
| 48 static const int kMiddlePaddingPx = 30; |
36 // views::View | 49 // views::View |
37 virtual void Layout(); | 50 virtual void Layout(); |
38 virtual void OnPaint(gfx::Canvas* canvas); | 51 // virtual void OnPaint(gfx::Canvas* canvas); |
| 52 |
| 53 FullscreenExitBubbleViews* bubble_; |
39 | 54 |
40 // Clickable hint text to show in the bubble. | 55 // Clickable hint text to show in the bubble. |
41 views::Link link_; | 56 views::Link link_; |
| 57 views::Label site_info_; |
| 58 views::NativeTextButton* accept_button_; |
| 59 views::NativeTextButton* deny_button_; |
| 60 |
| 61 bool show_buttons_; |
42 }; | 62 }; |
43 | 63 |
44 FullscreenExitBubbleViews::FullscreenExitView::FullscreenExitView( | 64 FullscreenExitBubbleViews::FullscreenExitView::FullscreenExitView( |
45 FullscreenExitBubbleViews* bubble, | 65 FullscreenExitBubbleViews* bubble, |
46 const std::wstring& accelerator) { | 66 const std::wstring& accelerator, |
| 67 const GURL& url, |
| 68 bool show_buttons) |
| 69 : bubble_(bubble), |
| 70 accept_button_(NULL), |
| 71 deny_button_(NULL), |
| 72 show_buttons_(show_buttons) { |
47 link_.set_parent_owned(false); | 73 link_.set_parent_owned(false); |
| 74 link_.set_collapse_when_hidden(false); |
| 75 link_.set_focusable(false); |
48 #if !defined(OS_CHROMEOS) | 76 #if !defined(OS_CHROMEOS) |
49 link_.SetText( | 77 link_.SetText( |
50 UTF16ToWide(l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE, | 78 UTF16ToWide(l10n_util::GetStringFUTF16(IDS_EXIT_FULLSCREEN_MODE, |
51 WideToUTF16(accelerator)))); | 79 WideToUTF16(accelerator)))); |
52 #else | 80 #else |
53 link_.SetText( | 81 link_.SetText( |
54 UTF16ToWide(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE))); | 82 UTF16ToWide(l10n_util::GetStringUTF16(IDS_EXIT_FULLSCREEN_MODE))); |
55 #endif | 83 #endif |
56 link_.set_listener(bubble); | 84 link_.set_listener(bubble); |
57 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( | 85 link_.SetFont(ResourceBundle::GetSharedInstance().GetFont( |
58 ResourceBundle::LargeFont)); | 86 ResourceBundle::MediumFont)); |
59 link_.SetNormalColor(SK_ColorWHITE); | 87 link_.SetNormalColor(SK_ColorBLACK); |
60 link_.SetHighlightedColor(SK_ColorWHITE); | 88 link_.SetHighlightedColor(SK_ColorBLACK); |
| 89 |
| 90 site_info_.set_parent_owned(false); |
| 91 site_info_.SetText( |
| 92 UTF16ToWide(l10n_util::GetStringFUTF16(IDS_FULLSCREEN_INFOBAR_REQUEST_PERMIS
SION, |
| 93 UTF8ToUTF16(url.host())))); |
| 94 site_info_.SetFont(ResourceBundle::GetSharedInstance().GetFont( |
| 95 ResourceBundle::MediumFont)); |
| 96 AddChildView(&site_info_); |
61 AddChildView(&link_); | 97 AddChildView(&link_); |
| 98 |
| 99 views::BubbleBorder* bubble_border = new views::BubbleBorder(views::BubbleBord
er::NONE); |
| 100 bubble_border->set_background_color(Bubble::kBackgroundColor); |
| 101 set_background(new views::BubbleBackground(bubble_border)); |
| 102 set_border(bubble_border); |
| 103 |
| 104 accept_button_ = new views::NativeTextButton(this, |
| 105 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FULLSCREEN_INFOBAR_ALLOW))); |
| 106 AddChildView(accept_button_); |
| 107 |
| 108 deny_button_ = new views::NativeTextButton(this, |
| 109 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FULLSCREEN_INFOBAR_DENY))); |
| 110 AddChildView(deny_button_); |
| 111 accept_button_->set_focusable(false); |
| 112 deny_button_->set_focusable(false); |
| 113 link_.SetVisible(false); |
| 114 if (!show_buttons_) { |
| 115 HideButtons(); |
| 116 } |
62 } | 117 } |
63 | 118 |
64 FullscreenExitBubbleViews::FullscreenExitView::~FullscreenExitView() { | 119 FullscreenExitBubbleViews::FullscreenExitView::~FullscreenExitView() { |
65 } | 120 } |
66 | 121 |
| 122 void FullscreenExitBubbleViews::FullscreenExitView::ButtonPressed( |
| 123 views::Button* sender, const views::Event& event) { |
| 124 if (sender == accept_button_) |
| 125 bubble_->OnAcceptFullscreen(); |
| 126 else |
| 127 bubble_->OnCancelFullscreen(); |
| 128 } |
| 129 |
| 130 void FullscreenExitBubbleViews::FullscreenExitView::HideButtons() { |
| 131 show_buttons_ = false; |
| 132 accept_button_->SetVisible(false); |
| 133 deny_button_->SetVisible(false); |
| 134 link_.SetVisible(true); |
| 135 } |
| 136 |
67 gfx::Size FullscreenExitBubbleViews::FullscreenExitView::GetPreferredSize() { | 137 gfx::Size FullscreenExitBubbleViews::FullscreenExitView::GetPreferredSize() { |
68 gfx::Size preferred_size(link_.GetPreferredSize()); | 138 gfx::Size link_preferred_size(link_.GetPreferredSize()); |
69 preferred_size.Enlarge(kPaddingPx * 2, kPaddingPx * 2); | 139 gfx::Size site_info_preferred_size(site_info_.GetPreferredSize()); |
70 return preferred_size; | 140 gfx::Size accept_preferred_size(accept_button_->GetPreferredSize()); |
| 141 gfx::Size deny_preferred_size(deny_button_->GetPreferredSize()); |
| 142 gfx::Insets insets(GetInsets()); |
| 143 |
| 144 int buttons_width = accept_preferred_size.width() + kPaddingPx + |
| 145 deny_preferred_size.width(); |
| 146 int button_box_width = std::max(buttons_width, link_preferred_size.width()); |
| 147 int width = kPaddingPx + site_info_preferred_size.width() + kMiddlePaddingPx + |
| 148 button_box_width + kPaddingPx; |
| 149 |
| 150 gfx::Size result(width + insets.width(), |
| 151 kPaddingPx * 2 + accept_preferred_size.height() + insets.height()); |
| 152 return result; |
71 } | 153 } |
72 | 154 |
73 void FullscreenExitBubbleViews::FullscreenExitView::Layout() { | 155 void FullscreenExitBubbleViews::FullscreenExitView::Layout() { |
74 gfx::Size link_preferred_size(link_.GetPreferredSize()); | 156 gfx::Size link_preferred_size(link_.GetPreferredSize()); |
75 link_.SetBounds(kPaddingPx, | 157 gfx::Size site_info_preferred_size(site_info_.GetPreferredSize()); |
76 height() - kPaddingPx - link_preferred_size.height(), | 158 gfx::Size accept_preferred_size(accept_button_->GetPreferredSize()); |
| 159 gfx::Size deny_preferred_size(deny_button_->GetPreferredSize()); |
| 160 gfx::Insets insets(GetInsets()); |
| 161 |
| 162 int inner_height = height() - insets.height(); |
| 163 int button_box_x = insets.left() + kPaddingPx + site_info_preferred_size.width
() + |
| 164 kMiddlePaddingPx; |
| 165 int site_info_y = insets.top() + |
| 166 (inner_height - site_info_preferred_size.height()) / 2; |
| 167 int link_y = insets.top() + (inner_height - link_preferred_size.height()) / 2; |
| 168 |
| 169 site_info_.SetBounds(insets.left() + kPaddingPx, |
| 170 site_info_y, |
| 171 site_info_preferred_size.width(), |
| 172 site_info_preferred_size.height()); |
| 173 link_.SetBounds(width() - insets.right() - kPaddingPx - link_preferred_size.wi
dth(), |
| 174 link_y, |
77 link_preferred_size.width(), link_preferred_size.height()); | 175 link_preferred_size.width(), link_preferred_size.height()); |
78 } | 176 if (show_buttons_) { |
79 | 177 accept_button_->SetBounds(button_box_x, |
80 void FullscreenExitBubbleViews::FullscreenExitView::OnPaint( | 178 insets.top() + kPaddingPx, |
81 gfx::Canvas* canvas) { | 179 accept_preferred_size.width(), |
82 // Create a round-bottomed rect to fill the whole View. | 180 accept_preferred_size.height()); |
83 SkRect rect; | 181 deny_button_->SetBounds( |
84 SkScalar padding = SkIntToScalar(kPaddingPx); | 182 button_box_x + accept_preferred_size.width() + kPaddingPx, |
85 // The "-padding" top coordinate ensures that the rect is always tall enough | 183 insets.top() + kPaddingPx, |
86 // to contain the complete rounded corner radius. If we set this to 0, as the | 184 deny_preferred_size.width(), |
87 // popup slides offscreen (in reality, squishes to 0 height), the corners will | 185 deny_preferred_size.height()); |
88 // flatten out as the height becomes less than the corner radius. | 186 } |
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 | |
94 // Fill it black. | |
95 SkPaint paint; | |
96 paint.setStyle(SkPaint::kFill_Style); | |
97 paint.setFlags(SkPaint::kAntiAlias_Flag); | |
98 paint.setColor(SK_ColorBLACK); | |
99 canvas->GetSkCanvas()->drawPath(path, paint); | |
100 } | 187 } |
101 | 188 |
102 // FullscreenExitBubbleViews --------------------------------------------------- | 189 // FullscreenExitBubbleViews --------------------------------------------------- |
103 | 190 |
104 FullscreenExitBubbleViews::FullscreenExitBubbleViews( | 191 FullscreenExitBubbleViews::FullscreenExitBubbleViews( |
105 views::Widget* frame, | 192 views::Widget* frame, |
106 CommandUpdater::CommandUpdaterDelegate* delegate) | 193 Browser* browser, |
107 : FullscreenExitBubble(delegate), | 194 const GURL& url, |
| 195 bool show_buttons) |
| 196 : FullscreenExitBubble(browser), |
108 root_view_(frame->GetRootView()), | 197 root_view_(frame->GetRootView()), |
109 popup_(NULL), | 198 popup_(NULL), |
110 size_animation_(new ui::SlideAnimation(this)) { | 199 size_animation_(new ui::SlideAnimation(this)), |
| 200 url_(url) { |
111 size_animation_->Reset(1); | 201 size_animation_->Reset(1); |
112 | 202 |
113 // Create the contents view. | 203 // Create the contents view. |
114 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); | 204 views::Accelerator accelerator(ui::VKEY_UNKNOWN, false, false, false); |
115 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); | 205 bool got_accelerator = frame->GetAccelerator(IDC_FULLSCREEN, &accelerator); |
116 DCHECK(got_accelerator); | 206 DCHECK(got_accelerator); |
117 view_ = new FullscreenExitView( | 207 view_ = new FullscreenExitView( |
118 this, UTF16ToWideHack(accelerator.GetShortcutText())); | 208 this, UTF16ToWideHack(accelerator.GetShortcutText()), url, show_buttons); |
119 | 209 |
120 // Initialize the popup. | 210 // Initialize the popup. |
121 popup_ = new views::Widget; | 211 popup_ = new views::Widget; |
122 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 212 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
123 params.transparent = true; | 213 params.transparent = true; |
124 params.can_activate = false; | 214 params.can_activate = false; |
125 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 215 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
126 params.parent = frame->GetNativeView(); | 216 params.parent = frame->GetNativeView(); |
127 params.bounds = GetPopupRect(false); | 217 params.bounds = GetPopupRect(false); |
128 popup_->Init(params); | 218 popup_->Init(params); |
| 219 gfx::Size size = GetPopupRect(true).size(); |
129 popup_->SetContentsView(view_); | 220 popup_->SetContentsView(view_); |
130 popup_->SetOpacity(static_cast<unsigned char>(0xff * kOpacity)); | 221 popup_->GetRootView()->SetLayoutManager(NULL); |
| 222 view_->SetBounds(0, 0, size.width(), size.height()); |
131 popup_->Show(); // This does not activate the popup. | 223 popup_->Show(); // This does not activate the popup. |
132 | 224 |
133 StartWatchingMouse(); | 225 if (!show_buttons) |
| 226 StartWatchingMouse(); |
134 } | 227 } |
135 | 228 |
136 FullscreenExitBubbleViews::~FullscreenExitBubbleViews() { | 229 FullscreenExitBubbleViews::~FullscreenExitBubbleViews() { |
137 // This is tricky. We may be in an ATL message handler stack, in which case | 230 // 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 | 231 // 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 | 232 // 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 | 233 // 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 | 234 // 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 | 235 // 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 | 236 // another OnFinalMessage() call (if not, as currently). So instead, we tell |
144 // the popup to synchronously hide, and then asynchronously close and delete | 237 // the popup to synchronously hide, and then asynchronously close and delete |
145 // itself. | 238 // itself. |
146 popup_->Close(); | 239 popup_->Close(); |
147 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); | 240 MessageLoop::current()->DeleteSoon(FROM_HERE, popup_); |
148 } | 241 } |
149 | 242 |
150 void FullscreenExitBubbleViews::LinkClicked( | 243 void FullscreenExitBubbleViews::LinkClicked( |
151 views::Link* source, int event_flags) { | 244 views::Link* source, int event_flags) { |
152 ToggleFullscreen(); | 245 ToggleFullscreen(); |
153 } | 246 } |
154 | 247 |
| 248 void FullscreenExitBubbleViews::OnAcceptFullscreen() { |
| 249 AcceptFullscreen(url_); |
| 250 view_->HideButtons(); |
| 251 StartWatchingMouse(); |
| 252 } |
| 253 |
| 254 void FullscreenExitBubbleViews::OnCancelFullscreen() { |
| 255 CancelFullscreen(); |
| 256 } |
| 257 |
155 void FullscreenExitBubbleViews::AnimationProgressed( | 258 void FullscreenExitBubbleViews::AnimationProgressed( |
156 const ui::Animation* animation) { | 259 const ui::Animation* animation) { |
157 gfx::Rect popup_rect(GetPopupRect(false)); | 260 gfx::Rect popup_rect(GetPopupRect(false)); |
158 if (popup_rect.IsEmpty()) { | 261 if (popup_rect.IsEmpty()) { |
159 popup_->Hide(); | 262 popup_->Hide(); |
160 } else { | 263 } else { |
161 popup_->SetBounds(popup_rect); | 264 popup_->SetBounds(popup_rect); |
| 265 view_->SetY(popup_rect.height() - view_->height()); |
162 popup_->Show(); | 266 popup_->Show(); |
163 } | 267 } |
164 } | 268 } |
| 269 |
165 void FullscreenExitBubbleViews::AnimationEnded( | 270 void FullscreenExitBubbleViews::AnimationEnded( |
166 const ui::Animation* animation) { | 271 const ui::Animation* animation) { |
167 AnimationProgressed(animation); | 272 AnimationProgressed(animation); |
168 } | 273 } |
169 | 274 |
170 void FullscreenExitBubbleViews::Hide() { | 275 void FullscreenExitBubbleViews::Hide() { |
171 size_animation_->SetSlideDuration(kSlideOutDurationMs); | 276 size_animation_->SetSlideDuration(kSlideOutDurationMs); |
172 size_animation_->Hide(); | 277 size_animation_->Hide(); |
173 } | 278 } |
174 | 279 |
(...skipping 30 matching lines...) Expand all Loading... |
205 } | 310 } |
206 // NOTE: don't use the bounds of the root_view_. On linux changing window | 311 // 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. | 312 // size is async. Instead we use the size of the screen. |
208 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow( | 313 gfx::Rect screen_bounds = gfx::Screen::GetMonitorAreaNearestWindow( |
209 root_view_->GetWidget()->GetNativeView()); | 314 root_view_->GetWidget()->GetNativeView()); |
210 gfx::Point origin(screen_bounds.x() + | 315 gfx::Point origin(screen_bounds.x() + |
211 (screen_bounds.width() - size.width()) / 2, | 316 (screen_bounds.width() - size.width()) / 2, |
212 screen_bounds.y()); | 317 screen_bounds.y()); |
213 return gfx::Rect(origin, size); | 318 return gfx::Rect(origin, size); |
214 } | 319 } |
OLD | NEW |