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 CHROME_BROWSER_UI_GTK_CUSTOM_BUTTON_H_ 6 #define CHROME_BROWSER_UI_GTK_CUSTOM_BUTTON_H_ 7 8 #include <gtk/gtk.h> 9 10 #include "base/compiler_specific.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "content/public/browser/notification_observer.h" 13 #include "content/public/browser/notification_registrar.h" 14 #include "third_party/skia/include/core/SkColor.h" 15 #include "ui/base/animation/animation_delegate.h" 16 #include "ui/base/animation/slide_animation.h" 17 #include "ui/base/gtk/gtk_signal.h" 18 #include "ui/base/gtk/owned_widget_gtk.h" 19 #include "ui/gfx/rect.h" 20 21 class GtkThemeService; 22 class SkBitmap; 23 24 namespace gfx { 25 class CairoCachedSurface; 26 } 27 28 // These classes implement two kinds of custom-drawn buttons. They're 29 // used on the toolbar and the bookmarks bar. 30 31 // CustomDrawButtonBase provides the base for building a custom drawn button. 32 // It handles managing the pixbufs containing all the static images used to draw 33 // the button. It also manages painting these pixbufs. 34 class CustomDrawButtonBase : public content::NotificationObserver { 35 public: 36 // If the images come from ResourceBundle rather than the theme provider, 37 // pass in NULL for |theme_provider|. 38 CustomDrawButtonBase(GtkThemeService* theme_provider, 39 int normal_id, 40 int pressed_id, 41 int hover_id, 42 int disabled_id); 43 44 virtual ~CustomDrawButtonBase(); 45 46 // Flip the image horizontally. Not to be used for RTL/LTR reasons. (In RTL 47 // mode, this will unflip the image.) 48 void set_flipped(bool flipped) { flipped_ = flipped; } 49 50 // Returns the dimensions of the first surface. 51 int Width() const; 52 int Height() const; 53 54 gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e, gdouble hover_state); 55 56 void set_paint_override(int state) { paint_override_ = state; } 57 int paint_override() const { return paint_override_; } 58 59 // Set the background details. 60 void SetBackground(SkColor color, 61 const SkBitmap& image, 62 const SkBitmap& mask); 63 64 // Provide content::NotificationObserver implementation. 65 virtual void Observe(int type, 66 const content::NotificationSource& source, 67 const content::NotificationDetails& details) OVERRIDE; 68 69 private: 70 // Get the CairoCachedSurface from |surfaces_| for |state|. 71 gfx::CairoCachedSurface* PixbufForState(int state); 72 73 // We store one surface for each possible state of the button; 74 // INSENSITIVE is the last available state; 75 scoped_ptr<gfx::CairoCachedSurface> surfaces_[GTK_STATE_INSENSITIVE + 1]; 76 77 // The background image. 78 scoped_ptr<gfx::CairoCachedSurface> background_image_; 79 80 // If non-negative, the state to paint the button. 81 int paint_override_; 82 83 // We need to remember the image ids that the user passes in and the theme 84 // provider so we can reload images if the user changes theme. 85 int normal_id_; 86 int pressed_id_; 87 int hover_id_; 88 int disabled_id_; 89 GtkThemeService* theme_service_; 90 91 // Whether the button is flipped horizontally. Not used for RTL (we get 92 // flipped versions from the theme provider). Used for the flipped window 93 // buttons. 94 bool flipped_; 95 96 // Used to listen for theme change notifications. 97 content::NotificationRegistrar registrar_; 98 99 DISALLOW_COPY_AND_ASSIGN(CustomDrawButtonBase); 100 }; 101 102 // CustomDrawHoverController is a convenience class that eases the common task 103 // of controlling the hover state of a button. The "hover state" refers to the 104 // percent opacity of a button's PRELIGHT. The PRELIGHT is animated such that 105 // when a user moves a mouse over a button the PRELIGHT fades in. 106 class CustomDrawHoverController : public ui::AnimationDelegate { 107 public: 108 explicit CustomDrawHoverController(GtkWidget* widget); 109 CustomDrawHoverController(); 110 111 virtual ~CustomDrawHoverController(); 112 113 void Init(GtkWidget* widget); 114 115 double GetCurrentValue() { 116 return slide_animation_.GetCurrentValue(); 117 } 118 119 private: 120 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; 121 122 CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnEnter, 123 GdkEventCrossing*); 124 CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnLeave, 125 GdkEventCrossing*); 126 127 ui::SlideAnimation slide_animation_; 128 GtkWidget* widget_; 129 }; 130 131 // CustomDrawButton is a plain button where all its various states are drawn 132 // with static images. In GTK rendering mode, it will show the standard button 133 // with GTK |stock_id|. 134 class CustomDrawButton : public content::NotificationObserver { 135 public: 136 // The constructor takes 4 resource ids. If a resource doesn't exist for a 137 // button, pass in 0. 138 CustomDrawButton(int normal_id, 139 int pressed_id, 140 int hover_id, 141 int disabled_id); 142 143 // Same as above, but uses themed (and possibly tinted) images. |stock_id| and 144 // |stock_size| are used for GTK+ theme mode. 145 CustomDrawButton(GtkThemeService* theme_provider, 146 int normal_id, 147 int pressed_id, 148 int hover_id, 149 int disabled_id, 150 const char* stock_id, 151 GtkIconSize stock_size); 152 153 // As above, but uses an arbitrary GtkImage rather than a stock icon. This 154 // constructor takes ownership of |native_widget|. 155 CustomDrawButton(GtkThemeService* theme_provider, 156 int normal_id, 157 int pressed_id, 158 int hover_id, 159 int disabled_id, 160 GtkWidget* native_widget); 161 162 virtual ~CustomDrawButton(); 163 164 void Init(); 165 166 // Make this CustomDrawButton always use the chrome style rendering; it will 167 // never render gtk-like. 168 void ForceChromeTheme(); 169 170 // Flip the image horizontally. Not to be used for RTL/LTR reasons. (In RTL 171 // mode, this will unflip the image.) 172 void set_flipped(bool flipped) { button_base_.set_flipped(flipped); } 173 174 GtkWidget* widget() const { return widget_.get(); } 175 176 // Returns the widget's allocation. 177 GtkAllocation WidgetAllocation() const; 178 179 // Returns the dimensions of the first surface. 180 int SurfaceWidth() const; 181 int SurfaceHeight() const; 182 183 // Set the state to draw. We will paint the widget as if it were in this 184 // state. 185 void SetPaintOverride(GtkStateType state); 186 187 // Resume normal drawing of the widget's state. 188 void UnsetPaintOverride(); 189 190 // Set the background details. 191 void SetBackground(SkColor color, 192 const SkBitmap& image, 193 const SkBitmap& mask); 194 195 // content::NotificationObserver implementation. 196 virtual void Observe(int type, 197 const content::NotificationSource& source, 198 const content::NotificationDetails& details) OVERRIDE; 199 200 // Returns a standard close button used for infobars and shelves (smaller 201 // with red hover). 202 // Pass a |theme_provider| to use Gtk icons in Gtk rendering mode. 203 static CustomDrawButton* CloseButtonBar(GtkThemeService* theme_provider); 204 205 // Returns a standard close button used for bubbles (larger). 206 // Pass a |theme_provider| to use Gtk icons in Gtk rendering mode. 207 static CustomDrawButton* CloseButtonBubble(GtkThemeService* theme_provider); 208 209 private: 210 // Sets the button to themed or not. 211 void SetBrowserTheme(); 212 213 // Whether to use the GTK+ theme. For this to be true, we have to be in GTK+ 214 // theme mode and we must have a valid stock icon resource. 215 bool UseGtkTheme(); 216 217 // Callback for custom button expose, used to draw the custom graphics. 218 CHROMEGTK_CALLBACK_1(CustomDrawButton, gboolean, OnCustomExpose, 219 GdkEventExpose*); 220 221 // The actual button widget. 222 ui::OwnedWidgetGtk widget_; 223 224 CustomDrawButtonBase button_base_; 225 226 CustomDrawHoverController hover_controller_; 227 228 // The widget to use when we are displaying in GTK+ theme mode. 229 ui::OwnedWidgetGtk native_widget_; 230 231 // Our theme provider. 232 GtkThemeService* theme_service_; 233 234 // True if we should never do gtk rendering. 235 bool forcing_chrome_theme_; 236 237 // Used to listen for theme change notifications. 238 content::NotificationRegistrar registrar_; 239 240 DISALLOW_COPY_AND_ASSIGN(CustomDrawButton); 241 }; 242 243 #endif // CHROME_BROWSER_UI_GTK_CUSTOM_BUTTON_H_ 244