OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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/speech/speech_input_bubble.h" | |
6 | |
7 #include "app/l10n_util.h" | |
8 #include "app/resource_bundle.h" | |
9 #include "base/message_loop.h" | |
10 #include "chrome/browser/browser.h" | |
11 #include "chrome/browser/browser_window.h" | |
12 #include "chrome/browser/tab_contents/tab_contents.h" | |
13 #include "chrome/browser/tab_contents/tab_contents_view.h" | |
14 #include "chrome/browser/views/info_bubble.h" | |
15 #include "chrome/common/notification_observer.h" | |
16 #include "chrome/common/notification_registrar.h" | |
17 #include "chrome/common/notification_service.h" | |
18 #include "chrome/common/notification_type.h" | |
19 #include "gfx/canvas.h" | |
20 #include "grit/generated_resources.h" | |
21 #include "grit/theme_resources.h" | |
22 #include "views/controls/image_view.h" | |
23 #include "views/controls/label.h" | |
24 #include "views/controls/link.h" | |
25 #include "views/standard_layout.h" | |
26 #include "views/view.h" | |
27 | |
28 namespace { | |
29 | |
30 // The speech bubble's arrow is so many pixels from the left of html element. | |
31 const int kBubbleTargetOffsetX = 5; | |
32 const int kBubbleHorizMargin = 40; | |
33 const int kBubbleVertMargin = 0; | |
34 | |
35 // This is the content view which is placed inside a SpeechInputBubble. | |
36 class ContentView | |
37 : public views::View, | |
38 public views::LinkController { | |
39 public: | |
40 explicit ContentView(SpeechInputBubbleDelegate* delegate); | |
41 | |
42 void SetRecognizingMode(); | |
43 | |
44 // views::LinkController methods. | |
45 virtual void LinkActivated(views::Link* source, int event_flags); | |
46 | |
47 // views::View overrides. | |
48 virtual gfx::Size GetPreferredSize(); | |
49 virtual void Layout(); | |
50 | |
51 private: | |
52 SpeechInputBubbleDelegate* delegate_; | |
53 views::ImageView* icon_; | |
54 views::Label* heading_; | |
55 views::Link* cancel_; | |
56 | |
57 DISALLOW_COPY_AND_ASSIGN(ContentView); | |
58 }; | |
59 | |
60 ContentView::ContentView(SpeechInputBubbleDelegate* delegate) | |
61 : delegate_(delegate) { | |
62 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
63 const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont); | |
64 | |
65 heading_ = new views::Label( | |
66 l10n_util::GetString(IDS_SPEECH_INPUT_BUBBLE_HEADING)); | |
67 heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL)); | |
68 heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | |
69 AddChildView(heading_); | |
70 | |
71 icon_ = new views::ImageView(); | |
72 icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
73 IDR_SPEECH_INPUT_RECORDING)); | |
74 icon_->SetHorizontalAlignment(views::ImageView::CENTER); | |
75 AddChildView(icon_); | |
76 | |
77 cancel_ = new views::Link(l10n_util::GetString(IDS_CANCEL)); | |
78 cancel_->SetController(this); | |
79 cancel_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL)); | |
80 cancel_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | |
81 AddChildView(cancel_); | |
82 } | |
83 | |
84 void ContentView::SetRecognizingMode() { | |
85 icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
86 IDR_SPEECH_INPUT_PROCESSING)); | |
87 } | |
88 | |
89 void ContentView::LinkActivated(views::Link* source, int event_flags) { | |
90 if (source == cancel_) { | |
91 delegate_->RecognitionCancelled(); | |
92 } else { | |
93 NOTREACHED() << "Unknown view"; | |
94 } | |
95 } | |
96 | |
97 gfx::Size ContentView::GetPreferredSize() { | |
98 int width = heading_->GetPreferredSize().width(); | |
99 int control_width = cancel_->GetPreferredSize().width(); | |
100 if (control_width > width) | |
101 width = control_width; | |
102 control_width = icon_->GetPreferredSize().width(); | |
103 if (control_width > width) | |
104 width = control_width; | |
105 width += kBubbleHorizMargin * 2; | |
106 | |
107 int height = kBubbleVertMargin * 2 + | |
108 heading_->GetPreferredSize().height() + | |
109 cancel_->GetPreferredSize().height() + | |
110 icon_->GetImage().height(); | |
111 return gfx::Size(width, height); | |
112 } | |
113 | |
114 void ContentView::Layout() { | |
115 int x = kBubbleHorizMargin; | |
116 int y = kBubbleVertMargin; | |
117 int control_width = width() - kBubbleHorizMargin * 2; | |
118 | |
119 int height = heading_->GetPreferredSize().height(); | |
120 heading_->SetBounds(x, y, control_width, height); | |
121 y += height; | |
122 | |
123 height = icon_->GetImage().height(); | |
124 icon_->SetBounds(x, y, control_width, height); | |
125 y += height; | |
126 | |
127 height = cancel_->GetPreferredSize().height(); | |
128 cancel_->SetBounds(x, y, control_width, height); | |
129 } | |
130 | |
131 // Implementation of SpeechInputBubble. | |
132 class SpeechInputBubbleImpl | |
133 : public SpeechInputBubble, | |
134 public InfoBubbleDelegate, | |
135 public NotificationObserver { | |
136 public: | |
137 SpeechInputBubbleImpl(TabContents* tab_contents, | |
138 Delegate* delegate, | |
sky
2010/08/24 16:08:28
align with ( on previous line.
| |
139 const gfx::Rect& element_rect); | |
140 ~SpeechInputBubbleImpl(); | |
sky
2010/08/24 16:08:28
virtual
| |
141 | |
142 virtual void SetRecognizingMode(); | |
143 | |
144 // Returns the screen rectangle to use as the info bubble's target. | |
145 // |element_rect| is the html element's bounds in page coordinates. | |
146 gfx::Rect GetInfoBubbleTarget(const gfx::Rect& element_rect); | |
147 | |
148 // NotificationObserver implementation. | |
149 virtual void Observe(NotificationType type, | |
150 const NotificationSource& source, | |
151 const NotificationDetails& details); | |
152 | |
153 // InfoBubbleDelegate | |
154 virtual void InfoBubbleClosing(InfoBubble* info_bubble, | |
155 bool closed_by_escape); | |
156 virtual bool CloseOnEscape(); | |
157 virtual bool FadeInOnShow(); | |
158 | |
159 private: | |
160 Delegate* delegate_; | |
161 InfoBubble* info_bubble_; | |
162 TabContents* tab_contents_; | |
163 ContentView* bubble_content_; | |
164 NotificationRegistrar registrar_; | |
165 bool did_close_; // Set to true if |Close()| was invoked by caller. | |
sky
2010/08/24 16:08:28
Update comment.
| |
166 | |
167 DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleImpl); | |
168 }; | |
169 | |
170 SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents, | |
171 Delegate* delegate, | |
172 const gfx::Rect& element_rect) | |
173 : delegate_(delegate), | |
174 info_bubble_(NULL), | |
175 tab_contents_(tab_contents), | |
176 bubble_content_(NULL), | |
177 did_close_(false) { | |
178 bubble_content_ = new ContentView(delegate_); | |
179 | |
180 views::Widget* parent = views::Widget::GetWidgetFromNativeWindow( | |
181 tab_contents_->view()->GetTopLevelNativeWindow()); | |
182 info_bubble_ = InfoBubble::Show(parent, | |
183 GetInfoBubbleTarget(element_rect), | |
184 BubbleBorder::TOP_LEFT, bubble_content_, | |
185 this); | |
186 | |
187 // We don't want fade outs when closing because it makes speech recognition | |
188 // appear slower than it is. Also setting it to false allows |Close| to | |
189 // destroy the bubble immediately instead of waiting for the fade animation | |
190 // to end so the caller can manage this object's life cycle like a normal | |
191 // stack based or member variable object. | |
192 info_bubble_->set_fade_away_on_close(false); | |
193 | |
194 registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
195 Source<TabContents>(tab_contents_)); | |
196 } | |
197 | |
198 SpeechInputBubbleImpl::~SpeechInputBubbleImpl() { | |
199 if (info_bubble_) { | |
200 did_close_ = true; | |
201 info_bubble_->Close(); | |
202 } | |
203 } | |
204 | |
205 void SpeechInputBubbleImpl::SetRecognizingMode() { | |
206 DCHECK(info_bubble_); | |
207 DCHECK(bubble_content_); | |
208 bubble_content_->SetRecognizingMode(); | |
209 } | |
210 | |
211 gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget( | |
212 const gfx::Rect& element_rect) { | |
213 gfx::Rect container_rect; | |
214 tab_contents_->GetContainerBounds(&container_rect); | |
215 return gfx::Rect( | |
216 container_rect.x() + element_rect.x() + kBubbleTargetOffsetX, | |
217 container_rect.y() + element_rect.y() + element_rect.height(), 1, 1); | |
sky
2010/08/24 16:08:28
Sounds the size be that of element_rect?
Satish
2010/08/24 16:22:04
We want the bubble's arrow to point at x, y positi
| |
218 } | |
219 | |
220 void SpeechInputBubbleImpl::Observe(NotificationType type, | |
221 const NotificationSource& source, | |
222 const NotificationDetails& details) { | |
223 if (type == NotificationType::TAB_CONTENTS_DESTROYED) { | |
224 delegate_->RecognitionCancelled(); | |
225 } else { | |
226 NOTREACHED() << "Unknown notification"; | |
227 } | |
228 } | |
229 | |
230 void SpeechInputBubbleImpl::InfoBubbleClosing(InfoBubble* info_bubble, | |
231 bool closed_by_escape) { | |
232 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
233 Source<TabContents>(tab_contents_)); | |
234 info_bubble_ = NULL; | |
235 bubble_content_ = NULL; | |
236 if (!did_close_) | |
237 delegate_->InfoBubbleClosed(); | |
238 } | |
239 | |
240 bool SpeechInputBubbleImpl::CloseOnEscape() { | |
241 return false; | |
242 } | |
243 | |
244 bool SpeechInputBubbleImpl::FadeInOnShow() { | |
245 return false; | |
246 } | |
247 | |
248 } // namespace | |
249 | |
250 SpeechInputBubble* SpeechInputBubble::Create( | |
251 TabContents* tab_contents, | |
252 SpeechInputBubble::Delegate* delegate, | |
253 const gfx::Rect& element_rect) { | |
254 return new SpeechInputBubbleImpl(tab_contents, delegate, element_rect); | |
255 } | |
OLD | NEW |