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 // 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 ¤t_run->classifications.back(); | 465 ¤t_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 Loading... | |
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 } | |
OLD | NEW |