X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=tests%2Fcellareascaffold.c;h=cfd7185780f3e671b5844db3333f71998f87ca9e;hb=f59b9e52d44a44a30a703c3d0590fbf93f3a2f62;hp=6d40be9edd15909cae7f80ddec406ede634b85a7;hpb=f330b40521cf1f5b2b33b33bf7c5df0f59355838;p=~andy%2Fgtk diff --git a/tests/cellareascaffold.c b/tests/cellareascaffold.c index 6d40be9ed..cfd718578 100644 --- a/tests/cellareascaffold.c +++ b/tests/cellareascaffold.c @@ -27,14 +27,6 @@ /* GObjectClass */ static void cell_area_scaffold_finalize (GObject *object); static void cell_area_scaffold_dispose (GObject *object); -static void cell_area_scaffold_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void cell_area_scaffold_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); /* GtkWidgetClass */ static void cell_area_scaffold_realize (GtkWidget *widget); @@ -57,35 +49,67 @@ static void cell_area_scaffold_get_preferred_width_for_height (GtkWidget gint for_size, gint *minimum_size, gint *natural_size); +static void cell_area_scaffold_map (GtkWidget *widget); +static void cell_area_scaffold_unmap (GtkWidget *widget); static gint cell_area_scaffold_focus (GtkWidget *widget, GtkDirectionType direction); +static gboolean cell_area_scaffold_button_press (GtkWidget *widget, + GdkEventButton *event); + +/* GtkContainerClass */ +static void cell_area_scaffold_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static void cell_area_scaffold_remove (GtkContainer *container, + GtkWidget *child); +static void cell_area_scaffold_put_edit_widget (CellAreaScaffold *scaffold, + GtkWidget *edit_widget, + gint x, + gint y, + gint width, + gint height); /* CellAreaScaffoldClass */ static void cell_area_scaffold_activate (CellAreaScaffold *scaffold); /* CellArea/GtkTreeModel callbacks */ -static void size_changed_cb (GtkCellAreaIter *iter, +static void size_changed_cb (GtkCellAreaContext *context, GParamSpec *pspec, CellAreaScaffold *scaffold); +static void focus_changed_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + const gchar *path, + CellAreaScaffold *scaffold); +static void add_editable_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + GdkRectangle *cell_area, + const gchar *path, + CellAreaScaffold *scaffold); +static void remove_editable_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + CellAreaScaffold *scaffold); static void row_changed_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, CellAreaScaffold *scaffold); -static void row_inserted_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - CellAreaScaffold *scaffold); -static void row_deleted_cb (GtkTreeModel *model, - GtkTreePath *path, - CellAreaScaffold *scaffold); -static void rows_reordered_cb (GtkTreeModel *model, - GtkTreePath *parent, - GtkTreeIter *iter, - gint *new_order, - CellAreaScaffold *scaffold); +static void row_inserted_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + CellAreaScaffold *scaffold); +static void row_deleted_cb (GtkTreeModel *model, + GtkTreePath *path, + CellAreaScaffold *scaffold); +static void rows_reordered_cb (GtkTreeModel *model, + GtkTreePath *parent, + GtkTreeIter *iter, + gint *new_order, + CellAreaScaffold *scaffold); typedef struct { - gint size; /* The size of the row in the scaffold's opposing orientation */ + gint size; /* The height of rows in the scaffold's */ } RowData; struct _CellAreaScaffoldPrivate { @@ -100,26 +124,30 @@ struct _CellAreaScaffoldPrivate { gulong row_deleted_id; gulong rows_reordered_id; - /* The area rendering the data and a global iter */ - GtkCellArea *area; - GtkCellAreaIter *iter; + /* The area rendering the data and a global context */ + GtkCellArea *area; + GtkCellAreaContext *context; /* Cache some info about rows (hieghts etc) */ GArray *row_data; /* Focus handling */ gint focus_row; + gulong focus_changed_id; /* Check when the underlying area changes the size and * we need to queue a redraw */ gulong size_changed_id; + /* Currently edited widget */ + GtkWidget *edit_widget; + GdkRectangle edit_rect; + gulong add_editable_id; + gulong remove_editable_id; -}; -enum { - PROP_0, - PROP_ORIENTATION + gint row_spacing; + gint indent; }; enum { @@ -129,8 +157,6 @@ enum { static guint scaffold_signals[N_SIGNALS] = { 0 }; -#define ROW_SPACING 2 - #define DIRECTION_STR(dir) \ ((dir) == GTK_DIR_TAB_FORWARD ? "tab forward" : \ (dir) == GTK_DIR_TAB_BACKWARD ? "tab backward" : \ @@ -139,7 +165,7 @@ static guint scaffold_signals[N_SIGNALS] = { 0 }; (dir) == GTK_DIR_LEFT ? "left" : \ (dir) == GTK_DIR_RIGHT ? "right" : "invalid") -G_DEFINE_TYPE_WITH_CODE (CellAreaScaffold, cell_area_scaffold, GTK_TYPE_WIDGET, +G_DEFINE_TYPE_WITH_CODE (CellAreaScaffold, cell_area_scaffold, GTK_TYPE_CONTAINER, G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)); @@ -153,8 +179,8 @@ cell_area_scaffold_init (CellAreaScaffold *scaffold) CellAreaScaffoldPrivate); priv = scaffold->priv; - priv->area = gtk_cell_area_box_new (); - priv->iter = gtk_cell_area_create_iter (priv->area); + priv->area = gtk_cell_area_box_new (); + priv->context = gtk_cell_area_create_context (priv->area); priv->row_data = g_array_new (FALSE, FALSE, sizeof (RowData)); @@ -162,23 +188,34 @@ cell_area_scaffold_init (CellAreaScaffold *scaffold) gtk_widget_set_can_focus (GTK_WIDGET (scaffold), TRUE); priv->size_changed_id = - g_signal_connect (priv->iter, "notify", + g_signal_connect (priv->context, "notify", G_CALLBACK (size_changed_cb), scaffold); + + priv->focus_changed_id = + g_signal_connect (priv->area, "focus-changed", + G_CALLBACK (focus_changed_cb), scaffold); + + priv->add_editable_id = + g_signal_connect (priv->area, "add-editable", + G_CALLBACK (add_editable_cb), scaffold); + + priv->remove_editable_id = + g_signal_connect (priv->area, "remove-editable", + G_CALLBACK (remove_editable_cb), scaffold); } static void cell_area_scaffold_class_init (CellAreaScaffoldClass *class) { - GObjectClass *gobject_class; - GtkWidgetClass *widget_class; + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; - gobject_class = G_OBJECT_CLASS(class); + gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = cell_area_scaffold_dispose; gobject_class->finalize = cell_area_scaffold_finalize; - gobject_class->get_property = cell_area_scaffold_get_property; - gobject_class->set_property = cell_area_scaffold_set_property; - widget_class = GTK_WIDGET_CLASS(class); + widget_class = GTK_WIDGET_CLASS (class); widget_class->realize = cell_area_scaffold_realize; widget_class->unrealize = cell_area_scaffold_unrealize; widget_class->draw = cell_area_scaffold_draw; @@ -187,11 +224,16 @@ cell_area_scaffold_class_init (CellAreaScaffoldClass *class) widget_class->get_preferred_height_for_width = cell_area_scaffold_get_preferred_height_for_width; widget_class->get_preferred_height = cell_area_scaffold_get_preferred_height; widget_class->get_preferred_width_for_height = cell_area_scaffold_get_preferred_width_for_height; + widget_class->map = cell_area_scaffold_map; + widget_class->unmap = cell_area_scaffold_unmap; widget_class->focus = cell_area_scaffold_focus; + widget_class->button_press_event = cell_area_scaffold_button_press; - class->activate = cell_area_scaffold_activate; + container_class = GTK_CONTAINER_CLASS (class); + container_class->forall = cell_area_scaffold_forall; + container_class->remove = cell_area_scaffold_remove; - g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation"); + class->activate = cell_area_scaffold_activate; scaffold_signals[ACTIVATE] = g_signal_new ("activate", @@ -233,72 +275,31 @@ cell_area_scaffold_dispose (GObject *object) cell_area_scaffold_set_model (scaffold, NULL); - if (priv->iter) + if (priv->context) { /* Disconnect signals */ - g_signal_handler_disconnect (priv->iter, priv->size_changed_id); + g_signal_handler_disconnect (priv->context, priv->size_changed_id); - g_object_unref (priv->iter); - priv->iter = NULL; + g_object_unref (priv->context); + priv->context = NULL; priv->size_changed_id = 0; } if (priv->area) { /* Disconnect signals */ + g_signal_handler_disconnect (priv->area, priv->focus_changed_id); + g_signal_handler_disconnect (priv->area, priv->add_editable_id); + g_signal_handler_disconnect (priv->area, priv->remove_editable_id); + g_object_unref (priv->area); priv->area = NULL; + priv->focus_changed_id = 0; } G_OBJECT_CLASS (cell_area_scaffold_parent_class)->dispose (object); } -static void -cell_area_scaffold_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (object); - CellAreaScaffoldPrivate *priv; - - priv = scaffold->priv; - - switch (prop_id) - { - case PROP_ORIENTATION: - gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->area), - g_value_get_enum (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -cell_area_scaffold_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (object); - CellAreaScaffoldPrivate *priv; - - priv = scaffold->priv; - - switch (prop_id) - { - case PROP_ORIENTATION: - g_value_set_enum (value, - gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - /********************************************************* * GtkWidgetClass * *********************************************************/ @@ -334,11 +335,8 @@ cell_area_scaffold_realize (GtkWidget *widget) gtk_widget_set_window (widget, window); g_object_ref (window); - priv->event_window = gdk_window_new (window, - &attributes, attributes_mask); + priv->event_window = gdk_window_new (window, &attributes, attributes_mask); gdk_window_set_user_data (priv->event_window, widget); - - gtk_widget_style_attach (widget); } static void @@ -363,9 +361,9 @@ cell_area_scaffold_draw (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; GtkTreeIter iter; gboolean valid; + GdkRectangle background_area; GdkRectangle render_area; GtkAllocation allocation; gint i = 0; @@ -376,7 +374,6 @@ cell_area_scaffold_draw (GtkWidget *widget, return FALSE; have_focus = gtk_widget_has_focus (widget); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); gtk_widget_get_allocation (widget, &allocation); @@ -385,6 +382,11 @@ cell_area_scaffold_draw (GtkWidget *widget, render_area.width = allocation.width; render_area.height = allocation.height; + background_area = render_area; + + render_area.x = priv->indent; + render_area.width -= priv->indent; + valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) { @@ -395,35 +397,42 @@ cell_area_scaffold_draw (GtkWidget *widget, else flags = 0; - if (orientation == GTK_ORIENTATION_HORIZONTAL) + render_area.height = data->size; + + background_area.height = render_area.height; + background_area.y = render_area.y; + + if (i == 0) + { + background_area.height += priv->row_spacing / 2; + background_area.height += priv->row_spacing % 2; + } + else if (i == priv->row_data->len - 1) { - render_area.height = data->size; + background_area.y -= priv->row_spacing / 2; + background_area.height += priv->row_spacing / 2; } else { - render_area.width = data->size; + background_area.y -= priv->row_spacing / 2; + background_area.height += priv->row_spacing; } gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE); - gtk_cell_area_render (priv->area, priv->iter, widget, cr, - &render_area, &render_area, flags, + gtk_cell_area_render (priv->area, priv->context, widget, cr, + &background_area, &render_area, flags, (have_focus && i == priv->focus_row)); - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - render_area.y += data->size; - render_area.y += ROW_SPACING; - } - else - { - render_area.x += data->size; - render_area.x += ROW_SPACING; - } + render_area.y += data->size; + render_area.y += priv->row_spacing; i++; valid = gtk_tree_model_iter_next (priv->model, &iter); } + /* Draw the edit widget after drawing everything else */ + GTK_WIDGET_CLASS (cell_area_scaffold_parent_class)->draw (widget, cr); + return FALSE; } @@ -432,16 +441,13 @@ request_all_base (CellAreaScaffold *scaffold) { CellAreaScaffoldPrivate *priv = scaffold->priv; GtkWidget *widget = GTK_WIDGET (scaffold); - GtkOrientation orientation; GtkTreeIter iter; gboolean valid; if (!priv->model) return; - g_signal_handler_block (priv->iter, priv->size_changed_id); - - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); + g_signal_handler_block (priv->context, priv->size_changed_id); valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) @@ -449,21 +455,12 @@ request_all_base (CellAreaScaffold *scaffold) gint min, nat; gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_get_preferred_width (priv->area, priv->iter, widget, &min, &nat); - else - gtk_cell_area_get_preferred_height (priv->area, priv->iter, widget, &min, &nat); + gtk_cell_area_get_preferred_width (priv->area, priv->context, widget, &min, &nat); valid = gtk_tree_model_iter_next (priv->model, &iter); } - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_iter_sum_preferred_width (priv->iter); - else - gtk_cell_area_iter_sum_preferred_height (priv->iter); - - g_signal_handler_unblock (priv->iter, priv->size_changed_id); + g_signal_handler_unblock (priv->context, priv->size_changed_id); } static void @@ -473,7 +470,6 @@ get_row_sizes (CellAreaScaffold *scaffold, { CellAreaScaffoldPrivate *priv = scaffold->priv; GtkWidget *widget = GTK_WIDGET (scaffold); - GtkOrientation orientation; GtkTreeIter iter; gboolean valid; gint i = 0; @@ -481,21 +477,14 @@ get_row_sizes (CellAreaScaffold *scaffold, if (!priv->model) return; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) { RowData *data = &g_array_index (array, RowData, i); gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_get_preferred_height_for_width (priv->area, priv->iter, widget, - for_size, &data->size, NULL); - else - gtk_cell_area_get_preferred_width_for_height (priv->area, priv->iter, widget, - for_size, &data->size, NULL); + gtk_cell_area_get_preferred_height_for_width (priv->area, priv->context, widget, + for_size, &data->size, NULL); i++; valid = gtk_tree_model_iter_next (priv->model, &iter); @@ -508,10 +497,6 @@ cell_area_scaffold_size_allocate (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; - - if (!priv->model) - return; gtk_widget_set_allocation (widget, allocation); @@ -522,19 +507,16 @@ cell_area_scaffold_size_allocate (GtkWidget *widget, allocation->width, allocation->height); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); + /* Allocate the child GtkCellEditable widget if one is currently editing a row */ + if (priv->edit_widget) + gtk_widget_size_allocate (priv->edit_widget, &priv->edit_rect); - /* Cache the per-row sizes and allocate the iter */ - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - get_row_sizes (scaffold, priv->row_data, allocation->width); - gtk_cell_area_iter_allocate_width (priv->iter, allocation->width); - } - else - { - get_row_sizes (scaffold, priv->row_data, allocation->height); - gtk_cell_area_iter_allocate_height (priv->iter, allocation->height); - } + if (!priv->model) + return; + + /* Cache the per-row sizes and allocate the context */ + gtk_cell_area_context_allocate (priv->context, allocation->width - priv->indent, -1); + get_row_sizes (scaffold, priv->row_data, allocation->width - priv->indent); } @@ -545,27 +527,15 @@ cell_area_scaffold_get_preferred_width (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; if (!priv->model) return; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - request_all_base (scaffold); - - gtk_cell_area_iter_get_preferred_width (priv->iter, minimum_size, natural_size); - } - else - { - gint min_size, nat_size; - - GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size); - GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, min_size, - minimum_size, natural_size); - } + request_all_base (scaffold); + gtk_cell_area_context_get_preferred_width (priv->context, minimum_size, natural_size); + + *minimum_size += priv->indent; + *natural_size += priv->indent; } static void @@ -576,47 +546,36 @@ cell_area_scaffold_get_preferred_height_for_width (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; + GArray *request_array; + gint n_rows, i, full_size = 0; if (!priv->model) return; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - GArray *request_array; - gint n_rows, i, full_size = 0; - - n_rows = gtk_tree_model_iter_n_children (priv->model, NULL); - - /* Get an array for the contextual request */ - request_array = g_array_new (FALSE, FALSE, sizeof (RowData)); - g_array_set_size (request_array, n_rows); - memset (request_array->data, 0x0, n_rows * sizeof (RowData)); + n_rows = gtk_tree_model_iter_n_children (priv->model, NULL); - /* Gather each contextual size into the request array */ - get_row_sizes (scaffold, request_array, for_size); + /* Get an array for the contextual request */ + request_array = g_array_new (FALSE, FALSE, sizeof (RowData)); + g_array_set_size (request_array, n_rows); + memset (request_array->data, 0x0, n_rows * sizeof (RowData)); - /* Sum up the size and add some row spacing */ - for (i = 0; i < n_rows; i++) - { - RowData *data = &g_array_index (request_array, RowData, i); - - full_size += data->size; - } - - full_size += MAX (0, n_rows -1) * ROW_SPACING; - - g_array_free (request_array, TRUE); + /* Gather each contextual size into the request array */ + get_row_sizes (scaffold, request_array, for_size - priv->indent); - *minimum_size = full_size; - *natural_size = full_size; - } - else + /* Sum up the size and add some row spacing */ + for (i = 0; i < n_rows; i++) { - GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_size, natural_size); + RowData *data = &g_array_index (request_array, RowData, i); + + full_size += data->size; } + + full_size += MAX (0, n_rows -1) * priv->row_spacing; + + g_array_free (request_array, TRUE); + + *minimum_size = full_size; + *natural_size = full_size; } static void @@ -626,27 +585,14 @@ cell_area_scaffold_get_preferred_height (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; + gint min_size, nat_size; if (!priv->model) return; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - - if (orientation == GTK_ORIENTATION_VERTICAL) - { - request_all_base (scaffold); - - gtk_cell_area_iter_get_preferred_height (priv->iter, minimum_size, natural_size); - } - else - { - gint min_size, nat_size; - - GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size); - GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_size, - minimum_size, natural_size); - } + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_size, + minimum_size, natural_size); } static void @@ -657,49 +603,38 @@ cell_area_scaffold_get_preferred_width_for_height (GtkWidget *widget, { CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); CellAreaScaffoldPrivate *priv = scaffold->priv; - GtkOrientation orientation; if (!priv->model) return; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - - if (orientation == GTK_ORIENTATION_VERTICAL) - { - GArray *request_array; - gint n_rows, i, full_size = 0; - - n_rows = gtk_tree_model_iter_n_children (priv->model, NULL); - - /* Get an array for the contextual request */ - request_array = g_array_new (FALSE, FALSE, sizeof (RowData)); - g_array_set_size (request_array, n_rows); - memset (request_array->data, 0x0, n_rows * sizeof (RowData)); - - /* Gather each contextual size into the request array */ - get_row_sizes (scaffold, request_array, for_size); - - /* Sum up the size and add some row spacing */ - for (i = 0; i < n_rows; i++) - { - RowData *data = &g_array_index (request_array, RowData, i); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_size, natural_size); +} - full_size += data->size; - } +static void +cell_area_scaffold_map (GtkWidget *widget) +{ + CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); + CellAreaScaffoldPrivate *priv = scaffold->priv; + + GTK_WIDGET_CLASS (cell_area_scaffold_parent_class)->map (widget); - full_size += MAX (0, n_rows -1) * ROW_SPACING; + if (priv->event_window) + gdk_window_show (priv->event_window); +} - g_array_free (request_array, TRUE); +static void +cell_area_scaffold_unmap (GtkWidget *widget) +{ + CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); + CellAreaScaffoldPrivate *priv = scaffold->priv; + + GTK_WIDGET_CLASS (cell_area_scaffold_parent_class)->unmap (widget); - *minimum_size = full_size; - *natural_size = full_size; - } - else - { - GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_size, natural_size); - } + if (priv->event_window) + gdk_window_hide (priv->event_window); } + static gint cell_area_scaffold_focus (GtkWidget *widget, GtkDirectionType direction) @@ -709,16 +644,16 @@ cell_area_scaffold_focus (GtkWidget *widget, GtkTreeIter iter; gboolean valid; gint focus_row; - GtkOrientation orientation; + gboolean changed = FALSE; /* Grab focus on ourself if we dont already have focus */ if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); /* Move focus from cell to cell and row to row */ - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); - focus_row = priv->focus_row; + + g_signal_handler_block (priv->area, priv->focus_changed_id); valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, priv->focus_row); while (valid) @@ -733,80 +668,148 @@ cell_area_scaffold_focus (GtkWidget *widget, /* XXX A smarter implementation would only invalidate the rectangles where * focus was removed from and new focus was placed */ gtk_widget_queue_draw (widget); - return TRUE; + changed = TRUE; + break; } else { - if (orientation == GTK_ORIENTATION_HORIZONTAL) + if (direction == GTK_DIR_RIGHT || + direction == GTK_DIR_LEFT) + break; + else if (direction == GTK_DIR_UP || + direction == GTK_DIR_TAB_BACKWARD) { - if (direction == GTK_DIR_RIGHT || - direction == GTK_DIR_LEFT) + if (focus_row == 0) break; - else if (direction == GTK_DIR_UP || - direction == GTK_DIR_TAB_BACKWARD) + else { - if (focus_row == 0) - break; - else - { - /* XXX A real implementation should check if the - * previous row can focus with it's attributes setup */ - focus_row--; - valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, focus_row); - } - } - else /* direction == GTK_DIR_DOWN || GTK_DIR_TAB_FORWARD */ - { - if (focus_row == priv->row_data->len - 1) - break; - else - { - /* XXX A real implementation should check if the - * previous row can focus with it's attributes setup */ - focus_row++; - valid = gtk_tree_model_iter_next (priv->model, &iter); - } + /* XXX A real implementation should check if the + * previous row can focus with its attributes setup */ + focus_row--; + valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, focus_row); } } - else /* (orientation == GTK_ORIENTATION_HORIZONTAL) */ + else /* direction == GTK_DIR_DOWN || GTK_DIR_TAB_FORWARD */ { - if (direction == GTK_DIR_UP || - direction == GTK_DIR_DOWN) + if (focus_row == priv->row_data->len - 1) break; - else if (direction == GTK_DIR_LEFT || - direction == GTK_DIR_TAB_BACKWARD) - { - if (focus_row == 0) - break; - else - { - /* XXX A real implementation should check if the - * previous row can focus with it's attributes setup */ - focus_row--; - valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, focus_row); - } - } - else /* direction == GTK_DIR_RIGHT || GTK_DIR_TAB_FORWARD */ + else { - if (focus_row == priv->row_data->len - 1) - break; - else - { - /* XXX A real implementation should check if the - * previous row can focus with it's attributes setup */ - focus_row++; - valid = gtk_tree_model_iter_next (priv->model, &iter); - } + /* XXX A real implementation should check if the + * previous row can focus with its attributes setup */ + focus_row++; + valid = gtk_tree_model_iter_next (priv->model, &iter); } } } } + g_signal_handler_unblock (priv->area, priv->focus_changed_id); + /* XXX A smarter implementation would only invalidate the rectangles where * focus was removed from and new focus was placed */ gtk_widget_queue_draw (widget); - return FALSE; + return changed; +} + +static gboolean +cell_area_scaffold_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (widget); + CellAreaScaffoldPrivate *priv = scaffold->priv; + GtkTreeIter iter; + gboolean valid; + gint i = 0; + GdkRectangle event_area; + GtkAllocation allocation; + gboolean handled = FALSE; + + gtk_widget_get_allocation (widget, &allocation); + + event_area.x = 0; + event_area.y = 0; + event_area.width = allocation.width; + event_area.height = allocation.height; + + event_area.x = priv->indent; + event_area.width -= priv->indent; + + valid = gtk_tree_model_get_iter_first (priv->model, &iter); + while (valid) + { + RowData *data = &g_array_index (priv->row_data, RowData, i); + + event_area.height = data->size; + + if (event->y >= event_area.y && + event->y <= event_area.y + event_area.height) + { + /* XXX A real implementation would assemble GtkCellRendererState flags here */ + gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE); + handled = gtk_cell_area_event (priv->area, priv->context, GTK_WIDGET (scaffold), + (GdkEvent *)event, &event_area, 0); + break; + } + + event_area.y += data->size; + event_area.y += priv->row_spacing; + + i++; + valid = gtk_tree_model_iter_next (priv->model, &iter); + } + + return handled; +} + + +/********************************************************* + * GtkContainerClass * + *********************************************************/ +static void +cell_area_scaffold_put_edit_widget (CellAreaScaffold *scaffold, + GtkWidget *edit_widget, + gint x, + gint y, + gint width, + gint height) +{ + CellAreaScaffoldPrivate *priv = scaffold->priv; + + priv->edit_rect.x = x; + priv->edit_rect.y = y; + priv->edit_rect.width = width; + priv->edit_rect.height = height; + priv->edit_widget = edit_widget; + + gtk_widget_set_parent (edit_widget, GTK_WIDGET (scaffold)); +} + +static void +cell_area_scaffold_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (container); + CellAreaScaffoldPrivate *priv = scaffold->priv; + + if (priv->edit_widget) + (* callback) (priv->edit_widget, callback_data); +} + +static void +cell_area_scaffold_remove (GtkContainer *container, + GtkWidget *child) +{ + CellAreaScaffold *scaffold = CELL_AREA_SCAFFOLD (container); + CellAreaScaffoldPrivate *priv = scaffold->priv; + + g_return_if_fail (child == priv->edit_widget); + + gtk_widget_unparent (priv->edit_widget); + priv->edit_widget = NULL; } /********************************************************* @@ -818,13 +821,11 @@ cell_area_scaffold_activate (CellAreaScaffold *scaffold) CellAreaScaffoldPrivate *priv = scaffold->priv; GtkWidget *widget = GTK_WIDGET (scaffold); GtkAllocation allocation; - GtkOrientation orientation; GdkRectangle cell_area; GtkTreeIter iter; gboolean valid; gint i = 0; - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (priv->area)); gtk_widget_get_allocation (widget, &allocation); cell_area.x = 0; @@ -832,6 +833,9 @@ cell_area_scaffold_activate (CellAreaScaffold *scaffold) cell_area.width = allocation.width; cell_area.height = allocation.height; + cell_area.x = priv->indent; + cell_area.width -= priv->indent; + valid = gtk_tree_model_get_iter_first (priv->model, &iter); while (valid) { @@ -839,21 +843,16 @@ cell_area_scaffold_activate (CellAreaScaffold *scaffold) if (i == priv->focus_row) { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - cell_area.height = data->size; - else - cell_area.width = data->size; + cell_area.height = data->size; gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE); - gtk_cell_area_activate (priv->area, priv->iter, widget, &cell_area, GTK_CELL_RENDERER_FOCUSED); + gtk_cell_area_activate (priv->area, priv->context, widget, &cell_area, + GTK_CELL_RENDERER_FOCUSED, FALSE); break; } - if (orientation == GTK_ORIENTATION_HORIZONTAL) - cell_area.y += data->size + ROW_SPACING; - else - cell_area.x += data->size + ROW_SPACING; + cell_area.y += data->size + priv->row_spacing; i++; valid = gtk_tree_model_iter_next (priv->model, &iter); @@ -864,9 +863,9 @@ cell_area_scaffold_activate (CellAreaScaffold *scaffold) * CellArea/GtkTreeModel callbacks * *********************************************************/ static void -size_changed_cb (GtkCellAreaIter *iter, - GParamSpec *pspec, - CellAreaScaffold *scaffold) +size_changed_cb (GtkCellAreaContext *context, + GParamSpec *pspec, + CellAreaScaffold *scaffold) { if (!strcmp (pspec->name, "minimum-width") || !strcmp (pspec->name, "natural-width") || @@ -875,8 +874,70 @@ size_changed_cb (GtkCellAreaIter *iter, gtk_widget_queue_resize (GTK_WIDGET (scaffold)); } +static void +focus_changed_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + const gchar *path, + CellAreaScaffold *scaffold) +{ + CellAreaScaffoldPrivate *priv = scaffold->priv; + GtkWidget *widget = GTK_WIDGET (scaffold); + GtkTreePath *treepath; + gint *indices; + + if (!priv->model) + return; + + /* We can be signaled that a renderer lost focus, here + * we dont care */ + if (!renderer) + return; + + treepath = gtk_tree_path_new_from_string (path); + indices = gtk_tree_path_get_indices (treepath); + + priv->focus_row = indices[0]; + + gtk_tree_path_free (treepath); + + /* Make sure we have focus now */ + if (!gtk_widget_has_focus (widget)) + gtk_widget_grab_focus (widget); + + gtk_widget_queue_draw (widget); +} + +static void +add_editable_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + GdkRectangle *cell_area, + const gchar *path, + CellAreaScaffold *scaffold) +{ + GtkAllocation allocation; + + gtk_widget_get_allocation (GTK_WIDGET (scaffold), &allocation); + + cell_area_scaffold_put_edit_widget (scaffold, GTK_WIDGET (edit_widget), + allocation.x + cell_area->x, + allocation.y + cell_area->y, + cell_area->width, cell_area->height); +} + +static void +remove_editable_cb (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + CellAreaScaffold *scaffold) +{ + gtk_container_remove (GTK_CONTAINER (scaffold), GTK_WIDGET (edit_widget)); + + gtk_widget_grab_focus (GTK_WIDGET (scaffold)); +} + static void -rebuild_and_flush_internals (CellAreaScaffold *scaffold) +rebuild_and_reset_internals (CellAreaScaffold *scaffold) { CellAreaScaffoldPrivate *priv = scaffold->priv; gint n_rows; @@ -892,9 +953,9 @@ rebuild_and_flush_internals (CellAreaScaffold *scaffold) else g_array_set_size (priv->row_data, 0); - /* Data changed, lets flush the iter and consequently queue resize and + /* Data changed, lets reset the context and consequently queue resize and * start everything over again (note this is definitly far from optimized) */ - gtk_cell_area_iter_flush (priv->iter); + gtk_cell_area_context_reset (priv->context); } static void @@ -903,7 +964,7 @@ row_changed_cb (GtkTreeModel *model, GtkTreeIter *iter, CellAreaScaffold *scaffold) { - rebuild_and_flush_internals (scaffold); + rebuild_and_reset_internals (scaffold); } static void @@ -912,7 +973,7 @@ row_inserted_cb (GtkTreeModel *model, GtkTreeIter *iter, CellAreaScaffold *scaffold) { - rebuild_and_flush_internals (scaffold); + rebuild_and_reset_internals (scaffold); } static void @@ -920,7 +981,7 @@ row_deleted_cb (GtkTreeModel *model, GtkTreePath *path, CellAreaScaffold *scaffold) { - rebuild_and_flush_internals (scaffold); + rebuild_and_reset_internals (scaffold); } static void @@ -930,7 +991,7 @@ rows_reordered_cb (GtkTreeModel *model, gint *new_order, CellAreaScaffold *scaffold) { - rebuild_and_flush_internals (scaffold); + rebuild_and_reset_internals (scaffold); } /********************************************************* @@ -999,7 +1060,7 @@ cell_area_scaffold_set_model (CellAreaScaffold *scaffold, G_CALLBACK (rows_reordered_cb), scaffold); } - rebuild_and_flush_internals (scaffold); + rebuild_and_reset_internals (scaffold); } } @@ -1014,3 +1075,64 @@ cell_area_scaffold_get_model (CellAreaScaffold *scaffold) return priv->model; } + + +void +cell_area_scaffold_set_row_spacing (CellAreaScaffold *scaffold, + gint spacing) +{ + CellAreaScaffoldPrivate *priv; + + g_return_if_fail (IS_CELL_AREA_SCAFFOLD (scaffold)); + + priv = scaffold->priv; + + if (priv->row_spacing != spacing) + { + priv->row_spacing = spacing; + gtk_widget_queue_resize (GTK_WIDGET (scaffold)); + } +} + +gint +cell_area_scaffold_get_row_spacing (CellAreaScaffold *scaffold) +{ + CellAreaScaffoldPrivate *priv; + + g_return_val_if_fail (IS_CELL_AREA_SCAFFOLD (scaffold), 0); + + priv = scaffold->priv; + + return priv->row_spacing; +} + +void +cell_area_scaffold_set_indentation (CellAreaScaffold *scaffold, + gint indent) +{ + CellAreaScaffoldPrivate *priv; + + g_return_if_fail (IS_CELL_AREA_SCAFFOLD (scaffold)); + + priv = scaffold->priv; + + if (priv->indent != indent) + { + priv->indent = indent; + gtk_widget_queue_resize (GTK_WIDGET (scaffold)); + } +} + +gint +cell_area_scaffold_get_indentation (CellAreaScaffold *scaffold) +{ + CellAreaScaffoldPrivate *priv; + + g_return_val_if_fail (IS_CELL_AREA_SCAFFOLD (scaffold), 0); + + priv = scaffold->priv; + + return priv->indent; +} + +