From 1a0d4df95730ab26981b3f26aa365aae84da36f5 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Sun, 28 Nov 1999 22:26:39 +0000 Subject: New methods; They implement editing. 1999-11-28 Miguel de Icaza * e-cell-text.c (ect_enter_edit, ect_leave_edit): New methods; They implement editing. * e-cell.h: new methods: enter_edit, leave_edit * e-table-model.h (set_value_at): make val argument const. * e-table-simple.c (simple_set_value_at): Make value argument const; * e-table-item.c (eti_set_arg): Add new mode: draw_focus; svn path=/trunk/; revision=1442 --- widgets/ChangeLog | 13 ++ widgets/e-cell-text.c | 361 ++++++++++++++++++++++++++++++++------- widgets/e-cell.c | 25 ++- widgets/e-cell.h | 20 ++- widgets/e-table-item.c | 87 +++++++--- widgets/e-table-item.h | 17 +- widgets/e-table-model.c | 2 +- widgets/e-table-model.h | 4 +- widgets/e-table-simple.c | 2 +- widgets/e-table-simple.h | 2 +- widgets/e-table/ChangeLog | 13 ++ widgets/e-table/e-cell-text.c | 361 ++++++++++++++++++++++++++++++++------- widgets/e-table/e-cell.c | 25 ++- widgets/e-table/e-cell.h | 20 ++- widgets/e-table/e-table-item.c | 87 +++++++--- widgets/e-table/e-table-item.h | 17 +- widgets/e-table/e-table-model.c | 2 +- widgets/e-table/e-table-model.h | 4 +- widgets/e-table/e-table-simple.c | 2 +- widgets/e-table/e-table-simple.h | 2 +- widgets/e-table/table-test.c | 3 +- widgets/table-test.c | 3 +- widgets/table/e-cell-text.c | 361 ++++++++++++++++++++++++++++++++------- widgets/table/e-cell.c | 25 ++- widgets/table/e-cell.h | 20 ++- widgets/table/e-table-item.c | 87 +++++++--- widgets/table/e-table-item.h | 17 +- widgets/table/e-table-model.c | 2 +- widgets/table/e-table-model.h | 4 +- widgets/table/e-table-simple.c | 2 +- widgets/table/e-table-simple.h | 2 +- widgets/table/table-test.c | 3 +- 32 files changed, 1301 insertions(+), 294 deletions(-) (limited to 'widgets') diff --git a/widgets/ChangeLog b/widgets/ChangeLog index 20d4c1e3d7..afc69d71a4 100644 --- a/widgets/ChangeLog +++ b/widgets/ChangeLog @@ -1,3 +1,16 @@ +1999-11-28 Miguel de Icaza + + * e-cell-text.c (ect_enter_edit, ect_leave_edit): New methods; + They implement editing. + + * e-cell.h: new methods: enter_edit, leave_edit + + * e-table-model.h (set_value_at): make val argument const. + + * e-table-simple.c (simple_set_value_at): Make value argument const; + + * e-table-item.c (eti_set_arg): Add new mode: draw_focus; + 1999-11-27 Miguel de Icaza * e-table-item.c (eti_event): beginning of the keyboard navigation. diff --git a/widgets/e-cell-text.c b/widgets/e-cell-text.c index a997d745d3..f0501ab4cb 100644 --- a/widgets/e-cell-text.c +++ b/widgets/e-cell-text.c @@ -8,61 +8,143 @@ */ #include #include +#include +#include +#include +#include +#include #include "e-cell-text.h" #include "e-util.h" +#include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() #define TEXT_PAD 2 +typedef struct { + char *old_text; + GtkWidget *entry_top; + GtkEntry *entry; + + /* + * Where the editing is taking place + */ + int col, row; +} CellEdit; + typedef struct { ECellView cell_view; GdkGC *gc; GdkFont *font; GnomeCanvas *canvas; + ETableItem *eti; + + /* + * During edition. + */ + CellEdit *edit; } ECellTextView; static ECellClass *parent_class; +static void +ect_queue_redraw (ECellTextView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * Accept the currently edited text + */ +static void +ect_accept_edits (ECellTextView *text_view) +{ + const char *text = gtk_entry_get_text (text_view->edit->entry); + CellEdit *edit = text_view->edit; + + e_table_model_set_value_at (text_view->eti->table_model, edit->col, edit->row, text); +} + +/* + * Shuts down the editing process + */ +static void +ect_stop_editing (ECellTextView *text_view) +{ + CellEdit *edit = text_view->edit; + + g_free (edit->old_text); + edit->old_text = NULL; + gtk_widget_destroy (edit->entry_top); + edit->entry_top = NULL; + edit->entry = NULL; + + g_free (edit); + + text_view->edit = NULL; +} + +/* + * Cancels the edits + */ +static void +ect_cancel_edit (ECellTextView *text_view) +{ + ect_queue_redraw (text_view, text_view->edit->col, text_view->edit->row); + ect_stop_editing (text_view); +} + +/* + * ECell::realize method + */ static ECellView * -ect_realize (ECell *ecell, GnomeCanvas *canvas) +ect_realize (ECell *ecell, void *view) { ECellText *ect = E_CELL_TEXT (ecell); - ECellTextView *ectv = g_new0 (ECellTextView, 1); - - ectv->cell_view.ecell = ecell; - ectv->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + ECellTextView *text_view = g_new0 (ECellTextView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + text_view->cell_view.ecell = ecell; + text_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); if (ect->font_name){ GdkFont *f; f = gdk_fontset_load (ect->font_name); - ectv->font = f; + text_view->font = f; } - if (!ectv->font){ - ectv->font = GTK_WIDGET (canvas)->style->font; + if (!text_view->font){ + text_view->font = GTK_WIDGET (canvas)->style->font; - gdk_font_ref (ectv->font); + gdk_font_ref (text_view->font); } - - ectv->canvas = canvas; - return (ECellView *)ectv; + text_view->eti = eti; + text_view->canvas = canvas; + + return (ECellView *)text_view; } +/* + * ECell::unrealize method + */ static void ect_unrealize (ECellView *ecv) { - ECellTextView *ectv = (ECellTextView *) ecv; + ECellTextView *text_view = (ECellTextView *) ecv; - gdk_gc_unref (ectv->gc); - ectv->gc = NULL; + gdk_gc_unref (text_view->gc); + text_view->gc = NULL; - gdk_font_unref (ectv->font); - ectv->font = NULL; + gdk_font_unref (text_view->font); + text_view->font = NULL; - g_free (ectv); + g_free (text_view); } +/* + * ECell::draw method + */ static void ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, gboolean selected, @@ -70,41 +152,117 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; + GtkWidget *w = GTK_WIDGET (text_view->canvas); GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int xoff, w; + GdkFont *font = text_view->font; + const int height = font->ascent + font->descent; + int xoff; + gboolean edit_display = FALSE; + + /* + * Figure if this cell is being edited + */ + if (text_view->edit){ + CellEdit *edit = text_view->edit; + + printf ("We are editing a cell [%d %d %d %d]\n", col, row, edit->col, edit->row); + if ((edit->col == col) && (edit->row == row)) + edit_display = TRUE; + } + + /* + * Be a nice citizen: clip to the region we are supposed to draw on + */ rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; - gdk_gc_set_clip_rectangle (text_view->gc, &rect); - switch (ect->justify){ - case GTK_JUSTIFY_LEFT: - xoff = 1; - break; - - case GTK_JUSTIFY_RIGHT: - w = 1 + gdk_text_width (text_view->font, str, strlen (str)); - xoff = (x2 - x1) - w; - break; + if (edit_display){ + CellEdit *edit = text_view->edit; + const char *text = gtk_entry_get_text (edit->entry); + GdkWChar *text_wc = g_new (GdkWChar, strlen (text) + 1); + int text_wc_len = gdk_mbstowcs (text_wc, text, strlen (text)); + const int cursor_pos = GTK_EDITABLE (edit->entry)->current_pos; + const int left_len = gdk_text_width_wc (text_view->font, text_wc, cursor_pos); + + text_wc [text_wc_len] = 0; - case GTK_JUSTIFY_CENTER: - xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; - break; - default: + /* + * Find a good spot for painting + */ xoff = 0; - g_warning ("Can not handle GTK_JUSTIFY_FILL"); - break; - } + + /* + * Paint + */ + gdk_gc_set_foreground (text_view->gc, &w->style->base [GTK_STATE_NORMAL]); + gdk_draw_rectangle (drawable, text_view->gc, TRUE, + rect.x, rect.y, rect.width, rect.height); + gdk_gc_set_foreground (text_view->gc, &w->style->text [GTK_STATE_NORMAL]); + + { + GdkGC *gc = text_view->gc; + const int y = y2 - font->descent - ((y2-y1-height)/2); + int px, i; + + px = x1; + + printf ("Cursor at: %d\n", cursor_pos); + + for (i = 0; *text_wc; text_wc++, i++){ + gdk_draw_text_wc ( + drawable, font, gc, px, y, text_wc, 1); + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } - /* Draw now */ - { - GtkWidget *w = GTK_WIDGET (text_view->canvas); + px += gdk_text_width_wc (font, text_wc, 1); + } + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } + } + } else { + /* + * Regular cell + */ GdkColor *background, *foreground; - const int height = text_view->font->ascent + text_view->font->descent; + int width; + + /* + * Compute draw mode + */ + switch (ect->justify){ + case GTK_JUSTIFY_LEFT: + xoff = 1; + break; + + case GTK_JUSTIFY_RIGHT: + width = 1 + gdk_text_width (font, str, strlen (str)); + xoff = (x2 - x1) - width; + break; + + case GTK_JUSTIFY_CENTER: + xoff = ((x2 - x1) - gdk_text_width (font, str, strlen (str))) / 2; + break; + default: + xoff = 0; + g_warning ("Can not handle GTK_JUSTIFY_FILL"); + break; + } + if (selected){ background = &w->style->bg [GTK_STATE_SELECTED]; @@ -118,33 +276,58 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, gdk_draw_rectangle (drawable, text_view->gc, TRUE, rect.x, rect.y, rect.width, rect.height); gdk_gc_set_foreground (text_view->gc, foreground); - gdk_draw_string (drawable, text_view->font, text_view->gc, - x1 + xoff, y2 - text_view->font->descent - ((y2-y1-height)/2), str); - } -} -static void -e_cell_text_start_editing (ECellText *ect, int col, int row) -{ - printf ("Starting to edit %d %d\n", col, row); + gdk_draw_string ( + drawable, font, text_view->gc, + x1 + xoff, + y2 - font->descent - ((y2-y1-height)/2), str); + } } +/* + * ECell::event method + */ static gint ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - ECell *ecell = ecell_view->ecell; - ECellText *ect = E_CELL_TEXT (ecell); + ECellTextView *text_view = (ECellTextView *) ecell_view; switch (event->type){ case GDK_BUTTON_PRESS: + if (text_view->edit){ + printf ("FIXME: Should handle click here\n"); + } else + e_table_item_enter_edit (text_view->eti, col, row); + break; + + case GDK_BUTTON_RELEASE: return TRUE; - default: + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + ect_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit) + e_table_item_enter_edit (text_view->eti, col, row); + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + ect_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: break; + + default: + return FALSE; } - return FALSE; + return TRUE; } +/* + * ECell::height method + */ static int ect_height (ECellView *ecell_view, int col, int row) { @@ -153,6 +336,66 @@ ect_height (ECellView *ecell_view, int col, int row) return (text_view->font->ascent + text_view->font->descent) + TEXT_PAD; } +/* + * Callback: invoked when the user pressed "enter" on the GtkEntry + */ +static void +ect_entry_activate (GtkEntry *entry, ECellTextView *text_view) +{ + e_table_item_leave_edit (text_view->eti); +} + +/* + * ECellView::enter_edit method + */ +static void * +ect_enter_edit (ECellView *ecell_view, int col, int row) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + CellEdit *edit; + + printf ("Entering edit mode! [%d %d]\n", col, row); + + edit = g_new (CellEdit, 1); + text_view->edit = edit; + + edit->entry = (GtkEntry *) gtk_entry_new (); + gtk_entry_set_text (edit->entry, str); + edit->old_text = g_strdup (str); + gtk_signal_connect (GTK_OBJECT (edit->entry), "activate", + GTK_SIGNAL_FUNC (ect_entry_activate), text_view); + + /* + * The hack: create this window off-screen + */ + edit->entry_top = gtk_window_new (GTK_WINDOW_POPUP); + gtk_container_add (GTK_CONTAINER (edit->entry_top), GTK_WIDGET (edit->entry)); + gtk_widget_set_uposition (edit->entry_top, 20000, 20000); + gtk_widget_show_all (edit->entry_top); + + ect_queue_redraw (text_view, col, row); + + return NULL; +} + +/* + * ECellView::leave_edit method + */ +static void +ect_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + + printf ("Leaving edit mode!\n"); + + ect_accept_edits (text_view); + ect_stop_editing (text_view); +} + +/* + * GtkObject::destroy method + */ static void ect_destroy (GtkObject *object) { @@ -170,12 +413,14 @@ e_cell_text_class_init (GtkObjectClass *object_class) object_class->destroy = ect_destroy; - ecc->realize = ect_realize; - ecc->unrealize = ect_unrealize; - ecc->draw = ect_draw; - ecc->event = ect_event; - ecc->height = ect_height; - + ecc->realize = ect_realize; + ecc->unrealize = ect_unrealize; + ecc->draw = ect_draw; + ecc->event = ect_event; + ecc->height = ect_height; + ecc->enter_edit = ect_enter_edit; + ecc->leave_edit = ect_leave_edit; + parent_class = gtk_type_class (PARENT_TYPE); } diff --git a/widgets/e-cell.c b/widgets/e-cell.c index 9caa31f2ca..2bc49f7a45 100644 --- a/widgets/e-cell.c +++ b/widgets/e-cell.c @@ -13,7 +13,7 @@ #define PARENT_TYPE gtk_object_get_type() static ECellView * -ec_realize (ECell *e_cell, GnomeCanvas *canvas) +ec_realize (ECell *e_cell, void *view) { return NULL; } @@ -28,20 +28,20 @@ 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"); + g_error ("e-cell-draw invoked\n"); } static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } static gint ec_height (ECellView *ecell_view, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } @@ -98,10 +98,10 @@ e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row) } ECellView * -e_cell_realize (ECell *ecell, GnomeCanvas *canvas) +e_cell_realize (ECell *ecell, void *view) { return E_CELL_CLASS (GTK_OBJECT (ecell)->klass)->realize ( - ecell, canvas); + ecell, view); } void @@ -125,3 +125,16 @@ e_cell_height (ECellView *ecell_view, int col, int row) ecell_view, col, row); } +void * +e_cell_enter_edit (ECellView *ecell_view, int col, int row) +{ + return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->enter_edit ( + ecell_view, col, row); +} + +void +e_cell_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->leave_edit ( + ecell_view, col, row, edit_context); +} diff --git a/widgets/e-cell.h b/widgets/e-cell.h index 9cd62f3909..b0f62d020c 100644 --- a/widgets/e-cell.h +++ b/widgets/e-cell.h @@ -1,7 +1,7 @@ #ifndef _E_CELL_H_ #define _E_CELL_H_ -#include +#include #include "e-table-model.h" #define E_CELL_TYPE (e_cell_get_type ()) @@ -29,19 +29,22 @@ struct _ECellView { typedef struct { GtkObjectClass parent_class; - ECellView *(*realize) (ECell *, GnomeCanvas *canvas); - void (*unrealize) (ECellView *); + ECellView *(*realize) (ECell *ecell, void *view); + void (*unrealize) (ECellView *e_cell_view); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, 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); - int (*height) (ECellView *ecell, int col, int row); + void (*focus) (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); + void (*unfocus) (ECellView *ecell_view); + int (*height) (ECellView *ecell_view, int col, int row); + + void *(*enter_edit)(ECellView *ecell_view, int col, int row); + void (*leave_edit)(ECellView *ecell_view, int col, int row, void *context); } ECellClass; 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); +ECellView *e_cell_realize (ECell *ecell, void *view); void e_cell_unrealize (ECellView *ecell_view); void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, int col, int row, gboolean selected, @@ -50,4 +53,7 @@ void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, in void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); +void *e_cell_enter_edit(ECellView *ecell_view, int col, int row); +void e_cell_leave_edit(ECellView *ecell_view, int col, int row, void *edit_context); + #endif /* _E_CELL_H_ */ diff --git a/widgets/e-table-item.c b/widgets/e-table-item.c index a561fbfd15..1b98bbfce4 100644 --- a/widgets/e-table-item.c +++ b/widgets/e-table-item.c @@ -37,6 +37,7 @@ enum { ARG_TABLE_X, ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, + ARG_TABLE_DRAW_FOCUS, ARG_LENGHT_THRESHOLD }; @@ -51,7 +52,6 @@ enum { static void eti_realize_cell_views (ETableItem *eti) { - GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti); int i; /* @@ -63,7 +63,7 @@ eti_realize_cell_views (ETableItem *eti) for (i = 0; i < eti->n_cells; i++){ ETableCol *col = e_table_header_get_column (eti->header, i); - eti->cell_views [i] = e_cell_realize (col->ecell, item->canvas); + eti->cell_views [i] = e_cell_realize (col->ecell, eti); } } @@ -117,12 +117,9 @@ eti_remove_table_model (ETableItem *eti) 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; - eti->table_model_selection_id = 0; eti->table_model = NULL; } @@ -284,7 +281,9 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) * border as well. */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) +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; @@ -301,10 +300,25 @@ eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int en eti->y1 + y1 + height + 1 + border); } -static void -eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) +void +e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row) { - eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + int border; + + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if ((start_col == eti->focused_col) || + (end_col == eti->focused_col) || + (start_row == eti->focused_row) || + (end_row == eti->focused_row)) + border = 2; + else + border = 0; + + eti_request_region_redraw (eti, start_col, start_row, end_col, end_row, border); } static void @@ -313,14 +327,11 @@ eti_add_table_model (ETableItem *eti, ETableModel *table_model) g_assert (eti->table_model == NULL); eti->table_model = table_model; - gtk_object_ref (GTK_OBJECT (table_model)); + gtk_object_ref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = gtk_signal_connect ( GTK_OBJECT (table_model), "model_changed", GTK_SIGNAL_FUNC (eti_table_model_changed), eti); - eti->table_model_selection_id = gtk_signal_connect ( - GTK_OBJECT (table_model), "row_selection", - GTK_SIGNAL_FUNC (eti_table_model_row_selection), eti); eti_table_model_changed (table_model, eti); } @@ -418,6 +429,11 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_GRID: eti->draw_grid = GTK_VALUE_BOOL (*arg); + break; + + case ARG_TABLE_DRAW_FOCUS: + eti->draw_focus = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -529,7 +545,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int f_x1, f_x2, f_y1, f_y2; gboolean f_found; - printf ("Rect: %d %d %d %d\n", x, y, width, height); +/* printf ("Rect: %d %d %d %d\n", x, y, width, height); */ /* * Clear the background */ @@ -604,7 +620,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, height = eti_row_height (eti, row); xd = x_offset; - printf ("paint: %d %d\n", yd, yd + height); +/* printf ("paint: %d %d\n", yd, yd + height); */ selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; @@ -631,9 +647,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * 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); + if (f_found && eti->draw_focus){ gdk_draw_rectangle ( drawable, eti->focus_gc, FALSE, f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); @@ -725,6 +739,8 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } case GDK_KEY_PRESS: + printf ("KEYPRESS!\n"); + if (eti->focused_col == -1) return FALSE; @@ -781,6 +797,7 @@ eti_row_selection (ETableItem *eti, int row, gboolean 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 @@ -813,6 +830,8 @@ 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); + gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -862,6 +881,11 @@ e_table_item_focus (ETableItem *eti, int col, int row) eti->focused_row = row; eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + + /* + * make sure we have the Gtk Focus + */ + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas)); } void @@ -944,7 +968,7 @@ 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)); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); switch (eti->selection_mode){ case GTK_SELECTION_SINGLE: @@ -973,3 +997,28 @@ e_table_item_select_row (ETableItem *eti, int row) } } + +void +e_table_item_enter_edit (ETableItem *eti, int col, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + eti->editing_col = col; + eti->editing_row = row; + + eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], col, row); +} + +void +e_table_item_leave_edit (ETableItem *eti) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + e_cell_leave_edit (eti->cell_views [eti->editing_col], eti->editing_col, eti->editing_row, eti->edit_ctx); + eti->editing_col = -1; + eti->editing_row = -1; + eti->edit_ctx = NULL; +} + diff --git a/widgets/e-table-item.h b/widgets/e-table-item.h index 17d422ddf5..02f7beb1ac 100644 --- a/widgets/e-table-item.h +++ b/widgets/e-table-item.h @@ -28,14 +28,14 @@ typedef struct { int header_dim_change_id; int header_structure_change_id; int table_model_change_id; - int table_model_selection_id; GdkGC *fill_gc; GdkGC *grid_gc; GdkGC *focus_gc; unsigned int draw_grid:1; - + unsigned int draw_focus:1; + int focused_col, focused_row; /* @@ -52,6 +52,12 @@ typedef struct { GSList *selection; GtkSelectionMode selection_mode; + + /* + * During edition + */ + int editing_col, editing_row; + void *edit_ctx; } ETableItem; typedef struct { @@ -85,4 +91,11 @@ void e_table_item_set_selection_mode (ETableItem *e_table_Item, gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, int row); +void e_table_item_leave_edit (ETableItem *eti); +void e_table_item_enter_edit (ETableItem *eti, int col, int row); + +void e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row); + #endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/e-table-model.c b/widgets/e-table-model.c index 288c20f20e..103bb31b57 100644 --- a/widgets/e-table-model.c +++ b/widgets/e-table-model.c @@ -61,7 +61,7 @@ e_table_model_value_at (ETableModel *e_table_model, int col, int row) } void -e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data) { g_return_if_fail (e_table_model != NULL); g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); diff --git a/widgets/e-table-model.h b/widgets/e-table-model.h index ea5d31493d..22339ae484 100644 --- a/widgets/e-table-model.h +++ b/widgets/e-table-model.h @@ -23,7 +23,7 @@ typedef struct { const char *(*column_name) (ETableModel *etm, int col); int (*row_count) (ETableModel *etm); void *(*value_at) (ETableModel *etm, int col, int row); - void (*set_value_at) (ETableModel *etm, int col, int row, void *value); + void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); /* @@ -40,7 +40,7 @@ int e_table_model_column_count (ETableModel *e_table_model); const char *e_table_model_column_name (ETableModel *e_table_model, int col); int e_table_model_row_count (ETableModel *e_table_model); void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); +void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); /* diff --git a/widgets/e-table-simple.c b/widgets/e-table-simple.c index 16691e5442..2076e06cef 100644 --- a/widgets/e-table-simple.c +++ b/widgets/e-table-simple.c @@ -47,7 +47,7 @@ simple_value_at (ETableModel *etm, int col, int row) } static void -simple_set_value_at (ETableModel *etm, int col, int row, void *val) +simple_set_value_at (ETableModel *etm, int col, int row, const void *val) { ETableSimple *simple = (ETableSimple *)etm; diff --git a/widgets/e-table-simple.h b/widgets/e-table-simple.h index 544e681a6c..1f7a17aeff 100644 --- a/widgets/e-table-simple.h +++ b/widgets/e-table-simple.h @@ -7,7 +7,7 @@ typedef int (*ETableSimpleColumnCountFn) (ETableModel *etm, void *dat typedef const char *(*ETableSimpleColumnNameFn) (ETableModel *etm, int col, void *data); typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *data); typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); -typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, void *val, void *data); +typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); typedef struct { diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index 20d4c1e3d7..afc69d71a4 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,3 +1,16 @@ +1999-11-28 Miguel de Icaza + + * e-cell-text.c (ect_enter_edit, ect_leave_edit): New methods; + They implement editing. + + * e-cell.h: new methods: enter_edit, leave_edit + + * e-table-model.h (set_value_at): make val argument const. + + * e-table-simple.c (simple_set_value_at): Make value argument const; + + * e-table-item.c (eti_set_arg): Add new mode: draw_focus; + 1999-11-27 Miguel de Icaza * e-table-item.c (eti_event): beginning of the keyboard navigation. diff --git a/widgets/e-table/e-cell-text.c b/widgets/e-table/e-cell-text.c index a997d745d3..f0501ab4cb 100644 --- a/widgets/e-table/e-cell-text.c +++ b/widgets/e-table/e-cell-text.c @@ -8,61 +8,143 @@ */ #include #include +#include +#include +#include +#include +#include #include "e-cell-text.h" #include "e-util.h" +#include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() #define TEXT_PAD 2 +typedef struct { + char *old_text; + GtkWidget *entry_top; + GtkEntry *entry; + + /* + * Where the editing is taking place + */ + int col, row; +} CellEdit; + typedef struct { ECellView cell_view; GdkGC *gc; GdkFont *font; GnomeCanvas *canvas; + ETableItem *eti; + + /* + * During edition. + */ + CellEdit *edit; } ECellTextView; static ECellClass *parent_class; +static void +ect_queue_redraw (ECellTextView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * Accept the currently edited text + */ +static void +ect_accept_edits (ECellTextView *text_view) +{ + const char *text = gtk_entry_get_text (text_view->edit->entry); + CellEdit *edit = text_view->edit; + + e_table_model_set_value_at (text_view->eti->table_model, edit->col, edit->row, text); +} + +/* + * Shuts down the editing process + */ +static void +ect_stop_editing (ECellTextView *text_view) +{ + CellEdit *edit = text_view->edit; + + g_free (edit->old_text); + edit->old_text = NULL; + gtk_widget_destroy (edit->entry_top); + edit->entry_top = NULL; + edit->entry = NULL; + + g_free (edit); + + text_view->edit = NULL; +} + +/* + * Cancels the edits + */ +static void +ect_cancel_edit (ECellTextView *text_view) +{ + ect_queue_redraw (text_view, text_view->edit->col, text_view->edit->row); + ect_stop_editing (text_view); +} + +/* + * ECell::realize method + */ static ECellView * -ect_realize (ECell *ecell, GnomeCanvas *canvas) +ect_realize (ECell *ecell, void *view) { ECellText *ect = E_CELL_TEXT (ecell); - ECellTextView *ectv = g_new0 (ECellTextView, 1); - - ectv->cell_view.ecell = ecell; - ectv->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + ECellTextView *text_view = g_new0 (ECellTextView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + text_view->cell_view.ecell = ecell; + text_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); if (ect->font_name){ GdkFont *f; f = gdk_fontset_load (ect->font_name); - ectv->font = f; + text_view->font = f; } - if (!ectv->font){ - ectv->font = GTK_WIDGET (canvas)->style->font; + if (!text_view->font){ + text_view->font = GTK_WIDGET (canvas)->style->font; - gdk_font_ref (ectv->font); + gdk_font_ref (text_view->font); } - - ectv->canvas = canvas; - return (ECellView *)ectv; + text_view->eti = eti; + text_view->canvas = canvas; + + return (ECellView *)text_view; } +/* + * ECell::unrealize method + */ static void ect_unrealize (ECellView *ecv) { - ECellTextView *ectv = (ECellTextView *) ecv; + ECellTextView *text_view = (ECellTextView *) ecv; - gdk_gc_unref (ectv->gc); - ectv->gc = NULL; + gdk_gc_unref (text_view->gc); + text_view->gc = NULL; - gdk_font_unref (ectv->font); - ectv->font = NULL; + gdk_font_unref (text_view->font); + text_view->font = NULL; - g_free (ectv); + g_free (text_view); } +/* + * ECell::draw method + */ static void ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, gboolean selected, @@ -70,41 +152,117 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; + GtkWidget *w = GTK_WIDGET (text_view->canvas); GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int xoff, w; + GdkFont *font = text_view->font; + const int height = font->ascent + font->descent; + int xoff; + gboolean edit_display = FALSE; + + /* + * Figure if this cell is being edited + */ + if (text_view->edit){ + CellEdit *edit = text_view->edit; + + printf ("We are editing a cell [%d %d %d %d]\n", col, row, edit->col, edit->row); + if ((edit->col == col) && (edit->row == row)) + edit_display = TRUE; + } + + /* + * Be a nice citizen: clip to the region we are supposed to draw on + */ rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; - gdk_gc_set_clip_rectangle (text_view->gc, &rect); - switch (ect->justify){ - case GTK_JUSTIFY_LEFT: - xoff = 1; - break; - - case GTK_JUSTIFY_RIGHT: - w = 1 + gdk_text_width (text_view->font, str, strlen (str)); - xoff = (x2 - x1) - w; - break; + if (edit_display){ + CellEdit *edit = text_view->edit; + const char *text = gtk_entry_get_text (edit->entry); + GdkWChar *text_wc = g_new (GdkWChar, strlen (text) + 1); + int text_wc_len = gdk_mbstowcs (text_wc, text, strlen (text)); + const int cursor_pos = GTK_EDITABLE (edit->entry)->current_pos; + const int left_len = gdk_text_width_wc (text_view->font, text_wc, cursor_pos); + + text_wc [text_wc_len] = 0; - case GTK_JUSTIFY_CENTER: - xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; - break; - default: + /* + * Find a good spot for painting + */ xoff = 0; - g_warning ("Can not handle GTK_JUSTIFY_FILL"); - break; - } + + /* + * Paint + */ + gdk_gc_set_foreground (text_view->gc, &w->style->base [GTK_STATE_NORMAL]); + gdk_draw_rectangle (drawable, text_view->gc, TRUE, + rect.x, rect.y, rect.width, rect.height); + gdk_gc_set_foreground (text_view->gc, &w->style->text [GTK_STATE_NORMAL]); + + { + GdkGC *gc = text_view->gc; + const int y = y2 - font->descent - ((y2-y1-height)/2); + int px, i; + + px = x1; + + printf ("Cursor at: %d\n", cursor_pos); + + for (i = 0; *text_wc; text_wc++, i++){ + gdk_draw_text_wc ( + drawable, font, gc, px, y, text_wc, 1); + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } - /* Draw now */ - { - GtkWidget *w = GTK_WIDGET (text_view->canvas); + px += gdk_text_width_wc (font, text_wc, 1); + } + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } + } + } else { + /* + * Regular cell + */ GdkColor *background, *foreground; - const int height = text_view->font->ascent + text_view->font->descent; + int width; + + /* + * Compute draw mode + */ + switch (ect->justify){ + case GTK_JUSTIFY_LEFT: + xoff = 1; + break; + + case GTK_JUSTIFY_RIGHT: + width = 1 + gdk_text_width (font, str, strlen (str)); + xoff = (x2 - x1) - width; + break; + + case GTK_JUSTIFY_CENTER: + xoff = ((x2 - x1) - gdk_text_width (font, str, strlen (str))) / 2; + break; + default: + xoff = 0; + g_warning ("Can not handle GTK_JUSTIFY_FILL"); + break; + } + if (selected){ background = &w->style->bg [GTK_STATE_SELECTED]; @@ -118,33 +276,58 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, gdk_draw_rectangle (drawable, text_view->gc, TRUE, rect.x, rect.y, rect.width, rect.height); gdk_gc_set_foreground (text_view->gc, foreground); - gdk_draw_string (drawable, text_view->font, text_view->gc, - x1 + xoff, y2 - text_view->font->descent - ((y2-y1-height)/2), str); - } -} -static void -e_cell_text_start_editing (ECellText *ect, int col, int row) -{ - printf ("Starting to edit %d %d\n", col, row); + gdk_draw_string ( + drawable, font, text_view->gc, + x1 + xoff, + y2 - font->descent - ((y2-y1-height)/2), str); + } } +/* + * ECell::event method + */ static gint ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - ECell *ecell = ecell_view->ecell; - ECellText *ect = E_CELL_TEXT (ecell); + ECellTextView *text_view = (ECellTextView *) ecell_view; switch (event->type){ case GDK_BUTTON_PRESS: + if (text_view->edit){ + printf ("FIXME: Should handle click here\n"); + } else + e_table_item_enter_edit (text_view->eti, col, row); + break; + + case GDK_BUTTON_RELEASE: return TRUE; - default: + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + ect_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit) + e_table_item_enter_edit (text_view->eti, col, row); + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + ect_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: break; + + default: + return FALSE; } - return FALSE; + return TRUE; } +/* + * ECell::height method + */ static int ect_height (ECellView *ecell_view, int col, int row) { @@ -153,6 +336,66 @@ ect_height (ECellView *ecell_view, int col, int row) return (text_view->font->ascent + text_view->font->descent) + TEXT_PAD; } +/* + * Callback: invoked when the user pressed "enter" on the GtkEntry + */ +static void +ect_entry_activate (GtkEntry *entry, ECellTextView *text_view) +{ + e_table_item_leave_edit (text_view->eti); +} + +/* + * ECellView::enter_edit method + */ +static void * +ect_enter_edit (ECellView *ecell_view, int col, int row) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + CellEdit *edit; + + printf ("Entering edit mode! [%d %d]\n", col, row); + + edit = g_new (CellEdit, 1); + text_view->edit = edit; + + edit->entry = (GtkEntry *) gtk_entry_new (); + gtk_entry_set_text (edit->entry, str); + edit->old_text = g_strdup (str); + gtk_signal_connect (GTK_OBJECT (edit->entry), "activate", + GTK_SIGNAL_FUNC (ect_entry_activate), text_view); + + /* + * The hack: create this window off-screen + */ + edit->entry_top = gtk_window_new (GTK_WINDOW_POPUP); + gtk_container_add (GTK_CONTAINER (edit->entry_top), GTK_WIDGET (edit->entry)); + gtk_widget_set_uposition (edit->entry_top, 20000, 20000); + gtk_widget_show_all (edit->entry_top); + + ect_queue_redraw (text_view, col, row); + + return NULL; +} + +/* + * ECellView::leave_edit method + */ +static void +ect_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + + printf ("Leaving edit mode!\n"); + + ect_accept_edits (text_view); + ect_stop_editing (text_view); +} + +/* + * GtkObject::destroy method + */ static void ect_destroy (GtkObject *object) { @@ -170,12 +413,14 @@ e_cell_text_class_init (GtkObjectClass *object_class) object_class->destroy = ect_destroy; - ecc->realize = ect_realize; - ecc->unrealize = ect_unrealize; - ecc->draw = ect_draw; - ecc->event = ect_event; - ecc->height = ect_height; - + ecc->realize = ect_realize; + ecc->unrealize = ect_unrealize; + ecc->draw = ect_draw; + ecc->event = ect_event; + ecc->height = ect_height; + ecc->enter_edit = ect_enter_edit; + ecc->leave_edit = ect_leave_edit; + parent_class = gtk_type_class (PARENT_TYPE); } diff --git a/widgets/e-table/e-cell.c b/widgets/e-table/e-cell.c index 9caa31f2ca..2bc49f7a45 100644 --- a/widgets/e-table/e-cell.c +++ b/widgets/e-table/e-cell.c @@ -13,7 +13,7 @@ #define PARENT_TYPE gtk_object_get_type() static ECellView * -ec_realize (ECell *e_cell, GnomeCanvas *canvas) +ec_realize (ECell *e_cell, void *view) { return NULL; } @@ -28,20 +28,20 @@ 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"); + g_error ("e-cell-draw invoked\n"); } static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } static gint ec_height (ECellView *ecell_view, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } @@ -98,10 +98,10 @@ e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row) } ECellView * -e_cell_realize (ECell *ecell, GnomeCanvas *canvas) +e_cell_realize (ECell *ecell, void *view) { return E_CELL_CLASS (GTK_OBJECT (ecell)->klass)->realize ( - ecell, canvas); + ecell, view); } void @@ -125,3 +125,16 @@ e_cell_height (ECellView *ecell_view, int col, int row) ecell_view, col, row); } +void * +e_cell_enter_edit (ECellView *ecell_view, int col, int row) +{ + return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->enter_edit ( + ecell_view, col, row); +} + +void +e_cell_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->leave_edit ( + ecell_view, col, row, edit_context); +} diff --git a/widgets/e-table/e-cell.h b/widgets/e-table/e-cell.h index 9cd62f3909..b0f62d020c 100644 --- a/widgets/e-table/e-cell.h +++ b/widgets/e-table/e-cell.h @@ -1,7 +1,7 @@ #ifndef _E_CELL_H_ #define _E_CELL_H_ -#include +#include #include "e-table-model.h" #define E_CELL_TYPE (e_cell_get_type ()) @@ -29,19 +29,22 @@ struct _ECellView { typedef struct { GtkObjectClass parent_class; - ECellView *(*realize) (ECell *, GnomeCanvas *canvas); - void (*unrealize) (ECellView *); + ECellView *(*realize) (ECell *ecell, void *view); + void (*unrealize) (ECellView *e_cell_view); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, 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); - int (*height) (ECellView *ecell, int col, int row); + void (*focus) (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); + void (*unfocus) (ECellView *ecell_view); + int (*height) (ECellView *ecell_view, int col, int row); + + void *(*enter_edit)(ECellView *ecell_view, int col, int row); + void (*leave_edit)(ECellView *ecell_view, int col, int row, void *context); } ECellClass; 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); +ECellView *e_cell_realize (ECell *ecell, void *view); void e_cell_unrealize (ECellView *ecell_view); void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, int col, int row, gboolean selected, @@ -50,4 +53,7 @@ void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, in void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); +void *e_cell_enter_edit(ECellView *ecell_view, int col, int row); +void e_cell_leave_edit(ECellView *ecell_view, int col, int row, void *edit_context); + #endif /* _E_CELL_H_ */ diff --git a/widgets/e-table/e-table-item.c b/widgets/e-table/e-table-item.c index a561fbfd15..1b98bbfce4 100644 --- a/widgets/e-table/e-table-item.c +++ b/widgets/e-table/e-table-item.c @@ -37,6 +37,7 @@ enum { ARG_TABLE_X, ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, + ARG_TABLE_DRAW_FOCUS, ARG_LENGHT_THRESHOLD }; @@ -51,7 +52,6 @@ enum { static void eti_realize_cell_views (ETableItem *eti) { - GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti); int i; /* @@ -63,7 +63,7 @@ eti_realize_cell_views (ETableItem *eti) for (i = 0; i < eti->n_cells; i++){ ETableCol *col = e_table_header_get_column (eti->header, i); - eti->cell_views [i] = e_cell_realize (col->ecell, item->canvas); + eti->cell_views [i] = e_cell_realize (col->ecell, eti); } } @@ -117,12 +117,9 @@ eti_remove_table_model (ETableItem *eti) 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; - eti->table_model_selection_id = 0; eti->table_model = NULL; } @@ -284,7 +281,9 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) * border as well. */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) +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; @@ -301,10 +300,25 @@ eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int en eti->y1 + y1 + height + 1 + border); } -static void -eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) +void +e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row) { - eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + int border; + + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if ((start_col == eti->focused_col) || + (end_col == eti->focused_col) || + (start_row == eti->focused_row) || + (end_row == eti->focused_row)) + border = 2; + else + border = 0; + + eti_request_region_redraw (eti, start_col, start_row, end_col, end_row, border); } static void @@ -313,14 +327,11 @@ eti_add_table_model (ETableItem *eti, ETableModel *table_model) g_assert (eti->table_model == NULL); eti->table_model = table_model; - gtk_object_ref (GTK_OBJECT (table_model)); + gtk_object_ref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = gtk_signal_connect ( GTK_OBJECT (table_model), "model_changed", GTK_SIGNAL_FUNC (eti_table_model_changed), eti); - eti->table_model_selection_id = gtk_signal_connect ( - GTK_OBJECT (table_model), "row_selection", - GTK_SIGNAL_FUNC (eti_table_model_row_selection), eti); eti_table_model_changed (table_model, eti); } @@ -418,6 +429,11 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_GRID: eti->draw_grid = GTK_VALUE_BOOL (*arg); + break; + + case ARG_TABLE_DRAW_FOCUS: + eti->draw_focus = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -529,7 +545,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int f_x1, f_x2, f_y1, f_y2; gboolean f_found; - printf ("Rect: %d %d %d %d\n", x, y, width, height); +/* printf ("Rect: %d %d %d %d\n", x, y, width, height); */ /* * Clear the background */ @@ -604,7 +620,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, height = eti_row_height (eti, row); xd = x_offset; - printf ("paint: %d %d\n", yd, yd + height); +/* printf ("paint: %d %d\n", yd, yd + height); */ selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; @@ -631,9 +647,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * 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); + if (f_found && eti->draw_focus){ gdk_draw_rectangle ( drawable, eti->focus_gc, FALSE, f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); @@ -725,6 +739,8 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } case GDK_KEY_PRESS: + printf ("KEYPRESS!\n"); + if (eti->focused_col == -1) return FALSE; @@ -781,6 +797,7 @@ eti_row_selection (ETableItem *eti, int row, gboolean 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 @@ -813,6 +830,8 @@ 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); + gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -862,6 +881,11 @@ e_table_item_focus (ETableItem *eti, int col, int row) eti->focused_row = row; eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + + /* + * make sure we have the Gtk Focus + */ + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas)); } void @@ -944,7 +968,7 @@ 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)); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); switch (eti->selection_mode){ case GTK_SELECTION_SINGLE: @@ -973,3 +997,28 @@ e_table_item_select_row (ETableItem *eti, int row) } } + +void +e_table_item_enter_edit (ETableItem *eti, int col, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + eti->editing_col = col; + eti->editing_row = row; + + eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], col, row); +} + +void +e_table_item_leave_edit (ETableItem *eti) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + e_cell_leave_edit (eti->cell_views [eti->editing_col], eti->editing_col, eti->editing_row, eti->edit_ctx); + eti->editing_col = -1; + eti->editing_row = -1; + eti->edit_ctx = NULL; +} + diff --git a/widgets/e-table/e-table-item.h b/widgets/e-table/e-table-item.h index 17d422ddf5..02f7beb1ac 100644 --- a/widgets/e-table/e-table-item.h +++ b/widgets/e-table/e-table-item.h @@ -28,14 +28,14 @@ typedef struct { int header_dim_change_id; int header_structure_change_id; int table_model_change_id; - int table_model_selection_id; GdkGC *fill_gc; GdkGC *grid_gc; GdkGC *focus_gc; unsigned int draw_grid:1; - + unsigned int draw_focus:1; + int focused_col, focused_row; /* @@ -52,6 +52,12 @@ typedef struct { GSList *selection; GtkSelectionMode selection_mode; + + /* + * During edition + */ + int editing_col, editing_row; + void *edit_ctx; } ETableItem; typedef struct { @@ -85,4 +91,11 @@ void e_table_item_set_selection_mode (ETableItem *e_table_Item, gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, int row); +void e_table_item_leave_edit (ETableItem *eti); +void e_table_item_enter_edit (ETableItem *eti, int col, int row); + +void e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_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 288c20f20e..103bb31b57 100644 --- a/widgets/e-table/e-table-model.c +++ b/widgets/e-table/e-table-model.c @@ -61,7 +61,7 @@ e_table_model_value_at (ETableModel *e_table_model, int col, int row) } void -e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data) { g_return_if_fail (e_table_model != NULL); g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); diff --git a/widgets/e-table/e-table-model.h b/widgets/e-table/e-table-model.h index ea5d31493d..22339ae484 100644 --- a/widgets/e-table/e-table-model.h +++ b/widgets/e-table/e-table-model.h @@ -23,7 +23,7 @@ typedef struct { const char *(*column_name) (ETableModel *etm, int col); int (*row_count) (ETableModel *etm); void *(*value_at) (ETableModel *etm, int col, int row); - void (*set_value_at) (ETableModel *etm, int col, int row, void *value); + void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); /* @@ -40,7 +40,7 @@ int e_table_model_column_count (ETableModel *e_table_model); const char *e_table_model_column_name (ETableModel *e_table_model, int col); int e_table_model_row_count (ETableModel *e_table_model); void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); +void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); /* diff --git a/widgets/e-table/e-table-simple.c b/widgets/e-table/e-table-simple.c index 16691e5442..2076e06cef 100644 --- a/widgets/e-table/e-table-simple.c +++ b/widgets/e-table/e-table-simple.c @@ -47,7 +47,7 @@ simple_value_at (ETableModel *etm, int col, int row) } static void -simple_set_value_at (ETableModel *etm, int col, int row, void *val) +simple_set_value_at (ETableModel *etm, int col, int row, const void *val) { ETableSimple *simple = (ETableSimple *)etm; diff --git a/widgets/e-table/e-table-simple.h b/widgets/e-table/e-table-simple.h index 544e681a6c..1f7a17aeff 100644 --- a/widgets/e-table/e-table-simple.h +++ b/widgets/e-table/e-table-simple.h @@ -7,7 +7,7 @@ typedef int (*ETableSimpleColumnCountFn) (ETableModel *etm, void *dat typedef const char *(*ETableSimpleColumnNameFn) (ETableModel *etm, int col, void *data); typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *data); typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); -typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, void *val, void *data); +typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); typedef struct { diff --git a/widgets/e-table/table-test.c b/widgets/e-table/table-test.c index 3517ecf692..f677e9e2d1 100644 --- a/widgets/e-table/table-test.c +++ b/widgets/e-table/table-test.c @@ -151,7 +151,7 @@ value_at (ETableModel *etc, int col, int row, void *data) } static void -set_value_at (ETableModel *etc, int col, int row, void *val, void *data) +set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) { g_assert (col < cols); g_assert (row < lines); @@ -236,6 +236,7 @@ main (int argc, char *argv []) "x", 10, "y", 30, "drawgrid", TRUE, + "drawfocus", TRUE, NULL); gtk_main (); diff --git a/widgets/table-test.c b/widgets/table-test.c index 3517ecf692..f677e9e2d1 100644 --- a/widgets/table-test.c +++ b/widgets/table-test.c @@ -151,7 +151,7 @@ value_at (ETableModel *etc, int col, int row, void *data) } static void -set_value_at (ETableModel *etc, int col, int row, void *val, void *data) +set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) { g_assert (col < cols); g_assert (row < lines); @@ -236,6 +236,7 @@ main (int argc, char *argv []) "x", 10, "y", 30, "drawgrid", TRUE, + "drawfocus", TRUE, NULL); gtk_main (); diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index a997d745d3..f0501ab4cb 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -8,61 +8,143 @@ */ #include #include +#include +#include +#include +#include +#include #include "e-cell-text.h" #include "e-util.h" +#include "e-table-item.h" #define PARENT_TYPE e_cell_get_type() #define TEXT_PAD 2 +typedef struct { + char *old_text; + GtkWidget *entry_top; + GtkEntry *entry; + + /* + * Where the editing is taking place + */ + int col, row; +} CellEdit; + typedef struct { ECellView cell_view; GdkGC *gc; GdkFont *font; GnomeCanvas *canvas; + ETableItem *eti; + + /* + * During edition. + */ + CellEdit *edit; } ECellTextView; static ECellClass *parent_class; +static void +ect_queue_redraw (ECellTextView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * Accept the currently edited text + */ +static void +ect_accept_edits (ECellTextView *text_view) +{ + const char *text = gtk_entry_get_text (text_view->edit->entry); + CellEdit *edit = text_view->edit; + + e_table_model_set_value_at (text_view->eti->table_model, edit->col, edit->row, text); +} + +/* + * Shuts down the editing process + */ +static void +ect_stop_editing (ECellTextView *text_view) +{ + CellEdit *edit = text_view->edit; + + g_free (edit->old_text); + edit->old_text = NULL; + gtk_widget_destroy (edit->entry_top); + edit->entry_top = NULL; + edit->entry = NULL; + + g_free (edit); + + text_view->edit = NULL; +} + +/* + * Cancels the edits + */ +static void +ect_cancel_edit (ECellTextView *text_view) +{ + ect_queue_redraw (text_view, text_view->edit->col, text_view->edit->row); + ect_stop_editing (text_view); +} + +/* + * ECell::realize method + */ static ECellView * -ect_realize (ECell *ecell, GnomeCanvas *canvas) +ect_realize (ECell *ecell, void *view) { ECellText *ect = E_CELL_TEXT (ecell); - ECellTextView *ectv = g_new0 (ECellTextView, 1); - - ectv->cell_view.ecell = ecell; - ectv->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + ECellTextView *text_view = g_new0 (ECellTextView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + text_view->cell_view.ecell = ecell; + text_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); if (ect->font_name){ GdkFont *f; f = gdk_fontset_load (ect->font_name); - ectv->font = f; + text_view->font = f; } - if (!ectv->font){ - ectv->font = GTK_WIDGET (canvas)->style->font; + if (!text_view->font){ + text_view->font = GTK_WIDGET (canvas)->style->font; - gdk_font_ref (ectv->font); + gdk_font_ref (text_view->font); } - - ectv->canvas = canvas; - return (ECellView *)ectv; + text_view->eti = eti; + text_view->canvas = canvas; + + return (ECellView *)text_view; } +/* + * ECell::unrealize method + */ static void ect_unrealize (ECellView *ecv) { - ECellTextView *ectv = (ECellTextView *) ecv; + ECellTextView *text_view = (ECellTextView *) ecv; - gdk_gc_unref (ectv->gc); - ectv->gc = NULL; + gdk_gc_unref (text_view->gc); + text_view->gc = NULL; - gdk_font_unref (ectv->font); - ectv->font = NULL; + gdk_font_unref (text_view->font); + text_view->font = NULL; - g_free (ectv); + g_free (text_view); } +/* + * ECell::draw method + */ static void ect_draw (ECellView *ecell_view, GdkDrawable *drawable, int col, int row, gboolean selected, @@ -70,41 +152,117 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, { ECellText *ect = E_CELL_TEXT (ecell_view->ecell); ECellTextView *text_view = (ECellTextView *) ecell_view; + GtkWidget *w = GTK_WIDGET (text_view->canvas); GdkRectangle rect; const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); - int xoff, w; + GdkFont *font = text_view->font; + const int height = font->ascent + font->descent; + int xoff; + gboolean edit_display = FALSE; + + /* + * Figure if this cell is being edited + */ + if (text_view->edit){ + CellEdit *edit = text_view->edit; + + printf ("We are editing a cell [%d %d %d %d]\n", col, row, edit->col, edit->row); + if ((edit->col == col) && (edit->row == row)) + edit_display = TRUE; + } + + /* + * Be a nice citizen: clip to the region we are supposed to draw on + */ rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; - gdk_gc_set_clip_rectangle (text_view->gc, &rect); - switch (ect->justify){ - case GTK_JUSTIFY_LEFT: - xoff = 1; - break; - - case GTK_JUSTIFY_RIGHT: - w = 1 + gdk_text_width (text_view->font, str, strlen (str)); - xoff = (x2 - x1) - w; - break; + if (edit_display){ + CellEdit *edit = text_view->edit; + const char *text = gtk_entry_get_text (edit->entry); + GdkWChar *text_wc = g_new (GdkWChar, strlen (text) + 1); + int text_wc_len = gdk_mbstowcs (text_wc, text, strlen (text)); + const int cursor_pos = GTK_EDITABLE (edit->entry)->current_pos; + const int left_len = gdk_text_width_wc (text_view->font, text_wc, cursor_pos); + + text_wc [text_wc_len] = 0; - case GTK_JUSTIFY_CENTER: - xoff = ((x2 - x1) - gdk_text_width (text_view->font, str, strlen (str))) / 2; - break; - default: + /* + * Find a good spot for painting + */ xoff = 0; - g_warning ("Can not handle GTK_JUSTIFY_FILL"); - break; - } + + /* + * Paint + */ + gdk_gc_set_foreground (text_view->gc, &w->style->base [GTK_STATE_NORMAL]); + gdk_draw_rectangle (drawable, text_view->gc, TRUE, + rect.x, rect.y, rect.width, rect.height); + gdk_gc_set_foreground (text_view->gc, &w->style->text [GTK_STATE_NORMAL]); + + { + GdkGC *gc = text_view->gc; + const int y = y2 - font->descent - ((y2-y1-height)/2); + int px, i; + + px = x1; + + printf ("Cursor at: %d\n", cursor_pos); + + for (i = 0; *text_wc; text_wc++, i++){ + gdk_draw_text_wc ( + drawable, font, gc, px, y, text_wc, 1); + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } - /* Draw now */ - { - GtkWidget *w = GTK_WIDGET (text_view->canvas); + px += gdk_text_width_wc (font, text_wc, 1); + } + + if (i == cursor_pos){ + gdk_draw_line ( + drawable, gc, + px, y - font->ascent, + px, y + font->descent - 1); + } + } + } else { + /* + * Regular cell + */ GdkColor *background, *foreground; - const int height = text_view->font->ascent + text_view->font->descent; + int width; + + /* + * Compute draw mode + */ + switch (ect->justify){ + case GTK_JUSTIFY_LEFT: + xoff = 1; + break; + + case GTK_JUSTIFY_RIGHT: + width = 1 + gdk_text_width (font, str, strlen (str)); + xoff = (x2 - x1) - width; + break; + + case GTK_JUSTIFY_CENTER: + xoff = ((x2 - x1) - gdk_text_width (font, str, strlen (str))) / 2; + break; + default: + xoff = 0; + g_warning ("Can not handle GTK_JUSTIFY_FILL"); + break; + } + if (selected){ background = &w->style->bg [GTK_STATE_SELECTED]; @@ -118,33 +276,58 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, gdk_draw_rectangle (drawable, text_view->gc, TRUE, rect.x, rect.y, rect.width, rect.height); gdk_gc_set_foreground (text_view->gc, foreground); - gdk_draw_string (drawable, text_view->font, text_view->gc, - x1 + xoff, y2 - text_view->font->descent - ((y2-y1-height)/2), str); - } -} -static void -e_cell_text_start_editing (ECellText *ect, int col, int row) -{ - printf ("Starting to edit %d %d\n", col, row); + gdk_draw_string ( + drawable, font, text_view->gc, + x1 + xoff, + y2 - font->descent - ((y2-y1-height)/2), str); + } } +/* + * ECell::event method + */ static gint ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - ECell *ecell = ecell_view->ecell; - ECellText *ect = E_CELL_TEXT (ecell); + ECellTextView *text_view = (ECellTextView *) ecell_view; switch (event->type){ case GDK_BUTTON_PRESS: + if (text_view->edit){ + printf ("FIXME: Should handle click here\n"); + } else + e_table_item_enter_edit (text_view->eti, col, row); + break; + + case GDK_BUTTON_RELEASE: return TRUE; - default: + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + ect_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit) + e_table_item_enter_edit (text_view->eti, col, row); + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + ect_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: break; + + default: + return FALSE; } - return FALSE; + return TRUE; } +/* + * ECell::height method + */ static int ect_height (ECellView *ecell_view, int col, int row) { @@ -153,6 +336,66 @@ ect_height (ECellView *ecell_view, int col, int row) return (text_view->font->ascent + text_view->font->descent) + TEXT_PAD; } +/* + * Callback: invoked when the user pressed "enter" on the GtkEntry + */ +static void +ect_entry_activate (GtkEntry *entry, ECellTextView *text_view) +{ + e_table_item_leave_edit (text_view->eti); +} + +/* + * ECellView::enter_edit method + */ +static void * +ect_enter_edit (ECellView *ecell_view, int col, int row) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + const char *str = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + CellEdit *edit; + + printf ("Entering edit mode! [%d %d]\n", col, row); + + edit = g_new (CellEdit, 1); + text_view->edit = edit; + + edit->entry = (GtkEntry *) gtk_entry_new (); + gtk_entry_set_text (edit->entry, str); + edit->old_text = g_strdup (str); + gtk_signal_connect (GTK_OBJECT (edit->entry), "activate", + GTK_SIGNAL_FUNC (ect_entry_activate), text_view); + + /* + * The hack: create this window off-screen + */ + edit->entry_top = gtk_window_new (GTK_WINDOW_POPUP); + gtk_container_add (GTK_CONTAINER (edit->entry_top), GTK_WIDGET (edit->entry)); + gtk_widget_set_uposition (edit->entry_top, 20000, 20000); + gtk_widget_show_all (edit->entry_top); + + ect_queue_redraw (text_view, col, row); + + return NULL; +} + +/* + * ECellView::leave_edit method + */ +static void +ect_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + ECellTextView *text_view = (ECellTextView *) ecell_view; + + printf ("Leaving edit mode!\n"); + + ect_accept_edits (text_view); + ect_stop_editing (text_view); +} + +/* + * GtkObject::destroy method + */ static void ect_destroy (GtkObject *object) { @@ -170,12 +413,14 @@ e_cell_text_class_init (GtkObjectClass *object_class) object_class->destroy = ect_destroy; - ecc->realize = ect_realize; - ecc->unrealize = ect_unrealize; - ecc->draw = ect_draw; - ecc->event = ect_event; - ecc->height = ect_height; - + ecc->realize = ect_realize; + ecc->unrealize = ect_unrealize; + ecc->draw = ect_draw; + ecc->event = ect_event; + ecc->height = ect_height; + ecc->enter_edit = ect_enter_edit; + ecc->leave_edit = ect_leave_edit; + parent_class = gtk_type_class (PARENT_TYPE); } diff --git a/widgets/table/e-cell.c b/widgets/table/e-cell.c index 9caa31f2ca..2bc49f7a45 100644 --- a/widgets/table/e-cell.c +++ b/widgets/table/e-cell.c @@ -13,7 +13,7 @@ #define PARENT_TYPE gtk_object_get_type() static ECellView * -ec_realize (ECell *e_cell, GnomeCanvas *canvas) +ec_realize (ECell *e_cell, void *view) { return NULL; } @@ -28,20 +28,20 @@ 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"); + g_error ("e-cell-draw invoked\n"); } static gint ec_event (ECellView *ecell_view, GdkEvent *event, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } static gint ec_height (ECellView *ecell_view, int col, int row) { - g_warning ("e-cell-event invoked\n"); + g_error ("e-cell-event invoked\n"); return 0; } @@ -98,10 +98,10 @@ e_cell_event (ECellView *ecell_view, GdkEvent *event, int col, int row) } ECellView * -e_cell_realize (ECell *ecell, GnomeCanvas *canvas) +e_cell_realize (ECell *ecell, void *view) { return E_CELL_CLASS (GTK_OBJECT (ecell)->klass)->realize ( - ecell, canvas); + ecell, view); } void @@ -125,3 +125,16 @@ e_cell_height (ECellView *ecell_view, int col, int row) ecell_view, col, row); } +void * +e_cell_enter_edit (ECellView *ecell_view, int col, int row) +{ + return E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->enter_edit ( + ecell_view, col, row); +} + +void +e_cell_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ + E_CELL_CLASS (GTK_OBJECT (ecell_view->ecell)->klass)->leave_edit ( + ecell_view, col, row, edit_context); +} diff --git a/widgets/table/e-cell.h b/widgets/table/e-cell.h index 9cd62f3909..b0f62d020c 100644 --- a/widgets/table/e-cell.h +++ b/widgets/table/e-cell.h @@ -1,7 +1,7 @@ #ifndef _E_CELL_H_ #define _E_CELL_H_ -#include +#include #include "e-table-model.h" #define E_CELL_TYPE (e_cell_get_type ()) @@ -29,19 +29,22 @@ struct _ECellView { typedef struct { GtkObjectClass parent_class; - ECellView *(*realize) (ECell *, GnomeCanvas *canvas); - void (*unrealize) (ECellView *); + ECellView *(*realize) (ECell *ecell, void *view); + void (*unrealize) (ECellView *e_cell_view); void (*draw) (ECellView *ecell_view, GdkDrawable *drawable, 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); - int (*height) (ECellView *ecell, int col, int row); + void (*focus) (ECellView *ecell_view, int col, int row, int x1, int y1, int x2, int y2); + void (*unfocus) (ECellView *ecell_view); + int (*height) (ECellView *ecell_view, int col, int row); + + void *(*enter_edit)(ECellView *ecell_view, int col, int row); + void (*leave_edit)(ECellView *ecell_view, int col, int row, void *context); } ECellClass; 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); +ECellView *e_cell_realize (ECell *ecell, void *view); void e_cell_unrealize (ECellView *ecell_view); void e_cell_draw (ECellView *ecell_view, GdkDrawable *dr, int col, int row, gboolean selected, @@ -50,4 +53,7 @@ void e_cell_focus (ECellView *ecell_view, int col, int row, int x1, in void e_cell_unfocus (ECellView *ecell_view); int e_cell_height (ECellView *ecell_view, int col, int row); +void *e_cell_enter_edit(ECellView *ecell_view, int col, int row); +void e_cell_leave_edit(ECellView *ecell_view, int col, int row, void *edit_context); + #endif /* _E_CELL_H_ */ diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index a561fbfd15..1b98bbfce4 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -37,6 +37,7 @@ enum { ARG_TABLE_X, ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, + ARG_TABLE_DRAW_FOCUS, ARG_LENGHT_THRESHOLD }; @@ -51,7 +52,6 @@ enum { static void eti_realize_cell_views (ETableItem *eti) { - GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti); int i; /* @@ -63,7 +63,7 @@ eti_realize_cell_views (ETableItem *eti) for (i = 0; i < eti->n_cells; i++){ ETableCol *col = e_table_header_get_column (eti->header, i); - eti->cell_views [i] = e_cell_realize (col->ecell, item->canvas); + eti->cell_views [i] = e_cell_realize (col->ecell, eti); } } @@ -117,12 +117,9 @@ eti_remove_table_model (ETableItem *eti) 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; - eti->table_model_selection_id = 0; eti->table_model = NULL; } @@ -284,7 +281,9 @@ eti_row_diff (ETableItem *eti, int start_row, int end_row) * border as well. */ static void -eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int end_col, int end_row, int border) +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; @@ -301,10 +300,25 @@ eti_request_region_redraw (ETableItem *eti, int start_col, int start_row, int en eti->y1 + y1 + height + 1 + border); } -static void -eti_table_model_row_selection (ETableModel *table_model, int row, gboolean selected, ETableItem *eti) +void +e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row) { - eti_request_region_redraw (eti, 0, row, eti->cols - 1, row, 0); + int border; + + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + if ((start_col == eti->focused_col) || + (end_col == eti->focused_col) || + (start_row == eti->focused_row) || + (end_row == eti->focused_row)) + border = 2; + else + border = 0; + + eti_request_region_redraw (eti, start_col, start_row, end_col, end_row, border); } static void @@ -313,14 +327,11 @@ eti_add_table_model (ETableItem *eti, ETableModel *table_model) g_assert (eti->table_model == NULL); eti->table_model = table_model; - gtk_object_ref (GTK_OBJECT (table_model)); + gtk_object_ref (GTK_OBJECT (eti->table_model)); eti->table_model_change_id = gtk_signal_connect ( GTK_OBJECT (table_model), "model_changed", GTK_SIGNAL_FUNC (eti_table_model_changed), eti); - eti->table_model_selection_id = gtk_signal_connect ( - GTK_OBJECT (table_model), "row_selection", - GTK_SIGNAL_FUNC (eti_table_model_row_selection), eti); eti_table_model_changed (table_model, eti); } @@ -418,6 +429,11 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_GRID: eti->draw_grid = GTK_VALUE_BOOL (*arg); + break; + + case ARG_TABLE_DRAW_FOCUS: + eti->draw_focus = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -529,7 +545,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int f_x1, f_x2, f_y1, f_y2; gboolean f_found; - printf ("Rect: %d %d %d %d\n", x, y, width, height); +/* printf ("Rect: %d %d %d %d\n", x, y, width, height); */ /* * Clear the background */ @@ -604,7 +620,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, height = eti_row_height (eti, row); xd = x_offset; - printf ("paint: %d %d\n", yd, yd + height); +/* printf ("paint: %d %d\n", yd, yd + height); */ selected = g_slist_find (eti->selection, GINT_TO_POINTER (row)) != NULL; @@ -631,9 +647,7 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * 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); + if (f_found && eti->draw_focus){ gdk_draw_rectangle ( drawable, eti->focus_gc, FALSE, f_x1 - 1, f_y1 - 1, f_x2 - f_x1 + 2 , f_y2 - f_y1 + 2); @@ -725,6 +739,8 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) } case GDK_KEY_PRESS: + printf ("KEYPRESS!\n"); + if (eti->focused_col == -1) return FALSE; @@ -781,6 +797,7 @@ eti_row_selection (ETableItem *eti, int row, gboolean 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 @@ -813,6 +830,8 @@ 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); + gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -862,6 +881,11 @@ e_table_item_focus (ETableItem *eti, int col, int row) eti->focused_row = row; eti_request_region_redraw (eti, col, row, col, row, FOCUSED_BORDER); + + /* + * make sure we have the Gtk Focus + */ + gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas)); } void @@ -944,7 +968,7 @@ 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)); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); switch (eti->selection_mode){ case GTK_SELECTION_SINGLE: @@ -973,3 +997,28 @@ e_table_item_select_row (ETableItem *eti, int row) } } + +void +e_table_item_enter_edit (ETableItem *eti, int col, int row) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + eti->editing_col = col; + eti->editing_row = row; + + eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], col, row); +} + +void +e_table_item_leave_edit (ETableItem *eti) +{ + g_return_if_fail (eti != NULL); + g_return_if_fail (E_IS_TABLE_ITEM (eti)); + + e_cell_leave_edit (eti->cell_views [eti->editing_col], eti->editing_col, eti->editing_row, eti->edit_ctx); + eti->editing_col = -1; + eti->editing_row = -1; + eti->edit_ctx = NULL; +} + diff --git a/widgets/table/e-table-item.h b/widgets/table/e-table-item.h index 17d422ddf5..02f7beb1ac 100644 --- a/widgets/table/e-table-item.h +++ b/widgets/table/e-table-item.h @@ -28,14 +28,14 @@ typedef struct { int header_dim_change_id; int header_structure_change_id; int table_model_change_id; - int table_model_selection_id; GdkGC *fill_gc; GdkGC *grid_gc; GdkGC *focus_gc; unsigned int draw_grid:1; - + unsigned int draw_focus:1; + int focused_col, focused_row; /* @@ -52,6 +52,12 @@ typedef struct { GSList *selection; GtkSelectionMode selection_mode; + + /* + * During edition + */ + int editing_col, editing_row; + void *edit_ctx; } ETableItem; typedef struct { @@ -85,4 +91,11 @@ void e_table_item_set_selection_mode (ETableItem *e_table_Item, gboolean e_table_item_is_row_selected (ETableItem *e_table_Item, int row); +void e_table_item_leave_edit (ETableItem *eti); +void e_table_item_enter_edit (ETableItem *eti, int col, int row); + +void e_table_item_redraw_range (ETableItem *eti, + int start_col, int start_row, + int end_col, int end_row); + #endif /* _E_TABLE_ITEM_H_ */ diff --git a/widgets/table/e-table-model.c b/widgets/table/e-table-model.c index 288c20f20e..103bb31b57 100644 --- a/widgets/table/e-table-model.c +++ b/widgets/table/e-table-model.c @@ -61,7 +61,7 @@ e_table_model_value_at (ETableModel *e_table_model, int col, int row) } void -e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data) +e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data) { g_return_if_fail (e_table_model != NULL); g_return_if_fail (E_IS_TABLE_MODEL (e_table_model)); diff --git a/widgets/table/e-table-model.h b/widgets/table/e-table-model.h index ea5d31493d..22339ae484 100644 --- a/widgets/table/e-table-model.h +++ b/widgets/table/e-table-model.h @@ -23,7 +23,7 @@ typedef struct { const char *(*column_name) (ETableModel *etm, int col); int (*row_count) (ETableModel *etm); void *(*value_at) (ETableModel *etm, int col, int row); - void (*set_value_at) (ETableModel *etm, int col, int row, void *value); + void (*set_value_at) (ETableModel *etm, int col, int row, const void *value); gboolean (*is_cell_editable) (ETableModel *etm, int col, int row); /* @@ -40,7 +40,7 @@ int e_table_model_column_count (ETableModel *e_table_model); const char *e_table_model_column_name (ETableModel *e_table_model, int col); int e_table_model_row_count (ETableModel *e_table_model); void *e_table_model_value_at (ETableModel *e_table_model, int col, int row); -void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, void *data); +void e_table_model_set_value_at (ETableModel *e_table_model, int col, int row, const void *data); gboolean e_table_model_is_cell_editable (ETableModel *e_table_model, int col, int row); /* diff --git a/widgets/table/e-table-simple.c b/widgets/table/e-table-simple.c index 16691e5442..2076e06cef 100644 --- a/widgets/table/e-table-simple.c +++ b/widgets/table/e-table-simple.c @@ -47,7 +47,7 @@ simple_value_at (ETableModel *etm, int col, int row) } static void -simple_set_value_at (ETableModel *etm, int col, int row, void *val) +simple_set_value_at (ETableModel *etm, int col, int row, const void *val) { ETableSimple *simple = (ETableSimple *)etm; diff --git a/widgets/table/e-table-simple.h b/widgets/table/e-table-simple.h index 544e681a6c..1f7a17aeff 100644 --- a/widgets/table/e-table-simple.h +++ b/widgets/table/e-table-simple.h @@ -7,7 +7,7 @@ typedef int (*ETableSimpleColumnCountFn) (ETableModel *etm, void *dat typedef const char *(*ETableSimpleColumnNameFn) (ETableModel *etm, int col, void *data); typedef int (*ETableSimpleRowCountFn) (ETableModel *etm, void *data); typedef void *(*ETableSimpleValueAtFn) (ETableModel *etm, int col, int row, void *data); -typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, void *val, void *data); +typedef void (*ETableSimpleSetValueAtFn) (ETableModel *etm, int col, int row, const void *val, void *data); typedef gboolean (*ETableSimpleIsCellEditableFn) (ETableModel *etm, int col, int row, void *data); typedef struct { diff --git a/widgets/table/table-test.c b/widgets/table/table-test.c index 3517ecf692..f677e9e2d1 100644 --- a/widgets/table/table-test.c +++ b/widgets/table/table-test.c @@ -151,7 +151,7 @@ value_at (ETableModel *etc, int col, int row, void *data) } static void -set_value_at (ETableModel *etc, int col, int row, void *val, void *data) +set_value_at (ETableModel *etc, int col, int row, const void *val, void *data) { g_assert (col < cols); g_assert (row < lines); @@ -236,6 +236,7 @@ main (int argc, char *argv []) "x", 10, "y", 30, "drawgrid", TRUE, + "drawfocus", TRUE, NULL); gtk_main (); -- cgit v1.2.3