| Index: ui/views/controls/combobox/combobox.cc
|
| diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
|
| deleted file mode 100644
|
| index 22689c736ede2a9a98656b25deda80fbdeb0b8ee..0000000000000000000000000000000000000000
|
| --- a/ui/views/controls/combobox/combobox.cc
|
| +++ /dev/null
|
| @@ -1,868 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "ui/views/controls/combobox/combobox.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/logging.h"
|
| -#include "base/message_loop/message_loop_proxy.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "ui/accessibility/ax_view_state.h"
|
| -#include "ui/base/models/combobox_model.h"
|
| -#include "ui/base/resource/resource_bundle.h"
|
| -#include "ui/events/event.h"
|
| -#include "ui/events/keycodes/keyboard_codes.h"
|
| -#include "ui/gfx/animation/throb_animation.h"
|
| -#include "ui/gfx/canvas.h"
|
| -#include "ui/gfx/image/image.h"
|
| -#include "ui/gfx/scoped_canvas.h"
|
| -#include "ui/gfx/text_utils.h"
|
| -#include "ui/native_theme/common_theme.h"
|
| -#include "ui/native_theme/native_theme.h"
|
| -#include "ui/resources/grit/ui_resources.h"
|
| -#include "ui/views/background.h"
|
| -#include "ui/views/color_constants.h"
|
| -#include "ui/views/controls/button/custom_button.h"
|
| -#include "ui/views/controls/button/label_button.h"
|
| -#include "ui/views/controls/combobox/combobox_listener.h"
|
| -#include "ui/views/controls/focusable_border.h"
|
| -#include "ui/views/controls/menu/menu_item_view.h"
|
| -#include "ui/views/controls/menu/menu_runner.h"
|
| -#include "ui/views/controls/menu/menu_runner_handler.h"
|
| -#include "ui/views/controls/menu/submenu_view.h"
|
| -#include "ui/views/controls/prefix_selector.h"
|
| -#include "ui/views/controls/textfield/textfield.h"
|
| -#include "ui/views/ime/input_method.h"
|
| -#include "ui/views/mouse_constants.h"
|
| -#include "ui/views/painter.h"
|
| -#include "ui/views/widget/widget.h"
|
| -
|
| -namespace views {
|
| -
|
| -namespace {
|
| -
|
| -// Menu border widths
|
| -const int kMenuBorderWidthLeft = 1;
|
| -const int kMenuBorderWidthTop = 1;
|
| -const int kMenuBorderWidthRight = 1;
|
| -
|
| -// Limit how small a combobox can be.
|
| -const int kMinComboboxWidth = 25;
|
| -
|
| -// Size of the combobox arrow margins
|
| -const int kDisclosureArrowLeftPadding = 7;
|
| -const int kDisclosureArrowRightPadding = 7;
|
| -const int kDisclosureArrowButtonLeftPadding = 11;
|
| -const int kDisclosureArrowButtonRightPadding = 12;
|
| -
|
| -// Define the id of the first item in the menu (since it needs to be > 0)
|
| -const int kFirstMenuItemId = 1000;
|
| -
|
| -// Used to indicate that no item is currently selected by the user.
|
| -const int kNoSelection = -1;
|
| -
|
| -const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON);
|
| -const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
|
| -const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
|
| -const int kFocusedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
|
| -const int kFocusedHoveredBodyButtonImages[] =
|
| - IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
|
| -const int kFocusedPressedBodyButtonImages[] =
|
| - IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
|
| -
|
| -#define MENU_IMAGE_GRID(x) { \
|
| - x ## _MENU_TOP, x ## _MENU_CENTER, x ## _MENU_BOTTOM, }
|
| -
|
| -const int kMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON);
|
| -const int kHoveredMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
|
| -const int kPressedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
|
| -const int kFocusedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
|
| -const int kFocusedHoveredMenuButtonImages[] =
|
| - MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
|
| -const int kFocusedPressedMenuButtonImages[] =
|
| - MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
|
| -
|
| -#undef MENU_IMAGE_GRID
|
| -
|
| -// The transparent button which holds a button state but is not rendered.
|
| -class TransparentButton : public CustomButton {
|
| - public:
|
| - TransparentButton(ButtonListener* listener)
|
| - : CustomButton(listener) {
|
| - SetAnimationDuration(LabelButton::kHoverAnimationDurationMs);
|
| - }
|
| - virtual ~TransparentButton() {}
|
| -
|
| - virtual bool OnMousePressed(const ui::MouseEvent& mouse_event) override {
|
| - parent()->RequestFocus();
|
| - return true;
|
| - }
|
| -
|
| - double GetAnimationValue() const {
|
| - return hover_animation_->GetCurrentValue();
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(TransparentButton);
|
| -};
|
| -
|
| -// Returns the next or previous valid index (depending on |increment|'s value).
|
| -// Skips separator or disabled indices. Returns -1 if there is no valid adjacent
|
| -// index.
|
| -int GetAdjacentIndex(ui::ComboboxModel* model, int increment, int index) {
|
| - DCHECK(increment == -1 || increment == 1);
|
| -
|
| - index += increment;
|
| - while (index >= 0 && index < model->GetItemCount()) {
|
| - if (!model->IsItemSeparatorAt(index) || !model->IsItemEnabledAt(index))
|
| - return index;
|
| - index += increment;
|
| - }
|
| - return kNoSelection;
|
| -}
|
| -
|
| -// Returns the image resource ids of an array for the body button.
|
| -//
|
| -// TODO(hajimehoshi): This function should return the images for the 'disabled'
|
| -// status. (crbug/270052)
|
| -const int* GetBodyButtonImageIds(bool focused,
|
| - Button::ButtonState state,
|
| - size_t* num) {
|
| - DCHECK(num);
|
| - *num = 9;
|
| - switch (state) {
|
| - case Button::STATE_DISABLED:
|
| - return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
|
| - case Button::STATE_NORMAL:
|
| - return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
|
| - case Button::STATE_HOVERED:
|
| - return focused ?
|
| - kFocusedHoveredBodyButtonImages : kHoveredBodyButtonImages;
|
| - case Button::STATE_PRESSED:
|
| - return focused ?
|
| - kFocusedPressedBodyButtonImages : kPressedBodyButtonImages;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -// Returns the image resource ids of an array for the menu button.
|
| -const int* GetMenuButtonImageIds(bool focused,
|
| - Button::ButtonState state,
|
| - size_t* num) {
|
| - DCHECK(num);
|
| - *num = 3;
|
| - switch (state) {
|
| - case Button::STATE_DISABLED:
|
| - return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
|
| - case Button::STATE_NORMAL:
|
| - return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
|
| - case Button::STATE_HOVERED:
|
| - return focused ?
|
| - kFocusedHoveredMenuButtonImages : kHoveredMenuButtonImages;
|
| - case Button::STATE_PRESSED:
|
| - return focused ?
|
| - kFocusedPressedMenuButtonImages : kPressedMenuButtonImages;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -// Returns the images for the menu buttons.
|
| -std::vector<const gfx::ImageSkia*> GetMenuButtonImages(
|
| - bool focused,
|
| - Button::ButtonState state) {
|
| - const int* ids;
|
| - size_t num_ids;
|
| - ids = GetMenuButtonImageIds(focused, state, &num_ids);
|
| - std::vector<const gfx::ImageSkia*> images;
|
| - images.reserve(num_ids);
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - for (size_t i = 0; i < num_ids; i++)
|
| - images.push_back(rb.GetImageSkiaNamed(ids[i]));
|
| - return images;
|
| -}
|
| -
|
| -// Paints three images in a column at the given location. The center image is
|
| -// stretched so as to fit the given height.
|
| -void PaintImagesVertically(gfx::Canvas* canvas,
|
| - const gfx::ImageSkia& top_image,
|
| - const gfx::ImageSkia& center_image,
|
| - const gfx::ImageSkia& bottom_image,
|
| - int x, int y, int width, int height) {
|
| - canvas->DrawImageInt(top_image,
|
| - 0, 0, top_image.width(), top_image.height(),
|
| - x, y, width, top_image.height(), false);
|
| - y += top_image.height();
|
| - int center_height = height - top_image.height() - bottom_image.height();
|
| - canvas->DrawImageInt(center_image,
|
| - 0, 0, center_image.width(), center_image.height(),
|
| - x, y, width, center_height, false);
|
| - y += center_height;
|
| - canvas->DrawImageInt(bottom_image,
|
| - 0, 0, bottom_image.width(), bottom_image.height(),
|
| - x, y, width, bottom_image.height(), false);
|
| -}
|
| -
|
| -// Paints the arrow button.
|
| -void PaintArrowButton(
|
| - gfx::Canvas* canvas,
|
| - const std::vector<const gfx::ImageSkia*>& arrow_button_images,
|
| - int x, int height) {
|
| - PaintImagesVertically(canvas,
|
| - *arrow_button_images[0],
|
| - *arrow_button_images[1],
|
| - *arrow_button_images[2],
|
| - x, 0, arrow_button_images[0]->width(), height);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -const char Combobox::kViewClassName[] = "views/Combobox";
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// Combobox, public:
|
| -
|
| -Combobox::Combobox(ui::ComboboxModel* model)
|
| - : model_(model),
|
| - style_(STYLE_NORMAL),
|
| - listener_(NULL),
|
| - selected_index_(model_->GetDefaultIndex()),
|
| - invalid_(false),
|
| - menu_(NULL),
|
| - dropdown_open_(false),
|
| - text_button_(new TransparentButton(this)),
|
| - arrow_button_(new TransparentButton(this)),
|
| - weak_ptr_factory_(this) {
|
| - model_->AddObserver(this);
|
| - UpdateFromModel();
|
| - SetFocusable(true);
|
| - UpdateBorder();
|
| -
|
| - // Initialize the button images.
|
| - Button::ButtonState button_states[] = {
|
| - Button::STATE_DISABLED,
|
| - Button::STATE_NORMAL,
|
| - Button::STATE_HOVERED,
|
| - Button::STATE_PRESSED,
|
| - };
|
| - for (int i = 0; i < 2; i++) {
|
| - for (size_t state_index = 0; state_index < arraysize(button_states);
|
| - state_index++) {
|
| - Button::ButtonState state = button_states[state_index];
|
| - size_t num;
|
| - bool focused = !!i;
|
| - const int* ids = GetBodyButtonImageIds(focused, state, &num);
|
| - body_button_painters_[focused][state].reset(
|
| - Painter::CreateImageGridPainter(ids));
|
| - menu_button_images_[focused][state] = GetMenuButtonImages(focused, state);
|
| - }
|
| - }
|
| -
|
| - text_button_->SetVisible(true);
|
| - arrow_button_->SetVisible(true);
|
| - text_button_->SetFocusable(false);
|
| - arrow_button_->SetFocusable(false);
|
| - AddChildView(text_button_);
|
| - AddChildView(arrow_button_);
|
| -}
|
| -
|
| -Combobox::~Combobox() {
|
| - model_->RemoveObserver(this);
|
| -}
|
| -
|
| -// static
|
| -const gfx::FontList& Combobox::GetFontList() {
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - return rb.GetFontList(ui::ResourceBundle::BaseFont);
|
| -}
|
| -
|
| -void Combobox::SetStyle(Style style) {
|
| - if (style_ == style)
|
| - return;
|
| -
|
| - style_ = style;
|
| - if (style_ == STYLE_ACTION)
|
| - selected_index_ = 0;
|
| -
|
| - UpdateBorder();
|
| - UpdateFromModel();
|
| - PreferredSizeChanged();
|
| -}
|
| -
|
| -void Combobox::ModelChanged() {
|
| - selected_index_ = std::min(0, model_->GetItemCount());
|
| - UpdateFromModel();
|
| - PreferredSizeChanged();
|
| -}
|
| -
|
| -void Combobox::SetSelectedIndex(int index) {
|
| - if (style_ == STYLE_ACTION)
|
| - return;
|
| -
|
| - selected_index_ = index;
|
| - SchedulePaint();
|
| -}
|
| -
|
| -bool Combobox::SelectValue(const base::string16& value) {
|
| - if (style_ == STYLE_ACTION)
|
| - return false;
|
| -
|
| - for (int i = 0; i < model()->GetItemCount(); ++i) {
|
| - if (value == model()->GetItemAt(i)) {
|
| - SetSelectedIndex(i);
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -void Combobox::SetAccessibleName(const base::string16& name) {
|
| - accessible_name_ = name;
|
| -}
|
| -
|
| -void Combobox::SetInvalid(bool invalid) {
|
| - if (invalid == invalid_)
|
| - return;
|
| -
|
| - invalid_ = invalid;
|
| -
|
| - UpdateBorder();
|
| - SchedulePaint();
|
| -}
|
| -
|
| -ui::TextInputClient* Combobox::GetTextInputClient() {
|
| - if (!selector_)
|
| - selector_.reset(new PrefixSelector(this));
|
| - return selector_.get();
|
| -}
|
| -
|
| -void Combobox::Layout() {
|
| - PrefixDelegate::Layout();
|
| -
|
| - gfx::Insets insets = GetInsets();
|
| - int text_button_width = 0;
|
| - int arrow_button_width = 0;
|
| -
|
| - switch (style_) {
|
| - case STYLE_NORMAL: {
|
| - arrow_button_width = width();
|
| - break;
|
| - }
|
| - case STYLE_ACTION: {
|
| - arrow_button_width = GetDisclosureArrowLeftPadding() +
|
| - ArrowSize().width() +
|
| - GetDisclosureArrowRightPadding();
|
| - text_button_width = width() - arrow_button_width;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - int arrow_button_x = std::max(0, text_button_width);
|
| - text_button_->SetBounds(0, 0, std::max(0, text_button_width), height());
|
| - arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height());
|
| -}
|
| -
|
| -bool Combobox::IsItemChecked(int id) const {
|
| - return false;
|
| -}
|
| -
|
| -bool Combobox::IsCommandEnabled(int id) const {
|
| - return model()->IsItemEnabledAt(MenuCommandToIndex(id));
|
| -}
|
| -
|
| -void Combobox::ExecuteCommand(int id) {
|
| - selected_index_ = MenuCommandToIndex(id);
|
| - OnPerformAction();
|
| -}
|
| -
|
| -bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) const {
|
| - return false;
|
| -}
|
| -
|
| -int Combobox::GetRowCount() {
|
| - return model()->GetItemCount();
|
| -}
|
| -
|
| -int Combobox::GetSelectedRow() {
|
| - return selected_index_;
|
| -}
|
| -
|
| -void Combobox::SetSelectedRow(int row) {
|
| - int prev_index = selected_index_;
|
| - SetSelectedIndex(row);
|
| - if (selected_index_ != prev_index)
|
| - OnPerformAction();
|
| -}
|
| -
|
| -base::string16 Combobox::GetTextForRow(int row) {
|
| - return model()->IsItemSeparatorAt(row) ? base::string16() :
|
| - model()->GetItemAt(row);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// Combobox, View overrides:
|
| -
|
| -gfx::Size Combobox::GetPreferredSize() const {
|
| - // The preferred size will drive the local bounds which in turn is used to set
|
| - // the minimum width for the dropdown list.
|
| - gfx::Insets insets = GetInsets();
|
| - insets += gfx::Insets(Textfield::kTextPadding,
|
| - Textfield::kTextPadding,
|
| - Textfield::kTextPadding,
|
| - Textfield::kTextPadding);
|
| - int total_width = std::max(kMinComboboxWidth, content_size_.width()) +
|
| - insets.width() + GetDisclosureArrowLeftPadding() +
|
| - ArrowSize().width() + GetDisclosureArrowRightPadding();
|
| - return gfx::Size(total_width, content_size_.height() + insets.height());
|
| -}
|
| -
|
| -const char* Combobox::GetClassName() const {
|
| - return kViewClassName;
|
| -}
|
| -
|
| -bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
|
| - // Escape should close the drop down list when it is active, not host UI.
|
| - if (e.key_code() != ui::VKEY_ESCAPE ||
|
| - e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) {
|
| - return false;
|
| - }
|
| - return dropdown_open_;
|
| -}
|
| -
|
| -bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
|
| - // TODO(oshima): handle IME.
|
| - DCHECK_EQ(e.type(), ui::ET_KEY_PRESSED);
|
| -
|
| - DCHECK_GE(selected_index_, 0);
|
| - DCHECK_LT(selected_index_, model()->GetItemCount());
|
| - if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
|
| - selected_index_ = 0;
|
| -
|
| - bool show_menu = false;
|
| - int new_index = kNoSelection;
|
| - switch (e.key_code()) {
|
| - // Show the menu on F4 without modifiers.
|
| - case ui::VKEY_F4:
|
| - if (e.IsAltDown() || e.IsAltGrDown() || e.IsControlDown())
|
| - return false;
|
| - show_menu = true;
|
| - break;
|
| -
|
| - // Move to the next item if any, or show the menu on Alt+Down like Windows.
|
| - case ui::VKEY_DOWN:
|
| - if (e.IsAltDown())
|
| - show_menu = true;
|
| - else
|
| - new_index = GetAdjacentIndex(model(), 1, selected_index_);
|
| - break;
|
| -
|
| - // Move to the end of the list.
|
| - case ui::VKEY_END:
|
| - case ui::VKEY_NEXT: // Page down.
|
| - new_index = GetAdjacentIndex(model(), -1, model()->GetItemCount());
|
| - break;
|
| -
|
| - // Move to the beginning of the list.
|
| - case ui::VKEY_HOME:
|
| - case ui::VKEY_PRIOR: // Page up.
|
| - new_index = GetAdjacentIndex(model(), 1, -1);
|
| - break;
|
| -
|
| - // Move to the previous item if any.
|
| - case ui::VKEY_UP:
|
| - new_index = GetAdjacentIndex(model(), -1, selected_index_);
|
| - break;
|
| -
|
| - // Click the button only when the button style mode.
|
| - case ui::VKEY_SPACE:
|
| - if (style_ == STYLE_ACTION) {
|
| - // When pressing space, the click event will be raised after the key is
|
| - // released.
|
| - text_button_->SetState(Button::STATE_PRESSED);
|
| - } else {
|
| - return false;
|
| - }
|
| - break;
|
| -
|
| - // Click the button only when the button style mode.
|
| - case ui::VKEY_RETURN:
|
| - if (style_ != STYLE_ACTION)
|
| - return false;
|
| - OnPerformAction();
|
| - break;
|
| -
|
| - default:
|
| - return false;
|
| - }
|
| -
|
| - if (show_menu) {
|
| - UpdateFromModel();
|
| - ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD);
|
| - } else if (new_index != selected_index_ && new_index != kNoSelection &&
|
| - style_ != STYLE_ACTION) {
|
| - DCHECK(!model()->IsItemSeparatorAt(new_index));
|
| - selected_index_ = new_index;
|
| - OnPerformAction();
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
|
| - if (style_ != STYLE_ACTION)
|
| - return false; // crbug.com/127520
|
| -
|
| - if (e.key_code() == ui::VKEY_SPACE && style_ == STYLE_ACTION)
|
| - OnPerformAction();
|
| -
|
| - return false;
|
| -}
|
| -
|
| -void Combobox::OnPaint(gfx::Canvas* canvas) {
|
| - switch (style_) {
|
| - case STYLE_NORMAL: {
|
| - OnPaintBackground(canvas);
|
| - PaintText(canvas);
|
| - OnPaintBorder(canvas);
|
| - break;
|
| - }
|
| - case STYLE_ACTION: {
|
| - PaintButtons(canvas);
|
| - PaintText(canvas);
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void Combobox::OnFocus() {
|
| - GetInputMethod()->OnFocus();
|
| - View::OnFocus();
|
| - // Border renders differently when focused.
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void Combobox::OnBlur() {
|
| - GetInputMethod()->OnBlur();
|
| - if (selector_)
|
| - selector_->OnViewBlur();
|
| - // Border renders differently when focused.
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void Combobox::GetAccessibleState(ui::AXViewState* state) {
|
| - state->role = ui::AX_ROLE_COMBO_BOX;
|
| - state->name = accessible_name_;
|
| - state->value = model_->GetItemAt(selected_index_);
|
| - state->index = selected_index_;
|
| - state->count = model_->GetItemCount();
|
| -}
|
| -
|
| -void Combobox::OnComboboxModelChanged(ui::ComboboxModel* model) {
|
| - DCHECK_EQ(model, model_);
|
| - ModelChanged();
|
| -}
|
| -
|
| -void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
|
| - if (!enabled())
|
| - return;
|
| -
|
| - RequestFocus();
|
| -
|
| - if (sender == text_button_) {
|
| - OnPerformAction();
|
| - } else {
|
| - DCHECK_EQ(arrow_button_, sender);
|
| - // TODO(hajimehoshi): Fix the problem that the arrow button blinks when
|
| - // cliking this while the dropdown menu is opened.
|
| - const base::TimeDelta delta = base::Time::Now() - closed_time_;
|
| - if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
|
| - 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);
|
| - }
|
| -}
|
| -
|
| -void Combobox::UpdateFromModel() {
|
| - const gfx::FontList& font_list = Combobox::GetFontList();
|
| -
|
| - menu_ = new MenuItemView(this);
|
| - // MenuRunner owns |menu_|.
|
| - dropdown_list_menu_runner_.reset(new MenuRunner(menu_, MenuRunner::COMBOBOX));
|
| -
|
| - int num_items = model()->GetItemCount();
|
| - int width = 0;
|
| - bool text_item_appended = false;
|
| - for (int i = 0; i < num_items; ++i) {
|
| - // When STYLE_ACTION is used, the first item and the following separators
|
| - // are not added to the dropdown menu. It is assumed that the first item is
|
| - // always selected and rendered on the top of the action button.
|
| - if (model()->IsItemSeparatorAt(i)) {
|
| - if (text_item_appended || style_ != STYLE_ACTION)
|
| - menu_->AppendSeparator();
|
| - continue;
|
| - }
|
| -
|
| - base::string16 text = model()->GetItemAt(i);
|
| -
|
| - // Inserting the Unicode formatting characters if necessary so that the
|
| - // text is displayed correctly in right-to-left UIs.
|
| - base::i18n::AdjustStringForLocaleDirection(&text);
|
| -
|
| - if (style_ != STYLE_ACTION || i > 0) {
|
| - menu_->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
|
| - text_item_appended = true;
|
| - }
|
| -
|
| - if (style_ != STYLE_ACTION || i == selected_index_)
|
| - width = std::max(width, gfx::GetStringWidth(text, font_list));
|
| - }
|
| -
|
| - content_size_.SetSize(width, font_list.GetHeight());
|
| -}
|
| -
|
| -void Combobox::UpdateBorder() {
|
| - scoped_ptr<FocusableBorder> border(new FocusableBorder());
|
| - if (style_ == STYLE_ACTION)
|
| - border->SetInsets(5, 10, 5, 10);
|
| - if (invalid_)
|
| - border->SetColor(kWarningColor);
|
| - SetBorder(border.Pass());
|
| -}
|
| -
|
| -void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const {
|
| - rect->set_x(GetMirroredXForRect(*rect));
|
| -}
|
| -
|
| -void Combobox::PaintText(gfx::Canvas* canvas) {
|
| - gfx::Insets insets = GetInsets();
|
| - insets += gfx::Insets(0, Textfield::kTextPadding, 0, Textfield::kTextPadding);
|
| -
|
| - gfx::ScopedCanvas scoped_canvas(canvas);
|
| - canvas->ClipRect(GetContentsBounds());
|
| -
|
| - int x = insets.left();
|
| - int y = insets.top();
|
| - int text_height = height() - insets.height();
|
| - SkColor text_color = GetNativeTheme()->GetSystemColor(
|
| - ui::NativeTheme::kColorId_LabelEnabledColor);
|
| -
|
| - DCHECK_GE(selected_index_, 0);
|
| - DCHECK_LT(selected_index_, model()->GetItemCount());
|
| - if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
|
| - selected_index_ = 0;
|
| - base::string16 text = model()->GetItemAt(selected_index_);
|
| -
|
| - gfx::Size arrow_size = ArrowSize();
|
| - int disclosure_arrow_offset = width() - arrow_size.width() -
|
| - GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding();
|
| -
|
| - const gfx::FontList& font_list = Combobox::GetFontList();
|
| - int text_width = gfx::GetStringWidth(text, font_list);
|
| - if ((text_width + insets.width()) > disclosure_arrow_offset)
|
| - text_width = disclosure_arrow_offset - insets.width();
|
| -
|
| - gfx::Rect text_bounds(x, y, text_width, text_height);
|
| - AdjustBoundsForRTLUI(&text_bounds);
|
| - canvas->DrawStringRect(text, font_list, text_color, text_bounds);
|
| -
|
| - int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding();
|
| - gfx::Rect arrow_bounds(arrow_x,
|
| - height() / 2 - arrow_size.height() / 2,
|
| - arrow_size.width(),
|
| - arrow_size.height());
|
| - AdjustBoundsForRTLUI(&arrow_bounds);
|
| -
|
| - // TODO(estade): hack alert! Remove this direct call into CommonTheme. For now
|
| - // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
|
| - // behavior. See crbug.com/384071
|
| - if (style_ == STYLE_ACTION) {
|
| - ui::CommonThemePaintComboboxArrow(canvas->sk_canvas(), arrow_bounds);
|
| - } else {
|
| - ui::NativeTheme::ExtraParams ignored;
|
| - GetNativeTheme()->Paint(canvas->sk_canvas(),
|
| - ui::NativeTheme::kComboboxArrow,
|
| - ui::NativeTheme::kNormal,
|
| - arrow_bounds,
|
| - ignored);
|
| - }
|
| -}
|
| -
|
| -void Combobox::PaintButtons(gfx::Canvas* canvas) {
|
| - DCHECK(style_ == STYLE_ACTION);
|
| -
|
| - gfx::ScopedCanvas scoped_canvas(canvas);
|
| - if (base::i18n::IsRTL()) {
|
| - canvas->Translate(gfx::Vector2d(width(), 0));
|
| - canvas->Scale(-1, 1);
|
| - }
|
| -
|
| - bool focused = HasFocus();
|
| - const std::vector<const gfx::ImageSkia*>& arrow_button_images =
|
| - menu_button_images_[focused][
|
| - arrow_button_->state() == Button::STATE_HOVERED ?
|
| - Button::STATE_NORMAL : arrow_button_->state()];
|
| -
|
| - int text_button_hover_alpha =
|
| - text_button_->state() == Button::STATE_PRESSED ? 0 :
|
| - static_cast<int>(static_cast<TransparentButton*>(text_button_)->
|
| - GetAnimationValue() * 255);
|
| - if (text_button_hover_alpha < 255) {
|
| - canvas->SaveLayerAlpha(255 - text_button_hover_alpha);
|
| - Painter* text_button_painter =
|
| - body_button_painters_[focused][
|
| - text_button_->state() == Button::STATE_HOVERED ?
|
| - Button::STATE_NORMAL : text_button_->state()].get();
|
| - Painter::PaintPainterAt(canvas, text_button_painter,
|
| - gfx::Rect(0, 0, text_button_->width(), height()));
|
| - canvas->Restore();
|
| - }
|
| - if (0 < text_button_hover_alpha) {
|
| - canvas->SaveLayerAlpha(text_button_hover_alpha);
|
| - Painter* text_button_hovered_painter =
|
| - body_button_painters_[focused][Button::STATE_HOVERED].get();
|
| - Painter::PaintPainterAt(canvas, text_button_hovered_painter,
|
| - gfx::Rect(0, 0, text_button_->width(), height()));
|
| - canvas->Restore();
|
| - }
|
| -
|
| - int arrow_button_hover_alpha =
|
| - arrow_button_->state() == Button::STATE_PRESSED ? 0 :
|
| - static_cast<int>(static_cast<TransparentButton*>(arrow_button_)->
|
| - GetAnimationValue() * 255);
|
| - if (arrow_button_hover_alpha < 255) {
|
| - canvas->SaveLayerAlpha(255 - arrow_button_hover_alpha);
|
| - PaintArrowButton(canvas, arrow_button_images, arrow_button_->x(), height());
|
| - canvas->Restore();
|
| - }
|
| - if (0 < arrow_button_hover_alpha) {
|
| - canvas->SaveLayerAlpha(arrow_button_hover_alpha);
|
| - const std::vector<const gfx::ImageSkia*>& arrow_button_hovered_images =
|
| - menu_button_images_[focused][Button::STATE_HOVERED];
|
| - PaintArrowButton(canvas, arrow_button_hovered_images,
|
| - arrow_button_->x(), height());
|
| - canvas->Restore();
|
| - }
|
| -}
|
| -
|
| -void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
|
| - if (!dropdown_list_menu_runner_.get())
|
| - UpdateFromModel();
|
| -
|
| - // Extend the menu to the width of the combobox.
|
| - SubmenuView* submenu = menu_->CreateSubmenu();
|
| - submenu->set_minimum_preferred_width(
|
| - size().width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
|
| -
|
| - gfx::Rect lb = GetLocalBounds();
|
| - gfx::Point menu_position(lb.origin());
|
| -
|
| - if (style_ == STYLE_NORMAL) {
|
| - // 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);
|
| - if (menu_position.x() < 0)
|
| - menu_position.set_x(0);
|
| -
|
| - gfx::Rect bounds(menu_position, lb.size());
|
| -
|
| - Button::ButtonState original_state = Button::STATE_NORMAL;
|
| - if (arrow_button_) {
|
| - original_state = arrow_button_->state();
|
| - arrow_button_->SetState(Button::STATE_PRESSED);
|
| - }
|
| - dropdown_open_ = true;
|
| - MenuAnchorPosition anchor_position =
|
| - style_ == STYLE_ACTION ? MENU_ANCHOR_TOPRIGHT : MENU_ANCHOR_TOPLEFT;
|
| - if (dropdown_list_menu_runner_->RunMenuAt(
|
| - GetWidget(), NULL, bounds, anchor_position, source_type) ==
|
| - MenuRunner::MENU_DELETED) {
|
| - return;
|
| - }
|
| - dropdown_open_ = false;
|
| - if (arrow_button_)
|
| - arrow_button_->SetState(original_state);
|
| - closed_time_ = base::Time::Now();
|
| -
|
| - // Need to explicitly clear mouse handler so that events get sent
|
| - // properly after the menu finishes running. If we don't do this, then
|
| - // the first click to other parts of the UI is eaten.
|
| - SetMouseHandler(NULL);
|
| -}
|
| -
|
| -void Combobox::OnPerformAction() {
|
| - NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, false);
|
| - SchedulePaint();
|
| -
|
| - // This combobox may be deleted by the listener.
|
| - base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
|
| - if (listener_)
|
| - listener_->OnPerformAction(this);
|
| -
|
| - if (weak_ptr && style_ == STYLE_ACTION)
|
| - selected_index_ = 0;
|
| -}
|
| -
|
| -int Combobox::MenuCommandToIndex(int menu_command_id) const {
|
| - // (note that the id received is offset by kFirstMenuItemId)
|
| - // Revert menu ID offset to map back to combobox model.
|
| - int index = menu_command_id - kFirstMenuItemId;
|
| - DCHECK_LT(index, model()->GetItemCount());
|
| - return index;
|
| -}
|
| -
|
| -int Combobox::GetDisclosureArrowLeftPadding() const {
|
| - switch (style_) {
|
| - case STYLE_NORMAL:
|
| - return kDisclosureArrowLeftPadding;
|
| - case STYLE_ACTION:
|
| - return kDisclosureArrowButtonLeftPadding;
|
| - }
|
| - NOTREACHED();
|
| - return 0;
|
| -}
|
| -
|
| -int Combobox::GetDisclosureArrowRightPadding() const {
|
| - switch (style_) {
|
| - case STYLE_NORMAL:
|
| - return kDisclosureArrowRightPadding;
|
| - case STYLE_ACTION:
|
| - return kDisclosureArrowButtonRightPadding;
|
| - }
|
| - NOTREACHED();
|
| - return 0;
|
| -}
|
| -
|
| -gfx::Size Combobox::ArrowSize() const {
|
| -#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
|
| - // TODO(estade): hack alert! This should always use GetNativeTheme(). For now
|
| - // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
|
| - // behavior. See crbug.com/384071
|
| - const ui::NativeTheme* native_theme_for_arrow = style_ == STYLE_ACTION ?
|
| - ui::NativeTheme::instance() :
|
| - GetNativeTheme();
|
| -#else
|
| - const ui::NativeTheme* native_theme_for_arrow = GetNativeTheme();
|
| -#endif
|
| -
|
| - ui::NativeTheme::ExtraParams ignored;
|
| - return native_theme_for_arrow->GetPartSize(ui::NativeTheme::kComboboxArrow,
|
| - ui::NativeTheme::kNormal,
|
| - ignored);
|
| -}
|
| -
|
| -} // namespace views
|
|
|