summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-11 07:29:34 +0000
committersatish@chromium.org <satish@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-11 07:29:34 +0000
commitcc91bcb9b9d9fb0c5eb38a8da54b76f3fcad4a51 (patch)
tree0f7d2b239d4ca3712bdb6ea248c45edf8d210884
parent3c11b5b02cf32fb578e0854cd6403a9fb31ba119 (diff)
downloadchromium_src-cc91bcb9b9d9fb0c5eb38a8da54b76f3fcad4a51.zip
chromium_src-cc91bcb9b9d9fb0c5eb38a8da54b76f3fcad4a51.tar.gz
chromium_src-cc91bcb9b9d9fb0c5eb38a8da54b76f3fcad4a51.tar.bz2
Extend speech input bubble on windows to display error messages with try-again and cancel buttons.
For recognition status, the bubble shows: - "Speak now" at the top - Image/icon with status below that - "Cancel" button at the bottom In message mode, the bubble shows: - The given message (could span multiple lines) at the top - A row of 2 buttons at the bottom, "Try again" and "Cancel" BUG=53598 TEST=manual, unplug mic and start recognition to check error message, and similarly give no speech to check. Review URL: http://codereview.chromium.org/3300029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59184 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/speech/speech_input_bubble_views.cc183
1 files changed, 121 insertions, 62 deletions
diff --git a/chrome/browser/speech/speech_input_bubble_views.cc b/chrome/browser/speech/speech_input_bubble_views.cc
index 640f585..0be6378 100644
--- a/chrome/browser/speech/speech_input_bubble_views.cc
+++ b/chrome/browser/speech/speech_input_bubble_views.cc
@@ -27,7 +27,7 @@
namespace {
-const int kBubbleHorizMargin = 40;
+const int kBubbleHorizMargin = 6;
const int kBubbleVertMargin = 0;
// This is the content view which is placed inside a SpeechInputBubble.
@@ -37,7 +37,8 @@ class ContentView
public:
explicit ContentView(SpeechInputBubbleDelegate* delegate);
- void SetRecognizingMode();
+ void UpdateLayout(SpeechInputBubbleBase::DisplayMode mode,
+ const string16& message_text);
// views::ButtonListener methods.
virtual void ButtonPressed(views::Button* source, const views::Event& event);
@@ -50,6 +51,8 @@ class ContentView
SpeechInputBubbleDelegate* delegate_;
views::ImageView* icon_;
views::Label* heading_;
+ views::Label* message_;
+ views::NativeButton* try_again_;
views::NativeButton* cancel_;
DISALLOW_COPY_AND_ASSIGN(ContentView);
@@ -58,14 +61,20 @@ class ContentView
ContentView::ContentView(SpeechInputBubbleDelegate* delegate)
: delegate_(delegate) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont);
+ const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont);
heading_ = new views::Label(
l10n_util::GetString(IDS_SPEECH_INPUT_BUBBLE_HEADING));
- heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL));
+ heading_->SetFont(font);
heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
AddChildView(heading_);
+ message_ = new views::Label();
+ message_->SetFont(font);
+ message_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ message_->SetMultiLine(true);
+ AddChildView(message_);
+
icon_ = new views::ImageView();
icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_SPEECH_INPUT_RECORDING));
@@ -74,54 +83,106 @@ ContentView::ContentView(SpeechInputBubbleDelegate* delegate)
cancel_ = new views::NativeButton(this, l10n_util::GetString(IDS_CANCEL));
AddChildView(cancel_);
+
+ try_again_ = new views::NativeButton(
+ this,
+ l10n_util::GetString(IDS_SPEECH_INPUT_TRY_AGAIN));
+ AddChildView(try_again_);
}
-void ContentView::SetRecognizingMode() {
- icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
- IDR_SPEECH_INPUT_PROCESSING));
+void ContentView::UpdateLayout(SpeechInputBubbleBase::DisplayMode mode,
+ const string16& message_text) {
+ bool is_message = (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE);
+ heading_->SetVisible(!is_message);
+ icon_->SetVisible(!is_message);
+ message_->SetVisible(is_message);
+ try_again_->SetVisible(is_message);
+
+ if (mode == SpeechInputBubbleBase::DISPLAY_MODE_MESSAGE) {
+ message_->SetText(message_text);
+ } else {
+ icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ (mode == SpeechInputBubbleBase::DISPLAY_MODE_RECORDING) ?
+ IDR_SPEECH_INPUT_RECORDING : IDR_SPEECH_INPUT_PROCESSING));
+ }
}
void ContentView::ButtonPressed(views::Button* source,
const views::Event& event) {
if (source == cancel_) {
delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
+ } else if (source == try_again_) {
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_TRY_AGAIN);
} else {
- NOTREACHED() << "Unknown view";
+ NOTREACHED() << "Unknown button";
}
}
gfx::Size ContentView::GetPreferredSize() {
int width = heading_->GetPreferredSize().width();
- int control_width = cancel_->GetPreferredSize().width();
+ int control_width = cancel_->GetPreferredSize().width() +
+ try_again_->GetPreferredSize().width() +
+ kRelatedButtonHSpacing;
if (control_width > width)
width = control_width;
control_width = icon_->GetPreferredSize().width();
if (control_width > width)
width = control_width;
+
+ int height = cancel_->GetPreferredSize().height();
+ if (message_->IsVisible()) {
+ height += message_->GetHeightForWidth(width) +
+ kLabelToControlVerticalSpacing;
+ } else {
+ height += heading_->GetPreferredSize().height() +
+ icon_->GetImage().height();
+ }
width += kBubbleHorizMargin * 2;
+ height += kBubbleVertMargin * 2;
- int height = kBubbleVertMargin * 2 +
- heading_->GetPreferredSize().height() +
- cancel_->GetPreferredSize().height() +
- icon_->GetImage().height();
return gfx::Size(width, height);
}
void ContentView::Layout() {
int x = kBubbleHorizMargin;
int y = kBubbleVertMargin;
- int control_width = width() - kBubbleHorizMargin * 2;
+ int available_width = width() - kBubbleHorizMargin * 2;
+ int available_height = height() - kBubbleVertMargin * 2;
+
+ if (message_->IsVisible()) {
+ DCHECK(try_again_->IsVisible());
+
+ int height = try_again_->GetPreferredSize().height();
+ int try_again_width = try_again_->GetPreferredSize().width();
+ int cancel_width = cancel_->GetPreferredSize().width();
+ y += available_height - height;
+ x += (available_width - cancel_width - try_again_width -
+ kRelatedButtonHSpacing) / 2;
+ try_again_->SetBounds(x, y, try_again_width, height);
+ cancel_->SetBounds(x + try_again_width + kRelatedButtonHSpacing, y,
+ cancel_width, height);
+
+ height = message_->GetHeightForWidth(available_width);
+ if (height > y - kBubbleVertMargin)
+ height = y - kBubbleVertMargin;
+ message_->SetBounds(kBubbleHorizMargin, kBubbleVertMargin,
+ available_width, height);
+ } else {
+ DCHECK(heading_->IsVisible());
+ DCHECK(icon_->IsVisible());
- int height = heading_->GetPreferredSize().height();
- heading_->SetBounds(x, y, control_width, height);
- y += height;
+ int height = heading_->GetPreferredSize().height();
+ heading_->SetBounds(x, y, available_width, height);
+ y += height;
- height = icon_->GetImage().height();
- icon_->SetBounds(x, y, control_width, height);
- y += height;
+ height = icon_->GetImage().height();
+ icon_->SetBounds(x, y, available_width, height);
+ y += height;
- height = cancel_->GetPreferredSize().height();
- cancel_->SetBounds(x, y, control_width, height);
+ height = cancel_->GetPreferredSize().height();
+ int width = cancel_->GetPreferredSize().width();
+ cancel_->SetBounds(x + (available_width - width) / 2, y, width, height);
+ }
}
// Implementation of SpeechInputBubble.
@@ -135,11 +196,11 @@ class SpeechInputBubbleImpl
const gfx::Rect& element_rect);
virtual ~SpeechInputBubbleImpl();
- virtual void SetRecognizingMode();
-
// SpeechInputBubble methods.
virtual void Show();
virtual void Hide();
+
+ // SpeechInputBubbleBase methods.
virtual void UpdateLayout();
// Returns the screen rectangle to use as the info bubble's target.
@@ -163,6 +224,7 @@ class SpeechInputBubbleImpl
TabContents* tab_contents_;
ContentView* bubble_content_;
NotificationRegistrar registrar_;
+ gfx::Rect element_rect_;
// Set to true if the object is being destroyed normally instead of the
// user clicking outside the window causing it to close automatically.
@@ -178,38 +240,13 @@ SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents,
info_bubble_(NULL),
tab_contents_(tab_contents),
bubble_content_(NULL),
+ element_rect_(element_rect),
did_invoke_close_(false) {
- bubble_content_ = new ContentView(delegate_);
-
- views::Widget* parent = views::Widget::GetWidgetFromNativeWindow(
- tab_contents_->view()->GetTopLevelNativeWindow());
- info_bubble_ = InfoBubble::Show(parent,
- GetInfoBubbleTarget(element_rect),
- BubbleBorder::TOP_LEFT, bubble_content_,
- this);
-
- // We don't want fade outs when closing because it makes speech recognition
- // appear slower than it is. Also setting it to false allows |Close| to
- // destroy the bubble immediately instead of waiting for the fade animation
- // to end so the caller can manage this object's life cycle like a normal
- // stack based or member variable object.
- info_bubble_->set_fade_away_on_close(false);
-
- registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab_contents_));
}
SpeechInputBubbleImpl::~SpeechInputBubbleImpl() {
- if (info_bubble_) {
- did_invoke_close_ = true;
- info_bubble_->Close();
- }
-}
-
-void SpeechInputBubbleImpl::SetRecognizingMode() {
- DCHECK(info_bubble_);
- DCHECK(bubble_content_);
- bubble_content_->SetRecognizingMode();
+ did_invoke_close_ = true;
+ Hide();
}
gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget(
@@ -222,17 +259,17 @@ gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget(
}
void SpeechInputBubbleImpl::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
+ const NotificationSource& source,
+ const NotificationDetails& details) {
if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
- delegate_->InfoBubbleButtonClicked(BUTTON_CANCEL);
+ delegate_->InfoBubbleButtonClicked(SpeechInputBubble::BUTTON_CANCEL);
} else {
NOTREACHED() << "Unknown notification";
}
}
void SpeechInputBubbleImpl::InfoBubbleClosing(InfoBubble* info_bubble,
- bool closed_by_escape) {
+ bool closed_by_escape) {
registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
Source<TabContents>(tab_contents_));
info_bubble_ = NULL;
@@ -250,18 +287,40 @@ bool SpeechInputBubbleImpl::FadeInOnShow() {
}
void SpeechInputBubbleImpl::Show() {
- // TODO(satish): Implement.
- NOTREACHED();
+ if (info_bubble_)
+ return; // nothing to do, already visible.
+
+ bubble_content_ = new ContentView(delegate_);
+ UpdateLayout();
+
+ views::Widget* parent = views::Widget::GetWidgetFromNativeWindow(
+ tab_contents_->view()->GetTopLevelNativeWindow());
+ info_bubble_ = InfoBubble::Show(parent,
+ GetInfoBubbleTarget(element_rect_),
+ BubbleBorder::TOP_LEFT, bubble_content_,
+ this);
+
+ // We don't want fade outs when closing because it makes speech recognition
+ // appear slower than it is. Also setting it to false allows |Close| to
+ // destroy the bubble immediately instead of waiting for the fade animation
+ // to end so the caller can manage this object's life cycle like a normal
+ // stack based or member variable object.
+ info_bubble_->set_fade_away_on_close(false);
+
+ registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(tab_contents_));
}
void SpeechInputBubbleImpl::Hide() {
- // TODO(satish): Implement.
- NOTREACHED();
+ if (info_bubble_)
+ info_bubble_->Close();
}
void SpeechInputBubbleImpl::UpdateLayout() {
- // TODO: Implement.
- NOTREACHED();
+ if (bubble_content_)
+ bubble_content_->UpdateLayout(display_mode(), message_text());
+ if (info_bubble_) // Will be null on first call.
+ info_bubble_->SizeToContents();
}
} // namespace