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