Home | History | Annotate | Download | only in button
      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_BUTTON_TEXT_BUTTON_H_
      6 #define UI_VIEWS_CONTROLS_BUTTON_TEXT_BUTTON_H_
      7 
      8 #include <string>
      9 
     10 #include "base/compiler_specific.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/strings/string16.h"
     13 #include "third_party/skia/include/core/SkColor.h"
     14 #include "ui/gfx/font_list.h"
     15 #include "ui/gfx/image/image_skia.h"
     16 #include "ui/views/border.h"
     17 #include "ui/views/controls/button/custom_button.h"
     18 #include "ui/views/native_theme_delegate.h"
     19 #include "ui/views/painter.h"
     20 
     21 namespace views {
     22 
     23 // A Border subclass for TextButtons that allows configurable insets for the
     24 // button.
     25 class VIEWS_EXPORT TextButtonBorder : public Border {
     26  public:
     27   TextButtonBorder();
     28   virtual ~TextButtonBorder();
     29 
     30   void SetInsets(const gfx::Insets& insets);
     31 
     32   // Border:
     33   virtual void Paint(const View& view, gfx::Canvas* canvas) OVERRIDE;
     34   virtual gfx::Insets GetInsets() const OVERRIDE;
     35   virtual gfx::Size GetMinimumSize() const OVERRIDE;
     36 
     37  private:
     38   gfx::Insets insets_;
     39 
     40   DISALLOW_COPY_AND_ASSIGN(TextButtonBorder);
     41 };
     42 
     43 
     44 // A Border subclass that paints a TextButton's background layer -- basically
     45 // the button frame in the hot/pushed states.
     46 //
     47 // Note that this type of button is not focusable by default and will not be
     48 // part of the focus chain.  Call SetFocusable(true) to make it part of the
     49 // focus chain.
     50 class VIEWS_EXPORT TextButtonDefaultBorder : public TextButtonBorder {
     51  public:
     52   TextButtonDefaultBorder();
     53   virtual ~TextButtonDefaultBorder();
     54 
     55   // TextButtonDefaultBorder takes and retains ownership of these |painter|s.
     56   void set_normal_painter(Painter* painter) { normal_painter_.reset(painter); }
     57   void set_hot_painter(Painter* painter) { hot_painter_.reset(painter); }
     58   void set_pushed_painter(Painter* painter) { pushed_painter_.reset(painter); }
     59 
     60  private:
     61   // TextButtonBorder:
     62   virtual void Paint(const View& view, gfx::Canvas* canvas) OVERRIDE;
     63   virtual gfx::Size GetMinimumSize() const OVERRIDE;
     64 
     65   scoped_ptr<Painter> normal_painter_;
     66   scoped_ptr<Painter> hot_painter_;
     67   scoped_ptr<Painter> pushed_painter_;
     68 
     69   int vertical_padding_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(TextButtonDefaultBorder);
     72 };
     73 
     74 
     75 // A Border subclass that paints a TextButton's background layer using the
     76 // platform's native theme look.  This handles normal/disabled/hot/pressed
     77 // states, with possible animation between states.
     78 class VIEWS_EXPORT TextButtonNativeThemeBorder : public TextButtonBorder {
     79  public:
     80   explicit TextButtonNativeThemeBorder(NativeThemeDelegate* delegate);
     81   virtual ~TextButtonNativeThemeBorder();
     82 
     83   // TextButtonBorder:
     84   virtual void Paint(const View& view, gfx::Canvas* canvas) OVERRIDE;
     85   // We don't override GetMinimumSize(), since there's no easy way to calculate
     86   // the minimum size required by the various theme components.
     87 
     88  private:
     89   // The delegate the controls the appearance of this border.
     90   NativeThemeDelegate* delegate_;
     91 
     92   DISALLOW_COPY_AND_ASSIGN(TextButtonNativeThemeBorder);
     93 };
     94 
     95 
     96 // A base class for different types of buttons, like push buttons, radio
     97 // buttons, and checkboxes, that do not depend on native components for look and
     98 // feel. TextButton reserves space for the largest string passed to SetText. To
     99 // reset the cached max size invoke ClearMaxTextSize.
    100 class VIEWS_EXPORT TextButtonBase : public CustomButton,
    101                                     public NativeThemeDelegate {
    102  public:
    103   // The menu button's class name.
    104   static const char kViewClassName[];
    105 
    106   virtual ~TextButtonBase();
    107 
    108   // Call SetText once per string in your set of possible values at button
    109   // creation time, so that it can contain the largest of them and avoid
    110   // resizing the button when the text changes.
    111   virtual void SetText(const base::string16& text);
    112   const base::string16& text() const { return text_; }
    113 
    114   enum TextAlignment {
    115     ALIGN_LEFT,
    116     ALIGN_CENTER,
    117     ALIGN_RIGHT
    118   };
    119 
    120   void set_alignment(TextAlignment alignment) { alignment_ = alignment; }
    121 
    122   const gfx::Animation* GetAnimation() const;
    123 
    124   void SetIsDefault(bool is_default);
    125   bool is_default() const { return is_default_; }
    126 
    127   // Set whether the button text can wrap on multiple lines.
    128   // Default is false.
    129   void SetMultiLine(bool multi_line);
    130 
    131   // Return whether the button text can wrap on multiple lines.
    132   bool multi_line() const { return multi_line_; }
    133 
    134   // TextButton remembers the maximum display size of the text passed to
    135   // SetText. This method resets the cached maximum display size to the
    136   // current size.
    137   void ClearMaxTextSize();
    138 
    139   void set_min_width(int min_width) { min_width_ = min_width; }
    140   void set_min_height(int min_height) { min_height_ = min_height; }
    141   void set_max_width(int max_width) { max_width_ = max_width; }
    142   const gfx::FontList& font_list() const { return font_list_; }
    143   void SetFontList(const gfx::FontList& font_list);
    144 
    145   void SetEnabledColor(SkColor color);
    146   void SetDisabledColor(SkColor color);
    147   void SetHighlightColor(SkColor color);
    148   void SetHoverColor(SkColor color);
    149 
    150   // Sets whether or not to show the hot and pushed states for the button icon
    151   // (if present) in addition to the normal state.  Defaults to true.
    152   bool show_multiple_icon_states() const { return show_multiple_icon_states_; }
    153   void SetShowMultipleIconStates(bool show_multiple_icon_states);
    154 
    155   void SetFocusPainter(scoped_ptr<Painter> focus_painter);
    156   Painter* focus_painter() { return focus_painter_.get(); }
    157 
    158   // Paint the button into the specified canvas. If |mode| is |PB_FOR_DRAG|, the
    159   // function paints a drag image representation into the canvas.
    160   enum PaintButtonMode { PB_NORMAL, PB_FOR_DRAG };
    161   virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode);
    162 
    163   // Overridden from View:
    164   virtual gfx::Size GetPreferredSize() const OVERRIDE;
    165   virtual gfx::Size GetMinimumSize() const OVERRIDE;
    166   virtual int GetHeightForWidth(int w) const OVERRIDE;
    167   virtual void OnEnabledChanged() OVERRIDE;
    168   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
    169   virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
    170   virtual const char* GetClassName() const OVERRIDE;
    171   virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
    172 
    173  protected:
    174   TextButtonBase(ButtonListener* listener, const base::string16& text);
    175 
    176   // Called when enabled or disabled state changes, or the colors for those
    177   // states change.
    178   virtual void UpdateColor();
    179 
    180   // Updates text_size_ and max_text_size_ from the current text/font. This is
    181   // invoked when the font list or text changes.
    182   void UpdateTextSize();
    183 
    184   // Calculate the size of the text size without setting any of the members.
    185   void CalculateTextSize(gfx::Size* text_size, int max_width) const;
    186 
    187   // Paint the button's text into the specified canvas. If |mode| is
    188   // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
    189   // can override this function to change only the text rendering.
    190   virtual void OnPaintText(gfx::Canvas* canvas, PaintButtonMode mode);
    191 
    192   void set_color_enabled(SkColor color) { color_enabled_ = color; }
    193   void set_color_disabled(SkColor color) { color_disabled_ = color; }
    194   void set_color_hover(SkColor color) { color_hover_ = color; }
    195 
    196   bool use_enabled_color_from_theme() const {
    197     return use_enabled_color_from_theme_;
    198   }
    199 
    200   bool use_disabled_color_from_theme() const {
    201     return use_disabled_color_from_theme_;
    202   }
    203 
    204   bool use_hover_color_from_theme() const {
    205     return use_hover_color_from_theme_;
    206   }
    207 
    208   // Overridden from NativeThemeDelegate:
    209   virtual gfx::Rect GetThemePaintRect() const OVERRIDE;
    210   virtual ui::NativeTheme::State GetThemeState(
    211       ui::NativeTheme::ExtraParams* params) const OVERRIDE;
    212   virtual const gfx::Animation* GetThemeAnimation() const OVERRIDE;
    213   virtual ui::NativeTheme::State GetBackgroundThemeState(
    214       ui::NativeTheme::ExtraParams* params) const OVERRIDE;
    215   virtual ui::NativeTheme::State GetForegroundThemeState(
    216       ui::NativeTheme::ExtraParams* params) const OVERRIDE;
    217 
    218   // Overridden from View:
    219   virtual void OnFocus() OVERRIDE;
    220   virtual void OnBlur() OVERRIDE;
    221 
    222   virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const;
    223 
    224   virtual gfx::Rect GetTextBounds() const;
    225 
    226   int ComputeCanvasStringFlags() const;
    227 
    228   // Calculate the bounds of the content of this button, including any extra
    229   // width needed on top of the text width.
    230   gfx::Rect GetContentBounds(int extra_width) const;
    231 
    232   // The text string that is displayed in the button.
    233   base::string16 text_;
    234 
    235   // The size of the text string.
    236   mutable gfx::Size text_size_;
    237 
    238   // Track the size of the largest text string seen so far, so that
    239   // changing text_ will not resize the button boundary.
    240   gfx::Size max_text_size_;
    241 
    242   // The alignment of the text string within the button.
    243   TextAlignment alignment_;
    244 
    245   // The font list used to paint the text.
    246   gfx::FontList font_list_;
    247 
    248   // The dimensions of the button will be at least these values.
    249   int min_width_;
    250   int min_height_;
    251 
    252   // The width of the button will never be larger than this value. A value <= 0
    253   // indicates the width is not constrained.
    254   int max_width_;
    255 
    256   // Whether or not to show the hot and pushed icon states.
    257   bool show_multiple_icon_states_;
    258 
    259   // Whether or not the button appears and behaves as the default button in its
    260   // current context.
    261   bool is_default_;
    262 
    263   // Whether the text button should handle its text string as multi-line.
    264   bool multi_line_;
    265 
    266  private:
    267   // Text color.
    268   SkColor color_;
    269 
    270   // State colors.
    271   SkColor color_enabled_;
    272   SkColor color_disabled_;
    273   SkColor color_highlight_;
    274   SkColor color_hover_;
    275 
    276   // True if the specified color should be used from the theme.
    277   bool use_enabled_color_from_theme_;
    278   bool use_disabled_color_from_theme_;
    279   bool use_highlight_color_from_theme_;
    280   bool use_hover_color_from_theme_;
    281 
    282   scoped_ptr<Painter> focus_painter_;
    283 
    284   DISALLOW_COPY_AND_ASSIGN(TextButtonBase);
    285 };
    286 
    287 
    288 // A button which displays text and/or and icon that can be changed in response
    289 // to actions. TextButton reserves space for the largest string passed to
    290 // SetText. To reset the cached max size invoke ClearMaxTextSize.
    291 class VIEWS_EXPORT TextButton : public TextButtonBase {
    292  public:
    293   // The button's class name.
    294   static const char kViewClassName[];
    295 
    296   TextButton(ButtonListener* listener, const base::string16& text);
    297   virtual ~TextButton();
    298 
    299   void set_icon_text_spacing(int icon_text_spacing) {
    300     icon_text_spacing_ = icon_text_spacing;
    301   }
    302 
    303   // Sets the icon.
    304   virtual void SetIcon(const gfx::ImageSkia& icon);
    305   virtual void SetHoverIcon(const gfx::ImageSkia& icon);
    306   virtual void SetPushedIcon(const gfx::ImageSkia& icon);
    307 
    308   bool HasIcon() const { return !icon_.isNull(); }
    309 
    310   // Meanings are reversed for right-to-left layouts.
    311   enum IconPlacement {
    312     ICON_ON_LEFT,
    313     ICON_ON_RIGHT,
    314     ICON_CENTERED  // Centered is valid only when text is empty.
    315   };
    316 
    317   IconPlacement icon_placement() { return icon_placement_; }
    318   void set_icon_placement(IconPlacement icon_placement) {
    319     // ICON_CENTERED works only when |text_| is empty.
    320     DCHECK((icon_placement != ICON_CENTERED) || text_.empty());
    321     icon_placement_ = icon_placement;
    322   }
    323 
    324   void set_ignore_minimum_size(bool ignore_minimum_size);
    325 
    326   void set_full_justification(bool full_justification);
    327 
    328   // Overridden from View:
    329   virtual gfx::Size GetPreferredSize() const OVERRIDE;
    330   virtual const char* GetClassName() const OVERRIDE;
    331 
    332   // Overridden from TextButtonBase:
    333   virtual void PaintButton(gfx::Canvas* canvas, PaintButtonMode mode) OVERRIDE;
    334 
    335  protected:
    336   // Paint the button's icon into the specified canvas. If |mode| is
    337   // |PB_FOR_DRAG|, the function paints a drag image representation. Derived
    338   // can override this function to change only the icon rendering.
    339   virtual void OnPaintIcon(gfx::Canvas* canvas, PaintButtonMode mode);
    340 
    341   gfx::ImageSkia icon() const { return icon_; }
    342 
    343   virtual const gfx::ImageSkia& GetImageToPaint() const;
    344 
    345   // Overridden from NativeThemeDelegate:
    346   virtual ui::NativeTheme::Part GetThemePart() const OVERRIDE;
    347 
    348   // Overridden from TextButtonBase:
    349   virtual void GetExtraParams(
    350       ui::NativeTheme::ExtraParams* params) const OVERRIDE;
    351   virtual gfx::Rect GetTextBounds() const OVERRIDE;
    352 
    353  private:
    354   // The position of the icon.
    355   IconPlacement icon_placement_;
    356 
    357   // An icon displayed with the text.
    358   gfx::ImageSkia icon_;
    359 
    360   // An optional different version of the icon for hover state.
    361   gfx::ImageSkia icon_hover_;
    362   bool has_hover_icon_;
    363 
    364   // An optional different version of the icon for pushed state.
    365   gfx::ImageSkia icon_pushed_;
    366   bool has_pushed_icon_;
    367 
    368   // Space between icon and text.
    369   int icon_text_spacing_;
    370 
    371   // True if the button should ignore the minimum size for the platform. Default
    372   // is true. Set to false to prevent narrower buttons.
    373   bool ignore_minimum_size_;
    374 
    375   // True if the icon and the text are aligned along both the left and right
    376   // margins of the button.
    377   bool full_justification_;
    378 
    379   DISALLOW_COPY_AND_ASSIGN(TextButton);
    380 };
    381 
    382 }  // namespace views
    383 
    384 #endif  // UI_VIEWS_CONTROLS_BUTTON_TEXT_BUTTON_H_
    385