Commit cfabb5a3 authored by Mohamed Amir Yosef's avatar Mohamed Amir Yosef Committed by Commit Bot

[UI] Support icons and secondary labels in combobox

The underlying dropdown menu model already supports showing icons and
secondary labels.

This CL add such support to the combobox model. When an item is selected
the main label is shown inside in the combobox together with the icon.
Secondary labels are displayed only inside the dropdown menu.

Bug: 1044038
Change-Id: Ibe3cc37464bfd8e416aeadec62827b8ca103d13f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2207386
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770807}
parent f4c7c7c7
...@@ -4,8 +4,18 @@ ...@@ -4,8 +4,18 @@
#include "ui/base/models/combobox_model.h" #include "ui/base/models/combobox_model.h"
#include "ui/base/models/image_model.h"
namespace ui { namespace ui {
base::string16 ComboboxModel::GetDropDownSecondaryTextAt(int index) const {
return base::string16();
}
ImageModel ComboboxModel::GetIconAt(int index) const {
return ui::ImageModel();
}
bool ComboboxModel::IsItemSeparatorAt(int index) { bool ComboboxModel::IsItemSeparatorAt(int index) {
return false; return false;
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
namespace ui { namespace ui {
class ComboboxModelObserver; class ComboboxModelObserver;
class ImageModel;
// A data model for a combo box. // A data model for a combo box.
class UI_BASE_EXPORT ComboboxModel { class UI_BASE_EXPORT ComboboxModel {
...@@ -23,6 +24,14 @@ class UI_BASE_EXPORT ComboboxModel { ...@@ -23,6 +24,14 @@ class UI_BASE_EXPORT ComboboxModel {
// Returns the string at the specified index. // Returns the string at the specified index.
virtual base::string16 GetItemAt(int index) = 0; virtual base::string16 GetItemAt(int index) = 0;
// Returns the secondary string at the specified index. Secondary strings are
// displayed in a second line inside every menu item.
virtual base::string16 GetDropDownSecondaryTextAt(int index) const;
// Gets the icon for the item at the specified index. ImageModel is empty if
// there is no icon.
virtual ImageModel GetIconAt(int index) const;
// Should return true if the item at |index| is a non-selectable separator // Should return true if the item at |index| is a non-selectable separator
// item. // item.
virtual bool IsItemSeparatorAt(int index); virtual bool IsItemSeparatorAt(int index);
......
...@@ -132,7 +132,13 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { ...@@ -132,7 +132,13 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel {
} }
// Overridden from 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(); } int GetItemCount() const override { return model_->GetItemCount(); }
...@@ -160,6 +166,12 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { ...@@ -160,6 +166,12 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel {
return text; return text;
} }
base::string16 GetSecondaryLabelAt(int index) const override {
base::string16 text = model_->GetDropDownSecondaryTextAt(index);
base::i18n::AdjustStringForLocaleDirection(&text);
return text;
}
bool IsItemDynamicAt(int index) const override { return true; } bool IsItemDynamicAt(int index) const override { return true; }
const gfx::FontList* GetLabelFontListAt(int index) const override { const gfx::FontList* GetLabelFontListAt(int index) const override {
...@@ -178,7 +190,7 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel { ...@@ -178,7 +190,7 @@ class Combobox::ComboboxMenuModel : public ui::MenuModel {
int GetGroupIdAt(int index) const override { return -1; } int GetGroupIdAt(int index) const override { return -1; }
ui::ImageModel GetIconAt(int index) const override { ui::ImageModel GetIconAt(int index) const override {
return ui::ImageModel(); return model_->GetIconAt(index);
} }
ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override { ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
...@@ -443,7 +455,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) { ...@@ -443,7 +455,7 @@ bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
void Combobox::OnPaint(gfx::Canvas* canvas) { void Combobox::OnPaint(gfx::Canvas* canvas) {
OnPaintBackground(canvas); OnPaintBackground(canvas);
PaintText(canvas); PaintIconAndText(canvas);
OnPaintBorder(canvas); OnPaintBorder(canvas);
} }
...@@ -543,7 +555,7 @@ void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const { ...@@ -543,7 +555,7 @@ void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const {
rect->set_x(GetMirroredXForRect(*rect)); rect->set_x(GetMirroredXForRect(*rect));
} }
void Combobox::PaintText(gfx::Canvas* canvas) { void Combobox::PaintIconAndText(gfx::Canvas* canvas) {
gfx::Insets insets = GetInsets(); gfx::Insets insets = GetInsets();
insets += gfx::Insets(0, LayoutProvider::Get()->GetDistanceMetric( insets += gfx::Insets(0, LayoutProvider::Get()->GetDistanceMetric(
DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING)); DISTANCE_TEXTFIELD_HORIZONTAL_TEXT_PADDING));
...@@ -553,7 +565,19 @@ void Combobox::PaintText(gfx::Canvas* canvas) { ...@@ -553,7 +565,19 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
int x = insets.left(); int x = insets.left();
int y = insets.top(); 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::Image icon_image = icon.GetImage();
int icon_y = y + (contents_height - icon_image.Height()) / 2;
canvas->DrawImageInt(icon_image.AsImageSkia(), x, icon_y);
x += icon_image.Width() + LayoutProvider::Get()->GetDistanceMetric(
DISTANCE_RELATED_LABEL_HORIZONTAL);
}
// Draw the text.
SkColor text_color = GetTextColorForEnableState(*this, GetEnabled()); SkColor text_color = GetTextColorForEnableState(*this, GetEnabled());
DCHECK_GE(selected_index_, 0); DCHECK_GE(selected_index_, 0);
DCHECK_LT(selected_index_, model()->GetItemCount()); DCHECK_LT(selected_index_, model()->GetItemCount());
...@@ -565,10 +589,10 @@ void Combobox::PaintText(gfx::Canvas* canvas) { ...@@ -565,10 +589,10 @@ void Combobox::PaintText(gfx::Canvas* canvas) {
const gfx::FontList& font_list = GetFontList(); const gfx::FontList& font_list = GetFontList();
int text_width = gfx::GetStringWidth(text, font_list); int text_width = gfx::GetStringWidth(text, font_list);
if ((text_width + insets.width()) > disclosure_arrow_offset) text_width =
text_width = disclosure_arrow_offset - insets.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); AdjustBoundsForRTLUI(&text_bounds);
canvas->DrawStringRect(text, font_list, text_color, text_bounds); canvas->DrawStringRect(text, font_list, text_color, text_bounds);
...@@ -633,18 +657,25 @@ void Combobox::OnPerformAction() { ...@@ -633,18 +657,25 @@ void Combobox::OnPerformAction() {
gfx::Size Combobox::GetContentSize() const { gfx::Size Combobox::GetContentSize() const {
const gfx::FontList& font_list = GetFontList(); const gfx::FontList& font_list = GetFontList();
int height = font_list.GetHeight();
int width = 0; int width = 0;
for (int i = 0; i < model()->GetItemCount(); ++i) { for (int i = 0; i < model()->GetItemCount(); ++i) {
if (model_->IsItemSeparatorAt(i)) if (model_->IsItemSeparatorAt(i))
continue; continue;
if (size_to_largest_label_ || i == selected_index_) { if (size_to_largest_label_ || i == selected_index_) {
width = std::max( int item_width =
width, gfx::GetStringWidth(menu_model_->GetLabelAt(i), font_list)); gfx::GetStringWidth(menu_model_->GetLabelAt(i), font_list);
if (!menu_model_->GetIconAt(i).IsEmpty()) {
gfx::Image icon = menu_model_->GetIconAt(i).GetImage();
item_width += icon.Width() + LayoutProvider::Get()->GetDistanceMetric(
DISTANCE_RELATED_LABEL_HORIZONTAL);
height = std::max(height, icon.Height());
}
width = std::max(width, item_width);
} }
} }
return gfx::Size(width, font_list.GetHeight()); return gfx::Size(width, height);
} }
PrefixSelector* Combobox::GetPrefixSelector() { PrefixSelector* Combobox::GetPrefixSelector() {
......
...@@ -126,7 +126,7 @@ class VIEWS_EXPORT Combobox : public View, ...@@ -126,7 +126,7 @@ class VIEWS_EXPORT Combobox : public View,
void AdjustBoundsForRTLUI(gfx::Rect* rect) const; void AdjustBoundsForRTLUI(gfx::Rect* rect) const;
// Draws the selected value of the drop down list // Draws the selected value of the drop down list
void PaintText(gfx::Canvas* canvas); void PaintIconAndText(gfx::Canvas* canvas);
// Show the drop down list // Show the drop down list
void ShowDropDownMenu(ui::MenuSourceType source_type); void ShowDropDownMenu(ui::MenuSourceType source_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment