diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2004-05-27 03:31:17 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2004-05-27 03:31:17 +0000 |
commit | 310fd268e7498582755fd21bcf5428794a832bc0 (patch) | |
tree | 9323eafee5beacd4743fd73599b1a82a11658958 /gtk | |
parent | 7c200f8a9c9985c483f6293d79d8b4192e2e6a4a (diff) | |
download | gtk+-310fd268e7498582755fd21bcf5428794a832bc0.tar.gz |
Support insensitive cells in tree views and combo boxes.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkcellrenderer.c | 18 | ||||
-rw-r--r-- | gtk/gtkcellrenderer.h | 1 | ||||
-rw-r--r-- | gtk/gtkcellrendererpixbuf.c | 35 | ||||
-rw-r--r-- | gtk/gtkcellrenderertext.c | 7 | ||||
-rw-r--r-- | gtk/gtkcellrenderertoggle.c | 6 | ||||
-rw-r--r-- | gtk/gtkcellview.c | 20 | ||||
-rw-r--r-- | gtk/gtkcellview.h | 2 | ||||
-rw-r--r-- | gtk/gtkcombobox.c | 153 | ||||
-rw-r--r-- | gtk/gtktreeselection.c | 89 |
9 files changed, 303 insertions, 28 deletions
diff --git a/gtk/gtkcellrenderer.c b/gtk/gtkcellrenderer.c index 31fffdaea7..345766d5e0 100644 --- a/gtk/gtkcellrenderer.c +++ b/gtk/gtkcellrenderer.c @@ -50,6 +50,7 @@ enum { PROP_ZERO, PROP_MODE, PROP_VISIBLE, + PROP_SENSITIVE, PROP_XALIGN, PROP_YALIGN, PROP_XPAD, @@ -111,6 +112,7 @@ gtk_cell_renderer_init (GtkCellRenderer *cell) cell->yalign = 0.5; cell->xpad = 0; cell->ypad = 0; + cell->sensitive = TRUE; } static void @@ -162,8 +164,14 @@ gtk_cell_renderer_class_init (GtkCellRendererClass *class) P_("visible"), P_("Display the cell"), TRUE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", + P_("Sensitive"), + P_("Display the cell sensitive"), + TRUE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_XALIGN, @@ -293,6 +301,9 @@ gtk_cell_renderer_get_property (GObject *object, case PROP_VISIBLE: g_value_set_boolean (value, cell->visible); break; + case PROP_SENSITIVE: + g_value_set_boolean (value, cell->sensitive); + break; case PROP_XALIGN: g_value_set_float (value, cell->xalign); break; @@ -355,6 +366,9 @@ gtk_cell_renderer_set_property (GObject *object, case PROP_VISIBLE: cell->visible = g_value_get_boolean (value); break; + case PROP_SENSITIVE: + cell->sensitive = g_value_get_boolean (value); + break; case PROP_XALIGN: cell->xalign = g_value_get_float (value); break; diff --git a/gtk/gtkcellrenderer.h b/gtk/gtkcellrenderer.h index 5b681aeb97..d6cab83c45 100644 --- a/gtk/gtkcellrenderer.h +++ b/gtk/gtkcellrenderer.h @@ -71,6 +71,7 @@ struct _GtkCellRenderer guint is_expander : 1; guint is_expanded : 1; guint cell_background_set : 1; + guint sensitive : 1; }; struct _GtkCellRendererClass diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c index 43772fa9e2..61cc5e8308 100644 --- a/gtk/gtkcellrendererpixbuf.c +++ b/gtk/gtkcellrendererpixbuf.c @@ -20,6 +20,7 @@ #include <config.h> #include <stdlib.h> #include "gtkcellrendererpixbuf.h" +#include "gtkiconfactory.h" #include "gtkintl.h" static void gtk_cell_renderer_pixbuf_get_property (GObject *object, @@ -72,6 +73,7 @@ struct _GtkCellRendererPixbufPrivate gchar *stock_id; GtkIconSize stock_size; gchar *stock_detail; + GdkPixbuf *insensitive; }; @@ -201,6 +203,9 @@ gtk_cell_renderer_pixbuf_finalize (GObject *object) if (priv->stock_detail) g_free (priv->stock_detail); + if (priv->insensitive) + g_object_unref (priv->insensitive); + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } @@ -467,6 +472,36 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer *cell, pix_rect.width -= cell->xpad * 2; pix_rect.height -= cell->ypad * 2; + if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !cell->sensitive) + { + if (!priv->insensitive) + { + GtkIconSource *source; + + source = gtk_icon_source_new (); + gtk_icon_source_set_pixbuf (source, pixbuf); + /* The size here is arbitrary; since size isn't + * wildcarded in the souce, it isn't supposed to be + * scaled by the engine function + */ + gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_icon_source_set_size_wildcarded (source, FALSE); + + priv->insensitive = gtk_style_render_icon (widget->style, + source, + gtk_widget_get_direction (widget), + GTK_STATE_INSENSITIVE, + /* arbitrary */ + (GtkIconSize)-1, + widget, + "gtkcellrendererpixbuf"); + + gtk_icon_source_free (source); + } + + pixbuf = priv->insensitive; + } + if (gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) && gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) gdk_draw_pixbuf (window, diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c index c3e0900057..83745154fc 100644 --- a/gtk/gtkcellrenderertext.c +++ b/gtk/gtkcellrenderertext.c @@ -1374,8 +1374,11 @@ gtk_cell_renderer_text_render (GtkCellRenderer *cell, gtk_cell_renderer_text_get_size (cell, widget, cell_area, &x_offset, &y_offset, NULL, NULL); - - if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) + if (!cell->sensitive) + { + state = GTK_STATE_INSENSITIVE; + } + else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { if (GTK_WIDGET_HAS_FOCUS (widget)) state = GTK_STATE_SELECTED; diff --git a/gtk/gtkcellrenderertoggle.c b/gtk/gtkcellrenderertoggle.c index 7c49318693..3b2a205ca7 100644 --- a/gtk/gtkcellrenderertoggle.c +++ b/gtk/gtkcellrenderertoggle.c @@ -348,7 +348,11 @@ gtk_cell_renderer_toggle_render (GtkCellRenderer *cell, else shadow = celltoggle->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; - if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) + if (!cell->sensitive) + { + state = GTK_STATE_INSENSITIVE; + } + else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { if (GTK_WIDGET_HAS_FOCUS (widget)) state = GTK_STATE_SELECTED; diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c index 84dc2e7fdc..14600a29c1 100644 --- a/gtk/gtkcellview.c +++ b/gtk/gtkcellview.c @@ -80,7 +80,6 @@ static void gtk_cell_view_set_valuesv (GtkCellView *cel va_list args); static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview, GtkCellRenderer *renderer); -static void gtk_cell_view_set_cell_data (GtkCellView *cellview); static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout, @@ -527,7 +526,7 @@ gtk_cell_view_get_cell_info (GtkCellView *cellview, return NULL; } -static void +void gtk_cell_view_set_cell_data (GtkCellView *cellview) { GList *i; @@ -979,3 +978,20 @@ gtk_cell_view_set_background_color (GtkCellView *view, } } } + +GList * +gtk_cell_view_get_cell_renderers (GtkCellView *cell_view) +{ + GList *retval = NULL, *list; + + g_return_val_if_fail (cell_view != NULL, NULL); + + for (list = cell_view->priv->cell_list; list; list = list->next) + { + GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data; + + retval = g_list_prepend (retval, info->cell); + } + + return g_list_reverse (retval); +} diff --git a/gtk/gtkcellview.h b/gtk/gtkcellview.h index 5212b351a5..844d505f80 100644 --- a/gtk/gtkcellview.h +++ b/gtk/gtkcellview.h @@ -76,6 +76,8 @@ gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_v void gtk_cell_view_set_background_color (GtkCellView *cell_view, const GdkColor *color); +void gtk_cell_view_set_cell_data (GtkCellView *cellview); +GList *gtk_cell_view_get_cell_renderers (GtkCellView *cellview); G_END_DECLS diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index eaca7a9680..1b539226b0 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -1142,6 +1142,140 @@ gtk_combo_box_list_position (GtkComboBox *combo_box, *y -= *height; } +static gboolean +menu_row_is_sensitive (GtkComboBox *combo_box, + GtkWidget *item) +{ + GtkWidget *cell_view; + GList *cells, *list; + gboolean sensitive; + + cell_view = gtk_bin_get_child (GTK_BIN (item)); + + gtk_cell_view_set_cell_data (GTK_CELL_VIEW (cell_view)); + cells = gtk_cell_view_get_cell_renderers (GTK_CELL_VIEW (cell_view)); + + sensitive = FALSE; + list = cells; + while (list) + { + g_object_get (G_OBJECT (list->data), "sensitive", &sensitive, NULL); + + if (sensitive) + break; + + list = list->next; + } + g_list_free (cells); + + return sensitive; +} + + +static gboolean +tree_column_row_is_sensitive (GtkComboBox *combo_box, + GtkTreeIter *iter) +{ + GList *cells, *list; + gboolean sensitive; + + if (!combo_box->priv->column) + return TRUE; + + gtk_tree_view_column_cell_set_cell_data (combo_box->priv->column, + combo_box->priv->model, + iter, FALSE, FALSE); + + cells = gtk_tree_view_column_get_cell_renderers (combo_box->priv->column); + + sensitive = FALSE; + list = cells; + while (list) + { + g_object_get (G_OBJECT (list->data), "sensitive", &sensitive, NULL); + + if (sensitive) + break; + + list = list->next; + } + g_list_free (cells); + + return sensitive; +} + +static gboolean +row_is_sensitive (GtkComboBox *combo_box, + gint index) +{ + gboolean sensitive; + + if (!combo_box->priv->model) + return TRUE; + + if (GTK_IS_MENU (combo_box->priv->popup_widget)) + { + GtkWidget *item; + GList *children, *child; + + children = gtk_container_get_children (GTK_CONTAINER (combo_box->priv->popup_widget)); + child = children; + if (GTK_IS_TEAROFF_MENU_ITEM (child->data)) + child = child->next; + child = g_list_nth (child, index); + item = GTK_WIDGET (child->data); + g_list_free (children); + + sensitive = menu_row_is_sensitive (combo_box, item); + } + else + { + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_path_new_from_indices (index, -1); + if (gtk_tree_model_get_iter (combo_box->priv->model, &iter, path)) + sensitive = tree_column_row_is_sensitive (combo_box, &iter); + else + sensitive = TRUE; + + gtk_tree_path_free (path); + + } + + return sensitive; +} + +static void +update_menu_sensitivity (GtkComboBox *combo_box) +{ + gint i, items; + GtkWidget *menu; + GList *children, *child; + + if (!combo_box->priv->model) + return; + + items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); + menu = combo_box->priv->popup_widget; + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + child = children; + + if (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; + + sensitive = menu_row_is_sensitive (combo_box, item); + gtk_widget_set_sensitive (item, sensitive); + } + g_list_free (children); +} + /** * gtk_combo_box_popup: * @combo_box: a #GtkComboBox @@ -1165,6 +1299,7 @@ gtk_combo_box_popup (GtkComboBox *combo_box) if (GTK_IS_MENU (combo_box->priv->popup_widget)) { + update_menu_sensitivity (combo_box); gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), combo_box->priv->active_item); @@ -1957,7 +2092,7 @@ gtk_combo_box_menu_button_press (GtkWidget *widget, if (event->type == GDK_BUTTON_PRESS && event->button == 1) { combo_box->priv->popup_in_progress = TRUE; - + update_menu_sensitivity (combo_box); gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), combo_box->priv->active_item); @@ -2295,6 +2430,10 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) j->data, GPOINTER_TO_INT (j->next->data)); } + + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), + info->cell, info->func, info->func_data, + NULL); } if (combo_box->priv->active_item != -1) @@ -2484,22 +2623,34 @@ gtk_combo_box_key_press (GtkWidget *widget, case GDK_Down: case GDK_KP_Down: new_index = index + 1; + while (new_index < items && !row_is_sensitive (combo_box, new_index)) + new_index++; + if (new_index == items) + new_index = index; break; case GDK_Up: case GDK_KP_Up: new_index = index - 1; + while (new_index >= 0 && !row_is_sensitive (combo_box, new_index)) + new_index--; + if (new_index < 0) + new_index = index; break; case GDK_Page_Up: case GDK_KP_Page_Up: case GDK_Home: case GDK_KP_Home: new_index = 0; + while (new_index < items - 1 && !row_is_sensitive (combo_box, new_index)) + new_index++; break; case GDK_Page_Down: case GDK_KP_Page_Down: case GDK_End: case GDK_KP_End: new_index = items - 1; + while (new_index > 0 && !row_is_sensitive (combo_box, new_index)) + new_index--; break; default: return FALSE; diff --git a/gtk/gtktreeselection.c b/gtk/gtktreeselection.c index 3ba806e9cb..d0f7f0752a 100644 --- a/gtk/gtktreeselection.c +++ b/gtk/gtktreeselection.c @@ -1279,6 +1279,73 @@ gtk_tree_selection_unselect_range (GtkTreeSelection *selection, g_signal_emit (selection, tree_selection_signals[CHANGED], 0); } +static gboolean +tree_column_is_sensitive (GtkTreeViewColumn *column, + GtkTreeModel *model, + GtkTreeIter *iter) +{ + GList *cells, *list; + gboolean sensitive; + gboolean visible; + + gtk_tree_view_column_cell_set_cell_data (column, model, + iter, FALSE, FALSE); + + cells = gtk_tree_view_column_get_cell_renderers (column); + + list = cells; + while (list) + { + g_object_get (G_OBJECT (list->data), + "sensitive", &sensitive, + "visible", &visible, + NULL); + + if (visible && sensitive) + break; + + list = list->next; + } + g_list_free (cells); + + return sensitive; +} + +static gboolean +row_is_selectable (GtkTreeSelection *selection, + GtkRBNode *node, + GtkTreePath *path) +{ + GList *list; + gboolean sensitive; + + sensitive = 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; + } + + if (!sensitive) + return FALSE; + + if (selection->user_func) + return (*selection->user_func) (selection, selection->tree_view->priv->model, path, + GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), + selection->user_data); + else + return TRUE; +} + + /* Called internally by gtktreeview.c It handles actually selecting the tree. */ @@ -1328,17 +1395,7 @@ _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, { /* We only want to select the new node if we can unselect the old one, * and we can select the new one. */ - if (selection->user_func) - { - if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, - GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), - selection->user_data)) - dirty = TRUE; - } - else - { - dirty = TRUE; - } + dirty = row_is_selectable (selection, node, path); /* if dirty is FALSE, we weren't able to select the new one, otherwise, we try to * unselect the new one @@ -1455,15 +1512,7 @@ gtk_tree_selection_real_select_node (GtkTreeSelection *selection, if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) != select) { path = _gtk_tree_view_find_path (selection->tree_view, tree, node); - if (selection->user_func) - { - if ((*selection->user_func) (selection, selection->tree_view->priv->model, path, - GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED), - selection->user_data)) - selected = TRUE; - } - else - selected = TRUE; + selected = row_is_selectable (selection, node, path); gtk_tree_path_free (path); } |