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