2 * This file is part of hildon-libs
4 * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@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
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
27 * @short_description: A widget to ask confirmation from the user
29 * Notes are used to for confirmation (OK/Cancel/etc.) from the user.
30 * A simple note contains an information text and an OK button to be
31 * pressed. Additional features such as progress bars or animation can
39 #include "hildon-note.h"
40 #include <gtk/gtklabel.h>
41 #include <gtk/gtkimage.h>
42 #include <gtk/gtkhbox.h>
43 #include <gtk/gtkalignment.h>
44 #include <gtk/gtkvbox.h>
45 #include <gtk/gtkbutton.h>
47 #include <hildon-widgets/hildon-defines.h>
48 #include <hildon-widgets/hildon-system-sound.h>
49 #include <hildon-widgets/hildon-banner.h> /* for _hildon_gtk_label_set_text_n_lines */
54 /* FIXME: Can these be included from somewhere? */
55 #define CONFIRMATION_SOUND_PATH "/usr/share/sounds/ui-confirmation_note.wav"
56 #define INFORMATION_SOUND_PATH "/usr/share/sounds/ui-information_note.wav"
57 #define HILDON_NOTE_CONFIRMATION_ICON "qgn_note_confirm"
58 #define HILDON_NOTE_INFORMATION_ICON "qgn_note_info"
60 #define _(String) dgettext(PACKAGE, String)
62 static GtkDialogClass *parent_class;
64 #define HILDON_NOTE_GET_PRIVATE(obj)\
65 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
66 HILDON_TYPE_NOTE, HildonNotePrivate));
68 typedef struct _HildonNotePrivate HildonNotePrivate;
70 static void hildon_note_class_init(HildonNoteClass * class);
71 static void hildon_note_init(HildonNote * dialog);
73 static void hildon_note_rebuild(HildonNote *note);
74 static void hildon_note_finalize(GObject * obj_self);
75 static void hildon_note_realize (GtkWidget *widget);
77 static void hildon_note_set_property(GObject * object,
81 static void hildon_note_get_property(GObject * object,
83 GValue * value, GParamSpec * pspec);
86 sound_handling(GtkWidget * widget, GdkEventExpose *event, gpointer data);
88 struct _HildonNotePrivate {
90 GtkWidget *cancelButton;
95 HildonNoteType note_n;
96 GtkWidget *progressbar;
97 gulong sound_signal_handler;
99 gchar *original_description;
104 PROP_HILDON_NOTE_TYPE,
105 PROP_HILDON_NOTE_DESCRIPTION,
106 PROP_HILDON_NOTE_ICON,
107 PROP_HILDON_NOTE_PROGRESSBAR,
108 PROP_HILDON_NOTE_STOCK_ICON
112 hildon_note_set_property(GObject * object,
114 const GValue * value, GParamSpec * pspec)
116 HildonNote *note = HILDON_NOTE(object);
117 HildonNotePrivate *priv;
120 priv = HILDON_NOTE_GET_PRIVATE(note);
123 case PROP_HILDON_NOTE_TYPE:
124 priv->note_n = g_value_get_enum(value);
125 hildon_note_rebuild(note);
127 case PROP_HILDON_NOTE_DESCRIPTION:
128 g_free(priv->original_description);
129 priv->original_description = g_value_dup_string(value);
131 _hildon_gtk_label_set_text_n_lines(GTK_LABEL(priv->label),
132 priv->original_description,
133 priv->note_n == HILDON_NOTE_PROGRESSBAR_TYPE ? 1 : 5);
136 case PROP_HILDON_NOTE_ICON:
137 gtk_image_set_from_icon_name(GTK_IMAGE(priv->icon),
138 g_value_get_string(value), HILDON_ICON_SIZE_BIG_NOTE);
140 case PROP_HILDON_NOTE_STOCK_ICON:
141 gtk_image_set_from_stock(GTK_IMAGE(priv->icon),
142 g_value_get_string(value), HILDON_ICON_SIZE_BIG_NOTE);
144 case PROP_HILDON_NOTE_PROGRESSBAR:
145 widget = g_value_get_object(value);
146 if (widget != priv->progressbar)
148 if (priv->progressbar)
149 g_object_unref(priv->progressbar);
151 priv->progressbar = widget;
155 g_object_ref(widget);
156 gtk_object_sink(GTK_OBJECT(widget));
159 hildon_note_rebuild(note);
163 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
169 hildon_note_get_property(GObject * object,
170 guint prop_id, GValue * value, GParamSpec * pspec)
172 HildonNote *note = HILDON_NOTE(object);
173 HildonNotePrivate *priv;
175 priv = HILDON_NOTE_GET_PRIVATE(note);
178 case PROP_HILDON_NOTE_TYPE:
179 g_value_set_enum(value, priv->note_n);
181 case PROP_HILDON_NOTE_DESCRIPTION:
182 g_value_set_string(value, priv->original_description);
184 case PROP_HILDON_NOTE_ICON:
185 g_object_get_property(G_OBJECT(priv->icon), "icon-name", value);
187 case PROP_HILDON_NOTE_STOCK_ICON:
188 g_object_get_property(G_OBJECT(priv->icon), "stock", value);
190 case PROP_HILDON_NOTE_PROGRESSBAR:
191 g_value_set_object(value, priv->progressbar);
194 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
199 GType hildon_note_get_type()
201 static GType dialog_type = 0;
204 static const GTypeInfo dialog_info = {
205 sizeof(HildonNoteClass),
206 NULL, /* base_init */
207 NULL, /* base_finalize */
208 (GClassInitFunc) hildon_note_class_init,
209 NULL, /* class_finalize */
210 NULL, /* class_data */
213 (GInstanceInitFunc) hildon_note_init
215 dialog_type = g_type_register_static(GTK_TYPE_DIALOG,
222 static void hildon_note_class_init(HildonNoteClass * class)
224 GObjectClass *object_class = G_OBJECT_CLASS(class);
225 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
227 /* set the global parent_class */
228 parent_class = g_type_class_peek_parent(class);
230 g_type_class_add_private(class, sizeof(HildonNotePrivate));
232 object_class->finalize = hildon_note_finalize;
233 object_class->set_property = hildon_note_set_property;
234 object_class->get_property = hildon_note_get_property;
235 widget_class->realize = hildon_note_realize;
237 g_object_class_install_property(object_class,
238 PROP_HILDON_NOTE_TYPE,
239 g_param_spec_enum("note_type",
241 "The type of the note dialog",
242 hildon_note_type_get_type(),
243 HILDON_NOTE_CONFIRMATION_TYPE,
244 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
247 * HildonNote:description:
249 * Description for note.
251 g_object_class_install_property(object_class,
252 PROP_HILDON_NOTE_DESCRIPTION,
253 g_param_spec_string("description",
255 "The text that appears in the note dialog",
264 g_object_class_install_property(object_class,
265 PROP_HILDON_NOTE_ICON,
266 g_param_spec_string("icon",
268 "The name of the icon that appears in the note dialog",
273 * HildonNote:stock-icon:
275 * Stock icon for note.
277 g_object_class_install_property(object_class,
278 PROP_HILDON_NOTE_STOCK_ICON,
279 g_param_spec_string("stock-icon",
281 "The stock name of the icon that appears in the note dialog",
286 * HildonNote:progressbar:
288 * Progressbar for note.
290 g_object_class_install_property(object_class,
291 PROP_HILDON_NOTE_PROGRESSBAR,
292 g_param_spec_object("progressbar",
293 "Progressbar widget",
294 "The progressbar that appears in the note dialog",
295 GTK_TYPE_PROGRESS_BAR,
299 static void hildon_note_init(HildonNote * dialog)
301 HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE(dialog);
303 priv->label = gtk_label_new(NULL);
304 priv->icon = gtk_image_new();
306 /* Acquire real references to our internal children, since
307 they are not nessecarily packed into container in each
309 g_object_ref(priv->label);
310 g_object_ref(priv->icon);
311 gtk_object_sink(GTK_OBJECT(priv->label));
312 gtk_object_sink(GTK_OBJECT(priv->icon));
314 gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
315 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
319 static void hildon_note_finalize(GObject * obj_self)
321 HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE(obj_self);
323 /* Free internal data */
324 g_object_unref(priv->label);
325 g_object_unref(priv->icon);
326 if (priv->progressbar)
327 g_object_unref(priv->progressbar);
329 g_free(priv->original_description);
331 G_OBJECT_CLASS(parent_class)->finalize(obj_self);
335 hildon_note_realize (GtkWidget *widget)
337 HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE(widget);
339 /* Make widget->window accessible */
340 GTK_WIDGET_CLASS (parent_class)->realize (widget);
342 /* Border only, no titlebar */
343 gdk_window_set_decorations (widget->window, GDK_DECOR_BORDER);
345 /* Because ESD is synchronous, we wish to play sound after the
346 note is already on screen to avoid blocking its appearance */
347 if (priv->sound_signal_handler == 0)
348 priv->sound_signal_handler = g_signal_connect_after(widget,
349 "expose-event", G_CALLBACK(sound_handling), NULL);
352 /* Helper function for removing a widget from it's container.
353 we own a separate reference to each object we try to unpack,
354 so extra referencing is not needed. */
355 static void unpack_widget(GtkWidget *widget)
357 g_assert(widget == NULL || GTK_IS_WIDGET(widget));
359 if (widget && widget->parent)
360 gtk_container_remove(GTK_CONTAINER(widget->parent), widget);
364 hildon_note_rebuild(HildonNote *note)
367 HildonNotePrivate *priv;
368 gboolean IsHorizontal = TRUE;
370 g_assert(HILDON_IS_NOTE(note));
372 priv = HILDON_NOTE_GET_PRIVATE (note);
373 dialog = GTK_DIALOG(note);
375 /* Reuse exiting content widgets for new layout */
376 unpack_widget(priv->label);
377 unpack_widget(priv->icon);
378 unpack_widget(priv->progressbar);
380 /* Destroy old layout and buttons */
382 gtk_widget_destroy(priv->box);
385 if (priv->okButton) {
386 gtk_widget_destroy(priv->okButton);
387 priv->okButton = NULL;
389 if (priv->cancelButton) {
390 gtk_widget_destroy(priv->cancelButton);
391 priv->cancelButton = NULL;
394 /* Add needed buttons and images for each note type */
395 switch (priv->note_n)
397 case HILDON_NOTE_CONFIRMATION_TYPE:
398 priv->okButton = gtk_dialog_add_button(dialog,
399 _("ecdg_bd_confirmation_note_ok"), GTK_RESPONSE_OK);
400 priv->cancelButton = gtk_dialog_add_button(dialog,
401 _("ecdg_bd_confirmation_note_cancel"), GTK_RESPONSE_CANCEL);
404 case HILDON_NOTE_CONFIRMATION_BUTTON_TYPE:
405 gtk_image_set_from_icon_name(GTK_IMAGE(priv->icon),
406 HILDON_NOTE_CONFIRMATION_ICON,
407 HILDON_ICON_SIZE_BIG_NOTE);
410 case HILDON_NOTE_INFORMATION_THEME_TYPE:
411 case HILDON_NOTE_INFORMATION_TYPE:
412 /* Add clickable OK button (cancel really,
413 but doesn't matter since this is info) */
414 priv->cancelButton = gtk_dialog_add_button(dialog,
415 _("ecdg_bd_information_note_ok"), GTK_RESPONSE_CANCEL);
416 gtk_image_set_from_icon_name(GTK_IMAGE(priv->icon),
417 HILDON_NOTE_INFORMATION_ICON,
418 HILDON_ICON_SIZE_BIG_NOTE);
421 case HILDON_NOTE_PROGRESSBAR_TYPE:
422 priv->cancelButton = gtk_dialog_add_button(dialog,
423 _("ecdg_bd_cancel_note_cancel"), GTK_RESPONSE_CANCEL);
424 IsHorizontal = FALSE;
432 /* Pack item with label horizontally */
433 priv->box = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
434 gtk_container_add(GTK_CONTAINER(dialog->vbox), priv->box);
437 GtkWidget *alignment = gtk_alignment_new(0, 0, 0, 0);
439 gtk_box_pack_start(GTK_BOX(priv->box), alignment, FALSE, FALSE, 0);
440 gtk_container_add(GTK_CONTAINER(alignment), priv->icon);
442 gtk_box_pack_start(GTK_BOX(priv->box), priv->label, TRUE, TRUE, 0);
445 /* Pack item with label vertically */
446 priv->box = gtk_vbox_new(FALSE, HILDON_MARGIN_DOUBLE);
447 gtk_container_add(GTK_CONTAINER(dialog->vbox), priv->box);
448 gtk_box_pack_start(GTK_BOX(priv->box), priv->label, TRUE, TRUE, 0);
450 if (priv->progressbar)
451 gtk_box_pack_start(GTK_BOX(priv->box), priv->progressbar, FALSE, FALSE, 0);
454 gtk_widget_show_all(priv->box);
458 * hildon_note_new_confirmation_add_buttons:
459 * @parent: the parent window. The X window ID of the parent window
460 * has to be the same as the X window ID of the application. This is
461 * important so that the window manager could handle the windows
463 * In GTK the X window ID can be checked using
464 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
465 * @description: the message to confirm
466 * @Varargs: arguments pairs for new buttons(label and return value).
467 * Terminate the list with %NULL value.
469 * Create a new confirmation note with custom buttons. Confirmation
470 * note has a text and any number of buttons. It's important to note
471 * that even though the name of the function might suggest, the
472 * default ok/cancel buttons are not appended but you have to provide
473 * all of the buttons.
475 * FIXME: This doc seems to be wrong, the two buttons aren't added so
476 * it would only contain the "additional" buttons? However, changing
477 * this would break those applications that rely on current behaviour.
479 * Returns: A #GtkWidget pointer of the note
481 GtkWidget *hildon_note_new_confirmation_add_buttons(GtkWindow *parent,
482 const gchar *description,
489 g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
491 GtkWidget *conf_note =
492 g_object_new(HILDON_TYPE_NOTE,
493 "note_type", HILDON_NOTE_CONFIRMATION_BUTTON_TYPE,
494 "description", description,
495 "icon", HILDON_NOTE_CONFIRMATION_ICON,
499 gtk_window_set_transient_for(GTK_WINDOW(conf_note), parent);
501 /* Add the buttons from varargs */
502 va_start(args, description);
505 message = va_arg(args, char *);
510 value = va_arg(args, int);
512 gtk_dialog_add_button(GTK_DIALOG(conf_note), message, value);
522 * hildon_note_new_confirmation:
523 * @parent: the parent window. The X window ID of the parent window
524 * has to be the same as the X window ID of the application. This is
525 * important so that the window manager could handle the windows
526 * correctly. In GTK the X window ID can be checked using
527 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
528 * @description: the message to confirm
530 * Create a new confirmation note. Confirmation note has text (description)
531 * that you specify, two buttons and a default confirmation stock icon.
533 * Returns: a #GtkWidget pointer of the note
535 GtkWidget *hildon_note_new_confirmation(GtkWindow * parent,
536 const gchar * description)
538 return hildon_note_new_confirmation_with_icon_name
539 (parent, description, HILDON_NOTE_CONFIRMATION_ICON);
543 * hildon_note_new_confirmation_with_icon_name:
544 * @parent: the parent window. The X window ID of the parent window
545 * has to be the same as the X window ID of the application. This is
546 * important so that the window manager could handle the windows
547 * correctly. In GTK the X window ID can be checked using
548 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
549 * @description: the message to confirm
550 * @icon_name: icon to be displayed. If NULL, default icon is used.
552 * Create a new confirmation note. Confirmation note has text(description)
553 * that you specify, two buttons and an icon.
555 * Returns: a #GtkWidget pointer of the note
557 GtkWidget *hildon_note_new_confirmation_with_icon_name(GtkWindow * parent,
563 GtkWidget *dialog = NULL;
565 g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
567 dialog = g_object_new(HILDON_TYPE_NOTE,
569 HILDON_NOTE_CONFIRMATION_TYPE,
570 "description", description, "icon",
573 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
579 * hildon_note_new_information:
580 * @parent: the parent window. The X window ID of the parent window
581 * has to be the same as the X window ID of the application. This is
582 * important so that the window manager could handle the windows
583 * correctly. In GTK the X window ID can be checked using
584 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
585 * @description: the message to confirm
587 * Create a new information note. Information note has a text(description)
588 * that you specify, an OK button and an icon.
590 * Returns: a #GtkWidget pointer of the note
592 GtkWidget *hildon_note_new_information(GtkWindow * parent,
593 const gchar * description)
595 return hildon_note_new_information_with_icon_name
596 (parent, description, HILDON_NOTE_INFORMATION_ICON);
600 * hildon_note_new_information_with_icon_name:
601 * @parent: the parent window. The X window ID of the parent window
602 * has to be the same as the X window ID of the application. This is
603 * important so that the window manager could handle the windows
604 * correctly. In GTK the X window ID can be checked using
605 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
606 * @description: the message to confirm
607 * @icon_name: icon to be displayed. If NULL, default icon is used.
609 * Create a new information note. Information note has text(description)
610 * that you specify, an OK button and an icon.
612 * Returns: a #GtkWidget pointer of the note
614 GtkWidget *hildon_note_new_information_with_icon_name(GtkWindow * parent,
620 GtkWidget *dialog = NULL;
622 g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
624 dialog = g_object_new(HILDON_TYPE_NOTE,
626 HILDON_NOTE_INFORMATION_THEME_TYPE,
627 "description", description,
628 "icon", icon_name, NULL);
630 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
636 * hildon_note_new_cancel_with_progress_bar:
637 * @parent: the parent window. The X window ID of the parent window
638 * has to be the same as the X window ID of the application. This is
639 * important so that the window manager could handle the windows
640 * correctly. In GTK the X window ID can be checked using
641 * GDK_WINDOW_XID(GTK_WIDGET(parent)->window).
642 * @description: the action to cancel
643 * @progressbar: a pointer to #GtkProgressBar to be filled with the
644 * progressbar assigned to this note. Use this to set the fraction of
645 * progressbar done. This parameter can be %NULL as well, in which
646 * case plain text cancel note appears.
648 * Create a new cancel note with a progress bar. Cancel note has
649 * text(description) that you specify, a Cancel button and a progress bar.
651 * Returns: a #GtkDialog. Use this to get rid of this note when you
654 GtkWidget *hildon_note_new_cancel_with_progress_bar(GtkWindow * parent,
660 GtkWidget *dialog = NULL;
662 g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
664 dialog = g_object_new(HILDON_TYPE_NOTE,
666 HILDON_NOTE_PROGRESSBAR_TYPE,
667 "description", description,
671 gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
678 * hildon_note_set_button_text:
679 * @note: a #HildonNote
680 * @text: sets the button text and if there is two buttons in dialog,
681 * the button texts will be <text>, "Cancel".
683 * Sets the button text to be used by the hildon_note widget.
685 void hildon_note_set_button_text(HildonNote * note, const gchar * text)
687 HildonNotePrivate *priv;
689 g_return_if_fail(HILDON_IS_NOTE(note));
691 priv = HILDON_NOTE_GET_PRIVATE(HILDON_NOTE(note));
692 if (priv->okButton) {
693 gtk_button_set_label(GTK_BUTTON(priv->okButton), text);
694 gtk_button_set_label(GTK_BUTTON(priv->cancelButton),
695 _("ecdg_bd_confirmation_note_cancel"));
697 gtk_button_set_label(GTK_BUTTON(priv->cancelButton), text);
702 * hildon_note_set_button_texts:
703 * @note: a #HildonNote
704 * @textOk: the new text of the default OK button
705 * @textCancel: the new text of the default cancel button
707 * Sets the button texts to be used by this hildon_note widget.
709 void hildon_note_set_button_texts(HildonNote * note,
710 const gchar * textOk,
711 const gchar * textCancel)
713 HildonNotePrivate *priv;
715 g_return_if_fail(HILDON_IS_NOTE(note));
717 priv = HILDON_NOTE_GET_PRIVATE(HILDON_NOTE(note));
718 if (priv->okButton) {
719 gtk_button_set_label(GTK_BUTTON(priv->okButton), textOk);
720 gtk_button_set_label(GTK_BUTTON(priv->cancelButton),
723 gtk_button_set_label(GTK_BUTTON(priv->cancelButton), textCancel);
727 /* We play a system sound when the note comes visible */
729 sound_handling(GtkWidget * widget, GdkEventExpose *event, gpointer data)
731 HildonNotePrivate *priv = HILDON_NOTE_GET_PRIVATE(widget);
732 g_signal_handler_disconnect(widget, priv->sound_signal_handler);
733 priv->sound_signal_handler = 0;
735 switch (priv->note_n)
737 case HILDON_NOTE_INFORMATION_TYPE:
738 case HILDON_NOTE_INFORMATION_THEME_TYPE:
739 hildon_play_system_sound(INFORMATION_SOUND_PATH);
741 case HILDON_NOTE_CONFIRMATION_TYPE:
742 case HILDON_NOTE_CONFIRMATION_BUTTON_TYPE:
743 hildon_play_system_sound(CONFIRMATION_SOUND_PATH);