Home | History | Annotate | Download | only in gtk
      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