From 8d75b6689bdf5dc7c1efad65867cba2a656f2dcc Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Sun, 28 Nov 1999 03:12:22 +0000 Subject: beginning of the keyboard navigation. 1999-11-27 Miguel de Icaza * e-table-item.c (eti_event): beginning of the keyboard navigation. * e-table-model.c (e_table_model_row_changed): new function. (e_table_model_cell_changed): new function. (e_table_model_class_init): New signals. * e-table-item.c (eti_request_region_redraw): x2, y2 offsets were wrong. (eti_select): Repaint selected region. (eti_request_region_redraw): Fix range. (eti_draw): Correct offset computation here. (e_table_item_class_init): New method: row_selection, handles the selection. Now it implement GTK_SELECTION_SINGLE and GTK_SELECTION_MULTIPLE. Focusing and selection should be correct now. svn path=/trunk/; revision=1441 --- widgets/ChangeLog | 20 ++ widgets/e-cell-text.c | 14 +- widgets/e-cell.c | 9 +- widgets/e-cell.h | 7 +- widgets/e-table-col.c | 10 +- widgets/e-table-group.c | 4 +- widgets/e-table-header-item.c | 2 +- widgets/e-table-header.c | 5 +- widgets/e-table-item.c | 386 ++++++++++++++++++++++++++++++---- widgets/e-table-item.h | 27 ++- widgets/e-table-model.c | 128 ++++++----- widgets/e-table-model.h | 14 +- widgets/e-table-sorted.c | 2 - widgets/e-table/ChangeLog | 20 ++ widgets/e-table/e-cell-text.c | 14 +- widgets/e-table/e-cell.c | 9 +- widgets/e-table/e-cell.h | 7 +- widgets/e-table/e-table-col.c | 10 +- widgets/e-table/e-table-group.c | 4 +- widgets/e-table/e-table-header-item.c | 2 +- widgets/e-table/e-table-header.c | 5 +- widgets/e-table/e-table-item.c | 386 ++++++++++++++++++++++++++++++---- widgets/e-table/e-table-item.h | 27 ++- widgets/e-table/e-table-model.c | 128 ++++++----- widgets/e-table/e-table-model.h | 14 +- widgets/e-table/e-table-sorted.c | 2 - widgets/e-table/table-test.c | 4 +- widgets/table-test.c | 4 +- widgets/table/e-cell-text.c | 14 +- widgets/table/e-cell.c | 9 +- widgets/table/e-cell.h | 7 +- widgets/table/e-table-col.c | 10 +- widgets/table/e-table-group.c | 4 +- widgets/table/e-table-header-item.c | 2 +- widgets/table/e-table-header.c | 5 +- widgets/table/e-table-item.c | 386 ++++++++++++++++++++++++++++++---- widgets/table/e-table-item.h | 27 ++- widgets/table/e-table-model.c | 128 ++++++----- widgets/table/e-table-model.h | 14 +- widgets/table/e-table-sorted.c | 2 - widgets/table/table-test.c | 4 +- 41 files changed, 1435 insertions(+), 441 deletions(-) diff --git a/widgets/ChangeLog b/widgets/ChangeLog index 8df0c6966d..20d4c1e3d7 100644 --- a/widgets/ChangeLog +++ b/widgets/ChangeLog @@ -1,3 +1,23 @@ +1999-11-27 Miguel de Icaza + + * e-table-item.c (eti_event): beginning of the keyboard navigation. + + * e-table-model.c (e_table_model_row_changed): new function. + (e_table_model_cell_changed): new function. + (e_table_model_class_init): New signals. + + * e-table-item.c (eti_request_region_redraw): x2, y2 offsets were + wrong. + (eti_select): Repaint selected region. + (eti_request_region_redraw): Fix range. + (eti_draw): Correct offset computation here. + (e_table_item_class_init): New method: row_selection, handles the + selection. + + Now it implement GTK_SELECTION_SINGLE and GTK_SELECTION_MULTIPLE. + + Focusing and selection should be correct now. + 1999-11-26 Miguel de Icaza * e-table-item.c (eti_realize): Compute height using the ecell diff --git a/widgets/e-cell-text.c b/widgets/e-cell-text.c index da26302664..a997d745d3 100644 --- a/widgets/e-cell-text.c +++ b/widgets/e-cell-text.c @@ -64,13 +64,14 @@ ect_unrealize (ECellView *ecv) } static void -ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ect_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int selected = e_table_model_get_selected_row (ecell_view->ecell->table_model) == row; int xoff, w; rect.x = x1; @@ -94,6 +95,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1 xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; break; default: + xoff = 0; g_warning ("Can not handle GTK_JUSTIFY_FILL"); break; } @@ -135,12 +137,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: - if (e_table_model_get_selected_row (ecell->table_model) == row) - e_cell_text_start_editing (ect, col, row); - else - e_table_model_select_row (ecell->table_model, row); return TRUE; + + default: + break; } + return FALSE; } static int diff --git a/widgets/e-cell.c b/widgets/e-cell.c index 8a8897c22a..9caa31f2ca 100644 --- a/widgets/e-cell.c +++ b/widgets/e-cell.c @@ -24,7 +24,9 @@ ec_unrealize (ECellView *e_cell) } static void -ec_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ec_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { g_warning ("e-cell-draw invoked\n"); } @@ -33,6 +35,7 @@ static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { g_warning ("e-cell-event invoked\n"); + return 0; } static gint @@ -109,10 +112,10 @@ e_cell_unrealize (ECellView *ecell_view) void e_cell_draw (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2) + int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->draw ( - ecell_view, drawable, col, row, x1, y1, x2, y2); + ecell_view, drawable, col, row, selected, x1, y1, x2, y2); } int diff --git a/widgets/e-cell.h b/widgets/e-cell.h index e57f341098..9cd62f3909 100644 --- a/widgets/e-cell.h +++ b/widgets/e-cell.h @@ -32,7 +32,7 @@ typedef struct { ECellView *(*realize) (ECell *, GnomeCanvas *canvas); void (*unrealize) (ECellView *); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2); + int col, int row, gboolean selected, int x1, int y1, int x2, int y2); gint (*event) (ECellView *ecell_view, GdkEvent *event, int col, int row); void (*focus) (ECellView *ecell, int col, int row, int x1, int y1, int x2, int y2); void (*unfocus) (ECellView *ecell); @@ -43,8 +43,9 @@ GtkType e_cell_get_type (void); void e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row); ECellView *e_cell_realize (ECell *ecell, GnomeCanvas *canvas); void e_cell_unrealize (ECellView *ecell_view); -void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, - int col, int row, int x1, int y1, int x2, int y2); +void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2); void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); diff --git a/widgets/e-table-col.c b/widgets/e-table-col.c index 4c61cddd0f..3ffc45a2ed 100644 --- a/widgets/e-table-col.c +++ b/widgets/e-table-col.c @@ -17,11 +17,11 @@ e_table_col_new (const char *id, int width, int min_width, { ETableCol *etc; - g_return_if_fail (id != NULL); - g_return_if_fail (width >= 0); - g_return_if_fail (min_width >= 0); - g_return_if_fail (width >= min_width); - g_return_if_fail (compare != NULL); + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (width >= 0, NULL); + g_return_val_if_fail (min_width >= 0, NULL); + g_return_val_if_fail (width >= min_width, NULL); + g_return_val_if_fail (compare != NULL, NULL); etc = g_new (ETableCol, 1); diff --git a/widgets/e-table-group.c b/widgets/e-table-group.c index bc751229a4..b1e681d255 100644 --- a/widgets/e-table-group.c +++ b/widgets/e-table-group.c @@ -76,10 +76,11 @@ e_table_group_append_child (ETableGroup *etg, ETableGroup *child) etg->u.children = g_slist_append (etg->u.children, child); } +#if 0 int e_table_group_size (ETableGroup *etg) { - g_return_if_fail (etg != NULL); + g_return_val_if_fail (etg != NULL, 0); if (etg->is_leaf) return e_table_model_height (etg->u.table); @@ -96,3 +97,4 @@ e_table_group_size (ETableGroup *etg) } } +#endif diff --git a/widgets/e-table-header-item.c b/widgets/e-table-header-item.c index 2ee8e2d619..1be7e7097b 100644 --- a/widgets/e-table-header-item.c +++ b/widgets/e-table-header-item.c @@ -7,6 +7,7 @@ * Copyright 1999, Helix Code, Inc. */ #include +#include #include "e-table-header.h" #include "e-table-header-item.h" #include "e-cursors.h" @@ -124,7 +125,6 @@ ethi_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableHeaderItem *ethi; - int v; item = GNOME_CANVAS_ITEM (o); ethi = E_TABLE_HEADER_ITEM (o); diff --git a/widgets/e-table-header.c b/widgets/e-table-header.c index 2279bf4ba6..5900c5ca4f 100644 --- a/widgets/e-table-header.c +++ b/widgets/e-table-header.c @@ -121,8 +121,6 @@ eth_update_offsets (ETableHeader *eth) void e_table_header_add_column (ETableHeader *eth, ETableCol *tc, int pos) { - ETableCol **new_ptr; - g_return_if_fail (eth != NULL); g_return_if_fail (E_IS_TABLE_HEADER (eth)); g_return_if_fail (tc != NULL); @@ -204,7 +202,6 @@ ETableCol ** e_table_header_get_columns (ETableHeader *eth) { ETableCol **ret; - int i; g_return_val_if_fail (eth != NULL, 0); g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); @@ -226,7 +223,7 @@ e_table_header_selection_ok (ETableHeader *eth) } int -ve_table_header_get_selected (ETableHeader *eth) +e_table_header_get_selected (ETableHeader *eth) { int i; int selected = 0; diff --git a/widgets/e-table-item.c b/widgets/e-table-item.c index 3b35f6c156..a561fbfd15 100644 --- a/widgets/e-table-item.c +++ b/widgets/e-table-item.c @@ -1,19 +1,35 @@ /* - * E-table-item.c: A view of a Table. + * E-table-item.c: A GnomeCanvasItem that is a view of an ETableModel. * * Author: * Miguel de Icaza (miguel@gnu.org) * * Copyright 1999, Helix Code, Inc. + * + * TODO: + * Add a border to the thing, so that focusing works properly. + * */ #include +#include +#include +#include #include "e-table-item.h" #include "e-cell.h" #define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () +#define FOCUSED_BORDER 2 + static GnomeCanvasItemClass *eti_parent_class; +enum { + ROW_SELECTION, + LAST_SIGNAL +}; + +static gint eti_signals [LAST_SIGNAL] = { 0, }; + enum { ARG_0, ARG_TABLE_HEADER, @@ -24,6 +40,14 @@ enum { ARG_LENGHT_THRESHOLD }; +/* + * During realization, we have to invoke the per-ecell realize routine + * (On our current setup, we have one e-cell per column. + * + * We might want to optimize this to only realize the unique e-cells: + * ie, a strings-only table, uses the same e-cell for every column, and + * we might want to avoid realizing each e-cell. + */ static void eti_realize_cell_views (ETableItem *eti) { @@ -43,14 +67,16 @@ eti_realize_cell_views (ETableItem *eti) } } +/* + * During unrealization: we invoke every e-cell (one per column in the current + * setup) to dispose all resources allocated + */ static void eti_unrealize_cell_views (ETableItem *eti) { int i; for (i = 0; i < eti->n_cells; i++){ - ETableCol *col = e_table_header_get_column (eti->header, i); - e_cell_unrealize (eti->cell_views [i]); eti->cell_views [i] = NULL; } @@ -59,6 +85,9 @@ eti_unrealize_cell_views (ETableItem *eti) } +/* + * GnomeCanvasItem::update method + */ static void eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { @@ -75,14 +104,21 @@ eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); } +/* + * eti_remove_table_model: + * + * Invoked to release the table model associated with this ETableItem + */ static void eti_remove_table_model (ETableItem *eti) { if (!eti->table_model) return; - gtk_signal_disconnect (eti->table_model_change_id); - gtk_signal_disconnect (eti->table_model_selection_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_selection_id); gtk_object_unref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = 0; @@ -90,14 +126,21 @@ eti_remove_table_model (ETableItem *eti) eti->table_model = NULL; } +/* + * eti_remove_header_model: + * + * Invoked to release the header model associated with this ETableItem + */ static void eti_remove_header_model (ETableItem *eti) { if (!eti->header) return; - gtk_signal_disconnect (eti->header_structure_change_id); - gtk_signal_disconnect (eti->header_dim_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_structure_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_dim_change_id); gtk_object_unref (GTK_OBJECT (eti->header)); eti->header_structure_change_id = 0; @@ -105,6 +148,12 @@ eti_remove_header_model (ETableItem *eti) eti->header = NULL; } +/* + * eti_row_height: + * + * Returns the height used by row @row. This does not include the one-pixel + * used as a separator between rows + */ static int eti_row_height (ETableItem *eti, int row) { @@ -123,6 +172,18 @@ eti_row_height (ETableItem *eti, int row) return max_h; } +/* + * eti_get_height: + * + * Returns the height of the ETableItem. + * + * The ETableItem might compute the whole height by asking every row its + * size. There is a special mode (designed to work when there are too + * many rows in the table that performing the previous step could take + * too long) set by the ETableItem->length_threshold that would determine + * when the height is computed by using the first row as the size for + * every other row in the ETableItem. + */ static int eti_get_height (ETableItem *eti) { @@ -148,6 +209,9 @@ eti_get_height (ETableItem *eti) return height; } +/* + * Callback routine: invoked when the ETableModel has suffered a change + */ static void eti_table_model_changed (ETableModel *table_model, ETableItem *eti) { @@ -160,6 +224,11 @@ eti_table_model_changed (ETableModel *table_model, ETableItem *eti) eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); } +/* + * eti_request_redraw: + * + * Queues a canvas redraw for the entire ETableItem. + */ static void eti_request_redraw (ETableItem *eti) { @@ -170,6 +239,9 @@ eti_request_redraw (ETableItem *eti) eti->y1 + eti->height + 1); } +/* + * Computes the distance from @start_col to @end_col in pixels. + */ static int eti_col_diff (ETableItem *eti, int start_col, int end_col) { @@ -185,6 +257,9 @@ eti_col_diff (ETableItem *eti, int start_col, int end_col) return total; } +/* + * Computes the distance between @start_row and @end_row in pixels + */ static int eti_row_diff (ETableItem *eti, int start_row, int end_row) { @@ -198,28 +273,38 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) return total; } +/* + * eti_request_region_redraw: + * + * Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row). + * This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell). + * + * The @border argument is a number of pixels around the region that should also be queued + * for redraw. This is typically used by the focus routines to queue a redraw for the + * border as well. + */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row) +eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) { GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; int x1, y1, width, height; - int col, row; x1 = eti_col_diff (eti, 0, start_col); y1 = eti_row_diff (eti, 0, start_row); - width = eti_col_diff (eti, start_col, end_col); - height = eti_row_diff (eti, start_col, end_row); - + width = eti_col_diff (eti, start_col, end_col + 1); + height = eti_row_diff (eti, start_row, end_row + 1); + gnome_canvas_request_redraw (canvas, - eti->x1 + x1, eti->y1 + y1, - eti->y1 + width + 1, - eti->x1 + height + 1); + eti->x1 + x1 - border, + eti->y1 + y1 - border, + eti->x1 + x1 + width + 1 + border, + eti->y1 + y1 + height + 1 + border); } static void eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) { - eti_request_region_redraw (eti, 0, row, eti->cols, row); + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); } static void @@ -282,6 +367,9 @@ eti_add_header_model (ETableItem *eti, ETableHeader *header) GTK_SIGNAL_FUNC (eti_header_structure_changed), eti); } +/* + * GtkObject::destroy method + */ static void eti_destroy (GtkObject *object) { @@ -289,6 +377,8 @@ eti_destroy (GtkObject *object) eti_remove_header_model (eti); eti_remove_table_model (eti); + + g_slist_free (eti->selection); if (GTK_OBJECT_CLASS (eti_parent_class)->destroy) (*GTK_OBJECT_CLASS (eti_parent_class)->destroy) (object); @@ -299,7 +389,6 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; - int v; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -343,6 +432,8 @@ eti_init (GnomeCanvasItem *item) eti->height = 0; eti->length_threshold = -1; + + eti->selection_mode = GTK_SELECTION_SINGLE; } static void @@ -355,13 +446,24 @@ eti_realize (GnomeCanvasItem *item) if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize) (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item); + /* + * Gdk Resource allocation + */ window = canvas_widget->window; - + eti->fill_gc = canvas_widget->style->white_gc; gdk_gc_ref (canvas_widget->style->white_gc); + eti->grid_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); + eti->focus_gc = gdk_gc_new (window); + gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->black); + gdk_gc_set_line_attributes (eti->focus_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); + + /* + * + */ eti_realize_cell_views (eti); eti->height = eti_get_height (eti); @@ -377,7 +479,9 @@ eti_unrealize (GnomeCanvasItem *item) eti->fill_gc = NULL; gdk_gc_unref (eti->grid_gc); eti->grid_gc = NULL; - + gdk_gc_unref (eti->focus_gc); + eti->focus_gc = NULL; + eti_unrealize_cell_views (eti); eti->height = 0; @@ -387,26 +491,28 @@ eti_unrealize (GnomeCanvasItem *item) } static void -draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, +draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; ECellView *ecell_view; - GdkFont *font; - char text [40]; - - font = GTK_WIDGET (canvas)->style->font; ecell_view = eti->cell_views [col]; - e_cell_draw (ecell_view, drawable, col, row, x1, y1, x2, y2); + e_cell_draw (ecell_view, drawable, col, row, selected, x1, y1, x2, y2); #if 0 + { + GdkFont *font; + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + font = GTK_WIDGET (canvas)->style->font; + sprintf (text, "%d:%d\n", col, row); gdk_draw_line (drawable, eti->grid_gc, x1, y1, x2, y2); gdk_draw_line (drawable, eti->grid_gc, x1, y2, x2, y1); sprintf (text, "%d:%d\n", col, row); gdk_draw_text (drawable, font, eti->grid_gc, x1, y2, text, strlen (text)); + } #endif } @@ -420,7 +526,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int first_col, last_col, x_offset; int first_row, last_row, y_offset, yd; int x1, x2; - int heights; + int f_x1, f_x2, f_y1, f_y2; + gboolean f_found; printf ("Rect: %d %d %d %d\n", x, y, width, height); /* @@ -435,7 +542,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_col = -1; last_col = x_offset = 0; - x1 = eti->x1; + x1 = x2 = eti->x1; for (col = 0; col < cols; col++, x1 = x2){ ETableCol *ecol = e_table_header_get_column (eti->header, col); @@ -465,9 +572,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, y_offset = 0; y1 = y2 = eti->y1; for (row = eti->top_item; row < rows; row++, y1 = y2){ - int xd; - y2 += eti_row_height (eti, row); + y2 += eti_row_height (eti, row) + 1; if (y1 > y + height) break; @@ -489,24 +595,49 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw cells */ yd = y_offset; + f_x1 = f_x2 = f_y1 = f_y2 = -1; + f_found = FALSE; for (row = first_row; row < last_row; row++){ int xd, height; + gboolean selected; height = eti_row_height (eti, row); xd = x_offset; printf ("paint: %d %d\n", yd, yd + height); + + selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; + for (col = first_col; col < last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); - draw_cell (eti, drawable, col, row, xd, yd, xd + ecol->width, yd + height); + draw_cell (eti, drawable, col, row, selected, xd, yd, xd + ecol->width, yd + height); + if (col == eti->focused_col && row == eti->focused_row){ + f_x1 = xd; + f_x2 = xd + ecol->width; + f_y1 = yd; + f_y2 = yd + height; + f_found = TRUE; + } + xd += ecol->width; } yd += height + 1; gdk_draw_line (drawable, eti->grid_gc, eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); } + + /* + * Draw focus + */ + if (f_found){ + printf ("FOUD: %d %d %d %d!\n", + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + } } static double @@ -547,7 +678,7 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) break; } - y1 = 0; + y1 = y2 = 0; for (row = 0; row < rows; row++, y1 = y2){ if (y < y1) return FALSE; @@ -564,13 +695,6 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) return TRUE; } -static void -eti_select (ETableItem *eti, int col, int row) -{ - eti->selected_col = col; - eti->selected_row = row; -} - static int eti_event (GnomeCanvasItem *item, GdkEvent *e) { @@ -586,22 +710,56 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) return TRUE; - if (eti->selected_row == row && eti->selected_col == col){ + if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; e_cell_event (ecell_view, e, col, row); - } else - eti_select (eti, col, row); + } else { + /* + * Focus the cell, and select the row + */ + e_table_item_focus (eti, col, row); + e_table_item_select_row (eti, row); + } break; } case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: if (eti->focused_col == -1) return FALSE; + switch (e->key.keyval){ + case GDK_Left: + if (eti->focused_col > 0) + e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); + break; + + case GDK_Right: + if ((eti->focused_col + 1) < eti->cols) + e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); + break; + + case GDK_Up: + if (eti->focused_row > 0) + e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); + break; + + case GDK_Down: + if ((eti->focused_row + 1) < eti->rows) + e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); + break; + + default: + } ecell_view = eti->cell_views [eti->focused_col]; + e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); + break; + + case GDK_KEY_RELEASE: + if (eti->focused_col == -1) + return FALSE; + ecell_view = eti->cell_views [eti->focused_col]; e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); break; @@ -610,12 +768,27 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } return TRUE; } + +/* + * ETableItem::row_selection method + */ +static void +eti_row_selection (ETableItem *eti, int row, gboolean selected) +{ + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + if (selected) + eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); + else + eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); +} + static void eti_class_init (GtkObjectClass *object_class) { GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - + ETableItemClass *eti_class = (ETableItemClass *) object_class; + eti_parent_class = gtk_type_class (PARENT_OBJECT_TYPE); object_class->destroy = eti_destroy; @@ -627,7 +800,9 @@ eti_class_init (GtkObjectClass *object_class) item_class->draw = eti_draw; item_class->point = eti_point; item_class->event = eti_event; - + + eti_class->row_selection = eti_row_selection; + gtk_object_add_arg_type ("ETableItem::ETableHeader", GTK_TYPE_POINTER, GTK_ARG_WRITABLE, ARG_TABLE_HEADER); gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_POINTER, @@ -638,6 +813,17 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_Y); gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); + + eti_signals [ROW_SELECTION] = + gtk_signal_new ("row_selection", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, eti_signals, LAST_SIGNAL); + } GtkType @@ -666,16 +852,124 @@ e_table_item_get_type (void) void e_table_item_focus (ETableItem *eti, int col, int row) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (eti->focused_col != -1) e_table_item_unfocus (eti); eti->focused_col = col; - eti->focused_row = row; + eti->focused_row = row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); } void e_table_item_unfocus (ETableItem *eti) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (eti->focused_row == -1) + return; + + { + const int col = eti->focused_col; + const int row = eti->focused_row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + } eti->focused_col = -1; eti->focused_row = -1; } + +const GSList * +e_table_item_get_selection (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); + + return eti->selection; +} + +GtkSelectionMode +e_table_item_get_selection_mode (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, GTK_SELECTION_SINGLE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), GTK_SELECTION_SINGLE); + + return eti->selection_mode; +} + +void +e_table_item_set_selection_mode (ETableItem *eti, GtkSelectionMode selection_mode) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (selection_mode == GTK_SELECTION_BROWSE || + selection_mode == GTK_SELECTION_EXTENDED){ + g_error ("GTK_SELECTION_BROWSE and GTK_SELECTION_EXTENDED are not implemented"); + } + + eti->selection_mode = selection_mode; +} + +gboolean +e_table_item_is_row_selected (ETableItem *eti, int row) +{ + g_return_val_if_fail (eti != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); + + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return TRUE; + else + return FALSE; +} + +void +e_table_item_unselect_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (e_table_item_is_row_selected (eti, row)){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + row, 0); + } +} + +void +e_table_item_select_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + switch (eti->selection_mode){ + case GTK_SELECTION_SINGLE: + if (eti->selection){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GPOINTER_TO_INT (eti->selection->data), 0); + } + g_slist_free (eti->selection); + eti->selection = NULL; + + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + case GTK_SELECTION_MULTIPLE: + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return; + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + default: + + } +} diff --git a/widgets/e-table-item.h b/widgets/e-table-item.h index fc36363413..17d422ddf5 100644 --- a/widgets/e-table-item.h +++ b/widgets/e-table-item.h @@ -32,6 +32,7 @@ typedef struct { GdkGC *fill_gc; GdkGC *grid_gc; + GdkGC *focus_gc; unsigned int draw_grid:1; @@ -49,15 +50,39 @@ typedef struct { */ int length_threshold; - int selected_col, selected_row; + GSList *selection; + GtkSelectionMode selection_mode; } ETableItem; typedef struct { GnomeCanvasItemClass parent_class; + + void (*row_selection) (ETableItem *eti, int row, gboolean selected); } ETableItemClass; GtkType e_table_item_get_type (void); + +/* + * Focus + */ void e_table_item_focus (ETableItem *eti, int col, int row); void e_table_item_unfocus (ETableItem *eti); +/* + * Selection + */ +void e_table_item_select_row (ETableItem *e_table_Item, int row); +void e_table_item_unselect_row (ETableItem *e_table_Item, int row); + +/* + * Handling the selection + */ +const GSList*e_table_item_get_selection (ETableItem *e_table_Item); + +GtkSelectionMode e_table_item_get_selection_mode (ETableItem *e_table_Item); +void e_table_item_set_selection_mode (ETableItem *e_table_Item, + GtkSelectionMode selection_mode); +gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, + int row); + #endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/e-table-model.c b/widgets/e-table-model.c index 3aa4e4be47..288c20f20e 100644 --- a/widgets/e-table-model.c +++ b/widgets/e-table-model.c @@ -16,55 +16,71 @@ static GtkObjectClass *e_table_model_parent_class; enum { MODEL_CHANGED, + MODEL_ROW_CHANGED, + MODEL_CELL_CHANGED, ROW_SELECTION, LAST_SIGNAL }; -static guint etm_signals [LAST_SIGNAL] = { 0, }; +static guint e_table_model_signals [LAST_SIGNAL] = { 0, }; int -e_table_model_column_count (ETableModel *etable) +e_table_model_column_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->column_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->column_count (e_table_model); } const char * -e_table_model_column_name (ETableModel *etable, int col) +e_table_model_column_name (ETableModel *e_table_model, int col) { - return ETM_CLASS (etable)->column_name (etable, col); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->column_name (e_table_model, col); } int -e_table_model_row_count (ETableModel *etable) +e_table_model_row_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->row_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->row_count (e_table_model); } void * -e_table_model_value_at (ETableModel *etable, int col, int row) +e_table_model_value_at (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->value_at (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->value_at (e_table_model, col, row); } void -e_table_model_set_value_at (ETableModel *etable, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) { - return ETM_CLASS (etable)->set_value_at (etable, col, row, data); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + + return ETM_CLASS (e_table_model)->set_value_at (e_table_model, col, row, data); } gboolean -e_table_model_is_cell_editable (ETableModel *etable, int col, int row) +e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->is_cell_editable (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE); + + return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); } static void e_table_model_destroy (GtkObject *object) { - GSList *l; - - ETableModel *etable = (ETableModel *) object; - if (e_table_model_parent_class->destroy) (*e_table_model_parent_class->destroy)(object); } @@ -76,7 +92,7 @@ e_table_model_class_init (GtkObjectClass *object_class) object_class->destroy = e_table_model_destroy; - etm_signals [MODEL_CHANGED] = + e_table_model_signals [MODEL_CHANGED] = gtk_signal_new ("model_changed", GTK_RUN_LAST, object_class->type, @@ -84,21 +100,23 @@ e_table_model_class_init (GtkObjectClass *object_class) gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - etm_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", + e_table_model_signals [MODEL_ROW_CHANGED] = + gtk_signal_new ("model_row_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, row_selection), + GTK_SIGNAL_OFFSET (ETableModelClass, model_row_changed), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + e_table_model_signals [MODEL_CELL_CHANGED] = + gtk_signal_new ("model_cell_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableModelClass, model_cell_changed), gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, etm_signals, LAST_SIGNAL); -} -static void -e_table_model_init (ETableModel *etm) -{ - etm->row_selected = -1; + gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); } GtkType @@ -112,7 +130,7 @@ e_table_model_get_type (void) sizeof (ETableModel), sizeof (ETableModelClass), (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) e_table_model_init, + (GtkObjectInitFunc) NULL, NULL, /* reserved 1 */ NULL, /* reserved 2 */ (GtkClassInitFunc) NULL @@ -127,53 +145,31 @@ e_table_model_get_type (void) void e_table_model_changed (ETableModel *e_table_model) { + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + gtk_signal_emit (GTK_OBJECT (e_table_model), - etm_signals [MODEL_CHANGED]); + e_table_model_signals [MODEL_CHANGED]); } -#if 0 -int -e_table_model_max_col_width (ETableModel *etm, int col) +void +e_table_model_row_changed (ETableModel *e_table_model, int row) { - const int nvals = e_table_model_row_count (etm); - int max = 0; - int row; - - for (row = 0; row < nvals; row++){ - int w; - - w = e_table_model_cell_width (etm, col, i); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - if (w > max) - max = w; - } - - return max; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_ROW_CHANGED], row); } -#endif void -e_table_model_select_row (ETableModel *etm, int row) +e_table_model_cell_changed (ETableModel *e_table_model, int col, int row) { - gtk_signal_emit (GTK_OBJECT (etm), etm_signals [ROW_SELECTION], row, 1); - etm->row_selected = row; -} + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); -void -e_table_model_unselect_row (ETableModel *etm, int row) -{ - if (etm->row_selected != -1){ - gtk_signal_emit ( - GTK_OBJECT (etm), etm_signals [ROW_SELECTION], - etm->row_selected, 0); - } - - etm->row_selected = -1; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_CELL_CHANGED], col, row); } -gint -e_table_model_get_selected_row (ETableModel *etm) -{ - return etm->row_selected; -} diff --git a/widgets/e-table-model.h b/widgets/e-table-model.h index d8de9e819e..ea5d31493d 100644 --- a/widgets/e-table-model.h +++ b/widgets/e-table-model.h @@ -11,9 +11,6 @@ typedef struct { GtkObject base; - - /* Temporary. I swear */ - int row_selected; } ETableModel; typedef struct { @@ -32,8 +29,9 @@ typedef struct { /* * Signals */ - void (*model_changed) (ETableModel *etm); - void (*row_selection) (ETableModel *etc, int row, gboolean selected); + void (*model_changed) (ETableModel *etm); + void (*model_row_changed) (ETableModel *etm, int row); + void (*model_cell_changed) (ETableModel *etm, int col, int row); } ETableModelClass; GtkType e_table_model_get_type (void); @@ -45,13 +43,13 @@ void *e_table_model_value_at (ETableModel *e_table_model, int col, void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); -void e_table_model_select_row (ETableModel *e_table_model, int row); -gint e_table_model_get_selected_row (ETableModel *e_table_model); - /* * Routines for emitting signals on the e_table */ void e_table_model_changed (ETableModel *e_table_model); +void e_table_model_row_changed (ETableModel *e_table_model, int row); +void e_table_model_cell_changed (ETableModel *e_table_model, int col, int row); #endif /* _E_TABLE_MODEL_H_ */ + diff --git a/widgets/e-table-sorted.c b/widgets/e-table-sorted.c index be19de2efb..90773e9cdc 100644 --- a/widgets/e-table-sorted.c +++ b/widgets/e-table-sorted.c @@ -30,7 +30,6 @@ static ETableSorted *sort_ets; static int my_sort (const void *a, const void *b) { - GCompareFunc comp; ETableModel *source = E_TABLE_SUBSET (sort_ets)->source; const int *ia = (const int *) a; const int *ib = (const int *) b; @@ -59,7 +58,6 @@ e_table_sorted_new (ETableModel *source, int col, GCompareFunc compare) ETableSorted *ets = gtk_type_new (E_TABLE_SORTED_TYPE); ETableSubset *etss = E_TABLE_SUBSET (ets); const int nvals = e_table_model_row_count (source); - unsigned int *buffer; int i; if (e_table_subset_construct (etss, source, nvals) == NULL){ diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index 8df0c6966d..20d4c1e3d7 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,3 +1,23 @@ +1999-11-27 Miguel de Icaza + + * e-table-item.c (eti_event): beginning of the keyboard navigation. + + * e-table-model.c (e_table_model_row_changed): new function. + (e_table_model_cell_changed): new function. + (e_table_model_class_init): New signals. + + * e-table-item.c (eti_request_region_redraw): x2, y2 offsets were + wrong. + (eti_select): Repaint selected region. + (eti_request_region_redraw): Fix range. + (eti_draw): Correct offset computation here. + (e_table_item_class_init): New method: row_selection, handles the + selection. + + Now it implement GTK_SELECTION_SINGLE and GTK_SELECTION_MULTIPLE. + + Focusing and selection should be correct now. + 1999-11-26 Miguel de Icaza * e-table-item.c (eti_realize): Compute height using the ecell diff --git a/widgets/e-table/e-cell-text.c b/widgets/e-table/e-cell-text.c index da26302664..a997d745d3 100644 --- a/widgets/e-table/e-cell-text.c +++ b/widgets/e-table/e-cell-text.c @@ -64,13 +64,14 @@ ect_unrealize (ECellView *ecv) } static void -ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ect_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int selected = e_table_model_get_selected_row (ecell_view->ecell->table_model) == row; int xoff, w; rect.x = x1; @@ -94,6 +95,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1 xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; break; default: + xoff = 0; g_warning ("Can not handle GTK_JUSTIFY_FILL"); break; } @@ -135,12 +137,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: - if (e_table_model_get_selected_row (ecell->table_model) == row) - e_cell_text_start_editing (ect, col, row); - else - e_table_model_select_row (ecell->table_model, row); return TRUE; + + default: + break; } + return FALSE; } static int diff --git a/widgets/e-table/e-cell.c b/widgets/e-table/e-cell.c index 8a8897c22a..9caa31f2ca 100644 --- a/widgets/e-table/e-cell.c +++ b/widgets/e-table/e-cell.c @@ -24,7 +24,9 @@ ec_unrealize (ECellView *e_cell) } static void -ec_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ec_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { g_warning ("e-cell-draw invoked\n"); } @@ -33,6 +35,7 @@ static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { g_warning ("e-cell-event invoked\n"); + return 0; } static gint @@ -109,10 +112,10 @@ e_cell_unrealize (ECellView *ecell_view) void e_cell_draw (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2) + int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->draw ( - ecell_view, drawable, col, row, x1, y1, x2, y2); + ecell_view, drawable, col, row, selected, x1, y1, x2, y2); } int diff --git a/widgets/e-table/e-cell.h b/widgets/e-table/e-cell.h index e57f341098..9cd62f3909 100644 --- a/widgets/e-table/e-cell.h +++ b/widgets/e-table/e-cell.h @@ -32,7 +32,7 @@ typedef struct { ECellView *(*realize) (ECell *, GnomeCanvas *canvas); void (*unrealize) (ECellView *); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2); + int col, int row, gboolean selected, int x1, int y1, int x2, int y2); gint (*event) (ECellView *ecell_view, GdkEvent *event, int col, int row); void (*focus) (ECellView *ecell, int col, int row, int x1, int y1, int x2, int y2); void (*unfocus) (ECellView *ecell); @@ -43,8 +43,9 @@ GtkType e_cell_get_type (void); void e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row); ECellView *e_cell_realize (ECell *ecell, GnomeCanvas *canvas); void e_cell_unrealize (ECellView *ecell_view); -void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, - int col, int row, int x1, int y1, int x2, int y2); +void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2); void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); diff --git a/widgets/e-table/e-table-col.c b/widgets/e-table/e-table-col.c index 4c61cddd0f..3ffc45a2ed 100644 --- a/widgets/e-table/e-table-col.c +++ b/widgets/e-table/e-table-col.c @@ -17,11 +17,11 @@ e_table_col_new (const char *id, int width, int min_width, { ETableCol *etc; - g_return_if_fail (id != NULL); - g_return_if_fail (width >= 0); - g_return_if_fail (min_width >= 0); - g_return_if_fail (width >= min_width); - g_return_if_fail (compare != NULL); + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (width >= 0, NULL); + g_return_val_if_fail (min_width >= 0, NULL); + g_return_val_if_fail (width >= min_width, NULL); + g_return_val_if_fail (compare != NULL, NULL); etc = g_new (ETableCol, 1); diff --git a/widgets/e-table/e-table-group.c b/widgets/e-table/e-table-group.c index bc751229a4..b1e681d255 100644 --- a/widgets/e-table/e-table-group.c +++ b/widgets/e-table/e-table-group.c @@ -76,10 +76,11 @@ e_table_group_append_child (ETableGroup *etg, ETableGroup *child) etg->u.children = g_slist_append (etg->u.children, child); } +#if 0 int e_table_group_size (ETableGroup *etg) { - g_return_if_fail (etg != NULL); + g_return_val_if_fail (etg != NULL, 0); if (etg->is_leaf) return e_table_model_height (etg->u.table); @@ -96,3 +97,4 @@ e_table_group_size (ETableGroup *etg) } } +#endif diff --git a/widgets/e-table/e-table-header-item.c b/widgets/e-table/e-table-header-item.c index 2ee8e2d619..1be7e7097b 100644 --- a/widgets/e-table/e-table-header-item.c +++ b/widgets/e-table/e-table-header-item.c @@ -7,6 +7,7 @@ * Copyright 1999, Helix Code, Inc. */ #include +#include #include "e-table-header.h" #include "e-table-header-item.h" #include "e-cursors.h" @@ -124,7 +125,6 @@ ethi_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableHeaderItem *ethi; - int v; item = GNOME_CANVAS_ITEM (o); ethi = E_TABLE_HEADER_ITEM (o); diff --git a/widgets/e-table/e-table-header.c b/widgets/e-table/e-table-header.c index 2279bf4ba6..5900c5ca4f 100644 --- a/widgets/e-table/e-table-header.c +++ b/widgets/e-table/e-table-header.c @@ -121,8 +121,6 @@ eth_update_offsets (ETableHeader *eth) void e_table_header_add_column (ETableHeader *eth, ETableCol *tc, int pos) { - ETableCol **new_ptr; - g_return_if_fail (eth != NULL); g_return_if_fail (E_IS_TABLE_HEADER (eth)); g_return_if_fail (tc != NULL); @@ -204,7 +202,6 @@ ETableCol ** e_table_header_get_columns (ETableHeader *eth) { ETableCol **ret; - int i; g_return_val_if_fail (eth != NULL, 0); g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); @@ -226,7 +223,7 @@ e_table_header_selection_ok (ETableHeader *eth) } int -ve_table_header_get_selected (ETableHeader *eth) +e_table_header_get_selected (ETableHeader *eth) { int i; int selected = 0; diff --git a/widgets/e-table/e-table-item.c b/widgets/e-table/e-table-item.c index 3b35f6c156..a561fbfd15 100644 --- a/widgets/e-table/e-table-item.c +++ b/widgets/e-table/e-table-item.c @@ -1,19 +1,35 @@ /* - * E-table-item.c: A view of a Table. + * E-table-item.c: A GnomeCanvasItem that is a view of an ETableModel. * * Author: * Miguel de Icaza (miguel@gnu.org) * * Copyright 1999, Helix Code, Inc. + * + * TODO: + * Add a border to the thing, so that focusing works properly. + * */ #include +#include +#include +#include #include "e-table-item.h" #include "e-cell.h" #define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () +#define FOCUSED_BORDER 2 + static GnomeCanvasItemClass *eti_parent_class; +enum { + ROW_SELECTION, + LAST_SIGNAL +}; + +static gint eti_signals [LAST_SIGNAL] = { 0, }; + enum { ARG_0, ARG_TABLE_HEADER, @@ -24,6 +40,14 @@ enum { ARG_LENGHT_THRESHOLD }; +/* + * During realization, we have to invoke the per-ecell realize routine + * (On our current setup, we have one e-cell per column. + * + * We might want to optimize this to only realize the unique e-cells: + * ie, a strings-only table, uses the same e-cell for every column, and + * we might want to avoid realizing each e-cell. + */ static void eti_realize_cell_views (ETableItem *eti) { @@ -43,14 +67,16 @@ eti_realize_cell_views (ETableItem *eti) } } +/* + * During unrealization: we invoke every e-cell (one per column in the current + * setup) to dispose all resources allocated + */ static void eti_unrealize_cell_views (ETableItem *eti) { int i; for (i = 0; i < eti->n_cells; i++){ - ETableCol *col = e_table_header_get_column (eti->header, i); - e_cell_unrealize (eti->cell_views [i]); eti->cell_views [i] = NULL; } @@ -59,6 +85,9 @@ eti_unrealize_cell_views (ETableItem *eti) } +/* + * GnomeCanvasItem::update method + */ static void eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { @@ -75,14 +104,21 @@ eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); } +/* + * eti_remove_table_model: + * + * Invoked to release the table model associated with this ETableItem + */ static void eti_remove_table_model (ETableItem *eti) { if (!eti->table_model) return; - gtk_signal_disconnect (eti->table_model_change_id); - gtk_signal_disconnect (eti->table_model_selection_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_selection_id); gtk_object_unref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = 0; @@ -90,14 +126,21 @@ eti_remove_table_model (ETableItem *eti) eti->table_model = NULL; } +/* + * eti_remove_header_model: + * + * Invoked to release the header model associated with this ETableItem + */ static void eti_remove_header_model (ETableItem *eti) { if (!eti->header) return; - gtk_signal_disconnect (eti->header_structure_change_id); - gtk_signal_disconnect (eti->header_dim_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_structure_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_dim_change_id); gtk_object_unref (GTK_OBJECT (eti->header)); eti->header_structure_change_id = 0; @@ -105,6 +148,12 @@ eti_remove_header_model (ETableItem *eti) eti->header = NULL; } +/* + * eti_row_height: + * + * Returns the height used by row @row. This does not include the one-pixel + * used as a separator between rows + */ static int eti_row_height (ETableItem *eti, int row) { @@ -123,6 +172,18 @@ eti_row_height (ETableItem *eti, int row) return max_h; } +/* + * eti_get_height: + * + * Returns the height of the ETableItem. + * + * The ETableItem might compute the whole height by asking every row its + * size. There is a special mode (designed to work when there are too + * many rows in the table that performing the previous step could take + * too long) set by the ETableItem->length_threshold that would determine + * when the height is computed by using the first row as the size for + * every other row in the ETableItem. + */ static int eti_get_height (ETableItem *eti) { @@ -148,6 +209,9 @@ eti_get_height (ETableItem *eti) return height; } +/* + * Callback routine: invoked when the ETableModel has suffered a change + */ static void eti_table_model_changed (ETableModel *table_model, ETableItem *eti) { @@ -160,6 +224,11 @@ eti_table_model_changed (ETableModel *table_model, ETableItem *eti) eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); } +/* + * eti_request_redraw: + * + * Queues a canvas redraw for the entire ETableItem. + */ static void eti_request_redraw (ETableItem *eti) { @@ -170,6 +239,9 @@ eti_request_redraw (ETableItem *eti) eti->y1 + eti->height + 1); } +/* + * Computes the distance from @start_col to @end_col in pixels. + */ static int eti_col_diff (ETableItem *eti, int start_col, int end_col) { @@ -185,6 +257,9 @@ eti_col_diff (ETableItem *eti, int start_col, int end_col) return total; } +/* + * Computes the distance between @start_row and @end_row in pixels + */ static int eti_row_diff (ETableItem *eti, int start_row, int end_row) { @@ -198,28 +273,38 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) return total; } +/* + * eti_request_region_redraw: + * + * Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row). + * This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell). + * + * The @border argument is a number of pixels around the region that should also be queued + * for redraw. This is typically used by the focus routines to queue a redraw for the + * border as well. + */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row) +eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) { GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; int x1, y1, width, height; - int col, row; x1 = eti_col_diff (eti, 0, start_col); y1 = eti_row_diff (eti, 0, start_row); - width = eti_col_diff (eti, start_col, end_col); - height = eti_row_diff (eti, start_col, end_row); - + width = eti_col_diff (eti, start_col, end_col + 1); + height = eti_row_diff (eti, start_row, end_row + 1); + gnome_canvas_request_redraw (canvas, - eti->x1 + x1, eti->y1 + y1, - eti->y1 + width + 1, - eti->x1 + height + 1); + eti->x1 + x1 - border, + eti->y1 + y1 - border, + eti->x1 + x1 + width + 1 + border, + eti->y1 + y1 + height + 1 + border); } static void eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) { - eti_request_region_redraw (eti, 0, row, eti->cols, row); + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); } static void @@ -282,6 +367,9 @@ eti_add_header_model (ETableItem *eti, ETableHeader *header) GTK_SIGNAL_FUNC (eti_header_structure_changed), eti); } +/* + * GtkObject::destroy method + */ static void eti_destroy (GtkObject *object) { @@ -289,6 +377,8 @@ eti_destroy (GtkObject *object) eti_remove_header_model (eti); eti_remove_table_model (eti); + + g_slist_free (eti->selection); if (GTK_OBJECT_CLASS (eti_parent_class)->destroy) (*GTK_OBJECT_CLASS (eti_parent_class)->destroy) (object); @@ -299,7 +389,6 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; - int v; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -343,6 +432,8 @@ eti_init (GnomeCanvasItem *item) eti->height = 0; eti->length_threshold = -1; + + eti->selection_mode = GTK_SELECTION_SINGLE; } static void @@ -355,13 +446,24 @@ eti_realize (GnomeCanvasItem *item) if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize) (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item); + /* + * Gdk Resource allocation + */ window = canvas_widget->window; - + eti->fill_gc = canvas_widget->style->white_gc; gdk_gc_ref (canvas_widget->style->white_gc); + eti->grid_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); + eti->focus_gc = gdk_gc_new (window); + gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->black); + gdk_gc_set_line_attributes (eti->focus_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); + + /* + * + */ eti_realize_cell_views (eti); eti->height = eti_get_height (eti); @@ -377,7 +479,9 @@ eti_unrealize (GnomeCanvasItem *item) eti->fill_gc = NULL; gdk_gc_unref (eti->grid_gc); eti->grid_gc = NULL; - + gdk_gc_unref (eti->focus_gc); + eti->focus_gc = NULL; + eti_unrealize_cell_views (eti); eti->height = 0; @@ -387,26 +491,28 @@ eti_unrealize (GnomeCanvasItem *item) } static void -draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, +draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; ECellView *ecell_view; - GdkFont *font; - char text [40]; - - font = GTK_WIDGET (canvas)->style->font; ecell_view = eti->cell_views [col]; - e_cell_draw (ecell_view, drawable, col, row, x1, y1, x2, y2); + e_cell_draw (ecell_view, drawable, col, row, selected, x1, y1, x2, y2); #if 0 + { + GdkFont *font; + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + font = GTK_WIDGET (canvas)->style->font; + sprintf (text, "%d:%d\n", col, row); gdk_draw_line (drawable, eti->grid_gc, x1, y1, x2, y2); gdk_draw_line (drawable, eti->grid_gc, x1, y2, x2, y1); sprintf (text, "%d:%d\n", col, row); gdk_draw_text (drawable, font, eti->grid_gc, x1, y2, text, strlen (text)); + } #endif } @@ -420,7 +526,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int first_col, last_col, x_offset; int first_row, last_row, y_offset, yd; int x1, x2; - int heights; + int f_x1, f_x2, f_y1, f_y2; + gboolean f_found; printf ("Rect: %d %d %d %d\n", x, y, width, height); /* @@ -435,7 +542,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_col = -1; last_col = x_offset = 0; - x1 = eti->x1; + x1 = x2 = eti->x1; for (col = 0; col < cols; col++, x1 = x2){ ETableCol *ecol = e_table_header_get_column (eti->header, col); @@ -465,9 +572,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, y_offset = 0; y1 = y2 = eti->y1; for (row = eti->top_item; row < rows; row++, y1 = y2){ - int xd; - y2 += eti_row_height (eti, row); + y2 += eti_row_height (eti, row) + 1; if (y1 > y + height) break; @@ -489,24 +595,49 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw cells */ yd = y_offset; + f_x1 = f_x2 = f_y1 = f_y2 = -1; + f_found = FALSE; for (row = first_row; row < last_row; row++){ int xd, height; + gboolean selected; height = eti_row_height (eti, row); xd = x_offset; printf ("paint: %d %d\n", yd, yd + height); + + selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; + for (col = first_col; col < last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); - draw_cell (eti, drawable, col, row, xd, yd, xd + ecol->width, yd + height); + draw_cell (eti, drawable, col, row, selected, xd, yd, xd + ecol->width, yd + height); + if (col == eti->focused_col && row == eti->focused_row){ + f_x1 = xd; + f_x2 = xd + ecol->width; + f_y1 = yd; + f_y2 = yd + height; + f_found = TRUE; + } + xd += ecol->width; } yd += height + 1; gdk_draw_line (drawable, eti->grid_gc, eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); } + + /* + * Draw focus + */ + if (f_found){ + printf ("FOUD: %d %d %d %d!\n", + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + } } static double @@ -547,7 +678,7 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) break; } - y1 = 0; + y1 = y2 = 0; for (row = 0; row < rows; row++, y1 = y2){ if (y < y1) return FALSE; @@ -564,13 +695,6 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) return TRUE; } -static void -eti_select (ETableItem *eti, int col, int row) -{ - eti->selected_col = col; - eti->selected_row = row; -} - static int eti_event (GnomeCanvasItem *item, GdkEvent *e) { @@ -586,22 +710,56 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) return TRUE; - if (eti->selected_row == row && eti->selected_col == col){ + if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; e_cell_event (ecell_view, e, col, row); - } else - eti_select (eti, col, row); + } else { + /* + * Focus the cell, and select the row + */ + e_table_item_focus (eti, col, row); + e_table_item_select_row (eti, row); + } break; } case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: if (eti->focused_col == -1) return FALSE; + switch (e->key.keyval){ + case GDK_Left: + if (eti->focused_col > 0) + e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); + break; + + case GDK_Right: + if ((eti->focused_col + 1) < eti->cols) + e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); + break; + + case GDK_Up: + if (eti->focused_row > 0) + e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); + break; + + case GDK_Down: + if ((eti->focused_row + 1) < eti->rows) + e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); + break; + + default: + } ecell_view = eti->cell_views [eti->focused_col]; + e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); + break; + + case GDK_KEY_RELEASE: + if (eti->focused_col == -1) + return FALSE; + ecell_view = eti->cell_views [eti->focused_col]; e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); break; @@ -610,12 +768,27 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } return TRUE; } + +/* + * ETableItem::row_selection method + */ +static void +eti_row_selection (ETableItem *eti, int row, gboolean selected) +{ + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + if (selected) + eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); + else + eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); +} + static void eti_class_init (GtkObjectClass *object_class) { GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - + ETableItemClass *eti_class = (ETableItemClass *) object_class; + eti_parent_class = gtk_type_class (PARENT_OBJECT_TYPE); object_class->destroy = eti_destroy; @@ -627,7 +800,9 @@ eti_class_init (GtkObjectClass *object_class) item_class->draw = eti_draw; item_class->point = eti_point; item_class->event = eti_event; - + + eti_class->row_selection = eti_row_selection; + gtk_object_add_arg_type ("ETableItem::ETableHeader", GTK_TYPE_POINTER, GTK_ARG_WRITABLE, ARG_TABLE_HEADER); gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_POINTER, @@ -638,6 +813,17 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_Y); gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); + + eti_signals [ROW_SELECTION] = + gtk_signal_new ("row_selection", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, eti_signals, LAST_SIGNAL); + } GtkType @@ -666,16 +852,124 @@ e_table_item_get_type (void) void e_table_item_focus (ETableItem *eti, int col, int row) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (eti->focused_col != -1) e_table_item_unfocus (eti); eti->focused_col = col; - eti->focused_row = row; + eti->focused_row = row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); } void e_table_item_unfocus (ETableItem *eti) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (eti->focused_row == -1) + return; + + { + const int col = eti->focused_col; + const int row = eti->focused_row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + } eti->focused_col = -1; eti->focused_row = -1; } + +const GSList * +e_table_item_get_selection (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); + + return eti->selection; +} + +GtkSelectionMode +e_table_item_get_selection_mode (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, GTK_SELECTION_SINGLE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), GTK_SELECTION_SINGLE); + + return eti->selection_mode; +} + +void +e_table_item_set_selection_mode (ETableItem *eti, GtkSelectionMode selection_mode) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (selection_mode == GTK_SELECTION_BROWSE || + selection_mode == GTK_SELECTION_EXTENDED){ + g_error ("GTK_SELECTION_BROWSE and GTK_SELECTION_EXTENDED are not implemented"); + } + + eti->selection_mode = selection_mode; +} + +gboolean +e_table_item_is_row_selected (ETableItem *eti, int row) +{ + g_return_val_if_fail (eti != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); + + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return TRUE; + else + return FALSE; +} + +void +e_table_item_unselect_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (e_table_item_is_row_selected (eti, row)){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + row, 0); + } +} + +void +e_table_item_select_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + switch (eti->selection_mode){ + case GTK_SELECTION_SINGLE: + if (eti->selection){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GPOINTER_TO_INT (eti->selection->data), 0); + } + g_slist_free (eti->selection); + eti->selection = NULL; + + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + case GTK_SELECTION_MULTIPLE: + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return; + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + default: + + } +} diff --git a/widgets/e-table/e-table-item.h b/widgets/e-table/e-table-item.h index fc36363413..17d422ddf5 100644 --- a/widgets/e-table/e-table-item.h +++ b/widgets/e-table/e-table-item.h @@ -32,6 +32,7 @@ typedef struct { GdkGC *fill_gc; GdkGC *grid_gc; + GdkGC *focus_gc; unsigned int draw_grid:1; @@ -49,15 +50,39 @@ typedef struct { */ int length_threshold; - int selected_col, selected_row; + GSList *selection; + GtkSelectionMode selection_mode; } ETableItem; typedef struct { GnomeCanvasItemClass parent_class; + + void (*row_selection) (ETableItem *eti, int row, gboolean selected); } ETableItemClass; GtkType e_table_item_get_type (void); + +/* + * Focus + */ void e_table_item_focus (ETableItem *eti, int col, int row); void e_table_item_unfocus (ETableItem *eti); +/* + * Selection + */ +void e_table_item_select_row (ETableItem *e_table_Item, int row); +void e_table_item_unselect_row (ETableItem *e_table_Item, int row); + +/* + * Handling the selection + */ +const GSList*e_table_item_get_selection (ETableItem *e_table_Item); + +GtkSelectionMode e_table_item_get_selection_mode (ETableItem *e_table_Item); +void e_table_item_set_selection_mode (ETableItem *e_table_Item, + GtkSelectionMode selection_mode); +gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, + int row); + #endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/e-table/e-table-model.c b/widgets/e-table/e-table-model.c index 3aa4e4be47..288c20f20e 100644 --- a/widgets/e-table/e-table-model.c +++ b/widgets/e-table/e-table-model.c @@ -16,55 +16,71 @@ static GtkObjectClass *e_table_model_parent_class; enum { MODEL_CHANGED, + MODEL_ROW_CHANGED, + MODEL_CELL_CHANGED, ROW_SELECTION, LAST_SIGNAL }; -static guint etm_signals [LAST_SIGNAL] = { 0, }; +static guint e_table_model_signals [LAST_SIGNAL] = { 0, }; int -e_table_model_column_count (ETableModel *etable) +e_table_model_column_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->column_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->column_count (e_table_model); } const char * -e_table_model_column_name (ETableModel *etable, int col) +e_table_model_column_name (ETableModel *e_table_model, int col) { - return ETM_CLASS (etable)->column_name (etable, col); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->column_name (e_table_model, col); } int -e_table_model_row_count (ETableModel *etable) +e_table_model_row_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->row_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->row_count (e_table_model); } void * -e_table_model_value_at (ETableModel *etable, int col, int row) +e_table_model_value_at (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->value_at (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->value_at (e_table_model, col, row); } void -e_table_model_set_value_at (ETableModel *etable, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) { - return ETM_CLASS (etable)->set_value_at (etable, col, row, data); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + + return ETM_CLASS (e_table_model)->set_value_at (e_table_model, col, row, data); } gboolean -e_table_model_is_cell_editable (ETableModel *etable, int col, int row) +e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->is_cell_editable (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE); + + return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); } static void e_table_model_destroy (GtkObject *object) { - GSList *l; - - ETableModel *etable = (ETableModel *) object; - if (e_table_model_parent_class->destroy) (*e_table_model_parent_class->destroy)(object); } @@ -76,7 +92,7 @@ e_table_model_class_init (GtkObjectClass *object_class) object_class->destroy = e_table_model_destroy; - etm_signals [MODEL_CHANGED] = + e_table_model_signals [MODEL_CHANGED] = gtk_signal_new ("model_changed", GTK_RUN_LAST, object_class->type, @@ -84,21 +100,23 @@ e_table_model_class_init (GtkObjectClass *object_class) gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - etm_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", + e_table_model_signals [MODEL_ROW_CHANGED] = + gtk_signal_new ("model_row_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, row_selection), + GTK_SIGNAL_OFFSET (ETableModelClass, model_row_changed), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + e_table_model_signals [MODEL_CELL_CHANGED] = + gtk_signal_new ("model_cell_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableModelClass, model_cell_changed), gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, etm_signals, LAST_SIGNAL); -} -static void -e_table_model_init (ETableModel *etm) -{ - etm->row_selected = -1; + gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); } GtkType @@ -112,7 +130,7 @@ e_table_model_get_type (void) sizeof (ETableModel), sizeof (ETableModelClass), (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) e_table_model_init, + (GtkObjectInitFunc) NULL, NULL, /* reserved 1 */ NULL, /* reserved 2 */ (GtkClassInitFunc) NULL @@ -127,53 +145,31 @@ e_table_model_get_type (void) void e_table_model_changed (ETableModel *e_table_model) { + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + gtk_signal_emit (GTK_OBJECT (e_table_model), - etm_signals [MODEL_CHANGED]); + e_table_model_signals [MODEL_CHANGED]); } -#if 0 -int -e_table_model_max_col_width (ETableModel *etm, int col) +void +e_table_model_row_changed (ETableModel *e_table_model, int row) { - const int nvals = e_table_model_row_count (etm); - int max = 0; - int row; - - for (row = 0; row < nvals; row++){ - int w; - - w = e_table_model_cell_width (etm, col, i); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - if (w > max) - max = w; - } - - return max; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_ROW_CHANGED], row); } -#endif void -e_table_model_select_row (ETableModel *etm, int row) +e_table_model_cell_changed (ETableModel *e_table_model, int col, int row) { - gtk_signal_emit (GTK_OBJECT (etm), etm_signals [ROW_SELECTION], row, 1); - etm->row_selected = row; -} + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); -void -e_table_model_unselect_row (ETableModel *etm, int row) -{ - if (etm->row_selected != -1){ - gtk_signal_emit ( - GTK_OBJECT (etm), etm_signals [ROW_SELECTION], - etm->row_selected, 0); - } - - etm->row_selected = -1; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_CELL_CHANGED], col, row); } -gint -e_table_model_get_selected_row (ETableModel *etm) -{ - return etm->row_selected; -} diff --git a/widgets/e-table/e-table-model.h b/widgets/e-table/e-table-model.h index d8de9e819e..ea5d31493d 100644 --- a/widgets/e-table/e-table-model.h +++ b/widgets/e-table/e-table-model.h @@ -11,9 +11,6 @@ typedef struct { GtkObject base; - - /* Temporary. I swear */ - int row_selected; } ETableModel; typedef struct { @@ -32,8 +29,9 @@ typedef struct { /* * Signals */ - void (*model_changed) (ETableModel *etm); - void (*row_selection) (ETableModel *etc, int row, gboolean selected); + void (*model_changed) (ETableModel *etm); + void (*model_row_changed) (ETableModel *etm, int row); + void (*model_cell_changed) (ETableModel *etm, int col, int row); } ETableModelClass; GtkType e_table_model_get_type (void); @@ -45,13 +43,13 @@ void *e_table_model_value_at (ETableModel *e_table_model, int col, void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); -void e_table_model_select_row (ETableModel *e_table_model, int row); -gint e_table_model_get_selected_row (ETableModel *e_table_model); - /* * Routines for emitting signals on the e_table */ void e_table_model_changed (ETableModel *e_table_model); +void e_table_model_row_changed (ETableModel *e_table_model, int row); +void e_table_model_cell_changed (ETableModel *e_table_model, int col, int row); #endif /* _E_TABLE_MODEL_H_ */ + diff --git a/widgets/e-table/e-table-sorted.c b/widgets/e-table/e-table-sorted.c index be19de2efb..90773e9cdc 100644 --- a/widgets/e-table/e-table-sorted.c +++ b/widgets/e-table/e-table-sorted.c @@ -30,7 +30,6 @@ static ETableSorted *sort_ets; static int my_sort (const void *a, const void *b) { - GCompareFunc comp; ETableModel *source = E_TABLE_SUBSET (sort_ets)->source; const int *ia = (const int *) a; const int *ib = (const int *) b; @@ -59,7 +58,6 @@ e_table_sorted_new (ETableModel *source, int col, GCompareFunc compare) ETableSorted *ets = gtk_type_new (E_TABLE_SORTED_TYPE); ETableSubset *etss = E_TABLE_SUBSET (ets); const int nvals = e_table_model_row_count (source); - unsigned int *buffer; int i; if (e_table_subset_construct (etss, source, nvals) == NULL){ diff --git a/widgets/e-table/table-test.c b/widgets/e-table/table-test.c index 73be9e5ecd..3517ecf692 100644 --- a/widgets/e-table/table-test.c +++ b/widgets/e-table/table-test.c @@ -12,6 +12,8 @@ #include "e-table-header.h" #include "e-table-header-item.h" #include "e-table-item.h" +#include "e-cursors.h" +#include "e-cell-text.h" char buffer [1024]; char **column_labels; @@ -157,7 +159,7 @@ set_value_at (ETableModel *etc, int col, int row, void *val, void *data) g_free (table_data [row][col]); table_data [row][col] = g_strdup (val); - printf ("Value at %d,%d set to %s\n", col, row, val); + printf ("Value at %d,%d set to %s\n", col, row, (char *) val); } static gboolean diff --git a/widgets/table-test.c b/widgets/table-test.c index 73be9e5ecd..3517ecf692 100644 --- a/widgets/table-test.c +++ b/widgets/table-test.c @@ -12,6 +12,8 @@ #include "e-table-header.h" #include "e-table-header-item.h" #include "e-table-item.h" +#include "e-cursors.h" +#include "e-cell-text.h" char buffer [1024]; char **column_labels; @@ -157,7 +159,7 @@ set_value_at (ETableModel *etc, int col, int row, void *val, void *data) g_free (table_data [row][col]); table_data [row][col] = g_strdup (val); - printf ("Value at %d,%d set to %s\n", col, row, val); + printf ("Value at %d,%d set to %s\n", col, row, (char *) val); } static gboolean diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index da26302664..a997d745d3 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -64,13 +64,14 @@ ect_unrealize (ECellView *ecv) } static void -ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ect_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int selected = e_table_model_get_selected_row (ecell_view->ecell->table_model) == row; int xoff, w; rect.x = x1; @@ -94,6 +95,7 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1 xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; break; default: + xoff = 0; g_warning ("Can not handle GTK_JUSTIFY_FILL"); break; } @@ -135,12 +137,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: - if (e_table_model_get_selected_row (ecell->table_model) == row) - e_cell_text_start_editing (ect, col, row); - else - e_table_model_select_row (ecell->table_model, row); return TRUE; + + default: + break; } + return FALSE; } static int diff --git a/widgets/table/e-cell.c b/widgets/table/e-cell.c index 8a8897c22a..9caa31f2ca 100644 --- a/widgets/table/e-cell.c +++ b/widgets/table/e-cell.c @@ -24,7 +24,9 @@ ec_unrealize (ECellView *e_cell) } static void -ec_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, int x1, int y1, int x2, int y2) +ec_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) { g_warning ("e-cell-draw invoked\n"); } @@ -33,6 +35,7 @@ static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { g_warning ("e-cell-event invoked\n"); + return 0; } static gint @@ -109,10 +112,10 @@ e_cell_unrealize (ECellView *ecell_view) void e_cell_draw (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2) + int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->draw ( - ecell_view, drawable, col, row, x1, y1, x2, y2); + ecell_view, drawable, col, row, selected, x1, y1, x2, y2); } int diff --git a/widgets/table/e-cell.h b/widgets/table/e-cell.h index e57f341098..9cd62f3909 100644 --- a/widgets/table/e-cell.h +++ b/widgets/table/e-cell.h @@ -32,7 +32,7 @@ typedef struct { ECellView *(*realize) (ECell *, GnomeCanvas *canvas); void (*unrealize) (ECellView *); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, - int col, int row, int x1, int y1, int x2, int y2); + int col, int row, gboolean selected, int x1, int y1, int x2, int y2); gint (*event) (ECellView *ecell_view, GdkEvent *event, int col, int row); void (*focus) (ECellView *ecell, int col, int row, int x1, int y1, int x2, int y2); void (*unfocus) (ECellView *ecell); @@ -43,8 +43,9 @@ GtkType e_cell_get_type (void); void e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row); ECellView *e_cell_realize (ECell *ecell, GnomeCanvas *canvas); void e_cell_unrealize (ECellView *ecell_view); -void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, - int col, int row, int x1, int y1, int x2, int y2); +void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2); void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); diff --git a/widgets/table/e-table-col.c b/widgets/table/e-table-col.c index 4c61cddd0f..3ffc45a2ed 100644 --- a/widgets/table/e-table-col.c +++ b/widgets/table/e-table-col.c @@ -17,11 +17,11 @@ e_table_col_new (const char *id, int width, int min_width, { ETableCol *etc; - g_return_if_fail (id != NULL); - g_return_if_fail (width >= 0); - g_return_if_fail (min_width >= 0); - g_return_if_fail (width >= min_width); - g_return_if_fail (compare != NULL); + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (width >= 0, NULL); + g_return_val_if_fail (min_width >= 0, NULL); + g_return_val_if_fail (width >= min_width, NULL); + g_return_val_if_fail (compare != NULL, NULL); etc = g_new (ETableCol, 1); diff --git a/widgets/table/e-table-group.c b/widgets/table/e-table-group.c index bc751229a4..b1e681d255 100644 --- a/widgets/table/e-table-group.c +++ b/widgets/table/e-table-group.c @@ -76,10 +76,11 @@ e_table_group_append_child (ETableGroup *etg, ETableGroup *child) etg->u.children = g_slist_append (etg->u.children, child); } +#if 0 int e_table_group_size (ETableGroup *etg) { - g_return_if_fail (etg != NULL); + g_return_val_if_fail (etg != NULL, 0); if (etg->is_leaf) return e_table_model_height (etg->u.table); @@ -96,3 +97,4 @@ e_table_group_size (ETableGroup *etg) } } +#endif diff --git a/widgets/table/e-table-header-item.c b/widgets/table/e-table-header-item.c index 2ee8e2d619..1be7e7097b 100644 --- a/widgets/table/e-table-header-item.c +++ b/widgets/table/e-table-header-item.c @@ -7,6 +7,7 @@ * Copyright 1999, Helix Code, Inc. */ #include +#include #include "e-table-header.h" #include "e-table-header-item.h" #include "e-cursors.h" @@ -124,7 +125,6 @@ ethi_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableHeaderItem *ethi; - int v; item = GNOME_CANVAS_ITEM (o); ethi = E_TABLE_HEADER_ITEM (o); diff --git a/widgets/table/e-table-header.c b/widgets/table/e-table-header.c index 2279bf4ba6..5900c5ca4f 100644 --- a/widgets/table/e-table-header.c +++ b/widgets/table/e-table-header.c @@ -121,8 +121,6 @@ eth_update_offsets (ETableHeader *eth) void e_table_header_add_column (ETableHeader *eth, ETableCol *tc, int pos) { - ETableCol **new_ptr; - g_return_if_fail (eth != NULL); g_return_if_fail (E_IS_TABLE_HEADER (eth)); g_return_if_fail (tc != NULL); @@ -204,7 +202,6 @@ ETableCol ** e_table_header_get_columns (ETableHeader *eth) { ETableCol **ret; - int i; g_return_val_if_fail (eth != NULL, 0); g_return_val_if_fail (E_IS_TABLE_HEADER (eth), 0); @@ -226,7 +223,7 @@ e_table_header_selection_ok (ETableHeader *eth) } int -ve_table_header_get_selected (ETableHeader *eth) +e_table_header_get_selected (ETableHeader *eth) { int i; int selected = 0; diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 3b35f6c156..a561fbfd15 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -1,19 +1,35 @@ /* - * E-table-item.c: A view of a Table. + * E-table-item.c: A GnomeCanvasItem that is a view of an ETableModel. * * Author: * Miguel de Icaza (miguel@gnu.org) * * Copyright 1999, Helix Code, Inc. + * + * TODO: + * Add a border to the thing, so that focusing works properly. + * */ #include +#include +#include +#include #include "e-table-item.h" #include "e-cell.h" #define PARENT_OBJECT_TYPE gnome_canvas_item_get_type () +#define FOCUSED_BORDER 2 + static GnomeCanvasItemClass *eti_parent_class; +enum { + ROW_SELECTION, + LAST_SIGNAL +}; + +static gint eti_signals [LAST_SIGNAL] = { 0, }; + enum { ARG_0, ARG_TABLE_HEADER, @@ -24,6 +40,14 @@ enum { ARG_LENGHT_THRESHOLD }; +/* + * During realization, we have to invoke the per-ecell realize routine + * (On our current setup, we have one e-cell per column. + * + * We might want to optimize this to only realize the unique e-cells: + * ie, a strings-only table, uses the same e-cell for every column, and + * we might want to avoid realizing each e-cell. + */ static void eti_realize_cell_views (ETableItem *eti) { @@ -43,14 +67,16 @@ eti_realize_cell_views (ETableItem *eti) } } +/* + * During unrealization: we invoke every e-cell (one per column in the current + * setup) to dispose all resources allocated + */ static void eti_unrealize_cell_views (ETableItem *eti) { int i; for (i = 0; i < eti->n_cells; i++){ - ETableCol *col = e_table_header_get_column (eti->header, i); - e_cell_unrealize (eti->cell_views [i]); eti->cell_views [i] = NULL; } @@ -59,6 +85,9 @@ eti_unrealize_cell_views (ETableItem *eti) } +/* + * GnomeCanvasItem::update method + */ static void eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) { @@ -75,14 +104,21 @@ eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); } +/* + * eti_remove_table_model: + * + * Invoked to release the table model associated with this ETableItem + */ static void eti_remove_table_model (ETableItem *eti) { if (!eti->table_model) return; - gtk_signal_disconnect (eti->table_model_change_id); - gtk_signal_disconnect (eti->table_model_selection_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->table_model), + eti->table_model_selection_id); gtk_object_unref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = 0; @@ -90,14 +126,21 @@ eti_remove_table_model (ETableItem *eti) eti->table_model = NULL; } +/* + * eti_remove_header_model: + * + * Invoked to release the header model associated with this ETableItem + */ static void eti_remove_header_model (ETableItem *eti) { if (!eti->header) return; - gtk_signal_disconnect (eti->header_structure_change_id); - gtk_signal_disconnect (eti->header_dim_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_structure_change_id); + gtk_signal_disconnect (GTK_OBJECT (eti->header), + eti->header_dim_change_id); gtk_object_unref (GTK_OBJECT (eti->header)); eti->header_structure_change_id = 0; @@ -105,6 +148,12 @@ eti_remove_header_model (ETableItem *eti) eti->header = NULL; } +/* + * eti_row_height: + * + * Returns the height used by row @row. This does not include the one-pixel + * used as a separator between rows + */ static int eti_row_height (ETableItem *eti, int row) { @@ -123,6 +172,18 @@ eti_row_height (ETableItem *eti, int row) return max_h; } +/* + * eti_get_height: + * + * Returns the height of the ETableItem. + * + * The ETableItem might compute the whole height by asking every row its + * size. There is a special mode (designed to work when there are too + * many rows in the table that performing the previous step could take + * too long) set by the ETableItem->length_threshold that would determine + * when the height is computed by using the first row as the size for + * every other row in the ETableItem. + */ static int eti_get_height (ETableItem *eti) { @@ -148,6 +209,9 @@ eti_get_height (ETableItem *eti) return height; } +/* + * Callback routine: invoked when the ETableModel has suffered a change + */ static void eti_table_model_changed (ETableModel *table_model, ETableItem *eti) { @@ -160,6 +224,11 @@ eti_table_model_changed (ETableModel *table_model, ETableItem *eti) eti_update (GNOME_CANVAS_ITEM (eti), NULL, NULL, 0); } +/* + * eti_request_redraw: + * + * Queues a canvas redraw for the entire ETableItem. + */ static void eti_request_redraw (ETableItem *eti) { @@ -170,6 +239,9 @@ eti_request_redraw (ETableItem *eti) eti->y1 + eti->height + 1); } +/* + * Computes the distance from @start_col to @end_col in pixels. + */ static int eti_col_diff (ETableItem *eti, int start_col, int end_col) { @@ -185,6 +257,9 @@ eti_col_diff (ETableItem *eti, int start_col, int end_col) return total; } +/* + * Computes the distance between @start_row and @end_row in pixels + */ static int eti_row_diff (ETableItem *eti, int start_row, int end_row) { @@ -198,28 +273,38 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) return total; } +/* + * eti_request_region_redraw: + * + * Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row). + * This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell). + * + * The @border argument is a number of pixels around the region that should also be queued + * for redraw. This is typically used by the focus routines to queue a redraw for the + * border as well. + */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row) +eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) { GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; int x1, y1, width, height; - int col, row; x1 = eti_col_diff (eti, 0, start_col); y1 = eti_row_diff (eti, 0, start_row); - width = eti_col_diff (eti, start_col, end_col); - height = eti_row_diff (eti, start_col, end_row); - + width = eti_col_diff (eti, start_col, end_col + 1); + height = eti_row_diff (eti, start_row, end_row + 1); + gnome_canvas_request_redraw (canvas, - eti->x1 + x1, eti->y1 + y1, - eti->y1 + width + 1, - eti->x1 + height + 1); + eti->x1 + x1 - border, + eti->y1 + y1 - border, + eti->x1 + x1 + width + 1 + border, + eti->y1 + y1 + height + 1 + border); } static void eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) { - eti_request_region_redraw (eti, 0, row, eti->cols, row); + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); } static void @@ -282,6 +367,9 @@ eti_add_header_model (ETableItem *eti, ETableHeader *header) GTK_SIGNAL_FUNC (eti_header_structure_changed), eti); } +/* + * GtkObject::destroy method + */ static void eti_destroy (GtkObject *object) { @@ -289,6 +377,8 @@ eti_destroy (GtkObject *object) eti_remove_header_model (eti); eti_remove_table_model (eti); + + g_slist_free (eti->selection); if (GTK_OBJECT_CLASS (eti_parent_class)->destroy) (*GTK_OBJECT_CLASS (eti_parent_class)->destroy) (object); @@ -299,7 +389,6 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) { GnomeCanvasItem *item; ETableItem *eti; - int v; item = GNOME_CANVAS_ITEM (o); eti = E_TABLE_ITEM (o); @@ -343,6 +432,8 @@ eti_init (GnomeCanvasItem *item) eti->height = 0; eti->length_threshold = -1; + + eti->selection_mode = GTK_SELECTION_SINGLE; } static void @@ -355,13 +446,24 @@ eti_realize (GnomeCanvasItem *item) if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize) (*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item); + /* + * Gdk Resource allocation + */ window = canvas_widget->window; - + eti->fill_gc = canvas_widget->style->white_gc; gdk_gc_ref (canvas_widget->style->white_gc); + eti->grid_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); + eti->focus_gc = gdk_gc_new (window); + gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->black); + gdk_gc_set_line_attributes (eti->focus_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); + + /* + * + */ eti_realize_cell_views (eti); eti->height = eti_get_height (eti); @@ -377,7 +479,9 @@ eti_unrealize (GnomeCanvasItem *item) eti->fill_gc = NULL; gdk_gc_unref (eti->grid_gc); eti->grid_gc = NULL; - + gdk_gc_unref (eti->focus_gc); + eti->focus_gc = NULL; + eti_unrealize_cell_views (eti); eti->height = 0; @@ -387,26 +491,28 @@ eti_unrealize (GnomeCanvasItem *item) } static void -draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, +draw_cell (ETableItem *eti, GdkDrawable *drawable, int col, int row, gboolean selected, int x1, int y1, int x2, int y2) { - GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; ECellView *ecell_view; - GdkFont *font; - char text [40]; - - font = GTK_WIDGET (canvas)->style->font; ecell_view = eti->cell_views [col]; - e_cell_draw (ecell_view, drawable, col, row, x1, y1, x2, y2); + e_cell_draw (ecell_view, drawable, col, row, selected, x1, y1, x2, y2); #if 0 + { + GdkFont *font; + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + font = GTK_WIDGET (canvas)->style->font; + sprintf (text, "%d:%d\n", col, row); gdk_draw_line (drawable, eti->grid_gc, x1, y1, x2, y2); gdk_draw_line (drawable, eti->grid_gc, x1, y2, x2, y1); sprintf (text, "%d:%d\n", col, row); gdk_draw_text (drawable, font, eti->grid_gc, x1, y2, text, strlen (text)); + } #endif } @@ -420,7 +526,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int first_col, last_col, x_offset; int first_row, last_row, y_offset, yd; int x1, x2; - int heights; + int f_x1, f_x2, f_y1, f_y2; + gboolean f_found; printf ("Rect: %d %d %d %d\n", x, y, width, height); /* @@ -435,7 +542,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_col = -1; last_col = x_offset = 0; - x1 = eti->x1; + x1 = x2 = eti->x1; for (col = 0; col < cols; col++, x1 = x2){ ETableCol *ecol = e_table_header_get_column (eti->header, col); @@ -465,9 +572,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, y_offset = 0; y1 = y2 = eti->y1; for (row = eti->top_item; row < rows; row++, y1 = y2){ - int xd; - y2 += eti_row_height (eti, row); + y2 += eti_row_height (eti, row) + 1; if (y1 > y + height) break; @@ -489,24 +595,49 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw cells */ yd = y_offset; + f_x1 = f_x2 = f_y1 = f_y2 = -1; + f_found = FALSE; for (row = first_row; row < last_row; row++){ int xd, height; + gboolean selected; height = eti_row_height (eti, row); xd = x_offset; printf ("paint: %d %d\n", yd, yd + height); + + selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; + for (col = first_col; col < last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); - draw_cell (eti, drawable, col, row, xd, yd, xd + ecol->width, yd + height); + draw_cell (eti, drawable, col, row, selected, xd, yd, xd + ecol->width, yd + height); + if (col == eti->focused_col && row == eti->focused_row){ + f_x1 = xd; + f_x2 = xd + ecol->width; + f_y1 = yd; + f_y2 = yd + height; + f_found = TRUE; + } + xd += ecol->width; } yd += height + 1; gdk_draw_line (drawable, eti->grid_gc, eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); } + + /* + * Draw focus + */ + if (f_found){ + printf ("FOUD: %d %d %d %d!\n", + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); + } } static double @@ -547,7 +678,7 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) break; } - y1 = 0; + y1 = y2 = 0; for (row = 0; row < rows; row++, y1 = y2){ if (y < y1) return FALSE; @@ -564,13 +695,6 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) return TRUE; } -static void -eti_select (ETableItem *eti, int col, int row) -{ - eti->selected_col = col; - eti->selected_row = row; -} - static int eti_event (GnomeCanvasItem *item, GdkEvent *e) { @@ -586,22 +710,56 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) return TRUE; - if (eti->selected_row == row && eti->selected_col == col){ + if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; e_cell_event (ecell_view, e, col, row); - } else - eti_select (eti, col, row); + } else { + /* + * Focus the cell, and select the row + */ + e_table_item_focus (eti, col, row); + e_table_item_select_row (eti, row); + } break; } case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: if (eti->focused_col == -1) return FALSE; + switch (e->key.keyval){ + case GDK_Left: + if (eti->focused_col > 0) + e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); + break; + + case GDK_Right: + if ((eti->focused_col + 1) < eti->cols) + e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); + break; + + case GDK_Up: + if (eti->focused_row > 0) + e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); + break; + + case GDK_Down: + if ((eti->focused_row + 1) < eti->rows) + e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); + break; + + default: + } ecell_view = eti->cell_views [eti->focused_col]; + e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); + break; + + case GDK_KEY_RELEASE: + if (eti->focused_col == -1) + return FALSE; + ecell_view = eti->cell_views [eti->focused_col]; e_cell_event (ecell_view, e, eti->focused_col, eti->focused_row); break; @@ -610,12 +768,27 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } return TRUE; } + +/* + * ETableItem::row_selection method + */ +static void +eti_row_selection (ETableItem *eti, int row, gboolean selected) +{ + eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + if (selected) + eti->selection = g_slist_prepend (eti->selection, GINT_TO_POINTER (row)); + else + eti->selection = g_slist_remove (eti->selection, GINT_TO_POINTER (row)); +} + static void eti_class_init (GtkObjectClass *object_class) { GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class; - + ETableItemClass *eti_class = (ETableItemClass *) object_class; + eti_parent_class = gtk_type_class (PARENT_OBJECT_TYPE); object_class->destroy = eti_destroy; @@ -627,7 +800,9 @@ eti_class_init (GtkObjectClass *object_class) item_class->draw = eti_draw; item_class->point = eti_point; item_class->event = eti_event; - + + eti_class->row_selection = eti_row_selection; + gtk_object_add_arg_type ("ETableItem::ETableHeader", GTK_TYPE_POINTER, GTK_ARG_WRITABLE, ARG_TABLE_HEADER); gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_POINTER, @@ -638,6 +813,17 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_Y); gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); + + eti_signals [ROW_SELECTION] = + gtk_signal_new ("row_selection", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableItemClass, row_selection), + gtk_marshal_NONE__INT_INT, + GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, eti_signals, LAST_SIGNAL); + } GtkType @@ -666,16 +852,124 @@ e_table_item_get_type (void) void e_table_item_focus (ETableItem *eti, int col, int row) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (eti->focused_col != -1) e_table_item_unfocus (eti); eti->focused_col = col; - eti->focused_row = row; + eti->focused_row = row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); } void e_table_item_unfocus (ETableItem *eti) { + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (eti->focused_row == -1) + return; + + { + const int col = eti->focused_col; + const int row = eti->focused_row; + + eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + } eti->focused_col = -1; eti->focused_row = -1; } + +const GSList * +e_table_item_get_selection (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), NULL); + + return eti->selection; +} + +GtkSelectionMode +e_table_item_get_selection_mode (ETableItem *eti) +{ + g_return_val_if_fail (eti != NULL, GTK_SELECTION_SINGLE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), GTK_SELECTION_SINGLE); + + return eti->selection_mode; +} + +void +e_table_item_set_selection_mode (ETableItem *eti, GtkSelectionMode selection_mode) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (selection_mode == GTK_SELECTION_BROWSE || + selection_mode == GTK_SELECTION_EXTENDED){ + g_error ("GTK_SELECTION_BROWSE and GTK_SELECTION_EXTENDED are not implemented"); + } + + eti->selection_mode = selection_mode; +} + +gboolean +e_table_item_is_row_selected (ETableItem *eti, int row) +{ + g_return_val_if_fail (eti != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE); + + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return TRUE; + else + return FALSE; +} + +void +e_table_item_unselect_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if (e_table_item_is_row_selected (eti, row)){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + row, 0); + } +} + +void +e_table_item_select_row (ETableItem *eti, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + switch (eti->selection_mode){ + case GTK_SELECTION_SINGLE: + if (eti->selection){ + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GPOINTER_TO_INT (eti->selection->data), 0); + } + g_slist_free (eti->selection); + eti->selection = NULL; + + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + case GTK_SELECTION_MULTIPLE: + if (g_slist_find (eti->selection, GINT_TO_POINTER (row))) + return; + gtk_signal_emit ( + GTK_OBJECT (eti), eti_signals [ROW_SELECTION], + GINT_TO_POINTER (row), 1); + break; + + default: + + } +} diff --git a/widgets/table/e-table-item.h b/widgets/table/e-table-item.h index fc36363413..17d422ddf5 100644 --- a/widgets/table/e-table-item.h +++ b/widgets/table/e-table-item.h @@ -32,6 +32,7 @@ typedef struct { GdkGC *fill_gc; GdkGC *grid_gc; + GdkGC *focus_gc; unsigned int draw_grid:1; @@ -49,15 +50,39 @@ typedef struct { */ int length_threshold; - int selected_col, selected_row; + GSList *selection; + GtkSelectionMode selection_mode; } ETableItem; typedef struct { GnomeCanvasItemClass parent_class; + + void (*row_selection) (ETableItem *eti, int row, gboolean selected); } ETableItemClass; GtkType e_table_item_get_type (void); + +/* + * Focus + */ void e_table_item_focus (ETableItem *eti, int col, int row); void e_table_item_unfocus (ETableItem *eti); +/* + * Selection + */ +void e_table_item_select_row (ETableItem *e_table_Item, int row); +void e_table_item_unselect_row (ETableItem *e_table_Item, int row); + +/* + * Handling the selection + */ +const GSList*e_table_item_get_selection (ETableItem *e_table_Item); + +GtkSelectionMode e_table_item_get_selection_mode (ETableItem *e_table_Item); +void e_table_item_set_selection_mode (ETableItem *e_table_Item, + GtkSelectionMode selection_mode); +gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, + int row); + #endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/table/e-table-model.c b/widgets/table/e-table-model.c index 3aa4e4be47..288c20f20e 100644 --- a/widgets/table/e-table-model.c +++ b/widgets/table/e-table-model.c @@ -16,55 +16,71 @@ static GtkObjectClass *e_table_model_parent_class; enum { MODEL_CHANGED, + MODEL_ROW_CHANGED, + MODEL_CELL_CHANGED, ROW_SELECTION, LAST_SIGNAL }; -static guint etm_signals [LAST_SIGNAL] = { 0, }; +static guint e_table_model_signals [LAST_SIGNAL] = { 0, }; int -e_table_model_column_count (ETableModel *etable) +e_table_model_column_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->column_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->column_count (e_table_model); } const char * -e_table_model_column_name (ETableModel *etable, int col) +e_table_model_column_name (ETableModel *e_table_model, int col) { - return ETM_CLASS (etable)->column_name (etable, col); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->column_name (e_table_model, col); } int -e_table_model_row_count (ETableModel *etable) +e_table_model_row_count (ETableModel *e_table_model) { - return ETM_CLASS (etable)->row_count (etable); + g_return_val_if_fail (e_table_model != NULL, 0); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), 0); + + return ETM_CLASS (e_table_model)->row_count (e_table_model); } void * -e_table_model_value_at (ETableModel *etable, int col, int row) +e_table_model_value_at (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->value_at (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, NULL); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), NULL); + + return ETM_CLASS (e_table_model)->value_at (e_table_model, col, row); } void -e_table_model_set_value_at (ETableModel *etable, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) { - return ETM_CLASS (etable)->set_value_at (etable, col, row, data); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + + return ETM_CLASS (e_table_model)->set_value_at (e_table_model, col, row, data); } gboolean -e_table_model_is_cell_editable (ETableModel *etable, int col, int row) +e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row) { - return ETM_CLASS (etable)->is_cell_editable (etable, col, row); + g_return_val_if_fail (e_table_model != NULL, FALSE); + g_return_val_if_fail (E_IS_TABLE_MODEL (e_table_model), FALSE); + + return ETM_CLASS (e_table_model)->is_cell_editable (e_table_model, col, row); } static void e_table_model_destroy (GtkObject *object) { - GSList *l; - - ETableModel *etable = (ETableModel *) object; - if (e_table_model_parent_class->destroy) (*e_table_model_parent_class->destroy)(object); } @@ -76,7 +92,7 @@ e_table_model_class_init (GtkObjectClass *object_class) object_class->destroy = e_table_model_destroy; - etm_signals [MODEL_CHANGED] = + e_table_model_signals [MODEL_CHANGED] = gtk_signal_new ("model_changed", GTK_RUN_LAST, object_class->type, @@ -84,21 +100,23 @@ e_table_model_class_init (GtkObjectClass *object_class) gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); - etm_signals [ROW_SELECTION] = - gtk_signal_new ("row_selection", + e_table_model_signals [MODEL_ROW_CHANGED] = + gtk_signal_new ("model_row_changed", GTK_RUN_LAST, object_class->type, - GTK_SIGNAL_OFFSET (ETableModelClass, row_selection), + GTK_SIGNAL_OFFSET (ETableModelClass, model_row_changed), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + e_table_model_signals [MODEL_CELL_CHANGED] = + gtk_signal_new ("model_cell_changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ETableModelClass, model_cell_changed), gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); - - gtk_object_class_add_signals (object_class, etm_signals, LAST_SIGNAL); -} -static void -e_table_model_init (ETableModel *etm) -{ - etm->row_selected = -1; + gtk_object_class_add_signals (object_class, e_table_model_signals, LAST_SIGNAL); } GtkType @@ -112,7 +130,7 @@ e_table_model_get_type (void) sizeof (ETableModel), sizeof (ETableModelClass), (GtkClassInitFunc) e_table_model_class_init, - (GtkObjectInitFunc) e_table_model_init, + (GtkObjectInitFunc) NULL, NULL, /* reserved 1 */ NULL, /* reserved 2 */ (GtkClassInitFunc) NULL @@ -127,53 +145,31 @@ e_table_model_get_type (void) void e_table_model_changed (ETableModel *e_table_model) { + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); + gtk_signal_emit (GTK_OBJECT (e_table_model), - etm_signals [MODEL_CHANGED]); + e_table_model_signals [MODEL_CHANGED]); } -#if 0 -int -e_table_model_max_col_width (ETableModel *etm, int col) +void +e_table_model_row_changed (ETableModel *e_table_model, int row) { - const int nvals = e_table_model_row_count (etm); - int max = 0; - int row; - - for (row = 0; row < nvals; row++){ - int w; - - w = e_table_model_cell_width (etm, col, i); + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); - if (w > max) - max = w; - } - - return max; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_ROW_CHANGED], row); } -#endif void -e_table_model_select_row (ETableModel *etm, int row) +e_table_model_cell_changed (ETableModel *e_table_model, int col, int row) { - gtk_signal_emit (GTK_OBJECT (etm), etm_signals [ROW_SELECTION], row, 1); - etm->row_selected = row; -} + g_return_if_fail (e_table_model != NULL); + g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); -void -e_table_model_unselect_row (ETableModel *etm, int row) -{ - if (etm->row_selected != -1){ - gtk_signal_emit ( - GTK_OBJECT (etm), etm_signals [ROW_SELECTION], - etm->row_selected, 0); - } - - etm->row_selected = -1; + gtk_signal_emit (GTK_OBJECT (e_table_model), + e_table_model_signals [MODEL_CELL_CHANGED], col, row); } -gint -e_table_model_get_selected_row (ETableModel *etm) -{ - return etm->row_selected; -} diff --git a/widgets/table/e-table-model.h b/widgets/table/e-table-model.h index d8de9e819e..ea5d31493d 100644 --- a/widgets/table/e-table-model.h +++ b/widgets/table/e-table-model.h @@ -11,9 +11,6 @@ typedef struct { GtkObject base; - - /* Temporary. I swear */ - int row_selected; } ETableModel; typedef struct { @@ -32,8 +29,9 @@ typedef struct { /* * Signals */ - void (*model_changed) (ETableModel *etm); - void (*row_selection) (ETableModel *etc, int row, gboolean selected); + void (*model_changed) (ETableModel *etm); + void (*model_row_changed) (ETableModel *etm, int row); + void (*model_cell_changed) (ETableModel *etm, int col, int row); } ETableModelClass; GtkType e_table_model_get_type (void); @@ -45,13 +43,13 @@ void *e_table_model_value_at (ETableModel *e_table_model, int col, void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); -void e_table_model_select_row (ETableModel *e_table_model, int row); -gint e_table_model_get_selected_row (ETableModel *e_table_model); - /* * Routines for emitting signals on the e_table */ void e_table_model_changed (ETableModel *e_table_model); +void e_table_model_row_changed (ETableModel *e_table_model, int row); +void e_table_model_cell_changed (ETableModel *e_table_model, int col, int row); #endif /* _E_TABLE_MODEL_H_ */ + diff --git a/widgets/table/e-table-sorted.c b/widgets/table/e-table-sorted.c index be19de2efb..90773e9cdc 100644 --- a/widgets/table/e-table-sorted.c +++ b/widgets/table/e-table-sorted.c @@ -30,7 +30,6 @@ static ETableSorted *sort_ets; static int my_sort (const void *a, const void *b) { - GCompareFunc comp; ETableModel *source = E_TABLE_SUBSET (sort_ets)->source; const int *ia = (const int *) a; const int *ib = (const int *) b; @@ -59,7 +58,6 @@ e_table_sorted_new (ETableModel *source, int col, GCompareFunc compare) ETableSorted *ets = gtk_type_new (E_TABLE_SORTED_TYPE); ETableSubset *etss = E_TABLE_SUBSET (ets); const int nvals = e_table_model_row_count (source); - unsigned int *buffer; int i; if (e_table_subset_construct (etss, source, nvals) == NULL){ diff --git a/widgets/table/table-test.c b/widgets/table/table-test.c index 73be9e5ecd..3517ecf692 100644 --- a/widgets/table/table-test.c +++ b/widgets/table/table-test.c @@ -12,6 +12,8 @@ #include "e-table-header.h" #include "e-table-header-item.h" #include "e-table-item.h" +#include "e-cursors.h" +#include "e-cell-text.h" char buffer [1024]; char **column_labels; @@ -157,7 +159,7 @@ set_value_at (ETableModel *etc, int col, int row, void *val, void *data) g_free (table_data [row][col]); table_data [row][col] = g_strdup (val); - printf ("Value at %d,%d set to %s\n", col, row, val); + printf ("Value at %d,%d set to %s\n", col, row, (char *) val); } static gboolean -- cgit v1.2.3