Home | History | Annotate | Download | only in gtk
      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/gtk/gtk_signal.h"
     16 #include "ui/base/gtk/owned_widget_gtk.h"
     17 #include "ui/gfx/animation/animation_delegate.h"
     18 #include "ui/gfx/animation/slide_animation.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 gfx::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 gfx::Animation* animation) OVERRIDE;
    121 
    122   CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnEnter,
    123                        GdkEventCrossing*);
    124   CHROMEGTK_CALLBACK_1(CustomDrawHoverController, gboolean, OnLeave,
    125                        GdkEventCrossing*);
    126 
    127   gfx::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