summaryrefslogtreecommitdiff
path: root/chromium/ui/views/controls/combobox
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/ui/views/controls/combobox
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-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.cc97
-rw-r--r--chromium/ui/views/controls/combobox/combobox.h4
-rw-r--r--chromium/ui/views/controls/combobox/combobox_unittest.cc82
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());