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