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