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 3 // found in the LICENSE file. 4 5 #ifndef UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_ 6 #define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_ 7 8 #include <string> 9 10 #include "base/time/time.h" 11 #include "ui/base/models/combobox_model_observer.h" 12 #include "ui/gfx/animation/animation_delegate.h" 13 #include "ui/gfx/native_widget_types.h" 14 #include "ui/views/controls/button/button.h" 15 #include "ui/views/controls/menu/menu_delegate.h" 16 #include "ui/views/controls/prefix_delegate.h" 17 18 namespace gfx { 19 class Font; 20 class SlideAnimation; 21 } 22 23 namespace ui { 24 class ComboboxModel; 25 } 26 27 namespace views { 28 29 class ComboboxListener; 30 class ComboboxMenuRunner; 31 class CustomButton; 32 class FocusableBorder; 33 class MenuRunner; 34 class MenuRunnerHandler; 35 class Painter; 36 class PrefixSelector; 37 38 // A non-editable combobox (aka a drop-down list or selector). 39 // Combobox has two distinct parts, the drop down arrow and the text. When the 40 // user clicks on the text the drop down is either shown 41 // (STYLE_SHOW_DROP_DOWN_ON_CLICK) or the listener is notified 42 // (STYLE_NOTIFY_ON_CLICK). 43 class VIEWS_EXPORT Combobox : public MenuDelegate, 44 public PrefixDelegate, 45 public ui::ComboboxModelObserver, 46 public ButtonListener { 47 public: 48 // The style of the combobox. 49 enum Style { 50 STYLE_SHOW_DROP_DOWN_ON_CLICK, 51 STYLE_NOTIFY_ON_CLICK, 52 }; 53 54 // The combobox's class name. 55 static const char kViewClassName[]; 56 57 // |model| is not owned by the combobox. 58 explicit Combobox(ui::ComboboxModel* model); 59 virtual ~Combobox(); 60 61 static const gfx::Font& GetFont(); 62 63 // Sets the listener which will be called when a selection has been made. 64 void set_listener(ComboboxListener* listener) { listener_ = listener; } 65 66 void SetStyle(Style style); 67 68 // Informs the combobox that its model changed. 69 void ModelChanged(); 70 71 // Gets/Sets the selected index. 72 int selected_index() const { return selected_index_; } 73 void SetSelectedIndex(int index); 74 75 // Looks for the first occurrence of |value| in |model()|. If found, selects 76 // the found index and returns true. Otherwise simply noops and returns false. 77 bool SelectValue(const base::string16& value); 78 79 ui::ComboboxModel* model() const { return model_; } 80 81 // Set the accessible name of the combobox. 82 void SetAccessibleName(const string16& name); 83 84 // Visually marks the combobox as having an invalid value selected. 85 // When invalid, it paints with white text on a red background. 86 // Callers are responsible for restoring validity with selection changes. 87 void SetInvalid(bool invalid); 88 bool invalid() const { return invalid_; } 89 90 // Overridden from View: 91 virtual gfx::Size GetPreferredSize() OVERRIDE; 92 virtual const char* GetClassName() const OVERRIDE; 93 virtual bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) OVERRIDE; 94 virtual bool OnKeyPressed(const ui::KeyEvent& e) OVERRIDE; 95 virtual bool OnKeyReleased(const ui::KeyEvent& e) OVERRIDE; 96 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 97 virtual void OnFocus() OVERRIDE; 98 virtual void OnBlur() OVERRIDE; 99 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; 100 virtual ui::TextInputClient* GetTextInputClient() OVERRIDE; 101 virtual void Layout() OVERRIDE; 102 103 // Overridden from MenuDelegate: 104 virtual bool IsItemChecked(int id) const OVERRIDE; 105 virtual bool IsCommandEnabled(int id) const OVERRIDE; 106 virtual void ExecuteCommand(int id) OVERRIDE; 107 virtual bool GetAccelerator(int id, ui::Accelerator* accelerator) OVERRIDE; 108 109 // Overridden from PrefixDelegate: 110 virtual int GetRowCount() OVERRIDE; 111 virtual int GetSelectedRow() OVERRIDE; 112 virtual void SetSelectedRow(int row) OVERRIDE; 113 virtual string16 GetTextForRow(int row) OVERRIDE; 114 115 // Overriden from ComboboxModelObserver: 116 virtual void OnModelChanged() OVERRIDE; 117 118 // Overriden from ButtonListener: 119 virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE; 120 121 private: 122 FRIEND_TEST_ALL_PREFIXES(ComboboxTest, Click); 123 FRIEND_TEST_ALL_PREFIXES(ComboboxTest, NotifyOnClickWithMouse); 124 125 // Updates the combobox's content from its model. 126 void UpdateFromModel(); 127 128 // Updates the border according to the current state. 129 void UpdateBorder(); 130 131 // Given bounds within our View, this helper mirrors the bounds if necessary. 132 void AdjustBoundsForRTLUI(gfx::Rect* rect) const; 133 134 // Draws the selected value of the drop down list 135 void PaintText(gfx::Canvas* canvas); 136 137 // Draws the button images. 138 void PaintButtons(gfx::Canvas* canvas); 139 140 // Show the drop down list 141 void ShowDropDownMenu(ui::MenuSourceType source_type); 142 143 // Called when the selection is changed by the user. 144 void OnSelectionChanged(); 145 146 // Converts a menu command ID to a menu item index. 147 int MenuCommandToIndex(int menu_command_id) const; 148 149 int GetDisclosureArrowLeftPadding() const; 150 int GetDisclosureArrowRightPadding() const; 151 152 // Handles the clicking event. 153 void HandleClickEvent(); 154 155 // Our model. Not owned. 156 ui::ComboboxModel* model_; 157 158 // The visual style of this combobox. 159 Style style_; 160 161 // Our listener. Not owned. Notified when the selected index change. 162 ComboboxListener* listener_; 163 164 // The current selected index; -1 and means no selection. 165 int selected_index_; 166 167 // True when the selection is visually denoted as invalid. 168 bool invalid_; 169 170 // The accessible name of this combobox. 171 string16 accessible_name_; 172 173 // A helper used to select entries by keyboard input. 174 scoped_ptr<PrefixSelector> selector_; 175 176 // The disclosure arrow next to the currently selected item from the list. 177 const gfx::ImageSkia* disclosure_arrow_; 178 179 // Responsible for showing the context menu. 180 scoped_ptr<MenuRunner> dropdown_list_menu_runner_; 181 182 // Is the drop down list showing 183 bool dropdown_open_; 184 185 // Like MenuButton, we use a time object in order to keep track of when the 186 // combobox was closed. The time is used for simulating menu behavior; that 187 // is, if the menu is shown and the button is pressed, we need to close the 188 // menu. There is no clean way to get the second click event because the 189 // menu is displayed using a modal loop and, unlike regular menus in Windows, 190 // the button is not part of the displayed menu. 191 base::Time closed_time_; 192 193 // The maximum dimensions of the content in the dropdown 194 gfx::Size content_size_; 195 196 // The painters or images that are used when |style_| is STYLE_BUTTONS. The 197 // first index means the state of unfocused or focused. 198 // The images are owned by ResourceBundle. 199 scoped_ptr<Painter> body_button_painters_[2][Button::STATE_COUNT]; 200 std::vector<const gfx::ImageSkia*> 201 menu_button_images_[2][Button::STATE_COUNT]; 202 203 // The transparent buttons to handle events and render buttons. These are 204 // placed on top of this combobox as child views, accept event and manage the 205 // button states. These are not rendered but when |style_| is 206 // STYLE_NOTIFY_ON_CLICK, a Combobox renders the button images according to 207 // these button states. 208 // The base View takes the ownerships of these as child views. 209 CustomButton* text_button_; 210 CustomButton* arrow_button_; 211 212 DISALLOW_COPY_AND_ASSIGN(Combobox); 213 }; 214 215 } // namespace views 216 217 #endif // UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_H_ 218