15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/combobox/combobox.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/accessibility/ax_view_state.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/combobox_model.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h"
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/keycodes/keyboard_codes.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/animation/throb_animation.h"
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/canvas.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/image/image.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/gfx/scoped_canvas.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/text_utils.h"
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/native_theme/common_theme.h"
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/background.h"
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/views/color_constants.h"
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/custom_button.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/button/label_button.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/combobox/combobox_listener.h"
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/views/controls/focusable_border.h"
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/views/controls/menu/menu_item_view.h"
31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/views/controls/menu/menu_runner.h"
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/controls/menu/menu_runner_handler.h"
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/views/controls/menu/submenu_view.h"
34fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "ui/views/controls/prefix_selector.h"
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/views/controls/textfield/textfield.h"
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/ime/input_method.h"
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/views/mouse_constants.h"
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/painter.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace {
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Menu border widths
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kMenuBorderWidthLeft = 1;
47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kMenuBorderWidthTop = 1;
48d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kMenuBorderWidthRight = 1;
49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Limit how small a combobox can be.
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kMinComboboxWidth = 25;
52d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Size of the combobox arrow margins
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kDisclosureArrowLeftPadding = 7;
55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kDisclosureArrowRightPadding = 7;
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kDisclosureArrowButtonLeftPadding = 11;
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kDisclosureArrowButtonRightPadding = 12;
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Define the id of the first item in the menu (since it needs to be > 0)
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kFirstMenuItemId = 1000;
61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Used to indicate that no item is currently selected by the user.
63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int kNoSelection = -1;
64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON);
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedHoveredBodyButtonImages[] =
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedPressedBodyButtonImages[] =
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#define MENU_IMAGE_GRID(x) { \
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    x ## _MENU_TOP, x ## _MENU_CENTER, x ## _MENU_BOTTOM, }
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON);
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kHoveredMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_H);
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kPressedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_P);
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedHoveredMenuButtonImages[] =
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_H);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kFocusedPressedMenuButtonImages[] =
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_F_P);
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#undef MENU_IMAGE_GRID
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The transparent button which holds a button state but is not rendered.
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class TransparentButton : public CustomButton {
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  TransparentButton(ButtonListener* listener)
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : CustomButton(listener) {
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SetAnimationDuration(LabelButton::kHoverAnimationDurationMs);
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual ~TransparentButton() {}
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual bool OnMousePressed(const ui::MouseEvent& mouse_event) OVERRIDE {
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    parent()->RequestFocus();
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  double GetAnimationValue() const {
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return hover_animation_->GetCurrentValue();
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TransparentButton);
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Returns the next or previous valid index (depending on |increment|'s value).
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Skips separator or disabled indices. Returns -1 if there is no valid adjacent
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// index.
113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)int GetAdjacentIndex(ui::ComboboxModel* model, int increment, int index) {
114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(increment == -1 || increment == 1);
115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  index += increment;
117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  while (index >= 0 && index < model->GetItemCount()) {
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!model->IsItemSeparatorAt(index) || !model->IsItemEnabledAt(index))
119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return index;
120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    index += increment;
121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return kNoSelection;
123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the image resource ids of an array for the body button.
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)//
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(hajimehoshi): This function should return the images for the 'disabled'
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// status. (crbug/270052)
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int* GetBodyButtonImageIds(bool focused,
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 Button::ButtonState state,
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 size_t* num) {
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(num);
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  *num = 9;
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (state) {
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_DISABLED:
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_NORMAL:
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ? kFocusedBodyButtonImages : kBodyButtonImages;
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_HOVERED:
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ?
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kFocusedHoveredBodyButtonImages : kHoveredBodyButtonImages;
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_PRESSED:
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ?
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kFocusedPressedBodyButtonImages : kPressedBodyButtonImages;
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    default:
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NOTREACHED();
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return NULL;
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the image resource ids of an array for the menu button.
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int* GetMenuButtonImageIds(bool focused,
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 Button::ButtonState state,
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 size_t* num) {
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(num);
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  *num = 3;
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (state) {
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_DISABLED:
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_NORMAL:
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ? kFocusedMenuButtonImages : kMenuButtonImages;
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_HOVERED:
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ?
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kFocusedHoveredMenuButtonImages : kHoveredMenuButtonImages;
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case Button::STATE_PRESSED:
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return focused ?
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kFocusedPressedMenuButtonImages : kPressedMenuButtonImages;
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    default:
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NOTREACHED();
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return NULL;
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the images for the menu buttons.
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)std::vector<const gfx::ImageSkia*> GetMenuButtonImages(
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool focused,
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Button::ButtonState state) {
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const int* ids;
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  size_t num_ids;
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ids = GetMenuButtonImageIds(focused, state, &num_ids);
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<const gfx::ImageSkia*> images;
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  images.reserve(num_ids);
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (size_t i = 0; i < num_ids; i++)
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    images.push_back(rb.GetImageSkiaNamed(ids[i]));
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return images;
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Paints three images in a column at the given location. The center image is
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// stretched so as to fit the given height.
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void PaintImagesVertically(gfx::Canvas* canvas,
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           const gfx::ImageSkia& top_image,
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           const gfx::ImageSkia& center_image,
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           const gfx::ImageSkia& bottom_image,
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           int x, int y, int width, int height) {
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  canvas->DrawImageInt(top_image,
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       0, 0, top_image.width(), top_image.height(),
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       x, y, width, top_image.height(), false);
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  y += top_image.height();
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int center_height = height - top_image.height() - bottom_image.height();
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  canvas->DrawImageInt(center_image,
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       0, 0, center_image.width(), center_image.height(),
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       x, y, width, center_height, false);
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  y += center_height;
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  canvas->DrawImageInt(bottom_image,
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       0, 0, bottom_image.width(), bottom_image.height(),
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       x, y, width, bottom_image.height(), false);
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Paints the arrow button.
211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void PaintArrowButton(
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    gfx::Canvas* canvas,
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const std::vector<const gfx::ImageSkia*>& arrow_button_images,
214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int x, int height) {
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PaintImagesVertically(canvas,
216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        *arrow_button_images[0],
217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        *arrow_button_images[1],
218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        *arrow_button_images[2],
219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        x, 0, arrow_button_images[0]->width(), height);
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace
223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const char Combobox::kViewClassName[] = "views/Combobox";
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Combobox, public:
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Combobox::Combobox(ui::ComboboxModel* model)
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    : model_(model),
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      style_(STYLE_NORMAL),
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listener_(NULL),
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      selected_index_(model_->GetDefaultIndex()),
235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      invalid_(false),
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      menu_(NULL),
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      dropdown_open_(false),
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      text_button_(new TransparentButton(this)),
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      arrow_button_(new TransparentButton(this)),
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  model_->AddObserver(this);
242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  UpdateFromModel();
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetFocusable(true);
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateBorder();
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Initialize the button images.
247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Button::ButtonState button_states[] = {
248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Button::STATE_DISABLED,
249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Button::STATE_NORMAL,
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Button::STATE_HOVERED,
251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Button::STATE_PRESSED,
252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (int i = 0; i < 2; i++) {
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for (size_t state_index = 0; state_index < arraysize(button_states);
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)         state_index++) {
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      Button::ButtonState state = button_states[state_index];
257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      size_t num;
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool focused = !!i;
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const int* ids = GetBodyButtonImageIds(focused, state, &num);
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      body_button_painters_[focused][state].reset(
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          Painter::CreateImageGridPainter(ids));
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      menu_button_images_[focused][state] = GetMenuButtonImages(focused, state);
263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  text_button_->SetVisible(true);
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  arrow_button_->SetVisible(true);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  text_button_->SetFocusable(false);
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  arrow_button_->SetFocusable(false);
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AddChildView(text_button_);
271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AddChildView(arrow_button_);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Combobox::~Combobox() {
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  model_->RemoveObserver(this);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const gfx::FontList& Combobox::GetFontList() {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return rb.GetFontList(ui::ResourceBundle::BaseFont);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Combobox::SetStyle(Style style) {
285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (style_ == style)
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  style_ = style;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ == STYLE_ACTION)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    selected_index_ = 0;
291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateBorder();
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UpdateFromModel();
294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PreferredSizeChanged();
295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Combobox::ModelChanged() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_index_ = std::min(0, model_->GetItemCount());
299d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  UpdateFromModel();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreferredSizeChanged();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Combobox::SetSelectedIndex(int index) {
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ == STYLE_ACTION)
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_index_ = index;
308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SchedulePaint();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool Combobox::SelectValue(const base::string16& value) {
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ == STYLE_ACTION)
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (int i = 0; i < model()->GetItemCount(); ++i) {
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (value == model()->GetItemAt(i)) {
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      SetSelectedIndex(i);
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Combobox::SetAccessibleName(const base::string16& name) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  accessible_name_ = name;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Combobox::SetInvalid(bool invalid) {
329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (invalid == invalid_)
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  invalid_ = invalid;
333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  UpdateBorder();
335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SchedulePaint();
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
338fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochui::TextInputClient* Combobox::GetTextInputClient() {
339fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  if (!selector_)
340fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    selector_.reset(new PrefixSelector(this));
341fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  return selector_.get();
342fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
343fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Combobox::Layout() {
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PrefixDelegate::Layout();
346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::Insets insets = GetInsets();
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int text_button_width = 0;
349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int arrow_button_width = 0;
350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (style_) {
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_NORMAL: {
353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      arrow_button_width = width();
354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_ACTION: {
357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      arrow_button_width = GetDisclosureArrowLeftPadding() +
3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          ArrowSize().width() +
359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GetDisclosureArrowRightPadding();
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      text_button_width = width() - arrow_button_width;
361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int arrow_button_x = std::max(0, text_button_width);
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  text_button_->SetBounds(0, 0, std::max(0, text_button_width), height());
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height());
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool Combobox::IsItemChecked(int id) const {
371d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return false;
372d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
373d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
374d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool Combobox::IsCommandEnabled(int id) const {
3754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return model()->IsItemEnabledAt(MenuCommandToIndex(id));
376d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
377d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
378d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::ExecuteCommand(int id) {
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  selected_index_ = MenuCommandToIndex(id);
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OnPerformAction();
381d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
382d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool Combobox::GetAccelerator(int id, ui::Accelerator* accel) const {
384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return false;
385d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
386d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
387fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochint Combobox::GetRowCount() {
388fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  return model()->GetItemCount();
389fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
390fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
391fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochint Combobox::GetSelectedRow() {
392fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  return selected_index_;
393fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
394fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
395fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid Combobox::SetSelectedRow(int row) {
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int prev_index = selected_index_;
397fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  SetSelectedIndex(row);
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (selected_index_ != prev_index)
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OnPerformAction();
400fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
401fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 Combobox::GetTextForRow(int row) {
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return model()->IsItemSeparatorAt(row) ? base::string16() :
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           model()->GetItemAt(row);
405fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch}
406fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Combobox, View overrides:
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size Combobox::GetPreferredSize() const {
411d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The preferred size will drive the local bounds which in turn is used to set
412d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the minimum width for the dropdown list.
413d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Insets insets = GetInsets();
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  insets += gfx::Insets(Textfield::kTextPadding,
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        Textfield::kTextPadding,
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        Textfield::kTextPadding,
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        Textfield::kTextPadding);
418d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int total_width = std::max(kMinComboboxWidth, content_size_.width()) +
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      insets.width() + GetDisclosureArrowLeftPadding() +
4206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      ArrowSize().width() + GetDisclosureArrowRightPadding();
421d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return gfx::Size(total_width, content_size_.height() + insets.height());
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
424d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const char* Combobox::GetClassName() const {
425d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return kViewClassName;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Escape should close the drop down list when it is active, not host UI.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (e.key_code() != ui::VKEY_ESCAPE ||
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return dropdown_open_;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
438d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // TODO(oshima): handle IME.
439d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_EQ(e.type(), ui::ET_KEY_PRESSED);
440d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
441d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GE(selected_index_, 0);
442d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_LT(selected_index_, model()->GetItemCount());
443d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
444d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    selected_index_ = 0;
445d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
446d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool show_menu = false;
447d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int new_index = kNoSelection;
448d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  switch (e.key_code()) {
4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Show the menu on F4 without modifiers.
4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case ui::VKEY_F4:
4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (e.IsAltDown() || e.IsAltGrDown() || e.IsControlDown())
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return false;
453d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      show_menu = true;
454d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
455d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Move to the next item if any, or show the menu on Alt+Down like Windows.
457d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_DOWN:
458d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (e.IsAltDown())
459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        show_menu = true;
460d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      else
461d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        new_index = GetAdjacentIndex(model(), 1, selected_index_);
462d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
463d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
464d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Move to the end of the list.
465d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_END:
466d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_NEXT:  // Page down.
467d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      new_index = GetAdjacentIndex(model(), -1, model()->GetItemCount());
468d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Move to the beginning of the list.
471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_HOME:
472d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_PRIOR:  // Page up.
473d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      new_index = GetAdjacentIndex(model(), 1, -1);
474d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
476d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Move to the previous item if any.
477d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    case ui::VKEY_UP:
478d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      new_index = GetAdjacentIndex(model(), -1, selected_index_);
479d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      break;
480d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Click the button only when the button style mode.
482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case ui::VKEY_SPACE:
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (style_ == STYLE_ACTION) {
484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // When pressing space, the click event will be raised after the key is
485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // released.
486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        text_button_->SetState(Button::STATE_PRESSED);
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Click the button only when the button style mode.
493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case ui::VKEY_RETURN:
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (style_ != STYLE_ACTION)
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      OnPerformAction();
497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
499d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    default:
500d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      return false;
501d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
502d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
503d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (show_menu) {
504d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    UpdateFromModel();
505d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD);
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (new_index != selected_index_ && new_index != kNoSelection &&
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             style_ != STYLE_ACTION) {
508d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK(!model()->IsItemSeparatorAt(new_index));
509d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    selected_index_ = new_index;
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnPerformAction();
511d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
512d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
513d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return true;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ != STYLE_ACTION)
518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return false;  // crbug.com/127520
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (e.key_code() == ui::VKEY_SPACE && style_ == STYLE_ACTION)
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnPerformAction();
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return false;
524d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
525d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
526d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::OnPaint(gfx::Canvas* canvas) {
527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (style_) {
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_NORMAL: {
529a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      OnPaintBackground(canvas);
530a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      PaintText(canvas);
531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      OnPaintBorder(canvas);
532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_ACTION: {
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      PaintButtons(canvas);
536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      PaintText(canvas);
537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Combobox::OnFocus() {
54358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetInputMethod()->OnFocus();
544d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  View::OnFocus();
545a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Border renders differently when focused.
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SchedulePaint();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Combobox::OnBlur() {
55058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetInputMethod()->OnBlur();
551fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  if (selector_)
552fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch    selector_->OnViewBlur();
553a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Border renders differently when focused.
554a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SchedulePaint();
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
557a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Combobox::GetAccessibleState(ui::AXViewState* state) {
558a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state->role = ui::AX_ROLE_COMBO_BOX;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->name = accessible_name_;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->value = model_->GetItemAt(selected_index_);
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->index = selected_index_;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->count = model_->GetItemCount();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Combobox::OnComboboxModelChanged(ui::ComboboxModel* model) {
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(model, model_);
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ModelChanged();
5684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
570a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Combobox::ButtonPressed(Button* sender, const ui::Event& event) {
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!enabled())
572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
573a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
574a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RequestFocus();
575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (sender == text_button_) {
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnPerformAction();
578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else {
579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DCHECK_EQ(arrow_button_, sender);
580a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // TODO(hajimehoshi): Fix the problem that the arrow button blinks when
581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // cliking this while the dropdown menu is opened.
582a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::TimeDelta delta = base::Time::Now() - closed_time_;
583a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
584a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
586a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE;
587a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (event.IsKeyEvent())
588a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      source_type = ui::MENU_SOURCE_KEYBOARD;
589a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else if (event.IsGestureEvent() || event.IsTouchEvent())
590a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      source_type = ui::MENU_SOURCE_TOUCH;
591a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ShowDropDownMenu(source_type);
592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
593a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
594a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
595d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::UpdateFromModel() {
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::FontList& font_list = Combobox::GetFontList();
597d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
598116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  menu_ = new MenuItemView(this);
599116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // MenuRunner owns |menu_|.
600116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  dropdown_list_menu_runner_.reset(new MenuRunner(menu_, MenuRunner::COMBOBOX));
601d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
602d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int num_items = model()->GetItemCount();
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int width = 0;
604a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool text_item_appended = false;
605d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  for (int i = 0; i < num_items; ++i) {
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // When STYLE_ACTION is used, the first item and the following separators
607a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // are not added to the dropdown menu. It is assumed that the first item is
608a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // always selected and rendered on the top of the action button.
609d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (model()->IsItemSeparatorAt(i)) {
610a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (text_item_appended || style_ != STYLE_ACTION)
611116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        menu_->AppendSeparator();
612d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      continue;
613d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
614d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 text = model()->GetItemAt(i);
616d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
617d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Inserting the Unicode formatting characters if necessary so that the
618d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // text is displayed correctly in right-to-left UIs.
619d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    base::i18n::AdjustStringForLocaleDirection(&text);
620d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (style_ != STYLE_ACTION || i > 0) {
622116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      menu_->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL);
623a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      text_item_appended = true;
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (style_ != STYLE_ACTION || i == selected_index_)
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      width = std::max(width, gfx::GetStringWidth(text, font_list));
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
629d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content_size_.SetSize(width, font_list.GetHeight());
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
633a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Combobox::UpdateBorder() {
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<FocusableBorder> border(new FocusableBorder());
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ == STYLE_ACTION)
6361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    border->SetInsets(5, 10, 5, 10);
637a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (invalid_)
638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    border->SetColor(kWarningColor);
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetBorder(border.PassAs<Border>());
640a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
642d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const {
643d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  rect->set_x(GetMirroredXForRect(*rect));
644d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
645d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
646d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::PaintText(gfx::Canvas* canvas) {
647d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Insets insets = GetInsets();
6481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  insets += gfx::Insets(0, Textfield::kTextPadding, 0, Textfield::kTextPadding);
649d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
650a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::ScopedCanvas scoped_canvas(canvas);
651d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  canvas->ClipRect(GetContentsBounds());
652d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
653d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int x = insets.left();
654d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int y = insets.top();
655d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int text_height = height() - insets.height();
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkColor text_color = GetNativeTheme()->GetSystemColor(
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::NativeTheme::kColorId_LabelEnabledColor);
658d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
659d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GE(selected_index_, 0);
660d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_LT(selected_index_, model()->GetItemCount());
661d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (selected_index_ < 0 || selected_index_ > model()->GetItemCount())
662d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    selected_index_ = 0;
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 text = model()->GetItemAt(selected_index_);
664d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  gfx::Size arrow_size = ArrowSize();
666f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int disclosure_arrow_offset = width() - arrow_size.width() -
667a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding();
668d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const gfx::FontList& font_list = Combobox::GetFontList();
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int text_width = gfx::GetStringWidth(text, font_list);
671d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if ((text_width + insets.width()) > disclosure_arrow_offset)
672d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    text_width = disclosure_arrow_offset - insets.width();
673d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
674d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Rect text_bounds(x, y, text_width, text_height);
675d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AdjustBoundsForRTLUI(&text_bounds);
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  canvas->DrawStringRect(text, font_list, text_color, text_bounds);
677d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
678a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding();
679a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::Rect arrow_bounds(arrow_x,
680f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         height() / 2 - arrow_size.height() / 2,
681f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         arrow_size.width(),
682f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                         arrow_size.height());
683d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AdjustBoundsForRTLUI(&arrow_bounds);
684d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
685f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(estade): hack alert! Remove this direct call into CommonTheme. For now
686f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
687f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // behavior. See crbug.com/384071
688f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (style_ == STYLE_ACTION) {
689f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::CommonThemePaintComboboxArrow(canvas->sk_canvas(), arrow_bounds);
690f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
691f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ui::NativeTheme::ExtraParams ignored;
692f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    GetNativeTheme()->Paint(canvas->sk_canvas(),
693f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            ui::NativeTheme::kComboboxArrow,
694f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            ui::NativeTheme::kNormal,
695f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            arrow_bounds,
696f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            ignored);
697f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Combobox::PaintButtons(gfx::Canvas* canvas) {
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(style_ == STYLE_ACTION);
702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
703a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  gfx::ScopedCanvas scoped_canvas(canvas);
704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (base::i18n::IsRTL()) {
705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Translate(gfx::Vector2d(width(), 0));
706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Scale(-1, 1);
707a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
708a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
709a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool focused = HasFocus();
710a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const std::vector<const gfx::ImageSkia*>& arrow_button_images =
711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      menu_button_images_[focused][
712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          arrow_button_->state() == Button::STATE_HOVERED ?
713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          Button::STATE_NORMAL : arrow_button_->state()];
714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int text_button_hover_alpha =
716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      text_button_->state() == Button::STATE_PRESSED ? 0 :
717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      static_cast<int>(static_cast<TransparentButton*>(text_button_)->
718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       GetAnimationValue() * 255);
719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (text_button_hover_alpha < 255) {
720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->SaveLayerAlpha(255 - text_button_hover_alpha);
721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Painter* text_button_painter =
722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        body_button_painters_[focused][
723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            text_button_->state() == Button::STATE_HOVERED ?
724a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Button::STATE_NORMAL : text_button_->state()].get();
725a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Painter::PaintPainterAt(canvas, text_button_painter,
726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            gfx::Rect(0, 0, text_button_->width(), height()));
727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Restore();
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (0 < text_button_hover_alpha) {
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->SaveLayerAlpha(text_button_hover_alpha);
731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Painter* text_button_hovered_painter =
732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        body_button_painters_[focused][Button::STATE_HOVERED].get();
733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Painter::PaintPainterAt(canvas, text_button_hovered_painter,
734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            gfx::Rect(0, 0, text_button_->width(), height()));
735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Restore();
736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
737d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
738a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int arrow_button_hover_alpha =
739a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      arrow_button_->state() == Button::STATE_PRESSED ? 0 :
740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      static_cast<int>(static_cast<TransparentButton*>(arrow_button_)->
741a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       GetAnimationValue() * 255);
742a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (arrow_button_hover_alpha < 255) {
743a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->SaveLayerAlpha(255 - arrow_button_hover_alpha);
744a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    PaintArrowButton(canvas, arrow_button_images, arrow_button_->x(), height());
745a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Restore();
746a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
747a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (0 < arrow_button_hover_alpha) {
748a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->SaveLayerAlpha(arrow_button_hover_alpha);
749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const std::vector<const gfx::ImageSkia*>& arrow_button_hovered_images =
750a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        menu_button_images_[focused][Button::STATE_HOVERED];
751a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    PaintArrowButton(canvas, arrow_button_hovered_images,
752a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     arrow_button_->x(), height());
753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    canvas->Restore();
754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
755d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
756d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
757d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) {
758d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!dropdown_list_menu_runner_.get())
759d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    UpdateFromModel();
760d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
761d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Extend the menu to the width of the combobox.
762116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SubmenuView* submenu = menu_->CreateSubmenu();
763a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  submenu->set_minimum_preferred_width(
764a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      size().width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
765d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
766d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Rect lb = GetLocalBounds();
767d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Point menu_position(lb.origin());
768d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (style_ == STYLE_NORMAL) {
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Inset the menu's requested position so the border of the menu lines up
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // with the border of the combobox.
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft);
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    menu_position.set_y(menu_position.y() + kMenuBorderWidthTop);
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
775d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight));
776d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
777d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  View::ConvertPointToScreen(this, &menu_position);
778d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (menu_position.x() < 0)
779a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    menu_position.set_x(0);
780d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
781d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::Rect bounds(menu_position, lb.size());
782d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
783a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Button::ButtonState original_state = Button::STATE_NORMAL;
784a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (arrow_button_) {
785a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    original_state = arrow_button_->state();
786a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    arrow_button_->SetState(Button::STATE_PRESSED);
787a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
788d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dropdown_open_ = true;
7895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MenuAnchorPosition anchor_position =
7905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      style_ == STYLE_ACTION ? MENU_ANCHOR_TOPRIGHT : MENU_ANCHOR_TOPLEFT;
791116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (dropdown_list_menu_runner_->RunMenuAt(
792116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          GetWidget(), NULL, bounds, anchor_position, source_type) ==
793a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MenuRunner::MENU_DELETED) {
794d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
795a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
796d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dropdown_open_ = false;
797a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (arrow_button_)
798a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    arrow_button_->SetState(original_state);
799d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  closed_time_ = base::Time::Now();
800d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
801d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Need to explicitly clear mouse handler so that events get sent
802d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // properly after the menu finishes running. If we don't do this, then
803d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the first click to other parts of the UI is eaten.
804d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetMouseHandler(NULL);
805d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
806d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Combobox::OnPerformAction() {
808a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, false);
809d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SchedulePaint();
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This combobox may be deleted by the listener.
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::WeakPtr<Combobox> weak_ptr = weak_ptr_factory_.GetWeakPtr();
813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (listener_)
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    listener_->OnPerformAction(this);
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (weak_ptr && style_ == STYLE_ACTION)
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    selected_index_ = 0;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)int Combobox::MenuCommandToIndex(int menu_command_id) const {
8214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // (note that the id received is offset by kFirstMenuItemId)
8224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Revert menu ID offset to map back to combobox model.
8234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int index = menu_command_id - kFirstMenuItemId;
8244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_LT(index, model()->GetItemCount());
8254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return index;
8264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
8274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
828a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int Combobox::GetDisclosureArrowLeftPadding() const {
829a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (style_) {
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_NORMAL:
831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return kDisclosureArrowLeftPadding;
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_ACTION:
833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return kDisclosureArrowButtonLeftPadding;
834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  NOTREACHED();
836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return 0;
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
839a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int Combobox::GetDisclosureArrowRightPadding() const {
840a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  switch (style_) {
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_NORMAL:
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return kDisclosureArrowRightPadding;
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case STYLE_ACTION:
844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return kDisclosureArrowButtonRightPadding;
845a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  NOTREACHED();
847a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return 0;
848a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
849a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
8506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)gfx::Size Combobox::ArrowSize() const {
8516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
8526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // TODO(estade): hack alert! This should always use GetNativeTheme(). For now
8536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // STYLE_ACTION isn't properly themed so we have to override the NativeTheme
8546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // behavior. See crbug.com/384071
8556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const ui::NativeTheme* native_theme_for_arrow = style_ == STYLE_ACTION ?
8566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      ui::NativeTheme::instance() :
8576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      GetNativeTheme();
8586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#else
8596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const ui::NativeTheme* native_theme_for_arrow = GetNativeTheme();
8606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif
8616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
8626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ui::NativeTheme::ExtraParams ignored;
8636d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  return native_theme_for_arrow->GetPartSize(ui::NativeTheme::kComboboxArrow,
8646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                             ui::NativeTheme::kNormal,
8656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                             ignored);
8666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
8676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace views
869