1 /* PSPP - computes sample statistics.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 #include <gtk/gtksignal.h>
20 #include <gtk/gtktable.h>
21 #include <gtk/gtkbutton.h>
22 #include <gtk/gtklabel.h>
23 #include <gdk/gdkkeysyms.h>
24 #include "psppire-keypad.h"
32 static void psppire_keypad_class_init (PsppireKeypadClass *klass);
33 static void psppire_keypad_init (PsppireKeypad *kp);
35 static guint keypad_signals[n_SIGNALS] = { 0 };
38 psppire_keypad_get_type (void)
40 static GType kp_type = 0;
44 static const GTypeInfo kp_info =
46 sizeof (PsppireKeypadClass),
48 NULL, /* base_finalize */
49 (GClassInitFunc) psppire_keypad_class_init,
50 NULL, /* class_finalize */
51 NULL, /* class_data */
52 sizeof (PsppireKeypad),
54 (GInstanceInitFunc) psppire_keypad_init,
57 kp_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "PsppireKeypad",
64 static GObjectClass * parent_class = NULL;
67 psppire_keypad_dispose (GObject *obj)
69 PsppireKeypad *kp = (PsppireKeypad *)obj;
71 if (kp->dispose_has_run)
74 /* Make sure dispose does not run twice. */
75 kp->dispose_has_run = TRUE;
77 g_hash_table_unref (kp->frag_table);
79 /* Chain up to the parent class */
80 G_OBJECT_CLASS (parent_class)->dispose (obj);
84 psppire_keypad_finalize (GObject *obj)
86 /* Chain up to the parent class */
87 G_OBJECT_CLASS (parent_class)->finalize (obj);
91 psppire_keypad_class_init (PsppireKeypadClass *klass)
93 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
95 parent_class = g_type_class_peek_parent (klass);
97 gobject_class->dispose = psppire_keypad_dispose;
98 gobject_class->finalize = psppire_keypad_finalize;
100 keypad_signals[INSERT_SYNTAX] = g_signal_new ("insert-syntax",
101 G_TYPE_FROM_CLASS (klass),
102 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
103 G_STRUCT_OFFSET (PsppireKeypadClass,
107 g_cclosure_marshal_VOID__STRING,
111 keypad_signals[ERASE] = g_signal_new ("erase",
112 G_TYPE_FROM_CLASS (klass),
113 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
114 G_STRUCT_OFFSET (PsppireKeypadClass,
118 g_cclosure_marshal_VOID__VOID,
124 These are the strings that will be arguments to
126 The order of these must correspond
127 to the order of the button declarations
129 static const char *keypad_insert_text[] = {
130 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
131 ".", "+", "-", "*", "**", "/", "=", "<>", "<", "<=",
132 ">", ">=", "&", "|", "~", "()", NULL
136 /* Callback for any button click.
137 Emits the "insert-syntax" signal for the keypad,
138 with the string corresponding to the clicked button.
141 button_click (GtkButton *b, PsppireKeypad *kp)
143 const gchar *s = g_hash_table_lookup (kp->frag_table, b);
147 g_signal_emit (kp, keypad_signals [INSERT_SYNTAX], 0, s);
149 g_signal_emit (kp, keypad_signals [ERASE], 0);
152 static const gint cols = 6;
153 static const gint rows = 5;
157 /* Add BUTTON to KP. The top-left corner at X1,Y1, the
158 botton-right corner at X2,Y2 */
160 add_button (PsppireKeypad *kp, GtkWidget **button,
164 g_object_set (G_OBJECT (*button), "focus-on-click", FALSE, NULL);
166 gtk_table_attach_defaults (GTK_TABLE (kp->table),
171 gtk_widget_set_size_request (*button,
172 30 * rows / (float) cols,
173 30 * cols / (float) rows);
175 g_hash_table_insert (kp->frag_table, *button,
176 (void *) keypad_insert_text[(button - &kp->digit[0])] );
178 g_signal_connect (*button, "clicked",
179 G_CALLBACK (button_click), kp);
181 gtk_widget_show (*button);
185 /* Return a new button with CODE as the unicode character for its label */
186 static inline GtkWidget *
187 button_new_from_unicode (gunichar code)
189 char s[6] = {0,0,0,0,0,0};
191 g_unichar_to_utf8 (code, s);
193 return gtk_button_new_with_label (s);
197 /* Callback which occurs when the mouse enters the widget.
198 It sets or unsets the focus.
201 enter_leave_notify (GtkWidget *widget,
202 GdkEventCrossing *event,
205 /* Do nothing if we're just moving between the widget and
207 if (event->detail == GDK_NOTIFY_INFERIOR)
210 if (event->type == GDK_ENTER_NOTIFY)
211 gtk_widget_grab_focus (widget);
213 if (event->type == GDK_LEAVE_NOTIFY)
214 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
220 key_release_callback (GtkWidget *widget,
224 if ( ! (GTK_WIDGET_FLAGS (widget) & GTK_HAS_FOCUS) )
227 switch (event->keyval)
230 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "(");
233 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, ")");
236 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, ">");
239 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "<");
243 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "=");
245 case GDK_KP_Multiply :
247 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "*");
251 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "+");
253 case GDK_KP_Subtract :
255 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "-");
257 case GDK_KP_Decimal :
259 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, ".");
263 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "/");
267 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "0");
271 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "1");
275 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "2");
279 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "3");
283 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "4");
287 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "5");
291 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "6");
295 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "7");
299 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "8");
303 g_signal_emit (widget, keypad_signals [INSERT_SYNTAX], 0, "9");
314 psppire_keypad_init (PsppireKeypad *kp)
317 const int digit_voffset = 0;
318 const int digit_hoffset = 3;
320 GTK_WIDGET_SET_FLAGS (kp, GTK_CAN_FOCUS);
321 GTK_WIDGET_UNSET_FLAGS (kp, GTK_HAS_FOCUS);
323 kp->dispose_has_run = FALSE;
325 g_signal_connect (kp, "enter-notify-event", G_CALLBACK (enter_leave_notify),
328 g_signal_connect (kp, "leave-notify-event", G_CALLBACK (enter_leave_notify),
331 g_signal_connect (kp, "key-release-event", G_CALLBACK (key_release_callback),
334 kp->frag_table = g_hash_table_new (g_direct_hash, g_direct_equal);
336 kp->table = gtk_table_new (rows, cols, TRUE);
338 /* Buttons for the digits */
339 for (i = 0; i < 10; i++)
343 snprintf (buf, 5, "%d", i);
344 kp->digit[i] = gtk_button_new_with_label (buf);
347 add_button (kp, &kp->digit[i],
348 digit_hoffset + 0, digit_hoffset + 2,
349 digit_voffset + 3, digit_voffset + 4);
351 add_button (kp, &kp->digit[i],
352 digit_hoffset + j % 3, digit_hoffset + j % 3 + 1,
353 digit_voffset + 2 - (j / 3),
354 digit_voffset + 2 - (j / 3) + 1);
357 /* ... all the other buttons */
359 kp->dot = button_new_from_unicode (0xB7); /* MIDDLE DOT */
360 add_button (kp, &kp->dot, digit_hoffset + 2,
365 kp->plus = gtk_button_new_with_label ("+");
366 add_button (kp, &kp->plus, 0, 1,
369 kp->minus = button_new_from_unicode (0x2212); /* MINUS SIGN */
370 add_button (kp, &kp->minus, 0, 1,
373 kp->star = button_new_from_unicode (0xD7); /* MULTIPLICATION SIGN */
374 add_button (kp, &kp->star, 0, 1,
377 kp->slash = button_new_from_unicode (0xF7); /* DIVISION SIGN */
378 add_button (kp, &kp->slash, 0, 1,
384 g_markup_printf_escaped ("<span style=\"italic\">x<sup>y</sup></span>");
386 label = gtk_label_new ("**");
388 gtk_label_set_markup (GTK_LABEL (label), markup);
391 kp->star_star = gtk_button_new ();
392 gtk_container_add (GTK_CONTAINER (kp->star_star), label);
394 gtk_widget_show (label);
396 add_button (kp, &kp->star_star,
402 kp->gt = button_new_from_unicode (0x3E); /* GREATER-THAN SIGN*/
403 add_button (kp, &kp->gt, 2, 3,
406 kp->lt = button_new_from_unicode (0x3C); /* LESS-THAN SIGN*/
407 add_button (kp, &kp->lt, 1, 2,
410 kp->ge = button_new_from_unicode (0x2265); /* GREATER-THAN OR EQUAL */
411 add_button (kp, &kp->ge, 2, 3,
414 kp->le = button_new_from_unicode (0x2264); /* LESS-THAN OR EQUAL */
415 add_button (kp, &kp->le, 1, 2,
418 kp->neq = button_new_from_unicode (0x2260); /* NOT EQUAL */
419 add_button (kp, &kp->neq, 2, 3,
422 kp->eq = gtk_button_new_with_label ("=");
423 add_button (kp, &kp->eq, 1, 2,
426 kp->parentheses = gtk_button_new_with_label ("()");
427 add_button (kp, &kp->parentheses, 2, 3,
431 kp->delete = gtk_button_new_with_label ("Delete");
432 add_button (kp, &kp->delete, 3, 6,
437 kp->and = button_new_from_unicode (0x2227); /* LOGICAL AND */
438 add_button (kp, &kp->and, 1, 2,
442 kp->or = button_new_from_unicode (0x2228); /* LOGICAL OR */
443 add_button (kp, &kp->or, 2, 3,
447 kp->not = button_new_from_unicode (0xAC); /* NOT SIGN */
448 add_button (kp, &kp->not, 1, 2,
453 g_object_set (G_OBJECT (kp->table), "row-spacing", 5, NULL);
454 g_object_set (G_OBJECT (kp->table), "column-spacing", 5, NULL);
456 gtk_container_add (GTK_CONTAINER (kp), kp->table);
457 gtk_widget_show (kp->table);
459 gtk_widget_add_events (GTK_WIDGET (kp),
460 GDK_KEY_RELEASE_MASK |
461 GDK_LEAVE_NOTIFY_MASK |
462 GDK_ENTER_NOTIFY_MASK |
463 GDK_FOCUS_CHANGE_MASK);
469 psppire_keypad_new (void)
471 return GTK_WIDGET (g_object_new (psppire_keypad_get_type (), NULL));