Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Side by Side Diff: chrome/browser/ui/views/autocomplete/autocomplete_result_view.cc

Issue 6731036: Enabled pressing TAB to cycle through the Omnibox results. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // For WinDDK ATL compatibility, these ATL headers must come first. 5 // For WinDDK ATL compatibility, these ATL headers must come first.
6 #include "build/build_config.h" 6 #include "build/build_config.h"
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <atlbase.h> // NOLINT 8 #include <atlbase.h> // NOLINT
9 #include <atlwin.h> // NOLINT 9 #include <atlwin.h> // NOLINT
10 #endif 10 #endif
11 11
12 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h" 12 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h"
13 13
14 #include <algorithm> // NOLINT 14 #include <algorithm> // NOLINT
15 15
16 #include "base/i18n/bidi_line_iterator.h" 16 #include "base/i18n/bidi_line_iterator.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/search_engines/template_url.h"
19 #include "chrome/browser/search_engines/template_url_model.h"
17 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view_model.h" 20 #include "chrome/browser/ui/views/autocomplete/autocomplete_result_view_model.h"
18 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 21 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
19 #include "grit/generated_resources.h" 22 #include "grit/generated_resources.h"
20 #include "grit/theme_resources.h" 23 #include "grit/theme_resources.h"
21 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/l10n/l10n_util.h"
22 #include "ui/base/resource/resource_bundle.h" 25 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/base/text/text_elider.h" 26 #include "ui/base/text/text_elider.h"
24 #include "ui/gfx/canvas_skia.h" 27 #include "ui/gfx/canvas_skia.h"
25 #include "ui/gfx/color_utils.h" 28 #include "ui/gfx/color_utils.h"
29 #include "views/controls/image_view.h"
30 #include "views/controls/label.h"
26 31
27 #if defined(OS_LINUX) 32 #if defined(OS_LINUX)
28 #include "chrome/browser/ui/gtk/gtk_util.h" 33 #include "chrome/browser/ui/gtk/gtk_util.h"
29 #include "ui/gfx/skia_utils_gtk.h" 34 #include "ui/gfx/skia_utils_gtk.h"
30 #endif 35 #endif
31 36
32 namespace { 37 namespace {
33 38
34 const char16 kEllipsis[] = { 0x2026 }; 39 const char16 kEllipsis[] = { 0x2026 };
35 40
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 return right_ - x; 104 return right_ - x;
100 } 105 }
101 106
102 private: 107 private:
103 int center_; 108 int center_;
104 int right_; 109 int right_;
105 110
106 DISALLOW_COPY_AND_ASSIGN(MirroringContext); 111 DISALLOW_COPY_AND_ASSIGN(MirroringContext);
107 }; 112 };
108 113
114 class AutocompleteResultView::IconLabelView : public views::View {
115 static const int kLineOffset = 1;
Peter Kasting 2011/04/07 20:19:21 Nit: Declare in private section, or in the functio
116 static const int kLinePadding = 2;
117 static const int kEdgeOffset = 2;
118 static const int kIconPadding = 3;
119 static const int kLabelEdgePadding = 5;
120
121 public:
122 IconLabelView::IconLabelView(gfx::Font font) {
Peter Kasting 2011/04/07 20:19:21 Nit: Write definitions out-of-line, even for class
123 image_ = new views::ImageView();
124 AddChildView(image_);
125 image_->SetImage(
126 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_OMNIBOX_SEARCH));
127 label_ = new views::Label();
128 AddChildView(label_);
129 label_->SetFont(font);
130 label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
131 }
132
133 virtual void Layout() {
134 const int icon_width = image_->GetPreferredSize().width();
135 image_->SetBounds(kEdgeOffset + kIconPadding, (height() - icon_width) / 2,
136 icon_width, icon_width);
137 const int label_padding = icon_width + kEdgeOffset + kIconPadding +
138 LocationBarView::kItemPadding;
139 const int label_height = label_->GetPreferredSize().height();
140 label_->SetBounds(label_padding, (height() - label_height) / 2, width() -
141 label_padding, label_height);
142 }
143
144 virtual gfx::Size GetPreferredSize() {
145 gfx::Size size(image_->GetPreferredSize());
146 size.Enlarge(label_->GetPreferredSize().width() + kLabelEdgePadding +
147 kEdgeOffset + kIconPadding + LocationBarView::kItemPadding, 0);
148 return size;
149 }
150
151 virtual void OnPaint(gfx::Canvas* canvas) {
152 if (selected) {
153 canvas->Save();
154 canvas->ClipRectInt(kEdgeOffset, 0, width() - kEdgeOffset, height());
155 canvas->AsCanvasSkia()->drawColor(GetColor(SELECTED, BACKGROUND));
156 canvas->Restore();
157 } else {
158 canvas->AsCanvasSkia()->drawColor(GetColor(NORMAL, BACKGROUND));
159 }
160
161 SkPaint paint;
162 paint.setColor(GetColor(NORMAL, DIMMED_TEXT));
163 paint.setStrokeWidth(SkIntToScalar(1));
164 paint.setAntiAlias(true);
165
166 canvas->AsCanvasSkia()->drawLine(SkIntToScalar(kLineOffset),
167 SkIntToScalar(kLinePadding), SkIntToScalar(kLineOffset),
168 SkIntToScalar(height() - kLinePadding * 2), paint);
169 }
170
171 void SetLabelColor(SkColor color) {
172 label_->SetColor(color);
173 }
174
175 void SetLabelText(const string16& text) {
176 label_->SetText(UTF16ToWide(text));
177 }
178
179 void SetSelected(bool flag) {
180 selected = flag;
181
182 if (selected)
183 image_->SetImage(
184 ResourceBundle::GetSharedInstance().
185 GetBitmapNamed(IDR_OMNIBOX_SEARCH_SELECTED));
186 else
187 image_->SetImage(
188 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_OMNIBOX_SEARCH));
189
190 SchedulePaint();
191 }
192
193 private:
194 views::ImageView* image_;
195 views::Label* label_;
196 bool selected;
197 };
198
109 AutocompleteResultView::AutocompleteResultView( 199 AutocompleteResultView::AutocompleteResultView(
110 AutocompleteResultViewModel* model, 200 AutocompleteResultViewModel* model,
111 int model_index, 201 int model_index,
112 const gfx::Font& font, 202 const gfx::Font& font,
113 const gfx::Font& bold_font) 203 const gfx::Font& bold_font)
114 : icon_vertical_padding_(kMinimumIconVerticalPadding), 204 : icon_vertical_padding_(kMinimumIconVerticalPadding),
115 text_vertical_padding_(kMinimumTextVerticalPadding), 205 text_vertical_padding_(kMinimumTextVerticalPadding),
116 model_(model), 206 model_(model),
117 model_index_(model_index), 207 model_index_(model_index),
118 normal_font_(font), 208 normal_font_(font),
119 bold_font_(bold_font), 209 bold_font_(bold_font),
120 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), 210 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))),
121 mirroring_context_(new MirroringContext()), 211 mirroring_context_(new MirroringContext()),
122 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { 212 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED),
213 search_view_(new IconLabelView(font)),
214 search_expanded_(false) {
123 CHECK_GE(model_index, 0); 215 CHECK_GE(model_index, 0);
124 if (icon_size_ == 0) { 216 if (icon_size_ == 0) {
125 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( 217 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
126 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> 218 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))->
127 width(); 219 width();
128 } 220 }
221
222 animation_.reset(new ui::SlideAnimation(this));
Peter Kasting 2011/04/07 20:19:21 Nit: You can do this in the initializer list (use
223 animation_->SetSlideDuration(500);
224
225 AddChildView(search_view_.get());
129 } 226 }
130 227
131 AutocompleteResultView::~AutocompleteResultView() { 228 AutocompleteResultView::~AutocompleteResultView() {
132 } 229 }
133 230
134 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { 231 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) {
135 const ResultViewState state = GetState(); 232 const ResultViewState state = GetState();
136 if (state != NORMAL) 233
234 if (state != NORMAL && !search_expanded_)
137 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); 235 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND));
138 236
139 // Paint the icon. 237 // Paint the icon.
140 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), 238 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_),
141 icon_bounds_.y()); 239 icon_bounds_.y());
142 240
143 // Paint the text. 241 // Paint the text.
144 int x = GetMirroredXForRect(text_bounds_); 242 int x = GetMirroredXForRect(text_bounds_);
145 mirroring_context_->Initialize(x, text_bounds_.width()); 243 mirroring_context_->Initialize(x, text_bounds_.width());
146 PaintMatch(canvas, match_, x); 244 PaintMatch(canvas, match_, x);
147 } 245 }
148 246
149 void AutocompleteResultView::Layout() { 247 void AutocompleteResultView::Layout() {
150 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding, 248 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding,
151 (height() - icon_size_) / 2, icon_size_, icon_size_); 249 (height() - icon_size_) / 2, icon_size_, icon_size_);
152 int text_x = icon_bounds_.right() + LocationBarView::kItemPadding; 250 const int text_x = icon_bounds_.right() + LocationBarView::kItemPadding;
153 int font_height = std::max(normal_font_.GetHeight(), bold_font_.GetHeight()); 251 const int font_height = std::max(normal_font_.GetHeight(),
154 text_bounds_.SetRect(text_x, std::max(0, (height() - font_height) / 2), 252 bold_font_.GetHeight());
155 std::max(bounds().width() - text_x - LocationBarView::kEdgeItemPadding, 253 const int text_y = std::max(0, (height() - font_height) / 2);
156 0), font_height); 254
255 if (keyword_.get() && keyword_->is_keyword_hint) {
256 gfx::Size search_size = search_view_->GetPreferredSize();
257 const double expanded_x = text_x +
Peter Kasting 2011/04/07 20:19:21 Nit: float is plenty of precision, no need for dou
258 normal_font_.GetStringWidth(UTF8ToUTF16(ui::kEllipsis)) +
259 LocationBarView::kItemPadding;
260 const double collapsed_x = bounds().width() - search_size.width();
261 const int search_x = static_cast<int>(collapsed_x - ((collapsed_x -
262 expanded_x) * animation_->GetCurrentValue()));
263
264 text_bounds_.SetRect(text_x, text_y, std::max(search_x - text_x, 0),
265 font_height);
266 search_view_->SetBounds(search_x, 0, std::max(bounds().width() -
267 search_x, 0), height());
268 } else {
269 text_bounds_.SetRect(text_x, text_y,
270 std::max(bounds().width() - text_x, 0), font_height);
271 }
157 } 272 }
158 273
159 gfx::Size AutocompleteResultView::GetPreferredSize() { 274 gfx::Size AutocompleteResultView::GetPreferredSize() {
160 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_)); 275 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_));
161 } 276 }
162 277
163 int AutocompleteResultView::GetPreferredHeight( 278 int AutocompleteResultView::GetPreferredHeight(
164 const gfx::Font& font, 279 const gfx::Font& font,
165 const gfx::Font& bold_font) { 280 const gfx::Font& bold_font) {
166 int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) + 281 int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) +
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; 377 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL;
263 } 378 }
264 379
265 const SkBitmap* AutocompleteResultView::GetIcon() const { 380 const SkBitmap* AutocompleteResultView::GetIcon() const {
266 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_); 381 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_);
267 if (bitmap) 382 if (bitmap)
268 return bitmap; 383 return bitmap;
269 384
270 int icon = match_.starred ? 385 int icon = match_.starred ?
271 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); 386 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type);
272 if (model_->IsSelectedIndex(model_index_)) { 387 if (model_->IsSelectedIndex(model_index_) && !search_expanded_) {
273 switch (icon) { 388 switch (icon) {
274 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; 389 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break;
275 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; 390 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break;
276 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; 391 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break;
277 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; 392 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break;
278 default: NOTREACHED(); break; 393 default: NOTREACHED(); break;
279 } 394 }
280 } 395 }
281 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); 396 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon);
282 } 397 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 462
348 current_run->classifications.push_back(ClassificationData()); 463 current_run->classifications.push_back(ClassificationData());
349 ClassificationData* current_data = 464 ClassificationData* current_data =
350 &current_run->classifications.back(); 465 &current_run->classifications.back();
351 current_data->text = text.substr(text_start, text_end - text_start); 466 current_data->text = text.substr(text_start, text_end - text_start);
352 467
353 // Calculate style-related data. 468 // Calculate style-related data.
354 const int style = classifications[i].style; 469 const int style = classifications[i].style;
355 const bool use_bold_font = !!(style & ACMatchClassification::MATCH); 470 const bool use_bold_font = !!(style & ACMatchClassification::MATCH);
356 current_data->font = &(use_bold_font ? bold_font_ : normal_font_); 471 current_data->font = &(use_bold_font ? bold_font_ : normal_font_);
357 const ResultViewState state = GetState(); 472 const ResultViewState state = search_expanded_ ? NORMAL : GetState();
358 if (style & ACMatchClassification::URL) 473 if (style & ACMatchClassification::URL)
359 current_data->color = GetColor(state, URL); 474 current_data->color = GetColor(state, URL);
360 else if (style & ACMatchClassification::DIM) 475 else if (style & ACMatchClassification::DIM)
361 current_data->color = GetColor(state, DIMMED_TEXT); 476 current_data->color = GetColor(state, DIMMED_TEXT);
362 else 477 else
363 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); 478 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT);
364 current_data->pixel_width = 479 current_data->pixel_width =
365 current_data->font->GetStringWidth(current_data->text); 480 current_data->font->GetStringWidth(current_data->text);
366 current_run->pixel_width += current_data->pixel_width; 481 current_run->pixel_width += current_data->pixel_width;
367 } 482 }
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
503 // * It's normal, and will be able to draw successfully with the 618 // * It's normal, and will be able to draw successfully with the
504 // ellipsis we'll append to it, or 619 // ellipsis we'll append to it, or
505 // * It is also bold, in which case we don't want to fall back 620 // * It is also bold, in which case we don't want to fall back
506 // to a normal ellipsis anyway (see comment above). 621 // to a normal ellipsis anyway (see comment above).
507 } 622 }
508 } 623 }
509 624
510 // We couldn't draw anything. 625 // We couldn't draw anything.
511 runs->clear(); 626 runs->clear();
512 } 627 }
628
629 void AutocompleteResultView::SetMatch(const AutocompleteMatch& match) {
630 const bool same_match = match.destination_url == match_.destination_url;
631 match_ = match;
632 keyword_ = match.keyword;
633
634 const bool keyword_mode = keyword_.get() && keyword_->is_keyword_hint &&
635 keyword_->is_keyword_mode;
636
637 if (keyword_mode && !search_expanded_)
638 animation_->Show();
639 else if (same_match && !keyword_mode && search_expanded_)
640 animation_->Hide();
641 else if (!same_match || (same_match && !animation_->is_animating())) {
642 animation_->Stop();
643 animation_->Reset();
644 }
645
646 search_expanded_ = keyword_mode;
647 search_view_->SetSelected(search_expanded_);
648 search_view_->SetVisible(keyword_.get() && keyword_->is_keyword_hint);
649
650 if (search_expanded_) {
651 int message_id = keyword_->template_url->IsExtensionKeyword() ?
652 IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH;
653 string16 text = l10n_util::GetStringFUTF16(message_id,
654 keyword_->text, l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE));
655 text.append(
656 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR));
657 text.append(
658 l10n_util::GetStringFUTF16(IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION,
659 keyword_->text));
660 search_view_->SetLabelText(text);
661 search_view_->SetLabelColor(GetColor(SELECTED, DIMMED_TEXT));
662 } else {
663 search_view_->SetLabelText(UTF8ToUTF16(ui::kEllipsis));
664 search_view_->SetLabelColor(GetColor(NORMAL, DIMMED_TEXT));
665 }
666 Layout();
667 }
668
669 void AutocompleteResultView::AnimationProgressed(const ui::Animation* animation) {
670 Layout();
671 SchedulePaint();
672 }
673
674 void AutocompleteResultView::AnimationCanceled(const ui::Animation* animation) {
675 Layout();
676 SchedulePaint();
677 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698