aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/e-cell-text.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/e-cell-text.c')
-rw-r--r--widgets/e-cell-text.c361
1 files changed, 303 insertions, 58 deletions
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 <config.h>
#include <gtk/gtkenums.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtksignal.h>
+#include <gdk/gdkkeysyms.h>
+#include <libgnomeui/gnome-canvas.h>
#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);
}