Commit 310fd268 authored by Matthias Clasen's avatar Matthias Clasen

Support insensitive cells in tree views and combo boxes.

parent 7c200f8a
Wed May 26 23:26:51 2004 Matthias Clasen <maclas@gmx.de>
Support insensitive cells in tree views and combo boxes:
* gtk/gtkcellrenderer.h:
* gtk/gtkcellrenderer.c: Add a ::sensitive property.
* gtk/gtkcellrendererpixbuf.c (gtk_cell_renderer_pixbuf_render):
* gtk/gtkcellrenderertext.c (gtk_cell_renderer_text_render):
* gtk/gtkcellrenderertoggle.c (gtk_cell_renderer_toggle_render):
Support drawing insensitive.
* gtk/gtkcellview.h:
* gtk/gtkcellview.c (gtk_cell_view_get_cell_renderers): New
function to obtain the cell renderers from a cell view. Also
export gtk_cell_view_set_cell_data().
* gtk/gtktreeselection.c (tree_column_is_sensitive):
* gtk/gtktreeselection.c (row_is_selectable): Helper functions
to determine whether all visible cells in a row are insensitive
and whether a row is selectable. A row is not selectable if the
user function says so or if all visible cells are insensitive.
* gtk/gtktreeselection.c (_gtk_tree_selection_internal_select_node):
* gtk/gtktreeselection.c (gtk_tree_selection_real_select_node):
Use row_is_selectable().
* gtk/gtkcombobox.c (row_is_sensitive):
* gtk/gtkcombobox.c (tree_column_row_is_sensitive):
* gtk/gtkcombobox.c (menu_row_is_sensitive): Helper functions
to determine row sensitivity in menu or list mode.
* gtk/gtkcombobox.c (update_menu_sensitivity): Helper function
to set up sensitivity menu items from the underlying rows.
* gtk/gtkcombobox.c (gtk_combo_box_popup):
* gtk/gtkcombobox.c (gtk_combo_box_menu_button_press): Use
update_menu_sensitivity().
* gtk/gtkcombobox.c (gtk_combo_box_list_setup): Setup the cell
data funcs.
* gtk/gtkcombobox.c (gtk_combo_box_key_press): Skip insensitive
rows.
* tests/testcombo.c (main): Make some rows insensitive.
2004-05-26 Robert Ögren <gtk@roboros.com>
* gdk/win32/gdkinput-win32.c (_gdk_input_other_event): Send key
......
Wed May 26 23:26:51 2004 Matthias Clasen <maclas@gmx.de>
Support insensitive cells in tree views and combo boxes:
* gtk/gtkcellrenderer.h:
* gtk/gtkcellrenderer.c: Add a ::sensitive property.
* gtk/gtkcellrendererpixbuf.c (gtk_cell_renderer_pixbuf_render):
* gtk/gtkcellrenderertext.c (gtk_cell_renderer_text_render):
* gtk/gtkcellrenderertoggle.c (gtk_cell_renderer_toggle_render):
Support drawing insensitive.
* gtk/gtkcellview.h:
* gtk/gtkcellview.c (gtk_cell_view_get_cell_renderers): New
function to obtain the cell renderers from a cell view. Also
export gtk_cell_view_set_cell_data().
* gtk/gtktreeselection.c (tree_column_is_sensitive):
* gtk/gtktreeselection.c (row_is_selectable): Helper functions
to determine whether all visible cells in a row are insensitive
and whether a row is selectable. A row is not selectable if the
user function says so or if all visible cells are insensitive.
* gtk/gtktreeselection.c (_gtk_tree_selection_internal_select_node):
* gtk/gtktreeselection.c (gtk_tree_selection_real_select_node):
Use row_is_selectable().
* gtk/gtkcombobox.c (row_is_sensitive):
* gtk/gtkcombobox.c (tree_column_row_is_sensitive):
* gtk/gtkcombobox.c (menu_row_is_sensitive): Helper functions
to determine row sensitivity in menu or list mode.
* gtk/gtkcombobox.c (update_menu_sensitivity): Helper function
to set up sensitivity menu items from the underlying rows.
* gtk/gtkcombobox.c (gtk_combo_box_popup):
* gtk/gtkcombobox.c (gtk_combo_box_menu_button_press): Use
update_menu_sensitivity().
* gtk/gtkcombobox.c (gtk_combo_box_list_setup): Setup the cell
data funcs.
* gtk/gtkcombobox.c (gtk_combo_box_key_press): Skip insensitive
rows.
* tests/testcombo.c (main): Make some rows insensitive.
2004-05-26 Robert Ögren <gtk@roboros.com>
* gdk/win32/gdkinput-win32.c (_gdk_input_other_event): Send key
......
Wed May 26 23:26:51 2004 Matthias Clasen <maclas@gmx.de>
Support insensitive cells in tree views and combo boxes:
* gtk/gtkcellrenderer.h:
* gtk/gtkcellrenderer.c: Add a ::sensitive property.
* gtk/gtkcellrendererpixbuf.c (gtk_cell_renderer_pixbuf_render):
* gtk/gtkcellrenderertext.c (gtk_cell_renderer_text_render):
* gtk/gtkcellrenderertoggle.c (gtk_cell_renderer_toggle_render):
Support drawing insensitive.
* gtk/gtkcellview.h:
* gtk/gtkcellview.c (gtk_cell_view_get_cell_renderers): New
function to obtain the cell renderers from a cell view. Also
export gtk_cell_view_set_cell_data().
* gtk/gtktreeselection.c (tree_column_is_sensitive):
* gtk/gtktreeselection.c (row_is_selectable): Helper functions
to determine whether all visible cells in a row are insensitive
and whether a row is selectable. A row is not selectable if the
user function says so or if all visible cells are insensitive.
* gtk/gtktreeselection.c (_gtk_tree_selection_internal_select_node):
* gtk/gtktreeselection.c (gtk_tree_selection_real_select_node):
Use row_is_selectable().
* gtk/gtkcombobox.c (row_is_sensitive):
* gtk/gtkcombobox.c (tree_column_row_is_sensitive):
* gtk/gtkcombobox.c (menu_row_is_sensitive): Helper functions
to determine row sensitivity in menu or list mode.
* gtk/gtkcombobox.c (update_menu_sensitivity): Helper function
to set up sensitivity menu items from the underlying rows.
* gtk/gtkcombobox.c (gtk_combo_box_popup):
* gtk/gtkcombobox.c (gtk_combo_box_menu_button_press): Use
update_menu_sensitivity().
* gtk/gtkcombobox.c (gtk_combo_box_list_setup): Setup the cell
data funcs.
* gtk/gtkcombobox.c (gtk_combo_box_key_press): Skip insensitive
rows.
* tests/testcombo.c (main): Make some rows insensitive.
2004-05-26 Robert Ögren <gtk@roboros.com>
* gdk/win32/gdkinput-win32.c (_gdk_input_other_event): Send key
......
Wed May 26 23:26:51 2004 Matthias Clasen <maclas@gmx.de>
Support insensitive cells in tree views and combo boxes:
* gtk/gtkcellrenderer.h:
* gtk/gtkcellrenderer.c: Add a ::sensitive property.
* gtk/gtkcellrendererpixbuf.c (gtk_cell_renderer_pixbuf_render):
* gtk/gtkcellrenderertext.c (gtk_cell_renderer_text_render):
* gtk/gtkcellrenderertoggle.c (gtk_cell_renderer_toggle_render):
Support drawing insensitive.
* gtk/gtkcellview.h:
* gtk/gtkcellview.c (gtk_cell_view_get_cell_renderers): New
function to obtain the cell renderers from a cell view. Also
export gtk_cell_view_set_cell_data().
* gtk/gtktreeselection.c (tree_column_is_sensitive):
* gtk/gtktreeselection.c (row_is_selectable): Helper functions
to determine whether all visible cells in a row are insensitive
and whether a row is selectable. A row is not selectable if the
user function says so or if all visible cells are insensitive.
* gtk/gtktreeselection.c (_gtk_tree_selection_internal_select_node):
* gtk/gtktreeselection.c (gtk_tree_selection_real_select_node):
Use row_is_selectable().
* gtk/gtkcombobox.c (row_is_sensitive):
* gtk/gtkcombobox.c (tree_column_row_is_sensitive):
* gtk/gtkcombobox.c (menu_row_is_sensitive): Helper functions
to determine row sensitivity in menu or list mode.
* gtk/gtkcombobox.c (update_menu_sensitivity): Helper function
to set up sensitivity menu items from the underlying rows.
* gtk/gtkcombobox.c (gtk_combo_box_popup):
* gtk/gtkcombobox.c (gtk_combo_box_menu_button_press): Use
update_menu_sensitivity().
* gtk/gtkcombobox.c (gtk_combo_box_list_setup): Setup the cell
data funcs.
* gtk/gtkcombobox.c (gtk_combo_box_key_press): Skip insensitive
rows.
* tests/testcombo.c (main): Make some rows insensitive.
2004-05-26 Robert Ögren <gtk@roboros.com>
* gdk/win32/gdkinput-win32.c (_gdk_input_other_event): Send key
......
......@@ -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;
......
......@@ -71,6 +71,7 @@ struct _GtkCellRenderer
guint is_expander : 1;
guint is_expanded : 1;
guint cell_background_set : 1;
guint sensitive : 1;
};
struct _GtkCellRendererClass
......
......@@ -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,
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
}
......@@ -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
......
......@@ -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;
......
<
......@@ -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))