diff options
author | Matthias Clasen <mclasen@redhat.com> | 2004-07-07 15:15:35 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2004-07-07 15:15:35 +0000 |
commit | 1aa00e521590a807868cdfe75e8fbf7fb6facc44 (patch) | |
tree | 5d848f45999ce4846fc2e56f82674dbc3c066807 | |
parent | a346f4a8ad8a037a014891b59db8efa47c30d37e (diff) | |
download | gtk+-1aa00e521590a807868cdfe75e8fbf7fb6facc44.tar.gz |
Support separators in combo boxes and more generally in tree views
2004-07-07 Matthias Clasen <mclasen@redhat.com>
Support separators in combo boxes and more generally in tree
views (#135873):
* gtk/gtkcombobox.h:
* gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column):
* gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column):
Add a ::row-separator-column property with getter and setter,
which can indicate a boolean model column to determine which
rows are separators.
* gtk/gtkcombobox.c: Display separator rows as separator menu
items in menu mode, and by using the new treeview separator
functionality in list mode.
* gtk/gtktreeview.h:
* gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func):
* gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func):
Add a callback to determine whether a row is a separator.
* gtk/gtktreeview.c (gtk_tree_view_bin_expose):
* gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon):
* gtk/gtktreeview.c (validate_row): Use the new callback
to determine whether a row is a separator, and draw it
as a separator then. Since separators should take up less
vertical space than regular rows, this requires removing
the redundant MAX(...,expander_size) calls which appear in
many places. Instead, the MAX() is now only done in
validate_row(), and only if the row is not a separator.
To catch possible side effects of this intrusive change,
I have left EXPANDER_MAX() calls in place of the MAX() calls
which will emit a warning if something breaks. They should
be removed before 2.6.
* gtk/gtktreeselection.c (row_is_selectable): Don't let
separator rows be selected.
* tests/testcombo.c (create_blaat): Add a separator column.
-rw-r--r-- | ChangeLog | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 40 | ||||
-rw-r--r-- | gtk/gtkcombobox.c | 184 | ||||
-rw-r--r-- | gtk/gtkcombobox.h | 4 | ||||
-rw-r--r-- | gtk/gtktreeselection.c | 24 | ||||
-rw-r--r-- | gtk/gtktreeview.c | 279 | ||||
-rw-r--r-- | gtk/gtktreeview.h | 9 | ||||
-rw-r--r-- | tests/testcombo.c | 29 |
10 files changed, 603 insertions, 86 deletions
@@ -1,3 +1,43 @@ +2004-07-07 Matthias Clasen <mclasen@redhat.com> + + Support separators in combo boxes and more generally in tree + views (#135873): + + * gtk/gtkcombobox.h: + * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column): + * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column): + Add a ::row-separator-column property with getter and setter, + which can indicate a boolean model column to determine which + rows are separators. + + * gtk/gtkcombobox.c: Display separator rows as separator menu + items in menu mode, and by using the new treeview separator + functionality in list mode. + + * gtk/gtktreeview.h: + * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func): + * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func): + Add a callback to determine whether a row is a separator. + + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): + * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon): + * gtk/gtktreeview.c (validate_row): Use the new callback + to determine whether a row is a separator, and draw it + as a separator then. Since separators should take up less + vertical space than regular rows, this requires removing + the redundant MAX(...,expander_size) calls which appear in + many places. Instead, the MAX() is now only done in + validate_row(), and only if the row is not a separator. + To catch possible side effects of this intrusive change, + I have left EXPANDER_MAX() calls in place of the MAX() calls + which will emit a warning if something breaks. They should + be removed before 2.6. + + * gtk/gtktreeselection.c (row_is_selectable): Don't let + separator rows be selected. + + * tests/testcombo.c (create_blaat): Add a separator column. + Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de> * gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 9b3a885c53..09c565b983 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,43 @@ +2004-07-07 Matthias Clasen <mclasen@redhat.com> + + Support separators in combo boxes and more generally in tree + views (#135873): + + * gtk/gtkcombobox.h: + * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column): + * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column): + Add a ::row-separator-column property with getter and setter, + which can indicate a boolean model column to determine which + rows are separators. + + * gtk/gtkcombobox.c: Display separator rows as separator menu + items in menu mode, and by using the new treeview separator + functionality in list mode. + + * gtk/gtktreeview.h: + * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func): + * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func): + Add a callback to determine whether a row is a separator. + + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): + * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon): + * gtk/gtktreeview.c (validate_row): Use the new callback + to determine whether a row is a separator, and draw it + as a separator then. Since separators should take up less + vertical space than regular rows, this requires removing + the redundant MAX(...,expander_size) calls which appear in + many places. Instead, the MAX() is now only done in + validate_row(), and only if the row is not a separator. + To catch possible side effects of this intrusive change, + I have left EXPANDER_MAX() calls in place of the MAX() calls + which will emit a warning if something breaks. They should + be removed before 2.6. + + * gtk/gtktreeselection.c (row_is_selectable): Don't let + separator rows be selected. + + * tests/testcombo.c (create_blaat): Add a separator column. + Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de> * gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 9b3a885c53..09c565b983 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,43 @@ +2004-07-07 Matthias Clasen <mclasen@redhat.com> + + Support separators in combo boxes and more generally in tree + views (#135873): + + * gtk/gtkcombobox.h: + * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column): + * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column): + Add a ::row-separator-column property with getter and setter, + which can indicate a boolean model column to determine which + rows are separators. + + * gtk/gtkcombobox.c: Display separator rows as separator menu + items in menu mode, and by using the new treeview separator + functionality in list mode. + + * gtk/gtktreeview.h: + * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func): + * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func): + Add a callback to determine whether a row is a separator. + + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): + * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon): + * gtk/gtktreeview.c (validate_row): Use the new callback + to determine whether a row is a separator, and draw it + as a separator then. Since separators should take up less + vertical space than regular rows, this requires removing + the redundant MAX(...,expander_size) calls which appear in + many places. Instead, the MAX() is now only done in + validate_row(), and only if the row is not a separator. + To catch possible side effects of this intrusive change, + I have left EXPANDER_MAX() calls in place of the MAX() calls + which will emit a warning if something breaks. They should + be removed before 2.6. + + * gtk/gtktreeselection.c (row_is_selectable): Don't let + separator rows be selected. + + * tests/testcombo.c (create_blaat): Add a separator column. + Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de> * gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 9b3a885c53..09c565b983 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,43 @@ +2004-07-07 Matthias Clasen <mclasen@redhat.com> + + Support separators in combo boxes and more generally in tree + views (#135873): + + * gtk/gtkcombobox.h: + * gtk/gtkcombobox.c (gtk_combo_box_get_row_separator_column): + * gtk/gtkcombobox.c (gtk_combo_box_set_row_separator_column): + Add a ::row-separator-column property with getter and setter, + which can indicate a boolean model column to determine which + rows are separators. + + * gtk/gtkcombobox.c: Display separator rows as separator menu + items in menu mode, and by using the new treeview separator + functionality in list mode. + + * gtk/gtktreeview.h: + * gtk/gtktreeview.c (gtk_tree_view_get_row_separator_func): + * gtk/gtktreeview.c (gtk_tree_view_set_row_separator_func): + Add a callback to determine whether a row is a separator. + + * gtk/gtktreeview.c (gtk_tree_view_bin_expose): + * gtk/gtktreeview.c (gtk_tree_view_create_row_drag_icon): + * gtk/gtktreeview.c (validate_row): Use the new callback + to determine whether a row is a separator, and draw it + as a separator then. Since separators should take up less + vertical space than regular rows, this requires removing + the redundant MAX(...,expander_size) calls which appear in + many places. Instead, the MAX() is now only done in + validate_row(), and only if the row is not a separator. + To catch possible side effects of this intrusive change, + I have left EXPANDER_MAX() calls in place of the MAX() calls + which will emit a warning if something breaks. They should + be removed before 2.6. + + * gtk/gtktreeselection.c (row_is_selectable): Don't let + separator rows be selected. + + * tests/testcombo.c (create_blaat): Add a separator column. + Tue Jul 6 22:58:00 2004 Matthias Clasen <maclas@gmx.de> * gdk/x11/gdkwindow-x11.c (gdk_x11_window_set_user_time): Fix diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 613b12f934..b08515dff9 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -32,6 +32,7 @@ #include "gtkliststore.h" #include "gtkmain.h" #include "gtkmenu.h" +#include "gtkseparatormenuitem.h" #include "gtktearoffmenuitem.h" #include "gtktogglebutton.h" #include "gtktreeselection.h" @@ -73,6 +74,7 @@ struct _GtkComboBoxPrivate gint col_column; gint row_column; + gint separator_column; gint wrap_width; @@ -171,6 +173,7 @@ enum { PROP_WRAP_WIDTH, PROP_ROW_SPAN_COLUMN, PROP_COLUMN_SPAN_COLUMN, + PROP_ROW_SEPARATOR_COLUMN, PROP_ACTIVE, PROP_ADD_TEAROFFS }; @@ -482,9 +485,9 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) g_param_spec_int ("row_span_column", P_("Row span column"), P_("TreeModel column containing the row span values"), - 0, + -1, G_MAXINT, - 0, + -1, G_PARAM_READWRITE)); g_object_class_install_property (object_class, @@ -492,9 +495,19 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) g_param_spec_int ("column_span_column", P_("Column span column"), P_("TreeModel column containing the column span values"), - 0, + -1, G_MAXINT, - 0, + -1, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_ROW_SEPARATOR_COLUMN, + g_param_spec_int ("row_separator_column", + P_("Row separator column"), + P_("Boolean TreeModel column specifying which rows are separators"), + -1, + G_MAXINT, + -1, G_PARAM_READWRITE)); g_object_class_install_property (object_class, @@ -563,6 +576,7 @@ gtk_combo_box_init (GtkComboBox *combo_box) combo_box->priv->active_item = -1; combo_box->priv->col_column = -1; combo_box->priv->row_column = -1; + combo_box->priv->separator_column = -1; } static void @@ -591,6 +605,10 @@ gtk_combo_box_set_property (GObject *object, gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value)); break; + case PROP_ROW_SEPARATOR_COLUMN: + gtk_combo_box_set_row_separator_column (combo_box, g_value_get_int (value)); + break; + case PROP_ACTIVE: gtk_combo_box_set_active (combo_box, g_value_get_int (value)); break; @@ -630,6 +648,10 @@ gtk_combo_box_get_property (GObject *object, g_value_set_int (value, combo_box->priv->col_column); break; + case PROP_ROW_SEPARATOR_COLUMN: + g_value_set_int (value, combo_box->priv->separator_column); + break; + case PROP_ACTIVE: g_value_set_int (value, gtk_combo_box_get_active (combo_box)); break; @@ -1153,7 +1175,10 @@ menu_row_is_sensitive (GtkComboBox *combo_box, GtkWidget *cell_view; GList *cells, *list; gboolean sensitive; - + + if (!GTK_IS_CELL_VIEW_MENU_ITEM (item)) + return FALSE; + cell_view = gtk_bin_get_child (GTK_BIN (item)); gtk_cell_view_set_cell_data (GTK_CELL_VIEW (cell_view)); @@ -1186,6 +1211,19 @@ tree_column_row_is_sensitive (GtkComboBox *combo_box, if (!combo_box->priv->column) return TRUE; + if (combo_box->priv->separator_column != -1) + { + gboolean is_separator; + + gtk_tree_model_get (combo_box->priv->model, + iter, + combo_box->priv->separator_column, &is_separator, + -1); + + if (is_separator) + return FALSE; + } + gtk_tree_view_column_cell_set_cell_data (combo_box->priv->column, combo_box->priv->model, iter, FALSE, FALSE); @@ -1266,14 +1304,14 @@ update_menu_sensitivity (GtkComboBox *combo_box) children = gtk_container_get_children (GTK_CONTAINER (menu)); child = children; - if (child && GTK_IS_TEAROFF_MENU_ITEM (child->data)) - child = child->next; - for (i = 0; i < items; i++, child = child->next) { GtkWidget *item = GTK_WIDGET (child->data); gboolean sensitive; + if (!GTK_IS_CELL_VIEW_MENU_ITEM (item)) + continue; + sensitive = menu_row_is_sensitive (combo_box, item); gtk_widget_set_sensitive (item, sensitive); } @@ -1327,7 +1365,7 @@ gtk_combo_box_popup (GtkComboBox *combo_box) gtk_widget_show_all (combo_box->priv->popup_frame); gtk_combo_box_list_position (combo_box, &x, &y, &width, &height); - + gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1); gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y); @@ -1378,6 +1416,7 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) } gtk_combo_box_list_remove_grabs (combo_box); + gtk_widget_hide_all (combo_box->priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), FALSE); @@ -1755,8 +1794,7 @@ gtk_combo_box_scroll_event (GtkWidget *widget, GdkEventScroll *event) { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); - gint index; - gint items; + gint index, new_index, items; index = gtk_combo_box_get_active (combo_box); @@ -1765,11 +1803,23 @@ gtk_combo_box_scroll_event (GtkWidget *widget, items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); if (event->direction == GDK_SCROLL_UP) - index--; - else - index++; + { + new_index = index - 1; + while (new_index >= 0 && !row_is_sensitive (combo_box, new_index)) + new_index--; + if (new_index < 0) + new_index = index; + } + else + { + new_index = index + 1; + while (new_index < items && !row_is_sensitive (combo_box, new_index)) + new_index++; + if (new_index == items) + new_index = index; + } - gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1)); + gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1)); } return TRUE; @@ -1905,16 +1955,33 @@ gtk_combo_box_menu_fill (GtkComboBox *combo_box) for (i = 0; i < items; i++) { GtkTreePath *path; + GtkTreeIter iter; + gboolean is_separator; path = gtk_tree_path_new_from_indices (i, -1); - tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model, - path); - g_signal_connect (tmp, "activate", - G_CALLBACK (gtk_combo_box_menu_item_activate), - combo_box); - cell_view_sync_cells (combo_box, - GTK_CELL_VIEW (GTK_BIN (tmp)->child)); + if (combo_box->priv->separator_column != -1) + { + gtk_tree_model_get_iter (combo_box->priv->model, &iter, path); + gtk_tree_model_get (combo_box->priv->model, &iter, + combo_box->priv->separator_column, &is_separator, -1); + } + else + is_separator = FALSE; + + if (is_separator) + tmp = gtk_separator_menu_item_new (); + else + { + tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model, + path); + g_signal_connect (tmp, "activate", + G_CALLBACK (gtk_combo_box_menu_item_activate), + combo_box); + + cell_view_sync_cells (combo_box, + GTK_CELL_VIEW (GTK_BIN (tmp)->child)); + } gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp); @@ -2345,6 +2412,21 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model, * list style */ +static gboolean +row_is_separator (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + GtkComboBox *combo_box = GTK_COMBO_BOX (data); + gboolean is_separator = FALSE; + + if (combo_box->priv->separator_column != -1) + gtk_tree_model_get (combo_box->priv->model, iter, + combo_box->priv->separator_column, &is_separator, -1); + + return is_separator; +} + static void gtk_combo_box_list_setup (GtkComboBox *combo_box) { @@ -2399,7 +2481,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) FALSE); gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (combo_box->priv->tree_view), TRUE); - + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (combo_box->priv->tree_view), + row_is_separator, combo_box, NULL); if (combo_box->priv->model) gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view), combo_box->priv->model); @@ -3303,7 +3386,7 @@ gtk_combo_box_set_row_span_column (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); col = gtk_tree_model_get_n_columns (combo_box->priv->model); - g_return_if_fail (row_span >= 0 && row_span < col); + g_return_if_fail (row_span >= -1 && row_span < col); if (row_span != combo_box->priv->row_column) { @@ -3353,7 +3436,7 @@ gtk_combo_box_set_column_span_column (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); col = gtk_tree_model_get_n_columns (combo_box->priv->model); - g_return_if_fail (column_span >= 0 && column_span < col); + g_return_if_fail (column_span >= -1 && column_span < col); if (column_span != combo_box->priv->col_column) { @@ -3876,3 +3959,54 @@ gtk_combo_box_set_add_tearoffs (GtkComboBox *combo_box, g_object_notify (G_OBJECT (combo_box), "add_tearoffs"); } } + +/** + * gtk_combo_box_set_row_separator_column: + * @combo_box: a #GtkComboBox + * @column: the index of a boolean model column, or -1 to + * turn off separators + * + * Sets the row separator column index. + * This model column contains boolean values which indicate + * whether a row is to be drawn as a separator or now. + * Setting the index to -1 turns off separators. + * + * Since: 2.6 + **/ +void +gtk_combo_box_set_row_separator_column (GtkComboBox *combo_box, + gint column) +{ + gint col; + + g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); + col = gtk_tree_model_get_n_columns (combo_box->priv->model); + g_return_if_fail (column >= -1 && column < col); + + if (combo_box->priv->separator_column != column) + { + combo_box->priv->separator_column = column; + + gtk_widget_queue_draw (combo_box); + + g_object_notify (G_OBJECT (combo_box), "row_separator_column"); + } +} + +/** + * gtk_combo_box_get_row_separator_column: + * @combo_box: a #GtkComboBox + * + * Returns the current row separator column index. + * + * Return value: the row separator column index + * + * Since: 2.6 + **/ +gint +gtk_combo_box_get_row_separator_column (GtkComboBox *combo_box) +{ + g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), -1); + + return combo_box->priv->separator_column; +} diff --git a/gtk/gtkcombobox.h b/gtk/gtkcombobox.h index 7ecccbfd74..4d6b3e460f 100644 --- a/gtk/gtkcombobox.h +++ b/gtk/gtkcombobox.h @@ -94,6 +94,10 @@ void gtk_combo_box_set_model (GtkComboBox *combo_box, GtkTreeModel *model); GtkTreeModel *gtk_combo_box_get_model (GtkComboBox *combo_box); +void gtk_combo_box_set_row_separator_column (GtkComboBox *combo_box, + gint column); +gint gtk_combo_box_get_row_separator_column (GtkComboBox *combo_box); + /* convenience -- text */ GtkWidget *gtk_combo_box_new_text (void); void gtk_combo_box_append_text (GtkComboBox *combo_box, diff --git a/gtk/gtktreeselection.c b/gtk/gtktreeselection.c index 4e5a76a7da..b8ac48b8b8 100644 --- a/gtk/gtktreeselection.c +++ b/gtk/gtktreeselection.c @@ -1319,21 +1319,29 @@ row_is_selectable (GtkTreeSelection *selection, GtkTreePath *path) { GList *list; - gboolean sensitive; - - sensitive = FALSE; + GtkTreeIter iter; + gboolean sensitive = FALSE; + + if (!gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path)) + sensitive = TRUE; + + if (!sensitive && selection->tree_view->priv->row_separator_func) + { + /* never allow separators to be selected */ + if ((* selection->tree_view->priv->row_separator_func) (selection->tree_view->priv->model, + &iter, + selection->tree_view->priv->row_separator_data)) + return FALSE; + } + for (list = selection->tree_view->priv->columns; list && !sensitive; list = list->next) { GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data); - GtkTreeIter iter; if (!column->visible) continue; - if (gtk_tree_model_get_iter (selection->tree_view->priv->model, &iter, path)) - sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter); - else - sensitive = TRUE; + sensitive = tree_column_is_sensitive (column, selection->tree_view->priv->model, &iter); } if (!sensitive) diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index c126658a18..217b78dd9c 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -62,6 +62,8 @@ #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node)))) #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2) +#define EXPANDER_MAX(height,expander_size,tree_view,tree,node) check_expander_max (height, expander_size, tree_view, tree, node) + typedef struct _GtkTreeViewChild GtkTreeViewChild; struct _GtkTreeViewChild @@ -423,6 +425,12 @@ static void gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view, gint wy, gint *tx, gint *ty); +static gint check_expander_max (gint height, + gint expander_size, + GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node); + static GtkContainerClass *parent_class = NULL; static guint tree_view_signals [LAST_SIGNAL] = { 0 }; @@ -1346,6 +1354,12 @@ gtk_tree_view_destroy (GtkObject *object) tree_view->priv->search_user_data = NULL; } + if (tree_view->priv->row_separator_destroy) + { + (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data); + tree_view->priv->row_separator_data = NULL; + } + gtk_tree_view_set_model (tree_view, NULL); if (GTK_OBJECT_CLASS (parent_class)->destroy) @@ -2155,8 +2169,9 @@ gtk_tree_view_button_press (GtkWidget *widget, path = _gtk_tree_view_find_path (tree_view, tree, node); depth = gtk_tree_path_get_depth (path); background_area.y = y_offset + event->y; - background_area.height = MAX (GTK_RBNODE_GET_HEIGHT (node), - tree_view->priv->expander_size); + background_area.height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), + tree_view->priv->expander_size, + tree_view, tree, node); background_area.x = 0; @@ -2621,7 +2636,8 @@ coords_are_over_arrow (GtkTreeView *tree_view, arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - arrow.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + arrow.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2); @@ -3309,7 +3325,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget, path); depth = gtk_tree_path_get_depth (path); gtk_tree_path_free (path); - + cursor_path = NULL; drag_dest_path = NULL; @@ -3330,7 +3346,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget, gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, NULL); - + n_visible_columns = 0; for (list = tree_view->priv->columns; list; list = list->next) { @@ -3355,8 +3371,17 @@ gtk_tree_view_bin_expose (GtkWidget *widget, do { gboolean parity; + gboolean is_separator = FALSE; + + if (tree_view->priv->row_separator_func) + { + is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, + &iter, + tree_view->priv->row_separator_data); + } - max_height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + max_height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); x_offset = -event->area.x; cell_offset = 0; @@ -3499,12 +3524,23 @@ gtk_tree_view_bin_expose (GtkWidget *widget, * level of the tree we're dropping at. */ highlight_x = cell_area.x; - _gtk_tree_view_column_cell_render (column, - event->window, - &background_area, - &cell_area, - &event->area, - flags); + if (is_separator) + gtk_paint_hline (widget->style, + event->window, + state, + &cell_area, + widget, + NULL, + cell_area.x, + cell_area.x + cell_area.width, + cell_area.y + cell_area.height / 2); + else + _gtk_tree_view_column_cell_render (column, + event->window, + &background_area, + &cell_area, + &event->area, + flags); if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT) { gint x, y; @@ -3517,12 +3553,23 @@ gtk_tree_view_bin_expose (GtkWidget *widget, } else { - _gtk_tree_view_column_cell_render (column, - event->window, - &background_area, - &cell_area, - &event->area, - flags); + if (is_separator) + gtk_paint_hline (widget->style, + event->window, + state, + &cell_area, + widget, + NULL, + cell_area.x, + cell_area.x + cell_area.width, + cell_area.y + cell_area.height / 2); + else + _gtk_tree_view_column_cell_render (column, + event->window, + &background_area, + &cell_area, + &event->area, + flags); } if (node == cursor && has_special_cell && ((column == tree_view->priv->focus_column && @@ -3579,8 +3626,9 @@ gtk_tree_view_bin_expose (GtkWidget *widget, "treeview-drop-indicator", 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node) - focus_line_width / 2, - width, MAX(BACKGROUND_HEIGHT (node), - tree_view->priv->expander_size) + width, EXPANDER_MAX(BACKGROUND_HEIGHT (node), + tree_view->priv->expander_size, + tree_view, tree, node) - focus_line_width + 1); break; } @@ -3621,8 +3669,9 @@ gtk_tree_view_bin_expose (GtkWidget *widget, 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node), width, - MAX (BACKGROUND_HEIGHT (node), - tree_view->priv->expander_size)); + EXPANDER_MAX (BACKGROUND_HEIGHT (node), + tree_view->priv->expander_size, + tree_view, tree, node)); } y_offset += max_height; @@ -4265,16 +4314,26 @@ validate_row (GtkTreeView *tree_view, gint horizontal_separator; gint depth = gtk_tree_path_get_depth (path); gboolean retval = FALSE; - + gboolean is_separator = FALSE; + gint focus_pad; + /* double check the row needs validating */ if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) && ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) return FALSE; + if (tree_view->priv->row_separator_func) + { + is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, + iter, + tree_view->priv->row_separator_data); + } + gtk_widget_style_get (GTK_WIDGET (tree_view), + "focus-padding", &focus_pad, "horizontal_separator", &horizontal_separator, NULL); - + for (list = tree_view->priv->columns; list; list = list->next) { gint tmp_width; @@ -4295,8 +4354,13 @@ validate_row (GtkTreeView *tree_view, NULL, NULL, NULL, &tmp_width, &tmp_height); - height = MAX (height, tmp_height); - height = MAX (height, tree_view->priv->expander_size); + if (!is_separator) + { + height = MAX (height, tmp_height); + height = MAX (height, tree_view->priv->expander_size); + } + else + height = 2 + 2 * focus_pad; if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view)) { @@ -4368,7 +4432,8 @@ validate_visible_area (GtkTreeView *tree_view) if (tree_view->priv->scroll_to_use_align) { - gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size); + gint height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); area_above = (total_height - height) * tree_view->priv->scroll_to_row_align; area_below = total_height - area_above - height; @@ -4382,7 +4447,8 @@ validate_visible_area (GtkTreeView *tree_view) * 2) row visible */ gint dy; - gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size); + gint height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); dy = _gtk_rbtree_node_find_offset (tree, node); @@ -4481,7 +4547,8 @@ validate_visible_area (GtkTreeView *tree_view) size_changed = TRUE; } area_above = 0; - area_below = total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size); + area_below = total_height - EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); } above_path = gtk_tree_path_copy (path); @@ -4569,7 +4636,8 @@ validate_visible_area (GtkTreeView *tree_view) } } - area_below -= MAX (new_height, tree_view->priv->expander_size); + area_below -= EXPANDER_MAX (new_height, tree_view->priv->expander_size, + tree_view, tree, node); } gtk_tree_path_free (path); @@ -4612,7 +4680,8 @@ validate_visible_area (GtkTreeView *tree_view) area_above -= new_height - old_height; } } - area_above -= MAX (new_height, tree_view->priv->expander_size); + area_above -= EXPANDER_MAX (new_height, tree_view->priv->expander_size, + tree_view, tree, node); update_dy = TRUE; } @@ -4701,8 +4770,9 @@ initialize_fixed_height_mode (GtkTreeView *tree_view) gtk_tree_path_free (path); - tree_view->priv->fixed_height = MAX (GTK_RBNODE_GET_HEIGHT (node), - tree_view->priv->expander_size); + tree_view->priv->fixed_height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), + tree_view->priv->expander_size, + tree_view, tree, node); } _gtk_rbtree_set_fixed_height (tree_view->priv->tree, @@ -4810,7 +4880,8 @@ do_validate_rows (GtkTreeView *tree_view) { gint height; - height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size); + height = EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); if (prev_height < 0) prev_height = height; else if (prev_height != height) @@ -5025,7 +5096,8 @@ gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view) return; } - if (MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size) + if (EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node) < tree_view->priv->top_row_dy) { /* new top row -- do NOT install the idle handler */ @@ -7927,7 +7999,8 @@ gtk_tree_view_queue_draw_arrow (GtkTreeView *tree_view, rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width); rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + rect.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); if (clip_rect) { @@ -7958,7 +8031,8 @@ _gtk_tree_view_queue_draw_node (GtkTreeView *tree_view, rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width); rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - rect.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + rect.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); if (clip_rect) { @@ -8183,11 +8257,13 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node); y += count * tree_view->priv->vadjustment->page_size; if (count > 0) - y -= MAX (GTK_RBNODE_GET_HEIGHT (cursor_node), - tree_view->priv->expander_size); + y -= EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (cursor_node), + tree_view->priv->expander_size, + tree_view, cursor_tree, cursor_node); else if (count < 0) - y += MAX (GTK_RBNODE_GET_HEIGHT (cursor_node), - tree_view->priv->expander_size); + y += EXPANDER_MAX (GTK_RBNODE_GET_HEIGHT (cursor_node), + tree_view->priv->expander_size, + tree_view, cursor_tree, cursor_node); y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower, (gint)tree_view->priv->vadjustment->upper - vertical_separator); if (y > tree_view->priv->height) @@ -10999,7 +11075,8 @@ gtk_tree_view_get_background_area (GtkTreeView *tree_view, rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); - rect->height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + rect->height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); } if (column) @@ -11492,6 +11569,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view, gint x = 1, y = 1; GdkDrawable *drawable; gint bin_window_width; + gboolean is_separator = FALSE; widget = GTK_WIDGET (tree_view); @@ -11509,11 +11587,19 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view, &iter, path)) return NULL; + + if (tree_view->priv->row_separator_func) + { + is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, + &iter, + tree_view->priv->row_separator_data); + } cell_offset = x; background_area.y = y; - background_area.height = MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size); + background_area.height = EXPANDER_MAX (BACKGROUND_HEIGHT (node), tree_view->priv->expander_size, + tree_view, tree, node); gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, NULL); @@ -11565,12 +11651,25 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view, } if (gtk_tree_view_column_cell_is_visible (column)) - _gtk_tree_view_column_cell_render (column, - drawable, - &background_area, - &cell_area, - &expose_area, - 0); + { + if (is_separator) + gtk_paint_hline (widget->style, + drawable, + GTK_STATE_NORMAL, + &cell_area, + widget, + NULL, + cell_area.x, + cell_area.x + cell_area.width, + cell_area.y + cell_area.height / 2); + else + _gtk_tree_view_column_cell_render (column, + drawable, + &background_area, + &cell_area, + &expose_area, + 0); + } cell_offset += column->width; } @@ -12338,3 +12437,85 @@ gtk_tree_view_get_hover_selection (GtkTreeView *tree_view) { return tree_view->priv->hover_selection; } + + +/** + * gtk_tree_view_get_row_separator_func: + * @tree_view: a #GtkTreeView + * + * Returns the current row separator function. + * + * Return value: the current row separator function. + * + * Since: 2.6 + **/ +GtkTreeViewRowSeparatorFunc +gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view) +{ + g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL); + + return tree_view->priv->row_separator_func; +} + +/** + * gtk_tree_view_set_row_separator_func: + * @tree_view: a #GtkTreeView + * @func: a #GtkTreeRowSeparatorFunc + * @data: user data to pass to @func, or %NULL + * @destroy: destroy notifier for @data, or %NULL + * + * Sets the row separator function, which is used to determine + * whether a row should be drawn as a separator. + * + * Since: 2.6 + **/ +void +gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view, + GtkTreeViewRowSeparatorFunc func, + gpointer data, + GtkDestroyNotify destroy) +{ + g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); + + if (tree_view->priv->row_separator_destroy) + (* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data); + + tree_view->priv->row_separator_func = func; + tree_view->priv->row_separator_data = data; + tree_view->priv->row_separator_destroy = destroy; +} + +static gint +check_expander_max (gint height, + gint expander_size, + GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node) +{ + if (height < expander_size) + { + gboolean is_separator = FALSE; + + if (tree_view->priv->row_separator_func) + { + GtkTreePath *path; + GtkTreeIter iter; + + path = _gtk_tree_view_find_path (tree_view, tree, node); + gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); + gtk_tree_path_free (path); + + is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, + &iter, + tree_view->priv->row_separator_data); + } + + if (!is_separator) + g_warning ("height less than expander size;\n" + "please report this in http://bugzilla.gnome.org/show_bug.cgi?id=145528\n"); + } + + return height; +} + + diff --git a/gtk/gtktreeview.h b/gtk/gtktreeview.h index 85baf95e06..d0f59174a9 100644 --- a/gtk/gtktreeview.h +++ b/gtk/gtktreeview.h @@ -124,6 +124,9 @@ typedef gboolean (*GtkTreeViewSearchEqualFunc) (GtkTreeModel *model, const gchar *key, GtkTreeIter *iter, gpointer search_data); +typedef gboolean (*GtkTreeViewRowSeparatorFunc) (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); /* Creators */ @@ -320,6 +323,12 @@ void gtk_tree_view_set_hover_selection (GtkTreeView *tree_view, gboolean hover); gboolean gtk_tree_view_get_hover_selection (GtkTreeView *tree_view); +GtkTreeViewRowSeparatorFunc gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view); +void gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view, + GtkTreeViewRowSeparatorFunc func, + gpointer data, + GtkDestroyNotify destroy); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/tests/testcombo.c b/tests/testcombo.c index 157963d583..b26f8ca50c 100644 --- a/tests/testcombo.c +++ b/tests/testcombo.c @@ -127,7 +127,7 @@ create_blaat () cellview = gtk_cell_view_new (); - store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING); + store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_BOOLEAN); pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_BUTTON, NULL); @@ -135,6 +135,7 @@ create_blaat () gtk_list_store_set (store, &iter, 0, pixbuf, 1, "gtk-stock-dialog-warning", + 2, FALSE, -1); pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_STOP, @@ -143,6 +144,7 @@ create_blaat () gtk_list_store_set (store, &iter, 0, pixbuf, 1, "gtk-stock-stop", + 2, FALSE, -1); pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_NEW, @@ -151,6 +153,7 @@ create_blaat () gtk_list_store_set (store, &iter, 0, pixbuf, 1, "gtk-stock-new", + 2, FALSE, -1); pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_CLEAR, @@ -159,6 +162,23 @@ create_blaat () gtk_list_store_set (store, &iter, 0, pixbuf, 1, "gtk-stock-clear", + 2, FALSE, + -1); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, NULL, + 1, "separator", + 2, TRUE, + -1); + + pixbuf = gtk_widget_render_icon (cellview, GTK_STOCK_OPEN, + GTK_ICON_SIZE_BUTTON, NULL); + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, pixbuf, + 1, "gtk-stock-open", + 2, FALSE, -1); gtk_widget_destroy (cellview); @@ -196,8 +216,7 @@ set_sensitive (GtkCellLayout *cell_layout, path = gtk_tree_model_get_path (tree_model, iter); indices = gtk_tree_path_get_indices (path); - - sensitive = indices[0] % 2; + sensitive = indices[0] != 1; gtk_tree_path_free (path); g_object_set (cell, "sensitive", sensitive, NULL); @@ -295,7 +314,9 @@ main (int argc, char **argv) renderer, set_sensitive, NULL, NULL); - gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 1); + gtk_combo_box_set_row_separator_column (GTK_COMBO_BOX (combobox), 2); + + gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), 0); /* GtkComboBox (grid mode) */ |