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"
46 #define GTK_ASSISTANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ASSISTANT, GtkAssistantPrivate))
48 #define HEADER_SPACING 12
49 #define ACTION_AREA_SPACING 12
51 typedef struct _GtkAssistantPage GtkAssistantPage;
53 struct _GtkAssistantPage
56 GtkAssistantPageType type;
60 GdkPixbuf *header_image;
61 GdkPixbuf *sidebar_image;
64 struct _GtkAssistantPrivate
66 GtkWidget *header_image;
67 GtkWidget *sidebar_image;
69 GtkWidget *action_area;
73 GtkAssistantPage *current_page;
75 GSList *visited_pages;
77 GtkSizeGroup *size_group;
79 GtkAssistantPageFunc forward_function;
80 gpointer forward_function_data;
81 GDestroyNotify forward_data_destroy;
84 static void gtk_assistant_class_init (GtkAssistantClass *class);
85 static void gtk_assistant_init (GtkAssistant *assistant);
86 static void gtk_assistant_destroy (GtkObject *object);
87 static void gtk_assistant_style_set (GtkWidget *widget,
89 static void gtk_assistant_size_request (GtkWidget *widget,
90 GtkRequisition *requisition);
91 static void gtk_assistant_size_allocate (GtkWidget *widget,
92 GtkAllocation *allocation);
93 static void gtk_assistant_map (GtkWidget *widget);
94 static void gtk_assistant_unmap (GtkWidget *widget);
95 static gboolean gtk_assistant_delete_event (GtkWidget *widget,
97 static gboolean gtk_assistant_expose (GtkWidget *widget,
98 GdkEventExpose *event);
99 static gboolean gtk_assistant_focus (GtkWidget *widget,
100 GtkDirectionType direction);
101 static void gtk_assistant_add (GtkContainer *container,
103 static void gtk_assistant_remove (GtkContainer *container,
105 static void gtk_assistant_forall (GtkContainer *container,
106 gboolean include_internals,
107 GtkCallback callback,
108 gpointer callback_data);
109 static void gtk_assistant_set_child_property (GtkContainer *container,
114 static void gtk_assistant_get_child_property (GtkContainer *container,
120 static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget);
125 CHILD_PROP_PAGE_TYPE,
126 CHILD_PROP_PAGE_TITLE,
127 CHILD_PROP_PAGE_HEADER_IMAGE,
128 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
129 CHILD_PROP_PAGE_COMPLETE
141 static guint signals [LAST_SIGNAL] = { 0 };
144 G_DEFINE_TYPE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW)
148 gtk_assistant_class_init (GtkAssistantClass *class)
150 GObjectClass *gobject_class;
151 GtkObjectClass *object_class;
152 GtkWidgetClass *widget_class;
153 GtkContainerClass *container_class;
155 gobject_class = (GObjectClass *) class;
156 object_class = (GtkObjectClass *) class;
157 widget_class = (GtkWidgetClass *) class;
158 container_class = (GtkContainerClass *) class;
160 object_class->destroy = gtk_assistant_destroy;
162 widget_class->style_set = gtk_assistant_style_set;
163 widget_class->size_request = gtk_assistant_size_request;
164 widget_class->size_allocate = gtk_assistant_size_allocate;
165 widget_class->map = gtk_assistant_map;
166 widget_class->unmap = gtk_assistant_unmap;
167 widget_class->delete_event = gtk_assistant_delete_event;
168 widget_class->expose_event = gtk_assistant_expose;
169 widget_class->focus = gtk_assistant_focus;
170 widget_class->get_accessible = gtk_assistant_get_accessible;
172 container_class->add = gtk_assistant_add;
173 container_class->remove = gtk_assistant_remove;
174 container_class->forall = gtk_assistant_forall;
175 container_class->set_child_property = gtk_assistant_set_child_property;
176 container_class->get_child_property = gtk_assistant_get_child_property;
179 * GtkAssistant::cancel:
180 * @assistant: the #GtkAssistant
182 * The ::cancel signal is emitted when then the cancel button is clicked.
187 g_signal_new (I_("cancel"),
188 G_TYPE_FROM_CLASS (gobject_class),
190 G_STRUCT_OFFSET (GtkAssistantClass, cancel),
192 g_cclosure_marshal_VOID__VOID,
196 * GtkAssistant::prepare:
197 * @assistant: the #GtkAssistant
198 * @page: the current page
200 * The ::prepared signal is emitted when a new page is set as the assistant's
201 * current page, before making the new page visible. A handler for this signal
202 * can do any preparation which are necessary before showing @page.
207 g_signal_new (I_("prepare"),
208 G_TYPE_FROM_CLASS (gobject_class),
210 G_STRUCT_OFFSET (GtkAssistantClass, prepare),
212 g_cclosure_marshal_VOID__OBJECT,
213 G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
216 * GtkAssistant::apply:
217 * @assistant: the @GtkAssistant
219 * The ::apply signal is emitted when the apply button is clicked. The default
220 * behavior of the #GtkAssistant is to switch to the page after the current page,
221 * unless the current page is the last one.
223 * A handler for the ::apply signal should carry out the actions for which the
224 * wizard has collected data. If the action takes a long time to complete, you
225 * might consider to put a page of type GTK_ASSISTANT_PAGE_PROGRESS after the
226 * confirmation page and handle this operation within the ::prepare signal of
232 g_signal_new (I_("apply"),
233 G_TYPE_FROM_CLASS (gobject_class),
235 G_STRUCT_OFFSET (GtkAssistantClass, apply),
237 g_cclosure_marshal_VOID__VOID,
241 * GtkAssistant::close:
242 * @assistant: the #GtkAssistant
244 * The ::close signal is emitted either when the close button of
245 * a summary page is clicked, or when the apply button in the last
246 * page in the flow (of type GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
251 g_signal_new (I_("close"),
252 G_TYPE_FROM_CLASS (gobject_class),
254 G_STRUCT_OFFSET (GtkAssistantClass, close),
256 g_cclosure_marshal_VOID__VOID,
259 gtk_widget_class_install_style_property (widget_class,
260 g_param_spec_int ("header-padding",
261 P_("Header Padding"),
262 P_("Number of pixels around the header."),
266 GTK_PARAM_READABLE));
267 gtk_widget_class_install_style_property (widget_class,
268 g_param_spec_int ("content-padding",
269 P_("Content Padding"),
270 P_("Number of pixels around the content pages."),
274 GTK_PARAM_READABLE));
277 * GtkAssistant:page-type:
279 * The type of the assistant page.
283 gtk_container_class_install_child_property (container_class,
284 CHILD_PROP_PAGE_TYPE,
285 g_param_spec_enum ("page-type",
287 P_("The type of the assistant page"),
288 GTK_TYPE_ASSISTANT_PAGE_TYPE,
289 GTK_ASSISTANT_PAGE_CONTENT,
290 GTK_PARAM_READWRITE));
293 * GtkAssistant:title:
295 * The title that is displayed in the page header.
297 * If title and header-image are both %NULL, no header is displayed.
301 gtk_container_class_install_child_property (container_class,
302 CHILD_PROP_PAGE_TITLE,
303 g_param_spec_string ("title",
305 P_("The title of the assistant page"),
307 GTK_PARAM_READWRITE));
310 * GtkAssistant:header-image:
312 * The image that is displayed next to the title in the page header.
314 * If title and header-image are both %NULL, no header is displayed.
318 gtk_container_class_install_child_property (container_class,
319 CHILD_PROP_PAGE_HEADER_IMAGE,
320 g_param_spec_object ("header-image",
322 P_("Header image for the assistant page"),
324 GTK_PARAM_READWRITE));
327 * GtkAssistant:header-image:
329 * The image that is displayed next to the page.
331 * Set this to %NULL to make the sidebar disappear.
335 gtk_container_class_install_child_property (container_class,
336 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
337 g_param_spec_object ("sidebar-image",
339 P_("Sidebar image for the assistant page"),
341 GTK_PARAM_READWRITE));
343 * GtkAssistant:complete:
345 * Setting the "complete" child property to %TRUE marks a page as complete
346 * (i.e.: all the required fields are filled out). GTK+ uses this information
347 * to control the sensitivity of the navigation buttons.
351 gtk_container_class_install_child_property (container_class,
352 CHILD_PROP_PAGE_COMPLETE,
353 g_param_spec_boolean ("complete",
355 P_("Whether all required fields on the page have been filled out"),
359 g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate));
363 default_forward_function (gint current_page, gpointer data)
365 GtkAssistant *assistant;
366 GtkAssistantPrivate *priv;
367 GtkAssistantPage *page_info;
370 assistant = GTK_ASSISTANT (data);
371 priv = assistant->priv;
373 page_node = g_list_nth (priv->pages, ++current_page);
378 page_info = (GtkAssistantPage *) page_node->data;
380 while (page_node && !GTK_WIDGET_VISIBLE (page_info->page))
382 page_node = page_node->next;
386 page_info = (GtkAssistantPage *) page_node->data;
393 compute_last_button_state (GtkAssistant *assistant)
395 GtkAssistantPrivate *priv = assistant->priv;
396 GtkAssistantPage *page_info, *current_page_info;
397 gint count, page_num, n_pages;
400 page_num = gtk_assistant_get_current_page (assistant);
401 n_pages = gtk_assistant_get_n_pages (assistant);
402 current_page_info = page_info = g_list_nth_data (priv->pages, page_num);
404 while (page_num >= 0 && page_num < n_pages &&
405 page_info->type == GTK_ASSISTANT_PAGE_CONTENT &&
406 (count == 0 || page_info->complete) &&
409 page_num = (priv->forward_function) (page_num, priv->forward_function_data);
410 page_info = g_list_nth_data (priv->pages, page_num);
414 g_assert (page_info);
417 /* make the last button visible if we can skip multiple
418 * pages and end on a confirmation or summary page
421 (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM ||
422 page_info->type == GTK_ASSISTANT_PAGE_SUMMARY))
424 gtk_widget_show (assistant->last);
425 gtk_widget_set_sensitive (assistant->last,
426 current_page_info->complete);
429 gtk_widget_hide (assistant->last);
433 set_assistant_header_image (GtkAssistant *assistant)
435 GtkAssistantPrivate *priv = assistant->priv;
437 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image),
438 priv->current_page->header_image);
442 set_assistant_sidebar_image (GtkAssistant *assistant)
444 GtkAssistantPrivate *priv = assistant->priv;
446 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image),
447 priv->current_page->sidebar_image);
449 if (priv->current_page->sidebar_image)
450 gtk_widget_show (priv->sidebar_image);
452 gtk_widget_hide (priv->sidebar_image);
456 set_assistant_buttons_state (GtkAssistant *assistant)
458 GtkAssistantPrivate *priv = assistant->priv;
460 if (!priv->current_page)
463 switch (priv->current_page->type)
465 case GTK_ASSISTANT_PAGE_INTRO:
466 gtk_widget_set_sensitive (assistant->cancel, TRUE);
467 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
468 gtk_widget_show (assistant->cancel);
469 gtk_widget_show (assistant->forward);
470 gtk_widget_hide (assistant->back);
471 gtk_widget_hide (assistant->apply);
472 gtk_widget_hide (assistant->close);
473 compute_last_button_state (assistant);
475 case GTK_ASSISTANT_PAGE_CONFIRM:
476 gtk_widget_set_sensitive (assistant->cancel, TRUE);
477 gtk_widget_set_sensitive (assistant->back, TRUE);
478 gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
479 gtk_widget_show (assistant->cancel);
480 gtk_widget_show (assistant->back);
481 gtk_widget_show (assistant->apply);
482 gtk_widget_hide (assistant->forward);
483 gtk_widget_hide (assistant->close);
484 gtk_widget_hide (assistant->last);
486 case GTK_ASSISTANT_PAGE_CONTENT:
487 gtk_widget_set_sensitive (assistant->cancel, TRUE);
488 gtk_widget_set_sensitive (assistant->back, TRUE);
489 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
490 gtk_widget_show (assistant->cancel);
491 gtk_widget_show (assistant->back);
492 gtk_widget_show (assistant->forward);
493 gtk_widget_hide (assistant->apply);
494 gtk_widget_hide (assistant->close);
495 compute_last_button_state (assistant);
497 case GTK_ASSISTANT_PAGE_SUMMARY:
498 gtk_widget_set_sensitive (assistant->close, TRUE);
499 gtk_widget_show (assistant->close);
500 gtk_widget_hide (assistant->cancel);
501 gtk_widget_hide (assistant->back);
502 gtk_widget_hide (assistant->forward);
503 gtk_widget_hide (assistant->apply);
504 gtk_widget_hide (assistant->last);
506 case GTK_ASSISTANT_PAGE_PROGRESS:
507 gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
508 gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
509 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
510 gtk_widget_show (assistant->cancel);
511 gtk_widget_show (assistant->back);
512 gtk_widget_show (assistant->forward);
513 gtk_widget_hide (assistant->apply);
514 gtk_widget_hide (assistant->close);
515 gtk_widget_hide (assistant->last);
518 g_assert_not_reached ();
521 /* this is quite general, we don't want to
522 * go back if it's the first page */
523 if (!priv->visited_pages)
524 gtk_widget_hide (assistant->back);
528 set_current_page (GtkAssistant *assistant,
529 GtkAssistantPage *page)
531 GtkAssistantPrivate *priv = assistant->priv;
532 GtkAssistantPage *old_page;
534 if (priv->current_page &&
535 GTK_WIDGET_DRAWABLE (priv->current_page->page))
536 old_page = priv->current_page;
540 priv->current_page = page;
542 set_assistant_buttons_state (assistant);
543 set_assistant_header_image (assistant);
544 set_assistant_sidebar_image (assistant);
546 g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
548 if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
550 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
551 gtk_widget_map (priv->current_page->page);
552 gtk_widget_map (priv->current_page->title);
555 if (old_page && GTK_WIDGET_MAPPED (old_page->page))
557 gtk_widget_set_child_visible (old_page->page, FALSE);
558 gtk_widget_unmap (old_page->page);
559 gtk_widget_unmap (old_page->title);
562 if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD))
564 GtkWidget *button[6];
567 /* find the best button to focus */
568 button[0] = assistant->apply;
569 button[1] = assistant->close;
570 button[2] = assistant->forward;
571 button[3] = assistant->back;
572 button[4] = assistant->cancel;
573 button[5] = assistant->last;
574 for (i = 0; i < 6; i++)
576 if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
578 gtk_widget_grab_focus (button[i]);
584 gtk_widget_queue_resize (GTK_WIDGET (assistant));
588 compute_next_step (GtkAssistant *assistant)
590 GtkAssistantPrivate *priv = assistant->priv;
591 GtkAssistantPage *page_info;
592 gint current_page, n_pages, next_page;
594 current_page = gtk_assistant_get_current_page (assistant);
595 page_info = priv->current_page;
596 n_pages = gtk_assistant_get_n_pages (assistant);
598 next_page = (priv->forward_function) (current_page,
599 priv->forward_function_data);
601 if (next_page >= 0 && next_page < n_pages)
603 priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info);
604 set_current_page (assistant, g_list_nth_data (priv->pages, next_page));
613 on_assistant_close (GtkWidget *widget,
614 GtkAssistant *assistant)
616 g_signal_emit (assistant, signals [CLOSE], 0, NULL);
620 on_assistant_apply (GtkWidget *widget,
621 GtkAssistant *assistant)
625 success = compute_next_step (assistant);
627 g_signal_emit (assistant, signals [APPLY], 0);
629 /* if the assistant hasn't switched to another page, just emit
630 * the CLOSE signal, it't the last page in the assistant flow
633 g_signal_emit (assistant, signals [CLOSE], 0);
637 on_assistant_forward (GtkWidget *widget,
638 GtkAssistant *assistant)
640 if (!compute_next_step (assistant))
641 g_critical ("Page flow is broken, you may want to end it with a page of "
642 "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY");
646 on_assistant_back (GtkWidget *widget,
647 GtkAssistant *assistant)
649 GtkAssistantPrivate *priv = assistant->priv;
650 GtkAssistantPage *page_info;
653 /* skip the progress pages when going back */
656 page_node = priv->visited_pages;
658 g_return_if_fail (page_node != NULL);
660 priv->visited_pages = priv->visited_pages->next;
661 page_info = (GtkAssistantPage *) page_node->data;
662 g_slist_free_1 (page_node);
664 while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS ||
665 !GTK_WIDGET_VISIBLE (page_info->page));
667 set_current_page (assistant, page_info);
671 on_assistant_cancel (GtkWidget *widget,
672 GtkAssistant *assistant)
674 g_signal_emit (assistant, signals [CANCEL], 0, NULL);
678 on_assistant_last (GtkWidget *widget,
679 GtkAssistant *assistant)
681 GtkAssistantPrivate *priv = assistant->priv;
683 while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT &&
684 priv->current_page->complete)
685 compute_next_step (assistant);
689 alternative_button_order (GtkAssistant *assistant)
691 GtkSettings *settings;
695 screen = gtk_widget_get_screen (GTK_WIDGET (assistant));
696 settings = gtk_settings_get_for_screen (screen);
698 g_object_get (settings,
699 "gtk-alternative-button-order", &result,
705 gtk_assistant_init (GtkAssistant *assistant)
707 GtkAssistantPrivate *priv;
709 priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
711 gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE);
713 gtk_widget_push_composite_child ();
716 priv->header_image = gtk_image_new ();
717 gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5);
718 gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant));
719 gtk_widget_show (priv->header_image);
722 priv->sidebar_image = gtk_image_new ();
723 gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.);
724 gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant));
725 gtk_widget_show (priv->sidebar_image);
728 priv->action_area = gtk_hbox_new (FALSE, 6);
730 assistant->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
731 assistant->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
732 assistant->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
733 assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
734 assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
735 assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
737 priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
738 gtk_size_group_add_widget (priv->size_group, assistant->close);
739 gtk_size_group_add_widget (priv->size_group, assistant->apply);
740 gtk_size_group_add_widget (priv->size_group, assistant->forward);
741 gtk_size_group_add_widget (priv->size_group, assistant->back);
742 gtk_size_group_add_widget (priv->size_group, assistant->cancel);
743 gtk_size_group_add_widget (priv->size_group, assistant->last);
745 if (!alternative_button_order (assistant))
747 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
748 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
749 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
750 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
751 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
752 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
756 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
757 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
758 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
759 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
760 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
761 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
764 gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant));
765 gtk_widget_show (assistant->forward);
766 gtk_widget_show (assistant->back);
767 gtk_widget_show (assistant->cancel);
768 gtk_widget_show (priv->action_area);
770 gtk_widget_pop_composite_child ();
773 priv->current_page = NULL;
774 priv->visited_pages = NULL;
776 priv->forward_function = default_forward_function;
777 priv->forward_function_data = assistant;
778 priv->forward_data_destroy = NULL;
780 g_signal_connect (G_OBJECT (assistant->close), "clicked",
781 G_CALLBACK (on_assistant_close), assistant);
782 g_signal_connect (G_OBJECT (assistant->apply), "clicked",
783 G_CALLBACK (on_assistant_apply), assistant);
784 g_signal_connect (G_OBJECT (assistant->forward), "clicked",
785 G_CALLBACK (on_assistant_forward), assistant);
786 g_signal_connect (G_OBJECT (assistant->back), "clicked",
787 G_CALLBACK (on_assistant_back), assistant);
788 g_signal_connect (G_OBJECT (assistant->cancel), "clicked",
789 G_CALLBACK (on_assistant_cancel), assistant);
790 g_signal_connect (G_OBJECT (assistant->last), "clicked",
791 G_CALLBACK (on_assistant_last), assistant);
795 gtk_assistant_set_child_property (GtkContainer *container,
803 case CHILD_PROP_PAGE_TYPE:
804 gtk_assistant_set_page_type (GTK_ASSISTANT (container), child,
805 g_value_get_enum (value));
807 case CHILD_PROP_PAGE_TITLE:
808 gtk_assistant_set_page_title (GTK_ASSISTANT (container), child,
809 g_value_get_string (value));
811 case CHILD_PROP_PAGE_HEADER_IMAGE:
812 gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child,
813 g_value_get_object (value));
815 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
816 gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child,
817 g_value_get_object (value));
819 case CHILD_PROP_PAGE_COMPLETE:
820 gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child,
821 g_value_get_boolean (value));
824 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
830 gtk_assistant_get_child_property (GtkContainer *container,
838 case CHILD_PROP_PAGE_TYPE:
839 g_value_set_enum (value,
840 gtk_assistant_get_page_type (GTK_ASSISTANT (container), child));
842 case CHILD_PROP_PAGE_TITLE:
843 g_value_set_string (value,
844 gtk_assistant_get_page_title (GTK_ASSISTANT (container), child));
846 case CHILD_PROP_PAGE_HEADER_IMAGE:
847 g_value_set_object (value,
848 gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child));
850 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
851 g_value_set_object (value,
852 gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child));
854 case CHILD_PROP_PAGE_COMPLETE:
855 g_value_set_boolean (value,
856 gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child));
859 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
865 on_page_notify_visibility (GtkWidget *widget,
869 GtkAssistant *assistant = GTK_ASSISTANT (data);
871 /* update buttons state, flow may have changed */
872 if (GTK_WIDGET_MAPPED (assistant))
873 set_assistant_buttons_state (assistant);
877 remove_page (GtkAssistant *assistant,
880 GtkAssistantPrivate *priv = assistant->priv;
881 GtkAssistantPage *page_info;
884 page_info = element->data;
886 /* If this is the current page, we need to switch away. */
887 if (page_info == priv->current_page)
889 if (!compute_next_step (assistant))
891 /* The best we can do at this point is probably to pick the first
894 page_node = priv->pages;
896 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
897 page_node = page_node->next;
899 if (page_node == element)
900 page_node = page_node->next;
903 priv->current_page = page_node->data;
905 priv->current_page = NULL;
909 priv->pages = g_list_remove_link (priv->pages, element);
910 priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info);
912 g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant);
913 gtk_widget_unparent (page_info->page);
915 if (page_info->header_image)
916 g_object_unref (page_info->header_image);
918 if (page_info->sidebar_image)
919 g_object_unref (page_info->sidebar_image);
921 gtk_widget_destroy (page_info->title);
922 g_slice_free (GtkAssistantPage, page_info);
923 g_list_free_1 (element);
927 gtk_assistant_destroy (GtkObject *object)
929 GtkAssistant *assistant = GTK_ASSISTANT (object);
930 GtkAssistantPrivate *priv = assistant->priv;
932 if (priv->header_image)
934 gtk_widget_destroy (priv->header_image);
935 priv->header_image = NULL;
938 if (priv->sidebar_image)
940 gtk_widget_destroy (priv->sidebar_image);
941 priv->sidebar_image = NULL;
944 if (priv->action_area)
946 gtk_widget_destroy (priv->action_area);
947 priv->action_area = NULL;
950 if (priv->size_group)
952 g_object_unref (priv->size_group);
953 priv->size_group = NULL;
956 if (priv->forward_function)
958 if (priv->forward_function_data &&
959 priv->forward_data_destroy)
960 priv->forward_data_destroy (priv->forward_function_data);
962 priv->forward_function = NULL;
963 priv->forward_function_data = NULL;
964 priv->forward_data_destroy = NULL;
967 if (priv->visited_pages)
969 g_slist_free (priv->visited_pages);
970 priv->visited_pages = NULL;
973 /* We set current to NULL so that the remove code doesn't try
974 * to do anything funny */
975 priv->current_page = NULL;
978 remove_page (GTK_ASSISTANT (object), priv->pages);
980 GTK_OBJECT_CLASS (gtk_assistant_parent_class)->destroy (object);
984 find_page (GtkAssistant *assistant,
987 GtkAssistantPrivate *priv = assistant->priv;
988 GList *child = priv->pages;
992 GtkAssistantPage *page_info = child->data;
993 if (page_info->page == page)
1003 set_title_colors (GtkWidget *assistant,
1004 GtkWidget *title_label)
1008 gtk_widget_ensure_style (assistant);
1009 style = gtk_widget_get_style (assistant);
1011 /* change colors schema, for making the header text visible */
1012 gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]);
1013 gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]);
1017 set_title_font (GtkWidget *assistant,
1018 GtkWidget *title_label)
1020 PangoFontDescription *desc;
1023 desc = pango_font_description_new ();
1024 size = pango_font_description_get_size (assistant->style->font_desc);
1026 pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD);
1027 pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE);
1029 gtk_widget_modify_font (title_label, desc);
1030 pango_font_description_free (desc);
1034 gtk_assistant_style_set (GtkWidget *widget,
1035 GtkStyle *old_style)
1037 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1038 GtkAssistantPrivate *priv = assistant->priv;
1045 GtkAssistantPage *page = list->data;
1047 set_title_colors (widget, page->title);
1048 set_title_font (widget, page->title);
1055 gtk_assistant_size_request (GtkWidget *widget,
1056 GtkRequisition *requisition)
1058 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1059 GtkAssistantPrivate *priv = assistant->priv;
1060 GtkRequisition child_requisition;
1061 gint header_padding, content_padding;
1062 gint width, height, header_width, header_height;
1065 gtk_widget_style_get (widget,
1066 "header-padding", &header_padding,
1067 "content-padding", &content_padding,
1070 header_width = header_height = 0;
1075 GtkAssistantPage *page = list->data;
1078 gtk_widget_size_request (page->page, &child_requisition);
1079 width = MAX (width, child_requisition.width);
1080 height = MAX (height, child_requisition.height);
1082 gtk_widget_size_request (page->title, &child_requisition);
1083 w = child_requisition.width;
1084 h = child_requisition.height;
1086 if (page->header_image)
1088 w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING;
1089 h = MAX (h, gdk_pixbuf_get_height (page->header_image));
1092 header_width = MAX (header_width, w);
1093 header_height = MAX (header_height, h);
1098 gtk_widget_size_request (priv->sidebar_image, &child_requisition);
1099 width += child_requisition.width;
1100 height = MAX (height, child_requisition.height);
1102 gtk_widget_set_size_request (priv->header_image, header_width, header_height);
1103 gtk_widget_size_request (priv->header_image, &child_requisition);
1104 width = MAX (width, header_width) + 2 * header_padding;
1105 height += header_height + 2 * header_padding;
1107 gtk_widget_size_request (priv->action_area, &child_requisition);
1108 width = MAX (width, child_requisition.width);
1109 height += child_requisition.height + ACTION_AREA_SPACING;
1111 width += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1112 height += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1114 requisition->width = width;
1115 requisition->height = height;
1119 gtk_assistant_size_allocate (GtkWidget *widget,
1120 GtkAllocation *allocation)
1122 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1123 GtkAssistantPrivate *priv = assistant->priv;
1124 GtkRequisition header_requisition;
1125 GtkAllocation child_allocation, header_allocation;
1126 gint header_padding, content_padding;
1130 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1131 pages = priv->pages;
1133 gtk_widget_style_get (widget,
1134 "header-padding", &header_padding,
1135 "content-padding", &content_padding,
1138 widget->allocation = *allocation;
1141 gtk_widget_get_child_requisition (priv->header_image, &header_requisition);
1143 header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding;
1144 header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding;
1145 header_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding;
1146 header_allocation.height = header_requisition.height;
1148 gtk_widget_size_allocate (priv->header_image, &header_allocation);
1151 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1152 child_allocation.y = allocation->height -
1153 GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
1154 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
1155 child_allocation.height = priv->action_area->requisition.height;
1157 gtk_widget_size_allocate (priv->action_area, &child_allocation);
1161 child_allocation.x = allocation->width -
1162 GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
1164 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1166 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1167 priv->header_image->allocation.height + 2 * header_padding;
1168 child_allocation.width = priv->sidebar_image->requisition.width;
1169 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1170 priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;
1172 gtk_widget_size_allocate (priv->sidebar_image, &child_allocation);
1175 child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding;
1176 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1177 priv->header_image->allocation.height + 2 * header_padding + content_padding;
1178 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding;
1179 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1180 priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding;
1182 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1185 child_allocation.x += priv->sidebar_image->allocation.width;
1187 child_allocation.width -= priv->sidebar_image->allocation.width;
1192 GtkAssistantPage *page = pages->data;
1194 gtk_widget_size_allocate (page->page, &child_allocation);
1195 gtk_widget_size_allocate (page->title, &header_allocation);
1196 pages = pages->next;
1201 gtk_assistant_map (GtkWidget *widget)
1203 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1204 GtkAssistantPrivate *priv = assistant->priv;
1207 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1209 gtk_widget_map (priv->header_image);
1210 gtk_widget_map (priv->action_area);
1212 if (GTK_WIDGET_VISIBLE (priv->sidebar_image) &&
1213 !GTK_WIDGET_MAPPED (priv->sidebar_image))
1214 gtk_widget_map (priv->sidebar_image);
1216 /* if there's no default page, pick the first one */
1217 if (!priv->current_page && priv->pages)
1219 page_node = priv->pages;
1221 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
1222 page_node = page_node->next;
1225 priv->current_page = page_node->data;
1228 if (priv->current_page &&
1229 GTK_WIDGET_VISIBLE (priv->current_page->page) &&
1230 !GTK_WIDGET_MAPPED (priv->current_page->page))
1232 set_assistant_buttons_state ((GtkAssistant *) widget);
1233 set_assistant_header_image ((GtkAssistant*) widget);
1234 set_assistant_sidebar_image ((GtkAssistant*) widget);
1236 g_signal_emit (widget, signals [PREPARE], 0, priv->current_page->page);
1237 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
1238 gtk_widget_map (priv->current_page->page);
1239 gtk_widget_map (priv->current_page->title);
1242 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
1246 gtk_assistant_unmap (GtkWidget *widget)
1248 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1249 GtkAssistantPrivate *priv = assistant->priv;
1251 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1253 gtk_widget_unmap (priv->header_image);
1254 gtk_widget_unmap (priv->action_area);
1256 if (GTK_WIDGET_DRAWABLE (priv->sidebar_image))
1257 gtk_widget_unmap (priv->sidebar_image);
1259 if (priv->current_page &&
1260 GTK_WIDGET_DRAWABLE (priv->current_page->page))
1261 gtk_widget_unmap (priv->current_page->page);
1263 g_slist_free (priv->visited_pages);
1264 priv->visited_pages = NULL;
1265 priv->current_page = NULL;
1267 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget);
1271 gtk_assistant_delete_event (GtkWidget *widget,
1274 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1275 GtkAssistantPrivate *priv = assistant->priv;
1277 /* Do not allow cancelling in the middle of a progress page */
1278 if (priv->current_page &&
1279 (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS ||
1280 priv->current_page->complete))
1281 g_signal_emit (widget, signals [CANCEL], 0, NULL);
1287 assistant_paint_colored_box (GtkWidget *widget)
1289 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1290 GtkAssistantPrivate *priv = assistant->priv;
1291 gint border_width, header_padding, content_padding;
1293 gint content_x, content_width;
1296 cr = gdk_cairo_create (widget->window);
1297 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1298 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1300 gtk_widget_style_get (widget,
1301 "header-padding", &header_padding,
1302 "content-padding", &content_padding,
1306 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]);
1307 cairo_rectangle (cr,
1310 widget->allocation.width - 2 * border_width,
1311 widget->allocation.height - priv->action_area->allocation.height - 2 * border_width - ACTION_AREA_SPACING);
1315 content_x = content_padding + border_width;
1316 content_width = widget->allocation.width - 2 * content_padding - 2 * border_width;
1318 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1321 content_x += priv->sidebar_image->allocation.width;
1322 content_width -= priv->sidebar_image->allocation.width;
1325 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]);
1327 cairo_rectangle (cr,
1329 priv->header_image->allocation.height + content_padding + 2 * header_padding + border_width,
1331 widget->allocation.height - 2 * border_width - priv->action_area->allocation.height -
1332 priv->header_image->allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING);
1339 gtk_assistant_expose (GtkWidget *widget,
1340 GdkEventExpose *event)
1342 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1343 GtkAssistantPrivate *priv = assistant->priv;
1344 GtkContainer *container;
1346 if (GTK_WIDGET_DRAWABLE (widget))
1348 container = GTK_CONTAINER (widget);
1350 assistant_paint_colored_box (widget);
1352 gtk_container_propagate_expose (container, priv->header_image, event);
1353 gtk_container_propagate_expose (container, priv->sidebar_image, event);
1354 gtk_container_propagate_expose (container, priv->action_area, event);
1356 if (priv->current_page)
1358 gtk_container_propagate_expose (container, priv->current_page->page, event);
1359 gtk_container_propagate_expose (container, priv->current_page->title, event);
1367 gtk_assistant_focus (GtkWidget *widget,
1368 GtkDirectionType direction)
1370 GtkAssistantPrivate *priv;
1371 GtkContainer *container;
1373 container = GTK_CONTAINER (widget);
1374 priv = GTK_ASSISTANT (widget)->priv;
1376 /* we only have to care about 2 widgets, action area and the current page */
1377 if (container->focus_child == priv->action_area)
1379 if (!gtk_widget_child_focus (priv->action_area, direction) &&
1380 (priv->current_page == NULL ||
1381 !gtk_widget_child_focus (priv->current_page->page, direction)))
1383 /* if we're leaving the action area and the current page hasn't
1384 any focusable widget, clear focus and go back to the action area */
1385 gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL);
1386 gtk_widget_child_focus (priv->action_area, direction);
1391 if ((priv->current_page == NULL ||
1392 !gtk_widget_child_focus (priv->current_page->page, direction)) &&
1393 !gtk_widget_child_focus (priv->action_area, direction))
1395 /* if we're leaving the current page and there isn't nothing focusable
1396 in the action area, try to clear focus and go back to the page */
1397 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
1398 if (priv->current_page != NULL)
1399 gtk_widget_child_focus (priv->current_page->page, direction);
1407 gtk_assistant_add (GtkContainer *container,
1410 gtk_assistant_append_page (GTK_ASSISTANT (container), page);
1414 gtk_assistant_remove (GtkContainer *container,
1417 GtkAssistant *assistant = (GtkAssistant*) container;
1420 element = find_page (assistant, page);
1424 remove_page (assistant, element);
1425 gtk_widget_queue_resize ((GtkWidget *) container);
1430 gtk_assistant_forall (GtkContainer *container,
1431 gboolean include_internals,
1432 GtkCallback callback,
1433 gpointer callback_data)
1435 GtkAssistant *assistant = (GtkAssistant*) container;
1436 GtkAssistantPrivate *priv = assistant->priv;
1439 if (include_internals)
1441 (*callback) (priv->header_image, callback_data);
1442 (*callback) (priv->sidebar_image, callback_data);
1443 (*callback) (priv->action_area, callback_data);
1446 pages = priv->pages;
1450 GtkAssistantPage *page = (GtkAssistantPage *) pages->data;
1452 (*callback) (page->page, callback_data);
1454 if (include_internals)
1455 (*callback) (page->title, callback_data);
1457 pages = pages->next;
1462 * gtk_assistant_new:
1464 * Creates a new #GtkAssistant.
1466 * Return value: a newly created #GtkAssistant
1471 gtk_assistant_new (void)
1473 GtkWidget *assistant;
1475 assistant = g_object_new (GTK_TYPE_ASSISTANT,
1482 * gtk_assistant_get_current_page:
1483 * @assistant: a #GtkAssistant
1485 * Returns the page number of the current page
1487 * Return value: The index (starting from 0) of the current page in
1488 * the @assistant, if the @assistant has no pages, -1 will be returned
1493 gtk_assistant_get_current_page (GtkAssistant *assistant)
1495 GtkAssistantPrivate *priv;
1497 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), -1);
1499 priv = assistant->priv;
1501 if (!priv->pages || !priv->current_page)
1504 return g_list_index (priv->pages, priv->current_page);
1508 * gtk_assistant_set_current_page:
1509 * @assistant: a #GtkAssistant
1510 * @page_num: index of the page to switch to, starting from 0.
1511 * If negative, the last page will be used. If greater
1512 * than the number of pages in the @assistant, nothing
1515 * Switches the page to @page_num. Note that this will only be necessary
1516 * in custom buttons, as the @assistant flow can be set with
1517 * gtk_assistant_set_forward_page_func().
1522 gtk_assistant_set_current_page (GtkAssistant *assistant,
1525 GtkAssistantPrivate *priv;
1526 GtkAssistantPage *page;
1528 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1530 priv = assistant->priv;
1533 page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num);
1535 page = (GtkAssistantPage *) g_list_last (priv->pages);
1537 g_return_if_fail (page != NULL);
1539 if (priv->current_page == page)
1542 /* only add the page to the visited list if the
1543 * assistant is mapped, if not, just use it as an
1544 * initial page setting, for the cases where the
1545 * initial page is != to 0
1547 if (GTK_WIDGET_MAPPED (assistant))
1548 priv->visited_pages = g_slist_prepend (priv->visited_pages,
1549 priv->current_page);
1551 set_current_page (assistant, page);
1555 * gtk_assistant_get_n_pages:
1556 * @assistant: a #GtkAssistant
1558 * Returns the number of pages in the @assistant
1560 * Return value: The number of pages in the @assistant.
1565 gtk_assistant_get_n_pages (GtkAssistant *assistant)
1567 GtkAssistantPrivate *priv;
1569 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1571 priv = assistant->priv;
1573 return g_list_length (priv->pages);
1577 * gtk_assistant_get_nth_page:
1578 * @assistant: a #GtkAssistant
1579 * @page_num: The index of a page in the @assistant, or -1 to get the last page;
1581 * Returns the child widget contained in page number @page_num.
1583 * Return value: The child widget, or %NULL if @page_num is out of bounds.
1588 gtk_assistant_get_nth_page (GtkAssistant *assistant,
1591 GtkAssistantPrivate *priv;
1592 GtkAssistantPage *page;
1595 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1597 priv = assistant->priv;
1599 elem = g_list_nth (priv->pages, page_num);
1604 page = (GtkAssistantPage *) elem->data;
1610 * gtk_assistant_prepend_page:
1611 * @assistant: a #GtkAssistant
1612 * @page: a #GtkWidget
1614 * Prepends a page to the @assistant.
1616 * Return value: the index (starting at 0) of the inserted page
1621 gtk_assistant_prepend_page (GtkAssistant *assistant,
1624 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1625 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1627 return gtk_assistant_insert_page (assistant, page, 0);
1631 * gtk_assistant_append_page:
1632 * @assistant: a #GtkAssistant
1633 * @page: a #GtkWidget
1635 * Appends a page to the @assistant.
1637 * Return value: the index (starting at 0) of the inserted page
1642 gtk_assistant_append_page (GtkAssistant *assistant,
1645 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1646 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1648 return gtk_assistant_insert_page (assistant, page, -1);
1652 * gtk_assistant_insert_page:
1653 * @assistant: a #GtkAssistant
1654 * @page: a #GtkWidget
1655 * @position: the index (starting at 0) at which to insert the page,
1656 * or -1 to append the page to the @assistant
1658 * Inserts a page in the @assistant at a given position.
1660 * Return value: the index (starting from 0) of the inserted page
1665 gtk_assistant_insert_page (GtkAssistant *assistant,
1669 GtkAssistantPrivate *priv;
1670 GtkAssistantPage *page_info;
1673 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1674 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1675 g_return_val_if_fail (page->parent == NULL, 0);
1676 g_return_val_if_fail (!GTK_WIDGET_TOPLEVEL (page), 0);
1678 priv = assistant->priv;
1680 page_info = g_slice_new0 (GtkAssistantPage);
1681 page_info->page = page;
1682 page_info->title = gtk_label_new (NULL);
1684 g_signal_connect (G_OBJECT (page), "notify::visible",
1685 G_CALLBACK (on_page_notify_visibility), assistant);
1687 gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5);
1688 set_title_colors (GTK_WIDGET (assistant), page_info->title);
1689 set_title_font (GTK_WIDGET (assistant), page_info->title);
1690 gtk_widget_show (page_info->title);
1692 n_pages = g_list_length (priv->pages);
1694 if (position < 0 || position > n_pages)
1697 priv->pages = g_list_insert (priv->pages, page_info, position);
1699 gtk_widget_set_child_visible (page_info->page, FALSE);
1700 gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant));
1701 gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant));
1703 if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant)))
1705 gtk_widget_realize (page_info->page);
1706 gtk_widget_realize (page_info->title);
1709 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1715 * gtk_assistant_set_forward_page_func:
1716 * @assistant: a #GtkAssistant
1717 * @page_func: the #GtkAssistantPageFunc, or %NULL to use the default one
1718 * @data: user data for @page_func
1719 * @destroy: destroy notifier for @data
1721 * Sets the page forwarding function to be @page_func, this function will
1722 * be used to determine what will be the next page when the user presses
1723 * the forward button. Setting @page_func to %NULL will make the assistant
1724 * to use the default forward function, which just goes to the next visible
1730 gtk_assistant_set_forward_page_func (GtkAssistant *assistant,
1731 GtkAssistantPageFunc page_func,
1733 GDestroyNotify destroy)
1735 GtkAssistantPrivate *priv;
1737 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1739 priv = assistant->priv;
1741 if (priv->forward_data_destroy &&
1742 priv->forward_function_data)
1743 (*priv->forward_data_destroy) (priv->forward_function_data);
1747 priv->forward_function = page_func;
1748 priv->forward_function_data = data;
1749 priv->forward_data_destroy = destroy;
1753 priv->forward_function = default_forward_function;
1754 priv->forward_function_data = assistant;
1755 priv->forward_data_destroy = NULL;
1758 /* Page flow has possibly changed, so the
1759 buttons state might need to change too */
1760 set_assistant_buttons_state (assistant);
1764 * gtk_assistant_add_action_widget:
1765 * @assistant: a #GtkAssistant
1766 * @child: a #GtkWidget
1768 * Adds a widget to the action area of a #GtkAssistant.
1773 gtk_assistant_add_action_widget (GtkAssistant *assistant,
1776 GtkAssistantPrivate *priv;
1778 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1779 g_return_if_fail (GTK_IS_WIDGET (child));
1781 priv = assistant->priv;
1783 if (GTK_IS_BUTTON (child))
1784 gtk_size_group_add_widget (priv->size_group, child);
1786 gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0);
1790 * gtk_assistant_remove_action_widget:
1791 * @assistant: a #GtkAssistant
1792 * @child: a #GtkWidget
1794 * Removes a widget from the action area of a #GtkAssistant.
1799 gtk_assistant_remove_action_widget (GtkAssistant *assistant,
1802 GtkAssistantPrivate *priv;
1804 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1805 g_return_if_fail (GTK_IS_WIDGET (child));
1807 priv = assistant->priv;
1809 if (GTK_IS_BUTTON (child))
1810 gtk_size_group_remove_widget (priv->size_group, child);
1812 gtk_container_remove (GTK_CONTAINER (priv->action_area), child);
1816 * gtk_assistant_set_page_title:
1817 * @assistant: a #GtkAssistant
1818 * @page: a page of @assistant
1819 * @title: the new title for @page
1821 * Sets a title for @page. The title is displayed in the header
1822 * area of the assistant when @page is the current page.
1827 gtk_assistant_set_page_title (GtkAssistant *assistant,
1831 GtkAssistantPage *page_info;
1834 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1835 g_return_if_fail (GTK_IS_WIDGET (page));
1837 child = find_page (assistant, page);
1839 g_return_if_fail (child != NULL);
1841 page_info = (GtkAssistantPage*) child->data;
1843 gtk_label_set_text ((GtkLabel*) page_info->title, title);
1844 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1845 gtk_widget_child_notify (page, "title");
1849 * gtk_assistant_get_page_title:
1850 * @assistant: a #GtkAssistant
1851 * @page: a page of @assistant
1853 * Gets the title for @page.
1855 * Return value: the title for @page.
1859 G_CONST_RETURN gchar*
1860 gtk_assistant_get_page_title (GtkAssistant *assistant,
1863 GtkAssistantPage *page_info;
1866 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1867 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
1869 child = find_page (assistant, page);
1871 g_return_val_if_fail (child != NULL, NULL);
1873 page_info = (GtkAssistantPage*) child->data;
1875 return gtk_label_get_text ((GtkLabel*) page_info->title);
1879 * gtk_assistant_set_page_type:
1880 * @assistant: a #GtkAssistant
1881 * @page: a page of @assistant
1882 * @type: the new type for @page
1884 * Sets the page type for @page. The page type determines the page
1885 * behavior in the @assistant.
1890 gtk_assistant_set_page_type (GtkAssistant *assistant,
1892 GtkAssistantPageType type)
1894 GtkAssistantPrivate *priv;
1895 GtkAssistantPage *page_info;
1898 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1899 g_return_if_fail (GTK_IS_WIDGET (page));
1901 priv = assistant->priv;
1902 child = find_page (assistant, page);
1904 g_return_if_fail (child != NULL);
1906 page_info = (GtkAssistantPage*) child->data;
1908 if (type != page_info->type)
1910 page_info->type = type;
1912 /* Always set buttons state, a change in a future page
1913 might change current page buttons */
1914 set_assistant_buttons_state (assistant);
1916 gtk_widget_child_notify (page, "page-type");
1921 * gtk_assistant_get_page_type:
1922 * @assistant: a #GtkAssistant
1923 * @page: a page of @assistant
1925 * Gets the page type of @page.
1927 * Return value: the page type of @page.
1931 GtkAssistantPageType
1932 gtk_assistant_get_page_type (GtkAssistant *assistant,
1935 GtkAssistantPage *page_info;
1938 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), GTK_ASSISTANT_PAGE_CONTENT);
1939 g_return_val_if_fail (GTK_IS_WIDGET (page), GTK_ASSISTANT_PAGE_CONTENT);
1941 child = find_page (assistant, page);
1943 g_return_val_if_fail (child != NULL, GTK_ASSISTANT_PAGE_CONTENT);
1945 page_info = (GtkAssistantPage*) child->data;
1947 return page_info->type;
1951 * gtk_assistant_set_page_header_image:
1952 * @assistant: a #GtkAssistant
1953 * @page: a page of @assistant
1954 * @pixbuf: the new header image @page
1956 * Sets a header image for @page. This image is displayed in the header
1957 * area of the assistant when @page is the current page.
1962 gtk_assistant_set_page_header_image (GtkAssistant *assistant,
1966 GtkAssistantPrivate *priv;
1967 GtkAssistantPage *page_info;
1970 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1971 g_return_if_fail (GTK_IS_WIDGET (page));
1972 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1974 priv = assistant->priv;
1975 child = find_page (assistant, page);
1977 g_return_if_fail (child != NULL);
1979 page_info = (GtkAssistantPage*) child->data;
1981 if (pixbuf != page_info->header_image)
1983 if (page_info->header_image)
1985 g_object_unref (page_info->header_image);
1986 page_info->header_image = NULL;
1990 page_info->header_image = g_object_ref (pixbuf);
1992 if (page_info == priv->current_page)
1993 set_assistant_header_image (assistant);
1995 gtk_widget_child_notify (page, "header-image");
2000 * gtk_assistant_get_page_header_image:
2001 * @assistant: a #GtkAssistant
2002 * @page: a page of @assistant
2004 * Gets the header image for @page.
2006 * Return value: the header image for @page, or %NULL
2007 * if there's no header image for the page.
2012 gtk_assistant_get_page_header_image (GtkAssistant *assistant,
2015 GtkAssistantPage *page_info;
2018 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2019 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2021 child = find_page (assistant, page);
2023 g_return_val_if_fail (child != NULL, NULL);
2025 page_info = (GtkAssistantPage*) child->data;
2027 return page_info->header_image;
2031 * gtk_assistant_set_page_side_image:
2032 * @assistant: a #GtkAssistant
2033 * @page: a page of @assistant
2034 * @pixbuf: the new header image @page
2036 * Sets a header image for @page. This image is displayed in the side
2037 * area of the assistant when @page is the current page.
2042 gtk_assistant_set_page_side_image (GtkAssistant *assistant,
2046 GtkAssistantPrivate *priv;
2047 GtkAssistantPage *page_info;
2050 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2051 g_return_if_fail (GTK_IS_WIDGET (page));
2052 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2054 priv = assistant->priv;
2055 child = find_page (assistant, page);
2057 g_return_if_fail (child != NULL);
2059 page_info = (GtkAssistantPage*) child->data;
2061 if (pixbuf != page_info->sidebar_image)
2063 if (page_info->sidebar_image)
2065 g_object_unref (page_info->sidebar_image);
2066 page_info->sidebar_image = NULL;
2070 page_info->sidebar_image = g_object_ref (pixbuf);
2072 if (page_info == priv->current_page)
2073 set_assistant_sidebar_image (assistant);
2075 gtk_widget_child_notify (page, "sidebar-image");
2080 * gtk_assistant_get_page_side_image:
2081 * @assistant: a #GtkAssistant
2082 * @page: a page of @assistant
2084 * Gets the header image for @page.
2086 * Return value: the side image for @page, or %NULL
2087 * if there's no side image for the page.
2092 gtk_assistant_get_page_side_image (GtkAssistant *assistant,
2095 GtkAssistantPage *page_info;
2098 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2099 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2101 child = find_page (assistant, page);
2103 g_return_val_if_fail (child != NULL, NULL);
2105 page_info = (GtkAssistantPage*) child->data;
2107 return page_info->sidebar_image;
2111 * gtk_assistant_set_page_complete:
2112 * @assistant: a #GtkAssistant
2113 * @page: a page of @assistant
2114 * @complete: the completeness status of the page
2116 * Sets whether @page contents are complete. This will make
2117 * @assistant update the buttons state to be able to continue the task.
2122 gtk_assistant_set_page_complete (GtkAssistant *assistant,
2126 GtkAssistantPrivate *priv;
2127 GtkAssistantPage *page_info;
2130 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2131 g_return_if_fail (GTK_IS_WIDGET (page));
2133 priv = assistant->priv;
2134 child = find_page (assistant, page);
2136 g_return_if_fail (child != NULL);
2138 page_info = (GtkAssistantPage*) child->data;
2140 if (complete != page_info->complete)
2142 page_info->complete = complete;
2144 /* Always set buttons state, a change in a future page
2145 might change current page buttons */
2146 set_assistant_buttons_state (assistant);
2148 gtk_widget_child_notify (page, "complete");
2153 * gtk_assistant_get_page_complete:
2154 * @assistant: a #GtkAssistant
2155 * @page: a page of @assistant
2157 * Gets whether @page is complete..
2159 * Return value: %TRUE if @page is complete.
2164 gtk_assistant_get_page_complete (GtkAssistant *assistant,
2167 GtkAssistantPage *page_info;
2170 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), FALSE);
2171 g_return_val_if_fail (GTK_IS_WIDGET (page), FALSE);
2173 child = find_page (assistant, page);
2175 g_return_val_if_fail (child != NULL, FALSE);
2177 page_info = (GtkAssistantPage*) child->data;
2179 return page_info->complete;
2183 * gtk_assistant_update_buttons_state:
2184 * @assistant: a #GtkAssistant
2186 * Forces @assistant to recompute the buttons state.
2188 * GTK+ automatically takes care of this in most situations,
2189 * e.g. when the user goes to a different page, or when the
2190 * visibility or completeness of a page changes.
2192 * One situation where it can be necessary to call this
2193 * function is when changing a value on the current page
2194 * affects the future page flow of the assistant.
2199 gtk_assistant_update_buttons_state (GtkAssistant *assistant)
2201 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2203 set_assistant_buttons_state (assistant);
2208 /* accessible implementation */
2211 gtk_assistant_accessible_get_n_children (AtkObject *accessible)
2213 GtkAssistant *assistant;
2216 widget = GTK_ACCESSIBLE (accessible)->widget;
2221 assistant = GTK_ASSISTANT (widget);
2223 return g_list_length (assistant->priv->pages) + 1;
2228 gtk_assistant_accessible_ref_child (AtkObject *accessible,
2231 GtkAssistant *assistant;
2232 GtkAssistantPrivate *priv;
2233 GtkWidget *widget, *child;
2237 widget = GTK_ACCESSIBLE (accessible)->widget;
2241 assistant = GTK_ASSISTANT (widget);
2242 priv = assistant->priv;
2243 n_pages = g_list_length (priv->pages);
2247 else if (index < n_pages)
2249 GtkAssistantPage *page = g_list_nth_data (priv->pages, index / 2);
2253 else if (index == n_pages)
2255 child = priv->action_area;
2260 obj = gtk_widget_get_accessible (child);
2262 return g_object_ref (obj);
2266 gtk_assistant_accessible_class_init (AtkObjectClass *class)
2268 class->get_n_children = gtk_assistant_accessible_get_n_children;
2269 class->ref_child = gtk_assistant_accessible_ref_child;
2273 gtk_assistant_accessible_get_type (void)
2275 static GType type = 0;
2280 * Figure out the size of the class and instance
2281 * we are deriving from
2283 AtkObjectFactory *factory;
2286 GType derived_atk_type;
2288 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2289 factory = atk_registry_get_factory (atk_get_default_registry (),
2291 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2292 g_type_query (derived_atk_type, &query);
2294 type = g_type_register_static_simple (derived_atk_type,
2295 I_("GtkAssistantAccessible"),
2297 (GClassInitFunc) gtk_assistant_accessible_class_init,
2298 query.instance_size,
2306 gtk_assistant_accessible_new (GObject *obj)
2308 AtkObject *accessible;
2310 g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL);
2312 accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL);
2313 atk_object_initialize (accessible, obj);
2319 gtk_assistant_accessible_factory_get_accessible_type (void)
2321 return gtk_assistant_accessible_get_type ();
2325 gtk_assistant_accessible_factory_create_accessible (GObject *obj)
2327 return gtk_assistant_accessible_new (obj);
2331 gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class)
2333 class->create_accessible = gtk_assistant_accessible_factory_create_accessible;
2334 class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type;
2338 gtk_assistant_accessible_factory_get_type (void)
2340 static GType type = 0;
2344 type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY,
2345 I_("GtkAssistantAccessibleFactory"),
2346 sizeof (AtkObjectFactoryClass),
2347 (GClassInitFunc) gtk_assistant_accessible_factory_class_init,
2348 sizeof (AtkObjectFactory),
2356 gtk_assistant_get_accessible (GtkWidget *widget)
2358 static gboolean first_time = TRUE;
2362 AtkObjectFactory *factory;
2363 AtkRegistry *registry;
2365 GType derived_atk_type;
2368 * Figure out whether accessibility is enabled by looking at the
2369 * type of the accessible object which would be created for
2370 * the parent type of GtkAssistant.
2372 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2374 registry = atk_get_default_registry ();
2375 factory = atk_registry_get_factory (registry,
2377 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2378 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
2380 atk_registry_set_factory_type (registry,
2382 gtk_assistant_accessible_factory_get_type ());
2387 return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget);
2391 #define __GTK_ASSISTANT_C__
2392 #include "gtkaliasdef.c"