diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/ui/views/controls/combobox | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/ui/views/controls/combobox')
-rw-r--r-- | chromium/ui/views/controls/combobox/combobox.cc | 97 | ||||
-rw-r--r-- | chromium/ui/views/controls/combobox/combobox.h | 4 | ||||
-rw-r--r-- | chromium/ui/views/controls/combobox/combobox_unittest.cc | 82 |
3 files changed, 95 insertions, 88 deletions
diff --git a/chromium/ui/views/controls/combobox/combobox.cc b/chromium/ui/views/controls/combobox/combobox.cc index b0364bcdb3e..72903d758de 100644 --- a/chromium/ui/views/controls/combobox/combobox.cc +++ b/chromium/ui/views/controls/combobox/combobox.cc @@ -17,12 +17,14 @@ #include "ui/base/ime/input_method.h" #include "ui/base/models/image_model.h" #include "ui/base/models/menu_model.h" +#include "ui/base/ui_base_types.h" #include "ui/events/event.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/scoped_canvas.h" #include "ui/gfx/text_utils.h" #include "ui/native_theme/native_theme.h" +#include "ui/native_theme/themed_vector_icon.h" #include "ui/views/animation/flood_fill_ink_drop_ripple.h" #include "ui/views/animation/ink_drop_impl.h" #include "ui/views/background.h" @@ -54,6 +56,15 @@ SkColor GetTextColorForEnableState(const Combobox& combobox, bool enabled) { return style::GetColor(combobox, style::CONTEXT_TEXTFIELD, style); } +gfx::ImageSkia GetImageSkiaFromImageModel(const ui::ImageModel* model, + const ui::NativeTheme* native_theme) { + DCHECK(model); + DCHECK(!model->IsEmpty()); + return model->IsImage() ? model->GetImage().AsImageSkia() + : ui::ThemedVectorIcon(model->GetVectorIcon()) + .GetImageSkia(native_theme); +} + // The transparent button which holds a button state but is not rendered. class TransparentButton : public Button { public: @@ -132,7 +143,13 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { } // Overridden from MenuModel: - bool HasIcons() const override { return false; } + bool HasIcons() const override { + for (int i = 0; i < GetItemCount(); ++i) { + if (!GetIconAt(i).IsEmpty()) + return true; + } + return false; + } int GetItemCount() const override { return model_->GetItemCount(); } @@ -155,7 +172,13 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { base::string16 GetLabelAt(int index) const override { // Inserting the Unicode formatting characters if necessary so that the // text is displayed correctly in right-to-left UIs. - base::string16 text = model_->GetItemAt(index); + base::string16 text = model_->GetDropDownTextAt(index); + base::i18n::AdjustStringForLocaleDirection(&text); + return text; + } + + base::string16 GetSecondaryLabelAt(int index) const override { + base::string16 text = model_->GetDropDownSecondaryTextAt(index); base::i18n::AdjustStringForLocaleDirection(&text); return text; } @@ -178,7 +201,7 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { int GetGroupIdAt(int index) const override { return -1; } ui::ImageModel GetIconAt(int index) const override { - return ui::ImageModel(); + return model_->GetDropDownIconAt(index); } ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override { @@ -443,7 +466,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) { void Combobox::OnPaint(gfx::Canvas* canvas) { OnPaintBackground(canvas); - PaintText(canvas); + PaintIconAndText(canvas); OnPaintBorder(canvas); } @@ -504,16 +527,8 @@ void Combobox::ButtonPressed(Button* sender, const ui::Event& event) { // TODO(hajimehoshi): Fix the problem that the arrow button blinks when // cliking this while the dropdown menu is opened. - const base::TimeDelta delta = base::TimeTicks::Now() - closed_time_; - if (delta <= kMinimumTimeBetweenButtonClicks) - return; - - ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE; - if (event.IsKeyEvent()) - source_type = ui::MENU_SOURCE_KEYBOARD; - else if (event.IsGestureEvent() || event.IsTouchEvent()) - source_type = ui::MENU_SOURCE_TOUCH; - ShowDropDownMenu(source_type); + if ((base::TimeTicks::Now() - closed_time_) > kMinimumTimeBetweenButtonClicks) + ShowDropDownMenu(ui::GetMenuSourceTypeForEvent(event)); } void Combobox::OnComboboxModelChanged(ui::ComboboxModel* model) { @@ -543,7 +558,7 @@ void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const { rect->set_x(GetMirroredXForRect(*rect)); } -void Combobox::PaintText(gfx::Canvas* canvas) { +void Combobox::PaintIconAndText(gfx::Canvas* canvas) { gfx::Insets insets = GetInsets(); insets += gfx::Insets(0, LayoutProvider::Get()->GetDistanceMetric( DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING)); @@ -553,7 +568,20 @@ void Combobox::PaintText(gfx::Canvas* canvas) { int x = insets.left(); int y = insets.top(); - int text_height = height() - insets.height(); + int contents_height = height() - insets.height(); + + // Draw the icon. + ui::ImageModel icon = model()->GetIconAt(selected_index_); + if (!icon.IsEmpty()) { + gfx::ImageSkia icon_skia = + GetImageSkiaFromImageModel(&icon, GetNativeTheme()); + int icon_y = y + (contents_height - icon_skia.height()) / 2; + canvas->DrawImageInt(icon_skia, x, icon_y); + x += icon_skia.width() + LayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_LABEL_HORIZONTAL); + } + + // Draw the text. SkColor text_color = GetTextColorForEnableState(*this, GetEnabled()); DCHECK_GE(selected_index_, 0); DCHECK_LT(selected_index_, model()->GetItemCount()); @@ -565,10 +593,10 @@ void Combobox::PaintText(gfx::Canvas* canvas) { const gfx::FontList& font_list = GetFontList(); int text_width = gfx::GetStringWidth(text, font_list); - if ((text_width + insets.width()) > disclosure_arrow_offset) - text_width = disclosure_arrow_offset - insets.width(); + text_width = + std::min(text_width, disclosure_arrow_offset - insets.right() - x); - gfx::Rect text_bounds(x, y, text_width, text_height); + gfx::Rect text_bounds(x, y, text_width, contents_height); AdjustBoundsForRTLUI(&text_bounds); canvas->DrawStringRect(text, font_list, text_color, text_bounds); @@ -581,21 +609,15 @@ void Combobox::PaintText(gfx::Canvas* canvas) { } void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) { - // Menu border widths. - constexpr int kMenuBorderWidthLeft = 1; constexpr int kMenuBorderWidthTop = 1; - constexpr int kMenuBorderWidthRight = 1; - + // Menu's requested position's width should be the same as local bounds so the + // border of the menu lines up with the border of the combobox. The y + // coordinate however should be shifted to the bottom with the border with not + // to overlap with the combobox border. gfx::Rect lb = GetLocalBounds(); gfx::Point menu_position(lb.origin()); - - // Inset the menu's requested position so the border of the menu lines up - // with the border of the combobox. - menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft); menu_position.set_y(menu_position.y() + kMenuBorderWidthTop); - lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight)); - View::ConvertPointToScreen(this, &menu_position); gfx::Rect bounds(menu_position, lb.size()); @@ -633,18 +655,27 @@ void Combobox::OnPerformAction() { gfx::Size Combobox::GetContentSize() const { const gfx::FontList& font_list = GetFontList(); - + int height = font_list.GetHeight(); int width = 0; for (int i = 0; i < model()->GetItemCount(); ++i) { if (model_->IsItemSeparatorAt(i)) continue; if (size_to_largest_label_ || i == selected_index_) { - width = std::max( - width, gfx::GetStringWidth(menu_model_->GetLabelAt(i), font_list)); + int item_width = gfx::GetStringWidth(model()->GetItemAt(i), font_list); + ui::ImageModel icon = model()->GetIconAt(i); + if (!icon.IsEmpty()) { + gfx::ImageSkia icon_skia = + GetImageSkiaFromImageModel(&icon, GetNativeTheme()); + item_width += + icon_skia.width() + LayoutProvider::Get()->GetDistanceMetric( + DISTANCE_RELATED_LABEL_HORIZONTAL); + height = std::max(height, icon_skia.height()); + } + width = std::max(width, item_width); } } - return gfx::Size(width, font_list.GetHeight()); + return gfx::Size(width, height); } PrefixSelector* Combobox::GetPrefixSelector() { diff --git a/chromium/ui/views/controls/combobox/combobox.h b/chromium/ui/views/controls/combobox/combobox.h index d6da07f7122..91ad60c9a14 100644 --- a/chromium/ui/views/controls/combobox/combobox.h +++ b/chromium/ui/views/controls/combobox/combobox.h @@ -126,7 +126,7 @@ class VIEWS_EXPORT Combobox : public View, void AdjustBoundsForRTLUI(gfx::Rect* rect) const; // Draws the selected value of the drop down list - void PaintText(gfx::Canvas* canvas); + void PaintIconAndText(gfx::Canvas* canvas); // Show the drop down list void ShowDropDownMenu(ui::MenuSourceType source_type); @@ -207,7 +207,7 @@ class VIEWS_EXPORT Combobox : public View, bool size_to_largest_label_; // The focus ring for this Combobox. - std::unique_ptr<FocusRing> focus_ring_; + FocusRing* focus_ring_ = nullptr; ScopedObserver<ui::ComboboxModel, ui::ComboboxModelObserver> observer_{this}; diff --git a/chromium/ui/views/controls/combobox/combobox_unittest.cc b/chromium/ui/views/controls/combobox/combobox_unittest.cc index 9f0698b0d0e..b081a0b7408 100644 --- a/chromium/ui/views/controls/combobox/combobox_unittest.cc +++ b/chromium/ui/views/controls/combobox/combobox_unittest.cc @@ -30,7 +30,9 @@ #include "ui/views/controls/combobox/combobox_listener.h" #include "ui/views/style/platform_style.h" #include "ui/views/test/combobox_test_api.h" +#include "ui/views/test/view_metadata_test_utils.h" #include "ui/views/test/views_test_base.h" +#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_utils.h" @@ -42,36 +44,7 @@ using test::ComboboxTestApi; namespace { -// A wrapper of Combobox to intercept the result of OnKeyPressed() and -// OnKeyReleased() methods. -class TestCombobox : public Combobox { - public: - explicit TestCombobox(ui::ComboboxModel* model) - : Combobox(model), key_handled_(false), key_received_(false) {} - - bool OnKeyPressed(const ui::KeyEvent& e) override { - key_received_ = true; - key_handled_ = Combobox::OnKeyPressed(e); - return key_handled_; - } - - bool OnKeyReleased(const ui::KeyEvent& e) override { - key_received_ = true; - key_handled_ = Combobox::OnKeyReleased(e); - return key_handled_; - } - - bool key_handled() const { return key_handled_; } - bool key_received() const { return key_received_; } - - void clear() { key_received_ = key_handled_ = false; } - - private: - bool key_handled_; - bool key_received_; - - DISALLOW_COPY_AND_ASSIGN(TestCombobox); -}; +using TestCombobox = Combobox; // A concrete class is needed to test the combobox. class TestComboboxModel : public ui::ComboboxModel { @@ -83,14 +56,14 @@ class TestComboboxModel : public ui::ComboboxModel { // ui::ComboboxModel: int GetItemCount() const override { return item_count_; } - base::string16 GetItemAt(int index) override { + base::string16 GetItemAt(int index) const override { if (IsItemSeparatorAt(index)) { NOTREACHED(); return ASCIIToUTF16("SEPARATOR"); } return ASCIIToUTF16(index % 2 == 0 ? "PEANUT BUTTER" : "JELLY"); } - bool IsItemSeparatorAt(int index) override { + bool IsItemSeparatorAt(int index) const override { return separators_.find(index) != separators_.end(); } @@ -147,10 +120,10 @@ class VectorComboboxModel : public ui::ComboboxModel { int GetItemCount() const override { return static_cast<int>(values_->size()); } - base::string16 GetItemAt(int index) override { + base::string16 GetItemAt(int index) const override { return ASCIIToUTF16(values_->at(index)); } - bool IsItemSeparatorAt(int index) override { return false; } + bool IsItemSeparatorAt(int index) const override { return false; } int GetDefaultIndex() const override { return default_index_; } void AddObserver(ui::ComboboxModelObserver* observer) override { observers_.AddObserver(observer); @@ -222,8 +195,7 @@ class ComboboxTest : public ViewsTestBase { ComboboxTest() = default; void TearDown() override { - if (widget_) - widget_->Close(); + widget_.reset(); ViewsTestBase::TearDown(); } @@ -234,26 +206,25 @@ class ComboboxTest : public ViewsTestBase { model_->SetSeparators(*separators); ASSERT_FALSE(combobox_); - combobox_ = new TestCombobox(model_.get()); - test_api_ = std::make_unique<ComboboxTestApi>(combobox_); + auto combobox = std::make_unique<TestCombobox>(model_.get()); + test_api_ = std::make_unique<ComboboxTestApi>(combobox.get()); test_api_->InstallTestMenuRunner(&menu_show_count_); - combobox_->SetID(1); + combobox->SetID(1); - widget_ = new Widget; + widget_ = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.bounds = gfx::Rect(200, 200, 200, 200); widget_->Init(std::move(params)); - View* container = new View(); - widget_->SetContentsView(container); - container->AddChildView(combobox_); + View* container = widget_->SetContentsView(std::make_unique<View>()); + combobox_ = container->AddChildView(std::move(combobox)); widget_->Show(); combobox_->RequestFocus(); combobox_->SizeToPreferredSize(); - event_generator_ = - std::make_unique<ui::test::EventGenerator>(GetRootWindow(widget_)); + event_generator_ = std::make_unique<ui::test::EventGenerator>( + GetRootWindow(widget_.get())); event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW); } @@ -291,7 +262,7 @@ class ComboboxTest : public ViewsTestBase { } // We need widget to populate wrapper class. - Widget* widget_ = nullptr; + UniqueWidgetPtr widget_; // |combobox_| will be allocated InitCombobox() and then owned by |widget_|. TestCombobox* combobox_ = nullptr; @@ -356,23 +327,28 @@ TEST_F(ComboboxTest, KeyTestMac) { } #endif +// Iterate through all the metadata and test each property. +TEST_F(ComboboxTest, MetadataTest) { + InitCombobox(nullptr); + test::TestViewMetadata(combobox_); +} + // Check that if a combobox is disabled before it has a native wrapper, then the // native wrapper inherits the disabled state when it gets created. TEST_F(ComboboxTest, DisabilityTest) { model_ = std::make_unique<TestComboboxModel>(); ASSERT_FALSE(combobox_); - combobox_ = new TestCombobox(model_.get()); - combobox_->SetEnabled(false); + auto combobox = std::make_unique<TestCombobox>(model_.get()); + combobox->SetEnabled(false); - widget_ = new Widget; + widget_ = std::make_unique<Widget>(); Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.bounds = gfx::Rect(100, 100, 100, 100); widget_->Init(std::move(params)); - View* container = new View(); - widget_->SetContentsView(container); - container->AddChildView(combobox_); + View* container = widget_->SetContentsView(std::make_unique<View>()); + combobox_ = container->AddChildView(std::move(combobox)); EXPECT_FALSE(combobox_->GetEnabled()); } @@ -559,7 +535,7 @@ TEST_F(ComboboxTest, ListenerHandlesDelete) { // |combobox| will be deleted on change. TestCombobox* combobox = new TestCombobox(&model); - std::unique_ptr<EvilListener> evil_listener(new EvilListener()); + auto evil_listener = std::make_unique<EvilListener>(); combobox->set_listener(evil_listener.get()); ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2)); EXPECT_TRUE(evil_listener->deleted()); |