From d4b1f0cadfc55a9454b695893555b15f56922d7b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Dec 2009 02:07:51 -0500 Subject: [PATCH] implement extended layout for GtkTreeView and GtkTreeViewColumn --- gtk/gtktreeprivate.h | 7 +++ gtk/gtktreeview.c | 117 ++++++++++++++++++++++++++++++++++------ gtk/gtktreeviewcolumn.c | 99 +++++++++++++++++++++++++--------- gtk/gtktreeviewcolumn.h | 1 + 4 files changed, 185 insertions(+), 39 deletions(-) diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h index dd0cf8d2a9..43c6e31069 100644 --- a/gtk/gtktreeprivate.h +++ b/gtk/gtktreeprivate.h @@ -77,6 +77,8 @@ enum */ #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*TREE_VIEW_HEADER_HEIGHT(tree_view)) +#define GTK_TREE_VIEW_COLUMN_GET_PRIVATE(column) (G_TYPE_INSTANCE_GET_PRIVATE ((column), GTK_TYPE_TREE_VIEW_COLUMN, GtkTreeViewColumnPrivate)) + typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder; struct _GtkTreeViewColumnReorder { @@ -298,6 +300,11 @@ struct _GtkTreeViewPrivate guint search_entry_avoid_unhandled_binding : 1; }; +struct _GtkTreeViewColumnPrivate +{ + gint natural_width; +}; + #ifdef __GNUC__ #define TREE_VIEW_INTERNAL_ASSERT(expr, ret) G_STMT_START{ \ diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 47b8e59d81..53732cd65c 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -27,6 +27,7 @@ #include "gtktreednd.h" #include "gtktreeprivate.h" #include "gtkcellrenderer.h" +#include "gtkextendedlayout.h" #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkbuildable.h" @@ -469,7 +470,7 @@ static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view, GObject *child, const gchar *type); static void gtk_tree_view_buildable_init (GtkBuildableIface *iface); - +static void gtk_tree_view_extended_layout_init (GtkExtendedLayoutIface *iface); static gboolean scroll_row_timeout (gpointer data); static void add_scroll_timeout (GtkTreeView *tree_view); @@ -484,7 +485,10 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_tree_view_buildable_init)) + gtk_tree_view_buildable_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT, + gtk_tree_view_extended_layout_init)) + static void gtk_tree_view_class_init (GtkTreeViewClass *class) @@ -2141,6 +2145,28 @@ gtk_tree_view_get_real_requested_width_from_column (GtkTreeView *tree_view return real_requested_width; } +static gint +gtk_tree_view_get_real_natural_width_from_column (GtkTreeView *tree_view, + GtkTreeViewColumn *column) +{ + GtkTreeViewColumnPrivate *column_priv; + GtkRequisition button_natural_size; + gint column_natural_width; + + column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column); + column_natural_width = column_priv->natural_width; + + if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE)) + { + gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (column->button), + NULL, &button_natural_size); + + column_natural_width = MAX (column_natural_width, button_natural_size.width); + } + + return column_natural_width; +} + /* GtkWidget::size_allocate helper */ static void gtk_tree_view_size_allocate_columns (GtkWidget *widget, @@ -2150,9 +2176,10 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget, GList *list, *first_column, *last_column; GtkTreeViewColumn *column; GtkAllocation allocation; - gint width = 0; + gint width = 0, natural_width; gint extra, extra_per_column, extra_for_last; gint full_requested_width = 0; + gint full_natural_width = 0; gint number_of_expand_columns = 0; gboolean column_changed = FALSE; gboolean rtl; @@ -2186,6 +2213,7 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget, continue; full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column); + full_natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column); if (column->expand) number_of_expand_columns++; @@ -2210,7 +2238,9 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget, } else { + full_natural_width -= full_requested_width; extra = MAX (widget->allocation.width - full_requested_width, 0); + natural_width = MIN (extra, full_natural_width); extra_for_last = 0; tree_view->priv->last_extra_space = extra; @@ -2232,6 +2262,7 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget, list = (rtl ? list->prev : list->next)) { gint real_requested_width = 0; + gint real_natural_width = 0; gint old_width; column = list->data; @@ -2257,10 +2288,14 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget, } real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column); + real_natural_width = gtk_tree_view_get_real_natural_width_from_column (tree_view, column); + real_natural_width -= real_requested_width; allocation.x = width; column->width = real_requested_width; + if (full_natural_width > 0) + column->width += natural_width * real_natural_width / full_natural_width; if (column->expand) { if (number_of_expand_columns == 1) @@ -5656,10 +5691,13 @@ validate_row (GtkTreeView *tree_view, for (list = tree_view->priv->columns; list; list = list->next) { - gint tmp_width; - gint tmp_height; + GtkTreeViewColumnPrivate *column_priv; + GtkRequisition requested_size; + GtkRequisition natural_size; + gint padding; column = list->data; + column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column); if (! column->visible) continue; @@ -5672,12 +5710,15 @@ validate_row (GtkTreeView *tree_view, node->children?TRUE:FALSE); gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, - &tmp_width, &tmp_height); + &requested_size.width, + &requested_size.height); + gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (column), + NULL, &natural_size); if (!is_separator) { - tmp_height += vertical_separator; - height = MAX (height, tmp_height); + requested_size.height += vertical_separator; + height = MAX (height, requested_size.height); height = MAX (height, tree_view->priv->expander_size); } else @@ -5690,26 +5731,31 @@ validate_row (GtkTreeView *tree_view, if (gtk_tree_view_is_expander_column (tree_view, column)) { - tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation; + padding = horizontal_separator + (depth - 1) * tree_view->priv->level_indentation; if (TREE_VIEW_DRAW_EXPANDERS (tree_view)) - tmp_width += depth * tree_view->priv->expander_size; + padding += depth * tree_view->priv->expander_size; } else - tmp_width = tmp_width + horizontal_separator; + padding = horizontal_separator; if (draw_vgrid_lines) { if (list->data == first_column || list->data == last_column) - tmp_width += grid_line_width / 2.0; + padding += grid_line_width / 2.0; else - tmp_width += grid_line_width; + padding += grid_line_width; } - if (tmp_width > column->requested_width) + requested_size.width += padding; + natural_size.width += padding; + + if (requested_size.width > column->requested_width || + natural_size.width > column_priv->natural_width) { retval = TRUE; - column->requested_width = tmp_width; + column->requested_width = requested_size.width; + column_priv->natural_width = natural_size.width; } } @@ -15636,5 +15682,46 @@ gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view) return tree_view->priv->tooltip_column; } +static void +gtk_tree_view_extended_layout_get_desired_size (GtkExtendedLayout *layout, + GtkRequisition *minimal_size, + GtkRequisition *desired_size) +{ + GtkTreeView *tree_view; + gint natural_width = 0; + GList *column_iter; + GtkRequisition requisition; + + tree_view = GTK_TREE_VIEW (layout); + + gtk_widget_size_request (GTK_WIDGET (layout), &requisition); + + for (column_iter = tree_view->priv->columns; column_iter; column_iter = column_iter->next) + { + GtkTreeViewColumn *column = column_iter->data; + + if (!column->visible) + continue; + + natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column); + } + + if (minimal_size) + *minimal_size = requisition; + + if (desired_size) + { + desired_size->height = requisition.height; + desired_size->width = natural_width; + } +} + +static void +gtk_tree_view_extended_layout_init (GtkExtendedLayoutIface *iface) +{ + iface->get_desired_size = gtk_tree_view_extended_layout_get_desired_size; +} + + #define __GTK_TREE_VIEW_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c index edec5deffe..0a1dd51364 100644 --- a/gtk/gtktreeviewcolumn.c +++ b/gtk/gtktreeviewcolumn.c @@ -26,6 +26,7 @@ #include "gtkbutton.h" #include "gtkalignment.h" #include "gtklabel.h" +#include "gtkextendedlayout.h" #include "gtkhbox.h" #include "gtkmarshalers.h" #include "gtkarrow.h" @@ -155,13 +156,18 @@ static void gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColum /* GtkBuildable implementation */ static void gtk_tree_view_column_buildable_init (GtkBuildableIface *iface); +static void gtk_tree_view_column_extended_layout_init (GtkExtendedLayoutIface *iface); + static guint tree_column_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, GTK_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, gtk_tree_view_column_cell_layout_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_tree_view_column_buildable_init)) + gtk_tree_view_column_buildable_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT, + gtk_tree_view_column_extended_layout_init)) + static void @@ -344,6 +350,8 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) G_MAXINT, -1, GTK_PARAM_READWRITE)); + + g_type_class_add_private (class, sizeof (GtkTreeViewColumnPrivate)); } static void @@ -2608,12 +2616,12 @@ gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column, * primarily by the #GtkTreeView. **/ void -gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column, +gtk_tree_view_column_cell_get_real_size (GtkTreeViewColumn *tree_column, const GdkRectangle *cell_area, gint *x_offset, gint *y_offset, - gint *width, - gint *height) + GtkRequisition *minimal_size, + GtkRequisition *desired_size) { GList *list; gboolean first_cell = TRUE; @@ -2621,10 +2629,10 @@ gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column, g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (height) - * height = 0; - if (width) - * width = 0; + minimal_size->height = 0; + minimal_size->width = 0; + desired_size->height = 0; + desired_size->width = 0; gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL); @@ -2632,33 +2640,59 @@ gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column, { GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; gboolean visible; - gint new_height = 0; - gint new_width = 0; + GtkRequisition min_req, nat_req; + g_object_get (info->cell, "visible", &visible, NULL); if (visible == FALSE) continue; - if (first_cell == FALSE && width) - *width += tree_column->spacing; + if (first_cell == FALSE) + { + min_req.width += tree_column->spacing; + nat_req.width += tree_column->spacing; + } - gtk_cell_renderer_get_size (info->cell, - tree_column->tree_view, - cell_area, - x_offset, - y_offset, - &new_width, - &new_height); + gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (info->cell), + &min_req, &nat_req); + + min_req.width += focus_line_width * 2; + min_req.height += focus_line_width * 2; + nat_req.width += focus_line_width * 2; + nat_req.height += focus_line_width * 2; + + info->requested_width = MAX (info->requested_width, min_req.width); - if (height) - * height = MAX (*height, new_height + focus_line_width * 2); - info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2); - if (width) - * width += info->requested_width; first_cell = FALSE; + + if (minimal_size) + *minimal_size = min_req; + + if (desired_size) + *desired_size = nat_req; } } +void +gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column, + const GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) +{ + GtkRequisition min_req; + + gtk_tree_view_column_cell_get_real_size (tree_column, cell_area, + x_offset, y_offset, &min_req, NULL); + + if (width) + *width = min_req.width; + + if (height) + *height = min_req.height; +} + /* rendering, event handling and rendering focus are somewhat complicated, and * quite a bit of code. Rather than duplicate them, we put them together to * keep the code in one place. @@ -3784,5 +3818,22 @@ gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column) return tree_column->tree_view; } +static void +gtk_tree_view_column_extended_layout_get_desired_size (GtkExtendedLayout *layout, + GtkRequisition *minimal_size, + GtkRequisition *desired_size) +{ + gtk_tree_view_column_cell_get_real_size (GTK_TREE_VIEW_COLUMN (layout), + NULL, NULL, NULL, + minimal_size, desired_size); +} + +static void +gtk_tree_view_column_extended_layout_init (GtkExtendedLayoutIface *iface) +{ + iface->get_desired_size = gtk_tree_view_column_extended_layout_get_desired_size; +} + + #define __GTK_TREE_VIEW_COLUMN_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtktreeviewcolumn.h b/gtk/gtktreeviewcolumn.h index b06e845d9f..75b4c5afc2 100644 --- a/gtk/gtktreeviewcolumn.h +++ b/gtk/gtktreeviewcolumn.h @@ -51,6 +51,7 @@ typedef enum typedef struct _GtkTreeViewColumn GtkTreeViewColumn; typedef struct _GtkTreeViewColumnClass GtkTreeViewColumnClass; +typedef struct _GtkTreeViewColumnPrivate GtkTreeViewColumnPrivate; typedef void (* GtkTreeCellDataFunc) (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,