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/speech/speech_input_bubble.h" | 5 #include "chrome/browser/speech/speech_input_bubble.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/message_loop.h" | |
10 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
11 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
12 #include "chrome/browser/ui/views/bubble/bubble.h" | |
13 #include "chrome/browser/ui/views/frame/browser_view.h" | 11 #include "chrome/browser/ui/views/frame/browser_view.h" |
12 #include "chrome/browser/ui/views/location_bar/location_icon_view.h" | |
14 #include "chrome/browser/ui/views/toolbar_view.h" | 13 #include "chrome/browser/ui/views/toolbar_view.h" |
15 #include "content/browser/tab_contents/tab_contents.h" | 14 #include "content/browser/tab_contents/tab_contents.h" |
16 #include "content/browser/tab_contents/tab_contents_view.h" | 15 #include "content/browser/tab_contents/tab_contents_view.h" |
17 #include "grit/generated_resources.h" | 16 #include "grit/generated_resources.h" |
18 #include "grit/theme_resources.h" | 17 #include "grit/theme_resources.h" |
19 #include "media/audio/audio_manager.h" | 18 #include "media/audio/audio_manager.h" |
20 #include "ui/base/l10n/l10n_util.h" | 19 #include "ui/base/l10n/l10n_util.h" |
21 #include "ui/base/resource/resource_bundle.h" | 20 #include "ui/base/resource/resource_bundle.h" |
22 #include "ui/gfx/canvas.h" | 21 #include "views/bubble/bubble_delegate.h" |
23 #include "views/border.h" | |
24 #include "views/controls/button/text_button.h" | 22 #include "views/controls/button/text_button.h" |
25 #include "views/controls/image_view.h" | 23 #include "views/controls/image_view.h" |
26 #include "views/controls/label.h" | 24 #include "views/controls/label.h" |
27 #include "views/controls/link.h" | 25 #include "views/controls/link.h" |
28 #include "views/controls/link_listener.h" | 26 #include "views/controls/link_listener.h" |
29 #include "views/layout/layout_constants.h" | 27 #include "views/layout/layout_constants.h" |
30 #include "views/view.h" | |
31 | 28 |
32 namespace { | 29 namespace { |
33 | 30 |
31 // TODO(msw): Get color from theme/window color. | |
32 const SkColor kColor = SK_ColorWHITE; | |
33 | |
34 const int kBubbleHorizMargin = 6; | 34 const int kBubbleHorizMargin = 6; |
35 const int kBubbleVertMargin = 4; | 35 const int kBubbleVertMargin = 4; |
36 const int kBubbleHeadingVertMargin = 6; | 36 const int kBubbleHeadingVertMargin = 6; |
37 const int kIconHorizontalOffset = 27; | 37 const int kIconHorizontalOffset = 27; |
38 const int kIconVerticalOffset = -7; | 38 const int kIconVerticalOffset = -7; |
39 | 39 |
40 // This is the content view which is placed inside a SpeechInputBubble. | 40 // This is the SpeechInputBubble content and views bubble delegate. |
41 class ContentView | 41 class SpeechInputBubbleView |
42 : public views::View, | 42 : public views::BubbleDelegateView, |
43 public views::ButtonListener, | 43 public views::ButtonListener, |
44 public views::LinkListener { | 44 public views::LinkListener { |
45 public: | 45 public: |
46 explicit ContentView(SpeechInputBubbleDelegate* delegate); | 46 SpeechInputBubbleView(SpeechInputBubbleDelegate* delegate, |
47 views::View* anchor_view, | |
48 const gfx::Rect& element_rect, | |
49 TabContents* tab_contents); | |
47 | 50 |
48 void UpdateLayout(SpeechInputBubbleBase::DisplayMode mode, | 51 void UpdateLayout(SpeechInputBubbleBase::DisplayMode mode, |
49 const string16& message_text, | 52 const string16& message_text, |
50 const SkBitmap& image); | 53 const SkBitmap& image); |
51 void SetImage(const SkBitmap& image); | 54 void SetImage(const SkBitmap& image); |
52 | 55 |
56 // views::BubbleDelegateView methods. | |
57 virtual void OnWidgetActivationChanged(views::Widget* widget, | |
58 bool active) OVERRIDE; | |
59 virtual gfx::Point GetAnchorPoint() OVERRIDE; | |
60 virtual void Init() OVERRIDE; | |
61 | |
53 // views::ButtonListener methods. | 62 // views::ButtonListener methods. |
54 virtual void ButtonPressed(views::Button* source, const views::Event& event); | 63 virtual void ButtonPressed(views::Button* source, const views::Event& event); |
55 | 64 |
56 // views::LinkListener methods. | 65 // views::LinkListener methods. |
57 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; | 66 virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE; |
58 | 67 |
59 // views::View overrides. | 68 // views::View overrides. |
60 virtual gfx::Size GetPreferredSize(); | 69 virtual gfx::Size GetPreferredSize(); |
61 virtual void Layout(); | 70 virtual void Layout(); |
62 | 71 |
63 private: | 72 private: |
64 SpeechInputBubbleDelegate* delegate_; | 73 SpeechInputBubbleDelegate* delegate_; |
74 gfx::Rect element_rect_; | |
75 TabContents* tab_contents_; | |
65 views::ImageView* icon_; | 76 views::ImageView* icon_; |
66 views::Label* heading_; | 77 views::Label* heading_; |
67 views::Label* message_; | 78 views::Label* message_; |
68 views::TextButton* try_again_; | 79 views::TextButton* try_again_; |
69 views::TextButton* cancel_; | 80 views::TextButton* cancel_; |
70 views::Link* mic_settings_; | 81 views::Link* mic_settings_; |
71 SpeechInputBubbleBase::DisplayMode display_mode_; | 82 SpeechInputBubbleBase::DisplayMode display_mode_; |
72 const int kIconLayoutMinWidth; | 83 const int kIconLayoutMinWidth; |
73 | 84 |
74 DISALLOW_COPY_AND_ASSIGN(ContentView); | 85 DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleView); |
75 }; | 86 }; |
76 | 87 |
77 ContentView::ContentView(SpeechInputBubbleDelegate* delegate) | 88 SpeechInputBubbleView::SpeechInputBubbleView( |
78 : delegate_(delegate), | 89 SpeechInputBubbleDelegate* delegate, |
79 display_mode_(SpeechInputBubbleBase::DISPLAY_MODE_WARM_UP), | 90 views::View* anchor_view, |
80 kIconLayoutMinWidth(ResourceBundle::GetSharedInstance().GetBitmapNamed( | 91 const gfx::Rect& element_rect, |
81 IDR_SPEECH_INPUT_MIC_EMPTY)->width()) { | 92 TabContents* tab_contents) |
93 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT, kColor), | |
94 delegate_(delegate), | |
95 element_rect_(element_rect), | |
96 tab_contents_(tab_contents), | |
97 display_mode_(SpeechInputBubbleBase::DISPLAY_MODE_WARM_UP), | |
98 kIconLayoutMinWidth(ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
99 IDR_SPEECH_INPUT_MIC_EMPTY)->width()) { | |
100 set_close_on_esc(false); | |
msw
2011/11/17 07:05:25
indentation fixed.
| |
101 } | |
102 | |
103 void SpeechInputBubbleView::OnWidgetActivationChanged(views::Widget* widget, | |
104 bool active) { | |
105 if (widget == GetWidget() && !active) | |
106 delegate_->InfoBubbleFocusChanged(); | |
107 BubbleDelegateView::OnWidgetActivationChanged(widget, active); | |
108 } | |
109 | |
110 gfx::Point SpeechInputBubbleView::GetAnchorPoint() { | |
111 gfx::Rect container_rect; | |
112 tab_contents_->GetContainerBounds(&container_rect); | |
113 gfx::Point anchor(container_rect.x() + element_rect_.CenterPoint().x(), | |
114 container_rect.y() + element_rect_.bottom()); | |
115 if (!container_rect.Contains(anchor)) | |
116 return BubbleDelegateView::GetAnchorPoint(); | |
117 return anchor; | |
118 } | |
119 | |
120 void SpeechInputBubbleView::Init() { | |
82 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 121 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
83 const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont); | 122 const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont); |
84 | 123 |
85 heading_ = new views::Label( | 124 heading_ = new views::Label( |
86 l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_BUBBLE_HEADING)); | 125 l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_BUBBLE_HEADING)); |
87 heading_->set_border(views::Border::CreateEmptyBorder( | 126 heading_->set_border(views::Border::CreateEmptyBorder( |
88 kBubbleHeadingVertMargin, 0, kBubbleHeadingVertMargin, 0)); | 127 kBubbleHeadingVertMargin, 0, kBubbleHeadingVertMargin, 0)); |
89 heading_->SetFont(font); | 128 heading_->SetFont(font); |
90 heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | 129 heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); |
91 heading_->SetText( | 130 heading_->SetText( |
(...skipping 17 matching lines...) Expand all Loading... | |
109 try_again_ = new views::NativeTextButton( | 148 try_again_ = new views::NativeTextButton( |
110 this, l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_TRY_AGAIN)); | 149 this, l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_TRY_AGAIN)); |
111 AddChildView(try_again_); | 150 AddChildView(try_again_); |
112 | 151 |
113 mic_settings_ = new views::Link( | 152 mic_settings_ = new views::Link( |
114 l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_MIC_SETTINGS)); | 153 l10n_util::GetStringUTF16(IDS_SPEECH_INPUT_MIC_SETTINGS)); |
115 mic_settings_->set_listener(this); | 154 mic_settings_->set_listener(this); |
116 AddChildView(mic_settings_); | 155 AddChildView(mic_settings_); |
117 } | 156 } |
118 | 157 |
119 void ContentView::UpdateLayout(SpeechInputBubbleBase::DisplayMode mode, | 158 void SpeechInputBubbleView::UpdateLayout( |
120 const string16& message_text, | 159 SpeechInputBubbleBase::DisplayMode mode, |
121 const SkBitmap& image) { | 160 const string16& message_text, |
161 const SkBitmap& image) { | |
122 display_mode_ = mode; | 162 display_mode_ = mode; |
123 bool is_message = (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE); | 163 bool is_message = (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE); |
124 icon_->SetVisible(!is_message); | 164 icon_->SetVisible(!is_message); |
125 message_->SetVisible(is_message); | 165 message_->SetVisible(is_message); |
126 mic_settings_->SetVisible(is_message); | 166 mic_settings_->SetVisible(is_message); |
127 try_again_->SetVisible(is_message); | 167 try_again_->SetVisible(is_message); |
128 cancel_->SetVisible(mode != SpeechInputBubbleBase::DISPLAY_MODE_WARM_UP); | 168 cancel_->SetVisible(mode != SpeechInputBubbleBase::DISPLAY_MODE_WARM_UP); |
129 heading_->SetVisible(mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING); | 169 heading_->SetVisible(mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING); |
130 | 170 |
131 if (is_message) { | 171 if (is_message) { |
132 message_->SetText(message_text); | 172 message_->SetText(message_text); |
133 } else { | 173 } else { |
134 SetImage(image); | 174 SetImage(image); |
alicet1
2011/11/17 17:59:13
is this method needed anywhere else? otherwise jus
msw
2011/11/17 20:42:53
SetImage is also called by SpeechInputBubbleImpl::
| |
135 } | 175 } |
136 | 176 |
137 if (icon_->IsVisible()) | 177 if (icon_->IsVisible()) |
138 icon_->ResetImageSize(); | 178 icon_->ResetImageSize(); |
139 | 179 |
140 // When moving from warming up to recording state, the size of the content | 180 // When moving from warming up to recording state, the size of the content |
141 // stays the same. So we wouldn't get a resize/layout call from the view | 181 // stays the same. So we wouldn't get a resize/layout call from the view |
142 // system and we do it ourselves. | 182 // system and we do it ourselves. |
143 if (GetPreferredSize() == size()) // |size()| here is the current size. | 183 if (GetPreferredSize() == size()) // |size()| here is the current size. |
144 Layout(); | 184 Layout(); |
185 | |
186 SizeToContents(); | |
145 } | 187 } |
146 | 188 |
147 void ContentView::SetImage(const SkBitmap& image) { | 189 void SpeechInputBubbleView::SetImage(const SkBitmap& image) { |
148 icon_->SetImage(image); | 190 icon_->SetImage(image); |
149 } | 191 } |
150 | 192 |
151 void ContentView::ButtonPressed(views::Button* source, | 193 void SpeechInputBubbleView::ButtonPressed(views::Button* source, |
152 const views::Event& event) { | 194 const views::Event& event) { |
153 if (source == cancel_) { | 195 if (source == cancel_) { |
154 delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL); | 196 delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL); |
197 GetWidget()->RemoveObserver(this); | |
155 } else if (source == try_again_) { | 198 } else if (source == try_again_) { |
156 delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN); | 199 delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN); |
157 } else { | 200 } else { |
158 NOTREACHED() << "Unknown button"; | 201 NOTREACHED() << "Unknown button"; |
159 } | 202 } |
160 } | 203 } |
161 | 204 |
162 void ContentView::LinkClicked(views::Link* source, int event_flags) { | 205 void SpeechInputBubbleView::LinkClicked(views::Link* source, int event_flags) { |
163 DCHECK_EQ(source, mic_settings_); | 206 DCHECK_EQ(source, mic_settings_); |
164 AudioManager::GetAudioManager()->ShowAudioInputSettings(); | 207 AudioManager::GetAudioManager()->ShowAudioInputSettings(); |
165 } | 208 } |
166 | 209 |
167 gfx::Size ContentView::GetPreferredSize() { | 210 gfx::Size SpeechInputBubbleView::GetPreferredSize() { |
168 int width = heading_->GetPreferredSize().width(); | 211 int width = heading_->GetPreferredSize().width(); |
169 int control_width = cancel_->GetPreferredSize().width(); | 212 int control_width = cancel_->GetPreferredSize().width(); |
170 if (try_again_->IsVisible()) { | 213 if (try_again_->IsVisible()) { |
171 control_width += try_again_->GetPreferredSize().width() + | 214 control_width += try_again_->GetPreferredSize().width() + |
172 views::kRelatedButtonHSpacing; | 215 views::kRelatedButtonHSpacing; |
173 } | 216 } |
174 width = std::max(width, control_width); | 217 width = std::max(width, control_width); |
175 control_width = std::max(icon_->GetPreferredSize().width(), | 218 control_width = std::max(icon_->GetPreferredSize().width(), |
176 kIconLayoutMinWidth); | 219 kIconLayoutMinWidth); |
177 width = std::max(width, control_width); | 220 width = std::max(width, control_width); |
(...skipping 12 matching lines...) Expand all Loading... | |
190 if (icon_->IsVisible()) | 233 if (icon_->IsVisible()) |
191 height += icon_->GetImage().height(); | 234 height += icon_->GetImage().height(); |
192 if (mic_settings_->IsVisible()) | 235 if (mic_settings_->IsVisible()) |
193 height += mic_settings_->GetPreferredSize().height(); | 236 height += mic_settings_->GetPreferredSize().height(); |
194 width += kBubbleHorizMargin * 2; | 237 width += kBubbleHorizMargin * 2; |
195 height += kBubbleVertMargin * 2; | 238 height += kBubbleVertMargin * 2; |
196 | 239 |
197 return gfx::Size(width, height); | 240 return gfx::Size(width, height); |
198 } | 241 } |
199 | 242 |
200 void ContentView::Layout() { | 243 void SpeechInputBubbleView::Layout() { |
201 int x = kBubbleHorizMargin; | 244 int x = kBubbleHorizMargin; |
202 int y = kBubbleVertMargin; | 245 int y = kBubbleVertMargin; |
203 int available_width = width() - kBubbleHorizMargin * 2; | 246 int available_width = width() - kBubbleHorizMargin * 2; |
204 int available_height = height() - kBubbleVertMargin * 2; | 247 int available_height = height() - kBubbleVertMargin * 2; |
205 | 248 |
206 if (message_->IsVisible()) { | 249 if (message_->IsVisible()) { |
207 DCHECK(try_again_->IsVisible()); | 250 DCHECK(try_again_->IsVisible()); |
208 | 251 |
209 int control_height = try_again_->GetPreferredSize().height(); | 252 int control_height = try_again_->GetPreferredSize().height(); |
210 int try_again_width = try_again_->GetPreferredSize().width(); | 253 int try_again_width = try_again_->GetPreferredSize().width(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 if (cancel_->IsVisible()) { | 285 if (cancel_->IsVisible()) { |
243 control_height = cancel_->GetPreferredSize().height(); | 286 control_height = cancel_->GetPreferredSize().height(); |
244 int width = cancel_->GetPreferredSize().width(); | 287 int width = cancel_->GetPreferredSize().width(); |
245 cancel_->SetBounds(x + (available_width - width) / 2, y, width, | 288 cancel_->SetBounds(x + (available_width - width) / 2, y, width, |
246 control_height); | 289 control_height); |
247 } | 290 } |
248 } | 291 } |
249 } | 292 } |
250 | 293 |
251 // Implementation of SpeechInputBubble. | 294 // Implementation of SpeechInputBubble. |
252 class SpeechInputBubbleImpl | 295 class SpeechInputBubbleImpl : public SpeechInputBubbleBase { |
253 : public SpeechInputBubbleBase, | |
254 public BubbleDelegate { | |
255 public: | 296 public: |
256 SpeechInputBubbleImpl(TabContents* tab_contents, | 297 SpeechInputBubbleImpl(TabContents* tab_contents, |
257 Delegate* delegate, | 298 Delegate* delegate, |
258 const gfx::Rect& element_rect); | 299 const gfx::Rect& element_rect); |
259 virtual ~SpeechInputBubbleImpl(); | 300 virtual ~SpeechInputBubbleImpl(); |
260 | 301 |
261 // SpeechInputBubble methods. | 302 // SpeechInputBubble methods. |
262 virtual void Show() OVERRIDE; | 303 virtual void Show() OVERRIDE; |
263 virtual void Hide() OVERRIDE; | 304 virtual void Hide() OVERRIDE; |
264 | 305 |
265 // SpeechInputBubbleBase methods. | 306 // SpeechInputBubbleBase methods. |
266 virtual void UpdateLayout() OVERRIDE; | 307 virtual void UpdateLayout() OVERRIDE; |
267 virtual void UpdateImage() OVERRIDE; | 308 virtual void UpdateImage() OVERRIDE; |
268 | 309 |
269 // Returns the screen rectangle to use as the info bubble's target. | |
270 // |element_rect| is the html element's bounds in page coordinates. | |
271 gfx::Rect GetInfoBubbleTarget(const gfx::Rect& element_rect); | |
272 | |
273 // BubbleDelegate | |
274 virtual void BubbleClosing(Bubble* bubble, bool closed_by_escape) OVERRIDE; | |
275 virtual bool CloseOnEscape() OVERRIDE; | |
276 virtual bool FadeInOnShow() OVERRIDE; | |
277 | |
278 private: | 310 private: |
279 Delegate* delegate_; | 311 Delegate* delegate_; |
280 Bubble* bubble_; | 312 SpeechInputBubbleView* bubble_; |
281 ContentView* bubble_content_; | |
282 gfx::Rect element_rect_; | 313 gfx::Rect element_rect_; |
283 | 314 |
284 // Set to true if the object is being destroyed normally instead of the | |
285 // user clicking outside the window causing it to close automatically. | |
286 bool did_invoke_close_; | |
287 | |
288 DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleImpl); | 315 DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleImpl); |
289 }; | 316 }; |
290 | 317 |
291 SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents, | 318 SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents, |
292 Delegate* delegate, | 319 Delegate* delegate, |
293 const gfx::Rect& element_rect) | 320 const gfx::Rect& element_rect) |
294 : SpeechInputBubbleBase(tab_contents), | 321 : SpeechInputBubbleBase(tab_contents), |
295 delegate_(delegate), | 322 delegate_(delegate), |
296 bubble_(NULL), | 323 bubble_(NULL), |
297 bubble_content_(NULL), | 324 element_rect_(element_rect) { |
298 element_rect_(element_rect), | |
299 did_invoke_close_(false) { | |
300 } | 325 } |
301 | 326 |
302 SpeechInputBubbleImpl::~SpeechInputBubbleImpl() { | 327 SpeechInputBubbleImpl::~SpeechInputBubbleImpl() { |
303 did_invoke_close_ = true; | |
304 Hide(); | 328 Hide(); |
305 } | 329 } |
306 | 330 |
307 gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget( | |
308 const gfx::Rect& element_rect) { | |
309 gfx::Rect container_rect; | |
310 tab_contents()->GetContainerBounds(&container_rect); | |
311 return gfx::Rect( | |
312 container_rect.x() + element_rect.right() - kBubbleTargetOffsetX, | |
313 container_rect.y() + element_rect.bottom(), 1, 1); | |
314 } | |
315 | |
316 void SpeechInputBubbleImpl::BubbleClosing(Bubble* bubble, | |
317 bool closed_by_escape) { | |
318 bubble_ = NULL; | |
319 bubble_content_ = NULL; | |
320 if (!did_invoke_close_) | |
321 delegate_->InfoBubbleFocusChanged(); | |
alicet1
2011/11/17 17:59:13
I think you moved this to be called when activatio
msw
2011/11/17 20:42:53
In general you would be right to move such code to
| |
322 } | |
323 | |
324 bool SpeechInputBubbleImpl::CloseOnEscape() { | |
alicet1
2011/11/17 17:59:13
this doesn't want close on esc? we should honor?
msw
2011/11/17 20:42:53
Yup, I call set_close_on_esc(false); in the Speech
| |
325 return false; | |
326 } | |
327 | |
328 bool SpeechInputBubbleImpl::FadeInOnShow() { | |
329 return false; | |
330 } | |
331 | |
332 void SpeechInputBubbleImpl::Show() { | 331 void SpeechInputBubbleImpl::Show() { |
333 if (bubble_) | 332 if (bubble_) |
334 return; // nothing to do, already visible. | 333 return; |
335 | 334 |
336 bubble_content_ = new ContentView(delegate_); | 335 // Anchor to the location icon view, in case |element_rect| is offscreen. |
336 Profile* profile = | |
337 Profile::FromBrowserContext(tab_contents()->browser_context()); | |
338 Browser* browser = Browser::GetOrCreateTabbedBrowser(profile); | |
339 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); | |
340 views::View* icon = browser_view->GetLocationBarView()->location_icon_view(); | |
341 bubble_ = new SpeechInputBubbleView(delegate_, icon, element_rect_, | |
342 tab_contents()); | |
343 views::BubbleDelegateView::CreateBubble(bubble_); | |
337 UpdateLayout(); | 344 UpdateLayout(); |
338 | 345 bubble_->Show(); |
339 views::Widget* toplevel_widget = | |
340 views::Widget::GetTopLevelWidgetForNativeView( | |
341 tab_contents()->view()->GetNativeView()); | |
342 if (toplevel_widget) { | |
alicet1
2011/11/17 17:59:13
how come you don't have to check for this now? I t
msw
2011/11/17 20:42:53
This ensured that the toplevel widget was availabl
| |
343 gfx::Rect container_rect; | |
344 tab_contents()->GetContainerBounds(&container_rect); | |
345 gfx::Rect target_rect = GetInfoBubbleTarget(element_rect_); | |
346 if (!container_rect.Contains(target_rect.x(), target_rect.y())) { | |
347 // Target is not in screen view, so point to page icon in omnibox. | |
348 Profile* profile = | |
349 Profile::FromBrowserContext(tab_contents()->browser_context()); | |
350 Browser* browser = Browser::GetOrCreateTabbedBrowser(profile); | |
351 BrowserView* browser_view = | |
352 BrowserView::GetBrowserViewForBrowser(browser); | |
353 gfx::Point point; | |
354 if (base::i18n::IsRTL()) { | |
355 int width = browser_view->toolbar()->location_bar()->width(); | |
356 point = gfx::Point(width - kIconHorizontalOffset, 0); | |
357 } | |
358 point.Offset(0, kIconVerticalOffset); | |
359 views::View::ConvertPointToScreen(browser_view->toolbar()->location_bar(), | |
360 &point); | |
361 target_rect = browser_view->toolbar()->location_bar()->bounds(); | |
362 target_rect.set_origin(point); | |
363 target_rect.set_width(kIconHorizontalOffset); | |
364 } | |
365 bubble_ = Bubble::Show(toplevel_widget, | |
366 target_rect, | |
367 views::BubbleBorder::TOP_LEFT, | |
368 views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR, | |
369 bubble_content_, this); | |
370 // We don't want fade outs when closing because it makes speech recognition | |
371 // appear slower than it is. Also setting it to false allows |Close| to | |
372 // destroy the bubble immediately instead of waiting for the fade animation | |
373 // to end so the caller can manage this object's life cycle like a normal | |
374 // stack based or member variable object. | |
375 bubble_->set_fade_away_on_close(false); | |
376 } | |
377 } | 346 } |
378 | 347 |
379 void SpeechInputBubbleImpl::Hide() { | 348 void SpeechInputBubbleImpl::Hide() { |
380 if (bubble_) | 349 if (bubble_) |
381 bubble_->Close(); | 350 bubble_->GetWidget()->Close(); |
351 bubble_ = NULL; | |
382 } | 352 } |
383 | 353 |
384 void SpeechInputBubbleImpl::UpdateLayout() { | 354 void SpeechInputBubbleImpl::UpdateLayout() { |
385 if (bubble_content_) | 355 if (bubble_) |
386 bubble_content_->UpdateLayout(display_mode(), message_text(), icon_image()); | 356 bubble_->UpdateLayout(display_mode(), message_text(), icon_image()); |
387 if (bubble_) // Will be null on first call. | |
388 bubble_->SizeToContents(); | |
389 } | 357 } |
390 | 358 |
391 void SpeechInputBubbleImpl::UpdateImage() { | 359 void SpeechInputBubbleImpl::UpdateImage() { |
392 if (bubble_content_) | 360 if (bubble_) |
393 bubble_content_->SetImage(icon_image()); | 361 bubble_->SetImage(icon_image()); |
394 } | 362 } |
395 | 363 |
396 } // namespace | 364 } // namespace |
397 | 365 |
398 SpeechInputBubble* SpeechInputBubble::CreateNativeBubble( | 366 SpeechInputBubble* SpeechInputBubble::CreateNativeBubble( |
399 TabContents* tab_contents, | 367 TabContents* tab_contents, |
400 SpeechInputBubble::Delegate* delegate, | 368 SpeechInputBubble::Delegate* delegate, |
401 const gfx::Rect& element_rect) { | 369 const gfx::Rect& element_rect) { |
402 return new SpeechInputBubbleImpl(tab_contents, delegate, element_rect); | 370 return new SpeechInputBubbleImpl(tab_contents, delegate, element_rect); |
403 } | 371 } |
OLD | NEW |