From c50636dba333983e99deeb76338bbec3390a1fbe Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Tue, 30 Nov 1999 05:50:54 +0000 Subject: New file. Implement a multi-state image toggle cell object. 1999-11-29 Miguel de Icaza * e-cell-toggle.c, e-cell-toggle.h: New file. Implement a multi-state image toggle cell object. * e-cell-text.c (ect_leave_edit): Handle the case of us calling leave edit manually. (ect_stop_editing): Leave manually editing here. (ect_draw): Add one pixel to the border for left and right; Handle off-screen cursor (must be improved). (ect_edit_select_all): New function. (ect_event): Select all text on editing start * e-table-item.c (eti_event): Map mouse events and dispatch them. (eti_event): Add spreadsheet mode for editing; Enter editing only with visual characters; Leave editing mode when a different row has been selected. (eti_get_height): Fix the computation for this; Fix logic for the length_threshold. (eti_draw): Add borders on all sides of the box; Only draw focus if the cell is not being edited. svn path=/trunk/; revision=1445 --- widgets/ChangeLog | 23 +++++ widgets/e-cell-checkbox.c | 185 ++++++++++++++++++++++++++++++++++ widgets/e-cell-checkbox.h | 25 +++++ widgets/e-cell-text.c | 74 +++++++++++--- widgets/e-cell-toggle.c | 204 ++++++++++++++++++++++++++++++++++++++ widgets/e-cell-toggle.h | 37 +++++++ widgets/e-table-item.c | 177 +++++++++++++++++++++++++-------- widgets/e-table-item.h | 2 +- widgets/e-table/ChangeLog | 23 +++++ widgets/e-table/e-cell-checkbox.c | 185 ++++++++++++++++++++++++++++++++++ widgets/e-table/e-cell-checkbox.h | 25 +++++ widgets/e-table/e-cell-text.c | 74 +++++++++++--- widgets/e-table/e-cell-toggle.c | 204 ++++++++++++++++++++++++++++++++++++++ widgets/e-table/e-cell-toggle.h | 37 +++++++ widgets/e-table/e-table-item.c | 177 +++++++++++++++++++++++++-------- widgets/e-table/e-table-item.h | 2 +- widgets/e-table/table-test.c | 1 + widgets/table-test.c | 1 + widgets/table/e-cell-checkbox.c | 185 ++++++++++++++++++++++++++++++++++ widgets/table/e-cell-checkbox.h | 25 +++++ widgets/table/e-cell-text.c | 74 +++++++++++--- widgets/table/e-cell-toggle.c | 204 ++++++++++++++++++++++++++++++++++++++ widgets/table/e-cell-toggle.h | 37 +++++++ widgets/table/e-table-item.c | 177 +++++++++++++++++++++++++-------- widgets/table/e-table-item.h | 2 +- widgets/table/table-test.c | 1 + 26 files changed, 1993 insertions(+), 168 deletions(-) create mode 100644 widgets/e-cell-checkbox.c create mode 100644 widgets/e-cell-checkbox.h create mode 100644 widgets/e-cell-toggle.c create mode 100644 widgets/e-cell-toggle.h create mode 100644 widgets/e-table/e-cell-checkbox.c create mode 100644 widgets/e-table/e-cell-checkbox.h create mode 100644 widgets/e-table/e-cell-toggle.c create mode 100644 widgets/e-table/e-cell-toggle.h create mode 100644 widgets/table/e-cell-checkbox.c create mode 100644 widgets/table/e-cell-checkbox.h create mode 100644 widgets/table/e-cell-toggle.c create mode 100644 widgets/table/e-cell-toggle.h (limited to 'widgets') diff --git a/widgets/ChangeLog b/widgets/ChangeLog index 7972994a79..fbb2ed0a86 100644 --- a/widgets/ChangeLog +++ b/widgets/ChangeLog @@ -1,3 +1,26 @@ +1999-11-29 Miguel de Icaza + + * e-cell-toggle.c, e-cell-toggle.h: New file. Implement a + multi-state image toggle cell object. + + * e-cell-text.c (ect_leave_edit): Handle the case of us calling + leave edit manually. + (ect_stop_editing): Leave manually editing here. + (ect_draw): Add one pixel to the border for left and right; + Handle off-screen cursor (must be improved). + (ect_edit_select_all): New function. + (ect_event): Select all text on editing start + + * e-table-item.c (eti_event): Map mouse events and dispatch them. + (eti_event): Add spreadsheet mode for editing; Enter editing only + with visual characters; + Leave editing mode when a different row has been selected. + (eti_get_height): Fix the computation for this; Fix logic for the + length_threshold. + + (eti_draw): Add borders on all sides of the box; + Only draw focus if the cell is not being edited. + 1999-11-28 Miguel de Icaza * e-table-item.c (eti_draw): Focus inside, not outside. diff --git a/widgets/e-cell-checkbox.c b/widgets/e-cell-checkbox.c new file mode 100644 index 0000000000..db74464d5c --- /dev/null +++ b/widgets/e-cell-checkbox.c @@ -0,0 +1,185 @@ +/* + * e-cell-checkbox.c: Checkbox cell renderer + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-checkbox.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellCheckboxView; + +static ECellClass *parent_class; + +static void +eccb_queue_redraw (ECellCheckboxView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +eecb_realize (ECell *ecell, void *view) +{ + ECellCheckbox *eccb = E_CELL_CHECKBOX (ecell); + ECellCheckboxView *check_view = g_new0 (ECellCheckboxView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + check_view->cell_view.ecell = ecell; + check_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + check_view->eti = eti; + check_view->canvas = canvas; + + return (ECellView *) check_view; +} + +/* + * ECell::unrealize method + */ +static void +eecb_unrealize (ECellView *ecv) +{ + ECellCheckboxView *check_view = (ECellCheckboxView *) ecv; + + gdk_gc_unref (check_view->gc); + text_view->gc = NULL; + + g_free (check_view); +} + +/* + * ECell::draw method + */ +static void +eecb_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ +} + +/* + * ECell::event method + */ +static gint +eecb_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellCheckboxView *text_view = (ECellCheckboxView *) ecell_view; + + switch (event->type){ + case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); + 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: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + eecb_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit){ + e_table_item_enter_edit (text_view->eti, col, row); + eecb_edit_seleecb_all (text_view); + } + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + eecb_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: + break; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +eecb_height (ECellView *ecell_view, int col, int row) +{ + return 10; +} + +/* + * ECellView::enter_edit method + */ +static void * +eecb_enter_edit (ECellView *ecell_view, int col, int row) +{ +} + +/* + * ECellView::leave_edit method + */ +static void +eecb_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ +} + +static void +e_cell_checkbox_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + ecc->realize = eecb_realize; + ecc->unrealize = eecb_unrealize; + ecc->draw = eecb_draw; + ecc->event = eecb_event; + ecc->height = eecb_height; + ecc->enter_edit = eecb_enter_edit; + ecc->leave_edit = eecb_leave_edit; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellCheckbox", ECellCheckbox, e_cell_checkbox_class_init, NULL, PARENT_TYPE); + +ECell * +e_cell_checkbox_new (ETableModel *etm) +{ + ECellCheckbox *eccb = gtk_type_new (e_cell_checkbox_get_type ()); + + E_CELL (eccb)->table_model = etm; + + return (ECell *) eccb; +} diff --git a/widgets/e-cell-checkbox.h b/widgets/e-cell-checkbox.h new file mode 100644 index 0000000000..6c85fbff21 --- /dev/null +++ b/widgets/e-cell-checkbox.h @@ -0,0 +1,25 @@ +#ifndef _E_CELL_CHECKBOX_H_ +#define _E_CELL_CHECKBOX_H_ + +#include +#include "e-cell.h" + +#define E_CELL_CHECKBOX_TYPE (e_cell_checkbox_get_type ()) +#define E_CELL_CHECKBOX(o) (GTK_CHECK_CAST ((o), E_CELL_CHECKBOX_TYPE, ECellCheckbox)) +#define E_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_CHECKBOX_TYPE, ECellCheckboxClass)) +#define E_IS_CELL_CHECKBOX(o) (GTK_CHECK_TYPE ((o), E_CELL_CHECKBOX_TYPE)) +#define E_IS_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_CHECKBOX_TYPE)) + +typedef struct { + ECell parent; +} ECellCheckbox; + +typedef struct { + ECellClass parent_class; +} ECellCheckboxClass; + +GtkType e_cell_checkbox_get_type (void); +ECell *e_cell_checkbox_new (ETableModel *model); + +#endif /* _E_CELL_CHECKBOX_H_ */ + diff --git a/widgets/e-cell-text.c b/widgets/e-cell-text.c index f0501ab4cb..b18c179ca5 100644 --- a/widgets/e-cell-text.c +++ b/widgets/e-cell-text.c @@ -82,6 +82,8 @@ ect_stop_editing (ECellTextView *text_view) g_free (edit); text_view->edit = NULL; + + e_table_item_leave_edit (text_view->eti); } /* @@ -166,8 +168,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, 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; } @@ -191,11 +191,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, text_wc [text_wc_len] = 0; - /* - * Find a good spot for painting - */ - xoff = 0; - /* * Paint */ @@ -208,11 +203,23 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, GdkGC *gc = text_view->gc; const int y = y2 - font->descent - ((y2-y1-height)/2); int px, i; + + /* + * Border + */ + x1 += 2; + x2--; px = x1; - printf ("Cursor at: %d\n", cursor_pos); - + /* + * If the cursor is outside the visible range + * + * FIXME: we really want a better behaviour. + */ + if ((px + left_len) > x2) + px -= left_len - (x2-x1); + for (i = 0; *text_wc; text_wc++, i++){ gdk_draw_text_wc ( drawable, font, gc, px, y, text_wc, 1); @@ -240,6 +247,12 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, */ GdkColor *background, *foreground; int width; + + /* + * Border + */ + x1++; + x2--; /* * Compute draw mode @@ -284,6 +297,17 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, } } +/* + * Selects the entire string + */ +static void +ect_edit_select_all (ECellTextView *text_view) +{ + g_assert (text_view->edit); + + gtk_editable_select_region (GTK_EDITABLE (text_view->edit->entry), 0, -1); +} + /* * ECell::event method */ @@ -294,6 +318,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); if (text_view->edit){ printf ("FIXME: Should handle click here\n"); } else @@ -301,6 +331,11 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) break; case GDK_BUTTON_RELEASE: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); return TRUE; case GDK_KEY_PRESS: @@ -309,8 +344,10 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) return TRUE; } - if (!text_view->edit) + if (!text_view->edit){ e_table_item_enter_edit (text_view->eti, col, row); + ect_edit_select_all (text_view); + } gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); ect_queue_redraw (text_view, col, row); @@ -355,10 +392,11 @@ ect_enter_edit (ECellView *ecell_view, int col, int row) 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->col = col; + edit->row = row; edit->entry = (GtkEntry *) gtk_entry_new (); gtk_entry_set_text (edit->entry, str); @@ -387,10 +425,14 @@ 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); + if (text_view->edit){ + ect_accept_edits (text_view); + ect_stop_editing (text_view); + } else { + /* + * We did invoke this leave edit internally + */ + } } /* diff --git a/widgets/e-cell-toggle.c b/widgets/e-cell-toggle.c new file mode 100644 index 0000000000..33e4d283ee --- /dev/null +++ b/widgets/e-cell-toggle.c @@ -0,0 +1,204 @@ +/* + * e-cell-toggle.c: Multi-state image toggle cell object. + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-toggle.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +Typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellToggleView; + +static ECellClass *parent_class; + +static void +etog_queue_redraw (ECellToggleView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +etog_realize (ECell *ecell, void *view) +{ + ECellToggle *eccb = E_CELL_TOGGLE (ecell); + ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + toggle_view->cell_view.ecell = ecell; + toggle_view->eti = eti; + toggle_view->canvas = canvas; + + return (ECellView *) toggle_view; +} + +/* + * ECell::unrealize method + */ +static void +etog_unrealize (ECellView *ecv) +{ + ECellToggleView *toggle_view = (ECellToggleView *) ecv; + + g_free (toggle_view); +} + +/* + * ECell::draw method + */ +static void +etog_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + GdkPixbuf *image; + const int value = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + + if (value >= toggle->n_states){ + g_warning ("Value from the table model is %d, the states we support are [0..%d)\n", + value, toggle->n_states); + return; + } + + image = toggle->images [value]; + +} + +static void +etog_set_value (ECellToggleView *toggle_view, int col, int row, int value) +{ + ECell *ecell = toggle_view->cell_view.ecell + ECellToggle *toggle = E_CELL_TOGGLE (ecell); + + if (value >= toggle->n_vals) + value = 0; + + e_table_model_set_value_at (ecell->table_model, col, row, value); + etog_queue_redraw (toggle_view, col, row); +} + +/* + * ECell::event method + */ +static gint +etog_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + int value = e_table_model_value_at (e_cell_view->ecell->table_model, col, row); + + switch (event->type){ + case GDK_BUTTON_RELEASE: + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_space){ + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + } + return FALSE; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +etog_height (ECellView *ecell_view, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + + return toggle->height; +} + +static void +etog_destroy (GtkObject *object) +{ + ECellToggle *etog = E_CELL_TOGGLE (object); + int i; + + for (i = 0; i < etog->n_states; i++) + gdk_pixbuf_unref (etog->images [i]); + + g_free (etog->images); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +e_cell_toggle_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + object_class->destroy = etog_destroy; + + ecc->realize = etog_realize; + ecc->unrealize = etog_unrealize; + ecc->draw = etog_draw; + ecc->event = etog_event; + ecc->height = etog_height; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellToggle", ECellToggle, e_cell_toggle_class_init, NULL, PARENT_TYPE); + +void +e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + int max_height = 0; + + E_CELL (etog)->table_model = etm; + + etog->border = border; + etog->n_states = n_states; + + etog->images = g_new (GdkPixbuf *, n_states); + + for (i = 0; i < n_states; i++){ + etog->images [i] = images [i]; + gdk_pixbuf_ref (images [i]); + + if (images [i]->art_pixbuf->height > max_height) + max_height = images [i]->art_pixbuf->height; + } + + etog->height = max_height; +} + +ECell * +e_cell_toggle_new (ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + ECellToggle *etog = gtk_type_new (e_cell_toggle_get_type ()); + + e_cell_toggle_construct (etog, etm, border, n_states, images); + + return (ECell *) etog; +} diff --git a/widgets/e-cell-toggle.h b/widgets/e-cell-toggle.h new file mode 100644 index 0000000000..3cd99f5d04 --- /dev/null +++ b/widgets/e-cell-toggle.h @@ -0,0 +1,37 @@ +#ifndef _E_CELL_TOGGLE_H_ +#define _E_CELL_TOGGLE_H_ + +#include +#include +#include "e-cell.h" + +#define E_CELL_TOGGLE_TYPE (e_cell_toggle_get_type ()) +#define E_CELL_TOGGLE(o) (GTK_CHECK_CAST ((o), E_CELL_TOGGLE_TYPE, ECellToggle)) +#define E_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TOGGLE_TYPE, ECellToggleClass)) +#define E_IS_CELL_TOGGLE(o) (GTK_CHECK_TYPE ((o), E_CELL_TOGGLE_TYPE)) +#define E_IS_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TOGGLE_TYPE)) + +typedef struct { + ECell parent; + + int border; + int n_states; + GdkPixbuf **images; + + int height; +} ECellToggle; + +typedef struct { + ECellClass parent_class; +} ECellToggleClass; + +GtkType e_cell_toggle_get_type (void); +ECell *e_cell_toggle_new (ETableModel *model, int border, + int n_states, + GdkPibux **images); +void e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, + int border, int n_states, GdkPixbuf **images); + +#endif /* _E_CELL_TOGGLE_H_ */ + + diff --git a/widgets/e-table-item.c b/widgets/e-table-item.c index 5816acfb23..ceb6adda95 100644 --- a/widgets/e-table-item.c +++ b/widgets/e-table-item.c @@ -38,9 +38,19 @@ enum { ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, + ARG_MODE_SPREADSHEET, ARG_LENGHT_THRESHOLD }; +static gboolean +eti_editing (ETableItem *eti) +{ + if (eti->editing_col == -1) + return FALSE; + else + return TRUE; +} + /* * During realization, we have to invoke the per-ecell realize routine * (On our current setup, we have one e-cell per column. @@ -186,23 +196,26 @@ eti_get_height (ETableItem *eti) { const int rows = eti->rows; int row; - int height = 0; + int height; if (rows == 0) return 0; - - if (rows > eti->length_threshold){ - height = eti_row_height (eti, 0) * rows; - return height; + if (eti->length_threshold != -1){ + if (rows > eti->length_threshold){ + height = (eti_row_height (eti, 0) + 1) * rows; + + /* + * 1 pixel at the top + */ + return height + 1; + } } - + + height = 1; for (row = 0; row < rows; row++) - height += eti_row_height (eti, row); + height += eti_row_height (eti, row) + 1; - /* Add division lines pixels */ - height += rows; - return height; } @@ -434,6 +447,10 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_FOCUS: eti->draw_focus = GTK_VALUE_BOOL (*arg); break; + + case ARG_MODE_SPREADSHEET: + eti->mode_spreadsheet = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -445,6 +462,8 @@ eti_init (GnomeCanvasItem *item) eti->focused_col = -1; eti->focused_row = -1; + eti->editing_col = -1; + eti->editing_row = -1; eti->height = 0; eti->length_threshold = -1; @@ -476,8 +495,12 @@ eti_realize (GnomeCanvasItem *item) 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]); - +#if 0 + /* This sets it to gray */ +/* gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); */ +#else + gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->black); +#endif eti->focus_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]); @@ -560,9 +583,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * Clear the background */ +#if 0 gdk_draw_rectangle ( drawable, eti->fill_gc, TRUE, eti->x1 - x, eti->y1 - y, eti->width, eti->height); +#endif /* * First column to draw, last column to draw @@ -597,8 +622,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_row = -1; y_offset = 0; - y1 = y2 = eti->y1; - for (row = eti->top_item; row < rows; row++, y1 = y2){ + y1 = y2 = eti->y1 + 1; + for (row = 0; row < rows; row++, y1 = y2){ y2 += eti_row_height (eti, row) + 1; @@ -624,6 +649,14 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, yd = y_offset; f_x1 = f_x2 = f_y1 = f_y2 = -1; f_found = FALSE; + + if (eti->draw_grid && first_row == 0){ + gdk_draw_line ( + drawable, eti->grid_gc, + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + } + yd++; + for (row = first_row; row < last_row; row++){ int xd, height; gboolean selected; @@ -650,25 +683,30 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, xd += ecol->width; } - yd += height + 1; + yd += height; if (eti->draw_grid) gdk_draw_line ( drawable, eti->grid_gc, - eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + yd++; } if (eti->draw_grid){ int xd = x_offset; - for (col = first_col; col < last_col; col++){ + for (col = first_col; col <= last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); gdk_draw_line ( drawable, eti->grid_gc, - xd, y_offset, xd, yd); + xd, y_offset, xd, yd - 1); - xd += ecol->width; + /* + * This looks wierd, but it is to draw the last line + */ + if (ecol) + xd += ecol->width; } } @@ -676,9 +714,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw focus */ if (f_found && eti->draw_focus){ - gdk_draw_rectangle ( - drawable, eti->focus_gc, FALSE, - f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); + + if (!eti_editing (eti)) + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); } } @@ -692,14 +732,14 @@ eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, } static gboolean -find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) +find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res, gdouble *x1_res, gdouble *y1_res) { const int cols = eti->cols; const int rows = eti->rows; gdouble x1, y1, x2, y2; int col, row; - /* FIXME: inneficient, fix later */ + /* FIXME: this routine is inneficient, fix later */ x -= eti->x1; y -= eti->y1; @@ -717,6 +757,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *col_res = col; + if (x1_res) + *x1_res = x - x1; break; } @@ -731,6 +773,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *row_res = row; + if (y1_res) + *y1_res = y - y1; break; } @@ -748,63 +792,113 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_BUTTON_RELEASE: case GDK_2BUTTON_PRESS: { int col, row; + gdouble x1, y1; - if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; + /* + * Adjust the event positions + */ + e->button.x = x1; + e->button.y = y1; + e_cell_event (ecell_view, e, col, row); } else { /* * Focus the cell, and select the row */ + e_table_item_leave_edit (eti); e_table_item_focus (eti, col, row); e_table_item_select_row (eti, row); } break; } + + case GDK_MOTION_NOTIFY: { + int col, row; + double x1, y1; + + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) + return TRUE; + + if (eti->focused_row == row && eti->focused_col == col){ + ecell_view = eti->cell_views [col]; + + /* + * Adjust the event positions + */ + e->button.x -= (x1 + eti->x1); + e->button.y -= (y1 + eti->y1); + + e_cell_event (ecell_view, e, col, row); + } + break; + } case GDK_KEY_PRESS: - printf ("KEYPRESS!\n"); - if (eti->focused_col == -1) return FALSE; switch (e->key.keyval){ case GDK_Left: - if (eti->focused_col > 0) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if (eti->focused_col > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); - break; + } + return TRUE; case GDK_Right: - if ((eti->focused_col + 1) < eti->cols) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if ((eti->focused_col + 1) < eti->cols){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); - break; + } + return TRUE; case GDK_Up: - if (eti->focused_row > 0) + if (eti->focused_row > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); - break; + } + return TRUE; case GDK_Down: - if ((eti->focused_row + 1) < eti->rows) + if ((eti->focused_row + 1) < eti->rows){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); - break; - + } + return TRUE; default: + if (!eti_editing (eti)){ + if ((e->key.state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)) != 0) + return 0; + + if (!(e->key.keyval >= 0x20 && e->key.keyval <= 0xff)) + return 0; + } } + 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); + if (eti_editing (eti)){ + ecell_view = eti->cell_views [eti->editing_col]; + e_cell_event (ecell_view, e, eti->editing_col, eti->editing_row); + } break; default: @@ -860,6 +954,8 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); + gtk_object_add_arg_type ("ETableItem::spreadsheet", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_MODE_SPREADSHEET); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -1044,6 +1140,9 @@ e_table_item_leave_edit (ETableItem *eti) g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (!eti_editing (eti)) + return; + 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; diff --git a/widgets/e-table-item.h b/widgets/e-table-item.h index 3f3d2a7d4d..6c4d837310 100644 --- a/widgets/e-table-item.h +++ b/widgets/e-table-item.h @@ -19,7 +19,6 @@ typedef struct { int x1, y1; int width, height; - int top_item; int cols, rows; /* @@ -36,6 +35,7 @@ typedef struct { unsigned int draw_grid:1; unsigned int draw_focus:1; + unsigned int mode_spreadsheet:1; int focused_col, focused_row; diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog index 7972994a79..fbb2ed0a86 100644 --- a/widgets/e-table/ChangeLog +++ b/widgets/e-table/ChangeLog @@ -1,3 +1,26 @@ +1999-11-29 Miguel de Icaza + + * e-cell-toggle.c, e-cell-toggle.h: New file. Implement a + multi-state image toggle cell object. + + * e-cell-text.c (ect_leave_edit): Handle the case of us calling + leave edit manually. + (ect_stop_editing): Leave manually editing here. + (ect_draw): Add one pixel to the border for left and right; + Handle off-screen cursor (must be improved). + (ect_edit_select_all): New function. + (ect_event): Select all text on editing start + + * e-table-item.c (eti_event): Map mouse events and dispatch them. + (eti_event): Add spreadsheet mode for editing; Enter editing only + with visual characters; + Leave editing mode when a different row has been selected. + (eti_get_height): Fix the computation for this; Fix logic for the + length_threshold. + + (eti_draw): Add borders on all sides of the box; + Only draw focus if the cell is not being edited. + 1999-11-28 Miguel de Icaza * e-table-item.c (eti_draw): Focus inside, not outside. diff --git a/widgets/e-table/e-cell-checkbox.c b/widgets/e-table/e-cell-checkbox.c new file mode 100644 index 0000000000..db74464d5c --- /dev/null +++ b/widgets/e-table/e-cell-checkbox.c @@ -0,0 +1,185 @@ +/* + * e-cell-checkbox.c: Checkbox cell renderer + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-checkbox.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellCheckboxView; + +static ECellClass *parent_class; + +static void +eccb_queue_redraw (ECellCheckboxView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +eecb_realize (ECell *ecell, void *view) +{ + ECellCheckbox *eccb = E_CELL_CHECKBOX (ecell); + ECellCheckboxView *check_view = g_new0 (ECellCheckboxView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + check_view->cell_view.ecell = ecell; + check_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + check_view->eti = eti; + check_view->canvas = canvas; + + return (ECellView *) check_view; +} + +/* + * ECell::unrealize method + */ +static void +eecb_unrealize (ECellView *ecv) +{ + ECellCheckboxView *check_view = (ECellCheckboxView *) ecv; + + gdk_gc_unref (check_view->gc); + text_view->gc = NULL; + + g_free (check_view); +} + +/* + * ECell::draw method + */ +static void +eecb_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ +} + +/* + * ECell::event method + */ +static gint +eecb_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellCheckboxView *text_view = (ECellCheckboxView *) ecell_view; + + switch (event->type){ + case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); + 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: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + eecb_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit){ + e_table_item_enter_edit (text_view->eti, col, row); + eecb_edit_seleecb_all (text_view); + } + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + eecb_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: + break; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +eecb_height (ECellView *ecell_view, int col, int row) +{ + return 10; +} + +/* + * ECellView::enter_edit method + */ +static void * +eecb_enter_edit (ECellView *ecell_view, int col, int row) +{ +} + +/* + * ECellView::leave_edit method + */ +static void +eecb_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ +} + +static void +e_cell_checkbox_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + ecc->realize = eecb_realize; + ecc->unrealize = eecb_unrealize; + ecc->draw = eecb_draw; + ecc->event = eecb_event; + ecc->height = eecb_height; + ecc->enter_edit = eecb_enter_edit; + ecc->leave_edit = eecb_leave_edit; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellCheckbox", ECellCheckbox, e_cell_checkbox_class_init, NULL, PARENT_TYPE); + +ECell * +e_cell_checkbox_new (ETableModel *etm) +{ + ECellCheckbox *eccb = gtk_type_new (e_cell_checkbox_get_type ()); + + E_CELL (eccb)->table_model = etm; + + return (ECell *) eccb; +} diff --git a/widgets/e-table/e-cell-checkbox.h b/widgets/e-table/e-cell-checkbox.h new file mode 100644 index 0000000000..6c85fbff21 --- /dev/null +++ b/widgets/e-table/e-cell-checkbox.h @@ -0,0 +1,25 @@ +#ifndef _E_CELL_CHECKBOX_H_ +#define _E_CELL_CHECKBOX_H_ + +#include +#include "e-cell.h" + +#define E_CELL_CHECKBOX_TYPE (e_cell_checkbox_get_type ()) +#define E_CELL_CHECKBOX(o) (GTK_CHECK_CAST ((o), E_CELL_CHECKBOX_TYPE, ECellCheckbox)) +#define E_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_CHECKBOX_TYPE, ECellCheckboxClass)) +#define E_IS_CELL_CHECKBOX(o) (GTK_CHECK_TYPE ((o), E_CELL_CHECKBOX_TYPE)) +#define E_IS_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_CHECKBOX_TYPE)) + +typedef struct { + ECell parent; +} ECellCheckbox; + +typedef struct { + ECellClass parent_class; +} ECellCheckboxClass; + +GtkType e_cell_checkbox_get_type (void); +ECell *e_cell_checkbox_new (ETableModel *model); + +#endif /* _E_CELL_CHECKBOX_H_ */ + diff --git a/widgets/e-table/e-cell-text.c b/widgets/e-table/e-cell-text.c index f0501ab4cb..b18c179ca5 100644 --- a/widgets/e-table/e-cell-text.c +++ b/widgets/e-table/e-cell-text.c @@ -82,6 +82,8 @@ ect_stop_editing (ECellTextView *text_view) g_free (edit); text_view->edit = NULL; + + e_table_item_leave_edit (text_view->eti); } /* @@ -166,8 +168,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, 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; } @@ -191,11 +191,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, text_wc [text_wc_len] = 0; - /* - * Find a good spot for painting - */ - xoff = 0; - /* * Paint */ @@ -208,11 +203,23 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, GdkGC *gc = text_view->gc; const int y = y2 - font->descent - ((y2-y1-height)/2); int px, i; + + /* + * Border + */ + x1 += 2; + x2--; px = x1; - printf ("Cursor at: %d\n", cursor_pos); - + /* + * If the cursor is outside the visible range + * + * FIXME: we really want a better behaviour. + */ + if ((px + left_len) > x2) + px -= left_len - (x2-x1); + for (i = 0; *text_wc; text_wc++, i++){ gdk_draw_text_wc ( drawable, font, gc, px, y, text_wc, 1); @@ -240,6 +247,12 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, */ GdkColor *background, *foreground; int width; + + /* + * Border + */ + x1++; + x2--; /* * Compute draw mode @@ -284,6 +297,17 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, } } +/* + * Selects the entire string + */ +static void +ect_edit_select_all (ECellTextView *text_view) +{ + g_assert (text_view->edit); + + gtk_editable_select_region (GTK_EDITABLE (text_view->edit->entry), 0, -1); +} + /* * ECell::event method */ @@ -294,6 +318,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); if (text_view->edit){ printf ("FIXME: Should handle click here\n"); } else @@ -301,6 +331,11 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) break; case GDK_BUTTON_RELEASE: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); return TRUE; case GDK_KEY_PRESS: @@ -309,8 +344,10 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) return TRUE; } - if (!text_view->edit) + if (!text_view->edit){ e_table_item_enter_edit (text_view->eti, col, row); + ect_edit_select_all (text_view); + } gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); ect_queue_redraw (text_view, col, row); @@ -355,10 +392,11 @@ ect_enter_edit (ECellView *ecell_view, int col, int row) 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->col = col; + edit->row = row; edit->entry = (GtkEntry *) gtk_entry_new (); gtk_entry_set_text (edit->entry, str); @@ -387,10 +425,14 @@ 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); + if (text_view->edit){ + ect_accept_edits (text_view); + ect_stop_editing (text_view); + } else { + /* + * We did invoke this leave edit internally + */ + } } /* diff --git a/widgets/e-table/e-cell-toggle.c b/widgets/e-table/e-cell-toggle.c new file mode 100644 index 0000000000..33e4d283ee --- /dev/null +++ b/widgets/e-table/e-cell-toggle.c @@ -0,0 +1,204 @@ +/* + * e-cell-toggle.c: Multi-state image toggle cell object. + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-toggle.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +Typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellToggleView; + +static ECellClass *parent_class; + +static void +etog_queue_redraw (ECellToggleView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +etog_realize (ECell *ecell, void *view) +{ + ECellToggle *eccb = E_CELL_TOGGLE (ecell); + ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + toggle_view->cell_view.ecell = ecell; + toggle_view->eti = eti; + toggle_view->canvas = canvas; + + return (ECellView *) toggle_view; +} + +/* + * ECell::unrealize method + */ +static void +etog_unrealize (ECellView *ecv) +{ + ECellToggleView *toggle_view = (ECellToggleView *) ecv; + + g_free (toggle_view); +} + +/* + * ECell::draw method + */ +static void +etog_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + GdkPixbuf *image; + const int value = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + + if (value >= toggle->n_states){ + g_warning ("Value from the table model is %d, the states we support are [0..%d)\n", + value, toggle->n_states); + return; + } + + image = toggle->images [value]; + +} + +static void +etog_set_value (ECellToggleView *toggle_view, int col, int row, int value) +{ + ECell *ecell = toggle_view->cell_view.ecell + ECellToggle *toggle = E_CELL_TOGGLE (ecell); + + if (value >= toggle->n_vals) + value = 0; + + e_table_model_set_value_at (ecell->table_model, col, row, value); + etog_queue_redraw (toggle_view, col, row); +} + +/* + * ECell::event method + */ +static gint +etog_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + int value = e_table_model_value_at (e_cell_view->ecell->table_model, col, row); + + switch (event->type){ + case GDK_BUTTON_RELEASE: + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_space){ + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + } + return FALSE; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +etog_height (ECellView *ecell_view, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + + return toggle->height; +} + +static void +etog_destroy (GtkObject *object) +{ + ECellToggle *etog = E_CELL_TOGGLE (object); + int i; + + for (i = 0; i < etog->n_states; i++) + gdk_pixbuf_unref (etog->images [i]); + + g_free (etog->images); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +e_cell_toggle_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + object_class->destroy = etog_destroy; + + ecc->realize = etog_realize; + ecc->unrealize = etog_unrealize; + ecc->draw = etog_draw; + ecc->event = etog_event; + ecc->height = etog_height; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellToggle", ECellToggle, e_cell_toggle_class_init, NULL, PARENT_TYPE); + +void +e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + int max_height = 0; + + E_CELL (etog)->table_model = etm; + + etog->border = border; + etog->n_states = n_states; + + etog->images = g_new (GdkPixbuf *, n_states); + + for (i = 0; i < n_states; i++){ + etog->images [i] = images [i]; + gdk_pixbuf_ref (images [i]); + + if (images [i]->art_pixbuf->height > max_height) + max_height = images [i]->art_pixbuf->height; + } + + etog->height = max_height; +} + +ECell * +e_cell_toggle_new (ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + ECellToggle *etog = gtk_type_new (e_cell_toggle_get_type ()); + + e_cell_toggle_construct (etog, etm, border, n_states, images); + + return (ECell *) etog; +} diff --git a/widgets/e-table/e-cell-toggle.h b/widgets/e-table/e-cell-toggle.h new file mode 100644 index 0000000000..3cd99f5d04 --- /dev/null +++ b/widgets/e-table/e-cell-toggle.h @@ -0,0 +1,37 @@ +#ifndef _E_CELL_TOGGLE_H_ +#define _E_CELL_TOGGLE_H_ + +#include +#include +#include "e-cell.h" + +#define E_CELL_TOGGLE_TYPE (e_cell_toggle_get_type ()) +#define E_CELL_TOGGLE(o) (GTK_CHECK_CAST ((o), E_CELL_TOGGLE_TYPE, ECellToggle)) +#define E_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TOGGLE_TYPE, ECellToggleClass)) +#define E_IS_CELL_TOGGLE(o) (GTK_CHECK_TYPE ((o), E_CELL_TOGGLE_TYPE)) +#define E_IS_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TOGGLE_TYPE)) + +typedef struct { + ECell parent; + + int border; + int n_states; + GdkPixbuf **images; + + int height; +} ECellToggle; + +typedef struct { + ECellClass parent_class; +} ECellToggleClass; + +GtkType e_cell_toggle_get_type (void); +ECell *e_cell_toggle_new (ETableModel *model, int border, + int n_states, + GdkPibux **images); +void e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, + int border, int n_states, GdkPixbuf **images); + +#endif /* _E_CELL_TOGGLE_H_ */ + + diff --git a/widgets/e-table/e-table-item.c b/widgets/e-table/e-table-item.c index 5816acfb23..ceb6adda95 100644 --- a/widgets/e-table/e-table-item.c +++ b/widgets/e-table/e-table-item.c @@ -38,9 +38,19 @@ enum { ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, + ARG_MODE_SPREADSHEET, ARG_LENGHT_THRESHOLD }; +static gboolean +eti_editing (ETableItem *eti) +{ + if (eti->editing_col == -1) + return FALSE; + else + return TRUE; +} + /* * During realization, we have to invoke the per-ecell realize routine * (On our current setup, we have one e-cell per column. @@ -186,23 +196,26 @@ eti_get_height (ETableItem *eti) { const int rows = eti->rows; int row; - int height = 0; + int height; if (rows == 0) return 0; - - if (rows > eti->length_threshold){ - height = eti_row_height (eti, 0) * rows; - return height; + if (eti->length_threshold != -1){ + if (rows > eti->length_threshold){ + height = (eti_row_height (eti, 0) + 1) * rows; + + /* + * 1 pixel at the top + */ + return height + 1; + } } - + + height = 1; for (row = 0; row < rows; row++) - height += eti_row_height (eti, row); + height += eti_row_height (eti, row) + 1; - /* Add division lines pixels */ - height += rows; - return height; } @@ -434,6 +447,10 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_FOCUS: eti->draw_focus = GTK_VALUE_BOOL (*arg); break; + + case ARG_MODE_SPREADSHEET: + eti->mode_spreadsheet = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -445,6 +462,8 @@ eti_init (GnomeCanvasItem *item) eti->focused_col = -1; eti->focused_row = -1; + eti->editing_col = -1; + eti->editing_row = -1; eti->height = 0; eti->length_threshold = -1; @@ -476,8 +495,12 @@ eti_realize (GnomeCanvasItem *item) 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]); - +#if 0 + /* This sets it to gray */ +/* gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); */ +#else + gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->black); +#endif eti->focus_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]); @@ -560,9 +583,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * Clear the background */ +#if 0 gdk_draw_rectangle ( drawable, eti->fill_gc, TRUE, eti->x1 - x, eti->y1 - y, eti->width, eti->height); +#endif /* * First column to draw, last column to draw @@ -597,8 +622,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_row = -1; y_offset = 0; - y1 = y2 = eti->y1; - for (row = eti->top_item; row < rows; row++, y1 = y2){ + y1 = y2 = eti->y1 + 1; + for (row = 0; row < rows; row++, y1 = y2){ y2 += eti_row_height (eti, row) + 1; @@ -624,6 +649,14 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, yd = y_offset; f_x1 = f_x2 = f_y1 = f_y2 = -1; f_found = FALSE; + + if (eti->draw_grid && first_row == 0){ + gdk_draw_line ( + drawable, eti->grid_gc, + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + } + yd++; + for (row = first_row; row < last_row; row++){ int xd, height; gboolean selected; @@ -650,25 +683,30 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, xd += ecol->width; } - yd += height + 1; + yd += height; if (eti->draw_grid) gdk_draw_line ( drawable, eti->grid_gc, - eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + yd++; } if (eti->draw_grid){ int xd = x_offset; - for (col = first_col; col < last_col; col++){ + for (col = first_col; col <= last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); gdk_draw_line ( drawable, eti->grid_gc, - xd, y_offset, xd, yd); + xd, y_offset, xd, yd - 1); - xd += ecol->width; + /* + * This looks wierd, but it is to draw the last line + */ + if (ecol) + xd += ecol->width; } } @@ -676,9 +714,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw focus */ if (f_found && eti->draw_focus){ - gdk_draw_rectangle ( - drawable, eti->focus_gc, FALSE, - f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); + + if (!eti_editing (eti)) + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); } } @@ -692,14 +732,14 @@ eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, } static gboolean -find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) +find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res, gdouble *x1_res, gdouble *y1_res) { const int cols = eti->cols; const int rows = eti->rows; gdouble x1, y1, x2, y2; int col, row; - /* FIXME: inneficient, fix later */ + /* FIXME: this routine is inneficient, fix later */ x -= eti->x1; y -= eti->y1; @@ -717,6 +757,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *col_res = col; + if (x1_res) + *x1_res = x - x1; break; } @@ -731,6 +773,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *row_res = row; + if (y1_res) + *y1_res = y - y1; break; } @@ -748,63 +792,113 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_BUTTON_RELEASE: case GDK_2BUTTON_PRESS: { int col, row; + gdouble x1, y1; - if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; + /* + * Adjust the event positions + */ + e->button.x = x1; + e->button.y = y1; + e_cell_event (ecell_view, e, col, row); } else { /* * Focus the cell, and select the row */ + e_table_item_leave_edit (eti); e_table_item_focus (eti, col, row); e_table_item_select_row (eti, row); } break; } + + case GDK_MOTION_NOTIFY: { + int col, row; + double x1, y1; + + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) + return TRUE; + + if (eti->focused_row == row && eti->focused_col == col){ + ecell_view = eti->cell_views [col]; + + /* + * Adjust the event positions + */ + e->button.x -= (x1 + eti->x1); + e->button.y -= (y1 + eti->y1); + + e_cell_event (ecell_view, e, col, row); + } + break; + } case GDK_KEY_PRESS: - printf ("KEYPRESS!\n"); - if (eti->focused_col == -1) return FALSE; switch (e->key.keyval){ case GDK_Left: - if (eti->focused_col > 0) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if (eti->focused_col > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); - break; + } + return TRUE; case GDK_Right: - if ((eti->focused_col + 1) < eti->cols) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if ((eti->focused_col + 1) < eti->cols){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); - break; + } + return TRUE; case GDK_Up: - if (eti->focused_row > 0) + if (eti->focused_row > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); - break; + } + return TRUE; case GDK_Down: - if ((eti->focused_row + 1) < eti->rows) + if ((eti->focused_row + 1) < eti->rows){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); - break; - + } + return TRUE; default: + if (!eti_editing (eti)){ + if ((e->key.state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)) != 0) + return 0; + + if (!(e->key.keyval >= 0x20 && e->key.keyval <= 0xff)) + return 0; + } } + 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); + if (eti_editing (eti)){ + ecell_view = eti->cell_views [eti->editing_col]; + e_cell_event (ecell_view, e, eti->editing_col, eti->editing_row); + } break; default: @@ -860,6 +954,8 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); + gtk_object_add_arg_type ("ETableItem::spreadsheet", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_MODE_SPREADSHEET); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -1044,6 +1140,9 @@ e_table_item_leave_edit (ETableItem *eti) g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (!eti_editing (eti)) + return; + 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; diff --git a/widgets/e-table/e-table-item.h b/widgets/e-table/e-table-item.h index 3f3d2a7d4d..6c4d837310 100644 --- a/widgets/e-table/e-table-item.h +++ b/widgets/e-table/e-table-item.h @@ -19,7 +19,6 @@ typedef struct { int x1, y1; int width, height; - int top_item; int cols, rows; /* @@ -36,6 +35,7 @@ typedef struct { unsigned int draw_grid:1; unsigned int draw_focus:1; + unsigned int mode_spreadsheet:1; int focused_col, focused_row; diff --git a/widgets/e-table/table-test.c b/widgets/e-table/table-test.c index f677e9e2d1..4ff03016b4 100644 --- a/widgets/e-table/table-test.c +++ b/widgets/e-table/table-test.c @@ -237,6 +237,7 @@ main (int argc, char *argv []) "y", 30, "drawgrid", TRUE, "drawfocus", TRUE, + "spreadsheet", TRUE, NULL); gtk_main (); diff --git a/widgets/table-test.c b/widgets/table-test.c index f677e9e2d1..4ff03016b4 100644 --- a/widgets/table-test.c +++ b/widgets/table-test.c @@ -237,6 +237,7 @@ main (int argc, char *argv []) "y", 30, "drawgrid", TRUE, "drawfocus", TRUE, + "spreadsheet", TRUE, NULL); gtk_main (); diff --git a/widgets/table/e-cell-checkbox.c b/widgets/table/e-cell-checkbox.c new file mode 100644 index 0000000000..db74464d5c --- /dev/null +++ b/widgets/table/e-cell-checkbox.c @@ -0,0 +1,185 @@ +/* + * e-cell-checkbox.c: Checkbox cell renderer + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-checkbox.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellCheckboxView; + +static ECellClass *parent_class; + +static void +eccb_queue_redraw (ECellCheckboxView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +eecb_realize (ECell *ecell, void *view) +{ + ECellCheckbox *eccb = E_CELL_CHECKBOX (ecell); + ECellCheckboxView *check_view = g_new0 (ECellCheckboxView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + check_view->cell_view.ecell = ecell; + check_view->gc = gdk_gc_new (GTK_WIDGET (canvas)->window); + check_view->eti = eti; + check_view->canvas = canvas; + + return (ECellView *) check_view; +} + +/* + * ECell::unrealize method + */ +static void +eecb_unrealize (ECellView *ecv) +{ + ECellCheckboxView *check_view = (ECellCheckboxView *) ecv; + + gdk_gc_unref (check_view->gc); + text_view->gc = NULL; + + g_free (check_view); +} + +/* + * ECell::draw method + */ +static void +eecb_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ +} + +/* + * ECell::event method + */ +static gint +eecb_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellCheckboxView *text_view = (ECellCheckboxView *) ecell_view; + + switch (event->type){ + case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); + 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: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Escape){ + eecb_cancel_edit (text_view); + return TRUE; + } + + if (!text_view->edit){ + e_table_item_enter_edit (text_view->eti, col, row); + eecb_edit_seleecb_all (text_view); + } + + gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); + eecb_queue_redraw (text_view, col, row); + break; + + case GDK_KEY_RELEASE: + break; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +eecb_height (ECellView *ecell_view, int col, int row) +{ + return 10; +} + +/* + * ECellView::enter_edit method + */ +static void * +eecb_enter_edit (ECellView *ecell_view, int col, int row) +{ +} + +/* + * ECellView::leave_edit method + */ +static void +eecb_leave_edit (ECellView *ecell_view, int col, int row, void *edit_context) +{ +} + +static void +e_cell_checkbox_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + ecc->realize = eecb_realize; + ecc->unrealize = eecb_unrealize; + ecc->draw = eecb_draw; + ecc->event = eecb_event; + ecc->height = eecb_height; + ecc->enter_edit = eecb_enter_edit; + ecc->leave_edit = eecb_leave_edit; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellCheckbox", ECellCheckbox, e_cell_checkbox_class_init, NULL, PARENT_TYPE); + +ECell * +e_cell_checkbox_new (ETableModel *etm) +{ + ECellCheckbox *eccb = gtk_type_new (e_cell_checkbox_get_type ()); + + E_CELL (eccb)->table_model = etm; + + return (ECell *) eccb; +} diff --git a/widgets/table/e-cell-checkbox.h b/widgets/table/e-cell-checkbox.h new file mode 100644 index 0000000000..6c85fbff21 --- /dev/null +++ b/widgets/table/e-cell-checkbox.h @@ -0,0 +1,25 @@ +#ifndef _E_CELL_CHECKBOX_H_ +#define _E_CELL_CHECKBOX_H_ + +#include +#include "e-cell.h" + +#define E_CELL_CHECKBOX_TYPE (e_cell_checkbox_get_type ()) +#define E_CELL_CHECKBOX(o) (GTK_CHECK_CAST ((o), E_CELL_CHECKBOX_TYPE, ECellCheckbox)) +#define E_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_CHECKBOX_TYPE, ECellCheckboxClass)) +#define E_IS_CELL_CHECKBOX(o) (GTK_CHECK_TYPE ((o), E_CELL_CHECKBOX_TYPE)) +#define E_IS_CELL_CHECKBOX_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_CHECKBOX_TYPE)) + +typedef struct { + ECell parent; +} ECellCheckbox; + +typedef struct { + ECellClass parent_class; +} ECellCheckboxClass; + +GtkType e_cell_checkbox_get_type (void); +ECell *e_cell_checkbox_new (ETableModel *model); + +#endif /* _E_CELL_CHECKBOX_H_ */ + diff --git a/widgets/table/e-cell-text.c b/widgets/table/e-cell-text.c index f0501ab4cb..b18c179ca5 100644 --- a/widgets/table/e-cell-text.c +++ b/widgets/table/e-cell-text.c @@ -82,6 +82,8 @@ ect_stop_editing (ECellTextView *text_view) g_free (edit); text_view->edit = NULL; + + e_table_item_leave_edit (text_view->eti); } /* @@ -166,8 +168,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, 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; } @@ -191,11 +191,6 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, text_wc [text_wc_len] = 0; - /* - * Find a good spot for painting - */ - xoff = 0; - /* * Paint */ @@ -208,11 +203,23 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, GdkGC *gc = text_view->gc; const int y = y2 - font->descent - ((y2-y1-height)/2); int px, i; + + /* + * Border + */ + x1 += 2; + x2--; px = x1; - printf ("Cursor at: %d\n", cursor_pos); - + /* + * If the cursor is outside the visible range + * + * FIXME: we really want a better behaviour. + */ + if ((px + left_len) > x2) + px -= left_len - (x2-x1); + for (i = 0; *text_wc; text_wc++, i++){ gdk_draw_text_wc ( drawable, font, gc, px, y, text_wc, 1); @@ -240,6 +247,12 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, */ GdkColor *background, *foreground; int width; + + /* + * Border + */ + x1++; + x2--; /* * Compute draw mode @@ -284,6 +297,17 @@ ect_draw (ECellView *ecell_view, GdkDrawable *drawable, } } +/* + * Selects the entire string + */ +static void +ect_edit_select_all (ECellTextView *text_view) +{ + g_assert (text_view->edit); + + gtk_editable_select_region (GTK_EDITABLE (text_view->edit->entry), 0, -1); +} + /* * ECell::event method */ @@ -294,6 +318,12 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) switch (event->type){ case GDK_BUTTON_PRESS: + /* + * Adjust for the border we use + */ + event->button.x++; + + printf ("Button pressed at %g %g\n", event->button.x, event->button.y); if (text_view->edit){ printf ("FIXME: Should handle click here\n"); } else @@ -301,6 +331,11 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) break; case GDK_BUTTON_RELEASE: + /* + * Adjust for the border we use + */ + event->button.x++; + printf ("Button released at %g %g\n", event->button.x, event->button.y); return TRUE; case GDK_KEY_PRESS: @@ -309,8 +344,10 @@ ect_event (ECellView *ecell_view, GdkEvent *event, int col, int row) return TRUE; } - if (!text_view->edit) + if (!text_view->edit){ e_table_item_enter_edit (text_view->eti, col, row); + ect_edit_select_all (text_view); + } gtk_widget_event (GTK_WIDGET (text_view->edit->entry), event); ect_queue_redraw (text_view, col, row); @@ -355,10 +392,11 @@ ect_enter_edit (ECellView *ecell_view, int col, int row) 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->col = col; + edit->row = row; edit->entry = (GtkEntry *) gtk_entry_new (); gtk_entry_set_text (edit->entry, str); @@ -387,10 +425,14 @@ 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); + if (text_view->edit){ + ect_accept_edits (text_view); + ect_stop_editing (text_view); + } else { + /* + * We did invoke this leave edit internally + */ + } } /* diff --git a/widgets/table/e-cell-toggle.c b/widgets/table/e-cell-toggle.c new file mode 100644 index 0000000000..33e4d283ee --- /dev/null +++ b/widgets/table/e-cell-toggle.c @@ -0,0 +1,204 @@ +/* + * e-cell-toggle.c: Multi-state image toggle cell object. + * + * Author: + * Miguel de Icaza (miguel@kernel.org) + * + * (C) 1999 Helix Code, Inc + */ +#include +#include +#include +#include +#include +#include +#include +#include "e-cell-toggle.h" +#include "e-util.h" +#include "e-table-item.h" + +#define PARENT_TYPE e_cell_get_type() + +Typedef struct { + ECellView cell_view; + GdkGC *gc; + GnomeCanvas *canvas; + ETableItem *eti; +} ECellToggleView; + +static ECellClass *parent_class; + +static void +etog_queue_redraw (ECellToggleView *text_view, int col, int row) +{ + e_table_item_redraw_range (text_view->eti, col, row, col, row); +} + +/* + * ECell::realize method + */ +static ECellView * +etog_realize (ECell *ecell, void *view) +{ + ECellToggle *eccb = E_CELL_TOGGLE (ecell); + ECellToggleView *toggle_view = g_new0 (ECellToggleView, 1); + ETableItem *eti = E_TABLE_ITEM (view); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (eti)->canvas; + + toggle_view->cell_view.ecell = ecell; + toggle_view->eti = eti; + toggle_view->canvas = canvas; + + return (ECellView *) toggle_view; +} + +/* + * ECell::unrealize method + */ +static void +etog_unrealize (ECellView *ecv) +{ + ECellToggleView *toggle_view = (ECellToggleView *) ecv; + + g_free (toggle_view); +} + +/* + * ECell::draw method + */ +static void +etog_draw (ECellView *ecell_view, GdkDrawable *drawable, + int col, int row, gboolean selected, + int x1, int y1, int x2, int y2) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + GdkPixbuf *image; + const int value = e_table_model_value_at (ecell_view->ecell->table_model, col, row); + + if (value >= toggle->n_states){ + g_warning ("Value from the table model is %d, the states we support are [0..%d)\n", + value, toggle->n_states); + return; + } + + image = toggle->images [value]; + +} + +static void +etog_set_value (ECellToggleView *toggle_view, int col, int row, int value) +{ + ECell *ecell = toggle_view->cell_view.ecell + ECellToggle *toggle = E_CELL_TOGGLE (ecell); + + if (value >= toggle->n_vals) + value = 0; + + e_table_model_set_value_at (ecell->table_model, col, row, value); + etog_queue_redraw (toggle_view, col, row); +} + +/* + * ECell::event method + */ +static gint +etog_event (ECellView *ecell_view, GdkEvent *event, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + ECellToggleView *toggle_view = (ECellToggleView *) ecell_view; + int value = e_table_model_value_at (e_cell_view->ecell->table_model, col, row); + + switch (event->type){ + case GDK_BUTTON_RELEASE: + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + + case GDK_KEY_PRESS: + if (event->key.keyval == GDK_space){ + etog_set_value (toggle_view, col, row, value + 1); + return TRUE; + } + return FALSE; + + default: + return FALSE; + } + return TRUE; +} + +/* + * ECell::height method + */ +static int +etog_height (ECellView *ecell_view, int col, int row) +{ + ECellToggle *toggle = E_CELL_TOGGLE (e_cell_view->ecell); + + return toggle->height; +} + +static void +etog_destroy (GtkObject *object) +{ + ECellToggle *etog = E_CELL_TOGGLE (object); + int i; + + for (i = 0; i < etog->n_states; i++) + gdk_pixbuf_unref (etog->images [i]); + + g_free (etog->images); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); +} + +static void +e_cell_toggle_class_init (GtkObjectClass *object_class) +{ + ECellClass *ecc = (ECellClass *) object_class; + + object_class->destroy = etog_destroy; + + ecc->realize = etog_realize; + ecc->unrealize = etog_unrealize; + ecc->draw = etog_draw; + ecc->event = etog_event; + ecc->height = etog_height; + + parent_class = gtk_type_class (PARENT_TYPE); +} + +E_MAKE_TYPE(e_cell_text, "ECellToggle", ECellToggle, e_cell_toggle_class_init, NULL, PARENT_TYPE); + +void +e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + int max_height = 0; + + E_CELL (etog)->table_model = etm; + + etog->border = border; + etog->n_states = n_states; + + etog->images = g_new (GdkPixbuf *, n_states); + + for (i = 0; i < n_states; i++){ + etog->images [i] = images [i]; + gdk_pixbuf_ref (images [i]); + + if (images [i]->art_pixbuf->height > max_height) + max_height = images [i]->art_pixbuf->height; + } + + etog->height = max_height; +} + +ECell * +e_cell_toggle_new (ETableModel *etm, int border, int n_states, GdkPixbuf **images) +{ + ECellToggle *etog = gtk_type_new (e_cell_toggle_get_type ()); + + e_cell_toggle_construct (etog, etm, border, n_states, images); + + return (ECell *) etog; +} diff --git a/widgets/table/e-cell-toggle.h b/widgets/table/e-cell-toggle.h new file mode 100644 index 0000000000..3cd99f5d04 --- /dev/null +++ b/widgets/table/e-cell-toggle.h @@ -0,0 +1,37 @@ +#ifndef _E_CELL_TOGGLE_H_ +#define _E_CELL_TOGGLE_H_ + +#include +#include +#include "e-cell.h" + +#define E_CELL_TOGGLE_TYPE (e_cell_toggle_get_type ()) +#define E_CELL_TOGGLE(o) (GTK_CHECK_CAST ((o), E_CELL_TOGGLE_TYPE, ECellToggle)) +#define E_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_TOGGLE_TYPE, ECellToggleClass)) +#define E_IS_CELL_TOGGLE(o) (GTK_CHECK_TYPE ((o), E_CELL_TOGGLE_TYPE)) +#define E_IS_CELL_TOGGLE_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_TOGGLE_TYPE)) + +typedef struct { + ECell parent; + + int border; + int n_states; + GdkPixbuf **images; + + int height; +} ECellToggle; + +typedef struct { + ECellClass parent_class; +} ECellToggleClass; + +GtkType e_cell_toggle_get_type (void); +ECell *e_cell_toggle_new (ETableModel *model, int border, + int n_states, + GdkPibux **images); +void e_cell_toggle_construct (ECellToggle *etog, ETableModel *etm, + int border, int n_states, GdkPixbuf **images); + +#endif /* _E_CELL_TOGGLE_H_ */ + + diff --git a/widgets/table/e-table-item.c b/widgets/table/e-table-item.c index 5816acfb23..ceb6adda95 100644 --- a/widgets/table/e-table-item.c +++ b/widgets/table/e-table-item.c @@ -38,9 +38,19 @@ enum { ARG_TABLE_Y, ARG_TABLE_DRAW_GRID, ARG_TABLE_DRAW_FOCUS, + ARG_MODE_SPREADSHEET, ARG_LENGHT_THRESHOLD }; +static gboolean +eti_editing (ETableItem *eti) +{ + if (eti->editing_col == -1) + return FALSE; + else + return TRUE; +} + /* * During realization, we have to invoke the per-ecell realize routine * (On our current setup, we have one e-cell per column. @@ -186,23 +196,26 @@ eti_get_height (ETableItem *eti) { const int rows = eti->rows; int row; - int height = 0; + int height; if (rows == 0) return 0; - - if (rows > eti->length_threshold){ - height = eti_row_height (eti, 0) * rows; - return height; + if (eti->length_threshold != -1){ + if (rows > eti->length_threshold){ + height = (eti_row_height (eti, 0) + 1) * rows; + + /* + * 1 pixel at the top + */ + return height + 1; + } } - + + height = 1; for (row = 0; row < rows; row++) - height += eti_row_height (eti, row); + height += eti_row_height (eti, row) + 1; - /* Add division lines pixels */ - height += rows; - return height; } @@ -434,6 +447,10 @@ eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) case ARG_TABLE_DRAW_FOCUS: eti->draw_focus = GTK_VALUE_BOOL (*arg); break; + + case ARG_MODE_SPREADSHEET: + eti->mode_spreadsheet = GTK_VALUE_BOOL (*arg); + break; } eti_update (item, NULL, NULL, 0); } @@ -445,6 +462,8 @@ eti_init (GnomeCanvasItem *item) eti->focused_col = -1; eti->focused_row = -1; + eti->editing_col = -1; + eti->editing_row = -1; eti->height = 0; eti->length_threshold = -1; @@ -476,8 +495,12 @@ eti_realize (GnomeCanvasItem *item) 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]); - +#if 0 + /* This sets it to gray */ +/* gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); */ +#else + gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->black); +#endif eti->focus_gc = gdk_gc_new (window); gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]); @@ -560,9 +583,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, /* * Clear the background */ +#if 0 gdk_draw_rectangle ( drawable, eti->fill_gc, TRUE, eti->x1 - x, eti->y1 - y, eti->width, eti->height); +#endif /* * First column to draw, last column to draw @@ -597,8 +622,8 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, */ first_row = -1; y_offset = 0; - y1 = y2 = eti->y1; - for (row = eti->top_item; row < rows; row++, y1 = y2){ + y1 = y2 = eti->y1 + 1; + for (row = 0; row < rows; row++, y1 = y2){ y2 += eti_row_height (eti, row) + 1; @@ -624,6 +649,14 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, yd = y_offset; f_x1 = f_x2 = f_y1 = f_y2 = -1; f_found = FALSE; + + if (eti->draw_grid && first_row == 0){ + gdk_draw_line ( + drawable, eti->grid_gc, + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + } + yd++; + for (row = first_row; row < last_row; row++){ int xd, height; gboolean selected; @@ -650,25 +683,30 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, xd += ecol->width; } - yd += height + 1; + yd += height; if (eti->draw_grid) gdk_draw_line ( drawable, eti->grid_gc, - eti->x1 - x, yd -1, eti->x1 + eti->width - x, yd -1); + eti->x1 - x, yd, eti->x1 + eti->width - x, yd); + yd++; } if (eti->draw_grid){ int xd = x_offset; - for (col = first_col; col < last_col; col++){ + for (col = first_col; col <= last_col; col++){ ETableCol *ecol = e_table_header_get_column (eti->header, col); gdk_draw_line ( drawable, eti->grid_gc, - xd, y_offset, xd, yd); + xd, y_offset, xd, yd - 1); - xd += ecol->width; + /* + * This looks wierd, but it is to draw the last line + */ + if (ecol) + xd += ecol->width; } } @@ -676,9 +714,11 @@ eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, * Draw focus */ if (f_found && eti->draw_focus){ - gdk_draw_rectangle ( - drawable, eti->focus_gc, FALSE, - f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); + + if (!eti_editing (eti)) + gdk_draw_rectangle ( + drawable, eti->focus_gc, FALSE, + f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1); } } @@ -692,14 +732,14 @@ eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, } static gboolean -find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) +find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res, gdouble *x1_res, gdouble *y1_res) { const int cols = eti->cols; const int rows = eti->rows; gdouble x1, y1, x2, y2; int col, row; - /* FIXME: inneficient, fix later */ + /* FIXME: this routine is inneficient, fix later */ x -= eti->x1; y -= eti->y1; @@ -717,6 +757,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *col_res = col; + if (x1_res) + *x1_res = x - x1; break; } @@ -731,6 +773,8 @@ find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res) continue; *row_res = row; + if (y1_res) + *y1_res = y - y1; break; } @@ -748,63 +792,113 @@ eti_event (GnomeCanvasItem *item, GdkEvent *e) case GDK_BUTTON_RELEASE: case GDK_2BUTTON_PRESS: { int col, row; + gdouble x1, y1; - if (!find_cell (eti, e->button.x, e->button.y, &col, &row)) + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) return TRUE; if (eti->focused_row == row && eti->focused_col == col){ ecell_view = eti->cell_views [col]; + /* + * Adjust the event positions + */ + e->button.x = x1; + e->button.y = y1; + e_cell_event (ecell_view, e, col, row); } else { /* * Focus the cell, and select the row */ + e_table_item_leave_edit (eti); e_table_item_focus (eti, col, row); e_table_item_select_row (eti, row); } break; } + + case GDK_MOTION_NOTIFY: { + int col, row; + double x1, y1; + + if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1)) + return TRUE; + + if (eti->focused_row == row && eti->focused_col == col){ + ecell_view = eti->cell_views [col]; + + /* + * Adjust the event positions + */ + e->button.x -= (x1 + eti->x1); + e->button.y -= (y1 + eti->y1); + + e_cell_event (ecell_view, e, col, row); + } + break; + } case GDK_KEY_PRESS: - printf ("KEYPRESS!\n"); - if (eti->focused_col == -1) return FALSE; switch (e->key.keyval){ case GDK_Left: - if (eti->focused_col > 0) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if (eti->focused_col > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col - 1, eti->focused_row); - break; + } + return TRUE; case GDK_Right: - if ((eti->focused_col + 1) < eti->cols) + if (!eti->mode_spreadsheet && eti_editing (eti)) + break; + + if ((eti->focused_col + 1) < eti->cols){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col + 1, eti->focused_row); - break; + } + return TRUE; case GDK_Up: - if (eti->focused_row > 0) + if (eti->focused_row > 0){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row - 1); - break; + } + return TRUE; case GDK_Down: - if ((eti->focused_row + 1) < eti->rows) + if ((eti->focused_row + 1) < eti->rows){ + e_table_item_leave_edit (eti); e_table_item_focus (eti, eti->focused_col, eti->focused_row + 1); - break; - + } + return TRUE; default: + if (!eti_editing (eti)){ + if ((e->key.state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)) != 0) + return 0; + + if (!(e->key.keyval >= 0x20 && e->key.keyval <= 0xff)) + return 0; + } } + 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); + if (eti_editing (eti)){ + ecell_view = eti->cell_views [eti->editing_col]; + e_cell_event (ecell_view, e, eti->editing_col, eti->editing_row); + } break; default: @@ -860,6 +954,8 @@ eti_class_init (GtkObjectClass *object_class) GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID); gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS); + gtk_object_add_arg_type ("ETableItem::spreadsheet", GTK_TYPE_BOOL, + GTK_ARG_WRITABLE, ARG_MODE_SPREADSHEET); eti_signals [ROW_SELECTION] = gtk_signal_new ("row_selection", @@ -1044,6 +1140,9 @@ e_table_item_leave_edit (ETableItem *eti) g_return_if_fail (eti != NULL); g_return_if_fail (E_IS_TABLE_ITEM (eti)); + if (!eti_editing (eti)) + return; + 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; diff --git a/widgets/table/e-table-item.h b/widgets/table/e-table-item.h index 3f3d2a7d4d..6c4d837310 100644 --- a/widgets/table/e-table-item.h +++ b/widgets/table/e-table-item.h @@ -19,7 +19,6 @@ typedef struct { int x1, y1; int width, height; - int top_item; int cols, rows; /* @@ -36,6 +35,7 @@ typedef struct { unsigned int draw_grid:1; unsigned int draw_focus:1; + unsigned int mode_spreadsheet:1; int focused_col, focused_row; diff --git a/widgets/table/table-test.c b/widgets/table/table-test.c index f677e9e2d1..4ff03016b4 100644 --- a/widgets/table/table-test.c +++ b/widgets/table/table-test.c @@ -237,6 +237,7 @@ main (int argc, char *argv []) "y", 30, "drawgrid", TRUE, "drawfocus", TRUE, + "spreadsheet", TRUE, NULL); gtk_main (); -- cgit