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