OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h" | 5 #include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <string> | 10 #include <string> |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 WindowOpenDisposition disposition) { | 481 WindowOpenDisposition disposition) { |
482 // OpenMatch() may close the popup, which will clear the result set and, by | 482 // OpenMatch() may close the popup, which will clear the result set and, by |
483 // extension, |match| and its contents. So copy the relevant match out to | 483 // extension, |match| and its contents. So copy the relevant match out to |
484 // make sure it stays alive until the call completes. | 484 // make sure it stays alive until the call completes. |
485 AutocompleteMatch match = model_->result().match_at(line); | 485 AutocompleteMatch match = model_->result().match_at(line); |
486 omnibox_view_->OpenMatch(match, disposition, GURL(), line, | 486 omnibox_view_->OpenMatch(match, disposition, GURL(), line, |
487 match.keyword); | 487 match.keyword); |
488 } | 488 } |
489 | 489 |
490 const gfx::Image* OmniboxPopupViewGtk::IconForMatch( | 490 const gfx::Image* OmniboxPopupViewGtk::IconForMatch( |
491 const AutocompleteMatch& match, bool selected) { | 491 const AutocompleteMatch& match, |
| 492 bool selected, |
| 493 bool is_selected_keyword) { |
492 const SkBitmap* bitmap = model_->GetIconIfExtensionMatch(match); | 494 const SkBitmap* bitmap = model_->GetIconIfExtensionMatch(match); |
493 if (bitmap) { | 495 if (bitmap) { |
494 if (!ContainsKey(images_, bitmap)) { | 496 if (!ContainsKey(images_, bitmap)) { |
495 // gfx::Image wants ownership of bitmaps given to it, and we might as | 497 // gfx::Image wants ownership of bitmaps given to it, and we might as |
496 // well make the bitmap copy a format that will be used. | 498 // well make the bitmap copy a format that will be used. |
497 images_[bitmap] = new gfx::Image(gfx::GdkPixbufFromSkBitmap(bitmap)); | 499 images_[bitmap] = new gfx::Image(gfx::GdkPixbufFromSkBitmap(bitmap)); |
498 } | 500 } |
499 return images_[bitmap]; | 501 return images_[bitmap]; |
500 } | 502 } |
501 | 503 |
502 int icon = match.starred ? | 504 int icon; |
503 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match.type); | 505 if (is_selected_keyword) |
| 506 icon = IDR_OMNIBOX_TTS; |
| 507 else if (match.starred) |
| 508 icon = IDR_OMNIBOX_STAR; |
| 509 else |
| 510 icon = AutocompleteMatch::TypeToIcon(match.type); |
| 511 |
504 if (selected) { | 512 if (selected) { |
505 switch (icon) { | 513 switch (icon) { |
506 case IDR_OMNIBOX_EXTENSION_APP: | 514 case IDR_OMNIBOX_EXTENSION_APP: |
507 icon = IDR_OMNIBOX_EXTENSION_APP_DARK; | 515 icon = IDR_OMNIBOX_EXTENSION_APP_DARK; |
508 break; | 516 break; |
509 case IDR_OMNIBOX_HTTP: | 517 case IDR_OMNIBOX_HTTP: |
510 icon = IDR_OMNIBOX_HTTP_DARK; | 518 icon = IDR_OMNIBOX_HTTP_DARK; |
511 break; | 519 break; |
512 case IDR_OMNIBOX_HISTORY: | 520 case IDR_OMNIBOX_HISTORY: |
513 icon = IDR_OMNIBOX_HISTORY_DARK; | 521 icon = IDR_OMNIBOX_HISTORY_DARK; |
514 break; | 522 break; |
515 case IDR_OMNIBOX_SEARCH: | 523 case IDR_OMNIBOX_SEARCH: |
516 icon = IDR_OMNIBOX_SEARCH_DARK; | 524 icon = IDR_OMNIBOX_SEARCH_DARK; |
517 break; | 525 break; |
518 case IDR_OMNIBOX_STAR: | 526 case IDR_OMNIBOX_STAR: |
519 icon = IDR_OMNIBOX_STAR_DARK; | 527 icon = IDR_OMNIBOX_STAR_DARK; |
520 break; | 528 break; |
| 529 case IDR_OMNIBOX_TTS: |
| 530 icon = IDR_OMNIBOX_TTS_DARK; |
| 531 break; |
521 default: | 532 default: |
522 NOTREACHED(); | 533 NOTREACHED(); |
523 break; | 534 break; |
524 } | 535 } |
525 } | 536 } |
526 | 537 |
527 return theme_service_->GetImageNamed(icon); | 538 return theme_service_->GetImageNamed(icon); |
528 } | 539 } |
529 | 540 |
| 541 void OmniboxPopupViewGtk::GetVisibleMatchForInput( |
| 542 size_t index, |
| 543 const AutocompleteMatch** match, |
| 544 bool* is_selected_keyword) { |
| 545 const AutocompleteResult& result = model_->result(); |
| 546 |
| 547 if (result.match_at(index).associated_keyword.get() && |
| 548 model_->selected_line() == index && |
| 549 model_->selected_line_state() == AutocompletePopupModel::KEYWORD) { |
| 550 *match = result.match_at(index).associated_keyword.get(); |
| 551 *is_selected_keyword = true; |
| 552 return; |
| 553 } |
| 554 |
| 555 *match = &result.match_at(index); |
| 556 *is_selected_keyword = false; |
| 557 } |
| 558 |
530 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, | 559 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, |
531 GdkEventMotion* event) { | 560 GdkEventMotion* event) { |
532 // TODO(deanm): Windows has a bunch of complicated logic here. | 561 // TODO(deanm): Windows has a bunch of complicated logic here. |
533 size_t line = LineFromY(static_cast<int>(event->y)); | 562 size_t line = LineFromY(static_cast<int>(event->y)); |
534 // There is both a hovered and selected line, hovered just means your mouse | 563 // There is both a hovered and selected line, hovered just means your mouse |
535 // is over it, but selected is what's showing in the location edit. | 564 // is over it, but selected is what's showing in the location edit. |
536 model_->SetHoveredLine(line); | 565 model_->SetHoveredLine(line); |
537 // Select the line if the user has the left mouse button down. | 566 // Select the line if the user has the left mouse button down. |
538 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) | 567 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) |
539 model_->SetSelectedLine(line, false, false); | 568 model_->SetSelectedLine(line, false, false); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 cairo_stroke(cr); | 632 cairo_stroke(cr); |
604 | 633 |
605 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); | 634 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); |
606 | 635 |
607 for (size_t i = 0; i < result.size(); ++i) { | 636 for (size_t i = 0; i < result.size(); ++i) { |
608 gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); | 637 gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); |
609 // Only repaint and layout damaged lines. | 638 // Only repaint and layout damaged lines. |
610 if (!line_rect.Intersects(damage_rect)) | 639 if (!line_rect.Intersects(damage_rect)) |
611 continue; | 640 continue; |
612 | 641 |
613 const AutocompleteMatch& match = result.match_at(i); | 642 const AutocompleteMatch* match = NULL; |
| 643 bool is_selected_keyword = false; |
| 644 GetVisibleMatchForInput(i, &match, &is_selected_keyword); |
614 bool is_selected = (model_->selected_line() == i); | 645 bool is_selected = (model_->selected_line() == i); |
615 bool is_hovered = (model_->hovered_line() == i); | 646 bool is_hovered = (model_->hovered_line() == i); |
616 if (is_selected || is_hovered) { | 647 if (is_selected || is_hovered) { |
617 gdk_cairo_set_source_color(cr, is_selected ? &selected_background_color_ : | 648 gdk_cairo_set_source_color(cr, is_selected ? &selected_background_color_ : |
618 &hovered_background_color_); | 649 &hovered_background_color_); |
619 // This entry is selected or hovered, fill a rect with the color. | 650 // This entry is selected or hovered, fill a rect with the color. |
620 cairo_rectangle(cr, line_rect.x(), line_rect.y(), | 651 cairo_rectangle(cr, line_rect.x(), line_rect.y(), |
621 line_rect.width(), line_rect.height()); | 652 line_rect.width(), line_rect.height()); |
622 cairo_fill(cr); | 653 cairo_fill(cr); |
623 } | 654 } |
624 | 655 |
625 int icon_start_x = ltr ? kIconLeftPadding : | 656 int icon_start_x = ltr ? kIconLeftPadding : |
626 (line_rect.width() - kIconLeftPadding - kIconWidth); | 657 (line_rect.width() - kIconLeftPadding - kIconWidth); |
627 // Draw the icon for this result. | 658 // Draw the icon for this result. |
628 DrawFullImage(cr, widget, | 659 DrawFullImage(cr, widget, |
629 IconForMatch(match, is_selected), | 660 IconForMatch(*match, is_selected, is_selected_keyword), |
630 icon_start_x, line_rect.y() + kIconTopPadding); | 661 icon_start_x, line_rect.y() + kIconTopPadding); |
631 | 662 |
632 // Draw the results text vertically centered in the results space. | 663 // Draw the results text vertically centered in the results space. |
633 // First draw the contents / url, but don't let it take up the whole width | 664 // First draw the contents / url, but don't let it take up the whole width |
634 // if there is also a description to be shown. | 665 // if there is also a description to be shown. |
635 bool has_description = !match.description.empty(); | 666 bool has_description = !match->description.empty(); |
636 int text_width = window_rect.width() - (kIconAreaWidth + kRightPadding); | 667 int text_width = window_rect.width() - (kIconAreaWidth + kRightPadding); |
637 int allocated_content_width = has_description ? | 668 int allocated_content_width = has_description ? |
638 static_cast<int>(text_width * kContentWidthPercentage) : text_width; | 669 static_cast<int>(text_width * kContentWidthPercentage) : text_width; |
639 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); | 670 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); |
640 | 671 |
641 // Note: We force to URL to LTR for all text directions. | 672 // Note: We force to URL to LTR for all text directions. |
642 SetupLayoutForMatch(layout_, match.contents, match.contents_class, | 673 SetupLayoutForMatch(layout_, match->contents, match->contents_class, |
643 is_selected ? &selected_content_text_color_ : | 674 is_selected ? &selected_content_text_color_ : |
644 &content_text_color_, | 675 &content_text_color_, |
645 is_selected ? &selected_content_dim_text_color_ : | 676 is_selected ? &selected_content_dim_text_color_ : |
646 &content_dim_text_color_, | 677 &content_dim_text_color_, |
647 is_selected ? &url_selected_text_color_ : | 678 is_selected ? &url_selected_text_color_ : |
648 &url_text_color_, | 679 &url_text_color_, |
649 std::string()); | 680 std::string()); |
650 | 681 |
651 int actual_content_width, actual_content_height; | 682 int actual_content_width, actual_content_height; |
652 pango_layout_get_size(layout_, | 683 pango_layout_get_size(layout_, |
(...skipping 14 matching lines...) Expand all Loading... |
667 pango_cairo_show_layout(cr, layout_); | 698 pango_cairo_show_layout(cr, layout_); |
668 cairo_restore(cr); | 699 cairo_restore(cr); |
669 | 700 |
670 if (has_description) { | 701 if (has_description) { |
671 pango_layout_set_width(layout_, | 702 pango_layout_set_width(layout_, |
672 (text_width - actual_content_width) * PANGO_SCALE); | 703 (text_width - actual_content_width) * PANGO_SCALE); |
673 | 704 |
674 // In Windows, a boolean "force_dim" is passed as true for the | 705 // In Windows, a boolean "force_dim" is passed as true for the |
675 // description. Here, we pass the dim text color for both normal and dim, | 706 // description. Here, we pass the dim text color for both normal and dim, |
676 // to accomplish the same thing. | 707 // to accomplish the same thing. |
677 SetupLayoutForMatch(layout_, match.description, match.description_class, | 708 SetupLayoutForMatch(layout_, match->description, match->description_class, |
678 is_selected ? &selected_content_dim_text_color_ : | 709 is_selected ? &selected_content_dim_text_color_ : |
679 &content_dim_text_color_, | 710 &content_dim_text_color_, |
680 is_selected ? &selected_content_dim_text_color_ : | 711 is_selected ? &selected_content_dim_text_color_ : |
681 &content_dim_text_color_, | 712 &content_dim_text_color_, |
682 is_selected ? &url_selected_text_color_ : | 713 is_selected ? &url_selected_text_color_ : |
683 &url_text_color_, | 714 &url_text_color_, |
684 std::string(" - ")); | 715 std::string(" - ")); |
685 gint actual_description_width; | 716 gint actual_description_width; |
686 pango_layout_get_size(layout_, &actual_description_width, NULL); | 717 pango_layout_get_size(layout_, &actual_description_width, NULL); |
687 | 718 |
688 cairo_save(cr); | 719 cairo_save(cr); |
689 cairo_move_to(cr, ltr ? | 720 cairo_move_to(cr, ltr ? |
690 (kIconAreaWidth + actual_content_width) : | 721 (kIconAreaWidth + actual_content_width) : |
691 (text_width - actual_content_width - | 722 (text_width - actual_content_width - |
692 (actual_description_width / PANGO_SCALE)), | 723 (actual_description_width / PANGO_SCALE)), |
693 content_y); | 724 content_y); |
694 pango_cairo_show_layout(cr, layout_); | 725 pango_cairo_show_layout(cr, layout_); |
695 cairo_restore(cr); | 726 cairo_restore(cr); |
696 } | 727 } |
| 728 |
| 729 if (match->associated_keyword.get()) { |
| 730 // If this entry has an associated keyword, draw the arrow at the extreme |
| 731 // other side of the omnibox. |
| 732 icon_start_x = ltr ? (line_rect.width() - kIconLeftPadding - kIconWidth) : |
| 733 kIconLeftPadding; |
| 734 // Draw the icon for this result. |
| 735 DrawFullImage(cr, widget, |
| 736 theme_service_->GetImageNamed( |
| 737 is_selected ? IDR_OMNIBOX_TTS_DARK : IDR_OMNIBOX_TTS), |
| 738 icon_start_x, line_rect.y() + kIconTopPadding); |
| 739 } |
697 } | 740 } |
698 | 741 |
699 cairo_destroy(cr); | 742 cairo_destroy(cr); |
700 return TRUE; | 743 return TRUE; |
701 } | 744 } |
OLD | NEW |