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