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