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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 | 93 |
94 // Return a Rect covering the whole area of |window|. | 94 // Return a Rect covering the whole area of |window|. |
95 gfx::Rect GetWindowRect(GdkWindow* window) { | 95 gfx::Rect GetWindowRect(GdkWindow* window) { |
96 gint width = gdk_window_get_width(window); | 96 gint width = gdk_window_get_width(window); |
97 gint height = gdk_window_get_height(window); | 97 gint height = gdk_window_get_height(window); |
98 return gfx::Rect(width, height); | 98 return gfx::Rect(width, height); |
99 } | 99 } |
100 | 100 |
101 // Return a Rect for the space for a result line. This excludes the border, | 101 // Return a Rect for the space for a result line. This excludes the border, |
102 // but includes the padding. This is the area that is colored for a selection. | 102 // but includes the padding. This is the area that is colored for a selection. |
103 gfx::Rect GetRectForLine(size_t line, int width) { | 103 gfx::Rect GetRectForLine(size_t line, int width) { |
Evan Stade
2013/08/14 19:32:48
make this a member function so you can account for
Jered
2013/08/14 21:16:22
Done.
| |
104 return gfx::Rect(kBorderThickness, | 104 return gfx::Rect(kBorderThickness, |
105 (line * kHeightPerResult) + kBorderThickness, | 105 (line * kHeightPerResult) + kBorderThickness, |
106 width - (kBorderThickness * 2), | 106 width - (kBorderThickness * 2), |
107 kHeightPerResult); | 107 kHeightPerResult); |
108 } | 108 } |
109 | 109 |
110 // TODO(deanm): Find some better home for this, and make it more efficient. | 110 // TODO(deanm): Find some better home for this, and make it more efficient. |
111 size_t GetUTF8Offset(const string16& text, size_t text_offset) { | 111 size_t GetUTF8Offset(const string16& text, size_t text_offset) { |
112 return UTF16ToUTF8(text.substr(0, text_offset)).length(); | 112 return UTF16ToUTF8(text.substr(0, text_offset)).length(); |
113 } | 113 } |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 | 340 |
341 bool OmniboxPopupViewGtk::IsOpen() const { | 341 bool OmniboxPopupViewGtk::IsOpen() const { |
342 return opened_; | 342 return opened_; |
343 } | 343 } |
344 | 344 |
345 void OmniboxPopupViewGtk::InvalidateLine(size_t line) { | 345 void OmniboxPopupViewGtk::InvalidateLine(size_t line) { |
346 // TODO(deanm): Is it possible to use some constant for the width, instead | 346 // TODO(deanm): Is it possible to use some constant for the width, instead |
347 // of having to query the width of the window? | 347 // of having to query the width of the window? |
348 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); | 348 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); |
349 GdkRectangle line_rect = GetRectForLine( | 349 GdkRectangle line_rect = GetRectForLine( |
350 line, GetWindowRect(gdk_window).width()).ToGdkRectangle(); | 350 line - GetHiddenMatchCount(), |
351 GetWindowRect(gdk_window).width()).ToGdkRectangle(); | |
351 gdk_window_invalidate_rect(gdk_window, &line_rect, FALSE); | 352 gdk_window_invalidate_rect(gdk_window, &line_rect, FALSE); |
352 } | 353 } |
353 | 354 |
354 void OmniboxPopupViewGtk::UpdatePopupAppearance() { | 355 void OmniboxPopupViewGtk::UpdatePopupAppearance() { |
355 const AutocompleteResult& result = model_->result(); | 356 const AutocompleteResult& result = model_->result(); |
356 if (result.empty()) { | 357 const size_t hidden_matches = GetHiddenMatchCount(); |
358 if (result.size() <= hidden_matches) { | |
357 Hide(); | 359 Hide(); |
358 return; | 360 return; |
359 } | 361 } |
360 | 362 |
361 Show(result.size()); | 363 Show(result.size() - hidden_matches); |
362 gtk_widget_queue_draw(window_); | 364 gtk_widget_queue_draw(window_); |
363 } | 365 } |
364 | 366 |
365 gfx::Rect OmniboxPopupViewGtk::GetTargetBounds() { | 367 gfx::Rect OmniboxPopupViewGtk::GetTargetBounds() { |
366 if (!gtk_widget_get_realized(window_)) | 368 if (!gtk_widget_get_realized(window_)) |
367 return gfx::Rect(); | 369 return gfx::Rect(); |
368 | 370 |
369 gfx::Rect retval = ui::GetWidgetScreenBounds(window_); | 371 gfx::Rect retval = ui::GetWidgetScreenBounds(window_); |
370 | 372 |
371 // The widget bounds don't update synchronously so may be out of sync with | 373 // The widget bounds don't update synchronously so may be out of sync with |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 void OmniboxPopupViewGtk::StackWindow() { | 463 void OmniboxPopupViewGtk::StackWindow() { |
462 gfx::NativeView omnibox_view = omnibox_view_->GetNativeView(); | 464 gfx::NativeView omnibox_view = omnibox_view_->GetNativeView(); |
463 DCHECK(GTK_IS_WIDGET(omnibox_view)); | 465 DCHECK(GTK_IS_WIDGET(omnibox_view)); |
464 GtkWidget* toplevel = gtk_widget_get_toplevel(omnibox_view); | 466 GtkWidget* toplevel = gtk_widget_get_toplevel(omnibox_view); |
465 DCHECK(gtk_widget_is_toplevel(toplevel)); | 467 DCHECK(gtk_widget_is_toplevel(toplevel)); |
466 ui::StackPopupWindow(window_, toplevel); | 468 ui::StackPopupWindow(window_, toplevel); |
467 } | 469 } |
468 | 470 |
469 size_t OmniboxPopupViewGtk::LineFromY(int y) { | 471 size_t OmniboxPopupViewGtk::LineFromY(int y) { |
470 size_t line = std::max(y - kBorderThickness, 0) / kHeightPerResult; | 472 size_t line = std::max(y - kBorderThickness, 0) / kHeightPerResult; |
471 return std::min(line, model_->result().size() - 1); | 473 return std::min(line + GetHiddenMatchCount(), model_->result().size() - 1); |
472 } | 474 } |
473 | 475 |
474 void OmniboxPopupViewGtk::AcceptLine(size_t line, | 476 void OmniboxPopupViewGtk::AcceptLine(size_t line, |
475 WindowOpenDisposition disposition) { | 477 WindowOpenDisposition disposition) { |
476 // OpenMatch() may close the popup, which will clear the result set and, by | 478 // OpenMatch() may close the popup, which will clear the result set and, by |
477 // extension, |match| and its contents. So copy the relevant match out to | 479 // extension, |match| and its contents. So copy the relevant match out to |
478 // make sure it stays alive until the call completes. | 480 // make sure it stays alive until the call completes. |
479 AutocompleteMatch match = model_->result().match_at(line); | 481 AutocompleteMatch match = model_->result().match_at(line); |
480 omnibox_view_->OpenMatch(match, disposition, GURL(), line); | 482 omnibox_view_->OpenMatch(match, disposition, GURL(), line); |
481 } | 483 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 model_->selected_line_state() == OmniboxPopupModel::KEYWORD) { | 535 model_->selected_line_state() == OmniboxPopupModel::KEYWORD) { |
534 *match = result.match_at(index).associated_keyword.get(); | 536 *match = result.match_at(index).associated_keyword.get(); |
535 *is_selected_keyword = true; | 537 *is_selected_keyword = true; |
536 return; | 538 return; |
537 } | 539 } |
538 | 540 |
539 *match = &result.match_at(index); | 541 *match = &result.match_at(index); |
540 *is_selected_keyword = false; | 542 *is_selected_keyword = false; |
541 } | 543 } |
542 | 544 |
545 size_t OmniboxPopupViewGtk::GetHiddenMatchCount() { | |
546 return model_->result().ShouldHideTopMatch() ? 1 : 0; | |
547 } | |
548 | |
543 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, | 549 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, |
544 GdkEventMotion* event) { | 550 GdkEventMotion* event) { |
545 // TODO(deanm): Windows has a bunch of complicated logic here. | 551 // TODO(deanm): Windows has a bunch of complicated logic here. |
546 size_t line = LineFromY(static_cast<int>(event->y)); | 552 size_t line = LineFromY(static_cast<int>(event->y)); |
547 // There is both a hovered and selected line, hovered just means your mouse | 553 // There is both a hovered and selected line, hovered just means your mouse |
548 // is over it, but selected is what's showing in the location edit. | 554 // is over it, but selected is what's showing in the location edit. |
549 model_->SetHoveredLine(line); | 555 model_->SetHoveredLine(line); |
550 // Select the line if the user has the left mouse button down. | 556 // Select the line if the user has the left mouse button down. |
551 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) | 557 if (!ignore_mouse_drag_ && (event->state & GDK_BUTTON1_MASK)) |
552 model_->SetSelectedLine(line, false, false); | 558 model_->SetSelectedLine(line, false, false); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
610 // to support painting a border that isn't 1 pixel thick. There is no point | 616 // to support painting a border that isn't 1 pixel thick. There is no point |
611 // in writing that code now, and explode if that day ever comes. | 617 // in writing that code now, and explode if that day ever comes. |
612 COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied); | 618 COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied); |
613 // Draw the 1px border around the entire window. | 619 // Draw the 1px border around the entire window. |
614 gdk_cairo_set_source_color(cr, &border_color_); | 620 gdk_cairo_set_source_color(cr, &border_color_); |
615 cairo_rectangle(cr, 0, 0, window_rect.width(), window_rect.height()); | 621 cairo_rectangle(cr, 0, 0, window_rect.width(), window_rect.height()); |
616 cairo_stroke(cr); | 622 cairo_stroke(cr); |
617 | 623 |
618 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); | 624 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); |
619 | 625 |
620 for (size_t i = 0; i < result.size(); ++i) { | 626 const size_t hidden_matches = GetHiddenMatchCount(); |
621 gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); | 627 for (size_t i = hidden_matches; i < result.size(); ++i) { |
628 gfx::Rect line_rect = GetRectForLine(i - hidden_matches, | |
629 window_rect.width()); | |
622 // Only repaint and layout damaged lines. | 630 // Only repaint and layout damaged lines. |
623 if (!line_rect.Intersects(damage_rect)) | 631 if (!line_rect.Intersects(damage_rect)) |
624 continue; | 632 continue; |
625 | 633 |
626 const AutocompleteMatch* match = NULL; | 634 const AutocompleteMatch* match = NULL; |
627 bool is_selected_keyword = false; | 635 bool is_selected_keyword = false; |
628 GetVisibleMatchForInput(i, &match, &is_selected_keyword); | 636 GetVisibleMatchForInput(i, &match, &is_selected_keyword); |
629 bool is_selected = (model_->selected_line() == i); | 637 bool is_selected = (model_->selected_line() == i); |
630 bool is_hovered = (model_->hovered_line() == i); | 638 bool is_hovered = (model_->hovered_line() == i); |
631 if (is_selected || is_hovered) { | 639 if (is_selected || is_hovered) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
721 theme_service_->GetImageNamed( | 729 theme_service_->GetImageNamed( |
722 is_selected ? IDR_OMNIBOX_TTS_DARK : | 730 is_selected ? IDR_OMNIBOX_TTS_DARK : |
723 IDR_OMNIBOX_TTS), | 731 IDR_OMNIBOX_TTS), |
724 icon_start_x, line_rect.y() + kIconTopPadding); | 732 icon_start_x, line_rect.y() + kIconTopPadding); |
725 } | 733 } |
726 } | 734 } |
727 | 735 |
728 cairo_destroy(cr); | 736 cairo_destroy(cr); |
729 return TRUE; | 737 return TRUE; |
730 } | 738 } |
OLD | NEW |