OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/views/controls/combobox/combobox.h" | 5 #include "ui/views/controls/combobox/combobox.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
9 #include "grit/ui_resources.h" | 9 #include "grit/ui_resources.h" |
10 #include "ui/base/accessibility/accessible_view_state.h" | 10 #include "ui/base/accessibility/accessible_view_state.h" |
11 #include "ui/base/models/combobox_model.h" | 11 #include "ui/base/models/combobox_model.h" |
12 #include "ui/base/resource/resource_bundle.h" | 12 #include "ui/base/resource/resource_bundle.h" |
13 #include "ui/events/event.h" | 13 #include "ui/events/event.h" |
14 #include "ui/events/keycodes/keyboard_codes.h" | 14 #include "ui/events/keycodes/keyboard_codes.h" |
| 15 #include "ui/gfx/animation/throb_animation.h" |
15 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/image/image.h" |
| 18 #include "ui/gfx/scoped_canvas.h" |
16 #include "ui/native_theme/native_theme.h" | 19 #include "ui/native_theme/native_theme.h" |
17 #include "ui/views/background.h" | 20 #include "ui/views/background.h" |
18 #include "ui/views/color_constants.h" | 21 #include "ui/views/color_constants.h" |
| 22 #include "ui/views/controls/button/custom_button.h" |
| 23 #include "ui/views/controls/button/label_button.h" |
19 #include "ui/views/controls/combobox/combobox_listener.h" | 24 #include "ui/views/controls/combobox/combobox_listener.h" |
20 #include "ui/views/controls/focusable_border.h" | 25 #include "ui/views/controls/focusable_border.h" |
21 #include "ui/views/controls/menu/menu_runner.h" | 26 #include "ui/views/controls/menu/menu_runner.h" |
| 27 #include "ui/views/controls/menu/menu_runner_handler.h" |
22 #include "ui/views/controls/menu/submenu_view.h" | 28 #include "ui/views/controls/menu/submenu_view.h" |
23 #include "ui/views/controls/prefix_selector.h" | 29 #include "ui/views/controls/prefix_selector.h" |
24 #include "ui/views/ime/input_method.h" | 30 #include "ui/views/ime/input_method.h" |
25 #include "ui/views/mouse_constants.h" | 31 #include "ui/views/mouse_constants.h" |
| 32 #include "ui/views/painter.h" |
26 #include "ui/views/widget/widget.h" | 33 #include "ui/views/widget/widget.h" |
27 | 34 |
28 namespace views { | 35 namespace views { |
29 | 36 |
30 namespace { | 37 namespace { |
31 | 38 |
32 // Menu border widths | 39 // Menu border widths |
33 const int kMenuBorderWidthLeft = 1; | 40 const int kMenuBorderWidthLeft = 1; |
34 const int kMenuBorderWidthTop = 1; | 41 const int kMenuBorderWidthTop = 1; |
35 const int kMenuBorderWidthRight = 1; | 42 const int kMenuBorderWidthRight = 1; |
36 | 43 |
37 // Limit how small a combobox can be. | 44 // Limit how small a combobox can be. |
38 const int kMinComboboxWidth = 25; | 45 const int kMinComboboxWidth = 25; |
39 | 46 |
40 // Size of the combobox arrow margins | 47 // Size of the combobox arrow margins |
41 const int kDisclosureArrowLeftPadding = 7; | 48 const int kDisclosureArrowLeftPadding = 7; |
42 const int kDisclosureArrowRightPadding = 7; | 49 const int kDisclosureArrowRightPadding = 7; |
| 50 const int kDisclosureArrowButtonLeftPadding = 11; |
| 51 const int kDisclosureArrowButtonRightPadding = 12; |
43 | 52 |
44 // Define the id of the first item in the menu (since it needs to be > 0) | 53 // Define the id of the first item in the menu (since it needs to be > 0) |
45 const int kFirstMenuItemId = 1000; | 54 const int kFirstMenuItemId = 1000; |
46 | 55 |
47 const SkColor kInvalidTextColor = SK_ColorWHITE; | 56 const SkColor kInvalidTextColor = SK_ColorWHITE; |
48 | 57 |
49 // Used to indicate that no item is currently selected by the user. | 58 // Used to indicate that no item is currently selected by the user. |
50 const int kNoSelection = -1; | 59 const int kNoSelection = -1; |
51 | 60 |
| 61 const int kBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON); |
| 62 const int kHoveredBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_H); |
| 63 const int kPressedBodyButtonImages[] = IMAGE_GRID(IDR_COMBOBOX_BUTTON_P); |
| 64 |
| 65 #define MENU_IMAGE_GRID(x) { \ |
| 66 x ## _MENU_TOP, x ## _MENU_CENTER, x ## _MENU_BOTTOM, } |
| 67 |
| 68 const int kMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON); |
| 69 const int kHoveredMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_H); |
| 70 const int kPressedMenuButtonImages[] = MENU_IMAGE_GRID(IDR_COMBOBOX_BUTTON_P); |
| 71 |
| 72 #undef MENU_IMAGE_GRID |
| 73 |
52 // The background to use for invalid comboboxes. | 74 // The background to use for invalid comboboxes. |
53 class InvalidBackground : public Background { | 75 class InvalidBackground : public Background { |
54 public: | 76 public: |
55 InvalidBackground() {} | 77 InvalidBackground() {} |
56 virtual ~InvalidBackground() {} | 78 virtual ~InvalidBackground() {} |
57 | 79 |
58 // Overridden from Background: | 80 // Overridden from Background: |
59 virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE { | 81 virtual void Paint(gfx::Canvas* canvas, View* view) const OVERRIDE { |
60 gfx::Rect bounds(view->GetLocalBounds()); | 82 gfx::Rect bounds(view->GetLocalBounds()); |
61 // Inset by 2 to leave 1 empty pixel between background and border. | 83 // Inset by 2 to leave 1 empty pixel between background and border. |
62 bounds.Inset(2, 2, 2, 2); | 84 bounds.Inset(2, 2, 2, 2); |
63 canvas->FillRect(bounds, kWarningColor); | 85 canvas->FillRect(bounds, kWarningColor); |
64 } | 86 } |
65 | 87 |
66 private: | 88 private: |
67 DISALLOW_COPY_AND_ASSIGN(InvalidBackground); | 89 DISALLOW_COPY_AND_ASSIGN(InvalidBackground); |
68 }; | 90 }; |
69 | 91 |
| 92 // The transparent button which holds a button state but is not rendered. |
| 93 class TransparentButton : public CustomButton { |
| 94 public: |
| 95 TransparentButton(ButtonListener* listener) |
| 96 : CustomButton(listener) { |
| 97 SetAnimationDuration(LabelButton::kHoverAnimationDurationMs); |
| 98 } |
| 99 virtual ~TransparentButton() {} |
| 100 |
| 101 double GetAnimationValue() const { |
| 102 return hover_animation_->GetCurrentValue(); |
| 103 } |
| 104 |
| 105 private: |
| 106 DISALLOW_COPY_AND_ASSIGN(TransparentButton); |
| 107 }; |
| 108 |
70 // Returns the next or previous valid index (depending on |increment|'s value). | 109 // Returns the next or previous valid index (depending on |increment|'s value). |
71 // Skips separator or disabled indices. Returns -1 if there is no valid adjacent | 110 // Skips separator or disabled indices. Returns -1 if there is no valid adjacent |
72 // index. | 111 // index. |
73 int GetAdjacentIndex(ui::ComboboxModel* model, int increment, int index) { | 112 int GetAdjacentIndex(ui::ComboboxModel* model, int increment, int index) { |
74 DCHECK(increment == -1 || increment == 1); | 113 DCHECK(increment == -1 || increment == 1); |
75 | 114 |
76 index += increment; | 115 index += increment; |
77 while (index >= 0 && index < model->GetItemCount()) { | 116 while (index >= 0 && index < model->GetItemCount()) { |
78 if (!model->IsItemSeparatorAt(index) || !model->IsItemEnabledAt(index)) | 117 if (!model->IsItemSeparatorAt(index) || !model->IsItemEnabledAt(index)) |
79 return index; | 118 return index; |
80 index += increment; | 119 index += increment; |
81 } | 120 } |
82 return kNoSelection; | 121 return kNoSelection; |
83 } | 122 } |
84 | 123 |
| 124 // Returns the image resource ids of an array for the body button. |
| 125 // |
| 126 // TODO(hajimehoshi): This function should return the images for the 'disabled' |
| 127 // status. (crbug/270052) |
| 128 // |
| 129 // TODO(hajimehoshi): Currently, |focused| is ignored. This should return the |
| 130 // images for the 'focused' status. (crbug/270052) |
| 131 const int* GetBodyButtonImageIds(bool focused, |
| 132 Button::ButtonState state, |
| 133 size_t* num) { |
| 134 DCHECK(num); |
| 135 *num = 9; |
| 136 switch (state) { |
| 137 case Button::STATE_DISABLED: |
| 138 return kBodyButtonImages; |
| 139 case Button::STATE_NORMAL: |
| 140 return kBodyButtonImages; |
| 141 case Button::STATE_HOVERED: |
| 142 return kHoveredBodyButtonImages; |
| 143 case Button::STATE_PRESSED: |
| 144 return kPressedBodyButtonImages; |
| 145 default: |
| 146 NOTREACHED(); |
| 147 } |
| 148 return NULL; |
| 149 } |
| 150 |
| 151 // Returns the image resource ids of an array for the menu button. |
| 152 const int* GetMenuButtonImageIds(bool focused, |
| 153 Button::ButtonState state, |
| 154 size_t* num) { |
| 155 DCHECK(num); |
| 156 *num = 3; |
| 157 switch (state) { |
| 158 case Button::STATE_DISABLED: |
| 159 return kMenuButtonImages; |
| 160 case Button::STATE_NORMAL: |
| 161 return kMenuButtonImages; |
| 162 case Button::STATE_HOVERED: |
| 163 return kHoveredMenuButtonImages; |
| 164 case Button::STATE_PRESSED: |
| 165 return kPressedMenuButtonImages; |
| 166 default: |
| 167 NOTREACHED(); |
| 168 } |
| 169 return NULL; |
| 170 } |
| 171 |
| 172 // Returns the images for the menu buttons. |
| 173 std::vector<const gfx::ImageSkia*> GetMenuButtonImages( |
| 174 bool focused, |
| 175 Button::ButtonState state) { |
| 176 const int* ids; |
| 177 size_t num_ids; |
| 178 ids = GetMenuButtonImageIds(focused, state, &num_ids); |
| 179 std::vector<const gfx::ImageSkia*> images; |
| 180 images.reserve(num_ids); |
| 181 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 182 for (size_t i = 0; i < num_ids; i++) |
| 183 images.push_back(rb.GetImageSkiaNamed(ids[i])); |
| 184 return images; |
| 185 } |
| 186 |
| 187 // Paints three images in a column at the given location. The center image is |
| 188 // stretched so as to fit the given height. |
| 189 void PaintImagesVertically(gfx::Canvas* canvas, |
| 190 const gfx::ImageSkia& top_image, |
| 191 const gfx::ImageSkia& center_image, |
| 192 const gfx::ImageSkia& bottom_image, |
| 193 int x, int y, int width, int height) { |
| 194 canvas->DrawImageInt(top_image, |
| 195 0, 0, top_image.width(), top_image.height(), |
| 196 x, y, width, top_image.height(), false); |
| 197 y += top_image.height(); |
| 198 int center_height = height - top_image.height() - bottom_image.height(); |
| 199 canvas->DrawImageInt(center_image, |
| 200 0, 0, center_image.width(), center_image.height(), |
| 201 x, y, width, center_height, false); |
| 202 y += center_height; |
| 203 canvas->DrawImageInt(bottom_image, |
| 204 0, 0, bottom_image.width(), bottom_image.height(), |
| 205 x, y, width, bottom_image.height(), false); |
| 206 } |
| 207 |
| 208 // Paints the arrow button. |
| 209 void PaintArrowButton( |
| 210 gfx::Canvas* canvas, |
| 211 const std::vector<const gfx::ImageSkia*>& arrow_button_images, |
| 212 int x, int height) { |
| 213 PaintImagesVertically(canvas, |
| 214 *arrow_button_images[0], |
| 215 *arrow_button_images[1], |
| 216 *arrow_button_images[2], |
| 217 x, 0, arrow_button_images[0]->width(), height); |
| 218 } |
| 219 |
85 } // namespace | 220 } // namespace |
86 | 221 |
87 // static | 222 // static |
88 const char Combobox::kViewClassName[] = "views/Combobox"; | 223 const char Combobox::kViewClassName[] = "views/Combobox"; |
89 | 224 |
90 //////////////////////////////////////////////////////////////////////////////// | 225 //////////////////////////////////////////////////////////////////////////////// |
91 // Combobox, public: | 226 // Combobox, public: |
92 | 227 |
93 Combobox::Combobox(ui::ComboboxModel* model) | 228 Combobox::Combobox(ui::ComboboxModel* model) |
94 : model_(model), | 229 : model_(model), |
| 230 style_(STYLE_SHOW_DROP_DOWN_ON_CLICK), |
95 listener_(NULL), | 231 listener_(NULL), |
96 selected_index_(model_->GetDefaultIndex()), | 232 selected_index_(model_->GetDefaultIndex()), |
97 invalid_(false), | 233 invalid_(false), |
98 text_border_(new FocusableBorder()), | |
99 disclosure_arrow_(ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 234 disclosure_arrow_(ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
100 IDR_MENU_DROPARROW).ToImageSkia()), | 235 IDR_MENU_DROPARROW).ToImageSkia()), |
101 dropdown_open_(false) { | 236 dropdown_open_(false), |
| 237 text_button_(new TransparentButton(this)), |
| 238 arrow_button_(new TransparentButton(this)) { |
102 model_->AddObserver(this); | 239 model_->AddObserver(this); |
103 UpdateFromModel(); | 240 UpdateFromModel(); |
104 set_focusable(true); | 241 set_focusable(true); |
105 set_border(text_border_); | 242 UpdateBorder(); |
| 243 |
| 244 // Initialize the button images. |
| 245 Button::ButtonState button_states[] = { |
| 246 Button::STATE_DISABLED, |
| 247 Button::STATE_NORMAL, |
| 248 Button::STATE_HOVERED, |
| 249 Button::STATE_PRESSED, |
| 250 }; |
| 251 for (int i = 0; i < 2; i++) { |
| 252 for (size_t state_index = 0; state_index < arraysize(button_states); |
| 253 state_index++) { |
| 254 Button::ButtonState state = button_states[state_index]; |
| 255 size_t num; |
| 256 bool focused = !!i; |
| 257 const int* ids = GetBodyButtonImageIds(focused, state, &num); |
| 258 body_button_painters_[focused][state].reset( |
| 259 Painter::CreateImageGridPainter(ids)); |
| 260 menu_button_images_[focused][state] = GetMenuButtonImages(focused, state); |
| 261 } |
| 262 } |
| 263 |
| 264 text_button_->SetVisible(true); |
| 265 arrow_button_->SetVisible(true); |
| 266 text_button_->set_focusable(false); |
| 267 arrow_button_->set_focusable(false); |
| 268 AddChildView(text_button_); |
| 269 AddChildView(arrow_button_); |
106 } | 270 } |
107 | 271 |
108 Combobox::~Combobox() { | 272 Combobox::~Combobox() { |
109 model_->RemoveObserver(this); | 273 model_->RemoveObserver(this); |
110 } | 274 } |
111 | 275 |
112 // static | 276 // static |
113 const gfx::Font& Combobox::GetFont() { | 277 const gfx::Font& Combobox::GetFont() { |
114 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 278 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
115 return rb.GetFont(ui::ResourceBundle::BaseFont); | 279 return rb.GetFont(ui::ResourceBundle::BaseFont); |
116 } | 280 } |
117 | 281 |
| 282 void Combobox::SetStyle(Style style) { |
| 283 if (style_ == style) |
| 284 return; |
| 285 |
| 286 style_ = style; |
| 287 |
| 288 UpdateBorder(); |
| 289 PreferredSizeChanged(); |
| 290 } |
| 291 |
118 void Combobox::ModelChanged() { | 292 void Combobox::ModelChanged() { |
119 selected_index_ = std::min(0, model_->GetItemCount()); | 293 selected_index_ = std::min(0, model_->GetItemCount()); |
120 UpdateFromModel(); | 294 UpdateFromModel(); |
121 PreferredSizeChanged(); | 295 PreferredSizeChanged(); |
122 } | 296 } |
123 | 297 |
124 void Combobox::SetSelectedIndex(int index) { | 298 void Combobox::SetSelectedIndex(int index) { |
125 selected_index_ = index; | 299 selected_index_ = index; |
126 SchedulePaint(); | 300 SchedulePaint(); |
127 } | 301 } |
(...skipping 10 matching lines...) Expand all Loading... |
138 | 312 |
139 void Combobox::SetAccessibleName(const string16& name) { | 313 void Combobox::SetAccessibleName(const string16& name) { |
140 accessible_name_ = name; | 314 accessible_name_ = name; |
141 } | 315 } |
142 | 316 |
143 void Combobox::SetInvalid(bool invalid) { | 317 void Combobox::SetInvalid(bool invalid) { |
144 if (invalid == invalid_) | 318 if (invalid == invalid_) |
145 return; | 319 return; |
146 | 320 |
147 invalid_ = invalid; | 321 invalid_ = invalid; |
148 if (invalid_) { | 322 |
149 text_border_->SetColor(kWarningColor); | 323 set_background(invalid_ ? new InvalidBackground() : NULL); |
150 set_background(new InvalidBackground()); | 324 UpdateBorder(); |
151 } else { | |
152 text_border_->UseDefaultColor(); | |
153 set_background(NULL); | |
154 } | |
155 SchedulePaint(); | 325 SchedulePaint(); |
156 } | 326 } |
157 | 327 |
158 ui::TextInputClient* Combobox::GetTextInputClient() { | 328 ui::TextInputClient* Combobox::GetTextInputClient() { |
159 if (!selector_) | 329 if (!selector_) |
160 selector_.reset(new PrefixSelector(this)); | 330 selector_.reset(new PrefixSelector(this)); |
161 return selector_.get(); | 331 return selector_.get(); |
162 } | 332 } |
163 | 333 |
| 334 void Combobox::Layout() { |
| 335 PrefixDelegate::Layout(); |
| 336 |
| 337 gfx::Insets insets = GetInsets(); |
| 338 int text_button_width = 0; |
| 339 int arrow_button_width = 0; |
| 340 |
| 341 switch (style_) { |
| 342 case STYLE_SHOW_DROP_DOWN_ON_CLICK: { |
| 343 arrow_button_width = width(); |
| 344 break; |
| 345 } |
| 346 case STYLE_NOTIFY_ON_CLICK: { |
| 347 arrow_button_width = GetDisclosureArrowLeftPadding() + |
| 348 disclosure_arrow_->width() + GetDisclosureArrowRightPadding(); |
| 349 text_button_width = width() - arrow_button_width; |
| 350 break; |
| 351 } |
| 352 } |
| 353 |
| 354 int arrow_button_x = std::max(0, text_button_width); |
| 355 text_button_->SetBounds(0, 0, std::max(0, text_button_width), height()); |
| 356 arrow_button_->SetBounds(arrow_button_x, 0, arrow_button_width, height()); |
| 357 } |
164 | 358 |
165 bool Combobox::IsItemChecked(int id) const { | 359 bool Combobox::IsItemChecked(int id) const { |
166 return false; | 360 return false; |
167 } | 361 } |
168 | 362 |
169 bool Combobox::IsCommandEnabled(int id) const { | 363 bool Combobox::IsCommandEnabled(int id) const { |
170 return model()->IsItemEnabledAt(MenuCommandToIndex(id)); | 364 return model()->IsItemEnabledAt(MenuCommandToIndex(id)); |
171 } | 365 } |
172 | 366 |
173 void Combobox::ExecuteCommand(int id) { | 367 void Combobox::ExecuteCommand(int id) { |
(...skipping 25 matching lines...) Expand all Loading... |
199 // Combobox, View overrides: | 393 // Combobox, View overrides: |
200 | 394 |
201 gfx::Size Combobox::GetPreferredSize() { | 395 gfx::Size Combobox::GetPreferredSize() { |
202 if (content_size_.IsEmpty()) | 396 if (content_size_.IsEmpty()) |
203 UpdateFromModel(); | 397 UpdateFromModel(); |
204 | 398 |
205 // The preferred size will drive the local bounds which in turn is used to set | 399 // The preferred size will drive the local bounds which in turn is used to set |
206 // the minimum width for the dropdown list. | 400 // the minimum width for the dropdown list. |
207 gfx::Insets insets = GetInsets(); | 401 gfx::Insets insets = GetInsets(); |
208 int total_width = std::max(kMinComboboxWidth, content_size_.width()) + | 402 int total_width = std::max(kMinComboboxWidth, content_size_.width()) + |
209 insets.width() + kDisclosureArrowLeftPadding + | 403 insets.width() + GetDisclosureArrowLeftPadding() + |
210 disclosure_arrow_->width() + kDisclosureArrowRightPadding; | 404 disclosure_arrow_->width() + GetDisclosureArrowRightPadding(); |
211 | |
212 return gfx::Size(total_width, content_size_.height() + insets.height()); | 405 return gfx::Size(total_width, content_size_.height() + insets.height()); |
213 } | 406 } |
214 | 407 |
215 const char* Combobox::GetClassName() const { | 408 const char* Combobox::GetClassName() const { |
216 return kViewClassName; | 409 return kViewClassName; |
217 } | 410 } |
218 | 411 |
219 bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { | 412 bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) { |
220 // Escape should close the drop down list when it is active, not host UI. | 413 // Escape should close the drop down list when it is active, not host UI. |
221 if (e.key_code() != ui::VKEY_ESCAPE || | 414 if (e.key_code() != ui::VKEY_ESCAPE || |
222 e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) { | 415 e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) { |
223 return false; | 416 return false; |
224 } | 417 } |
225 return dropdown_open_; | 418 return dropdown_open_; |
226 } | 419 } |
227 | 420 |
228 bool Combobox::OnMousePressed(const ui::MouseEvent& mouse_event) { | |
229 RequestFocus(); | |
230 const base::TimeDelta delta = base::Time::Now() - closed_time_; | |
231 if (mouse_event.IsLeftMouseButton() && | |
232 (delta.InMilliseconds() > kMinimumMsBetweenButtonClicks)) { | |
233 UpdateFromModel(); | |
234 ShowDropDownMenu(ui::MENU_SOURCE_MOUSE); | |
235 } | |
236 | |
237 return true; | |
238 } | |
239 | |
240 bool Combobox::OnMouseDragged(const ui::MouseEvent& mouse_event) { | |
241 return true; | |
242 } | |
243 | |
244 bool Combobox::OnKeyPressed(const ui::KeyEvent& e) { | 421 bool Combobox::OnKeyPressed(const ui::KeyEvent& e) { |
245 // TODO(oshima): handle IME. | 422 // TODO(oshima): handle IME. |
246 DCHECK_EQ(e.type(), ui::ET_KEY_PRESSED); | 423 DCHECK_EQ(e.type(), ui::ET_KEY_PRESSED); |
247 | 424 |
248 DCHECK_GE(selected_index_, 0); | 425 DCHECK_GE(selected_index_, 0); |
249 DCHECK_LT(selected_index_, model()->GetItemCount()); | 426 DCHECK_LT(selected_index_, model()->GetItemCount()); |
250 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount()) | 427 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount()) |
251 selected_index_ = 0; | 428 selected_index_ = 0; |
252 | 429 |
253 bool show_menu = false; | 430 bool show_menu = false; |
(...skipping 24 matching lines...) Expand all Loading... |
278 case ui::VKEY_HOME: | 455 case ui::VKEY_HOME: |
279 case ui::VKEY_PRIOR: // Page up. | 456 case ui::VKEY_PRIOR: // Page up. |
280 new_index = GetAdjacentIndex(model(), 1, -1); | 457 new_index = GetAdjacentIndex(model(), 1, -1); |
281 break; | 458 break; |
282 | 459 |
283 // Move to the previous item if any. | 460 // Move to the previous item if any. |
284 case ui::VKEY_UP: | 461 case ui::VKEY_UP: |
285 new_index = GetAdjacentIndex(model(), -1, selected_index_); | 462 new_index = GetAdjacentIndex(model(), -1, selected_index_); |
286 break; | 463 break; |
287 | 464 |
| 465 // Click the button only when the button style mode. |
| 466 case ui::VKEY_SPACE: |
| 467 if (style_ == STYLE_NOTIFY_ON_CLICK) { |
| 468 // When pressing space, the click event will be raised after the key is |
| 469 // released. |
| 470 text_button_->SetState(Button::STATE_PRESSED); |
| 471 } |
| 472 break; |
| 473 |
| 474 // Click the button only when the button style mode. |
| 475 case ui::VKEY_RETURN: |
| 476 HandleClickEvent(); |
| 477 break; |
| 478 |
288 default: | 479 default: |
289 return false; | 480 return false; |
290 } | 481 } |
291 | 482 |
292 if (show_menu) { | 483 if (show_menu) { |
293 UpdateFromModel(); | 484 UpdateFromModel(); |
294 ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD); | 485 ShowDropDownMenu(ui::MENU_SOURCE_KEYBOARD); |
295 } else if (new_index != selected_index_ && new_index != kNoSelection) { | 486 } else if (new_index != selected_index_ && new_index != kNoSelection) { |
296 DCHECK(!model()->IsItemSeparatorAt(new_index)); | 487 DCHECK(!model()->IsItemSeparatorAt(new_index)); |
297 selected_index_ = new_index; | 488 selected_index_ = new_index; |
298 OnSelectionChanged(); | 489 OnSelectionChanged(); |
299 } | 490 } |
300 | 491 |
301 return true; | 492 return true; |
302 } | 493 } |
303 | 494 |
304 bool Combobox::OnKeyReleased(const ui::KeyEvent& e) { | 495 bool Combobox::OnKeyReleased(const ui::KeyEvent& e) { |
305 return false; // crbug.com/127520 | 496 if (style_ != STYLE_NOTIFY_ON_CLICK) |
306 } | 497 return false; // crbug.com/127520 |
307 | 498 |
308 void Combobox::OnGestureEvent(ui::GestureEvent* gesture) { | 499 if (e.key_code() == ui::VKEY_SPACE) |
309 if (gesture->type() == ui::ET_GESTURE_TAP) { | 500 HandleClickEvent(); |
310 UpdateFromModel(); | 501 |
311 ShowDropDownMenu(ui::MENU_SOURCE_TOUCH); | 502 return false; |
312 gesture->StopPropagation(); | |
313 return; | |
314 } | |
315 View::OnGestureEvent(gesture); | |
316 } | 503 } |
317 | 504 |
318 void Combobox::OnPaint(gfx::Canvas* canvas) { | 505 void Combobox::OnPaint(gfx::Canvas* canvas) { |
319 OnPaintBackground(canvas); | 506 switch (style_) { |
320 PaintText(canvas); | 507 case STYLE_SHOW_DROP_DOWN_ON_CLICK: { |
321 OnPaintBorder(canvas); | 508 OnPaintBackground(canvas); |
| 509 PaintText(canvas); |
| 510 OnPaintBorder(canvas); |
| 511 break; |
| 512 } |
| 513 case STYLE_NOTIFY_ON_CLICK: { |
| 514 PaintButtons(canvas); |
| 515 PaintText(canvas); |
| 516 break; |
| 517 } |
| 518 } |
322 } | 519 } |
323 | 520 |
324 void Combobox::OnFocus() { | 521 void Combobox::OnFocus() { |
325 GetInputMethod()->OnFocus(); | 522 GetInputMethod()->OnFocus(); |
326 View::OnFocus(); | 523 View::OnFocus(); |
327 // Border renders differently when focused. | 524 // Border renders differently when focused. |
328 SchedulePaint(); | 525 SchedulePaint(); |
329 } | 526 } |
330 | 527 |
331 void Combobox::OnBlur() { | 528 void Combobox::OnBlur() { |
332 GetInputMethod()->OnBlur(); | 529 GetInputMethod()->OnBlur(); |
333 if (selector_) | 530 if (selector_) |
334 selector_->OnViewBlur(); | 531 selector_->OnViewBlur(); |
335 // Border renders differently when focused. | 532 // Border renders differently when focused. |
336 SchedulePaint(); | 533 SchedulePaint(); |
337 } | 534 } |
338 | 535 |
339 void Combobox::GetAccessibleState(ui::AccessibleViewState* state) { | 536 void Combobox::GetAccessibleState(ui::AccessibleViewState* state) { |
340 state->role = ui::AccessibilityTypes::ROLE_COMBOBOX; | 537 state->role = ui::AccessibilityTypes::ROLE_COMBOBOX; |
341 state->name = accessible_name_; | 538 state->name = accessible_name_; |
342 state->value = model_->GetItemAt(selected_index_); | 539 state->value = model_->GetItemAt(selected_index_); |
343 state->index = selected_index_; | 540 state->index = selected_index_; |
344 state->count = model_->GetItemCount(); | 541 state->count = model_->GetItemCount(); |
345 } | 542 } |
346 | 543 |
347 void Combobox::OnModelChanged() { | 544 void Combobox::OnModelChanged() { |
348 ModelChanged(); | 545 ModelChanged(); |
349 } | 546 } |
350 | 547 |
| 548 void Combobox::ButtonPressed(Button* sender, const ui::Event& event) { |
| 549 RequestFocus(); |
| 550 |
| 551 if (sender == text_button_) { |
| 552 HandleClickEvent(); |
| 553 } else { |
| 554 DCHECK_EQ(arrow_button_, sender); |
| 555 // TODO(hajimehoshi): Fix the problem that the arrow button blinks when |
| 556 // cliking this while the dropdown menu is opened. |
| 557 const base::TimeDelta delta = base::Time::Now() - closed_time_; |
| 558 if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks) |
| 559 return; |
| 560 |
| 561 ui::MenuSourceType source_type = ui::MENU_SOURCE_MOUSE; |
| 562 if (event.IsKeyEvent()) |
| 563 source_type = ui::MENU_SOURCE_KEYBOARD; |
| 564 else if (event.IsGestureEvent() || event.IsTouchEvent()) |
| 565 source_type = ui::MENU_SOURCE_TOUCH; |
| 566 ShowDropDownMenu(source_type); |
| 567 } |
| 568 } |
| 569 |
351 void Combobox::UpdateFromModel() { | 570 void Combobox::UpdateFromModel() { |
352 int max_width = 0; | 571 int max_width = 0; |
353 const gfx::Font& font = Combobox::GetFont(); | 572 const gfx::Font& font = Combobox::GetFont(); |
354 | 573 |
355 MenuItemView* menu = new MenuItemView(this); | 574 MenuItemView* menu = new MenuItemView(this); |
356 // MenuRunner owns |menu|. | 575 // MenuRunner owns |menu|. |
357 dropdown_list_menu_runner_.reset(new MenuRunner(menu)); | 576 dropdown_list_menu_runner_.reset(new MenuRunner(menu)); |
358 | 577 |
359 int num_items = model()->GetItemCount(); | 578 int num_items = model()->GetItemCount(); |
360 for (int i = 0; i < num_items; ++i) { | 579 for (int i = 0; i < num_items; ++i) { |
361 if (model()->IsItemSeparatorAt(i)) { | 580 if (model()->IsItemSeparatorAt(i)) { |
362 menu->AppendSeparator(); | 581 menu->AppendSeparator(); |
363 continue; | 582 continue; |
364 } | 583 } |
365 | 584 |
366 string16 text = model()->GetItemAt(i); | 585 string16 text = model()->GetItemAt(i); |
367 | 586 |
368 // Inserting the Unicode formatting characters if necessary so that the | 587 // Inserting the Unicode formatting characters if necessary so that the |
369 // text is displayed correctly in right-to-left UIs. | 588 // text is displayed correctly in right-to-left UIs. |
370 base::i18n::AdjustStringForLocaleDirection(&text); | 589 base::i18n::AdjustStringForLocaleDirection(&text); |
371 | 590 |
372 menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL); | 591 menu->AppendMenuItem(i + kFirstMenuItemId, text, MenuItemView::NORMAL); |
373 max_width = std::max(max_width, font.GetStringWidth(text)); | 592 max_width = std::max(max_width, font.GetStringWidth(text)); |
374 } | 593 } |
375 | 594 |
376 content_size_.SetSize(max_width, font.GetHeight()); | 595 content_size_.SetSize(max_width, font.GetHeight()); |
377 } | 596 } |
378 | 597 |
| 598 void Combobox::UpdateBorder() { |
| 599 FocusableBorder* border = new FocusableBorder(); |
| 600 if (style_ == STYLE_NOTIFY_ON_CLICK) |
| 601 border->SetInsets(8, 13, 8, 13); |
| 602 if (invalid_) |
| 603 border->SetColor(kWarningColor); |
| 604 set_border(border); |
| 605 } |
| 606 |
379 void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const { | 607 void Combobox::AdjustBoundsForRTLUI(gfx::Rect* rect) const { |
380 rect->set_x(GetMirroredXForRect(*rect)); | 608 rect->set_x(GetMirroredXForRect(*rect)); |
381 } | 609 } |
382 | 610 |
383 void Combobox::PaintText(gfx::Canvas* canvas) { | 611 void Combobox::PaintText(gfx::Canvas* canvas) { |
384 gfx::Insets insets = GetInsets(); | 612 gfx::Insets insets = GetInsets(); |
385 | 613 |
386 canvas->Save(); | 614 gfx::ScopedCanvas scoped_canvas(canvas); |
387 canvas->ClipRect(GetContentsBounds()); | 615 canvas->ClipRect(GetContentsBounds()); |
388 | 616 |
389 int x = insets.left(); | 617 int x = insets.left(); |
390 int y = insets.top(); | 618 int y = insets.top(); |
391 int text_height = height() - insets.height(); | 619 int text_height = height() - insets.height(); |
392 SkColor text_color = invalid() ? kInvalidTextColor : | 620 SkColor text_color = invalid() ? kInvalidTextColor : |
393 GetNativeTheme()->GetSystemColor( | 621 GetNativeTheme()->GetSystemColor( |
394 ui::NativeTheme::kColorId_LabelEnabledColor); | 622 ui::NativeTheme::kColorId_LabelEnabledColor); |
395 | 623 |
396 DCHECK_GE(selected_index_, 0); | 624 DCHECK_GE(selected_index_, 0); |
397 DCHECK_LT(selected_index_, model()->GetItemCount()); | 625 DCHECK_LT(selected_index_, model()->GetItemCount()); |
398 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount()) | 626 if (selected_index_ < 0 || selected_index_ > model()->GetItemCount()) |
399 selected_index_ = 0; | 627 selected_index_ = 0; |
400 string16 text = model()->GetItemAt(selected_index_); | 628 string16 text = model()->GetItemAt(selected_index_); |
401 | 629 |
402 int disclosure_arrow_offset = width() - disclosure_arrow_->width() | 630 int disclosure_arrow_offset = width() - disclosure_arrow_->width() - |
403 - kDisclosureArrowLeftPadding - kDisclosureArrowRightPadding; | 631 GetDisclosureArrowLeftPadding() - GetDisclosureArrowRightPadding(); |
404 | 632 |
405 const gfx::Font& font = Combobox::GetFont(); | 633 const gfx::Font& font = Combobox::GetFont(); |
406 int text_width = font.GetStringWidth(text); | 634 int text_width = font.GetStringWidth(text); |
407 if ((text_width + insets.width()) > disclosure_arrow_offset) | 635 if ((text_width + insets.width()) > disclosure_arrow_offset) |
408 text_width = disclosure_arrow_offset - insets.width(); | 636 text_width = disclosure_arrow_offset - insets.width(); |
409 | 637 |
410 gfx::Rect text_bounds(x, y, text_width, text_height); | 638 gfx::Rect text_bounds(x, y, text_width, text_height); |
411 AdjustBoundsForRTLUI(&text_bounds); | 639 AdjustBoundsForRTLUI(&text_bounds); |
412 canvas->DrawStringInt(text, font, text_color, text_bounds); | 640 canvas->DrawStringInt(text, font, text_color, text_bounds); |
413 | 641 |
414 gfx::Rect arrow_bounds(disclosure_arrow_offset + kDisclosureArrowLeftPadding, | 642 int arrow_x = disclosure_arrow_offset + GetDisclosureArrowLeftPadding(); |
| 643 gfx::Rect arrow_bounds(arrow_x, |
415 height() / 2 - disclosure_arrow_->height() / 2, | 644 height() / 2 - disclosure_arrow_->height() / 2, |
416 disclosure_arrow_->width(), | 645 disclosure_arrow_->width(), |
417 disclosure_arrow_->height()); | 646 disclosure_arrow_->height()); |
418 AdjustBoundsForRTLUI(&arrow_bounds); | 647 AdjustBoundsForRTLUI(&arrow_bounds); |
419 | 648 |
420 SkPaint paint; | 649 SkPaint paint; |
421 // This makes the arrow subtractive. | 650 // This makes the arrow subtractive. |
422 if (invalid()) | 651 if (invalid()) |
423 paint.setXfermodeMode(SkXfermode::kDstOut_Mode); | 652 paint.setXfermodeMode(SkXfermode::kDstOut_Mode); |
424 canvas->DrawImageInt(*disclosure_arrow_, arrow_bounds.x(), arrow_bounds.y(), | 653 canvas->DrawImageInt(*disclosure_arrow_, arrow_bounds.x(), arrow_bounds.y(), |
425 paint); | 654 paint); |
| 655 } |
426 | 656 |
427 canvas->Restore(); | 657 void Combobox::PaintButtons(gfx::Canvas* canvas) { |
| 658 DCHECK(style_ == STYLE_NOTIFY_ON_CLICK); |
| 659 |
| 660 gfx::ScopedCanvas scoped_canvas(canvas); |
| 661 if (base::i18n::IsRTL()) { |
| 662 canvas->Translate(gfx::Vector2d(width(), 0)); |
| 663 canvas->Scale(-1, 1); |
| 664 } |
| 665 |
| 666 bool focused = HasFocus(); |
| 667 const std::vector<const gfx::ImageSkia*>& arrow_button_images = |
| 668 menu_button_images_[focused][ |
| 669 arrow_button_->state() == Button::STATE_HOVERED ? |
| 670 Button::STATE_NORMAL : arrow_button_->state()]; |
| 671 |
| 672 int text_button_hover_alpha = |
| 673 text_button_->state() == Button::STATE_PRESSED ? 0 : |
| 674 static_cast<int>(static_cast<TransparentButton*>(text_button_)-> |
| 675 GetAnimationValue() * 255); |
| 676 if (text_button_hover_alpha < 255) { |
| 677 canvas->SaveLayerAlpha(255 - text_button_hover_alpha); |
| 678 Painter* text_button_painter = |
| 679 body_button_painters_[focused][ |
| 680 text_button_->state() == Button::STATE_HOVERED ? |
| 681 Button::STATE_NORMAL : text_button_->state()].get(); |
| 682 Painter::PaintPainterAt(canvas, text_button_painter, |
| 683 gfx::Rect(0, 0, text_button_->width(), height())); |
| 684 canvas->Restore(); |
| 685 } |
| 686 if (0 < text_button_hover_alpha) { |
| 687 canvas->SaveLayerAlpha(text_button_hover_alpha); |
| 688 Painter* text_button_hovered_painter = |
| 689 body_button_painters_[focused][Button::STATE_HOVERED].get(); |
| 690 Painter::PaintPainterAt(canvas, text_button_hovered_painter, |
| 691 gfx::Rect(0, 0, text_button_->width(), height())); |
| 692 canvas->Restore(); |
| 693 } |
| 694 |
| 695 int arrow_button_hover_alpha = |
| 696 arrow_button_->state() == Button::STATE_PRESSED ? 0 : |
| 697 static_cast<int>(static_cast<TransparentButton*>(arrow_button_)-> |
| 698 GetAnimationValue() * 255); |
| 699 if (arrow_button_hover_alpha < 255) { |
| 700 canvas->SaveLayerAlpha(255 - arrow_button_hover_alpha); |
| 701 PaintArrowButton(canvas, arrow_button_images, arrow_button_->x(), height()); |
| 702 canvas->Restore(); |
| 703 } |
| 704 if (0 < arrow_button_hover_alpha) { |
| 705 canvas->SaveLayerAlpha(arrow_button_hover_alpha); |
| 706 const std::vector<const gfx::ImageSkia*>& arrow_button_hovered_images = |
| 707 menu_button_images_[focused][Button::STATE_HOVERED]; |
| 708 PaintArrowButton(canvas, arrow_button_hovered_images, |
| 709 arrow_button_->x(), height()); |
| 710 canvas->Restore(); |
| 711 } |
428 } | 712 } |
429 | 713 |
430 void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) { | 714 void Combobox::ShowDropDownMenu(ui::MenuSourceType source_type) { |
431 if (!dropdown_list_menu_runner_.get()) | 715 if (!dropdown_list_menu_runner_.get()) |
432 UpdateFromModel(); | 716 UpdateFromModel(); |
433 | 717 |
434 // Extend the menu to the width of the combobox. | 718 // Extend the menu to the width of the combobox. |
435 MenuItemView* menu = dropdown_list_menu_runner_->GetMenu(); | 719 MenuItemView* menu = dropdown_list_menu_runner_->GetMenu(); |
436 SubmenuView* submenu = menu->CreateSubmenu(); | 720 SubmenuView* submenu = menu->CreateSubmenu(); |
437 submenu->set_minimum_preferred_width(size().width() - | 721 submenu->set_minimum_preferred_width( |
438 (kMenuBorderWidthLeft + kMenuBorderWidthRight)); | 722 size().width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight)); |
439 | 723 |
440 gfx::Rect lb = GetLocalBounds(); | 724 gfx::Rect lb = GetLocalBounds(); |
441 gfx::Point menu_position(lb.origin()); | 725 gfx::Point menu_position(lb.origin()); |
442 | 726 |
443 // Inset the menu's requested position so the border of the menu lines up | 727 // Inset the menu's requested position so the border of the menu lines up |
444 // with the border of the combobox. | 728 // with the border of the combobox. |
445 menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft); | 729 menu_position.set_x(menu_position.x() + kMenuBorderWidthLeft); |
446 menu_position.set_y(menu_position.y() + kMenuBorderWidthTop); | 730 menu_position.set_y(menu_position.y() + kMenuBorderWidthTop); |
447 lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight)); | 731 lb.set_width(lb.width() - (kMenuBorderWidthLeft + kMenuBorderWidthRight)); |
448 | 732 |
449 View::ConvertPointToScreen(this, &menu_position); | 733 View::ConvertPointToScreen(this, &menu_position); |
450 if (menu_position.x() < 0) | 734 if (menu_position.x() < 0) |
451 menu_position.set_x(0); | 735 menu_position.set_x(0); |
452 | 736 |
453 gfx::Rect bounds(menu_position, lb.size()); | 737 gfx::Rect bounds(menu_position, lb.size()); |
454 | 738 |
| 739 Button::ButtonState original_state = Button::STATE_NORMAL; |
| 740 if (arrow_button_) { |
| 741 original_state = arrow_button_->state(); |
| 742 arrow_button_->SetState(Button::STATE_PRESSED); |
| 743 } |
455 dropdown_open_ = true; | 744 dropdown_open_ = true; |
456 if (dropdown_list_menu_runner_->RunMenuAt(GetWidget(), NULL, bounds, | 745 if (dropdown_list_menu_runner_->RunMenuAt(GetWidget(), NULL, bounds, |
457 MenuItemView::TOPLEFT, source_type, MenuRunner::COMBOBOX) == | 746 MenuItemView::TOPLEFT, source_type, |
458 MenuRunner::MENU_DELETED) | 747 MenuRunner::COMBOBOX) == |
| 748 MenuRunner::MENU_DELETED) { |
459 return; | 749 return; |
| 750 } |
460 dropdown_open_ = false; | 751 dropdown_open_ = false; |
| 752 if (arrow_button_) |
| 753 arrow_button_->SetState(original_state); |
461 closed_time_ = base::Time::Now(); | 754 closed_time_ = base::Time::Now(); |
462 | 755 |
463 // Need to explicitly clear mouse handler so that events get sent | 756 // Need to explicitly clear mouse handler so that events get sent |
464 // properly after the menu finishes running. If we don't do this, then | 757 // properly after the menu finishes running. If we don't do this, then |
465 // the first click to other parts of the UI is eaten. | 758 // the first click to other parts of the UI is eaten. |
466 SetMouseHandler(NULL); | 759 SetMouseHandler(NULL); |
467 } | 760 } |
468 | 761 |
469 void Combobox::OnSelectionChanged() { | 762 void Combobox::OnSelectionChanged() { |
470 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false); | 763 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false); |
471 SchedulePaint(); | 764 SchedulePaint(); |
472 if (listener_) | 765 if (listener_) |
473 listener_->OnSelectedIndexChanged(this); | 766 listener_->OnSelectedIndexChanged(this); |
474 // |this| may now be deleted. | 767 // |this| may now be deleted. |
475 } | 768 } |
476 | 769 |
477 int Combobox::MenuCommandToIndex(int menu_command_id) const { | 770 int Combobox::MenuCommandToIndex(int menu_command_id) const { |
478 // (note that the id received is offset by kFirstMenuItemId) | 771 // (note that the id received is offset by kFirstMenuItemId) |
479 // Revert menu ID offset to map back to combobox model. | 772 // Revert menu ID offset to map back to combobox model. |
480 int index = menu_command_id - kFirstMenuItemId; | 773 int index = menu_command_id - kFirstMenuItemId; |
481 DCHECK_LT(index, model()->GetItemCount()); | 774 DCHECK_LT(index, model()->GetItemCount()); |
482 return index; | 775 return index; |
483 } | 776 } |
484 | 777 |
| 778 int Combobox::GetDisclosureArrowLeftPadding() const { |
| 779 switch (style_) { |
| 780 case STYLE_SHOW_DROP_DOWN_ON_CLICK: |
| 781 return kDisclosureArrowLeftPadding; |
| 782 case STYLE_NOTIFY_ON_CLICK: |
| 783 return kDisclosureArrowButtonLeftPadding; |
| 784 } |
| 785 NOTREACHED(); |
| 786 return 0; |
| 787 } |
| 788 |
| 789 int Combobox::GetDisclosureArrowRightPadding() const { |
| 790 switch (style_) { |
| 791 case STYLE_SHOW_DROP_DOWN_ON_CLICK: |
| 792 return kDisclosureArrowRightPadding; |
| 793 case STYLE_NOTIFY_ON_CLICK: |
| 794 return kDisclosureArrowButtonRightPadding; |
| 795 } |
| 796 NOTREACHED(); |
| 797 return 0; |
| 798 } |
| 799 |
| 800 void Combobox::HandleClickEvent() { |
| 801 if (style_ != STYLE_NOTIFY_ON_CLICK) |
| 802 return; |
| 803 |
| 804 if (listener_) |
| 805 listener_->OnComboboxTextButtonClicked(this); |
| 806 } |
| 807 |
485 } // namespace views | 808 } // namespace views |
OLD | NEW |