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
21class CairoCachedSurface;
22class GtkThemeService;
23class 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.
31class 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.
101class 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|.
129class 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