]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererspin.c
Merge branch 'master' into native-layout
[~andy/gtk] / gtk / gtkcellrendererspin.c
1 /* GtkCellRendererSpin
2  * Copyright (C) 2004 Lorenzo Gil Sanchez
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Authors: Lorenzo Gil Sanchez    <lgs@sicem.biz>
20  *          Carlos Garnacho Parro  <carlosg@gnome.org>
21  */
22
23 #include "config.h"
24 #include <gdk/gdkkeysyms.h>
25 #include "gtkintl.h"
26 #include "gtkprivate.h"
27 #include "gtkspinbutton.h"
28 #include "gtkcellrendererspin.h"
29 #include "gtkalias.h"
30
31 #define GTK_CELL_RENDERER_SPIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_RENDERER_SPIN, GtkCellRendererSpinPrivate))
32
33 struct _GtkCellRendererSpinPrivate
34 {
35   GtkAdjustment *adjustment;
36   gdouble climb_rate;
37   guint   digits;
38 };
39
40 static void gtk_cell_renderer_spin_finalize   (GObject                  *object);
41
42 static void gtk_cell_renderer_spin_get_property (GObject      *object,
43                                                  guint         prop_id,
44                                                  GValue       *value,
45                                                  GParamSpec   *spec);
46 static void gtk_cell_renderer_spin_set_property (GObject      *object,
47                                                  guint         prop_id,
48                                                  const GValue *value,
49                                                  GParamSpec   *spec);
50
51 static GtkCellEditable * gtk_cell_renderer_spin_start_editing (GtkCellRenderer     *cell,
52                                                                GdkEvent            *event,
53                                                                GtkWidget           *widget,
54                                                                const gchar         *path,
55                                                                GdkRectangle        *background_area,
56                                                                GdkRectangle        *cell_area,
57                                                                GtkCellRendererState flags);
58 enum {
59   PROP_0,
60   PROP_ADJUSTMENT,
61   PROP_CLIMB_RATE,
62   PROP_DIGITS
63 };
64
65 #define GTK_CELL_RENDERER_SPIN_PATH "gtk-cell-renderer-spin-path"
66
67 G_DEFINE_TYPE (GtkCellRendererSpin, gtk_cell_renderer_spin, GTK_TYPE_CELL_RENDERER_TEXT)
68
69
70 static void
71 gtk_cell_renderer_spin_class_init (GtkCellRendererSpinClass *klass)
72 {
73   GObjectClass *object_class = G_OBJECT_CLASS (klass);
74   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
75
76   object_class->finalize     = gtk_cell_renderer_spin_finalize;
77   object_class->get_property = gtk_cell_renderer_spin_get_property;
78   object_class->set_property = gtk_cell_renderer_spin_set_property;
79
80   cell_class->start_editing  = gtk_cell_renderer_spin_start_editing;
81
82   /**
83    * GtkCellRendererSpin:adjustment:
84    *
85    * The adjustment that holds the value of the spinbutton. 
86    * This must be non-%NULL for the cell renderer to be editable.
87    *
88    * Since: 2.10
89    */
90   g_object_class_install_property (object_class,
91                                    PROP_ADJUSTMENT,
92                                    g_param_spec_object ("adjustment",
93                                                         P_("Adjustment"),
94                                                         P_("The adjustment that holds the value of the spinbutton."),
95                                                         GTK_TYPE_ADJUSTMENT,
96                                                         GTK_PARAM_READWRITE));
97
98
99   /**
100    * GtkCellRendererSpin:climb-rate:
101    *
102    * The acceleration rate when you hold down a button.
103    *
104    * Since: 2.10
105    */
106   g_object_class_install_property (object_class,
107                                    PROP_CLIMB_RATE,
108                                    g_param_spec_double ("climb-rate",
109                                                         P_("Climb rate"),
110                                                         P_("The acceleration rate when you hold down a button"),
111                                                         0.0, G_MAXDOUBLE, 0.0,
112                                                         GTK_PARAM_READWRITE));  
113   /**
114    * GtkCellRendererSpin:digits:
115    *
116    * The number of decimal places to display.
117    *
118    * Since: 2.10
119    */
120   g_object_class_install_property (object_class,
121                                    PROP_DIGITS,
122                                    g_param_spec_uint ("digits",
123                                                       P_("Digits"),
124                                                       P_("The number of decimal places to display"),
125                                                       0, 20, 0,
126                                                       GTK_PARAM_READWRITE));  
127
128   g_type_class_add_private (object_class, sizeof (GtkCellRendererSpinPrivate));
129 }
130
131 static void
132 gtk_cell_renderer_spin_init (GtkCellRendererSpin *self)
133 {
134   GtkCellRendererSpinPrivate *priv;
135
136   priv = GTK_CELL_RENDERER_SPIN_GET_PRIVATE (self);
137
138   priv->adjustment = NULL;
139   priv->climb_rate = 0.0;
140   priv->digits = 0;
141 }
142
143 static void
144 gtk_cell_renderer_spin_finalize (GObject *object)
145 {
146   GtkCellRendererSpinPrivate *priv;
147
148   priv = GTK_CELL_RENDERER_SPIN_GET_PRIVATE (object);
149
150   if (priv && priv->adjustment)
151     g_object_unref (priv->adjustment);
152
153   G_OBJECT_CLASS (gtk_cell_renderer_spin_parent_class)->finalize (object);
154 }
155
156 static void
157 gtk_cell_renderer_spin_get_property (GObject      *object,
158                                      guint         prop_id,
159                                      GValue       *value,
160                                      GParamSpec   *pspec)
161 {
162   GtkCellRendererSpin *renderer;
163   GtkCellRendererSpinPrivate *priv;
164
165   renderer = GTK_CELL_RENDERER_SPIN (object);
166   priv = GTK_CELL_RENDERER_SPIN_GET_PRIVATE (renderer);
167
168   switch (prop_id)
169     {
170     case PROP_ADJUSTMENT:
171       g_value_set_object (value, priv->adjustment);
172       break;
173     case PROP_CLIMB_RATE:
174       g_value_set_double (value, priv->climb_rate);
175       break;
176     case PROP_DIGITS:
177       g_value_set_uint (value, priv->digits);
178       break;
179     default:
180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181       break;
182     }
183 }
184
185 static void
186 gtk_cell_renderer_spin_set_property (GObject      *object,
187                                      guint         prop_id,
188                                      const GValue *value,
189                                      GParamSpec   *pspec)
190 {
191   GtkCellRendererSpin *renderer;
192   GtkCellRendererSpinPrivate *priv;
193   GObject *obj;
194
195   renderer = GTK_CELL_RENDERER_SPIN (object);
196   priv = GTK_CELL_RENDERER_SPIN_GET_PRIVATE (renderer);
197
198   switch (prop_id)
199     {
200     case PROP_ADJUSTMENT:
201       obj = g_value_get_object (value);
202
203       if (priv->adjustment)
204         {
205           g_object_unref (priv->adjustment);
206           priv->adjustment = NULL;
207         }
208
209       if (obj)
210         priv->adjustment = g_object_ref_sink (obj);
211       break;
212     case PROP_CLIMB_RATE:
213       priv->climb_rate = g_value_get_double (value);
214       break;
215     case PROP_DIGITS:
216       priv->digits = g_value_get_uint (value);
217       break;
218     default:
219       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220       break;
221     }
222 }
223
224 static gboolean
225 gtk_cell_renderer_spin_focus_out_event (GtkWidget *widget,
226                                         GdkEvent  *event,
227                                         gpointer   data)
228 {
229   const gchar *path;
230   const gchar *new_text;
231   gboolean canceled;
232
233   g_object_get (widget,
234                 "editing-canceled", &canceled,
235                 NULL);
236
237   g_signal_handlers_disconnect_by_func (widget,
238                                         gtk_cell_renderer_spin_focus_out_event,
239                                         data);
240
241   gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
242
243   if (!canceled)
244     {
245       path = g_object_get_data (G_OBJECT (widget), GTK_CELL_RENDERER_SPIN_PATH);
246
247       new_text = gtk_entry_get_text (GTK_ENTRY (widget));
248       g_signal_emit_by_name (data, "edited", path, new_text);
249     }
250   
251   return FALSE;
252 }
253
254 static gboolean
255 gtk_cell_renderer_spin_key_press_event (GtkWidget   *widget,
256                                         GdkEventKey *event,
257                                         gpointer     data)
258 {
259   if (event->state == 0)
260     {
261       if (event->keyval == GDK_Up)
262         {
263           gtk_spin_button_spin (GTK_SPIN_BUTTON (widget), GTK_SPIN_STEP_FORWARD, 1);
264           return TRUE;
265         }
266       else if (event->keyval == GDK_Down)
267         {
268           gtk_spin_button_spin (GTK_SPIN_BUTTON (widget), GTK_SPIN_STEP_BACKWARD, 1);
269           return TRUE;
270         }
271     }
272
273   return FALSE;
274 }
275
276 static gboolean
277 gtk_cell_renderer_spin_button_press_event (GtkWidget      *widget,
278                                            GdkEventButton *event,
279                                            gpointer        user_data)
280 {
281   /* Block 2BUTTON and 3BUTTON here, so that they won't be eaten
282    * by tree view.
283    */
284   if (event->type == GDK_2BUTTON_PRESS
285       || event->type == GDK_3BUTTON_PRESS)
286     return TRUE;
287
288   return FALSE;
289 }
290
291 static GtkCellEditable *
292 gtk_cell_renderer_spin_start_editing (GtkCellRenderer     *cell,
293                                       GdkEvent            *event,
294                                       GtkWidget           *widget,
295                                       const gchar         *path,
296                                       GdkRectangle        *background_area,
297                                       GdkRectangle        *cell_area,
298                                       GtkCellRendererState flags)
299 {
300   GtkCellRendererSpinPrivate *priv;
301   GtkCellRendererText *cell_text;
302   GtkWidget *spin;
303
304   cell_text = GTK_CELL_RENDERER_TEXT (cell);
305   priv = GTK_CELL_RENDERER_SPIN_GET_PRIVATE (cell);
306
307   if (!cell_text->editable)
308     return NULL;
309
310   if (!priv->adjustment)
311     return NULL;
312
313   spin = gtk_spin_button_new (priv->adjustment,
314                               priv->climb_rate, priv->digits);
315
316   g_signal_connect (spin, "button-press-event",
317                     G_CALLBACK (gtk_cell_renderer_spin_button_press_event),
318                     NULL);
319
320   if (cell_text->text)
321     gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin),
322                                g_ascii_strtod (cell_text->text, NULL));
323
324   g_object_set_data_full (G_OBJECT (spin), GTK_CELL_RENDERER_SPIN_PATH,
325                           g_strdup (path), g_free);
326
327   g_signal_connect (G_OBJECT (spin), "focus-out-event",
328                     G_CALLBACK (gtk_cell_renderer_spin_focus_out_event),
329                     cell);
330   g_signal_connect (G_OBJECT (spin), "key-press-event",
331                     G_CALLBACK (gtk_cell_renderer_spin_key_press_event),
332                     cell);
333
334   gtk_widget_show (spin);
335
336   return GTK_CELL_EDITABLE (spin);
337 }
338
339 /**
340  * gtk_cell_renderer_spin_new:
341  *
342  * Creates a new #GtkCellRendererSpin. 
343  *
344  * Returns: a new #GtkCellRendererSpin
345  *
346  * Since: 2.10
347  */
348 GtkCellRenderer *
349 gtk_cell_renderer_spin_new (void)
350 {
351   return g_object_new (GTK_TYPE_CELL_RENDERER_SPIN, NULL);
352 }
353
354
355 #define __GTK_CELL_RENDERER_SPIN_C__
356 #include  "gtkaliasdef.c"