2 * GTK - The GIMP Toolkit
3 * Copyright (C) 1999 Red Hat, Inc.
4 * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
5 * Copyright (C) 2003 Matthias Clasen <mclasen@redhat.com>
6 * Copyright (C) 2005 Carlos Garnacho Parro <carlosg@gnome.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
30 #include "gtkassistant.h"
32 #include "gtkaccessible.h"
33 #include "gtkbutton.h"
38 #include "gtksizegroup.h"
42 #include "gtkprivate.h"
43 #include "gtkbuildable.h"
47 #define GTK_ASSISTANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ASSISTANT, GtkAssistantPrivate))
49 #define HEADER_SPACING 12
50 #define ACTION_AREA_SPACING 12
52 typedef struct _GtkAssistantPage GtkAssistantPage;
54 struct _GtkAssistantPage
57 GtkAssistantPageType type;
61 GdkPixbuf *header_image;
62 GdkPixbuf *sidebar_image;
65 struct _GtkAssistantPrivate
67 GtkWidget *header_image;
68 GtkWidget *sidebar_image;
70 GtkWidget *action_area;
74 GtkAssistantPage *current_page;
76 GSList *visited_pages;
78 GtkSizeGroup *size_group;
80 GtkAssistantPageFunc forward_function;
81 gpointer forward_function_data;
82 GDestroyNotify forward_data_destroy;
85 static void gtk_assistant_class_init (GtkAssistantClass *class);
86 static void gtk_assistant_init (GtkAssistant *assistant);
87 static void gtk_assistant_destroy (GtkObject *object);
88 static void gtk_assistant_style_set (GtkWidget *widget,
90 static void gtk_assistant_size_request (GtkWidget *widget,
91 GtkRequisition *requisition);
92 static void gtk_assistant_size_allocate (GtkWidget *widget,
93 GtkAllocation *allocation);
94 static void gtk_assistant_map (GtkWidget *widget);
95 static void gtk_assistant_unmap (GtkWidget *widget);
96 static gboolean gtk_assistant_delete_event (GtkWidget *widget,
98 static gboolean gtk_assistant_expose (GtkWidget *widget,
99 GdkEventExpose *event);
100 static gboolean gtk_assistant_focus (GtkWidget *widget,
101 GtkDirectionType direction);
102 static void gtk_assistant_add (GtkContainer *container,
104 static void gtk_assistant_remove (GtkContainer *container,
106 static void gtk_assistant_forall (GtkContainer *container,
107 gboolean include_internals,
108 GtkCallback callback,
109 gpointer callback_data);
110 static void gtk_assistant_set_child_property (GtkContainer *container,
115 static void gtk_assistant_get_child_property (GtkContainer *container,
121 static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget);
123 static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface);
124 static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
126 const gchar *childname);
127 static gboolean gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
130 const gchar *tagname,
131 GMarkupParser *parser,
133 static void gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
136 const gchar *tagname,
143 CHILD_PROP_PAGE_TYPE,
144 CHILD_PROP_PAGE_TITLE,
145 CHILD_PROP_PAGE_HEADER_IMAGE,
146 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
147 CHILD_PROP_PAGE_COMPLETE
159 static guint signals [LAST_SIGNAL] = { 0 };
162 G_DEFINE_TYPE_WITH_CODE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW,
163 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
164 gtk_assistant_buildable_interface_init))
168 gtk_assistant_class_init (GtkAssistantClass *class)
170 GObjectClass *gobject_class;
171 GtkObjectClass *object_class;
172 GtkWidgetClass *widget_class;
173 GtkContainerClass *container_class;
175 gobject_class = (GObjectClass *) class;
176 object_class = (GtkObjectClass *) class;
177 widget_class = (GtkWidgetClass *) class;
178 container_class = (GtkContainerClass *) class;
180 object_class->destroy = gtk_assistant_destroy;
182 widget_class->style_set = gtk_assistant_style_set;
183 widget_class->size_request = gtk_assistant_size_request;
184 widget_class->size_allocate = gtk_assistant_size_allocate;
185 widget_class->map = gtk_assistant_map;
186 widget_class->unmap = gtk_assistant_unmap;
187 widget_class->delete_event = gtk_assistant_delete_event;
188 widget_class->expose_event = gtk_assistant_expose;
189 widget_class->focus = gtk_assistant_focus;
190 widget_class->get_accessible = gtk_assistant_get_accessible;
192 container_class->add = gtk_assistant_add;
193 container_class->remove = gtk_assistant_remove;
194 container_class->forall = gtk_assistant_forall;
195 container_class->set_child_property = gtk_assistant_set_child_property;
196 container_class->get_child_property = gtk_assistant_get_child_property;
199 * GtkAssistant::cancel:
200 * @assistant: the #GtkAssistant
202 * The ::cancel signal is emitted when then the cancel button is clicked.
207 g_signal_new (I_("cancel"),
208 G_TYPE_FROM_CLASS (gobject_class),
210 G_STRUCT_OFFSET (GtkAssistantClass, cancel),
212 g_cclosure_marshal_VOID__VOID,
216 * GtkAssistant::prepare:
217 * @assistant: the #GtkAssistant
218 * @page: the current page
220 * The ::prepare signal is emitted when a new page is set as the assistant's
221 * current page, before making the new page visible. A handler for this signal
222 * can do any preparation which are necessary before showing @page.
227 g_signal_new (I_("prepare"),
228 G_TYPE_FROM_CLASS (gobject_class),
230 G_STRUCT_OFFSET (GtkAssistantClass, prepare),
232 g_cclosure_marshal_VOID__OBJECT,
233 G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
236 * GtkAssistant::apply:
237 * @assistant: the @GtkAssistant
239 * The ::apply signal is emitted when the apply button is clicked. The default
240 * behavior of the #GtkAssistant is to switch to the page after the current
241 * page, unless the current page is the last one.
243 * A handler for the ::apply signal should carry out the actions for which
244 * the wizard has collected data. If the action takes a long time to complete,
245 * you might consider to put a page of type %GTK_ASSISTANT_PAGE_PROGRESS
246 * after the confirmation page and handle this operation within the
247 * #GtkAssistant::prepare signal of the progress page.
252 g_signal_new (I_("apply"),
253 G_TYPE_FROM_CLASS (gobject_class),
255 G_STRUCT_OFFSET (GtkAssistantClass, apply),
257 g_cclosure_marshal_VOID__VOID,
261 * GtkAssistant::close:
262 * @assistant: the #GtkAssistant
264 * The ::close signal is emitted either when the close button of
265 * a summary page is clicked, or when the apply button in the last
266 * page in the flow (of type %GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
271 g_signal_new (I_("close"),
272 G_TYPE_FROM_CLASS (gobject_class),
274 G_STRUCT_OFFSET (GtkAssistantClass, close),
276 g_cclosure_marshal_VOID__VOID,
279 gtk_widget_class_install_style_property (widget_class,
280 g_param_spec_int ("header-padding",
281 P_("Header Padding"),
282 P_("Number of pixels around the header."),
286 GTK_PARAM_READABLE));
287 gtk_widget_class_install_style_property (widget_class,
288 g_param_spec_int ("content-padding",
289 P_("Content Padding"),
290 P_("Number of pixels around the content pages."),
294 GTK_PARAM_READABLE));
297 * GtkAssistant:page-type:
299 * The type of the assistant page.
303 gtk_container_class_install_child_property (container_class,
304 CHILD_PROP_PAGE_TYPE,
305 g_param_spec_enum ("page-type",
307 P_("The type of the assistant page"),
308 GTK_TYPE_ASSISTANT_PAGE_TYPE,
309 GTK_ASSISTANT_PAGE_CONTENT,
310 GTK_PARAM_READWRITE));
313 * GtkAssistant:title:
315 * The title that is displayed in the page header.
317 * If title and header-image are both %NULL, no header is displayed.
321 gtk_container_class_install_child_property (container_class,
322 CHILD_PROP_PAGE_TITLE,
323 g_param_spec_string ("title",
325 P_("The title of the assistant page"),
327 GTK_PARAM_READWRITE));
330 * GtkAssistant:header-image:
332 * The image that is displayed next to the title in the page header.
334 * If title and header-image are both %NULL, no header is displayed.
338 gtk_container_class_install_child_property (container_class,
339 CHILD_PROP_PAGE_HEADER_IMAGE,
340 g_param_spec_object ("header-image",
342 P_("Header image for the assistant page"),
344 GTK_PARAM_READWRITE));
347 * GtkAssistant:header-image:
349 * The image that is displayed next to the page.
351 * Set this to %NULL to make the sidebar disappear.
355 gtk_container_class_install_child_property (container_class,
356 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
357 g_param_spec_object ("sidebar-image",
359 P_("Sidebar image for the assistant page"),
361 GTK_PARAM_READWRITE));
363 * GtkAssistant:complete:
365 * Setting the "complete" child property to %TRUE marks a page as complete
366 * (i.e.: all the required fields are filled out). GTK+ uses this information
367 * to control the sensitivity of the navigation buttons.
371 gtk_container_class_install_child_property (container_class,
372 CHILD_PROP_PAGE_COMPLETE,
373 g_param_spec_boolean ("complete",
375 P_("Whether all required fields on the page have been filled out"),
379 g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate));
383 default_forward_function (gint current_page, gpointer data)
385 GtkAssistant *assistant;
386 GtkAssistantPrivate *priv;
387 GtkAssistantPage *page_info;
390 assistant = GTK_ASSISTANT (data);
391 priv = assistant->priv;
393 page_node = g_list_nth (priv->pages, ++current_page);
398 page_info = (GtkAssistantPage *) page_node->data;
400 while (page_node && !GTK_WIDGET_VISIBLE (page_info->page))
402 page_node = page_node->next;
406 page_info = (GtkAssistantPage *) page_node->data;
413 compute_last_button_state (GtkAssistant *assistant)
415 GtkAssistantPrivate *priv = assistant->priv;
416 GtkAssistantPage *page_info, *current_page_info;
417 gint count, page_num, n_pages;
420 page_num = gtk_assistant_get_current_page (assistant);
421 n_pages = gtk_assistant_get_n_pages (assistant);
422 current_page_info = page_info = g_list_nth_data (priv->pages, page_num);
424 while (page_num >= 0 && page_num < n_pages &&
425 page_info->type == GTK_ASSISTANT_PAGE_CONTENT &&
426 (count == 0 || page_info->complete) &&
429 page_num = (priv->forward_function) (page_num, priv->forward_function_data);
430 page_info = g_list_nth_data (priv->pages, page_num);
435 /* make the last button visible if we can skip multiple
436 * pages and end on a confirmation or summary page
438 if (count > 1 && page_info &&
439 (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM ||
440 page_info->type == GTK_ASSISTANT_PAGE_SUMMARY))
442 gtk_widget_show (assistant->last);
443 gtk_widget_set_sensitive (assistant->last,
444 current_page_info->complete);
447 gtk_widget_hide (assistant->last);
451 set_assistant_header_image (GtkAssistant *assistant)
453 GtkAssistantPrivate *priv = assistant->priv;
455 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image),
456 priv->current_page->header_image);
460 set_assistant_sidebar_image (GtkAssistant *assistant)
462 GtkAssistantPrivate *priv = assistant->priv;
464 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image),
465 priv->current_page->sidebar_image);
467 if (priv->current_page->sidebar_image)
468 gtk_widget_show (priv->sidebar_image);
470 gtk_widget_hide (priv->sidebar_image);
474 set_assistant_buttons_state (GtkAssistant *assistant)
476 GtkAssistantPrivate *priv = assistant->priv;
478 if (!priv->current_page)
481 switch (priv->current_page->type)
483 case GTK_ASSISTANT_PAGE_INTRO:
484 gtk_widget_set_sensitive (assistant->cancel, TRUE);
485 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
486 gtk_widget_grab_default (assistant->forward);
487 gtk_widget_show (assistant->cancel);
488 gtk_widget_show (assistant->forward);
489 gtk_widget_hide (assistant->back);
490 gtk_widget_hide (assistant->apply);
491 gtk_widget_hide (assistant->close);
492 compute_last_button_state (assistant);
494 case GTK_ASSISTANT_PAGE_CONFIRM:
495 gtk_widget_set_sensitive (assistant->cancel, TRUE);
496 gtk_widget_set_sensitive (assistant->back, TRUE);
497 gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
498 gtk_widget_grab_default (assistant->apply);
499 gtk_widget_show (assistant->cancel);
500 gtk_widget_show (assistant->back);
501 gtk_widget_show (assistant->apply);
502 gtk_widget_hide (assistant->forward);
503 gtk_widget_hide (assistant->close);
504 gtk_widget_hide (assistant->last);
506 case GTK_ASSISTANT_PAGE_CONTENT:
507 gtk_widget_set_sensitive (assistant->cancel, TRUE);
508 gtk_widget_set_sensitive (assistant->back, TRUE);
509 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
510 gtk_widget_grab_default (assistant->forward);
511 gtk_widget_show (assistant->cancel);
512 gtk_widget_show (assistant->back);
513 gtk_widget_show (assistant->forward);
514 gtk_widget_hide (assistant->apply);
515 gtk_widget_hide (assistant->close);
516 compute_last_button_state (assistant);
518 case GTK_ASSISTANT_PAGE_SUMMARY:
519 gtk_widget_set_sensitive (assistant->close, TRUE);
520 gtk_widget_grab_default (assistant->close);
521 gtk_widget_show (assistant->close);
522 gtk_widget_hide (assistant->cancel);
523 gtk_widget_hide (assistant->back);
524 gtk_widget_hide (assistant->forward);
525 gtk_widget_hide (assistant->apply);
526 gtk_widget_hide (assistant->last);
528 case GTK_ASSISTANT_PAGE_PROGRESS:
529 gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
530 gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
531 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
532 gtk_widget_grab_default (assistant->forward);
533 gtk_widget_show (assistant->cancel);
534 gtk_widget_show (assistant->back);
535 gtk_widget_show (assistant->forward);
536 gtk_widget_hide (assistant->apply);
537 gtk_widget_hide (assistant->close);
538 gtk_widget_hide (assistant->last);
541 g_assert_not_reached ();
544 /* this is quite general, we don't want to
545 * go back if it's the first page */
546 if (!priv->visited_pages)
547 gtk_widget_hide (assistant->back);
551 set_current_page (GtkAssistant *assistant,
552 GtkAssistantPage *page)
554 GtkAssistantPrivate *priv = assistant->priv;
555 GtkAssistantPage *old_page;
557 if (priv->current_page &&
558 GTK_WIDGET_DRAWABLE (priv->current_page->page))
559 old_page = priv->current_page;
563 priv->current_page = page;
565 set_assistant_buttons_state (assistant);
566 set_assistant_header_image (assistant);
567 set_assistant_sidebar_image (assistant);
569 g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
571 if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
573 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
574 gtk_widget_map (priv->current_page->page);
575 gtk_widget_map (priv->current_page->title);
578 if (old_page && GTK_WIDGET_MAPPED (old_page->page))
580 gtk_widget_set_child_visible (old_page->page, FALSE);
581 gtk_widget_unmap (old_page->page);
582 gtk_widget_unmap (old_page->title);
585 if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD))
587 GtkWidget *button[6];
590 /* find the best button to focus */
591 button[0] = assistant->apply;
592 button[1] = assistant->close;
593 button[2] = assistant->forward;
594 button[3] = assistant->back;
595 button[4] = assistant->cancel;
596 button[5] = assistant->last;
597 for (i = 0; i < 6; i++)
599 if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
601 gtk_widget_grab_focus (button[i]);
607 gtk_widget_queue_resize (GTK_WIDGET (assistant));
611 compute_next_step (GtkAssistant *assistant)
613 GtkAssistantPrivate *priv = assistant->priv;
614 GtkAssistantPage *page_info;
615 gint current_page, n_pages, next_page;
617 current_page = gtk_assistant_get_current_page (assistant);
618 page_info = priv->current_page;
619 n_pages = gtk_assistant_get_n_pages (assistant);
621 next_page = (priv->forward_function) (current_page,
622 priv->forward_function_data);
624 if (next_page >= 0 && next_page < n_pages)
626 priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info);
627 set_current_page (assistant, g_list_nth_data (priv->pages, next_page));
636 on_assistant_close (GtkWidget *widget,
637 GtkAssistant *assistant)
639 g_signal_emit (assistant, signals [CLOSE], 0, NULL);
643 on_assistant_apply (GtkWidget *widget,
644 GtkAssistant *assistant)
648 g_signal_emit (assistant, signals [APPLY], 0);
650 success = compute_next_step (assistant);
652 /* if the assistant hasn't switched to another page, just emit
653 * the CLOSE signal, it't the last page in the assistant flow
656 g_signal_emit (assistant, signals [CLOSE], 0);
660 on_assistant_forward (GtkWidget *widget,
661 GtkAssistant *assistant)
663 if (!compute_next_step (assistant))
664 g_critical ("Page flow is broken, you may want to end it with a page of "
665 "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY");
669 on_assistant_back (GtkWidget *widget,
670 GtkAssistant *assistant)
672 GtkAssistantPrivate *priv = assistant->priv;
673 GtkAssistantPage *page_info;
676 /* skip the progress pages when going back */
679 page_node = priv->visited_pages;
681 g_return_if_fail (page_node != NULL);
683 priv->visited_pages = priv->visited_pages->next;
684 page_info = (GtkAssistantPage *) page_node->data;
685 g_slist_free_1 (page_node);
687 while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS ||
688 !GTK_WIDGET_VISIBLE (page_info->page));
690 set_current_page (assistant, page_info);
694 on_assistant_cancel (GtkWidget *widget,
695 GtkAssistant *assistant)
697 g_signal_emit (assistant, signals [CANCEL], 0, NULL);
701 on_assistant_last (GtkWidget *widget,
702 GtkAssistant *assistant)
704 GtkAssistantPrivate *priv = assistant->priv;
706 while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT &&
707 priv->current_page->complete)
708 compute_next_step (assistant);
712 alternative_button_order (GtkAssistant *assistant)
714 GtkSettings *settings;
718 screen = gtk_widget_get_screen (GTK_WIDGET (assistant));
719 settings = gtk_settings_get_for_screen (screen);
721 g_object_get (settings,
722 "gtk-alternative-button-order", &result,
728 gtk_assistant_init (GtkAssistant *assistant)
730 GtkAssistantPrivate *priv;
732 priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
734 gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE);
735 gtk_container_set_border_width (GTK_CONTAINER (assistant), 12);
737 gtk_widget_push_composite_child ();
740 priv->header_image = gtk_image_new ();
741 gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5);
742 gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant));
743 gtk_widget_show (priv->header_image);
746 priv->sidebar_image = gtk_image_new ();
747 gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.);
748 gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant));
749 gtk_widget_show (priv->sidebar_image);
752 priv->action_area = gtk_hbox_new (FALSE, 6);
754 assistant->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
755 assistant->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
756 assistant->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
757 assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
758 assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
759 assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
760 GTK_WIDGET_SET_FLAGS (assistant->close, GTK_CAN_DEFAULT);
761 GTK_WIDGET_SET_FLAGS (assistant->apply, GTK_CAN_DEFAULT);
762 GTK_WIDGET_SET_FLAGS (assistant->forward, GTK_CAN_DEFAULT);
764 priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
765 gtk_size_group_add_widget (priv->size_group, assistant->close);
766 gtk_size_group_add_widget (priv->size_group, assistant->apply);
767 gtk_size_group_add_widget (priv->size_group, assistant->forward);
768 gtk_size_group_add_widget (priv->size_group, assistant->back);
769 gtk_size_group_add_widget (priv->size_group, assistant->cancel);
770 gtk_size_group_add_widget (priv->size_group, assistant->last);
772 if (!alternative_button_order (assistant))
774 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
775 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
776 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
777 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
778 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
779 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
783 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
784 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
785 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
786 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
787 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
788 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
791 gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant));
792 gtk_widget_show (assistant->forward);
793 gtk_widget_show (assistant->back);
794 gtk_widget_show (assistant->cancel);
795 gtk_widget_show (priv->action_area);
797 gtk_widget_pop_composite_child ();
800 priv->current_page = NULL;
801 priv->visited_pages = NULL;
803 priv->forward_function = default_forward_function;
804 priv->forward_function_data = assistant;
805 priv->forward_data_destroy = NULL;
807 g_signal_connect (G_OBJECT (assistant->close), "clicked",
808 G_CALLBACK (on_assistant_close), assistant);
809 g_signal_connect (G_OBJECT (assistant->apply), "clicked",
810 G_CALLBACK (on_assistant_apply), assistant);
811 g_signal_connect (G_OBJECT (assistant->forward), "clicked",
812 G_CALLBACK (on_assistant_forward), assistant);
813 g_signal_connect (G_OBJECT (assistant->back), "clicked",
814 G_CALLBACK (on_assistant_back), assistant);
815 g_signal_connect (G_OBJECT (assistant->cancel), "clicked",
816 G_CALLBACK (on_assistant_cancel), assistant);
817 g_signal_connect (G_OBJECT (assistant->last), "clicked",
818 G_CALLBACK (on_assistant_last), assistant);
822 gtk_assistant_set_child_property (GtkContainer *container,
830 case CHILD_PROP_PAGE_TYPE:
831 gtk_assistant_set_page_type (GTK_ASSISTANT (container), child,
832 g_value_get_enum (value));
834 case CHILD_PROP_PAGE_TITLE:
835 gtk_assistant_set_page_title (GTK_ASSISTANT (container), child,
836 g_value_get_string (value));
838 case CHILD_PROP_PAGE_HEADER_IMAGE:
839 gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child,
840 g_value_get_object (value));
842 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
843 gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child,
844 g_value_get_object (value));
846 case CHILD_PROP_PAGE_COMPLETE:
847 gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child,
848 g_value_get_boolean (value));
851 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
857 gtk_assistant_get_child_property (GtkContainer *container,
865 case CHILD_PROP_PAGE_TYPE:
866 g_value_set_enum (value,
867 gtk_assistant_get_page_type (GTK_ASSISTANT (container), child));
869 case CHILD_PROP_PAGE_TITLE:
870 g_value_set_string (value,
871 gtk_assistant_get_page_title (GTK_ASSISTANT (container), child));
873 case CHILD_PROP_PAGE_HEADER_IMAGE:
874 g_value_set_object (value,
875 gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child));
877 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
878 g_value_set_object (value,
879 gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child));
881 case CHILD_PROP_PAGE_COMPLETE:
882 g_value_set_boolean (value,
883 gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child));
886 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
892 on_page_notify_visibility (GtkWidget *widget,
896 GtkAssistant *assistant = GTK_ASSISTANT (data);
898 /* update buttons state, flow may have changed */
899 if (GTK_WIDGET_MAPPED (assistant))
900 set_assistant_buttons_state (assistant);
904 remove_page (GtkAssistant *assistant,
907 GtkAssistantPrivate *priv = assistant->priv;
908 GtkAssistantPage *page_info;
911 page_info = element->data;
913 /* If this is the current page, we need to switch away. */
914 if (page_info == priv->current_page)
916 if (!compute_next_step (assistant))
918 /* The best we can do at this point is probably to pick the first
921 page_node = priv->pages;
923 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
924 page_node = page_node->next;
926 if (page_node == element)
927 page_node = page_node->next;
930 priv->current_page = page_node->data;
932 priv->current_page = NULL;
936 priv->pages = g_list_remove_link (priv->pages, element);
937 priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info);
939 g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant);
940 gtk_widget_unparent (page_info->page);
942 if (page_info->header_image)
943 g_object_unref (page_info->header_image);
945 if (page_info->sidebar_image)
946 g_object_unref (page_info->sidebar_image);
948 gtk_widget_destroy (page_info->title);
949 g_slice_free (GtkAssistantPage, page_info);
950 g_list_free_1 (element);
954 gtk_assistant_destroy (GtkObject *object)
956 GtkAssistant *assistant = GTK_ASSISTANT (object);
957 GtkAssistantPrivate *priv = assistant->priv;
959 if (priv->header_image)
961 gtk_widget_destroy (priv->header_image);
962 priv->header_image = NULL;
965 if (priv->sidebar_image)
967 gtk_widget_destroy (priv->sidebar_image);
968 priv->sidebar_image = NULL;
971 if (priv->action_area)
973 gtk_widget_destroy (priv->action_area);
974 priv->action_area = NULL;
977 if (priv->size_group)
979 g_object_unref (priv->size_group);
980 priv->size_group = NULL;
983 if (priv->forward_function)
985 if (priv->forward_function_data &&
986 priv->forward_data_destroy)
987 priv->forward_data_destroy (priv->forward_function_data);
989 priv->forward_function = NULL;
990 priv->forward_function_data = NULL;
991 priv->forward_data_destroy = NULL;
994 if (priv->visited_pages)
996 g_slist_free (priv->visited_pages);
997 priv->visited_pages = NULL;
1000 /* We set current to NULL so that the remove code doesn't try
1001 * to do anything funny */
1002 priv->current_page = NULL;
1005 remove_page (GTK_ASSISTANT (object), priv->pages);
1007 GTK_OBJECT_CLASS (gtk_assistant_parent_class)->destroy (object);
1011 find_page (GtkAssistant *assistant,
1014 GtkAssistantPrivate *priv = assistant->priv;
1015 GList *child = priv->pages;
1019 GtkAssistantPage *page_info = child->data;
1020 if (page_info->page == page)
1023 child = child->next;
1030 set_title_colors (GtkWidget *assistant,
1031 GtkWidget *title_label)
1035 gtk_widget_ensure_style (assistant);
1036 style = gtk_widget_get_style (assistant);
1038 /* change colors schema, for making the header text visible */
1039 gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]);
1040 gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]);
1044 set_title_font (GtkWidget *assistant,
1045 GtkWidget *title_label)
1047 PangoFontDescription *desc;
1050 desc = pango_font_description_new ();
1051 size = pango_font_description_get_size (assistant->style->font_desc);
1053 pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD);
1054 pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE);
1056 gtk_widget_modify_font (title_label, desc);
1057 pango_font_description_free (desc);
1061 gtk_assistant_style_set (GtkWidget *widget,
1062 GtkStyle *old_style)
1064 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1065 GtkAssistantPrivate *priv = assistant->priv;
1072 GtkAssistantPage *page = list->data;
1074 set_title_colors (widget, page->title);
1075 set_title_font (widget, page->title);
1082 gtk_assistant_size_request (GtkWidget *widget,
1083 GtkRequisition *requisition)
1085 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1086 GtkAssistantPrivate *priv = assistant->priv;
1087 GtkRequisition child_requisition;
1088 gint header_padding, content_padding;
1089 gint width, height, header_width, header_height;
1092 gtk_widget_style_get (widget,
1093 "header-padding", &header_padding,
1094 "content-padding", &content_padding,
1097 header_width = header_height = 0;
1102 GtkAssistantPage *page = list->data;
1105 gtk_widget_size_request (page->page, &child_requisition);
1106 width = MAX (width, child_requisition.width);
1107 height = MAX (height, child_requisition.height);
1109 gtk_widget_size_request (page->title, &child_requisition);
1110 w = child_requisition.width;
1111 h = child_requisition.height;
1113 if (page->header_image)
1115 w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING;
1116 h = MAX (h, gdk_pixbuf_get_height (page->header_image));
1119 header_width = MAX (header_width, w);
1120 header_height = MAX (header_height, h);
1125 gtk_widget_size_request (priv->sidebar_image, &child_requisition);
1126 width += child_requisition.width;
1127 height = MAX (height, child_requisition.height);
1129 gtk_widget_set_size_request (priv->header_image, header_width, header_height);
1130 gtk_widget_size_request (priv->header_image, &child_requisition);
1131 width = MAX (width, header_width) + 2 * header_padding;
1132 height += header_height + 2 * header_padding;
1134 gtk_widget_size_request (priv->action_area, &child_requisition);
1135 width = MAX (width, child_requisition.width);
1136 height += child_requisition.height + ACTION_AREA_SPACING;
1138 width += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1139 height += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1141 requisition->width = width;
1142 requisition->height = height;
1146 gtk_assistant_size_allocate (GtkWidget *widget,
1147 GtkAllocation *allocation)
1149 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1150 GtkAssistantPrivate *priv = assistant->priv;
1151 GtkRequisition header_requisition;
1152 GtkAllocation child_allocation, header_allocation;
1153 gint header_padding, content_padding;
1157 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1158 pages = priv->pages;
1160 gtk_widget_style_get (widget,
1161 "header-padding", &header_padding,
1162 "content-padding", &content_padding,
1165 widget->allocation = *allocation;
1168 gtk_widget_get_child_requisition (priv->header_image, &header_requisition);
1170 header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding;
1171 header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding;
1172 header_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding;
1173 header_allocation.height = header_requisition.height;
1175 gtk_widget_size_allocate (priv->header_image, &header_allocation);
1178 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1179 child_allocation.y = allocation->height -
1180 GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
1181 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
1182 child_allocation.height = priv->action_area->requisition.height;
1184 gtk_widget_size_allocate (priv->action_area, &child_allocation);
1188 child_allocation.x = allocation->width -
1189 GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
1191 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1193 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1194 priv->header_image->allocation.height + 2 * header_padding;
1195 child_allocation.width = priv->sidebar_image->requisition.width;
1196 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1197 priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;
1199 gtk_widget_size_allocate (priv->sidebar_image, &child_allocation);
1202 child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding;
1203 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1204 priv->header_image->allocation.height + 2 * header_padding + content_padding;
1205 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding;
1206 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1207 priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding;
1209 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1212 child_allocation.x += priv->sidebar_image->allocation.width;
1214 child_allocation.width -= priv->sidebar_image->allocation.width;
1219 GtkAssistantPage *page = pages->data;
1221 gtk_widget_size_allocate (page->page, &child_allocation);
1222 gtk_widget_size_allocate (page->title, &header_allocation);
1223 pages = pages->next;
1228 gtk_assistant_map (GtkWidget *widget)
1230 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1231 GtkAssistantPrivate *priv = assistant->priv;
1233 GtkAssistantPage *page;
1235 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1237 gtk_widget_map (priv->header_image);
1238 gtk_widget_map (priv->action_area);
1240 if (GTK_WIDGET_VISIBLE (priv->sidebar_image) &&
1241 !GTK_WIDGET_MAPPED (priv->sidebar_image))
1242 gtk_widget_map (priv->sidebar_image);
1244 /* if there's no default page, pick the first one */
1246 if (!priv->current_page)
1248 page_node = priv->pages;
1250 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
1251 page_node = page_node->next;
1254 page = page_node->data;
1258 GTK_WIDGET_VISIBLE (page->page) &&
1259 !GTK_WIDGET_MAPPED (page->page))
1260 set_current_page (assistant, page);
1262 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
1266 gtk_assistant_unmap (GtkWidget *widget)
1268 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1269 GtkAssistantPrivate *priv = assistant->priv;
1271 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1273 gtk_widget_unmap (priv->header_image);
1274 gtk_widget_unmap (priv->action_area);
1276 if (GTK_WIDGET_DRAWABLE (priv->sidebar_image))
1277 gtk_widget_unmap (priv->sidebar_image);
1279 if (priv->current_page &&
1280 GTK_WIDGET_DRAWABLE (priv->current_page->page))
1281 gtk_widget_unmap (priv->current_page->page);
1283 g_slist_free (priv->visited_pages);
1284 priv->visited_pages = NULL;
1285 priv->current_page = NULL;
1287 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget);
1291 gtk_assistant_delete_event (GtkWidget *widget,
1294 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1295 GtkAssistantPrivate *priv = assistant->priv;
1297 /* Do not allow cancelling in the middle of a progress page */
1298 if (priv->current_page &&
1299 (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS ||
1300 priv->current_page->complete))
1301 g_signal_emit (widget, signals [CANCEL], 0, NULL);
1307 assistant_paint_colored_box (GtkWidget *widget)
1309 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1310 GtkAssistantPrivate *priv = assistant->priv;
1311 gint border_width, header_padding, content_padding;
1313 gint content_x, content_width;
1316 cr = gdk_cairo_create (widget->window);
1317 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1318 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1320 gtk_widget_style_get (widget,
1321 "header-padding", &header_padding,
1322 "content-padding", &content_padding,
1326 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]);
1327 cairo_rectangle (cr,
1330 widget->allocation.width - 2 * border_width,
1331 widget->allocation.height - priv->action_area->allocation.height - 2 * border_width - ACTION_AREA_SPACING);
1335 content_x = content_padding + border_width;
1336 content_width = widget->allocation.width - 2 * content_padding - 2 * border_width;
1338 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1341 content_x += priv->sidebar_image->allocation.width;
1342 content_width -= priv->sidebar_image->allocation.width;
1345 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]);
1347 cairo_rectangle (cr,
1349 priv->header_image->allocation.height + content_padding + 2 * header_padding + border_width,
1351 widget->allocation.height - 2 * border_width - priv->action_area->allocation.height -
1352 priv->header_image->allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING);
1359 gtk_assistant_expose (GtkWidget *widget,
1360 GdkEventExpose *event)
1362 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1363 GtkAssistantPrivate *priv = assistant->priv;
1364 GtkContainer *container;
1366 if (GTK_WIDGET_DRAWABLE (widget))
1368 container = GTK_CONTAINER (widget);
1370 assistant_paint_colored_box (widget);
1372 gtk_container_propagate_expose (container, priv->header_image, event);
1373 gtk_container_propagate_expose (container, priv->sidebar_image, event);
1374 gtk_container_propagate_expose (container, priv->action_area, event);
1376 if (priv->current_page)
1378 gtk_container_propagate_expose (container, priv->current_page->page, event);
1379 gtk_container_propagate_expose (container, priv->current_page->title, event);
1387 gtk_assistant_focus (GtkWidget *widget,
1388 GtkDirectionType direction)
1390 GtkAssistantPrivate *priv;
1391 GtkContainer *container;
1393 container = GTK_CONTAINER (widget);
1394 priv = GTK_ASSISTANT (widget)->priv;
1396 /* we only have to care about 2 widgets, action area and the current page */
1397 if (container->focus_child == priv->action_area)
1399 if (!gtk_widget_child_focus (priv->action_area, direction) &&
1400 (priv->current_page == NULL ||
1401 !gtk_widget_child_focus (priv->current_page->page, direction)))
1403 /* if we're leaving the action area and the current page hasn't
1404 any focusable widget, clear focus and go back to the action area */
1405 gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL);
1406 gtk_widget_child_focus (priv->action_area, direction);
1411 if ((priv->current_page == NULL ||
1412 !gtk_widget_child_focus (priv->current_page->page, direction)) &&
1413 !gtk_widget_child_focus (priv->action_area, direction))
1415 /* if we're leaving the current page and there isn't nothing focusable
1416 in the action area, try to clear focus and go back to the page */
1417 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
1418 if (priv->current_page != NULL)
1419 gtk_widget_child_focus (priv->current_page->page, direction);
1427 gtk_assistant_add (GtkContainer *container,
1430 gtk_assistant_append_page (GTK_ASSISTANT (container), page);
1434 gtk_assistant_remove (GtkContainer *container,
1437 GtkAssistant *assistant = (GtkAssistant*) container;
1440 element = find_page (assistant, page);
1444 remove_page (assistant, element);
1445 gtk_widget_queue_resize ((GtkWidget *) container);
1450 gtk_assistant_forall (GtkContainer *container,
1451 gboolean include_internals,
1452 GtkCallback callback,
1453 gpointer callback_data)
1455 GtkAssistant *assistant = (GtkAssistant*) container;
1456 GtkAssistantPrivate *priv = assistant->priv;
1459 if (include_internals)
1461 (*callback) (priv->header_image, callback_data);
1462 (*callback) (priv->sidebar_image, callback_data);
1463 (*callback) (priv->action_area, callback_data);
1466 pages = priv->pages;
1470 GtkAssistantPage *page = (GtkAssistantPage *) pages->data;
1472 (*callback) (page->page, callback_data);
1474 if (include_internals)
1475 (*callback) (page->title, callback_data);
1477 pages = pages->next;
1482 * gtk_assistant_new:
1484 * Creates a new #GtkAssistant.
1486 * Return value: a newly created #GtkAssistant
1491 gtk_assistant_new (void)
1493 GtkWidget *assistant;
1495 assistant = g_object_new (GTK_TYPE_ASSISTANT, NULL);
1501 * gtk_assistant_get_current_page:
1502 * @assistant: a #GtkAssistant
1504 * Returns the page number of the current page
1506 * Return value: The index (starting from 0) of the current page in
1507 * the @assistant, if the @assistant has no pages, -1 will be returned
1512 gtk_assistant_get_current_page (GtkAssistant *assistant)
1514 GtkAssistantPrivate *priv;
1516 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), -1);
1518 priv = assistant->priv;
1520 if (!priv->pages || !priv->current_page)
1523 return g_list_index (priv->pages, priv->current_page);
1527 * gtk_assistant_set_current_page:
1528 * @assistant: a #GtkAssistant
1529 * @page_num: index of the page to switch to, starting from 0.
1530 * If negative, the last page will be used. If greater
1531 * than the number of pages in the @assistant, nothing
1534 * Switches the page to @page_num. Note that this will only be necessary
1535 * in custom buttons, as the @assistant flow can be set with
1536 * gtk_assistant_set_forward_page_func().
1541 gtk_assistant_set_current_page (GtkAssistant *assistant,
1544 GtkAssistantPrivate *priv;
1545 GtkAssistantPage *page;
1547 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1549 priv = assistant->priv;
1552 page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num);
1554 page = (GtkAssistantPage *) g_list_last (priv->pages);
1556 g_return_if_fail (page != NULL);
1558 if (priv->current_page == page)
1561 /* only add the page to the visited list if the
1562 * assistant is mapped, if not, just use it as an
1563 * initial page setting, for the cases where the
1564 * initial page is != to 0
1566 if (GTK_WIDGET_MAPPED (assistant))
1567 priv->visited_pages = g_slist_prepend (priv->visited_pages,
1568 priv->current_page);
1570 set_current_page (assistant, page);
1574 * gtk_assistant_get_n_pages:
1575 * @assistant: a #GtkAssistant
1577 * Returns the number of pages in the @assistant
1579 * Return value: The number of pages in the @assistant.
1584 gtk_assistant_get_n_pages (GtkAssistant *assistant)
1586 GtkAssistantPrivate *priv;
1588 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1590 priv = assistant->priv;
1592 return g_list_length (priv->pages);
1596 * gtk_assistant_get_nth_page:
1597 * @assistant: a #GtkAssistant
1598 * @page_num: The index of a page in the @assistant, or -1 to get the last page;
1600 * Returns the child widget contained in page number @page_num.
1602 * Return value: The child widget, or %NULL if @page_num is out of bounds.
1607 gtk_assistant_get_nth_page (GtkAssistant *assistant,
1610 GtkAssistantPrivate *priv;
1611 GtkAssistantPage *page;
1614 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1616 priv = assistant->priv;
1618 elem = g_list_nth (priv->pages, page_num);
1623 page = (GtkAssistantPage *) elem->data;
1629 * gtk_assistant_prepend_page:
1630 * @assistant: a #GtkAssistant
1631 * @page: a #GtkWidget
1633 * Prepends a page to the @assistant.
1635 * Return value: the index (starting at 0) of the inserted page
1640 gtk_assistant_prepend_page (GtkAssistant *assistant,
1643 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1644 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1646 return gtk_assistant_insert_page (assistant, page, 0);
1650 * gtk_assistant_append_page:
1651 * @assistant: a #GtkAssistant
1652 * @page: a #GtkWidget
1654 * Appends a page to the @assistant.
1656 * Return value: the index (starting at 0) of the inserted page
1661 gtk_assistant_append_page (GtkAssistant *assistant,
1664 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1665 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1667 return gtk_assistant_insert_page (assistant, page, -1);
1671 * gtk_assistant_insert_page:
1672 * @assistant: a #GtkAssistant
1673 * @page: a #GtkWidget
1674 * @position: the index (starting at 0) at which to insert the page,
1675 * or -1 to append the page to the @assistant
1677 * Inserts a page in the @assistant at a given position.
1679 * Return value: the index (starting from 0) of the inserted page
1684 gtk_assistant_insert_page (GtkAssistant *assistant,
1688 GtkAssistantPrivate *priv;
1689 GtkAssistantPage *page_info;
1692 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1693 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1694 g_return_val_if_fail (page->parent == NULL, 0);
1695 g_return_val_if_fail (!GTK_WIDGET_TOPLEVEL (page), 0);
1697 priv = assistant->priv;
1699 page_info = g_slice_new0 (GtkAssistantPage);
1700 page_info->page = page;
1701 page_info->title = gtk_label_new (NULL);
1703 g_signal_connect (G_OBJECT (page), "notify::visible",
1704 G_CALLBACK (on_page_notify_visibility), assistant);
1706 gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5);
1707 set_title_colors (GTK_WIDGET (assistant), page_info->title);
1708 set_title_font (GTK_WIDGET (assistant), page_info->title);
1709 gtk_widget_show (page_info->title);
1711 n_pages = g_list_length (priv->pages);
1713 if (position < 0 || position > n_pages)
1716 priv->pages = g_list_insert (priv->pages, page_info, position);
1718 gtk_widget_set_child_visible (page_info->page, FALSE);
1719 gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant));
1720 gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant));
1722 if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant)))
1724 gtk_widget_realize (page_info->page);
1725 gtk_widget_realize (page_info->title);
1728 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1734 * gtk_assistant_set_forward_page_func:
1735 * @assistant: a #GtkAssistant
1736 * @page_func: the #GtkAssistantPageFunc, or %NULL to use the default one
1737 * @data: user data for @page_func
1738 * @destroy: destroy notifier for @data
1740 * Sets the page forwarding function to be @page_func, this function will
1741 * be used to determine what will be the next page when the user presses
1742 * the forward button. Setting @page_func to %NULL will make the assistant
1743 * to use the default forward function, which just goes to the next visible
1749 gtk_assistant_set_forward_page_func (GtkAssistant *assistant,
1750 GtkAssistantPageFunc page_func,
1752 GDestroyNotify destroy)
1754 GtkAssistantPrivate *priv;
1756 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1758 priv = assistant->priv;
1760 if (priv->forward_data_destroy &&
1761 priv->forward_function_data)
1762 (*priv->forward_data_destroy) (priv->forward_function_data);
1766 priv->forward_function = page_func;
1767 priv->forward_function_data = data;
1768 priv->forward_data_destroy = destroy;
1772 priv->forward_function = default_forward_function;
1773 priv->forward_function_data = assistant;
1774 priv->forward_data_destroy = NULL;
1777 /* Page flow has possibly changed, so the
1778 buttons state might need to change too */
1779 set_assistant_buttons_state (assistant);
1783 * gtk_assistant_add_action_widget:
1784 * @assistant: a #GtkAssistant
1785 * @child: a #GtkWidget
1787 * Adds a widget to the action area of a #GtkAssistant.
1792 gtk_assistant_add_action_widget (GtkAssistant *assistant,
1795 GtkAssistantPrivate *priv;
1797 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1798 g_return_if_fail (GTK_IS_WIDGET (child));
1800 priv = assistant->priv;
1802 if (GTK_IS_BUTTON (child))
1803 gtk_size_group_add_widget (priv->size_group, child);
1805 gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0);
1809 * gtk_assistant_remove_action_widget:
1810 * @assistant: a #GtkAssistant
1811 * @child: a #GtkWidget
1813 * Removes a widget from the action area of a #GtkAssistant.
1818 gtk_assistant_remove_action_widget (GtkAssistant *assistant,
1821 GtkAssistantPrivate *priv;
1823 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1824 g_return_if_fail (GTK_IS_WIDGET (child));
1826 priv = assistant->priv;
1828 if (GTK_IS_BUTTON (child))
1829 gtk_size_group_remove_widget (priv->size_group, child);
1831 gtk_container_remove (GTK_CONTAINER (priv->action_area), child);
1835 * gtk_assistant_set_page_title:
1836 * @assistant: a #GtkAssistant
1837 * @page: a page of @assistant
1838 * @title: the new title for @page
1840 * Sets a title for @page. The title is displayed in the header
1841 * area of the assistant when @page is the current page.
1846 gtk_assistant_set_page_title (GtkAssistant *assistant,
1850 GtkAssistantPage *page_info;
1853 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1854 g_return_if_fail (GTK_IS_WIDGET (page));
1856 child = find_page (assistant, page);
1858 g_return_if_fail (child != NULL);
1860 page_info = (GtkAssistantPage*) child->data;
1862 gtk_label_set_text ((GtkLabel*) page_info->title, title);
1863 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1864 gtk_widget_child_notify (page, "title");
1868 * gtk_assistant_get_page_title:
1869 * @assistant: a #GtkAssistant
1870 * @page: a page of @assistant
1872 * Gets the title for @page.
1874 * Return value: the title for @page.
1878 G_CONST_RETURN gchar*
1879 gtk_assistant_get_page_title (GtkAssistant *assistant,
1882 GtkAssistantPage *page_info;
1885 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1886 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
1888 child = find_page (assistant, page);
1890 g_return_val_if_fail (child != NULL, NULL);
1892 page_info = (GtkAssistantPage*) child->data;
1894 return gtk_label_get_text ((GtkLabel*) page_info->title);
1898 * gtk_assistant_set_page_type:
1899 * @assistant: a #GtkAssistant
1900 * @page: a page of @assistant
1901 * @type: the new type for @page
1903 * Sets the page type for @page. The page type determines the page
1904 * behavior in the @assistant.
1909 gtk_assistant_set_page_type (GtkAssistant *assistant,
1911 GtkAssistantPageType type)
1913 GtkAssistantPrivate *priv;
1914 GtkAssistantPage *page_info;
1917 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1918 g_return_if_fail (GTK_IS_WIDGET (page));
1920 priv = assistant->priv;
1921 child = find_page (assistant, page);
1923 g_return_if_fail (child != NULL);
1925 page_info = (GtkAssistantPage*) child->data;
1927 if (type != page_info->type)
1929 page_info->type = type;
1931 /* Always set buttons state, a change in a future page
1932 might change current page buttons */
1933 set_assistant_buttons_state (assistant);
1935 gtk_widget_child_notify (page, "page-type");
1940 * gtk_assistant_get_page_type:
1941 * @assistant: a #GtkAssistant
1942 * @page: a page of @assistant
1944 * Gets the page type of @page.
1946 * Return value: the page type of @page.
1950 GtkAssistantPageType
1951 gtk_assistant_get_page_type (GtkAssistant *assistant,
1954 GtkAssistantPage *page_info;
1957 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), GTK_ASSISTANT_PAGE_CONTENT);
1958 g_return_val_if_fail (GTK_IS_WIDGET (page), GTK_ASSISTANT_PAGE_CONTENT);
1960 child = find_page (assistant, page);
1962 g_return_val_if_fail (child != NULL, GTK_ASSISTANT_PAGE_CONTENT);
1964 page_info = (GtkAssistantPage*) child->data;
1966 return page_info->type;
1970 * gtk_assistant_set_page_header_image:
1971 * @assistant: a #GtkAssistant
1972 * @page: a page of @assistant
1973 * @pixbuf: the new header image @page
1975 * Sets a header image for @page. This image is displayed in the header
1976 * area of the assistant when @page is the current page.
1981 gtk_assistant_set_page_header_image (GtkAssistant *assistant,
1985 GtkAssistantPrivate *priv;
1986 GtkAssistantPage *page_info;
1989 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1990 g_return_if_fail (GTK_IS_WIDGET (page));
1991 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1993 priv = assistant->priv;
1994 child = find_page (assistant, page);
1996 g_return_if_fail (child != NULL);
1998 page_info = (GtkAssistantPage*) child->data;
2000 if (pixbuf != page_info->header_image)
2002 if (page_info->header_image)
2004 g_object_unref (page_info->header_image);
2005 page_info->header_image = NULL;
2009 page_info->header_image = g_object_ref (pixbuf);
2011 if (page_info == priv->current_page)
2012 set_assistant_header_image (assistant);
2014 gtk_widget_child_notify (page, "header-image");
2019 * gtk_assistant_get_page_header_image:
2020 * @assistant: a #GtkAssistant
2021 * @page: a page of @assistant
2023 * Gets the header image for @page.
2025 * Return value: the header image for @page, or %NULL
2026 * if there's no header image for the page.
2031 gtk_assistant_get_page_header_image (GtkAssistant *assistant,
2034 GtkAssistantPage *page_info;
2037 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2038 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2040 child = find_page (assistant, page);
2042 g_return_val_if_fail (child != NULL, NULL);
2044 page_info = (GtkAssistantPage*) child->data;
2046 return page_info->header_image;
2050 * gtk_assistant_set_page_side_image:
2051 * @assistant: a #GtkAssistant
2052 * @page: a page of @assistant
2053 * @pixbuf: the new header image @page
2055 * Sets a header image for @page. This image is displayed in the side
2056 * area of the assistant when @page is the current page.
2061 gtk_assistant_set_page_side_image (GtkAssistant *assistant,
2065 GtkAssistantPrivate *priv;
2066 GtkAssistantPage *page_info;
2069 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2070 g_return_if_fail (GTK_IS_WIDGET (page));
2071 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2073 priv = assistant->priv;
2074 child = find_page (assistant, page);
2076 g_return_if_fail (child != NULL);
2078 page_info = (GtkAssistantPage*) child->data;
2080 if (pixbuf != page_info->sidebar_image)
2082 if (page_info->sidebar_image)
2084 g_object_unref (page_info->sidebar_image);
2085 page_info->sidebar_image = NULL;
2089 page_info->sidebar_image = g_object_ref (pixbuf);
2091 if (page_info == priv->current_page)
2092 set_assistant_sidebar_image (assistant);
2094 gtk_widget_child_notify (page, "sidebar-image");
2099 * gtk_assistant_get_page_side_image:
2100 * @assistant: a #GtkAssistant
2101 * @page: a page of @assistant
2103 * Gets the header image for @page.
2105 * Return value: the side image for @page, or %NULL
2106 * if there's no side image for the page.
2111 gtk_assistant_get_page_side_image (GtkAssistant *assistant,
2114 GtkAssistantPage *page_info;
2117 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2118 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2120 child = find_page (assistant, page);
2122 g_return_val_if_fail (child != NULL, NULL);
2124 page_info = (GtkAssistantPage*) child->data;
2126 return page_info->sidebar_image;
2130 * gtk_assistant_set_page_complete:
2131 * @assistant: a #GtkAssistant
2132 * @page: a page of @assistant
2133 * @complete: the completeness status of the page
2135 * Sets whether @page contents are complete. This will make
2136 * @assistant update the buttons state to be able to continue the task.
2141 gtk_assistant_set_page_complete (GtkAssistant *assistant,
2145 GtkAssistantPrivate *priv;
2146 GtkAssistantPage *page_info;
2149 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2150 g_return_if_fail (GTK_IS_WIDGET (page));
2152 priv = assistant->priv;
2153 child = find_page (assistant, page);
2155 g_return_if_fail (child != NULL);
2157 page_info = (GtkAssistantPage*) child->data;
2159 if (complete != page_info->complete)
2161 page_info->complete = complete;
2163 /* Always set buttons state, a change in a future page
2164 might change current page buttons */
2165 set_assistant_buttons_state (assistant);
2167 gtk_widget_child_notify (page, "complete");
2172 * gtk_assistant_get_page_complete:
2173 * @assistant: a #GtkAssistant
2174 * @page: a page of @assistant
2176 * Gets whether @page is complete.
2178 * Return value: %TRUE if @page is complete.
2183 gtk_assistant_get_page_complete (GtkAssistant *assistant,
2186 GtkAssistantPage *page_info;
2189 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), FALSE);
2190 g_return_val_if_fail (GTK_IS_WIDGET (page), FALSE);
2192 child = find_page (assistant, page);
2194 g_return_val_if_fail (child != NULL, FALSE);
2196 page_info = (GtkAssistantPage*) child->data;
2198 return page_info->complete;
2202 * gtk_assistant_update_buttons_state:
2203 * @assistant: a #GtkAssistant
2205 * Forces @assistant to recompute the buttons state.
2207 * GTK+ automatically takes care of this in most situations,
2208 * e.g. when the user goes to a different page, or when the
2209 * visibility or completeness of a page changes.
2211 * One situation where it can be necessary to call this
2212 * function is when changing a value on the current page
2213 * affects the future page flow of the assistant.
2218 gtk_assistant_update_buttons_state (GtkAssistant *assistant)
2220 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2222 set_assistant_buttons_state (assistant);
2227 /* accessible implementation */
2230 gtk_assistant_accessible_get_n_children (AtkObject *accessible)
2232 GtkAssistant *assistant;
2235 widget = GTK_ACCESSIBLE (accessible)->widget;
2240 assistant = GTK_ASSISTANT (widget);
2242 return g_list_length (assistant->priv->pages) + 1;
2247 gtk_assistant_accessible_ref_child (AtkObject *accessible,
2250 GtkAssistant *assistant;
2251 GtkAssistantPrivate *priv;
2252 GtkWidget *widget, *child;
2257 widget = GTK_ACCESSIBLE (accessible)->widget;
2261 assistant = GTK_ASSISTANT (widget);
2262 priv = assistant->priv;
2263 n_pages = g_list_length (priv->pages);
2267 else if (index < n_pages)
2269 GtkAssistantPage *page = g_list_nth_data (priv->pages, index);
2272 title = gtk_assistant_get_page_title (assistant, child);
2274 else if (index == n_pages)
2276 child = priv->action_area;
2282 obj = gtk_widget_get_accessible (child);
2285 atk_object_set_name (obj, title);
2287 return g_object_ref (obj);
2291 gtk_assistant_accessible_class_init (AtkObjectClass *class)
2293 class->get_n_children = gtk_assistant_accessible_get_n_children;
2294 class->ref_child = gtk_assistant_accessible_ref_child;
2298 gtk_assistant_accessible_get_type (void)
2300 static GType type = 0;
2305 * Figure out the size of the class and instance
2306 * we are deriving from
2308 AtkObjectFactory *factory;
2311 GType derived_atk_type;
2313 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2314 factory = atk_registry_get_factory (atk_get_default_registry (),
2316 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2317 g_type_query (derived_atk_type, &query);
2319 type = g_type_register_static_simple (derived_atk_type,
2320 I_("GtkAssistantAccessible"),
2322 (GClassInitFunc) gtk_assistant_accessible_class_init,
2323 query.instance_size,
2331 gtk_assistant_accessible_new (GObject *obj)
2333 AtkObject *accessible;
2335 g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL);
2337 accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL);
2338 atk_object_initialize (accessible, obj);
2344 gtk_assistant_accessible_factory_get_accessible_type (void)
2346 return gtk_assistant_accessible_get_type ();
2350 gtk_assistant_accessible_factory_create_accessible (GObject *obj)
2352 return gtk_assistant_accessible_new (obj);
2356 gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class)
2358 class->create_accessible = gtk_assistant_accessible_factory_create_accessible;
2359 class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type;
2363 gtk_assistant_accessible_factory_get_type (void)
2365 static GType type = 0;
2369 type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY,
2370 I_("GtkAssistantAccessibleFactory"),
2371 sizeof (AtkObjectFactoryClass),
2372 (GClassInitFunc) gtk_assistant_accessible_factory_class_init,
2373 sizeof (AtkObjectFactory),
2381 gtk_assistant_get_accessible (GtkWidget *widget)
2383 static gboolean first_time = TRUE;
2387 AtkObjectFactory *factory;
2388 AtkRegistry *registry;
2390 GType derived_atk_type;
2393 * Figure out whether accessibility is enabled by looking at the
2394 * type of the accessible object which would be created for
2395 * the parent type of GtkAssistant.
2397 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2399 registry = atk_get_default_registry ();
2400 factory = atk_registry_get_factory (registry,
2402 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2403 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
2405 atk_registry_set_factory_type (registry,
2407 gtk_assistant_accessible_factory_get_type ());
2412 return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget);
2416 static GtkBuildableIface *parent_buildable_iface;
2419 gtk_assistant_buildable_interface_init (GtkBuildableIface *iface)
2421 parent_buildable_iface = g_type_interface_peek_parent (iface);
2422 iface->get_internal_child = gtk_assistant_buildable_get_internal_child;
2423 iface->custom_tag_start = gtk_assistant_buildable_custom_tag_start;
2424 iface->custom_finished = gtk_assistant_buildable_custom_finished;
2428 gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
2429 GtkBuilder *builder,
2430 const gchar *childname)
2432 if (strcmp (childname, "action_area") == 0)
2433 return G_OBJECT (GTK_ASSISTANT (buildable)->priv->action_area);
2435 return parent_buildable_iface->get_internal_child (buildable,
2441 gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
2442 GtkBuilder *builder,
2444 const gchar *tagname,
2445 GMarkupParser *parser,
2448 return parent_buildable_iface->custom_tag_start (buildable, builder, child,
2449 tagname, parser, data);
2453 gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
2454 GtkBuilder *builder,
2456 const gchar *tagname,
2459 parent_buildable_iface->custom_finished (buildable, builder, child,
2460 tagname, user_data);
2464 #define __GTK_ASSISTANT_C__
2465 #include "gtkaliasdef.c"