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

Side by Side Diff: ui/views/controls/combobox/combobox.cc

Issue 1904753002: MenuButton: support Mac look & feel (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: only cache one arrow image Created 4 years, 7 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
OLDNEW
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 "ui/views/controls/combobox/combobox.h" 5 #include "ui/views/controls/combobox/combobox.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <utility> 9 #include <utility>
10 10
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 namespace { 47 namespace {
48 48
49 // Menu border widths 49 // Menu border widths
50 const int kMenuBorderWidthLeft = 1; 50 const int kMenuBorderWidthLeft = 1;
51 const int kMenuBorderWidthTop = 1; 51 const int kMenuBorderWidthTop = 1;
52 const int kMenuBorderWidthRight = 1; 52 const int kMenuBorderWidthRight = 1;
53 53
54 // Limit how small a combobox can be. 54 // Limit how small a combobox can be.
55 const int kMinComboboxWidth = 25; 55 const int kMinComboboxWidth = 25;
56 56
57 // Size of the combobox arrow margins
58 const int kDisclosureArrowLeftPadding = 7;
59 const int kDisclosureArrowRightPadding = 7;
60 const int kDisclosureArrowButtonLeftPadding = 11;
61 const int kDisclosureArrowButtonRightPadding = 12;
62
63 // Define the id of the first item in the menu (since it needs to be > 0) 57 // Define the id of the first item in the menu (since it needs to be > 0)
64 const int kFirstMenuItemId = 1000; 58 const int kFirstMenuItemId = 1000;
65 59
66 // Used to indicate that no item is currently selected by the user. 60 // Used to indicate that no item is currently selected by the user.
67 const int kNoSelection = -1; 61 const int kNoSelection = -1;
68 62
69 const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON); 63 const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON);
70 const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H); 64 const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
71 const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P); 65 const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
72 const int kFocusedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_F); 66 const int kFocusedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 329
336 Combobox* owner_; // Weak. Owns this. 330 Combobox* owner_; // Weak. Owns this.
337 ui::ComboboxModel* model_; // Weak. 331 ui::ComboboxModel* model_; // Weak.
338 332
339 DISALLOW_COPY_AND_ASSIGN(ComboboxMenuModelAdapter); 333 DISALLOW_COPY_AND_ASSIGN(ComboboxMenuModelAdapter);
340 }; 334 };
341 335
342 //////////////////////////////////////////////////////////////////////////////// 336 ////////////////////////////////////////////////////////////////////////////////
343 // Combobox, public: 337 // Combobox, public:
344 338
345 Combobox::Combobox(ui::ComboboxModel* model) 339 Combobox::Combobox(ui::ComboboxModel* model, Style style)
346 : model_(model), 340 : model_(model),
347 style_(STYLE_NORMAL), 341 style_(style),
348 listener_(NULL), 342 listener_(NULL),
349 selected_index_(model_->GetDefaultIndex()), 343 selected_index_(model_->GetDefaultIndex()),
350 invalid_(false), 344 invalid_(false),
351 menu_model_adapter_(new ComboboxMenuModelAdapter(this, model)), 345 menu_model_adapter_(new ComboboxMenuModelAdapter(this, model)),
352 text_button_(new TransparentButton(this)), 346 text_button_(new TransparentButton(this)),
353 arrow_button_(new TransparentButton(this)), 347 arrow_button_(new TransparentButton(this)),
354 weak_ptr_factory_(this) { 348 weak_ptr_factory_(this) {
349 if (style_ == STYLE_ACTION)
350 selected_index_ = 0;
351
355 ModelChanged(); 352 ModelChanged();
356 SetFocusable(true); 353 SetFocusable(true);
357 UpdateBorder(); 354 UpdateBorder();
355 arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style);
358 // set_background() takes ownership but takes a raw pointer. 356 // set_background() takes ownership but takes a raw pointer.
359 std::unique_ptr<Background> b = PlatformStyle::CreateComboboxBackground(); 357 std::unique_ptr<Background> b =
358 PlatformStyle::CreateComboboxBackground(GetShoulderWidth());
360 set_background(b.release()); 359 set_background(b.release());
361 360
362 // Initialize the button images. 361 // Initialize the button images.
363 Button::ButtonState button_states[] = { 362 Button::ButtonState button_states[] = {
364 Button::STATE_DISABLED, 363 Button::STATE_DISABLED,
365 Button::STATE_NORMAL, 364 Button::STATE_NORMAL,
366 Button::STATE_HOVERED, 365 Button::STATE_HOVERED,
367 Button::STATE_PRESSED, 366 Button::STATE_PRESSED,
368 }; 367 };
369 for (int i = 0; i < 2; i++) { 368 for (int i = 0; i < 2; i++) {
(...skipping 23 matching lines...) Expand all
393 DCHECK(selector_.get() != GetInputMethod()->GetTextInputClient()); 392 DCHECK(selector_.get() != GetInputMethod()->GetTextInputClient());
394 } 393 }
395 } 394 }
396 395
397 // static 396 // static
398 const gfx::FontList& Combobox::GetFontList() { 397 const gfx::FontList& Combobox::GetFontList() {
399 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 398 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
400 return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta); 399 return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
401 } 400 }
402 401
403 void Combobox::SetStyle(Style style) {
404 if (style_ == style)
405 return;
406
407 style_ = style;
408 if (style_ == STYLE_ACTION)
409 selected_index_ = 0;
410
411 UpdateBorder();
412 content_size_ = GetContentSize();
413 PreferredSizeChanged();
414 }
415
416 void Combobox::ModelChanged() { 402 void Combobox::ModelChanged() {
417 // If the selection is no longer valid (or the model is empty), restore the 403 // If the selection is no longer valid (or the model is empty), restore the
418 // default index. 404 // default index.
419 if (selected_index_ >= model_->GetItemCount() || 405 if (selected_index_ >= model_->GetItemCount() ||
420 model_->GetItemCount() == 0 || 406 model_->GetItemCount() == 0 ||
421 model_->IsItemSeparatorAt(selected_index_)) { 407 model_->IsItemSeparatorAt(selected_index_)) {
422 selected_index_ = model_->GetDefaultIndex(); 408 selected_index_ = model_->GetDefaultIndex();
423 } 409 }
424 410
425 content_size_ = GetContentSize(); 411 content_size_ = GetContentSize();
(...skipping 28 matching lines...) Expand all
454 void Combobox::SetInvalid(bool invalid) { 440 void Combobox::SetInvalid(bool invalid) {
455 if (invalid == invalid_) 441 if (invalid == invalid_)
456 return; 442 return;
457 443
458 invalid_ = invalid; 444 invalid_ = invalid;
459 445
460 UpdateBorder(); 446 UpdateBorder();
461 SchedulePaint(); 447 SchedulePaint();
462 } 448 }
463 449
464 int Combobox::GetArrowButtonWidth() const { 450 int Combobox::GetShoulderWidth() const {
tapted 2016/04/27 03:25:11 nit: move to the end of the file to match declarat
Elly Fong-Jones 2016/04/28 17:03:12 Done.
465 return GetDisclosureArrowLeftPadding() + 451 const int kNormalPadding = 7;
466 ArrowSize().width() + 452 const int kActionPadding = 11;
467 GetDisclosureArrowRightPadding(); 453 int padding = style_ == STYLE_NORMAL ? kNormalPadding : kActionPadding;
454 return ArrowSize().width() + 2 * padding;
468 } 455 }
469 456
470 void Combobox::Layout() { 457 void Combobox::Layout() {
471 PrefixDelegate::Layout(); 458 PrefixDelegate::Layout();
472 459
473 gfx::Insets insets = GetInsets(); 460 gfx::Insets insets = GetInsets();
474 int text_button_width = 0; 461 int text_button_width = 0;
475 int arrow_button_width = 0; 462 int arrow_button_width = 0;
476 463
477 switch (style_) { 464 switch (style_) {
478 case STYLE_NORMAL: { 465 case STYLE_NORMAL: {
479 arrow_button_width = width(); 466 arrow_button_width = width();
480 break; 467 break;
481 } 468 }
482 case STYLE_ACTION: { 469 case STYLE_ACTION: {
483 arrow_button_width = GetDisclosureArrowLeftPadding() + 470 arrow_button_width = GetShoulderWidth();
484 ArrowSize().width() +
485 GetDisclosureArrowRightPadding();
486 text_button_width = width() - arrow_button_width; 471 text_button_width = width() - arrow_button_width;
487 break; 472 break;
488 } 473 }
489 } 474 }
490 475
491 int arrow_button_x = std::max(0, text_button_width); 476 int arrow_button_x = std::max(0, text_button_width);
492 text_button_->SetBounds(0, 0, std::max(0, text_button_width), height()); 477 text_button_->SetBounds(0, 0, std::max(0, text_button_width), height());
493 arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height()); 478 arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height());
494 } 479 }
495 480
481 void Combobox::OnEnabledChanged() {
482 PrefixDelegate::OnEnabledChanged();
483 arrow_image_ = PlatformStyle::CreateComboboxArrow(enabled(), style_);
484 }
485
496 int Combobox::GetRowCount() { 486 int Combobox::GetRowCount() {
497 return model()->GetItemCount(); 487 return model()->GetItemCount();
498 } 488 }
499 489
500 int Combobox::GetSelectedRow() { 490 int Combobox::GetSelectedRow() {
501 return selected_index_; 491 return selected_index_;
502 } 492 }
503 493
504 void Combobox::SetSelectedRow(int row) { 494 void Combobox::SetSelectedRow(int row) {
505 int prev_index = selected_index_; 495 int prev_index = selected_index_;
(...skipping 12 matching lines...) Expand all
518 508
519 gfx::Size Combobox::GetPreferredSize() const { 509 gfx::Size Combobox::GetPreferredSize() const {
520 // The preferred size will drive the local bounds which in turn is used to set 510 // The preferred size will drive the local bounds which in turn is used to set
521 // the minimum width for the dropdown list. 511 // the minimum width for the dropdown list.
522 gfx::Insets insets = GetInsets(); 512 gfx::Insets insets = GetInsets();
523 insets += gfx::Insets(Textfield::kTextPadding, 513 insets += gfx::Insets(Textfield::kTextPadding,
524 Textfield::kTextPadding, 514 Textfield::kTextPadding,
525 Textfield::kTextPadding, 515 Textfield::kTextPadding,
526 Textfield::kTextPadding); 516 Textfield::kTextPadding);
527 int total_width = std::max(kMinComboboxWidth, content_size_.width()) + 517 int total_width = std::max(kMinComboboxWidth, content_size_.width()) +
528 insets.width() + GetDisclosureArrowLeftPadding() + 518 insets.width() + GetShoulderWidth();
529 ArrowSize().width() + GetDisclosureArrowRightPadding();
530 return gfx::Size(total_width, content_size_.height() + insets.height()); 519 return gfx::Size(total_width, content_size_.height() + insets.height());
531 } 520 }
532 521
533 const char* Combobox::GetClassName() const { 522 const char* Combobox::GetClassName() const {
534 return kViewClassName; 523 return kViewClassName;
535 } 524 }
536 525
537 bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { 526 bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
538 // Escape should close the drop down list when it is active, not host UI. 527 // Escape should close the drop down list when it is active, not host UI.
539 if (e.key_code() != ui::VKEY_ESCAPE || 528 if (e.key_code() != ui::VKEY_ESCAPE ||
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 SkColor text_color = GetNativeTheme()->GetSystemColor( 715 SkColor text_color = GetNativeTheme()->GetSystemColor(
727 enabled() ? ui::NativeTheme::kColorId_LabelEnabledColor : 716 enabled() ? ui::NativeTheme::kColorId_LabelEnabledColor :
728 ui::NativeTheme::kColorId_LabelDisabledColor); 717 ui::NativeTheme::kColorId_LabelDisabledColor);
729 718
730 DCHECK_GE(selected_index_, 0); 719 DCHECK_GE(selected_index_, 0);
731 DCHECK_LT(selected_index_, model()->GetItemCount()); 720 DCHECK_LT(selected_index_, model()->GetItemCount());
732 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount()) 721 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
733 selected_index_ = 0; 722 selected_index_ = 0;
734 base::string16 text = model()->GetItemAt(selected_index_); 723 base::string16 text = model()->GetItemAt(selected_index_);
735 724
736 gfx::Size arrow_size = ArrowSize(); 725 int disclosure_arrow_offset = width() - GetShoulderWidth();
737 int disclosure_arrow_offset = width() - arrow_size.width() -
738 GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding();
739 726
740 const gfx::FontList& font_list = Combobox::GetFontList(); 727 const gfx::FontList& font_list = Combobox::GetFontList();
741 int text_width = gfx::GetStringWidth(text, font_list); 728 int text_width = gfx::GetStringWidth(text, font_list);
742 if ((text_width + insets.width()) > disclosure_arrow_offset) 729 if ((text_width + insets.width()) > disclosure_arrow_offset)
743 text_width = disclosure_arrow_offset - insets.width(); 730 text_width = disclosure_arrow_offset - insets.width();
744 731
745 gfx::Rect text_bounds(x, y, text_width, text_height); 732 gfx::Rect text_bounds(x, y, text_width, text_height);
746 AdjustBoundsForRTLUI(&text_bounds); 733 AdjustBoundsForRTLUI(&text_bounds);
747 canvas->DrawStringRect(text, font_list, text_color, text_bounds); 734 canvas->DrawStringRect(text, font_list, text_color, text_bounds);
748 735
749 int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding(); 736 gfx::Rect arrow_bounds(disclosure_arrow_offset, 0, GetShoulderWidth(),
750 gfx::Rect arrow_bounds(arrow_x, 737 height());
751 height() / 2 - arrow_size.height() / 2, 738 arrow_bounds.ClampToCenteredSize(ArrowSize());
752 arrow_size.width(),
753 arrow_size.height());
754 AdjustBoundsForRTLUI(&arrow_bounds); 739 AdjustBoundsForRTLUI(&arrow_bounds);
755 740
756 gfx::ImageSkia arrow_image = PlatformStyle::CreateComboboxArrow( 741 canvas->DrawImageInt(arrow_image_, arrow_bounds.x(), arrow_bounds.y());
757 enabled(), style_);
758 canvas->DrawImageInt(arrow_image, arrow_bounds.x(), arrow_bounds.y());
759 } 742 }
760 743
761 void Combobox::PaintButtons(gfx::Canvas* canvas) { 744 void Combobox::PaintButtons(gfx::Canvas* canvas) {
762 DCHECK(style_ == STYLE_ACTION); 745 DCHECK(style_ == STYLE_ACTION);
763 746
764 gfx::ScopedCanvas scoped_canvas(canvas); 747 gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, bounds());
765 if (base::i18n::IsRTL()) {
766 canvas->Translate(gfx::Vector2d(width(), 0));
767 canvas->Scale(-1, 1);
768 }
769 748
770 bool focused = HasFocus(); 749 bool focused = HasFocus();
771 const std::vector<const gfx::ImageSkia*>& arrow_button_images = 750 const std::vector<const gfx::ImageSkia*>& arrow_button_images =
772 menu_button_images_[focused][ 751 menu_button_images_[focused][
773 arrow_button_->state() == Button::STATE_HOVERED ? 752 arrow_button_->state() == Button::STATE_HOVERED ?
774 Button::STATE_NORMAL : arrow_button_->state()]; 753 Button::STATE_NORMAL : arrow_button_->state()];
775 754
776 int text_button_hover_alpha = 755 int text_button_hover_alpha =
777 text_button_->state() == Button::STATE_PRESSED ? 0 : 756 text_button_->state() == Button::STATE_PRESSED ? 0 :
778 static_cast<int>(static_cast<TransparentButton*>(text_button_)-> 757 static_cast<int>(static_cast<TransparentButton*>(text_button_)->
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 845
867 // This combobox may be deleted by the listener. 846 // This combobox may be deleted by the listener.
868 base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr(); 847 base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
869 if (listener_) 848 if (listener_)
870 listener_->OnPerformAction(this); 849 listener_->OnPerformAction(this);
871 850
872 if (weak_ptr && style_ == STYLE_ACTION) 851 if (weak_ptr && style_ == STYLE_ACTION)
873 selected_index_ = 0; 852 selected_index_ = 0;
874 } 853 }
875 854
876 int Combobox::GetDisclosureArrowLeftPadding() const {
877 switch (style_) {
878 case STYLE_NORMAL:
879 return kDisclosureArrowLeftPadding;
880 case STYLE_ACTION:
881 return kDisclosureArrowButtonLeftPadding;
882 }
883 NOTREACHED();
884 return 0;
885 }
886
887 int Combobox::GetDisclosureArrowRightPadding() const {
888 switch (style_) {
889 case STYLE_NORMAL:
890 return kDisclosureArrowRightPadding;
891 case STYLE_ACTION:
892 return kDisclosureArrowButtonRightPadding;
893 }
894 NOTREACHED();
895 return 0;
896 }
897
898 gfx::Size Combobox::ArrowSize() const { 855 gfx::Size Combobox::ArrowSize() const {
899 return PlatformStyle::CreateComboboxArrow(enabled(), style_).size(); 856 return arrow_image_.size();
900 } 857 }
901 858
902 gfx::Size Combobox::GetContentSize() const { 859 gfx::Size Combobox::GetContentSize() const {
903 const gfx::FontList& font_list = GetFontList(); 860 const gfx::FontList& font_list = GetFontList();
904 861
905 int width = 0; 862 int width = 0;
906 for (int i = 0; i < model()->GetItemCount(); ++i) { 863 for (int i = 0; i < model()->GetItemCount(); ++i) {
907 if (model_->IsItemSeparatorAt(i)) 864 if (model_->IsItemSeparatorAt(i))
908 continue; 865 continue;
909 866
910 if (style_ != STYLE_ACTION || i == selected_index_) { 867 if (style_ != STYLE_ACTION || i == selected_index_) {
911 width = std::max( 868 width = std::max(
912 width, 869 width,
913 gfx::GetStringWidth(menu_model_adapter_->GetLabelAt(i), font_list)); 870 gfx::GetStringWidth(menu_model_adapter_->GetLabelAt(i), font_list));
914 } 871 }
915 } 872 }
916 return gfx::Size(width, font_list.GetHeight()); 873 return gfx::Size(width, font_list.GetHeight());
917 } 874 }
918 875
919 PrefixSelector* Combobox::GetPrefixSelector() { 876 PrefixSelector* Combobox::GetPrefixSelector() {
920 if (!selector_) 877 if (!selector_)
921 selector_.reset(new PrefixSelector(this)); 878 selector_.reset(new PrefixSelector(this));
922 return selector_.get(); 879 return selector_.get();
923 } 880 }
924 881
925 } // namespace views 882 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698