X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkassistant.c;h=3ba9f227be5abc7934d793a7877a92be13638a2d;hb=ea043cab5718304d9b6170afa2d3f959fc99c718;hp=17ecf46a872940972063fab7a86fe586965fb5ae;hpb=c7514e8f0d19a833257497caff413bb4dfae6eb4;p=~andy%2Fgtk diff --git a/gtk/gtkassistant.c b/gtk/gtkassistant.c index 17ecf46a8..3ba9f227b 100644 --- a/gtk/gtkassistant.c +++ b/gtk/gtkassistant.c @@ -18,9 +18,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /** @@ -62,12 +60,13 @@ #include "gtkassistant.h" -#include "gtkaccessibleprivate.h" #include "gtkbutton.h" -#include "gtkhbox.h" -#include "gtkhbbox.h" +#include "gtkbox.h" +#include "gtkframe.h" +#include "gtknotebook.h" #include "gtkimage.h" #include "gtklabel.h" +#include "gtksettings.h" #include "gtksizegroup.h" #include "gtksizerequest.h" #include "gtkstock.h" @@ -75,6 +74,7 @@ #include "gtkintl.h" #include "gtkprivate.h" #include "gtkbuildable.h" +#include "a11y/gtkwindowaccessible.h" #define HEADER_SPACING 12 @@ -84,12 +84,15 @@ typedef struct _GtkAssistantPage GtkAssistantPage; struct _GtkAssistantPage { - GtkWidget *page; GtkAssistantPageType type; - guint complete : 1; + guint complete : 1; guint complete_set : 1; - GtkWidget *title; + gchar *title; + + GtkWidget *page; + GtkWidget *regular_title; + GtkWidget *current_title; GdkPixbuf *header_image; GdkPixbuf *sidebar_image; }; @@ -103,54 +106,37 @@ struct _GtkAssistantPrivate GtkWidget *close; GtkWidget *last; - GtkWidget *header_image; - GtkWidget *sidebar_image; - + GtkWidget *sidebar; + GtkWidget *content; GtkWidget *action_area; GList *pages; - - GtkAssistantPage *current_page; - GSList *visited_pages; + GtkAssistantPage *current_page; - GtkSizeGroup *size_group; + GtkSizeGroup *button_size_group; + GtkSizeGroup *title_size_group; GtkAssistantPageFunc forward_function; gpointer forward_function_data; GDestroyNotify forward_data_destroy; + gint extra_buttons; + guint committed : 1; }; static void gtk_assistant_class_init (GtkAssistantClass *class); static void gtk_assistant_init (GtkAssistant *assistant); static void gtk_assistant_destroy (GtkWidget *widget); -static void gtk_assistant_style_updated (GtkWidget *widget); -static void gtk_assistant_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural); -static void gtk_assistant_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural); -static void gtk_assistant_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); static void gtk_assistant_map (GtkWidget *widget); static void gtk_assistant_unmap (GtkWidget *widget); static gboolean gtk_assistant_delete_event (GtkWidget *widget, GdkEventAny *event); -static gboolean gtk_assistant_draw (GtkWidget *widget, - cairo_t *cr); -static gboolean gtk_assistant_focus (GtkWidget *widget, - GtkDirectionType direction); static void gtk_assistant_add (GtkContainer *container, GtkWidget *page); static void gtk_assistant_remove (GtkContainer *container, GtkWidget *page); -static void gtk_assistant_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); static void gtk_assistant_set_child_property (GtkContainer *container, GtkWidget *child, guint property_id, @@ -162,9 +148,6 @@ static void gtk_assistant_get_child_property (GtkContainer *container, GValue *value, GParamSpec *pspec); -static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget); -static GType gtk_assistant_accessible_factory_get_type (void); - static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface); static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable, GtkBuilder *builder, @@ -183,6 +166,14 @@ static void gtk_assistant_buildable_custom_finished (GtkBuildable *bui static GList* find_page (GtkAssistant *assistant, GtkWidget *page); +static void gtk_assistant_do_set_page_header_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf); +static void gtk_assistant_do_set_page_side_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf); + +GType _gtk_assistant_accessible_get_type (void); enum { @@ -223,20 +214,14 @@ gtk_assistant_class_init (GtkAssistantClass *class) container_class = (GtkContainerClass *) class; widget_class->destroy = gtk_assistant_destroy; - widget_class->style_updated = gtk_assistant_style_updated; - widget_class->get_preferred_width = gtk_assistant_get_preferred_width; - widget_class->get_preferred_height = gtk_assistant_get_preferred_height; - widget_class->size_allocate = gtk_assistant_size_allocate; widget_class->map = gtk_assistant_map; widget_class->unmap = gtk_assistant_unmap; widget_class->delete_event = gtk_assistant_delete_event; - widget_class->draw = gtk_assistant_draw; - widget_class->focus = gtk_assistant_focus; - widget_class->get_accessible = gtk_assistant_get_accessible; + + gtk_widget_class_set_accessible_type (widget_class, _gtk_assistant_accessible_get_type ()); container_class->add = gtk_assistant_add; container_class->remove = gtk_assistant_remove; - container_class->forall = gtk_assistant_forall; container_class->set_child_property = gtk_assistant_set_child_property; container_class->get_child_property = gtk_assistant_get_child_property; @@ -262,9 +247,11 @@ gtk_assistant_class_init (GtkAssistantClass *class) * @assistant: the #GtkAssistant * @page: the current page * - * The ::prepare signal is emitted when a new page is set as the assistant's - * current page, before making the new page visible. A handler for this signal - * can do any preparation which are necessary before showing @page. + * The ::prepare signal is emitted when a new page is set as the + * assistant's current page, before making the new page visible. + * + * A handler for this signal can do any preparations which are + * necessary before showing @page. * * Since: 2.10 */ @@ -281,15 +268,17 @@ gtk_assistant_class_init (GtkAssistantClass *class) * GtkAssistant::apply: * @assistant: the #GtkAssistant * - * The ::apply signal is emitted when the apply button is clicked. The default - * behavior of the #GtkAssistant is to switch to the page after the current - * page, unless the current page is the last one. + * The ::apply signal is emitted when the apply button is clicked. + * + * The default behavior of the #GtkAssistant is to switch to the page + * after the current page, unless the current page is the last one. * - * A handler for the ::apply signal should carry out the actions for which - * the wizard has collected data. If the action takes a long time to complete, - * you might consider putting a page of type %GTK_ASSISTANT_PAGE_PROGRESS - * after the confirmation page and handle this operation within the - * #GtkAssistant::prepare signal of the progress page. + * A handler for the ::apply signal should carry out the actions for + * which the wizard has collected data. If the action takes a long time + * to complete, you might consider putting a page of type + * %GTK_ASSISTANT_PAGE_PROGRESS after the confirmation page and handle + * this operation within the #GtkAssistant::prepare signal of the progress + * page. * * Since: 2.10 */ @@ -357,9 +346,7 @@ gtk_assistant_class_init (GtkAssistantClass *class) /** * GtkAssistant:title: * - * The title that is displayed in the page header. - * - * If title and header-image are both %NULL, no header is displayed. + * The title of the page. * * Since: 2.10 */ @@ -374,11 +361,12 @@ gtk_assistant_class_init (GtkAssistantClass *class) /** * GtkAssistant:header-image: * - * The image that is displayed next to the title in the page header. - * - * If title and header-image are both %NULL, no header is displayed. + * This image used to be displayed in the page header. * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. */ gtk_container_class_install_child_property (container_class, CHILD_PROP_PAGE_HEADER_IMAGE, @@ -389,13 +377,13 @@ gtk_assistant_class_init (GtkAssistantClass *class) GTK_PARAM_READWRITE)); /** - * GtkAssistant:header-image: - * - * The image that is displayed next to the page. + * GtkAssistant:sidebar-image: * - * Set this to %NULL to make the sidebar disappear. + * This image used to be displayed in the 'sidebar'. * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, the sidebar image is no longer shown. */ gtk_container_class_install_child_property (container_class, CHILD_PROP_PAGE_SIDEBAR_IMAGE, @@ -404,12 +392,13 @@ gtk_assistant_class_init (GtkAssistantClass *class) P_("Sidebar image for the assistant page"), GDK_TYPE_PIXBUF, GTK_PARAM_READWRITE)); + /** * GtkAssistant:complete: * - * Setting the "complete" child property to %TRUE marks a page as complete - * (i.e.: all the required fields are filled out). GTK+ uses this information - * to control the sensitivity of the navigation buttons. + * Setting the "complete" child property to %TRUE marks a page as + * complete (i.e.: all the required fields are filled out). GTK+ uses + * this information to control the sensitivity of the navigation buttons. * * Since: 2.10 */ @@ -454,17 +443,23 @@ default_forward_function (gint current_page, gpointer data) return current_page; } -static void -compute_last_button_state (GtkAssistant *assistant) +static gboolean +last_button_visible (GtkAssistant *assistant, GtkAssistantPage *page) { GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info, *current_page_info; + GtkAssistantPage *page_info; gint count, page_num, n_pages; + if (page == NULL) + return FALSE; + + if (page->type != GTK_ASSISTANT_PAGE_CONTENT) + return FALSE; + count = 0; - page_num = gtk_assistant_get_current_page (assistant); - n_pages = gtk_assistant_get_n_pages (assistant); - current_page_info = page_info = g_list_nth_data (priv->pages, page_num); + page_num = g_list_index (priv->pages, page); + n_pages = g_list_length (priv->pages); + page_info = page; while (page_num >= 0 && page_num < n_pages && page_info->type == GTK_ASSISTANT_PAGE_CONTENT && @@ -477,63 +472,87 @@ compute_last_button_state (GtkAssistant *assistant) count++; } - /* make the last button visible if we can skip multiple + /* Make the last button visible if we can skip multiple * pages and end on a confirmation or summary page */ if (count > 1 && page_info && (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM || page_info->type == GTK_ASSISTANT_PAGE_SUMMARY)) - { - gtk_widget_show (priv->last); - gtk_widget_set_sensitive (priv->last, - current_page_info->complete); - } + return TRUE; else - gtk_widget_hide (priv->last); + return FALSE; } static void -compute_progress_state (GtkAssistant *assistant) +update_actions_size (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; - gint page_num, n_pages; + GList *l; + GtkAssistantPage *page; + gint buttons, page_buttons; - n_pages = gtk_assistant_get_n_pages (assistant); - page_num = gtk_assistant_get_current_page (assistant); + if (!priv->current_page) + return; - page_num = (priv->forward_function) (page_num, priv->forward_function_data); + /* Some heuristics to find out how many buttons we should + * reserve space for. It is possible to trick this code + * with page forward functions and invisible pages, etc. + */ + buttons = 0; + for (l = priv->pages; l; l = l->next) + { + page = l->data; - if (page_num >= 0 && page_num < n_pages) - gtk_widget_show (priv->forward); - else - gtk_widget_hide (priv->forward); + if (!gtk_widget_get_visible (page->page)) + continue; + + page_buttons = 2; /* cancel, forward/apply/close */ + if (l != priv->pages) + page_buttons += 1; /* back */ + if (last_button_visible (assistant, page)) + page_buttons += 1; /* last */ + + buttons = MAX (buttons, page_buttons); + } + + buttons += priv->extra_buttons; + + gtk_widget_set_size_request (priv->action_area, + buttons * gtk_widget_get_allocated_width (priv->cancel) + (buttons - 1) * 6, + -1); } static void -set_assistant_header_image (GtkAssistant *assistant) +compute_last_button_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image), - priv->current_page->header_image); + gtk_widget_set_sensitive (priv->last, priv->current_page->complete); + if (last_button_visible (assistant, priv->current_page)) + gtk_widget_show (priv->last); + else + gtk_widget_hide (priv->last); } static void -set_assistant_sidebar_image (GtkAssistant *assistant) +compute_progress_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; + gint page_num, n_pages; + + n_pages = gtk_assistant_get_n_pages (assistant); + page_num = gtk_assistant_get_current_page (assistant); - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image), - priv->current_page->sidebar_image); + page_num = (priv->forward_function) (page_num, priv->forward_function_data); - if (priv->current_page->sidebar_image) - gtk_widget_show (priv->sidebar_image); + if (page_num >= 0 && page_num < n_pages) + gtk_widget_show (priv->forward); else - gtk_widget_hide (priv->sidebar_image); + gtk_widget_hide (priv->forward); } static void -set_assistant_buttons_state (GtkAssistant *assistant) +update_buttons_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; @@ -621,44 +640,98 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_hide (priv->back); } -static void -set_current_page (GtkAssistant *assistant, - GtkAssistantPage *page) +static gboolean +update_page_title_state (GtkAssistant *assistant, GList *list) { + GtkAssistantPage *page, *other; GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *old_page; + gboolean visible; + GList *l; - if (priv->current_page && - gtk_widget_is_drawable (priv->current_page->page)) - old_page = priv->current_page; - else - old_page = NULL; + page = list->data; - priv->current_page = page; + if (page->title == NULL || page->title[0] == 0) + visible = FALSE; + else + visible = gtk_widget_get_visible (page->page); - set_assistant_buttons_state (assistant); - set_assistant_header_image (assistant); - set_assistant_sidebar_image (assistant); + if (page == priv->current_page) + { + gtk_widget_set_visible (page->regular_title, FALSE); + gtk_widget_set_visible (page->current_title, visible); + } + else + { + /* If multiple consecutive pages have the same title, + * we only show it once, since it would otherwise look + * silly. We have to be a little careful, since we + * _always_ show the title of the current page. + */ + if (list->prev) + { + other = list->prev->data; + if (g_strcmp0 (page->title, other->title) == 0) + visible = FALSE; + } + for (l = list->next; l; l = l->next) + { + other = l->data; + if (g_strcmp0 (page->title, other->title) != 0) + break; - g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page); + if (other == priv->current_page) + { + visible = FALSE; + break; + } + } - if (gtk_widget_get_visible (priv->current_page->page) && - gtk_widget_get_mapped (GTK_WIDGET (assistant))) - { - gtk_widget_set_child_visible (priv->current_page->page, TRUE); - gtk_widget_set_child_visible (priv->current_page->title, TRUE); - gtk_widget_map (priv->current_page->page); - gtk_widget_map (priv->current_page->title); + gtk_widget_set_visible (page->regular_title, visible); + gtk_widget_set_visible (page->current_title, FALSE); } - if (old_page && gtk_widget_get_mapped (old_page->page)) + return visible; +} + +static void +update_title_state (GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + GList *l; + gboolean show_titles; + + show_titles = FALSE; + for (l = priv->pages; l != NULL; l = l->next) { - gtk_widget_set_child_visible (old_page->page, FALSE); - gtk_widget_set_child_visible (old_page->title, FALSE); - gtk_widget_unmap (old_page->page); - gtk_widget_unmap (old_page->title); + if (update_page_title_state (assistant, l)) + show_titles = TRUE; } + gtk_widget_set_visible (priv->sidebar, show_titles); +} + +static void +set_current_page (GtkAssistant *assistant, + gint page_num) +{ + GtkAssistantPrivate *priv = assistant->priv; + + priv->current_page = (GtkAssistantPage *)g_list_nth_data (priv->pages, page_num); + + g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page); + /* do not continue if the prepare signal handler has already changed the + * current page */ + if (priv->current_page != (GtkAssistantPage *)g_list_nth_data (priv->pages, page_num)) + return; + + update_title_state (assistant); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->content), page_num); + + /* update buttons state, flow may have changed */ + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_buttons_state (assistant); + if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD)) { GtkWidget *button[6]; @@ -702,7 +775,7 @@ compute_next_step (GtkAssistant *assistant) if (next_page >= 0 && next_page < n_pages) { priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info); - set_current_page (assistant, g_list_nth_data (priv->pages, next_page)); + set_current_page (assistant, next_page); return TRUE; } @@ -782,60 +855,184 @@ alternative_button_order (GtkAssistant *assistant) return result; } +static gboolean +assistant_sidebar_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer user_data) +{ + gint width, height; + GtkStyleContext *context; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + context = gtk_widget_get_style_context (widget); + + gtk_render_background (context, cr, 0, 0, width, height); + + return FALSE; +} + +static void +on_page_notify_visibility (GtkWidget *widget, + GParamSpec *arg, + gpointer data) +{ + GtkAssistant *assistant = GTK_ASSISTANT (data); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + { + update_buttons_state (assistant); + update_title_state (assistant); + } +} + +static void +assistant_remove_page_cb (GtkNotebook *notebook, + GtkWidget *page, + GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + GtkAssistantPage *page_info; + GList *page_node; + GList *element; + + element = find_page (assistant, page); + if (!element) + return; + + page_info = element->data; + + /* If this is the current page, we need to switch away. */ + if (page_info == priv->current_page) + { + if (!compute_next_step (assistant)) + { + /* The best we can do at this point is probably to pick + * the first visible page. + */ + page_node = priv->pages; + + while (page_node && + !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page)) + page_node = page_node->next; + + if (page_node == element) + page_node = page_node->next; + + if (page_node) + priv->current_page = page_node->data; + else + priv->current_page = NULL; + } + } + + g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant); + + gtk_size_group_remove_widget (priv->title_size_group, page_info->regular_title); + gtk_size_group_remove_widget (priv->title_size_group, page_info->current_title); + + gtk_container_remove (GTK_CONTAINER (priv->sidebar), page_info->regular_title); + gtk_container_remove (GTK_CONTAINER (priv->sidebar), page_info->current_title); + + priv->pages = g_list_remove_link (priv->pages, element); + priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info); + + g_free (page_info->title); + + g_slice_free (GtkAssistantPage, page_info); + g_list_free_1 (element); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + { + update_buttons_state (assistant); + update_actions_size (assistant); + } +} + static void gtk_assistant_init (GtkAssistant *assistant) { GtkAssistantPrivate *priv; GtkStyleContext *context; + GtkWidget *main_box; + GtkWidget *content_box; + GtkWidget *sidebar_frame; assistant->priv = G_TYPE_INSTANCE_GET_PRIVATE (assistant, GTK_TYPE_ASSISTANT, GtkAssistantPrivate); priv = assistant->priv; - gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE); - gtk_container_set_border_width (GTK_CONTAINER (assistant), 12); + /* use border on inner panes instead */ + gtk_container_set_border_width (GTK_CONTAINER (assistant), 0); gtk_widget_push_composite_child (); - /* Header */ - priv->header_image = gtk_image_new (); - gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5); - gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant)); - gtk_widget_show (priv->header_image); + main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + priv->sidebar = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - context = gtk_widget_get_style_context (priv->header_image); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + /* use a frame for the sidebar, and manually render a background + * in it. GtkFrame also gives us padding support for free. + */ + sidebar_frame = gtk_frame_new (NULL); + context = gtk_widget_get_style_context (sidebar_frame); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SIDEBAR); - /* Sidebar */ - priv->sidebar_image = gtk_image_new (); - gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.); - gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant)); - gtk_widget_show (priv->sidebar_image); + g_signal_connect (sidebar_frame, "draw", + G_CALLBACK (assistant_sidebar_draw_cb), assistant); - context = gtk_widget_get_style_context (priv->sidebar_image); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + content_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (content_box), 12); + priv->content = gtk_notebook_new (); + gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->content), FALSE); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->content), FALSE); + priv->action_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + + g_signal_connect (priv->content, "remove", + G_CALLBACK (assistant_remove_page_cb), assistant); + + gtk_container_add (GTK_CONTAINER (sidebar_frame), priv->sidebar); + gtk_box_pack_start (GTK_BOX (main_box), sidebar_frame, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_box), content_box, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (content_box), priv->content, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (content_box), priv->action_area, FALSE, TRUE, 0); + gtk_widget_set_halign (priv->action_area, GTK_ALIGN_END); + + gtk_widget_show_all (main_box); - /* Action area */ - priv->action_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + gtk_widget_set_parent (main_box, GTK_WIDGET (assistant)); + _gtk_bin_set_child (GTK_BIN (assistant), main_box); priv->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE); priv->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY); - priv->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD); - priv->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK); + priv->forward = gtk_button_new_with_mnemonic (_("C_ontinue")); + gtk_button_set_image (GTK_BUTTON (priv->forward), + gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON)); + priv->back = gtk_button_new_with_mnemonic (_("Go _Back")); + gtk_button_set_image (GTK_BUTTON (priv->back), + gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON)); priv->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - priv->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST); + priv->last = gtk_button_new_with_mnemonic (_("_Finish")); + gtk_button_set_image (GTK_BUTTON (priv->last), + gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_BUTTON)); gtk_widget_set_can_default (priv->close, TRUE); gtk_widget_set_can_default (priv->apply, TRUE); gtk_widget_set_can_default (priv->forward, TRUE); - priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - gtk_size_group_add_widget (priv->size_group, priv->close); - gtk_size_group_add_widget (priv->size_group, priv->apply); - gtk_size_group_add_widget (priv->size_group, priv->forward); - gtk_size_group_add_widget (priv->size_group, priv->back); - gtk_size_group_add_widget (priv->size_group, priv->cancel); - gtk_size_group_add_widget (priv->size_group, priv->last); + priv->button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_add_widget (priv->button_size_group, priv->close); + gtk_size_group_add_widget (priv->button_size_group, priv->apply); + gtk_size_group_add_widget (priv->button_size_group, priv->forward); + gtk_size_group_add_widget (priv->button_size_group, priv->back); + gtk_size_group_add_widget (priv->button_size_group, priv->cancel); + gtk_size_group_add_widget (priv->button_size_group, priv->last); + + gtk_widget_set_no_show_all (priv->close, TRUE); + gtk_widget_set_no_show_all (priv->apply, TRUE); + gtk_widget_set_no_show_all (priv->forward, TRUE); + gtk_widget_set_no_show_all (priv->back, TRUE); + gtk_widget_set_no_show_all (priv->cancel, TRUE); + gtk_widget_set_no_show_all (priv->last, TRUE); if (!alternative_button_order (assistant)) { @@ -856,7 +1053,6 @@ gtk_assistant_init (GtkAssistant *assistant) gtk_box_pack_end (GTK_BOX (priv->action_area), priv->last, FALSE, FALSE, 0); } - gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant)); gtk_widget_show (priv->forward); gtk_widget_show (priv->back); gtk_widget_show (priv->cancel); @@ -864,6 +1060,8 @@ gtk_assistant_init (GtkAssistant *assistant) gtk_widget_pop_composite_child (); + priv->title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + priv->pages = NULL; priv->current_page = NULL; priv->visited_pages = NULL; @@ -887,11 +1085,11 @@ gtk_assistant_init (GtkAssistant *assistant) } static void -gtk_assistant_set_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - const GValue *value, - GParamSpec *pspec) +gtk_assistant_set_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec) { switch (property_id) { @@ -904,12 +1102,12 @@ gtk_assistant_set_child_property (GtkContainer *container, g_value_get_string (value)); break; case CHILD_PROP_PAGE_HEADER_IMAGE: - gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child, - g_value_get_object (value)); + gtk_assistant_do_set_page_header_image (GTK_ASSISTANT (container), child, + g_value_get_object (value)); break; case CHILD_PROP_PAGE_SIDEBAR_IMAGE: - gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child, - g_value_get_object (value)); + gtk_assistant_do_set_page_side_image (GTK_ASSISTANT (container), child, + g_value_get_object (value)); break; case CHILD_PROP_PAGE_COMPLETE: gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child, @@ -928,403 +1126,118 @@ gtk_assistant_get_child_property (GtkContainer *container, GValue *value, GParamSpec *pspec) { + GtkAssistant *assistant = GTK_ASSISTANT (container); + switch (property_id) { case CHILD_PROP_PAGE_TYPE: g_value_set_enum (value, - gtk_assistant_get_page_type (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_type (assistant, child)); break; case CHILD_PROP_PAGE_TITLE: g_value_set_string (value, - gtk_assistant_get_page_title (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_title (assistant, child)); break; case CHILD_PROP_PAGE_HEADER_IMAGE: g_value_set_object (value, - gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child)); + ((GtkAssistantPage*) find_page (assistant, child))->header_image); break; case CHILD_PROP_PAGE_SIDEBAR_IMAGE: g_value_set_object (value, - gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child)); + ((GtkAssistantPage*) find_page (assistant, child))->sidebar_image); break; case CHILD_PROP_PAGE_COMPLETE: g_value_set_boolean (value, - gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_complete (assistant, child)); break; default: - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); - break; - } -} - -static void -on_page_notify_visibility (GtkWidget *widget, - GParamSpec *arg, - gpointer data) -{ - GtkAssistant *assistant = GTK_ASSISTANT (data); - - /* update buttons state, flow may have changed */ - if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) - set_assistant_buttons_state (assistant); -} - -static void -remove_page (GtkAssistant *assistant, - GList *element) -{ - GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info; - GList *page_node; - - page_info = element->data; - - /* If this is the current page, we need to switch away. */ - if (page_info == priv->current_page) - { - if (!compute_next_step (assistant)) - { - /* The best we can do at this point is probably to pick - * the first visible page. - */ - page_node = priv->pages; - - while (page_node && - !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page)) - page_node = page_node->next; - - if (page_node == element) - page_node = page_node->next; - - if (page_node) - priv->current_page = page_node->data; - else - priv->current_page = NULL; - } - } - - priv->pages = g_list_remove_link (priv->pages, element); - priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info); - - g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant); - gtk_widget_unparent (page_info->page); - - if (page_info->header_image) - g_object_unref (page_info->header_image); - - if (page_info->sidebar_image) - g_object_unref (page_info->sidebar_image); - - gtk_widget_destroy (page_info->title); - g_slice_free (GtkAssistantPage, page_info); - g_list_free_1 (element); -} - -static void -gtk_assistant_destroy (GtkWidget *widget) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - - if (priv->header_image) - { - gtk_widget_destroy (priv->header_image); - priv->header_image = NULL; - } - - if (priv->sidebar_image) - { - gtk_widget_destroy (priv->sidebar_image); - priv->sidebar_image = NULL; - } - - if (priv->action_area) - { - gtk_widget_destroy (priv->action_area); - priv->action_area = NULL; - } - - if (priv->size_group) - { - g_object_unref (priv->size_group); - priv->size_group = NULL; - } - - if (priv->forward_function) - { - if (priv->forward_function_data && - priv->forward_data_destroy) - priv->forward_data_destroy (priv->forward_function_data); - - priv->forward_function = NULL; - priv->forward_function_data = NULL; - priv->forward_data_destroy = NULL; - } - - if (priv->visited_pages) - { - g_slist_free (priv->visited_pages); - priv->visited_pages = NULL; - } - - /* We set current to NULL so that the remove code doesn't try - * to do anything funny */ - priv->current_page = NULL; - - while (priv->pages) - remove_page (assistant, priv->pages); - - GTK_WIDGET_CLASS (gtk_assistant_parent_class)->destroy (widget); -} - -static GList* -find_page (GtkAssistant *assistant, - GtkWidget *page) -{ - GtkAssistantPrivate *priv = assistant->priv; - GList *child = priv->pages; - - while (child) - { - GtkAssistantPage *page_info = child->data; - if (page_info->page == page) - return child; - - child = child->next; - } - - return NULL; -} - -static void -set_title_font (GtkWidget *assistant, - GtkWidget *title_label) -{ - PangoFontDescription *desc; - GtkStyleContext *context; - gint size; - - gtk_widget_override_font (title_label, NULL); - - desc = pango_font_description_new (); - context = gtk_widget_get_style_context (title_label); - size = pango_font_description_get_size (gtk_style_context_get_font (context, 0)); - - pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD); - pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE); - - gtk_widget_override_font (title_label, desc); - pango_font_description_free (desc); -} - -static void -gtk_assistant_style_updated (GtkWidget *widget) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GList *list; - - GTK_WIDGET_CLASS (gtk_assistant_parent_class)->style_updated (widget); - - list = priv->pages; - - while (list) - { - GtkAssistantPage *page = list->data; - - set_title_font (widget, page->title); - list = list->next; - } -} - -static void -gtk_assistant_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkRequisition child_requisition; - gint header_padding, content_padding; - gint width, height, header_width, header_height; - guint border_width; - GList *list; - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - width = height = 0; - header_width = header_height = 0; - list = priv->pages; - - while (list) - { - GtkAssistantPage *page = list->data; - gint w, h; - - gtk_widget_get_preferred_size (page->page, - &child_requisition, NULL); - width = MAX (width, child_requisition.width); - height = MAX (height, child_requisition.height); - - gtk_widget_get_preferred_size (page->title, - &child_requisition, NULL); - w = child_requisition.width; - h = child_requisition.height; - - if (page->header_image) - { - w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING; - h = MAX (h, gdk_pixbuf_get_height (page->header_image)); - } - - header_width = MAX (header_width, w); - header_height = MAX (header_height, h); - - list = list->next; + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + break; } - - gtk_widget_get_preferred_size (priv->sidebar_image, - &child_requisition, NULL); - width += child_requisition.width; - height = MAX (height, child_requisition.height); - - gtk_widget_set_size_request (priv->header_image, header_width, header_height); - gtk_widget_get_preferred_size (priv->header_image, - &child_requisition, NULL); - width = MAX (width, header_width) + 2 * header_padding; - height += header_height + 2 * header_padding; - - gtk_widget_get_preferred_size (priv->action_area, - &child_requisition, NULL); - width = MAX (width, child_requisition.width); - height += child_requisition.height + ACTION_AREA_SPACING; - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - width += border_width * 2 + content_padding * 2; - height += border_width * 2 + content_padding * 2; - - requisition->width = width; - requisition->height = height; -} - -static void -gtk_assistant_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - GtkRequisition requisition; - - gtk_assistant_size_request (widget, &requisition); - - *minimum = *natural = requisition.width; -} - -static void -gtk_assistant_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - GtkRequisition requisition; - - gtk_assistant_size_request (widget, &requisition); - - *minimum = *natural = requisition.height; } static void -gtk_assistant_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +gtk_assistant_destroy (GtkWidget *widget) { GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; - GtkRequisition header_requisition, action_requisition, sidebar_requisition; - GtkAllocation child_allocation, header_allocation; - GtkAllocation action_area_allocation, header_image_allocation; - gint header_padding, content_padding; - guint border_width; - gboolean rtl; - GList *pages; - - rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - pages = priv->pages; - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - - gtk_widget_set_allocation (widget, allocation); - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - /* Header */ - gtk_widget_get_preferred_size (priv->header_image, - &header_requisition, NULL); - header_allocation.x = border_width + header_padding; - header_allocation.y = border_width + header_padding; - header_allocation.width = allocation->width - 2 * border_width - 2 * header_padding; - header_allocation.height = header_requisition.height; + /* We set current to NULL so that the remove code doesn't try + * to do anything funny + */ + priv->current_page = NULL; - gtk_widget_size_allocate (priv->header_image, &header_allocation); + if (priv->content) + { + GtkNotebook *notebook; + GtkWidget *page; - /* Action area */ - gtk_widget_get_preferred_size (priv->action_area, - &action_requisition, NULL); + /* Remove all pages from the content notebook. */ + notebook = (GtkNotebook *) priv->content; + while ((page = gtk_notebook_get_nth_page (notebook, 0)) != NULL) + gtk_container_remove ((GtkContainer *) notebook, page); - child_allocation.x = border_width; - child_allocation.y = allocation->height - border_width - action_requisition.height; - child_allocation.width = allocation->width - 2 * border_width; - child_allocation.height = action_requisition.height; + /* Our GtkAssistantPage list should be empty now. */ + g_warn_if_fail (priv->pages == NULL); - gtk_widget_size_allocate (priv->action_area, &child_allocation); + priv->content = NULL; + } - gtk_widget_get_allocation (priv->header_image, &header_image_allocation); - gtk_widget_get_allocation (priv->action_area, &action_area_allocation); + if (priv->sidebar) + priv->sidebar = NULL; - /* Sidebar */ - gtk_widget_get_preferred_size (priv->sidebar_image, - &sidebar_requisition, NULL); + if (priv->action_area) + priv->action_area = NULL; - if (rtl) - child_allocation.x = allocation->width - border_width - sidebar_requisition.width; - else - child_allocation.x = border_width; + if (priv->button_size_group) + { + g_object_unref (priv->button_size_group); + priv->button_size_group = NULL; + } - child_allocation.y = border_width + header_image_allocation.height + 2 * header_padding; - child_allocation.width = sidebar_requisition.width; - child_allocation.height = allocation->height - 2 * border_width - - header_image_allocation.height - 2 * header_padding - action_area_allocation.height; + if (priv->title_size_group) + { + g_object_unref (priv->title_size_group); + priv->title_size_group = NULL; + } - gtk_widget_size_allocate (priv->sidebar_image, &child_allocation); + if (priv->forward_function) + { + if (priv->forward_function_data && + priv->forward_data_destroy) + priv->forward_data_destroy (priv->forward_function_data); - /* Pages */ - child_allocation.x = border_width + content_padding; - child_allocation.y = border_width + - header_image_allocation.height + 2 * header_padding + content_padding; - child_allocation.width = allocation->width - 2 * border_width - 2 * content_padding; - child_allocation.height = allocation->height - 2 * border_width - - header_image_allocation.height - 2 * header_padding - ACTION_AREA_SPACING - action_area_allocation.height - 2 * content_padding; + priv->forward_function = NULL; + priv->forward_function_data = NULL; + priv->forward_data_destroy = NULL; + } - if (gtk_widget_get_visible (priv->sidebar_image)) + if (priv->visited_pages) { - GtkAllocation sidebar_image_allocation; - - gtk_widget_get_allocation (priv->sidebar_image, &sidebar_image_allocation); + g_slist_free (priv->visited_pages); + priv->visited_pages = NULL; + } - if (!rtl) - child_allocation.x += sidebar_image_allocation.width; + GTK_WIDGET_CLASS (gtk_assistant_parent_class)->destroy (widget); +} - child_allocation.width -= sidebar_image_allocation.width; - } +static GList* +find_page (GtkAssistant *assistant, + GtkWidget *page) +{ + GtkAssistantPrivate *priv = assistant->priv; + GList *child = priv->pages; - while (pages) + while (child) { - GtkAssistantPage *page = pages->data; + GtkAssistantPage *page_info = child->data; + if (page_info->page == page) + return child; - gtk_widget_size_allocate (page->page, &child_allocation); - gtk_widget_size_allocate (page->title, &header_allocation); - pages = pages->next; + child = child->next; } + + return NULL; } static void @@ -1334,33 +1247,31 @@ gtk_assistant_map (GtkWidget *widget) GtkAssistantPrivate *priv = assistant->priv; GList *page_node; GtkAssistantPage *page; - - gtk_widget_set_mapped (widget, TRUE); - - gtk_widget_map (priv->header_image); - gtk_widget_map (priv->action_area); - - if (gtk_widget_get_visible (priv->sidebar_image) && - !gtk_widget_get_mapped (priv->sidebar_image)) - gtk_widget_map (priv->sidebar_image); + gint page_num; /* if there's no default page, pick the first one */ page = NULL; + page_num = 0; if (!priv->current_page) { page_node = priv->pages; while (page_node && !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page)) - page_node = page_node->next; + { + page_node = page_node->next; + page_num++; + } if (page_node) page = page_node->data; } - if (page && - gtk_widget_get_visible (page->page) && - !gtk_widget_get_mapped (page->page)) - set_current_page (assistant, page); + if (page && gtk_widget_get_visible (page->page)) + set_current_page (assistant, page_num); + + update_buttons_state (assistant); + update_actions_size (assistant); + update_title_state (assistant); GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget); } @@ -1371,23 +1282,6 @@ gtk_assistant_unmap (GtkWidget *widget) GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; - gtk_widget_set_mapped (widget, FALSE); - - gtk_widget_unmap (priv->header_image); - gtk_widget_unmap (priv->action_area); - - if (gtk_widget_is_drawable (priv->sidebar_image)) - gtk_widget_unmap (priv->sidebar_image); - - if (priv->current_page && - gtk_widget_is_drawable (priv->current_page->page)) - { - gtk_widget_set_child_visible (priv->current_page->page, FALSE); - gtk_widget_set_child_visible (priv->current_page->title, FALSE); - gtk_widget_unmap (priv->current_page->title); - gtk_widget_unmap (priv->current_page->page); - } - g_slist_free (priv->visited_pages); priv->visited_pages = NULL; priv->current_page = NULL; @@ -1411,147 +1305,6 @@ gtk_assistant_delete_event (GtkWidget *widget, return TRUE; } -static void -assistant_paint_colored_box (GtkWidget *widget, - cairo_t *cr) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkAllocation allocation, action_area_allocation, header_image_allocation; - GtkStyleContext *context; - GtkStateFlags state; - GdkRGBA color; - gint border_width, header_padding, content_padding; - gint content_x, content_width; - gboolean rtl; - - rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - - context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - - gtk_widget_get_allocation (widget, &allocation); - gtk_widget_get_allocation (priv->action_area, &action_area_allocation); - gtk_widget_get_allocation (priv->header_image, &header_image_allocation); - - /* colored box */ - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); - - gtk_style_context_get_background_color (context, state, &color); - gdk_cairo_set_source_rgba (cr, &color); - - cairo_rectangle (cr, - border_width, - border_width, - allocation.width - 2 * border_width, - allocation.height - action_area_allocation.height - 2 * border_width - ACTION_AREA_SPACING); - cairo_fill (cr); - - /* content box */ - content_x = content_padding + border_width; - content_width = allocation.width - 2 * content_padding - 2 * border_width; - - if (gtk_widget_get_visible (priv->sidebar_image)) - { - GtkAllocation sidebar_image_allocation; - - gtk_widget_get_allocation (priv->sidebar_image, &sidebar_image_allocation); - - if (!rtl) - content_x += sidebar_image_allocation.width; - content_width -= sidebar_image_allocation.width; - } - - gtk_style_context_restore (context); - - gtk_style_context_get_background_color (context, state, &color); - gdk_cairo_set_source_rgba (cr, &color); - - cairo_rectangle (cr, - content_x, - header_image_allocation.height + content_padding + 2 * header_padding + border_width, - content_width, - allocation.height - 2 * border_width - action_area_allocation.height - - header_image_allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING); - cairo_fill (cr); -} - -static gboolean -gtk_assistant_draw (GtkWidget *widget, - cairo_t *cr) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkContainer *container = GTK_CONTAINER (widget); - - if (GTK_WIDGET_CLASS (gtk_assistant_parent_class)->draw) - GTK_WIDGET_CLASS (gtk_assistant_parent_class)->draw (widget, cr); - - assistant_paint_colored_box (widget, cr); - - gtk_container_propagate_draw (container, priv->header_image, cr); - gtk_container_propagate_draw (container, priv->sidebar_image, cr); - gtk_container_propagate_draw (container, priv->action_area, cr); - - if (priv->current_page) - { - gtk_container_propagate_draw (container, priv->current_page->page, cr); - gtk_container_propagate_draw (container, priv->current_page->title, cr); - } - - return FALSE; -} - -static gboolean -gtk_assistant_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - GtkAssistantPrivate *priv; - GtkContainer *container; - - container = GTK_CONTAINER (widget); - priv = GTK_ASSISTANT (widget)->priv; - - /* we only have to care about 2 widgets, action area and the current page */ - if (gtk_container_get_focus_child (container) == priv->action_area) - { - if (!gtk_widget_child_focus (priv->action_area, direction) && - (priv->current_page == NULL || - !gtk_widget_child_focus (priv->current_page->page, direction))) - { - /* if we're leaving the action area and the current page has no - * focusable widget, clear focus and go back to the action area - */ - gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL); - gtk_widget_child_focus (priv->action_area, direction); - } - } - else - { - if ((priv->current_page == NULL || - !gtk_widget_child_focus (priv->current_page->page, direction)) && - !gtk_widget_child_focus (priv->action_area, direction)) - { - /* if we're leaving the current page and there isn't nothing - * focusable in the action area, try to clear focus and go back - * to the page - */ - gtk_window_set_focus (GTK_WINDOW (widget), NULL); - if (priv->current_page != NULL) - gtk_widget_child_focus (priv->current_page->page, direction); - } - } - - return TRUE; -} - static void gtk_assistant_add (GtkContainer *container, GtkWidget *page) @@ -1564,46 +1317,12 @@ gtk_assistant_remove (GtkContainer *container, GtkWidget *page) { GtkAssistant *assistant = (GtkAssistant*) container; - GList *element; - - element = find_page (assistant, page); - - if (element) - { - remove_page (assistant, element); - gtk_widget_queue_resize ((GtkWidget *) container); - } -} - -static void -gtk_assistant_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) -{ - GtkAssistant *assistant = (GtkAssistant*) container; - GtkAssistantPrivate *priv = assistant->priv; - GList *pages; - - if (include_internals) - { - (*callback) (priv->header_image, callback_data); - (*callback) (priv->sidebar_image, callback_data); - (*callback) (priv->action_area, callback_data); - } - pages = priv->pages; - - while (pages) + /* Forward this removal to the content notebook */ + if (gtk_widget_get_parent (page) == assistant->priv->content) { - GtkAssistantPage *page = (GtkAssistantPage *) pages->data; - - (*callback) (page->page, callback_data); - - if (include_internals) - (*callback) (page->title, callback_data); - - pages = pages->next; + container = (GtkContainer *) assistant->priv->content; + gtk_container_remove (container, page); } } @@ -1630,11 +1349,11 @@ gtk_assistant_new (void) * gtk_assistant_get_current_page: * @assistant: a #GtkAssistant * - * Returns the page number of the current page + * Returns the page number of the current page. * * Return value: The index (starting from 0) of the current - * page in the @assistant, if the @assistant has no pages, - * -1 will be returned + * page in the @assistant, or -1 if the @assistant has no pages, + * or no current page. * * Since: 2.10 */ @@ -1683,7 +1402,10 @@ gtk_assistant_set_current_page (GtkAssistant *assistant, if (page_num >= 0) page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num); else - page = (GtkAssistantPage *) g_list_last (priv->pages)->data; + { + page = (GtkAssistantPage *) g_list_last (priv->pages)->data; + page_num = g_list_length (priv->pages); + } g_return_if_fail (page != NULL); @@ -1698,7 +1420,7 @@ gtk_assistant_set_current_page (GtkAssistant *assistant, priv->visited_pages = g_slist_prepend (priv->visited_pages, priv->current_page); - set_current_page (assistant, page); + set_current_page (assistant, page_num); } /** @@ -1765,7 +1487,7 @@ gtk_assistant_previous_page (GtkAssistant *assistant) while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS || !gtk_widget_get_visible (page_info->page)); - set_current_page (assistant, page_info); + set_current_page (assistant, g_list_index (priv->pages, page_info)); } /** @@ -1891,8 +1613,8 @@ gtk_assistant_insert_page (GtkAssistant *assistant, { GtkAssistantPrivate *priv; GtkAssistantPage *page_info; - GtkStyleContext *context; gint n_pages; + GtkStyleContext *context; g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); @@ -1903,18 +1625,31 @@ gtk_assistant_insert_page (GtkAssistant *assistant, page_info = g_slice_new0 (GtkAssistantPage); page_info->page = page; - page_info->title = gtk_label_new (NULL); - - g_signal_connect (G_OBJECT (page), "notify::visible", - G_CALLBACK (on_page_notify_visibility), assistant); + page_info->regular_title = gtk_label_new (NULL); + gtk_widget_set_no_show_all (page_info->regular_title, TRUE); + page_info->current_title = gtk_label_new (NULL); + gtk_widget_set_no_show_all (page_info->current_title, TRUE); + + /* Note: we need to use misc alignment here as long as GtkLabel + * pays attention to it. GtkWiget::halign is ineffective, since + * all the labels are getting the same size anyway, due to the + * size group. + */ + gtk_misc_set_alignment (GTK_MISC (page_info->regular_title), 0, 0.5); + gtk_widget_show (page_info->regular_title); - gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5); - set_title_font (GTK_WIDGET (assistant), page_info->title); - gtk_widget_show (page_info->title); + gtk_misc_set_alignment (GTK_MISC (page_info->current_title), 0, 0.5); + gtk_widget_hide (page_info->current_title); - context = gtk_widget_get_style_context (page_info->title); + context = gtk_widget_get_style_context (page_info->current_title); gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); + gtk_size_group_add_widget (priv->title_size_group, page_info->regular_title); + gtk_size_group_add_widget (priv->title_size_group, page_info->current_title); + + g_signal_connect (G_OBJECT (page), "notify::visible", + G_CALLBACK (on_page_notify_visibility), assistant); + n_pages = g_list_length (priv->pages); if (position < 0 || position > n_pages) @@ -1922,22 +1657,46 @@ gtk_assistant_insert_page (GtkAssistant *assistant, priv->pages = g_list_insert (priv->pages, page_info, position); - gtk_widget_set_child_visible (page_info->page, FALSE); - gtk_widget_set_child_visible (page_info->title, FALSE); - gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant)); - gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant)); + gtk_box_pack_start (GTK_BOX (priv->sidebar), page_info->regular_title, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (priv->sidebar), page_info->current_title, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (priv->sidebar), page_info->regular_title, 2 * position); + gtk_box_reorder_child (GTK_BOX (priv->sidebar), page_info->current_title, 2 * position + 1); - if (gtk_widget_get_realized (GTK_WIDGET (assistant))) + gtk_notebook_insert_page (GTK_NOTEBOOK (priv->content), page, NULL, position); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) { - gtk_widget_realize (page_info->page); - gtk_widget_realize (page_info->title); + update_buttons_state (assistant); + update_actions_size (assistant); } - gtk_widget_queue_resize (GTK_WIDGET (assistant)); - return position; } +/** + * gtk_assistant_remove_page: + * @assistant: a #GtkAssistant + * @page_num: the index of a page in the @assistant, + * or -1 to remove the last page + * + * Removes the @page_num's page from @assistant. + * + * Since: 3.2 + */ +void +gtk_assistant_remove_page (GtkAssistant *assistant, + gint page_num) +{ + GtkWidget *page; + + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + page = gtk_assistant_get_nth_page (assistant, page_num); + + if (page) + gtk_container_remove (GTK_CONTAINER (assistant), page); +} + /** * gtk_assistant_set_forward_page_func: * @assistant: a #GtkAssistant @@ -1988,7 +1747,8 @@ gtk_assistant_set_forward_page_func (GtkAssistant *assistant, /* Page flow has possibly changed, so the * buttons state might need to change too */ - set_assistant_buttons_state (assistant); + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_buttons_state (assistant); } /** @@ -2012,7 +1772,12 @@ gtk_assistant_add_action_widget (GtkAssistant *assistant, priv = assistant->priv; if (GTK_IS_BUTTON (child)) - gtk_size_group_add_widget (priv->size_group, child); + { + gtk_size_group_add_widget (priv->button_size_group, child); + priv->extra_buttons += 1; + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_actions_size (assistant); + } gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0); } @@ -2038,7 +1803,12 @@ gtk_assistant_remove_action_widget (GtkAssistant *assistant, priv = assistant->priv; if (GTK_IS_BUTTON (child)) - gtk_size_group_remove_widget (priv->size_group, child); + { + gtk_size_group_remove_widget (priv->button_size_group, child); + priv->extra_buttons -= 1; + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_actions_size (assistant); + } gtk_container_remove (GTK_CONTAINER (priv->action_area), child); } @@ -2073,9 +1843,14 @@ gtk_assistant_set_page_title (GtkAssistant *assistant, page_info = (GtkAssistantPage*) child->data; - gtk_label_set_text ((GtkLabel*) page_info->title, title); + g_free (page_info->title); + page_info->title = g_strdup (title); + + gtk_label_set_text ((GtkLabel*) page_info->regular_title, title); + gtk_label_set_text ((GtkLabel*) page_info->current_title, title); + gtk_widget_queue_resize (GTK_WIDGET (assistant)); - gtk_widget_child_notify (page, "title"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "title"); } /** @@ -2089,7 +1864,7 @@ gtk_assistant_set_page_title (GtkAssistant *assistant, * * Since: 2.10 */ -G_CONST_RETURN gchar* +const gchar* gtk_assistant_get_page_title (GtkAssistant *assistant, GtkWidget *page) { @@ -2105,7 +1880,7 @@ gtk_assistant_get_page_title (GtkAssistant *assistant, page_info = (GtkAssistantPage*) child->data; - return gtk_label_get_text ((GtkLabel*) page_info->title); + return page_info->title; } /** @@ -2151,9 +1926,9 @@ gtk_assistant_set_page_type (GtkAssistant *assistant, /* Always set buttons state, a change in a future page * might change current page buttons */ - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); - gtk_widget_child_notify (page, "page-type"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "page-type"); } } @@ -2195,25 +1970,31 @@ gtk_assistant_get_page_type (GtkAssistant *assistant, * * Sets a header image for @page. * - * This image is displayed in the header area of the assistant - * when @page is the current page. - * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. */ void gtk_assistant_set_page_header_image (GtkAssistant *assistant, GtkWidget *page, GdkPixbuf *pixbuf) { - GtkAssistantPrivate *priv; - GtkAssistantPage *page_info; - GList *child; - g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); - priv = assistant->priv; + gtk_assistant_do_set_page_header_image (assistant, page, pixbuf); +} + +static void +gtk_assistant_do_set_page_header_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf) +{ + GtkAssistantPage *page_info; + GList *child; + child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2231,10 +2012,7 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, if (pixbuf) page_info->header_image = g_object_ref (pixbuf); - if (page_info == priv->current_page) - set_assistant_header_image (assistant); - - gtk_widget_child_notify (page, "header-image"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "header-image"); } } @@ -2249,6 +2027,9 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, * or %NULL if there's no header image for the page * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. */ GdkPixbuf* gtk_assistant_get_page_header_image (GtkAssistant *assistant, @@ -2273,29 +2054,38 @@ gtk_assistant_get_page_header_image (GtkAssistant *assistant, * gtk_assistant_set_page_side_image: * @assistant: a #GtkAssistant * @page: a page of @assistant - * @pixbuf: (allow-none): the new header image @page + * @pixbuf: (allow-none): the new side image @page * - * Sets a header image for @page. + * Sets a side image for @page. * - * This image is displayed in the side area of the assistant + * This image used to be displayed in the side area of the assistant * when @page is the current page. * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, sidebar images are not + * shown anymore. */ void gtk_assistant_set_page_side_image (GtkAssistant *assistant, GtkWidget *page, GdkPixbuf *pixbuf) { - GtkAssistantPrivate *priv; - GtkAssistantPage *page_info; - GList *child; - g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); - priv = assistant->priv; + gtk_assistant_do_set_page_side_image (assistant, page, pixbuf); +} + +static void +gtk_assistant_do_set_page_side_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf) +{ + GtkAssistantPage *page_info; + GList *child; + child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2313,10 +2103,7 @@ gtk_assistant_set_page_side_image (GtkAssistant *assistant, if (pixbuf) page_info->sidebar_image = g_object_ref (pixbuf); - if (page_info == priv->current_page) - set_assistant_sidebar_image (assistant); - - gtk_widget_child_notify (page, "sidebar-image"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "sidebar-image"); } } @@ -2325,12 +2112,15 @@ gtk_assistant_set_page_side_image (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * - * Gets the header image for @page. + * Gets the side image for @page. * * Return value: (transfer none): the side image for @page, * or %NULL if there's no side image for the page * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, sidebar images are not + * shown anymore. */ GdkPixbuf* gtk_assistant_get_page_side_image (GtkAssistant *assistant, @@ -2389,9 +2179,9 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant, /* Always set buttons state, a change in a future page * might change current page buttons */ - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); - gtk_widget_child_notify (page, "complete"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "complete"); } } @@ -2446,7 +2236,7 @@ gtk_assistant_update_buttons_state (GtkAssistant *assistant) { g_return_if_fail (GTK_IS_ASSISTANT (assistant)); - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); } /** @@ -2475,32 +2265,16 @@ gtk_assistant_commit (GtkAssistant *assistant) assistant->priv->committed = TRUE; - set_assistant_buttons_state (assistant); -} - -static AtkObject * -gtk_assistant_get_accessible (GtkWidget *widget) -{ - static gboolean first_time = TRUE; - - if (first_time) - { - _gtk_accessible_set_factory_type (GTK_TYPE_ASSISTANT, - gtk_assistant_accessible_factory_get_type ()); - - first_time = FALSE; - } - - return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget); + update_buttons_state (assistant); } /* accessible implementation */ /* dummy typedefs */ -typedef struct _GtkAssistantAccessible GtkAssistantAccessible; -typedef struct _GtkAssistantAccessibleClass GtkAssistantAccessibleClass; +typedef GtkWindowAccessible GtkAssistantAccessible; +typedef GtkWindowAccessibleClass GtkAssistantAccessibleClass; -ATK_DEFINE_TYPE (GtkAssistantAccessible, _gtk_assistant_accessible, GTK_TYPE_ASSISTANT); +G_DEFINE_TYPE (GtkAssistantAccessible, _gtk_assistant_accessible, GTK_TYPE_WINDOW_ACCESSIBLE); static gint gtk_assistant_accessible_get_n_children (AtkObject *accessible) @@ -2572,43 +2346,6 @@ _gtk_assistant_accessible_init (GtkAssistantAccessible *self) { } -/* factory */ -typedef AtkObjectFactory GtkAssistantAccessibleFactory; -typedef AtkObjectFactoryClass GtkAssistantAccessibleFactoryClass; - -G_DEFINE_TYPE (GtkAssistantAccessibleFactory, - gtk_assistant_accessible_factory, - ATK_TYPE_OBJECT_FACTORY); - -static GType -gtk_assistant_accessible_factory_get_accessible_type (void) -{ - return _gtk_assistant_accessible_get_type (); -} - -static AtkObject* -gtk_assistant_accessible_factory_create_accessible (GObject *obj) -{ - AtkObject *accessible; - - accessible = g_object_new (_gtk_assistant_accessible_get_type (), NULL); - atk_object_initialize (accessible, obj); - - return accessible; -} - -static void -gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class) -{ - class->create_accessible = gtk_assistant_accessible_factory_create_accessible; - class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type; -} - -static void -gtk_assistant_accessible_factory_init (AtkObjectFactory *factory) -{ -} - /* buildable implementation */ static GtkBuildableIface *parent_buildable_iface;