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 //////////////////////////////////////////////////////////////////////////////// 24 // 25 // TextButtonBorder 26 // 27 // An abstract Border subclass for TextButtons that allows configurable insets 28 // for the button. 29 // 30 //////////////////////////////////////////////////////////////////////////////// 31 class 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 41 private: 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 //////////////////////////////////////////////////////////////////////////////// 63 class 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 //////////////////////////////////////////////////////////////////////////////// 97 class 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 //////////////////////////////////////////////////////////////////////////////// 123 class 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 //////////////////////////////////////////////////////////////////////////////// 323 class 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