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 public: | |
116 explicit IconLabelView(gfx::Font font); | |
117 | |
118 virtual void Layout(); | |
119 virtual gfx::Size GetPreferredSize(); | |
120 virtual void OnPaint(gfx::Canvas* canvas); | |
121 | |
122 void SetLabelColor(SkColor color); | |
123 void SetLabelText(const string16& text); | |
124 void SetSelected(bool flag); | |
Peter Kasting
2011/04/13 21:06:59
Nit: Name the arg |selected|.
| |
125 | |
126 private: | |
127 views::ImageView* image_; | |
128 views::Label* label_; | |
129 bool selected_; | |
130 | |
131 DISALLOW_COPY_AND_ASSIGN(IconLabelView); | |
132 }; | |
133 | |
134 AutocompleteResultView::IconLabelView::IconLabelView(gfx::Font font) | |
135 : selected_(false) { | |
136 image_ = new views::ImageView(); | |
137 AddChildView(image_); | |
Peter Kasting
2011/04/13 21:06:59
Nit: I think our typical practice is to AddChildVi
| |
138 image_->SetImage( | |
139 ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_OMNIBOX_SEARCH)); | |
140 label_ = new views::Label(); | |
141 AddChildView(label_); | |
142 label_->SetFont(font); | |
143 label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
144 } | |
145 | |
146 void AutocompleteResultView::IconLabelView::Layout() { | |
147 const int icon_width = image_->GetPreferredSize().width(); | |
148 image_->SetBounds(LocationBarView::kItemPadding * 2, | |
Peter Kasting
2011/04/13 21:06:59
The use of padding constants in these next two fun
| |
149 (height() - icon_width) / 2, icon_width, icon_width); | |
150 const int label_padding = icon_width + LocationBarView::kItemPadding * 3; | |
151 const int label_height = label_->GetPreferredSize().height(); | |
152 label_->SetBounds(label_padding, (height() - label_height) / 2, width() - | |
153 label_padding, label_height); | |
154 } | |
155 | |
156 gfx::Size AutocompleteResultView::IconLabelView::GetPreferredSize() { | |
157 gfx::Size size(image_->GetPreferredSize()); | |
158 size.Enlarge(label_->GetPreferredSize().width() + | |
159 LocationBarView::kExtensionItemPadding + | |
160 LocationBarView::kItemPadding * 3, 0); | |
161 return size; | |
162 } | |
163 | |
164 void AutocompleteResultView::IconLabelView::OnPaint(gfx::Canvas* canvas) { | |
165 if (selected_) { | |
166 canvas->Save(); | |
167 canvas->ClipRectInt(LocationBarView::kItemPadding, 0, width() - | |
168 LocationBarView::kItemPadding, height()); | |
169 canvas->AsCanvasSkia()->drawColor(GetColor(SELECTED, BACKGROUND)); | |
170 canvas->Restore(); | |
171 } else { | |
172 canvas->AsCanvasSkia()->drawColor(GetColor(NORMAL, BACKGROUND)); | |
173 } | |
174 | |
175 SkPaint paint; | |
176 paint.setColor(GetColor(NORMAL, DIMMED_TEXT)); | |
177 paint.setStrokeWidth(SkIntToScalar(1)); | |
178 paint.setAntiAlias(true); | |
179 | |
180 canvas->AsCanvasSkia()->drawLine( | |
181 SkIntToScalar(LocationBarView::kVerticalEdgeThickness), | |
182 SkIntToScalar(LocationBarView::kNormalHorizontalEdgeThickness), | |
183 SkIntToScalar(LocationBarView::kVerticalEdgeThickness), | |
184 SkIntToScalar(height() - | |
185 LocationBarView::kNormalHorizontalEdgeThickness * 2), paint); | |
186 } | |
187 | |
188 void AutocompleteResultView::IconLabelView::SetLabelColor(SkColor color) { | |
189 label_->SetColor(color); | |
190 } | |
191 | |
192 void AutocompleteResultView::IconLabelView::SetLabelText(const string16& text) { | |
193 label_->SetText(UTF16ToWide(text)); | |
194 } | |
195 | |
196 void AutocompleteResultView::IconLabelView::SetSelected(bool flag) { | |
197 selected_ = flag; | |
198 | |
199 if (selected_) | |
Peter Kasting
2011/04/13 21:06:59
Nit: Collapse this to one call using ?:
| |
200 image_->SetImage(ResourceBundle::GetSharedInstance(). | |
201 GetBitmapNamed(IDR_OMNIBOX_SEARCH_SELECTED)); | |
202 else | |
203 image_->SetImage(ResourceBundle::GetSharedInstance(). | |
204 GetBitmapNamed(IDR_OMNIBOX_SEARCH)); | |
205 | |
206 SchedulePaint(); | |
207 } | |
208 | |
109 AutocompleteResultView::AutocompleteResultView( | 209 AutocompleteResultView::AutocompleteResultView( |
110 AutocompleteResultViewModel* model, | 210 AutocompleteResultViewModel* model, |
111 int model_index, | 211 int model_index, |
112 const gfx::Font& font, | 212 const gfx::Font& font, |
113 const gfx::Font& bold_font) | 213 const gfx::Font& bold_font) |
114 : icon_vertical_padding_(kMinimumIconVerticalPadding), | 214 : icon_vertical_padding_(kMinimumIconVerticalPadding), |
115 text_vertical_padding_(kMinimumTextVerticalPadding), | 215 text_vertical_padding_(kMinimumTextVerticalPadding), |
116 model_(model), | 216 model_(model), |
117 model_index_(model_index), | 217 model_index_(model_index), |
118 normal_font_(font), | 218 normal_font_(font), |
119 bold_font_(bold_font), | 219 bold_font_(bold_font), |
120 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), | 220 ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), |
121 mirroring_context_(new MirroringContext()), | 221 mirroring_context_(new MirroringContext()), |
122 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { | 222 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED), |
223 search_view_(new IconLabelView(font)), | |
224 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))) { | |
123 CHECK_GE(model_index, 0); | 225 CHECK_GE(model_index, 0); |
124 if (icon_size_ == 0) { | 226 if (icon_size_ == 0) { |
125 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( | 227 icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( |
126 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> | 228 AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> |
127 width(); | 229 width(); |
128 } | 230 } |
231 | |
232 animation_->SetSlideDuration(500); | |
233 | |
234 AddChildView(search_view_.get()); | |
129 } | 235 } |
130 | 236 |
131 AutocompleteResultView::~AutocompleteResultView() { | 237 AutocompleteResultView::~AutocompleteResultView() { |
132 } | 238 } |
133 | 239 |
134 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { | 240 void AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { |
135 const ResultViewState state = GetState(); | 241 const ResultViewState state = GetState(); |
136 if (state != NORMAL) | 242 if (state != NORMAL && |
243 match_.keyword_state != AutocompleteMatch::DUAL_SHOWING_KEYWORD) | |
137 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); | 244 canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); |
138 | 245 |
139 // Paint the icon. | 246 // Paint the icon. |
140 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), | 247 canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), |
141 icon_bounds_.y()); | 248 icon_bounds_.y()); |
142 | 249 |
143 // Paint the text. | 250 // Paint the text. |
144 int x = GetMirroredXForRect(text_bounds_); | 251 int x = GetMirroredXForRect(text_bounds_); |
145 mirroring_context_->Initialize(x, text_bounds_.width()); | 252 mirroring_context_->Initialize(x, text_bounds_.width()); |
146 PaintMatch(canvas, match_, x); | 253 PaintMatch(canvas, match_, x); |
147 } | 254 } |
148 | 255 |
149 void AutocompleteResultView::Layout() { | 256 void AutocompleteResultView::Layout() { |
150 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding, | 257 icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding, |
151 (height() - icon_size_) / 2, icon_size_, icon_size_); | 258 (height() - icon_size_) / 2, icon_size_, icon_size_); |
152 int text_x = icon_bounds_.right() + LocationBarView::kItemPadding; | 259 const int text_x = icon_bounds_.right() + LocationBarView::kItemPadding; |
153 int font_height = std::max(normal_font_.GetHeight(), bold_font_.GetHeight()); | 260 const int font_height = std::max(normal_font_.GetHeight(), |
154 text_bounds_.SetRect(text_x, std::max(0, (height() - font_height) / 2), | 261 bold_font_.GetHeight()); |
155 std::max(bounds().width() - text_x - LocationBarView::kEdgeItemPadding, | 262 const int text_y = std::max(0, (height() - font_height) / 2); |
156 0), font_height); | 263 |
264 if (match_.has_keyword_hint()) { | |
265 gfx::Size search_size = search_view_->GetPreferredSize(); | |
266 const float expanded_x = static_cast<float>(text_x + | |
267 normal_font_.GetStringWidth(UTF8ToUTF16(ui::kEllipsis)) + | |
268 LocationBarView::kItemPadding); | |
269 const float collapsed_x = static_cast<float>(bounds().width() - | |
270 search_size.width()); | |
271 const int search_x = static_cast<int>(collapsed_x - ((collapsed_x - | |
272 expanded_x) * animation_->GetCurrentValue())); | |
273 | |
274 text_bounds_.SetRect(text_x, text_y, std::max(search_x - text_x, 0), | |
275 font_height); | |
276 search_view_->SetBounds(search_x, 0, std::max(bounds().width() - | |
277 search_x, 0), height()); | |
278 } else { | |
279 text_bounds_.SetRect(text_x, text_y, | |
280 std::max(bounds().width() - text_x, 0), font_height); | |
281 } | |
157 } | 282 } |
158 | 283 |
159 gfx::Size AutocompleteResultView::GetPreferredSize() { | 284 gfx::Size AutocompleteResultView::GetPreferredSize() { |
160 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_)); | 285 return gfx::Size(0, GetPreferredHeight(normal_font_, bold_font_)); |
161 } | 286 } |
162 | 287 |
163 int AutocompleteResultView::GetPreferredHeight( | 288 int AutocompleteResultView::GetPreferredHeight( |
164 const gfx::Font& font, | 289 const gfx::Font& font, |
165 const gfx::Font& bold_font) { | 290 const gfx::Font& bold_font) { |
166 int text_height = std::max(font.GetHeight(), bold_font.GetHeight()) + | 291 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; | 387 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; |
263 } | 388 } |
264 | 389 |
265 const SkBitmap* AutocompleteResultView::GetIcon() const { | 390 const SkBitmap* AutocompleteResultView::GetIcon() const { |
266 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_); | 391 const SkBitmap* bitmap = model_->GetSpecialIcon(model_index_); |
267 if (bitmap) | 392 if (bitmap) |
268 return bitmap; | 393 return bitmap; |
269 | 394 |
270 int icon = match_.starred ? | 395 int icon = match_.starred ? |
271 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); | 396 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); |
272 if (model_->IsSelectedIndex(model_index_)) { | 397 if (model_->IsSelectedIndex(model_index_) && |
398 match_.keyword_state != AutocompleteMatch::DUAL_SHOWING_KEYWORD) { | |
273 switch (icon) { | 399 switch (icon) { |
274 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; | 400 case IDR_OMNIBOX_HTTP: icon = IDR_OMNIBOX_HTTP_SELECTED; break; |
275 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; | 401 case IDR_OMNIBOX_HISTORY: icon = IDR_OMNIBOX_HISTORY_SELECTED; break; |
276 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; | 402 case IDR_OMNIBOX_SEARCH: icon = IDR_OMNIBOX_SEARCH_SELECTED; break; |
277 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; | 403 case IDR_OMNIBOX_STAR: icon = IDR_OMNIBOX_STAR_SELECTED; break; |
278 default: NOTREACHED(); break; | 404 default: NOTREACHED(); break; |
279 } | 405 } |
280 } | 406 } |
281 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); | 407 return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); |
282 } | 408 } |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 | 473 |
348 current_run->classifications.push_back(ClassificationData()); | 474 current_run->classifications.push_back(ClassificationData()); |
349 ClassificationData* current_data = | 475 ClassificationData* current_data = |
350 ¤t_run->classifications.back(); | 476 ¤t_run->classifications.back(); |
351 current_data->text = text.substr(text_start, text_end - text_start); | 477 current_data->text = text.substr(text_start, text_end - text_start); |
352 | 478 |
353 // Calculate style-related data. | 479 // Calculate style-related data. |
354 const int style = classifications[i].style; | 480 const int style = classifications[i].style; |
355 const bool use_bold_font = !!(style & ACMatchClassification::MATCH); | 481 const bool use_bold_font = !!(style & ACMatchClassification::MATCH); |
356 current_data->font = &(use_bold_font ? bold_font_ : normal_font_); | 482 current_data->font = &(use_bold_font ? bold_font_ : normal_font_); |
357 const ResultViewState state = GetState(); | 483 const ResultViewState state = |
484 (match_.keyword_state == AutocompleteMatch::DUAL_SHOWING_KEYWORD) ? | |
485 NORMAL : GetState(); | |
358 if (style & ACMatchClassification::URL) | 486 if (style & ACMatchClassification::URL) |
359 current_data->color = GetColor(state, URL); | 487 current_data->color = GetColor(state, URL); |
360 else if (style & ACMatchClassification::DIM) | 488 else if (style & ACMatchClassification::DIM) |
361 current_data->color = GetColor(state, DIMMED_TEXT); | 489 current_data->color = GetColor(state, DIMMED_TEXT); |
362 else | 490 else |
363 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); | 491 current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); |
364 current_data->pixel_width = | 492 current_data->pixel_width = |
365 current_data->font->GetStringWidth(current_data->text); | 493 current_data->font->GetStringWidth(current_data->text); |
366 current_run->pixel_width += current_data->pixel_width; | 494 current_run->pixel_width += current_data->pixel_width; |
367 } | 495 } |
(...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 | 631 // * It's normal, and will be able to draw successfully with the |
504 // ellipsis we'll append to it, or | 632 // ellipsis we'll append to it, or |
505 // * It is also bold, in which case we don't want to fall back | 633 // * It is also bold, in which case we don't want to fall back |
506 // to a normal ellipsis anyway (see comment above). | 634 // to a normal ellipsis anyway (see comment above). |
507 } | 635 } |
508 } | 636 } |
509 | 637 |
510 // We couldn't draw anything. | 638 // We couldn't draw anything. |
511 runs->clear(); | 639 runs->clear(); |
512 } | 640 } |
641 | |
642 void AutocompleteResultView::SetMatch(const AutocompleteMatch& match) { | |
643 const bool same_match = match.destination_url == match_.destination_url; | |
644 const bool is_keyword_mode = | |
645 match_.keyword_state == AutocompleteMatch::DUAL_SHOWING_KEYWORD; | |
646 const bool wants_keyword_mode = | |
647 match.keyword_state == AutocompleteMatch::DUAL_SHOWING_KEYWORD; | |
648 | |
649 match_ = match; | |
650 | |
651 if (wants_keyword_mode && !is_keyword_mode) | |
Peter Kasting
2011/04/13 21:06:59
Do you need to check |same_match| here?
Nit: All
| |
652 animation_->Show(); | |
653 else if (same_match && !wants_keyword_mode && is_keyword_mode) | |
654 animation_->Hide(); | |
655 else if ((!same_match) || (same_match && !animation_->is_animating())) { | |
Peter Kasting
2011/04/13 21:06:59
Nit: You can eliminate "same_match &&" and all the
| |
656 animation_->Stop(); | |
657 animation_->Reset(); | |
658 } | |
659 | |
660 search_view_->SetSelected(wants_keyword_mode); | |
661 search_view_->SetVisible(match_.has_keyword_hint()); | |
Peter Kasting
2011/04/13 21:06:59
Here you really want to check if the match is a DU
| |
662 | |
663 if (wants_keyword_mode) { | |
664 int message_id = match_.keyword_url->IsExtensionKeyword() ? | |
665 IDS_EXTENSION_KEYWORD_COMMAND : IDS_KEYWORD_SEARCH; | |
666 string16 text = l10n_util::GetStringFUTF16(message_id, | |
667 match_.keyword, l10n_util::GetStringUTF16(IDS_EMPTY_KEYWORD_VALUE)); | |
Peter Kasting
2011/04/13 21:06:59
You should be using match_.keyword_url->AdjustedSh
| |
668 text.append( | |
669 l10n_util::GetStringUTF16( | |
670 IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR)); | |
671 text.append( | |
672 l10n_util::GetStringFUTF16(IDS_AUTOCOMPLETE_KEYWORD_DESCRIPTION, | |
673 match_.keyword)); | |
674 search_view_->SetLabelText(text); | |
675 search_view_->SetLabelColor(GetColor(SELECTED, DIMMED_TEXT)); | |
676 } else { | |
677 search_view_->SetLabelText(UTF8ToUTF16(ui::kEllipsis)); | |
678 search_view_->SetLabelColor(GetColor(NORMAL, DIMMED_TEXT)); | |
679 } | |
680 Layout(); | |
681 } | |
682 | |
683 void AutocompleteResultView::AnimationProgressed( | |
684 const ui::Animation* animation) { | |
685 Layout(); | |
686 SchedulePaint(); | |
687 } | |
688 | |
OLD | NEW |