]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererspinner.c
gtkcellrendererspinner: Remove GET_PRIV() macro
[~andy/gtk] / gtk / gtkcellrendererspinner.c
1 /* GTK - The GIMP Toolkit
2  *
3  * Copyright (C) 2009 Matthias Clasen <mclasen@redhat.com>
4  * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
5  * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA  02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 2007.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28  */
29
30 #include "config.h"
31
32 #include "gtkcellrendererspinner.h"
33 #include "gtkiconfactory.h"
34 #include "gtkicontheme.h"
35 #include "gtkintl.h"
36
37
38 /**
39  * SECTION:gtkcellrendererspinner
40  * @Short_description: Renders a spinning animation in a cell
41  * @Title: GtkCellRendererSpinner
42  * @See_also: #GtkSpinner, #GtkCellRendererProgress
43  *
44  * GtkCellRendererSpinner renders a spinning animation in a cell, very
45  * similar to #GtkSpinner. It can often be used as an alternative
46  * to a #GtkCellRendererProgress for displaying indefinite activity,
47  * instead of actual progress.
48  *
49  * To start the animation in a cell, set the #GtkCellRendererSpinner:active
50  * property to %TRUE and increment the #GtkCellRendererSpinner:pulse property
51  * at regular intervals. The usual way to set the cell renderer properties
52  * for each cell is to bind them to columns in your tree model using e.g.
53  * gtk_tree_view_column_add_attribute().
54  */
55
56
57 enum {
58   PROP_0,
59   PROP_ACTIVE,
60   PROP_PULSE,
61   PROP_SIZE
62 };
63
64 struct _GtkCellRendererSpinnerPrivate
65 {
66   gboolean active;
67   guint pulse;
68   GtkIconSize icon_size, old_icon_size;
69   gint size;
70 };
71
72
73 static void gtk_cell_renderer_spinner_get_property (GObject         *object,
74                                                     guint            param_id,
75                                                     GValue          *value,
76                                                     GParamSpec      *pspec);
77 static void gtk_cell_renderer_spinner_set_property (GObject         *object,
78                                                     guint            param_id,
79                                                     const GValue    *value,
80                                                     GParamSpec      *pspec);
81 static void gtk_cell_renderer_spinner_get_size     (GtkCellRenderer *cell,
82                                                     GtkWidget       *widget,
83                                                     GdkRectangle    *cell_area,
84                                                     gint            *x_offset,
85                                                     gint            *y_offset,
86                                                     gint            *width,
87                                                     gint            *height);
88 static void gtk_cell_renderer_spinner_render       (GtkCellRenderer *cell,
89                                                     GdkWindow       *window,
90                                                     GtkWidget       *widget,
91                                                     GdkRectangle    *background_area,
92                                                     GdkRectangle    *cell_area,
93                                                     GdkRectangle    *expose_area,
94                                                     guint            flags);
95
96 G_DEFINE_TYPE (GtkCellRendererSpinner, gtk_cell_renderer_spinner, GTK_TYPE_CELL_RENDERER)
97
98 static void
99 gtk_cell_renderer_spinner_class_init (GtkCellRendererSpinnerClass *klass)
100 {
101   GObjectClass *object_class = G_OBJECT_CLASS (klass);
102   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
103
104   object_class->get_property = gtk_cell_renderer_spinner_get_property;
105   object_class->set_property = gtk_cell_renderer_spinner_set_property;
106
107   cell_class->get_size = gtk_cell_renderer_spinner_get_size;
108   cell_class->render = gtk_cell_renderer_spinner_render;
109
110   /* GtkCellRendererSpinner:active:
111    *
112    * Whether the spinner is active (ie. shown) in the cell
113    *
114    * Since: 2.20
115    */
116   g_object_class_install_property (object_class,
117                                    PROP_ACTIVE,
118                                    g_param_spec_boolean ("active",
119                                                          P_("Active"),
120                                                          P_("Whether the spinner is active (ie. shown) in the cell"),
121                                                          FALSE,
122                                                          G_PARAM_READWRITE));
123   /**
124    * GtkCellRendererSpinner:pulse:
125    *
126    * Pulse of the spinner. Increment this value to draw the next frame of the
127    * spinner animation. Usually, you would update this value in a timeout.
128    *
129    * The #GtkSpinner widget draws one full cycle of the animation per second by default.
130    * You can learn about the number of frames used by the theme
131    * by looking at the #GtkSpinner:num-steps style property and the duration
132    * of the cycle by looking at #GtkSpinner:cycle-duration.
133    *
134    * Since: 2.20
135    */
136   g_object_class_install_property (object_class,
137                                    PROP_PULSE,
138                                    g_param_spec_uint ("pulse",
139                                                       P_("Pulse"),
140                                                       P_("Pulse of the spinner"),
141                                                       0, G_MAXUINT, 0,
142                                                       G_PARAM_READWRITE));
143   /**
144    * GtkCellRendererSpinner:size:
145    *
146    * The #GtkIconSize value that specifies the size of the rendered spinner.
147    *
148    * Since: 2.20
149    */
150   g_object_class_install_property (object_class,
151                                    PROP_SIZE,
152                                    g_param_spec_enum ("size",
153                                                       P_("Size"),
154                                                       P_("The GtkIconSize value that specifies the size of the rendered spinner"),
155                                                       GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_MENU,
156                                                       G_PARAM_READWRITE));
157
158
159   g_type_class_add_private (object_class, sizeof (GtkCellRendererSpinnerPrivate));
160 }
161
162 static void
163 gtk_cell_renderer_spinner_init (GtkCellRendererSpinner *cell)
164 {
165   cell->priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
166                                             GTK_TYPE_CELL_RENDERER_SPINNER,
167                                             GtkCellRendererSpinnerPrivate);
168
169   cell->priv->pulse = 0;
170   cell->priv->old_icon_size = GTK_ICON_SIZE_INVALID;
171   cell->priv->icon_size = GTK_ICON_SIZE_MENU;
172 }
173
174 /**
175  * gtk_cell_renderer_spinner_new
176  *
177  * Returns a new cell renderer which will show a spinner to indicate
178  * activity.
179  *
180  * Return value: a new #GtkCellRenderer
181  *
182  * Since: 2.20
183  */
184 GtkCellRenderer *
185 gtk_cell_renderer_spinner_new (void)
186 {
187   return g_object_new (GTK_TYPE_CELL_RENDERER_SPINNER, NULL);
188 }
189
190 static void
191 gtk_cell_renderer_spinner_update_size (GtkCellRendererSpinner *cell,
192                                        GtkWidget              *widget)
193 {
194   GtkCellRendererSpinnerPrivate *priv = cell->priv;
195   GdkScreen *screen;
196   GtkIconTheme *icon_theme;
197   GtkSettings *settings;
198
199   if (cell->priv->old_icon_size == cell->priv->icon_size)
200     return;
201
202   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
203   icon_theme = gtk_icon_theme_get_for_screen (screen);
204   settings = gtk_settings_get_for_screen (screen);
205
206   if (!gtk_icon_size_lookup_for_settings (settings, priv->icon_size, &priv->size, NULL))
207     {
208       g_warning ("Invalid icon size %u\n", priv->icon_size);
209       priv->size = 24;
210     }
211 }
212
213 static void
214 gtk_cell_renderer_spinner_get_property (GObject    *object,
215                                         guint       param_id,
216                                         GValue     *value,
217                                         GParamSpec *pspec)
218 {
219   GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
220   GtkCellRendererSpinnerPrivate *priv = cell->priv;
221
222   switch (param_id)
223     {
224       case PROP_ACTIVE:
225         g_value_set_boolean (value, priv->active);
226         break;
227       case PROP_PULSE:
228         g_value_set_uint (value, priv->pulse);
229         break;
230       case PROP_SIZE:
231         g_value_set_enum (value, priv->icon_size);
232         break;
233       default:
234         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
235     }
236 }
237
238 static void
239 gtk_cell_renderer_spinner_set_property (GObject      *object,
240                                         guint         param_id,
241                                         const GValue *value,
242                                         GParamSpec   *pspec)
243 {
244   GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
245   GtkCellRendererSpinnerPrivate *priv = cell->priv;
246
247   switch (param_id)
248     {
249       case PROP_ACTIVE:
250         priv->active = g_value_get_boolean (value);
251         break;
252       case PROP_PULSE:
253         priv->pulse = g_value_get_uint (value);
254         break;
255       case PROP_SIZE:
256         priv->old_icon_size = priv->icon_size;
257         priv->icon_size = g_value_get_enum (value);
258         break;
259       default:
260         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
261     }
262 }
263
264 static void
265 gtk_cell_renderer_spinner_get_size (GtkCellRenderer *cellr,
266                                     GtkWidget       *widget,
267                                     GdkRectangle    *cell_area,
268                                     gint            *x_offset,
269                                     gint            *y_offset,
270                                     gint            *width,
271                                     gint            *height)
272 {
273   GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
274   GtkCellRendererSpinnerPrivate *priv = cell->priv;
275   gdouble align;
276   gint w, h;
277   gint xpad, ypad;
278   gfloat xalign, yalign;
279   gboolean rtl;
280
281   rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
282
283   gtk_cell_renderer_spinner_update_size (cell, widget);
284
285   g_object_get (cellr,
286                 "xpad", &xpad,
287                 "ypad", &ypad,
288                 "xalign", &xalign,
289                 "yalign", &yalign,
290                 NULL);
291   w = h = priv->size;
292
293   if (cell_area)
294     {
295       if (x_offset)
296         {
297           align = rtl ? 1.0 - xalign : xalign;
298           *x_offset = align * (cell_area->width - w);
299           *x_offset = MAX (*x_offset, 0);
300         }
301       if (y_offset)
302         {
303           align = rtl ? 1.0 - yalign : yalign;
304           *y_offset = align * (cell_area->height - h);
305           *y_offset = MAX (*y_offset, 0);
306         }
307     }
308   else
309     {
310       if (x_offset)
311         *x_offset = 0;
312       if (y_offset)
313         *y_offset = 0;
314     }
315
316   if (width)
317     *width = w;
318   if (height)
319     *height = h;
320 }
321
322 static void
323 gtk_cell_renderer_spinner_render (GtkCellRenderer *cellr,
324                                   GdkWindow       *window,
325                                   GtkWidget       *widget,
326                                   GdkRectangle    *background_area,
327                                   GdkRectangle    *cell_area,
328                                   GdkRectangle    *expose_area,
329                                   guint            flags)
330 {
331   GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
332   GtkCellRendererSpinnerPrivate *priv = cell->priv;
333   GtkStateType state;
334   GdkRectangle pix_rect;
335   GdkRectangle draw_rect;
336   gint xpad, ypad;
337
338   if (!priv->active)
339     return;
340
341   gtk_cell_renderer_spinner_get_size (cellr, widget, cell_area,
342                                       &pix_rect.x, &pix_rect.y,
343                                       &pix_rect.width, &pix_rect.height);
344
345   g_object_get (cellr,
346                 "xpad", &xpad,
347                 "ypad", &ypad,
348                 NULL);
349   pix_rect.x += cell_area->x + xpad;
350   pix_rect.y += cell_area->y + ypad;
351   pix_rect.width -= xpad * 2;
352   pix_rect.height -= ypad * 2;
353
354   if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) ||
355       !gdk_rectangle_intersect (expose_area, &pix_rect, &draw_rect))
356     {
357       return;
358     }
359
360   state = GTK_STATE_NORMAL;
361   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE ||
362       !gtk_cell_renderer_get_sensitive (cellr))
363     {
364       state = GTK_STATE_INSENSITIVE;
365     }
366   else
367     {
368       if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
369         {
370           if (gtk_widget_has_focus (widget))
371             state = GTK_STATE_SELECTED;
372           else
373             state = GTK_STATE_ACTIVE;
374         }
375       else
376         state = GTK_STATE_PRELIGHT;
377     }
378
379   gtk_paint_spinner (widget->style,
380                      window,
381                      state,
382                      expose_area,
383                      widget,
384                      "cell",
385                      priv->pulse,
386                      draw_rect.x, draw_rect.y,
387                      draw_rect.width, draw_rect.height);
388 }