From 9e64b59c9d838b3d0a55b0eb95fc088ec26f1644 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 31 Oct 2012 14:14:04 +0100 Subject: Bug #422273 - Wrap searchbar widgets for smaller minimum width request --- shell/e-shell-searchbar.c | 234 ++++++++++++++++++++++++++++++++++++++++------ shell/e-shell-searchbar.h | 4 +- shell/e-shell-sidebar.c | 6 -- shell/e-shell-view.c | 30 ------ shell/e-shell-view.h | 1 - 5 files changed, 210 insertions(+), 65 deletions(-) (limited to 'shell') diff --git a/shell/e-shell-searchbar.c b/shell/e-shell-searchbar.c index 9d9ad5a0cb..b80b3e27cd 100644 --- a/shell/e-shell-searchbar.c +++ b/shell/e-shell-searchbar.c @@ -43,6 +43,9 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarPrivate)) +/* spacing between "groups" on the search bar */ +#define COLUMN_SPACING 24 + #define SEARCH_OPTION_ADVANCED (-1) /* Default "state key file" group: [Search Bar] */ @@ -65,6 +68,10 @@ struct _EShellSearchbarPrivate { GtkWidget *search_entry; GtkWidget *scope_combo_box; + /* Child widget containers (referenced) */ + GSList *child_containers; + guint resize_idle_id; + /* State Key File */ gchar *state_group; @@ -95,7 +102,7 @@ enum { G_DEFINE_TYPE_WITH_CODE ( EShellSearchbar, e_shell_searchbar, - GTK_TYPE_BOX, + GTK_TYPE_GRID, G_IMPLEMENT_INTERFACE ( E_TYPE_EXTENSIBLE, NULL)) @@ -461,6 +468,105 @@ shell_searchbar_option_changed_cb (GtkRadioAction *action, e_shell_searchbar_set_search_text (searchbar, NULL); } +static gboolean +shell_searchbar_resize_idle_cb (gpointer user_data) +{ + GtkWidget *widget; + EShellSearchbar *searchbar; + GSList *iter, *widths = NULL, *witer; + gint row, column, roww, maxw, child_left, child_top, allocated_width; + gboolean needs_reposition = FALSE; + + widget = user_data; + searchbar = E_SHELL_SEARCHBAR (widget); + allocated_width = gtk_widget_get_allocated_width (widget); + + row = 0; + column = 0; + roww = 0; + maxw = 0; + + for (iter = searchbar->priv->child_containers; iter != NULL; iter = iter->next) { + GtkWidget *child = iter->data; + gint minw = -1; + + if (!gtk_widget_get_visible (child)) + minw = 0; + else + gtk_widget_get_preferred_width (child, &minw, NULL); + + widths = g_slist_append (widths, GINT_TO_POINTER (minw)); + + if (roww && minw) { + roww += COLUMN_SPACING; + column++; + } + + roww += minw; + + if (minw > maxw) + maxw = minw; + + if (roww > allocated_width) { + row++; + roww = minw; + column = 0; + } + + gtk_container_child_get (GTK_CONTAINER (widget), child, + "left-attach", &child_left, + "top-attach", &child_top, + NULL); + + needs_reposition = needs_reposition || child_left != column || child_top != row; + + if (column == 0 && row > 0 && roww < maxw) { + /* columns has same width, thus use the wider widget for calculations*/ + roww = maxw; + } + } + + if (needs_reposition) { + row = 0; + column = 0; + roww = 0; + + for (iter = searchbar->priv->child_containers; iter; iter = iter->next) { + gtk_container_remove (GTK_CONTAINER (widget), iter->data); + } + + for (witer = widths, iter = searchbar->priv->child_containers; witer && iter; witer = witer->next, iter = iter->next) { + GtkWidget *child = iter->data; + gint w = GPOINTER_TO_INT (witer->data); + + if (roww && w) { + roww += COLUMN_SPACING; + column++; + } + + roww += w; + + if (roww > allocated_width) { + row++; + roww = w; + column = 0; + } + + gtk_grid_attach (GTK_GRID (widget), child, column, row, 1, 1); + + if (column == 0 && row > 0 && roww < maxw) + roww = maxw; + } + } + + g_slist_free (widths); + + searchbar->priv->resize_idle_id = 0; + g_object_unref (searchbar); + + return FALSE; +} + static void shell_searchbar_set_shell_view (EShellSearchbar *searchbar, EShellView *shell_view) @@ -635,6 +741,16 @@ shell_searchbar_dispose (GObject *object) priv = E_SHELL_SEARCHBAR_GET_PRIVATE (object); + if (priv->resize_idle_id) { + g_source_remove (priv->resize_idle_id); + priv->resize_idle_id = 0; + } + + if (priv->child_containers) { + g_slist_free_full (priv->child_containers, g_object_unref); + priv->child_containers = NULL; + } + if (priv->shell_view != NULL) { g_object_remove_weak_pointer ( G_OBJECT (priv->shell_view), &priv->shell_view); @@ -664,14 +780,12 @@ shell_searchbar_constructed (GObject *object) EShellView *shell_view; EShellWindow *shell_window; EShellSearchbar *searchbar; - GtkSizeGroup *size_group; GtkAction *action; GtkWidget *widget; searchbar = E_SHELL_SEARCHBAR (object); shell_view = e_shell_searchbar_get_shell_view (searchbar); shell_window = e_shell_view_get_shell_window (shell_view); - size_group = e_shell_view_get_size_group (shell_view); g_signal_connect ( shell_view, "clear-search", @@ -732,9 +846,6 @@ shell_searchbar_constructed (GObject *object) widget, "primary-icon-tooltip-text", G_BINDING_SYNC_CREATE); - widget = GTK_WIDGET (searchbar); - gtk_size_group_add_widget (size_group, widget); - e_extensible_load_extensions (E_EXTENSIBLE (object)); /* Chain up to parent's constructed() method. */ @@ -753,6 +864,46 @@ shell_searchbar_map (GtkWidget *widget) e_shell_searchbar_load_state (E_SHELL_SEARCHBAR (widget)); } +static void +shell_searchbar_size_allocate (GtkWidget *widget, + GdkRectangle *allocation) +{ + EShellSearchbar *searchbar; + + GTK_WIDGET_CLASS (e_shell_searchbar_parent_class)->size_allocate (widget, allocation); + + searchbar = E_SHELL_SEARCHBAR (widget); + + if (!searchbar->priv->resize_idle_id) + searchbar->priv->resize_idle_id = g_idle_add (shell_searchbar_resize_idle_cb, g_object_ref (searchbar)); +} + +static void +shell_searchbar_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width) +{ + GList *children, *iter; + gint max_minimum = 0, max_natural = 0; + + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (iter = children; iter != NULL; iter = iter->next) { + GtkWidget *child = iter->data; + gint minimum = 0, natural = 0; + + if (gtk_widget_get_visible (child)) { + gtk_widget_get_preferred_width (child, &minimum, &natural); + if (minimum > max_minimum) + max_minimum = minimum; + if (natural > max_natural) + max_natural = natural; + } + } + + *minimum_width = max_minimum + COLUMN_SPACING; + *natural_width = max_natural + COLUMN_SPACING; +} + static void e_shell_searchbar_class_init (EShellSearchbarClass *class) { @@ -769,6 +920,8 @@ e_shell_searchbar_class_init (EShellSearchbarClass *class) widget_class = GTK_WIDGET_CLASS (class); widget_class->map = shell_searchbar_map; + widget_class->size_allocate = shell_searchbar_size_allocate; + widget_class->get_preferred_width = shell_searchbar_get_preferred_width; g_object_class_install_property ( object_class, @@ -911,34 +1064,43 @@ e_shell_searchbar_class_init (EShellSearchbarClass *class) static void e_shell_searchbar_init (EShellSearchbar *searchbar) { - GtkBox *box; + GtkGrid *grid; GtkLabel *label; GtkWidget *widget; searchbar->priv = E_SHELL_SEARCHBAR_GET_PRIVATE (searchbar); + searchbar->priv->child_containers = NULL; - gtk_box_set_spacing (GTK_BOX (searchbar), 24); + gtk_grid_set_column_spacing (GTK_GRID (searchbar), COLUMN_SPACING); + gtk_grid_set_row_spacing (GTK_GRID (searchbar), 4); /* Filter Combo Widgets */ - box = GTK_BOX (searchbar); + grid = GTK_GRID (searchbar); - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + widget = gtk_grid_new (); + g_object_set (G_OBJECT (widget), + "orientation", GTK_ORIENTATION_HORIZONTAL, + "column-spacing", 3, + "valign", GTK_ALIGN_CENTER, + NULL); + gtk_grid_attach (grid, widget, 0, 0, 1, 1); + searchbar->priv->child_containers = g_slist_append ( + searchbar->priv->child_containers, g_object_ref (widget)); g_object_bind_property ( searchbar, "filter-visible", widget, "visible", G_BINDING_SYNC_CREATE); - box = GTK_BOX (widget); + grid = GTK_GRID (widget); /* Translators: The "Show:" label precedes a combo box that * allows the user to filter the current view. Examples of * items that appear in the combo box are "Unread Messages", * "Important Messages", or "Active Appointments". */ widget = gtk_label_new_with_mnemonic (_("Sho_w:")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_grid_attach (grid, widget, 0, 0, 1, 1); gtk_widget_show (widget); g_object_bind_property ( @@ -950,28 +1112,37 @@ e_shell_searchbar_init (EShellSearchbar *searchbar) widget = e_action_combo_box_new (); gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_grid_attach (grid, widget, 1, 0, 1, 1); searchbar->priv->filter_combo_box = widget; gtk_widget_show (widget); /* Search Entry Widgets */ - box = GTK_BOX (searchbar); + grid = GTK_GRID (searchbar); - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, TRUE, TRUE, 0); + widget = gtk_grid_new (); + g_object_set (G_OBJECT (widget), + "orientation", GTK_ORIENTATION_HORIZONTAL, + "column-spacing", 3, + "valign", GTK_ALIGN_CENTER, + "halign", GTK_ALIGN_FILL, + "hexpand", TRUE, + NULL); + gtk_grid_attach (grid, widget, 1, 0, 1, 1); + searchbar->priv->child_containers = g_slist_append ( + searchbar->priv->child_containers, g_object_ref (widget)); g_object_bind_property ( searchbar, "search-visible", widget, "visible", G_BINDING_SYNC_CREATE); - box = GTK_BOX (widget); + grid = GTK_GRID (widget); /* Translators: This is part of the quick search interface. * example: Search: [_______________] in [ Current Folder ] */ widget = gtk_label_new_with_mnemonic (_("Sear_ch:")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_grid_attach (grid, widget, 0, 0, 1, 1); gtk_widget_show (widget); g_object_bind_property ( @@ -983,7 +1154,11 @@ e_shell_searchbar_init (EShellSearchbar *searchbar) widget = gtk_entry_new (); gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, TRUE, TRUE, 0); + g_object_set (G_OBJECT (widget), + "halign", GTK_ALIGN_FILL, + "hexpand", TRUE, + NULL); + gtk_grid_attach (grid, widget, 1, 0, 1, 1); searchbar->priv->search_entry = widget; gtk_widget_show (widget); @@ -1019,29 +1194,36 @@ e_shell_searchbar_init (EShellSearchbar *searchbar) /* Scope Combo Widgets */ - box = GTK_BOX (searchbar); + grid = GTK_GRID (searchbar); - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + widget = gtk_grid_new (); + g_object_set (G_OBJECT (widget), + "orientation", GTK_ORIENTATION_HORIZONTAL, + "column-spacing", 3, + "valign", GTK_ALIGN_CENTER, + NULL); + gtk_grid_attach (grid, widget, 2, 0, 1, 1); + searchbar->priv->child_containers = g_slist_append ( + searchbar->priv->child_containers, g_object_ref (widget)); g_object_bind_property ( searchbar, "scope-visible", widget, "visible", G_BINDING_SYNC_CREATE); - box = GTK_BOX (widget); + grid = GTK_GRID (widget); /* Translators: This is part of the quick search interface. * example: Search: [_______________] in [ Current Folder ] */ widget = gtk_label_new_with_mnemonic (_("i_n")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_grid_attach (grid, widget, 0, 0, 1, 1); gtk_widget_show (widget); label = GTK_LABEL (widget); widget = e_action_combo_box_new (); gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_grid_attach (grid, widget, 1, 0, 1, 1); searchbar->priv->scope_combo_box = widget; gtk_widget_show (widget); diff --git a/shell/e-shell-searchbar.h b/shell/e-shell-searchbar.h index a9e73c9f02..6c68e72d80 100644 --- a/shell/e-shell-searchbar.h +++ b/shell/e-shell-searchbar.h @@ -58,12 +58,12 @@ typedef struct _EShellSearchbarPrivate EShellSearchbarPrivate; * functions below. **/ struct _EShellSearchbar { - GtkBox parent; + GtkGrid parent; EShellSearchbarPrivate *priv; }; struct _EShellSearchbarClass { - GtkBoxClass parent_class; + GtkGridClass parent_class; }; GType e_shell_searchbar_get_type (void); diff --git a/shell/e-shell-sidebar.c b/shell/e-shell-sidebar.c index 362321069a..95afe576b4 100644 --- a/shell/e-shell-sidebar.c +++ b/shell/e-shell-sidebar.c @@ -203,20 +203,14 @@ shell_sidebar_constructed (GObject *object) { EShellView *shell_view; EShellSidebar *shell_sidebar; - GtkSizeGroup *size_group; GtkAction *action; - GtkWidget *widget; gchar *label; gchar *icon_name; shell_sidebar = E_SHELL_SIDEBAR (object); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); - size_group = e_shell_view_get_size_group (shell_view); action = e_shell_view_get_action (shell_view); - widget = shell_sidebar->priv->event_box; - gtk_size_group_add_widget (size_group, widget); - g_object_get (action, "icon-name", &icon_name, NULL); e_shell_sidebar_set_icon_name (shell_sidebar, icon_name); g_free (icon_name); diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index 1e7e27b87b..90fdbc852e 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -67,7 +67,6 @@ struct _EShellViewPrivate { guint merge_id; GtkAction *action; - GtkSizeGroup *size_group; GtkWidget *shell_content; GtkWidget *shell_sidebar; GtkWidget *shell_taskbar; @@ -622,10 +621,6 @@ shell_view_constructed (GObject *object) shell_view->priv->searchbar = g_object_ref_sink (widget); } - /* Size group should be safe to unreference now. */ - g_object_unref (shell_view->priv->size_group); - shell_view->priv->size_group = NULL; - /* Update actions whenever the Preferences window is closed. */ widget = e_shell_get_preferences_window (shell); shell_view->priv->preferences_window = g_object_ref (widget); @@ -1102,8 +1097,6 @@ static void e_shell_view_init (EShellView *shell_view, EShellViewClass *class) { - GtkSizeGroup *size_group; - /* XXX Our use of GInstanceInitFunc's 'class' parameter * prevents us from using G_DEFINE_ABSTRACT_TYPE. */ @@ -1113,11 +1106,8 @@ e_shell_view_init (EShellView *shell_view, if (class->view_collection == NULL) shell_view_init_view_collection (class); - size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); - shell_view->priv = E_SHELL_VIEW_GET_PRIVATE (shell_view); shell_view->priv->state_key_file = g_key_file_new (); - shell_view->priv->size_group = size_group; } GType @@ -1487,26 +1477,6 @@ e_shell_view_get_search_query (EShellView *shell_view) return g_string_free (string, FALSE); } -/** - * e_shell_view_get_size_group: - * @shell_view: an #EShellView - * - * Returns a #GtkSizeGroup that #EShellContent and #EShellSidebar use - * to keep the search bar and sidebar banner vertically aligned. The - * rest of the application should have no need for this. - * - * Note, this is only available during #EShellView construction. - * - * Returns: a #GtkSizeGroup for internal use - **/ -GtkSizeGroup * -e_shell_view_get_size_group (EShellView *shell_view) -{ - g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - - return shell_view->priv->size_group; -} - /** * e_shell_view_get_shell_backend: * @shell_view: an #EShellView diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index 84b3c69314..736af40b6a 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -201,7 +201,6 @@ EFilterRule * e_shell_view_get_search_rule (EShellView *shell_view); void e_shell_view_set_search_rule (EShellView *shell_view, EFilterRule *search_rule); gchar * e_shell_view_get_search_query (EShellView *shell_view); -GtkSizeGroup * e_shell_view_get_size_group (EShellView *shell_view); EShellBackend * e_shell_view_get_shell_backend (EShellView *shell_view); EShellContent * e_shell_view_get_shell_content (EShellView *shell_view); EShellSidebar * e_shell_view_get_shell_sidebar (EShellView *shell_view); -- cgit v1.2.3