2 * This file is a part of hildon
4 * Copyright (C) 2006 Nokia Corporation, all rights reserved.
6 * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * SECTION:hildon-code-dialog
27 * @short_description: A keypad-like widget used to enter pincodes.
29 * #HildonCodeDialog displays a keypad that can be used to enter
30 * numerical pin codes or lock codes. It emits a 'input' signal each time
31 * an input action is performed on the dialog.
35 /* FIXME We need property access in this widget */
37 #undef HILDON_DISABLE_DEPRECATED
44 #include <gdk/gdkkeysyms.h>
46 #include "hildon-code-dialog.h"
47 #include "hildon-defines.h"
48 #include "hildon-banner.h"
49 #include "hildon-code-dialog-private.h"
51 #define HEIGHT (48-HILDON_MARGIN_DEFAULT)
53 #define WIDTH (100-HILDON_MARGIN_DEFAULT)
55 #define BACKSPACE_ICON "general_backspace"
58 dgettext("hildon-libs", String)
61 dgettext("hildon-common-strings", String)
63 #define DEVICELOCK_OK _("wdgt_bd_done")
65 #define DEVICELOCK_TITLE dgettext("osso-system-lock", "secu_application_title")
67 #define DEVICELOCK_MAX_CHAR_REACHED c_("ckdg_ib_maximum_characters_reached")
69 #define MAX_PINCODE_LEN (10)
72 hildon_code_dialog_class_init (HildonCodeDialogClass *cd_class);
75 hildon_code_dialog_init (HildonCodeDialog *self);
78 hildon_code_dialog_realize (GtkWidget *widget);
81 hildon_code_dialog_unrealize (GtkWidget *widget);
84 hildon_code_dialog_finalize (GObject *object);
87 hildon_code_dialog_button_clicked (GtkButton *buttonm,
91 hildon_code_dialog_backspace (HildonCodeDialog *dialog);
94 hildon_code_dialog_im_commit (GtkIMContext *im_context,
99 hildon_code_dialog_insert_text (GtkEditable *editable,
101 gint new_text_length,
106 hildon_code_dialog_key_press_event (GtkWidget *widget,
111 hildon_code_dialog_real_input (HildonCodeDialog *dialog);
114 hildon_code_dialog_input (HildonCodeDialog *dialog);
116 static GtkDialogClass* parent_class = NULL;
118 static guint input_signal;
121 * hildon_code_dialog_get_type:
123 * Initializes and returns the type of a hildon code dialog.
125 * Returns: GType of #HildonCodeDialog
128 hildon_code_dialog_get_type (void)
130 static GType type = 0;
134 static const GTypeInfo info =
136 sizeof (HildonCodeDialogClass),
137 NULL, /* base_init */
138 NULL, /* base_finalize */
139 (GClassInitFunc) hildon_code_dialog_class_init,
140 NULL, /* class_finalize */
141 NULL, /* class_data */
142 sizeof (HildonCodeDialog),
144 (GInstanceInitFunc) hildon_code_dialog_init
146 type = g_type_register_static (GTK_TYPE_DIALOG,
147 "HildonCodeDialog", &info, 0);
153 hildon_code_dialog_class_init (HildonCodeDialogClass *cd_class)
155 GObjectClass *gobject_class = G_OBJECT_CLASS (cd_class);
156 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (cd_class);
158 parent_class = GTK_DIALOG_CLASS (g_type_class_peek_parent (cd_class));
159 g_type_class_add_private (cd_class, sizeof (HildonCodeDialogPrivate));
161 gobject_class->finalize = hildon_code_dialog_finalize;
163 widget_class->realize = hildon_code_dialog_realize;
164 widget_class->unrealize = hildon_code_dialog_unrealize;
166 cd_class->input = hildon_code_dialog_real_input;
168 /* FIXME Document this signal! */
169 input_signal = g_signal_new("input",
170 HILDON_TYPE_CODE_DIALOG,
172 G_STRUCT_OFFSET (HildonCodeDialogClass, input),
174 g_cclosure_marshal_VOID__VOID,
180 hildon_code_dialog_init (HildonCodeDialog *dialog)
182 HildonCodeDialogPrivate *priv;
184 GtkWidget *dialog_vbox1 = NULL;
185 GtkWidget *table = NULL;
186 GtkWidget *alignment = NULL;
187 GtkWidget *vbox1 = NULL;
188 GtkWidget *image1 = NULL;
189 GtkWidget *dialog_action_area1 = NULL;
193 priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
196 const gchar* numstrs[10] = {
197 "0","1","2","3","4","5","6","7","8","9"
200 GdkPixbuf* pixbuf = NULL;
201 GtkIconTheme* icon_theme = NULL;
202 GtkIconInfo *icon_info = NULL;
205 /* Set default title */
206 gtk_window_set_title (GTK_WINDOW (dialog), DEVICELOCK_TITLE);
208 gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
209 gtk_dialog_set_has_separator ((GtkDialog *) dialog, FALSE);
211 hints.min_width = -1;
212 hints.min_height = -1;
213 hints.max_width = -1;
214 hints.max_height = -1;
216 gtk_window_set_geometry_hints (GTK_WINDOW (dialog), GTK_WIDGET (dialog), &hints,
217 GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
219 table = gtk_table_new (4, 3, FALSE);
220 gtk_table_set_row_spacings (GTK_TABLE (table), HILDON_MARGIN_DEFAULT );
221 gtk_table_set_col_spacings (GTK_TABLE (table), HILDON_MARGIN_DEFAULT );
223 dialog_vbox1 = GTK_DIALOG (dialog)->vbox;
224 vbox1 = gtk_vbox_new (FALSE, 0);
225 gtk_box_set_spacing (GTK_BOX (vbox1), HILDON_MARGIN_DOUBLE);
227 priv->help_text = gtk_label_new ("");
228 alignment = gtk_alignment_new (0.5,0,1,1);
229 gtk_container_add (GTK_CONTAINER (alignment), priv->help_text);
231 priv->entry = gtk_entry_new ();
233 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (priv->entry), GTK_CAN_FOCUS);
234 gtk_entry_set_invisible_char (GTK_ENTRY (priv->entry), g_utf8_get_char ("*"));
235 gtk_entry_set_alignment (GTK_ENTRY (priv->entry), 1.0);
237 gtk_editable_set_editable (GTK_EDITABLE (priv->entry),FALSE);
238 gtk_entry_set_visibility (GTK_ENTRY (priv->entry), FALSE);
240 gtk_box_pack_start (GTK_BOX (vbox1), alignment, TRUE,FALSE,0);
241 gtk_box_pack_start (GTK_BOX (vbox1), priv->entry, TRUE,FALSE,0);
242 gtk_box_pack_start (GTK_BOX (vbox1), table, FALSE,TRUE,0);
244 gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, FALSE,TRUE,0);
246 for(i = 1;i <= 3; i++) {
247 priv->buttons[0][i-1] = gtk_button_new_with_mnemonic (numstrs[i]);
248 gtk_widget_set_size_request (priv->buttons[0][i-1], WIDTH, HEIGHT);
249 gtk_table_attach_defaults (GTK_TABLE (table), priv->buttons[0][i-1],
253 for(i = 4;i <= 6;i++) {
254 priv->buttons[1][i-4] = gtk_button_new_with_mnemonic (numstrs[i]);
255 gtk_widget_set_size_request (priv->buttons[1][i-4], WIDTH, HEIGHT);
256 gtk_table_attach_defaults (GTK_TABLE (table), priv->buttons[1][i-4],
261 priv->buttons[2][i-7] = gtk_button_new_with_mnemonic (numstrs[i]);
262 gtk_widget_set_size_request (priv->buttons[2][i-7], WIDTH, HEIGHT);
263 gtk_table_attach_defaults (GTK_TABLE (table), priv->buttons[2][i-7],
267 priv->buttons[3][0] = priv->buttons[3][1] =
268 gtk_button_new_with_mnemonic (numstrs[0]);
269 gtk_widget_set_size_request (priv->buttons[3][0], WIDTH, HEIGHT);
270 gtk_table_attach (GTK_TABLE (table), priv->buttons[3][0],
271 0,2,3,4, (GtkAttachOptions) (GTK_FILL),
272 (GtkAttachOptions) (0), 0, 0);
274 priv->buttons[3][2] = gtk_button_new ();
275 gtk_widget_set_size_request (priv->buttons[3][2], WIDTH, HEIGHT);
276 gtk_table_attach_defaults (GTK_TABLE (table), priv->buttons[3][2],
279 icon_theme = gtk_icon_theme_get_default ();
281 icon_info = gtk_icon_theme_lookup_icon (icon_theme, BACKSPACE_ICON, 1,
282 GTK_ICON_LOOKUP_NO_SVG);
283 base_size = gtk_icon_info_get_base_size (icon_info);
284 gtk_icon_info_free (icon_info);
286 pixbuf = gtk_icon_theme_load_icon (icon_theme,
287 BACKSPACE_ICON, base_size,
288 GTK_ICON_LOOKUP_NO_SVG,
291 image1 = gtk_image_new_from_pixbuf (pixbuf);
292 g_object_unref (G_OBJECT(pixbuf));
293 gtk_container_add (GTK_CONTAINER (priv->buttons[3][2]), image1);
294 dialog_action_area1 = GTK_DIALOG (dialog)->action_area;
295 gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1),
296 #if GTK_CHECK_VERSION(2,11,0) || defined(MAEMO_GTK)
297 GTK_BUTTONBOX_CENTER);
299 GTK_BUTTONBOX_DEFAULT_STYLE);
302 okButton = gtk_dialog_add_button (GTK_DIALOG (dialog) ,DEVICELOCK_OK,
305 gtk_widget_set_sensitive (okButton, FALSE);
307 priv->buttons[4][0] = priv->buttons[4][1] = okButton;
309 priv->im_context = gtk_im_multicontext_new();
311 g_object_set (G_OBJECT (priv->im_context), "hildon-input-mode",
312 HILDON_GTK_INPUT_MODE_NUMERIC, NULL);
318 g_signal_connect (G_OBJECT (priv->im_context), "commit",
319 G_CALLBACK (hildon_code_dialog_im_commit), dialog);
321 g_signal_connect (G_OBJECT (priv->entry), "insert_text",
322 G_CALLBACK (hildon_code_dialog_insert_text), dialog);
324 gtk_entry_set_max_length (GTK_ENTRY (priv->entry), MAX_PINCODE_LEN);
326 for (x = 0; x < 3; x++)
328 for (y = 0; y < 3; y++)
330 g_signal_connect (G_OBJECT (priv->buttons[x][y]), "clicked",
331 G_CALLBACK (hildon_code_dialog_button_clicked), dialog);
332 g_signal_connect (G_OBJECT (priv->buttons[x][y]), "key-press-event",
333 G_CALLBACK (hildon_code_dialog_key_press_event), dialog);
337 g_signal_connect (G_OBJECT (priv->buttons[3][0]), "clicked",
338 G_CALLBACK (hildon_code_dialog_button_clicked), dialog);
339 g_signal_connect (G_OBJECT (priv->buttons[3][0]), "key-press-event",
340 G_CALLBACK (hildon_code_dialog_key_press_event), dialog);
342 g_signal_connect (G_OBJECT (priv->buttons[3][2]), "clicked",
343 G_CALLBACK (hildon_code_dialog_button_clicked), dialog);
344 g_signal_connect (G_OBJECT (priv->buttons[3][2]), "key-press-event",
345 G_CALLBACK (hildon_code_dialog_key_press_event), dialog);
347 g_signal_connect (G_OBJECT (okButton), "key-press-event",
348 G_CALLBACK(hildon_code_dialog_key_press_event), dialog);
350 gtk_widget_show_all (GTK_WIDGET (GTK_DIALOG (dialog)->vbox));
354 hildon_code_dialog_realize (GtkWidget *widget)
356 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (widget);
357 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
359 if (GTK_WIDGET_CLASS (parent_class)->realize)
360 (* GTK_WIDGET_CLASS (parent_class)->realize) (widget);
362 gtk_im_context_set_client_window (GTK_IM_CONTEXT (priv->im_context),
363 GTK_WIDGET (dialog)->window);
364 gtk_im_context_focus_in (priv->im_context);
368 hildon_code_dialog_unrealize (GtkWidget *widget)
370 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (widget);
371 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
373 gtk_im_context_set_client_window (GTK_IM_CONTEXT (priv->im_context), NULL);
375 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
376 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
380 hildon_code_dialog_finalize (GObject *object)
382 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (object);
383 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
385 g_object_unref (priv->im_context);
387 G_OBJECT_CLASS(parent_class)->finalize(object);
391 hildon_code_dialog_backspace (HildonCodeDialog *dialog)
393 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
398 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry)));
407 pos = g_utf8_find_prev_char (text, pos);
414 gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
418 gtk_widget_set_sensitive (priv->buttons[4][0], FALSE);
421 gtk_editable_set_position (GTK_EDITABLE (priv->entry), -1);
427 hildon_code_dialog_button_clicked (GtkButton *button,
430 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (user_data);
431 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
434 const char *number = gtk_button_get_label (button);
436 if (number && *number )
438 gtk_editable_set_editable (GTK_EDITABLE (priv->entry), TRUE);
440 g_signal_emit_by_name (GTK_ENTRY (priv->entry)->im_context, "commit",
443 gtk_editable_set_editable (GTK_EDITABLE (priv->entry), FALSE);
445 gtk_editable_set_position (GTK_EDITABLE (priv->entry), -1);
449 hildon_code_dialog_backspace (dialog);
454 hildon_code_dialog_im_commit (GtkIMContext *im_context,
458 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (user_data);
459 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
464 digit = g_ascii_strtod(utf8, NULL);
466 if (g_ascii_isdigit(*utf8))
468 gtk_editable_set_editable (GTK_EDITABLE (priv->entry), TRUE);
470 g_signal_emit_by_name (GTK_ENTRY (priv->entry)->im_context, "commit",
473 gtk_editable_set_editable (GTK_EDITABLE (priv->entry), FALSE);
475 gtk_editable_set_position (GTK_EDITABLE (priv->entry), -1);
480 hildon_code_dialog_insert_text (GtkEditable *editable,
482 gint new_text_length,
486 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (user_data);
487 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
488 gchar *text = g_strdup(gtk_entry_get_text (GTK_ENTRY (priv->entry)));
489 glong length = g_utf8_strlen (text, -1);
493 if (length == MAX_PINCODE_LEN)
495 hildon_banner_show_information (GTK_WIDGET (dialog),
497 DEVICELOCK_MAX_CHAR_REACHED);
502 /* make the Ok button sensitive */
503 gtk_widget_set_sensitive (priv->buttons[4][0], TRUE);
506 hildon_code_dialog_input (dialog);
510 hildon_code_dialog_key_press_event (GtkWidget *widget,
514 HildonCodeDialog *dialog = HILDON_CODE_DIALOG (user_data);
515 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
516 GtkWidget *new_widget = widget;
521 if (gtk_im_context_filter_keypress (priv->im_context, event))
524 if (event->keyval == GDK_BackSpace)
526 hildon_code_dialog_backspace (dialog);
530 for (x = 0; x < 5; x++)
532 for (y = 0; y < 3; y++)
534 if (priv->buttons[x][y] == widget)
542 while (new_widget == widget)
544 switch (event->keyval)
566 new_widget = priv->buttons[x][y];
569 gtk_widget_grab_focus (new_widget);
575 * hildon_code_dialog_new:
577 * Use this function to create a new HildonCodeDialog.
579 * Return value: A @HildonCodeDialog.
582 hildon_code_dialog_new (void)
584 HildonCodeDialog *dialog = g_object_new (HILDON_TYPE_CODE_DIALOG, NULL);
586 return GTK_WIDGET (dialog);
590 * hildon_code_dialog_get_code:
591 * @dialog: The #HildonCodeDialog from which to get the entered code
593 * Use this function to access the code entered by the user.
595 * Return value: The entered code.
598 hildon_code_dialog_get_code (HildonCodeDialog *dialog)
600 g_return_val_if_fail (HILDON_IS_CODE_DIALOG (dialog), NULL);
602 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
605 return gtk_entry_get_text (GTK_ENTRY (priv->entry));
609 * hildon_code_dialog_clear_clode:
610 * @dialog: The #HildonCodeDialog whose entry should be cleared:
612 * Use this function to clear the user entered code.
615 hildon_code_dialog_clear_code (HildonCodeDialog *dialog)
617 g_return_if_fail (HILDON_IS_CODE_DIALOG (dialog));
619 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
622 gtk_entry_set_text (GTK_ENTRY (priv->entry), "");
623 gtk_widget_set_sensitive (priv->buttons[4][0], FALSE);
627 * hildon_code_dialog_set_help_text:
628 * @dialog: The #HildonCodeDialog whose entry should be cleared:
629 * @text: The text to use in the help label.
631 * Use this function to set the text that will be displayd in the
635 hildon_code_dialog_set_help_text (HildonCodeDialog *dialog,
638 g_return_if_fail (HILDON_IS_CODE_DIALOG (dialog));
640 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
643 gtk_label_set_text (GTK_LABEL (priv->help_text), text);
647 hildon_code_dialog_real_input (HildonCodeDialog *dialog)
652 hildon_code_dialog_input (HildonCodeDialog *dialog)
654 /* Emit the signal */
655 g_signal_emit (dialog, input_signal, 0);
659 * hildon_code_dialog_set_input_sensitive
660 * @dialog: The #HildonCodeDialog whose state is to be changed
661 * @sensitive: The new state
663 * This function will block or enable the input on the code dialog by
664 * making the input button sensitive (or not).
667 hildon_code_dialog_set_input_sensitive (HildonCodeDialog *dialog,
673 g_return_if_fail (HILDON_IS_CODE_DIALOG (dialog));
675 HildonCodeDialogPrivate *priv = HILDON_CODE_DIALOG_GET_PRIVATE (dialog);
678 for (i = 0; i < 5; i++)
679 for (k = 0; k < 3; k++)
680 if (i != 4 && (k != 0 || k != 2))
681 gtk_widget_set_sensitive (priv->buttons [i][k], sensitive);
683 gtk_widget_set_sensitive (priv->help_text, sensitive);
684 gtk_widget_set_sensitive (priv->entry, sensitive);