X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkassistant.c;h=3ba9f227be5abc7934d793a7877a92be13638a2d;hb=HEAD;hp=ba3164296adc79f3152361cf773524b7a46cd510;hpb=c70f3e26d22f8e6149930183fcd4398df7747444;p=~andy%2Fgtk diff --git a/gtk/gtkassistant.c b/gtk/gtkassistant.c index ba3164296..3ba9f227b 100644 --- a/gtk/gtkassistant.c +++ b/gtk/gtkassistant.c @@ -1,4 +1,4 @@ -/* +/* * GTK - The GIMP Toolkit * Copyright (C) 1999 Red Hat, Inc. * Copyright (C) 2002 Anders Carlsson @@ -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,19 +60,21 @@ #include "gtkassistant.h" -#include "gtkaccessible.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" - +#include "gtktypebuiltins.h" #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,67 +106,47 @@ 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_set (GtkWidget *widget, - GtkStyle *old_style); -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); + GdkEventAny *event); static void gtk_assistant_add (GtkContainer *container, - GtkWidget *page); + 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); + GtkWidget *page); static void gtk_assistant_set_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - const GValue *value, - GParamSpec *pspec); + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec); static void gtk_assistant_get_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget); + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec); static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface); static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable, @@ -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_set = gtk_assistant_style_set; - 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; @@ -250,57 +235,61 @@ gtk_assistant_class_init (GtkAssistantClass *class) */ signals[CANCEL] = g_signal_new (I_("cancel"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, cancel), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, cancel), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** * GtkAssistant::prepare: * @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 */ signals[PREPARE] = g_signal_new (I_("prepare"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, prepare), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, prepare), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_WIDGET); /** * 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 */ signals[APPLY] = g_signal_new (I_("apply"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, apply), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, apply), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * GtkAssistant::close: @@ -314,29 +303,29 @@ gtk_assistant_class_init (GtkAssistantClass *class) */ signals[CLOSE] = g_signal_new (I_("close"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, close), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, close), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("header-padding", - P_("Header Padding"), - P_("Number of pixels around the header."), - 0, - G_MAXINT, - 6, - GTK_PARAM_READABLE)); + g_param_spec_int ("header-padding", + P_("Header Padding"), + P_("Number of pixels around the header."), + 0, + G_MAXINT, + 6, + GTK_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("content-padding", - P_("Content Padding"), - P_("Number of pixels around the content pages."), - 0, - G_MAXINT, - 1, - GTK_PARAM_READABLE)); + g_param_spec_int ("content-padding", + P_("Content Padding"), + P_("Number of pixels around the content pages."), + 0, + G_MAXINT, + 1, + GTK_PARAM_READABLE)); /** * GtkAssistant:page-type: @@ -346,80 +335,80 @@ gtk_assistant_class_init (GtkAssistantClass *class) * Since: 2.10 */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_TYPE, - g_param_spec_enum ("page-type", - P_("Page type"), - P_("The type of the assistant page"), - GTK_TYPE_ASSISTANT_PAGE_TYPE, - GTK_ASSISTANT_PAGE_CONTENT, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_TYPE, + g_param_spec_enum ("page-type", + P_("Page type"), + P_("The type of the assistant page"), + GTK_TYPE_ASSISTANT_PAGE_TYPE, + GTK_ASSISTANT_PAGE_CONTENT, + GTK_PARAM_READWRITE)); /** * 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 */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_TITLE, - g_param_spec_string ("title", - P_("Page title"), - P_("The title of the assistant page"), - NULL, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_TITLE, + g_param_spec_string ("title", + P_("Page title"), + P_("The title of the assistant page"), + NULL, + GTK_PARAM_READWRITE)); /** * 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, - g_param_spec_object ("header-image", - P_("Header image"), - P_("Header image for the assistant page"), - GDK_TYPE_PIXBUF, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_HEADER_IMAGE, + g_param_spec_object ("header-image", + P_("Header image"), + P_("Header image for the assistant page"), + GDK_TYPE_PIXBUF, + 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, - g_param_spec_object ("sidebar-image", - P_("Sidebar image"), - P_("Sidebar image for the assistant page"), - GDK_TYPE_PIXBUF, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_SIDEBAR_IMAGE, + g_param_spec_object ("sidebar-image", + P_("Sidebar image"), + 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 - **/ + */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_COMPLETE, - g_param_spec_boolean ("complete", - P_("Page complete"), - P_("Whether all required fields on the page have been filled out"), - FALSE, - G_PARAM_READWRITE)); + CHILD_PROP_PAGE_COMPLETE, + g_param_spec_boolean ("complete", + P_("Page complete"), + P_("Whether all required fields on the page have been filled out"), + FALSE, + G_PARAM_READWRITE)); g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate)); } @@ -448,28 +437,34 @@ default_forward_function (gint current_page, gpointer data) current_page++; if (page_node) - page_info = (GtkAssistantPage *) page_node->data; + page_info = (GtkAssistantPage *) page_node->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 && - (count == 0 || page_info->complete) && - count < n_pages) + page_info->type == GTK_ASSISTANT_PAGE_CONTENT && + (count == 0 || page_info->complete) && + count < n_pages) { page_num = (priv->forward_function) (page_num, priv->forward_function_data); page_info = g_list_nth_data (priv->pages, page_num); @@ -477,69 +472,93 @@ 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; - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image), - priv->current_page->sidebar_image); + n_pages = gtk_assistant_get_n_pages (assistant); + page_num = gtk_assistant_get_current_page (assistant); - if (priv->current_page->sidebar_image) - gtk_widget_show (priv->sidebar_image); + page_num = (priv->forward_function) (page_num, priv->forward_function_data); + + 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; if (!priv->current_page) return; - + switch (priv->current_page->type) { case GTK_ASSISTANT_PAGE_INTRO: @@ -615,46 +634,104 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_show (priv->cancel); /* this is quite general, we don't want to - * go back if it's the first page */ + * go back if it's the first page + */ if (!priv->visited_pages) 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_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_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]; @@ -669,7 +746,8 @@ set_current_page (GtkAssistant *assistant, button[5] = priv->last; for (i = 0; i < 6; i++) { - if (gtk_widget_get_visible (button[i]) && gtk_widget_get_sensitive (button[i])) + if (gtk_widget_get_visible (button[i]) && + gtk_widget_get_sensitive (button[i])) { gtk_widget_grab_focus (button[i]); break; @@ -692,12 +770,12 @@ compute_next_step (GtkAssistant *assistant) n_pages = gtk_assistant_get_n_pages (assistant); next_page = (priv->forward_function) (current_page, - priv->forward_function_data); + priv->forward_function_data); 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; } @@ -757,7 +835,7 @@ on_assistant_last (GtkWidget *widget, GtkAssistantPrivate *priv = assistant->priv; while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT && - priv->current_page->complete) + priv->current_page->complete) compute_next_step (assistant); } @@ -772,58 +850,189 @@ alternative_button_order (GtkAssistant *assistant) settings = gtk_settings_get_for_screen (screen); g_object_get (settings, - "gtk-alternative-button-order", &result, - NULL); + "gtk-alternative-button-order", &result, + NULL); 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); + + /* 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); + + g_signal_connect (sidebar_frame, "draw", + G_CALLBACK (assistant_sidebar_draw_cb), assistant); - /* 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); + 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); - /* Action area */ - 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); + + 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)) { @@ -844,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); @@ -852,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; @@ -861,47 +1071,47 @@ gtk_assistant_init (GtkAssistant *assistant) priv->forward_data_destroy = NULL; g_signal_connect (G_OBJECT (priv->close), "clicked", - G_CALLBACK (on_assistant_close), assistant); + G_CALLBACK (on_assistant_close), assistant); g_signal_connect (G_OBJECT (priv->apply), "clicked", - G_CALLBACK (on_assistant_apply), assistant); + G_CALLBACK (on_assistant_apply), assistant); g_signal_connect (G_OBJECT (priv->forward), "clicked", - G_CALLBACK (on_assistant_forward), assistant); + G_CALLBACK (on_assistant_forward), assistant); g_signal_connect (G_OBJECT (priv->back), "clicked", - G_CALLBACK (on_assistant_back), assistant); + G_CALLBACK (on_assistant_back), assistant); g_signal_connect (G_OBJECT (priv->cancel), "clicked", - G_CALLBACK (on_assistant_cancel), assistant); + G_CALLBACK (on_assistant_cancel), assistant); g_signal_connect (G_OBJECT (priv->last), "clicked", - G_CALLBACK (on_assistant_last), assistant); + G_CALLBACK (on_assistant_last), 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) { case CHILD_PROP_PAGE_TYPE: gtk_assistant_set_page_type (GTK_ASSISTANT (container), child, - g_value_get_enum (value)); + g_value_get_enum (value)); break; case CHILD_PROP_PAGE_TITLE: gtk_assistant_set_page_title (GTK_ASSISTANT (container), child, - g_value_get_string (value)); + 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, - g_value_get_boolean (value)); + g_value_get_boolean (value)); break; default: GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); @@ -911,32 +1121,34 @@ gtk_assistant_set_child_property (GtkContainer *container, static void gtk_assistant_get_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - GValue *value, - GParamSpec *pspec) + GtkWidget *child, + guint property_id, + 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); @@ -945,384 +1157,87 @@ gtk_assistant_get_child_property (GtkContainer *container, } 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) +gtk_assistant_destroy (GtkWidget *widget) { + GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info; - GList *page_node; - page_info = element->data; + /* We set current to NULL so that the remove code doesn't try + * to do anything funny + */ + priv->current_page = NULL; - /* If this is the current page, we need to switch away. */ - if (page_info == priv->current_page) + if (priv->content) { - 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); + GtkNotebook *notebook; + GtkWidget *page; - if (page_info->header_image) - g_object_unref (page_info->header_image); + /* 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); - if (page_info->sidebar_image) - g_object_unref (page_info->sidebar_image); + /* Our GtkAssistantPage list should be empty now. */ + g_warn_if_fail (priv->pages == NULL); - 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; + priv->content = NULL; } - if (priv->sidebar_image) - { - gtk_widget_destroy (priv->sidebar_image); - priv->sidebar_image = NULL; - } + if (priv->sidebar) + priv->sidebar = NULL; if (priv->action_area) + priv->action_area = NULL; + + if (priv->button_size_group) { - gtk_widget_destroy (priv->action_area); - priv->action_area = NULL; + g_object_unref (priv->button_size_group); + priv->button_size_group = NULL; } - if (priv->size_group) + if (priv->title_size_group) { - g_object_unref (priv->size_group); - priv->size_group = NULL; + g_object_unref (priv->title_size_group); + priv->title_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_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_colors (GtkWidget *assistant, - GtkWidget *title_label) -{ - GtkStyle *style; - - gtk_widget_ensure_style (assistant); - style = gtk_widget_get_style (assistant); - - /* change colors schema, for making the header text visible */ - gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]); - gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]); -} - -static void -set_title_font (GtkWidget *assistant, - GtkWidget *title_label) -{ - PangoFontDescription *desc; - gint size; - - desc = pango_font_description_new (); - size = pango_font_description_get_size (gtk_widget_get_style (assistant)->font_desc); - - pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD); - pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE); - - gtk_widget_modify_font (title_label, desc); - pango_font_description_free (desc); -} - -static void -gtk_assistant_style_set (GtkWidget *widget, - GtkStyle *old_style) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GList *list; - - list = priv->pages; - - while (list) - { - GtkAssistantPage *page = list->data; - - set_title_colors (widget, page->title); - 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_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) -{ - 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; - - gtk_widget_size_allocate (priv->header_image, &header_allocation); - - /* Action area */ - gtk_widget_get_preferred_size (priv->action_area, - &action_requisition, NULL); - - 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; - - gtk_widget_size_allocate (priv->action_area, &child_allocation); - - gtk_widget_get_allocation (priv->header_image, &header_image_allocation); - gtk_widget_get_allocation (priv->action_area, &action_area_allocation); - - /* Sidebar */ - gtk_widget_get_preferred_size (priv->sidebar_image, - &sidebar_requisition, NULL); - - if (rtl) - child_allocation.x = allocation->width - border_width - sidebar_requisition.width; - else - child_allocation.x = border_width; - - 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; - - gtk_widget_size_allocate (priv->sidebar_image, &child_allocation); - - /* 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_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 @@ -1332,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; + 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); } @@ -1369,18 +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_unmap (priv->current_page->page); - g_slist_free (priv->visited_pages); priv->visited_pages = NULL; priv->current_page = NULL; @@ -1390,7 +1291,7 @@ gtk_assistant_unmap (GtkWidget *widget) static gboolean gtk_assistant_delete_event (GtkWidget *widget, - GdkEventAny *event) + GdkEventAny *event) { GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; @@ -1404,196 +1305,36 @@ 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; - GtkStyle *style; - 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); - - style = gtk_widget_get_style (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 */ - gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_SELECTED]); - 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; - } - - gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]); - - 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 hasn't - any 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) + GtkWidget *page) { gtk_assistant_append_page (GTK_ASSISTANT (container), page); } static void 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) + GtkWidget *page) { 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); } } /** * gtk_assistant_new: - * + * * Creates a new #GtkAssistant. * * Return value: a newly created #GtkAssistant * * Since: 2.10 - **/ + */ GtkWidget* gtk_assistant_new (void) { @@ -1608,13 +1349,14 @@ 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 + * Return value: The index (starting from 0) of the current + * page in the @assistant, or -1 if the @assistant has no pages, + * or no current page. * * Since: 2.10 - **/ + */ gint gtk_assistant_get_current_page (GtkAssistant *assistant) { @@ -1634,19 +1376,21 @@ gtk_assistant_get_current_page (GtkAssistant *assistant) * gtk_assistant_set_current_page: * @assistant: a #GtkAssistant * @page_num: index of the page to switch to, starting from 0. - * If negative, the last page will be used. If greater - * than the number of pages in the @assistant, nothing - * will be done. + * If negative, the last page will be used. If greater + * than the number of pages in the @assistant, nothing + * will be done. * - * Switches the page to @page_num. Note that this will only be necessary - * in custom buttons, as the @assistant flow can be set with + * Switches the page to @page_num. + * + * Note that this will only be necessary in custom buttons, + * as the @assistant flow can be set with * gtk_assistant_set_forward_page_func(). * * Since: 2.10 - **/ + */ void gtk_assistant_set_current_page (GtkAssistant *assistant, - gint page_num) + gint page_num) { GtkAssistantPrivate *priv; GtkAssistantPage *page; @@ -1658,64 +1402,66 @@ 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); if (priv->current_page == page) return; - /* only add the page to the visited list if the - * assistant is mapped, if not, just use it as an - * initial page setting, for the cases where the - * initial page is != to 0 + /* only add the page to the visited list if the assistant is mapped, + * if not, just use it as an initial page setting, for the cases where + * the initial page is != to 0 */ if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) priv->visited_pages = g_slist_prepend (priv->visited_pages, - priv->current_page); + priv->current_page); - set_current_page (assistant, page); + set_current_page (assistant, page_num); } /** * gtk_assistant_next_page: * @assistant: a #GtkAssistant * - * Navigate to the next page. It is a programming - * error to call this function if there is no next page. + * Navigate to the next page. + * + * It is a programming error to call this function when + * there is no next page. * * This function is for use when creating pages of the - * #GTK_ASSISTANT_PAGE_CUSTOM type. + * #GTK_ASSISTANT_PAGE_CUSTOM type. * * Since: 3.0 - **/ + */ void gtk_assistant_next_page (GtkAssistant *assistant) { - GtkAssistantPrivate *priv; - g_return_if_fail (GTK_IS_ASSISTANT (assistant)); - priv = assistant->priv; - if (!compute_next_step (assistant)) - g_critical ("Page flow is broken, you may want to end it with a page of " - "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY"); + g_critical ("Page flow is broken.\n" + "You may want to end it with a page of type\n" + "GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY"); } /** * gtk_assistant_previous_page: * @assistant: a #GtkAssistant * - * Navigate to the previous visited page. It is a programming - * error to call this function if no previous page is - * available. + * Navigate to the previous visited page. + * + * It is a programming error to call this function when + * no previous page is available. * * This function is for use when creating pages of the - * #GTK_ASSISTANT_PAGE_CUSTOM type. + * #GTK_ASSISTANT_PAGE_CUSTOM type. * * Since: 3.0 - **/ + */ void gtk_assistant_previous_page (GtkAssistant *assistant) { @@ -1739,9 +1485,9 @@ gtk_assistant_previous_page (GtkAssistant *assistant) g_slist_free_1 (page_node); } while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS || - !gtk_widget_get_visible (page_info->page)); + !gtk_widget_get_visible (page_info->page)); - set_current_page (assistant, page_info); + set_current_page (assistant, g_list_index (priv->pages, page_info)); } /** @@ -1750,10 +1496,10 @@ gtk_assistant_previous_page (GtkAssistant *assistant) * * Returns the number of pages in the @assistant * - * Return value: The number of pages in the @assistant. + * Return value: the number of pages in the @assistant * * Since: 2.10 - **/ + */ gint gtk_assistant_get_n_pages (GtkAssistant *assistant) { @@ -1769,18 +1515,19 @@ gtk_assistant_get_n_pages (GtkAssistant *assistant) /** * gtk_assistant_get_nth_page: * @assistant: a #GtkAssistant - * @page_num: The index of a page in the @assistant, or -1 to get the last page; + * @page_num: the index of a page in the @assistant, + * or -1 to get the last page * * Returns the child widget contained in page number @page_num. * - * Return value: (transfer none): The child widget, or %NULL - * if @page_num is out of bounds. + * Return value: (transfer none): the child widget, or %NULL + * if @page_num is out of bounds * * Since: 2.10 - **/ + */ GtkWidget* gtk_assistant_get_nth_page (GtkAssistant *assistant, - gint page_num) + gint page_num) { GtkAssistantPrivate *priv; GtkAssistantPage *page; @@ -1814,10 +1561,10 @@ gtk_assistant_get_nth_page (GtkAssistant *assistant, * Return value: the index (starting at 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_prepend_page (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); @@ -1835,10 +1582,10 @@ gtk_assistant_prepend_page (GtkAssistant *assistant, * Return value: the index (starting at 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_append_page (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); @@ -1851,22 +1598,23 @@ gtk_assistant_append_page (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a #GtkWidget * @position: the index (starting at 0) at which to insert the page, - * or -1 to append the page to the @assistant + * or -1 to append the page to the @assistant * * Inserts a page in the @assistant at a given position. * * Return value: the index (starting from 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_insert_page (GtkAssistant *assistant, - GtkWidget *page, - gint position) + GtkWidget *page, + gint position) { GtkAssistantPrivate *priv; GtkAssistantPage *page_info; 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); @@ -1877,15 +1625,30 @@ gtk_assistant_insert_page (GtkAssistant *assistant, page_info = g_slice_new0 (GtkAssistantPage); page_info->page = page; - page_info->title = gtk_label_new (NULL); + 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); - g_signal_connect (G_OBJECT (page), "notify::visible", - G_CALLBACK (on_page_notify_visibility), assistant); + 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->current_title); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); - gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5); - set_title_colors (GTK_WIDGET (assistant), page_info->title); - set_title_font (GTK_WIDGET (assistant), page_info->title); - gtk_widget_show (page_info->title); + 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); @@ -1894,41 +1657,69 @@ 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_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 - * @page_func: (allow-none): the #GtkAssistantPageFunc, or %NULL to use the default one + * @page_func: (allow-none): the #GtkAssistantPageFunc, or %NULL + * to use the default one * @data: user data for @page_func * @destroy: destroy notifier for @data * - * Sets the page forwarding function to be @page_func, this function will - * be used to determine what will be the next page when the user presses - * the forward button. Setting @page_func to %NULL will make the assistant - * to use the default forward function, which just goes to the next visible - * page. + * Sets the page forwarding function to be @page_func. + * + * This function will be used to determine what will be + * the next page when the user presses the forward button. + * Setting @page_func to %NULL will make the assistant to + * use the default forward function, which just goes to the + * next visible page. * * Since: 2.10 - **/ + */ void gtk_assistant_set_forward_page_func (GtkAssistant *assistant, - GtkAssistantPageFunc page_func, - gpointer data, - GDestroyNotify destroy) + GtkAssistantPageFunc page_func, + gpointer data, + GDestroyNotify destroy) { GtkAssistantPrivate *priv; @@ -1954,22 +1745,24 @@ 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); + * buttons state might need to change too + */ + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_buttons_state (assistant); } /** * gtk_assistant_add_action_widget: * @assistant: a #GtkAssistant * @child: a #GtkWidget - * + * * Adds a widget to the action area of a #GtkAssistant. * * Since: 2.10 - **/ + */ void gtk_assistant_add_action_widget (GtkAssistant *assistant, - GtkWidget *child) + GtkWidget *child) { GtkAssistantPrivate *priv; @@ -1979,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); } @@ -1992,10 +1790,10 @@ gtk_assistant_add_action_widget (GtkAssistant *assistant, * Removes a widget from the action area of a #GtkAssistant. * * Since: 2.10 - **/ + */ void gtk_assistant_remove_action_widget (GtkAssistant *assistant, - GtkWidget *child) + GtkWidget *child) { GtkAssistantPrivate *priv; @@ -2005,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); } @@ -2015,16 +1818,18 @@ gtk_assistant_remove_action_widget (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @title: the new title for @page - * - * Sets a title for @page. The title is displayed in the header - * area of the assistant when @page is the current page. + * + * Sets a title for @page. + * + * The title is displayed in the header area of the assistant + * when @page is the current page. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_title (GtkAssistant *assistant, - GtkWidget *page, - const gchar *title) + GtkWidget *page, + const gchar *title) { GtkAssistantPage *page_info; GList *child; @@ -2038,25 +1843,30 @@ 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"); } /** * gtk_assistant_get_page_title: * @assistant: a #GtkAssistant * @page: a page of @assistant - * - * Gets the title for @page. - * - * Return value: the title for @page. + * + * Gets the title for @page. + * + * Return value: the title for @page * * Since: 2.10 - **/ -G_CONST_RETURN gchar* + */ +const gchar* gtk_assistant_get_page_title (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2070,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; } /** @@ -2078,25 +1888,24 @@ gtk_assistant_get_page_title (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @type: the new type for @page - * - * Sets the page type for @page. The page type determines the page - * behavior in the @assistant. + * + * Sets the page type for @page. + * + * The page type determines the page behavior in the @assistant. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_type (GtkAssistant *assistant, - GtkWidget *page, - GtkAssistantPageType type) + GtkWidget *page, + GtkAssistantPageType type) { - GtkAssistantPrivate *priv; GtkAssistantPage *page_info; GList *child; g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); - priv = assistant->priv; child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2115,10 +1924,11 @@ 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); + * might change current page buttons + */ + update_buttons_state (assistant); - gtk_widget_child_notify (page, "page-type"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "page-type"); } } @@ -2129,13 +1939,13 @@ gtk_assistant_set_page_type (GtkAssistant *assistant, * * Gets the page type of @page. * - * Return value: the page type of @page. + * Return value: the page type of @page * * Since: 2.10 - **/ + */ GtkAssistantPageType gtk_assistant_get_page_type (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2158,25 +1968,33 @@ gtk_assistant_get_page_type (GtkAssistant *assistant, * @page: a page of @assistant * @pixbuf: (allow-none): the new header image @page * - * Sets a header image for @page. This image is displayed in the header - * area of the assistant when @page is the current page. + * Sets a header image for @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) + 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); @@ -2186,18 +2004,15 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, if (pixbuf != page_info->header_image) { if (page_info->header_image) - { - g_object_unref (page_info->header_image); - page_info->header_image = NULL; - } + { + g_object_unref (page_info->header_image); + page_info->header_image = NULL; + } if (pixbuf) - page_info->header_image = g_object_ref (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"); } } @@ -2208,14 +2023,17 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, * * Gets the header image for @page. * - * Return value: (transfer none): the header image for @page, or %NULL - * if there's no header image for the page. + * Return value: (transfer none): the header image for @page, + * 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, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2236,27 +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. This image is displayed in the side - * area of the assistant when @page is the current page. + * Sets a side image for @page. + * + * 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) + 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); @@ -2266,18 +2095,15 @@ gtk_assistant_set_page_side_image (GtkAssistant *assistant, if (pixbuf != page_info->sidebar_image) { if (page_info->sidebar_image) - { - g_object_unref (page_info->sidebar_image); - page_info->sidebar_image = NULL; - } + { + g_object_unref (page_info->sidebar_image); + page_info->sidebar_image = NULL; + } if (pixbuf) - page_info->sidebar_image = g_object_ref (pixbuf); - - if (page_info == priv->current_page) - set_assistant_sidebar_image (assistant); + page_info->sidebar_image = g_object_ref (pixbuf); - gtk_widget_child_notify (page, "sidebar-image"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "sidebar-image"); } } @@ -2286,16 +2112,19 @@ 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. + * 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, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2317,25 +2146,25 @@ gtk_assistant_get_page_side_image (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @complete: the completeness status of the page - * - * Sets whether @page contents are complete. This will make - * @assistant update the buttons state to be able to continue the task. + * + * Sets whether @page contents are complete. + * + * This will make @assistant update the buttons state + * to be able to continue the task. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_complete (GtkAssistant *assistant, - GtkWidget *page, - gboolean complete) + GtkWidget *page, + gboolean complete) { - GtkAssistantPrivate *priv; GtkAssistantPage *page_info; GList *child; g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); - priv = assistant->priv; child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2348,10 +2177,11 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant, page_info->complete_set = TRUE; /* Always set buttons state, a change in a future page - might change current page buttons */ - set_assistant_buttons_state (assistant); + * might change current page buttons + */ + update_buttons_state (assistant); - gtk_widget_child_notify (page, "complete"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "complete"); } } @@ -2359,16 +2189,16 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant, * gtk_assistant_get_page_complete: * @assistant: a #GtkAssistant * @page: a page of @assistant - * + * * Gets whether @page is complete. - * + * * Return value: %TRUE if @page is complete. * * Since: 2.10 - **/ + */ gboolean gtk_assistant_get_page_complete (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2388,10 +2218,10 @@ gtk_assistant_get_page_complete (GtkAssistant *assistant, /** * gtk_assistant_update_buttons_state: * @assistant: a #GtkAssistant - * + * * Forces @assistant to recompute the buttons state. - * - * GTK+ automatically takes care of this in most situations, + * + * GTK+ automatically takes care of this in most situations, * e.g. when the user goes to a different page, or when the * visibility or completeness of a page changes. * @@ -2400,13 +2230,13 @@ gtk_assistant_get_page_complete (GtkAssistant *assistant, * affects the future page flow of the assistant. * * Since: 2.10 - **/ + */ void gtk_assistant_update_buttons_state (GtkAssistant *assistant) { g_return_if_fail (GTK_IS_ASSISTANT (assistant)); - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); } /** @@ -2419,12 +2249,12 @@ gtk_assistant_update_buttons_state (GtkAssistant *assistant) * * Use this when the information provided up to the current * page is hereafter deemed permanent and cannot be modified - * or undone. For example, showing a progress page to track + * or undone. For example, showing a progress page to track * a long-running, unreversible operation after the user has * clicked apply on a confirmation page. * * Since: 2.22 - **/ + */ void gtk_assistant_commit (GtkAssistant *assistant) { @@ -2435,33 +2265,32 @@ gtk_assistant_commit (GtkAssistant *assistant) assistant->priv->committed = TRUE; - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); } +/* accessible implementation */ +/* dummy typedefs */ +typedef GtkWindowAccessible GtkAssistantAccessible; +typedef GtkWindowAccessibleClass GtkAssistantAccessibleClass; -/* accessible implementation */ +G_DEFINE_TYPE (GtkAssistantAccessible, _gtk_assistant_accessible, GTK_TYPE_WINDOW_ACCESSIBLE); static gint gtk_assistant_accessible_get_n_children (AtkObject *accessible) { - GtkAssistant *assistant; GtkWidget *widget; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); - - if (!widget) + if (widget == NULL) return 0; - assistant = GTK_ASSISTANT (widget); - - return g_list_length (assistant->priv->pages) + 1; + return g_list_length (GTK_ASSISTANT (widget)->priv->pages) + 1; } - static AtkObject * gtk_assistant_accessible_ref_child (AtkObject *accessible, - gint index) + gint index) { GtkAssistant *assistant; GtkAssistantPrivate *priv; @@ -2471,7 +2300,7 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, const gchar *title; widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); - if (!widget) + if (widget == NULL) return NULL; assistant = GTK_ASSISTANT (widget); @@ -2494,7 +2323,7 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, } else return NULL; - + obj = gtk_widget_get_accessible (child); if (title) @@ -2504,130 +2333,20 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, } static void -gtk_assistant_accessible_class_init (AtkObjectClass *class) -{ - class->get_n_children = gtk_assistant_accessible_get_n_children; - class->ref_child = gtk_assistant_accessible_ref_child; -} - -static GType -gtk_assistant_accessible_get_type (void) +_gtk_assistant_accessible_class_init (GtkAssistantAccessibleClass *klass) { - static GType type = 0; - - if (!type) - { - /* - * Figure out the size of the class and instance - * we are deriving from - */ - AtkObjectFactory *factory; - GType derived_type; - GTypeQuery query; - GType derived_atk_type; - - derived_type = g_type_parent (GTK_TYPE_ASSISTANT); - factory = atk_registry_get_factory (atk_get_default_registry (), - derived_type); - derived_atk_type = atk_object_factory_get_accessible_type (factory); - g_type_query (derived_atk_type, &query); - - type = g_type_register_static_simple (derived_atk_type, - I_("GtkAssistantAccessible"), - query.class_size, - (GClassInitFunc) gtk_assistant_accessible_class_init, - query.instance_size, - NULL, 0); - } - - return type; -} - -static AtkObject * -gtk_assistant_accessible_new (GObject *obj) -{ - AtkObject *accessible; + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); - g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL); - - accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL); - atk_object_initialize (accessible, obj); - - return accessible; -} - -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) -{ - return gtk_assistant_accessible_new (obj); + atk_class->get_n_children = gtk_assistant_accessible_get_n_children; + atk_class->ref_child = gtk_assistant_accessible_ref_child; } static void -gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class) +_gtk_assistant_accessible_init (GtkAssistantAccessible *self) { - class->create_accessible = gtk_assistant_accessible_factory_create_accessible; - class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type; -} - -static GType -gtk_assistant_accessible_factory_get_type (void) -{ - static GType type = 0; - - if (!type) - { - type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY, - I_("GtkAssistantAccessibleFactory"), - sizeof (AtkObjectFactoryClass), - (GClassInitFunc) gtk_assistant_accessible_factory_class_init, - sizeof (AtkObjectFactory), - NULL, 0); - } - - return type; -} - -static AtkObject * -gtk_assistant_get_accessible (GtkWidget *widget) -{ - static gboolean first_time = TRUE; - - if (first_time) - { - AtkObjectFactory *factory; - AtkRegistry *registry; - GType derived_type; - GType derived_atk_type; - - /* - * Figure out whether accessibility is enabled by looking at the - * type of the accessible object which would be created for - * the parent type of GtkAssistant. - */ - derived_type = g_type_parent (GTK_TYPE_ASSISTANT); - - registry = atk_get_default_registry (); - factory = atk_registry_get_factory (registry, - derived_type); - derived_atk_type = atk_object_factory_get_accessible_type (factory); - if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) - { - atk_registry_set_factory_type (registry, - GTK_TYPE_ASSISTANT, - gtk_assistant_accessible_factory_get_type ()); - } - first_time = FALSE; - } - - return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget); } +/* buildable implementation */ static GtkBuildableIface *parent_buildable_iface;