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