Remove variables assigned to but never used.
[pspp] / src / ui / gui / customentry.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2005, 2007, 2010, 2011, 2012  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /*
18    This widget is a subclass of GtkEntry.  It's an entry widget with a
19    button on the right hand side.
20
21    This code is heavily based upon the GtkSpinButton widget.  Therefore
22    the copyright notice of that code is pasted below.
23
24    Please note however,  this code is covered by the GPL, not the LGPL.
25 */
26
27 /* GTK - The GIMP Toolkit
28  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
29  *
30  * GtkSpinButton widget for GTK+
31  * Copyright (C) 1998 Lars Hamann and Stefan Jeske
32  *
33  * This library is free software; you can redistribute it and/or
34  * modify it under the terms of the GNU Lesser General Public
35  * License as published by the Free Software Foundation; either
36  * version 2 of the License, or (at your option) any later version.
37  *
38  * This library is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  * Lesser General Public License for more details.
42  *
43  * You should have received a copy of the GNU Lesser General Public
44  * License along with this library.  If not, see
45  * <http://www.gnu.org/licenses/>.
46  */
47
48
49 /*
50  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
51  * file for a list of people on the GTK+ Team.  See the ChangeLog
52  * files for a list of changes.  These files are distributed with
53  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
54  */
55
56 #include <config.h>
57
58 #include <gtk/gtk.h>
59 #include "customentry.h"
60 #include "helper.h"
61
62 static void psppire_custom_entry_class_init          (PsppireCustomEntryClass *klass);
63 static void psppire_custom_entry_init                (PsppireCustomEntry      *ce);
64
65 static GtkEntryClass *parent_class = NULL;
66
67 /* Signals */
68 enum
69 {
70   CLICKED,
71   n_SIGNALS
72 };
73
74
75 static guint custom_entry_signals[n_SIGNALS] = {0};
76
77
78 GType
79 psppire_custom_entry_get_type (void)
80 {
81   static GType ce_type = 0;
82
83   if (!ce_type)
84     {
85       static const GTypeInfo ce_info =
86         {
87           sizeof (PsppireCustomEntryClass),
88           NULL, /* base_init */
89           NULL, /* base_finalize */
90           (GClassInitFunc) psppire_custom_entry_class_init,
91           NULL, /* class_finalize */
92           NULL, /* class_data */
93           sizeof (PsppireCustomEntry),
94           0,
95           (GInstanceInitFunc) psppire_custom_entry_init,
96         };
97
98       ce_type = g_type_register_static (GTK_TYPE_ENTRY, "PsppireCustomEntry",
99                                         &ce_info, 0);
100     }
101
102   return ce_type;
103 }
104
105
106 static void
107 psppire_custom_entry_map (GtkWidget *widget)
108 {
109   if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget))
110     {
111       GTK_WIDGET_CLASS (parent_class)->map (widget);
112       gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
113     }
114 }
115
116 static void
117 psppire_custom_entry_unmap (GtkWidget *widget)
118 {
119   if (gtk_widget_get_mapped (widget))
120     {
121       gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
122       GTK_WIDGET_CLASS (parent_class)->unmap (widget);
123     }
124 }
125
126 static gint psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry);
127
128 static void
129 psppire_custom_entry_realize (GtkWidget *widget)
130 {
131   PsppireCustomEntry *custom_entry;
132   GdkWindowAttr attributes;
133   gint attributes_mask;
134   guint real_width;
135   gint button_size ;
136
137   custom_entry = PSPPIRE_CUSTOM_ENTRY (widget);
138
139   button_size = psppire_custom_entry_get_button_width (custom_entry);
140
141   real_width = widget->allocation.width;
142   widget->allocation.width -= button_size + 2 * widget->style->xthickness;
143   gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
144                          GDK_KEY_RELEASE_MASK);
145   GTK_WIDGET_CLASS (parent_class)->realize (widget);
146
147   widget->allocation.width = real_width;
148
149   attributes.window_type = GDK_WINDOW_CHILD;
150   attributes.wclass = GDK_INPUT_OUTPUT;
151   attributes.visual = gtk_widget_get_visual (widget);
152   attributes.colormap = gtk_widget_get_colormap (widget);
153   attributes.event_mask = gtk_widget_get_events (widget);
154   attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
155     | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
156     | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
157
158   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
159
160   attributes.x = (widget->allocation.x +
161                   widget->allocation.width - button_size -
162                   2 * widget->style->xthickness);
163   attributes.y = widget->allocation.y + (widget->allocation.height -
164                                          widget->requisition.height) / 2;
165   attributes.width = button_size + 2 * widget->style->xthickness;
166   attributes.height = widget->requisition.height;
167
168   custom_entry->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
169                                         &attributes, attributes_mask);
170   gdk_window_set_user_data (custom_entry->panel, widget);
171
172   gtk_style_set_background (widget->style, custom_entry->panel, GTK_STATE_NORMAL);
173
174
175   gtk_widget_queue_resize (GTK_WIDGET (custom_entry));
176 }
177
178
179 #define MIN_BUTTON_WIDTH  6
180
181 static gint
182 psppire_custom_entry_get_button_width (PsppireCustomEntry *custom_entry)
183 {
184   const gint size = pango_font_description_get_size
185     (GTK_WIDGET (custom_entry)->style->font_desc);
186
187   gint button_width = MAX (PANGO_PIXELS (size), MIN_BUTTON_WIDTH);
188
189   return button_width - button_width % 2; /* force even */
190 }
191
192 /**
193  * custom_entry_get_shadow_type:
194  * @custom_entry: a #PsppireCustomEntry
195  *
196  * Convenience function to Get the shadow type from the underlying widget's
197  * style.
198  *
199  * Return value: the #GtkShadowType
200  **/
201 static gint
202 psppire_custom_entry_get_shadow_type (PsppireCustomEntry *custom_entry)
203 {
204   GtkShadowType rc_shadow_type;
205
206   gtk_widget_style_get (GTK_WIDGET (custom_entry), "shadow_type", &rc_shadow_type, NULL);
207
208   return rc_shadow_type;
209 }
210
211
212 static void
213 psppire_custom_entry_unrealize (GtkWidget *widget)
214 {
215   PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
216
217   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
218
219   if (ce->panel)
220     {
221       gdk_window_set_user_data (ce->panel, NULL);
222       gdk_window_destroy (ce->panel);
223       ce->panel = NULL;
224     }
225 }
226
227
228 static void
229 psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
230 {
231   GtkWidget *widget;
232
233   widget = GTK_WIDGET (custom_entry);
234
235   if (gtk_widget_is_drawable (widget))
236     {
237       gtk_widget_queue_draw (widget);
238
239       /* We must invalidate the panel window ourselves, because it
240        * is not a child of widget->window
241        */
242       gdk_window_invalidate_rect (custom_entry->panel, NULL, TRUE);
243     }
244 }
245
246
247 static gint
248 psppire_custom_entry_expose (GtkWidget      *widget,
249                      GdkEventExpose *event)
250 {
251   PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
252
253   g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
254   g_return_val_if_fail (event != NULL, FALSE);
255
256   if (gtk_widget_is_drawable (widget))
257     {
258       gboolean is_editable;
259       GtkShadowType shadow_type;
260       GdkRectangle rect;
261
262       rect.x = 0;
263       rect.y = 0;
264
265       if (event->window != ce->panel)
266         GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
267
268       gdk_drawable_get_size (ce->panel, &rect.width, &rect.height);
269
270       gdk_window_begin_paint_rect (ce->panel, &rect);
271
272
273       shadow_type = psppire_custom_entry_get_shadow_type (ce);
274
275       g_object_get (widget, "editable", &is_editable, NULL);
276
277       gtk_paint_box (widget->style, ce->panel,
278                      is_editable ? GTK_STATE_NORMAL: GTK_STATE_INSENSITIVE,
279                      shadow_type,
280                      NULL, widget, "customentry",
281                      rect.x, rect.y, rect.width, rect.height);
282
283
284       gdk_window_end_paint (ce->panel);
285     }
286
287   return FALSE;
288 }
289
290
291 static gint
292 psppire_custom_entry_button_press (GtkWidget      *widget,
293                            GdkEventButton *event);
294
295 static void
296 psppire_custom_entry_size_allocate (GtkWidget     *widget,
297                             GtkAllocation *allocation);
298
299
300
301 static void
302 psppire_custom_entry_class_init (PsppireCustomEntryClass *klass)
303 {
304   GObjectClass     *gobject_class = G_OBJECT_CLASS (klass);
305
306   GtkWidgetClass   *widget_class;
307
308   parent_class = g_type_class_peek_parent (klass);
309
310   widget_class   = (GtkWidgetClass*)   klass;
311
312   widget_class->map = psppire_custom_entry_map;
313   widget_class->unmap = psppire_custom_entry_unmap;
314
315   widget_class->realize = psppire_custom_entry_realize;
316   widget_class->unrealize = psppire_custom_entry_unrealize;
317
318   widget_class->expose_event = psppire_custom_entry_expose;
319   widget_class->button_press_event = psppire_custom_entry_button_press;
320
321   widget_class->size_allocate = psppire_custom_entry_size_allocate;
322
323
324   gtk_widget_class_install_style_property_parser
325     (widget_class,
326      g_param_spec_enum ("shadow_type",
327                         "Shadow Type",
328                         "Style of bevel around the custom entry button",
329                         GTK_TYPE_SHADOW_TYPE,
330                         GTK_SHADOW_ETCHED_IN,
331                         G_PARAM_READABLE),
332      gtk_rc_property_parse_enum);
333
334   custom_entry_signals[CLICKED] =
335     g_signal_new ("clicked",
336                   G_TYPE_FROM_CLASS (gobject_class),
337                   G_SIGNAL_RUN_LAST,
338                   0,
339                   NULL, NULL,
340                   g_cclosure_marshal_VOID__VOID,
341                   G_TYPE_NONE,
342                   0);
343
344
345 }
346
347 static void
348 psppire_custom_entry_init (PsppireCustomEntry *ce)
349 {
350 }
351
352 GtkWidget*
353 psppire_custom_entry_new ()
354 {
355   return GTK_WIDGET (g_object_new (psppire_custom_entry_get_type (), NULL));
356 }
357
358
359
360 static gint
361 psppire_custom_entry_button_press (GtkWidget *widget,
362                                    GdkEventButton *event)
363 {
364   PsppireCustomEntry *ce = PSPPIRE_CUSTOM_ENTRY (widget);
365
366   if (event->window == ce->panel)
367     {
368       gboolean is_editable ;
369       if (!gtk_widget_has_focus (widget))
370         gtk_widget_grab_focus (widget);
371
372       g_object_get (ce, "editable", &is_editable, NULL);
373
374       if ( event->button == 1 && is_editable )
375         g_signal_emit (widget, custom_entry_signals[CLICKED], 0);
376
377     }
378   else
379     return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
380
381   return FALSE;
382 }
383
384
385
386 static void
387 psppire_custom_entry_size_allocate (GtkWidget     *widget,
388                             GtkAllocation *allocation)
389 {
390   PsppireCustomEntry *ce;
391   GtkAllocation entry_allocation;
392   GtkAllocation panel_allocation;
393   gint button_width;
394   gint panel_width;
395
396   g_return_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget));
397   g_return_if_fail (allocation != NULL);
398
399   ce = PSPPIRE_CUSTOM_ENTRY (widget);
400   button_width = psppire_custom_entry_get_button_width (ce);
401   panel_width = button_width + 2 * widget->style->xthickness;
402
403   widget->allocation = *allocation;
404
405   entry_allocation = *allocation;
406   entry_allocation.width -= panel_width;
407
408   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
409     {
410       entry_allocation.x += panel_width;
411       panel_allocation.x = allocation->x;
412     }
413   else
414     {
415       panel_allocation.x = allocation->x + allocation->width - panel_width;
416     }
417
418   panel_allocation.width = panel_width;
419   panel_allocation.height = MIN (widget->requisition.height, allocation->height);
420
421   panel_allocation.y = allocation->y + (allocation->height -
422                                         panel_allocation.height) / 2;
423
424   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
425
426   if (gtk_widget_get_realized (widget))
427     {
428       gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
429                               panel_allocation.x,
430                               panel_allocation.y,
431                               panel_allocation.width,
432                               panel_allocation.height);
433     }
434
435   psppire_custom_entry_redraw (ce);
436 }
437
438
439
440
441