aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lahey <clahey@src.gnome.org>2000-01-11 14:44:57 +0800
committerChris Lahey <clahey@src.gnome.org>2000-01-11 14:44:57 +0800
commita01de808cd46baea31419a42b221cb65974a9fb1 (patch)
treea32c6dc47d19d64c907d7d577798cad380a6caa2
parentb2a25c6add10c40eb6d369fdf504f2e7d13d2c97 (diff)
downloadgsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar.gz
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar.bz2
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar.lz
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar.xz
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.tar.zst
gsoc2013-evolution-a01de808cd46baea31419a42b221cb65974a9fb1.zip
Removed some code which got in the way of testing properly.
* widgets/test-minicard.c: Removed some code which got in the way of testing properly. * widgets/e-minicard-label.c (e_minicard_label_realize): Made the field text item editable. * widgets/Makefile.am: Added e-text-event-process*.[ch]. * widgets/e-text.c, widgets/e-text.h: Changed these to support editing. * widgets/e-text-event-processor.c, widgets/e-text-event-processor.h, widgets/e-text-event-processor-types.h, widgets/e-text-event-processor-emacs-like.c, widgets/e-text-event-processor-emacs-like.h: These are a new pair of classes which handle all events from the text item and convert them into commands. svn path=/trunk/; revision=1553
-rw-r--r--ChangeLog39
-rw-r--r--addressbook/gui/minicard/e-minicard-label.c1
-rw-r--r--addressbook/gui/minicard/test-minicard.c10
-rw-r--r--addressbook/gui/widgets/e-minicard-label.c1
-rw-r--r--addressbook/gui/widgets/test-minicard.c10
-rw-r--r--e-util/e-text-event-processor-emacs-like.c327
-rw-r--r--e-util/e-text-event-processor-emacs-like.h68
-rw-r--r--e-util/e-text-event-processor-types.h131
-rw-r--r--e-util/e-text-event-processor.c103
-rw-r--r--e-util/e-text-event-processor.h74
-rw-r--r--widgets/Makefile.am6
-rw-r--r--widgets/e-minicard-label.c1
-rw-r--r--widgets/e-minicard/e-minicard-label.c1
-rw-r--r--widgets/e-minicard/test-minicard.c10
-rw-r--r--widgets/e-text-event-processor-emacs-like.c327
-rw-r--r--widgets/e-text-event-processor-emacs-like.h68
-rw-r--r--widgets/e-text-event-processor-types.h131
-rw-r--r--widgets/e-text-event-processor.c103
-rw-r--r--widgets/e-text-event-processor.h74
-rw-r--r--widgets/e-text.c464
-rw-r--r--widgets/e-text.h20
-rw-r--r--widgets/e-text/e-text-event-processor-emacs-like.c327
-rw-r--r--widgets/e-text/e-text-event-processor-emacs-like.h68
-rw-r--r--widgets/e-text/e-text-event-processor-types.h131
-rw-r--r--widgets/e-text/e-text-event-processor.c103
-rw-r--r--widgets/e-text/e-text-event-processor.h74
-rw-r--r--widgets/e-text/e-text.c464
-rw-r--r--widgets/e-text/e-text.h20
-rw-r--r--widgets/test-minicard.c10
-rw-r--r--widgets/text/e-text-event-processor-emacs-like.c327
-rw-r--r--widgets/text/e-text-event-processor-emacs-like.h68
-rw-r--r--widgets/text/e-text-event-processor-types.h131
-rw-r--r--widgets/text/e-text-event-processor.c103
-rw-r--r--widgets/text/e-text-event-processor.h74
-rw-r--r--widgets/text/e-text.c464
-rw-r--r--widgets/text/e-text.h20
36 files changed, 4231 insertions, 122 deletions
diff --git a/ChangeLog b/ChangeLog
index b7c67a0e8e..47717a2d73 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2000-01-11 Christopher James Lahey <clahey@helixcode.com>
+
+ * widgets/test-minicard.c: Removed some code which got in the way
+ of testing properly.
+
+ * widgets/e-minicard-label.c (e_minicard_label_realize): Made the
+ field text item editable.
+
+ * widgets/Makefile.am: Added e-text-event-process*.[ch].
+
+ * widgets/e-text.c, widgets/e-text.h: Changed these to support
+ editing.
+
+ * widgets/e-text-event-processor.c,
+ widgets/e-text-event-processor.h,
+ widgets/e-text-event-processor-types.h,
+ widgets/e-text-event-processor-emacs-like.c,
+ widgets/e-text-event-processor-emacs-like.h: These are a new pair
+ of classes which handle all events from the text item and convert
+ them into commands.
+
+
+2000-01-10 Christopher James Lahey <clahey@helixcode.com>
+
+ * widgets/Makefile.am: Added minicard and text stuff.
+
+ * widgets/e-minicard.c, widgets/e-minicard.h,
+ widgets/e-minicard-label.c, widgets/e-minicard-label.h: Added
+ canvas items for the minicard view in the contact manager.
+
+ * widgets/test-minicard.c, widgets/test-minicard-label.c: Tests
+ for the minicard items.
+
+ * widgets/e-text.h, widgets/e-text.c: New canvas item. Based on
+ GnomeCanvasText. Adds ellipsis capabilities. Used in
+ e-minicard*.[ch].
+
+ * widgets/.cvsignore: Added minicard-test and minicard-label-test.
+
2000-01-06 Miguel de Icaza <miguel@gnu.org>
* configure.in: Add Bonobo detection, Bonobo flags for compilation
diff --git a/addressbook/gui/minicard/e-minicard-label.c b/addressbook/gui/minicard/e-minicard-label.c
index e3c61ff9bf..0b6db4115a 100644
--- a/addressbook/gui/minicard/e-minicard-label.c
+++ b/addressbook/gui/minicard/e-minicard-label.c
@@ -239,6 +239,7 @@ e_minicard_label_realize (GnomeCanvasItem *item)
"use_ellipsis", TRUE,
"font", "lucidasans-10",
"fill_color", "black",
+ "editable", TRUE,
NULL );
if ( e_minicard_label->field_text )
diff --git a/addressbook/gui/minicard/test-minicard.c b/addressbook/gui/minicard/test-minicard.c
index 4f56fbe936..79077c4b2d 100644
--- a/addressbook/gui/minicard/test-minicard.c
+++ b/addressbook/gui/minicard/test-minicard.c
@@ -61,11 +61,6 @@ static void about_callback( GtkWidget *widget, gpointer data )
gtk_widget_show (about);
}
-static void button_press_callback( GtkWidget *widget, gpointer data )
-{
- gnome_canvas_item_grab_focus( card );
-}
-
int main( int argc, char *argv[] )
{
GtkWidget *app;
@@ -102,7 +97,6 @@ int main( int argc, char *argv[] )
gnome_app_set_contents( GNOME_APP( app ), canvas );
-
/* Connect the signals */
gtk_signal_connect( GTK_OBJECT( app ), "destroy",
GTK_SIGNAL_FUNC( destroy_callback ),
@@ -112,10 +106,6 @@ int main( int argc, char *argv[] )
GTK_SIGNAL_FUNC( allocate_callback ),
( gpointer ) app );
- gtk_signal_connect( GTK_OBJECT( canvas ), "button_press_event",
- GTK_SIGNAL_FUNC( button_press_callback ),
- ( gpointer ) app );
-
gtk_widget_show_all( app );
gtk_main();
diff --git a/addressbook/gui/widgets/e-minicard-label.c b/addressbook/gui/widgets/e-minicard-label.c
index e3c61ff9bf..0b6db4115a 100644
--- a/addressbook/gui/widgets/e-minicard-label.c
+++ b/addressbook/gui/widgets/e-minicard-label.c
@@ -239,6 +239,7 @@ e_minicard_label_realize (GnomeCanvasItem *item)
"use_ellipsis", TRUE,
"font", "lucidasans-10",
"fill_color", "black",
+ "editable", TRUE,
NULL );
if ( e_minicard_label->field_text )
diff --git a/addressbook/gui/widgets/test-minicard.c b/addressbook/gui/widgets/test-minicard.c
index 4f56fbe936..79077c4b2d 100644
--- a/addressbook/gui/widgets/test-minicard.c
+++ b/addressbook/gui/widgets/test-minicard.c
@@ -61,11 +61,6 @@ static void about_callback( GtkWidget *widget, gpointer data )
gtk_widget_show (about);
}
-static void button_press_callback( GtkWidget *widget, gpointer data )
-{
- gnome_canvas_item_grab_focus( card );
-}
-
int main( int argc, char *argv[] )
{
GtkWidget *app;
@@ -102,7 +97,6 @@ int main( int argc, char *argv[] )
gnome_app_set_contents( GNOME_APP( app ), canvas );
-
/* Connect the signals */
gtk_signal_connect( GTK_OBJECT( app ), "destroy",
GTK_SIGNAL_FUNC( destroy_callback ),
@@ -112,10 +106,6 @@ int main( int argc, char *argv[] )
GTK_SIGNAL_FUNC( allocate_callback ),
( gpointer ) app );
- gtk_signal_connect( GTK_OBJECT( canvas ), "button_press_event",
- GTK_SIGNAL_FUNC( button_press_callback ),
- ( gpointer ) app );
-
gtk_widget_show_all( app );
gtk_main();
diff --git a/e-util/e-text-event-processor-emacs-like.c b/e-util/e-text-event-processor-emacs-like.c
new file mode 100644
index 0000000000..1d7d36d45f
--- /dev/null
+++ b/e-util/e-text-event-processor-emacs-like.c
@@ -0,0 +1,327 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor-emacs-like.h"
+static void e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *card);
+static void e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass);
+static gint e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+static ETextEventProcessorClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+static const ETextEventProcessorCommand control_keys[26] =
+{
+ { E_TEP_START_OF_LINE, E_TEP_MOVE, 0, "" }, /* a */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_COPY, 0, "" }, /* c */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_END_OF_LINE, E_TEP_MOVE, 0, "" }, /* e */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_END_OF_LINE, E_TEP_DELETE, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_FORWARD_LINE, E_TEP_MOVE, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_BACKWARD_LINE, E_TEP_MOVE, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_START_OF_LINE, E_TEP_DELETE, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* v */
+ { E_TEP_BACKWARD_WORD, E_TEP_DELETE, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+};
+
+static const ETextEventProcessorCommand alt_keys[26] =
+{
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* a */
+ { E_TEP_BACKWARD_WORD, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* c */
+ { E_TEP_FORWARD_WORD, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* e */
+ { E_TEP_FORWARD_WORD, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* v */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+
+};
+
+GtkType
+e_text_event_processor_emacs_like_get_type (void)
+{
+ static GtkType text_event_processor_emacs_like_type = 0;
+
+ if (!text_event_processor_emacs_like_type)
+ {
+ static const GtkTypeInfo text_event_processor_emacs_like_info =
+ {
+ "ETextEventProcessorEmacsLike",
+ sizeof (ETextEventProcessorEmacsLike),
+ sizeof (ETextEventProcessorEmacsLikeClass),
+ (GtkClassInitFunc) e_text_event_processor_emacs_like_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_emacs_like_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_emacs_like_type = gtk_type_unique (e_text_event_processor_get_type (), &text_event_processor_emacs_like_info);
+ }
+
+ return text_event_processor_emacs_like_type;
+}
+
+static void
+e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass)
+{
+ GtkObjectClass *object_class;
+ ETextEventProcessorClass *processor_class;
+
+ object_class = (GtkObjectClass*) klass;
+ processor_class = (ETextEventProcessorClass*) klass;
+
+ parent_class = gtk_type_class (e_text_event_processor_get_type ());
+
+ processor_class->event = e_text_event_processor_emacs_like_event;
+}
+
+static void
+e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *tep)
+{
+}
+
+static gint
+e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ ETextEventProcessorCommand command;
+ ETextEventProcessorEmacsLike *tep_el = E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(tep);
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 1) {
+ if (event->button.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ command.position = E_TEP_VALUE;
+ command.value = event->button.position;
+ tep_el->mouse_down = TRUE;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 1) {
+ tep_el->mouse_down = FALSE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (tep_el->mouse_down) {
+ command.action = E_TEP_SELECT;
+ command.position = E_TEP_VALUE;
+ command.value = event->motion.position;
+ }
+ break;
+ case GDK_KEY_PRESS:
+ {
+ ETextEventProcessorEventKey key = event->key;
+ if (key.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ switch(key.keyval) {
+ case GDK_Home:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_START_OF_BUFFER;
+ else
+ command.position = E_TEP_START_OF_LINE;
+ break;
+ case GDK_End:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_END_OF_BUFFER;
+ else
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Page_Up: command.position = E_TEP_BACKWARD_PAGE; break;
+ case GDK_Page_Down: command.position = E_TEP_FORWARD_PAGE; break;
+ /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
+ case GDK_Up: command.position = E_TEP_BACKWARD_LINE; break;
+ case GDK_Down: command.position = E_TEP_FORWARD_LINE; break;
+ case GDK_Left:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Right:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_FORWARD_WORD;
+ else
+ command.position = E_TEP_FORWARD_CHARACTER;
+ break;
+
+ case GDK_BackSpace:
+ command.action = E_TEP_DELETE;
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Clear:
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Insert:
+ if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_PASTE;
+ command.position = E_TEP_SELECTION;
+ } else if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_COPY;
+ command.position = E_TEP_SELECTION;
+ } else {
+ /* gtk_toggle_insert(text) -- IMPLEMENT */
+ }
+ break;
+ case GDK_Delete:
+ if (key.state & GDK_CONTROL_MASK){
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_WORD;
+ } else if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_COPY;
+
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_CHARACTER;
+ }
+ break;
+ case GDK_Tab:
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\t";
+ break;
+ case GDK_Return:
+ if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_ACTIVATE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\n";
+ }
+ break;
+ case GDK_Escape:
+ command.action = E_TEP_NOP;
+ command.position = E_TEP_SELECTION;
+ /* Don't insert literally */
+ break;
+
+ default:
+ if (key.state & GDK_CONTROL_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = control_keys[(int) (key.keyval - 'a')].position;
+ if (control_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = control_keys[(int) (key.keyval - 'a')].action;
+ command.value = control_keys[(int) (key.keyval - 'a')].value;
+ command.string = control_keys[(int) (key.keyval - 'a')].string;
+ }
+
+ if (key.keyval == 'x') {
+ }
+
+ break;
+ } else if (key.state & GDK_MOD1_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = alt_keys[(int) (key.keyval - 'a')].position;
+ if (alt_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = alt_keys[(int) (key.keyval - 'a')].action;
+ command.value = alt_keys[(int) (key.keyval - 'a')].value;
+ command.string = alt_keys[(int) (key.keyval - 'a')].string;
+ }
+ } else if (key.length > 0) {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = strlen(key.string);
+ command.string = key.string;
+
+ } else {
+ command.action = E_TEP_NOP;
+ }
+ }
+ break;
+ case GDK_KEY_RELEASE:
+ command.action = E_TEP_NOP;
+ break;
+ default:
+ command.action = E_TEP_NOP;
+ break;
+ }
+ }
+ if (command.action != E_TEP_NOP) {
+ gtk_signal_emit_by_name (GTK_OBJECT (tep), "command", &command);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ETextEventProcessor *
+e_text_event_processor_emacs_like_new (void)
+{
+ ETextEventProcessorEmacsLike *retval = gtk_type_new (e_text_event_processor_emacs_like_get_type ());
+ return E_TEXT_EVENT_PROCESSOR (retval);
+}
+
diff --git a/e-util/e-text-event-processor-emacs-like.h b/e-util/e-text-event-processor-emacs-like.h
new file mode 100644
index 0000000000..651bb552b3
--- /dev/null
+++ b/e-util/e-text-event-processor-emacs-like.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor-emacs-like.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+#define __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessorEmacsLike - Turns events on a text widget into commands. Uses an emacs-ish interface.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE (e_text_event_processor_emacs_like_get_type ())
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLike))
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLikeClass))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+
+
+typedef struct _ETextEventProcessorEmacsLike ETextEventProcessorEmacsLike;
+typedef struct _ETextEventProcessorEmacsLikeClass ETextEventProcessorEmacsLikeClass;
+
+struct _ETextEventProcessorEmacsLike
+{
+ ETextEventProcessor parent;
+
+ /* object specific fields */
+ gboolean mouse_down;
+};
+
+struct _ETextEventProcessorEmacsLikeClass
+{
+ ETextEventProcessorClass parent_class;
+};
+
+
+GtkType e_text_event_processor_emacs_like_get_type (void);
+ETextEventProcessor *e_text_event_processor_emacs_like_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__ */
diff --git a/e-util/e-text-event-processor-types.h b/e-util/e-text-event-processor-types.h
new file mode 100644
index 0000000000..30b7bcafc9
--- /dev/null
+++ b/e-util/e-text-event-processor-types.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+#define __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <gdk/gdktypes.h>
+
+typedef enum _ETextEventProcessorCommandPosition ETextEventProcessorCommandPosition;
+typedef enum _ETextEventProcessorCommandAction ETextEventProcessorCommandAction;
+typedef struct _ETextEventProcessorCommand ETextEventProcessorCommand;
+
+typedef union _ETextEventProcessorEvent ETextEventProcessorEvent;
+typedef struct _ETextEventProcessorEventButton ETextEventProcessorEventButton;
+typedef struct _ETextEventProcessorEventKey ETextEventProcessorEventKey;
+typedef struct _ETextEventProcessorEventMotion ETextEventProcessorEventMotion;
+
+enum _ETextEventProcessorCommandPosition {
+ E_TEP_VALUE,
+ E_TEP_SELECTION,
+
+ E_TEP_START_OF_BUFFER,
+ E_TEP_END_OF_BUFFER,
+
+ E_TEP_START_OF_LINE,
+ E_TEP_END_OF_LINE,
+
+ E_TEP_FORWARD_CHARACTER,
+ E_TEP_BACKWARD_CHARACTER,
+
+ E_TEP_FORWARD_WORD,
+ E_TEP_BACKWARD_WORD,
+
+ E_TEP_FORWARD_LINE,
+ E_TEP_BACKWARD_LINE,
+
+ E_TEP_FORWARD_PARAGRAPH,
+ E_TEP_BACKWARD_PARAGRAPH,
+
+ E_TEP_FORWARD_PAGE,
+ E_TEP_BACKWARD_PAGE
+};
+
+enum _ETextEventProcessorCommandAction {
+ E_TEP_MOVE,
+ E_TEP_SELECT,
+ E_TEP_DELETE,
+
+ E_TEP_INSERT,
+ E_TEP_COPY,
+ E_TEP_PASTE,
+ E_TEP_SET_SELECT_BY_WORD,
+ E_TEP_ACTIVATE,
+
+ E_TEP_NOP
+};
+
+struct _ETextEventProcessorCommand {
+ ETextEventProcessorCommandPosition position;
+ ETextEventProcessorCommandAction action;
+ int value;
+ char *string;
+};
+
+struct _ETextEventProcessorEventButton {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint button;
+ gint position;
+};
+
+struct _ETextEventProcessorEventKey {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint keyval;
+ gint length;
+ gchar *string;
+};
+
+struct _ETextEventProcessorEventMotion {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ gint position;
+};
+
+union _ETextEventProcessorEvent {
+ GdkEventType type;
+ ETextEventProcessorEventButton button;
+ ETextEventProcessorEventKey key;
+ ETextEventProcessorEventMotion motion;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_TYPES_H__ */
diff --git a/e-util/e-text-event-processor.c b/e-util/e-text-event-processor.c
new file mode 100644
index 0000000000..47f028ca62
--- /dev/null
+++ b/e-util/e-text-event-processor.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+static void e_text_event_processor_init (ETextEventProcessor *card);
+static void e_text_event_processor_class_init (ETextEventProcessorClass *klass);
+
+static GtkObjectClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+enum {
+ E_TEP_EVENT,
+ E_TEP_LAST_SIGNAL
+};
+
+static guint e_tep_signals[E_TEP_LAST_SIGNAL] = { 0 };
+
+GtkType
+e_text_event_processor_get_type (void)
+{
+ static GtkType text_event_processor_type = 0;
+
+ if (!text_event_processor_type)
+ {
+ static const GtkTypeInfo text_event_processor_info =
+ {
+ "ETextEventProcessor",
+ sizeof (ETextEventProcessor),
+ sizeof (ETextEventProcessorClass),
+ (GtkClassInitFunc) e_text_event_processor_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_type = gtk_type_unique (gtk_object_get_type (), &text_event_processor_info);
+ }
+
+ return text_event_processor_type;
+}
+
+static void
+e_text_event_processor_class_init (ETextEventProcessorClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ e_tep_signals[E_TEP_EVENT] =
+ gtk_signal_new ("command",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (ETextEventProcessorClass, command),
+ gtk_marshal_NONE__POINTER,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ gtk_object_class_add_signals (object_class, e_tep_signals, E_TEP_LAST_SIGNAL);
+
+ klass->event = NULL;
+ klass->command = NULL;
+}
+
+static void
+e_text_event_processor_init (ETextEventProcessor *tep)
+{
+}
+
+gint
+e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ if (E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event) {
+ return E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event(tep, event);
+ } else {
+ return 0;
+ }
+}
diff --git a/e-util/e-text-event-processor.h b/e-util/e-text-event-processor.h
new file mode 100644
index 0000000000..1fc79f3f70
--- /dev/null
+++ b/e-util/e-text-event-processor.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_H__
+#define __E_TEXT_EVENT_PROCESSOR_H__
+
+#include <gnome.h>
+#include "e-text-event-processor-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessor - Turns events on a text widget into commands.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_TYPE (e_text_event_processor_get_type ())
+#define E_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessor))
+#define E_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
+#define E_IS_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+
+
+typedef struct _ETextEventProcessor ETextEventProcessor;
+typedef struct _ETextEventProcessorClass ETextEventProcessorClass;
+
+struct _ETextEventProcessor
+{
+ GtkObject parent;
+
+ /* object specific fields */
+
+};
+
+struct _ETextEventProcessorClass
+{
+ GtkObjectClass parent_class;
+
+ /* signals */
+ void (* command) (ETextEventProcessor *tep, ETextEventProcessorCommand *command);
+
+ /* virtual functions */
+ gint (* event) (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+};
+
+
+GtkType e_text_event_processor_get_type (void);
+gint e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_H__ */
diff --git a/widgets/Makefile.am b/widgets/Makefile.am
index 76337f05a4..2012b00429 100644
--- a/widgets/Makefile.am
+++ b/widgets/Makefile.am
@@ -18,7 +18,11 @@ libevolutionwidgets_a_SOURCES = \
e-minicard-label.c \
e-minicard-label.h \
e-text.c \
- e-text.h
+ e-text.h \
+ e-text-event-processor.c \
+ e-text-event-processor.h \
+ e-text-event-processor-emacs-like.c \
+ e-text-event-processor-emacs-like.h
noinst_PROGRAMS = \
minicard-label-test \
diff --git a/widgets/e-minicard-label.c b/widgets/e-minicard-label.c
index e3c61ff9bf..0b6db4115a 100644
--- a/widgets/e-minicard-label.c
+++ b/widgets/e-minicard-label.c
@@ -239,6 +239,7 @@ e_minicard_label_realize (GnomeCanvasItem *item)
"use_ellipsis", TRUE,
"font", "lucidasans-10",
"fill_color", "black",
+ "editable", TRUE,
NULL );
if ( e_minicard_label->field_text )
diff --git a/widgets/e-minicard/e-minicard-label.c b/widgets/e-minicard/e-minicard-label.c
index e3c61ff9bf..0b6db4115a 100644
--- a/widgets/e-minicard/e-minicard-label.c
+++ b/widgets/e-minicard/e-minicard-label.c
@@ -239,6 +239,7 @@ e_minicard_label_realize (GnomeCanvasItem *item)
"use_ellipsis", TRUE,
"font", "lucidasans-10",
"fill_color", "black",
+ "editable", TRUE,
NULL );
if ( e_minicard_label->field_text )
diff --git a/widgets/e-minicard/test-minicard.c b/widgets/e-minicard/test-minicard.c
index 4f56fbe936..79077c4b2d 100644
--- a/widgets/e-minicard/test-minicard.c
+++ b/widgets/e-minicard/test-minicard.c
@@ -61,11 +61,6 @@ static void about_callback( GtkWidget *widget, gpointer data )
gtk_widget_show (about);
}
-static void button_press_callback( GtkWidget *widget, gpointer data )
-{
- gnome_canvas_item_grab_focus( card );
-}
-
int main( int argc, char *argv[] )
{
GtkWidget *app;
@@ -102,7 +97,6 @@ int main( int argc, char *argv[] )
gnome_app_set_contents( GNOME_APP( app ), canvas );
-
/* Connect the signals */
gtk_signal_connect( GTK_OBJECT( app ), "destroy",
GTK_SIGNAL_FUNC( destroy_callback ),
@@ -112,10 +106,6 @@ int main( int argc, char *argv[] )
GTK_SIGNAL_FUNC( allocate_callback ),
( gpointer ) app );
- gtk_signal_connect( GTK_OBJECT( canvas ), "button_press_event",
- GTK_SIGNAL_FUNC( button_press_callback ),
- ( gpointer ) app );
-
gtk_widget_show_all( app );
gtk_main();
diff --git a/widgets/e-text-event-processor-emacs-like.c b/widgets/e-text-event-processor-emacs-like.c
new file mode 100644
index 0000000000..1d7d36d45f
--- /dev/null
+++ b/widgets/e-text-event-processor-emacs-like.c
@@ -0,0 +1,327 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor-emacs-like.h"
+static void e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *card);
+static void e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass);
+static gint e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+static ETextEventProcessorClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+static const ETextEventProcessorCommand control_keys[26] =
+{
+ { E_TEP_START_OF_LINE, E_TEP_MOVE, 0, "" }, /* a */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_COPY, 0, "" }, /* c */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_END_OF_LINE, E_TEP_MOVE, 0, "" }, /* e */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_END_OF_LINE, E_TEP_DELETE, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_FORWARD_LINE, E_TEP_MOVE, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_BACKWARD_LINE, E_TEP_MOVE, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_START_OF_LINE, E_TEP_DELETE, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* v */
+ { E_TEP_BACKWARD_WORD, E_TEP_DELETE, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+};
+
+static const ETextEventProcessorCommand alt_keys[26] =
+{
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* a */
+ { E_TEP_BACKWARD_WORD, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* c */
+ { E_TEP_FORWARD_WORD, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* e */
+ { E_TEP_FORWARD_WORD, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* v */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+
+};
+
+GtkType
+e_text_event_processor_emacs_like_get_type (void)
+{
+ static GtkType text_event_processor_emacs_like_type = 0;
+
+ if (!text_event_processor_emacs_like_type)
+ {
+ static const GtkTypeInfo text_event_processor_emacs_like_info =
+ {
+ "ETextEventProcessorEmacsLike",
+ sizeof (ETextEventProcessorEmacsLike),
+ sizeof (ETextEventProcessorEmacsLikeClass),
+ (GtkClassInitFunc) e_text_event_processor_emacs_like_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_emacs_like_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_emacs_like_type = gtk_type_unique (e_text_event_processor_get_type (), &text_event_processor_emacs_like_info);
+ }
+
+ return text_event_processor_emacs_like_type;
+}
+
+static void
+e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass)
+{
+ GtkObjectClass *object_class;
+ ETextEventProcessorClass *processor_class;
+
+ object_class = (GtkObjectClass*) klass;
+ processor_class = (ETextEventProcessorClass*) klass;
+
+ parent_class = gtk_type_class (e_text_event_processor_get_type ());
+
+ processor_class->event = e_text_event_processor_emacs_like_event;
+}
+
+static void
+e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *tep)
+{
+}
+
+static gint
+e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ ETextEventProcessorCommand command;
+ ETextEventProcessorEmacsLike *tep_el = E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(tep);
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 1) {
+ if (event->button.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ command.position = E_TEP_VALUE;
+ command.value = event->button.position;
+ tep_el->mouse_down = TRUE;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 1) {
+ tep_el->mouse_down = FALSE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (tep_el->mouse_down) {
+ command.action = E_TEP_SELECT;
+ command.position = E_TEP_VALUE;
+ command.value = event->motion.position;
+ }
+ break;
+ case GDK_KEY_PRESS:
+ {
+ ETextEventProcessorEventKey key = event->key;
+ if (key.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ switch(key.keyval) {
+ case GDK_Home:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_START_OF_BUFFER;
+ else
+ command.position = E_TEP_START_OF_LINE;
+ break;
+ case GDK_End:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_END_OF_BUFFER;
+ else
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Page_Up: command.position = E_TEP_BACKWARD_PAGE; break;
+ case GDK_Page_Down: command.position = E_TEP_FORWARD_PAGE; break;
+ /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
+ case GDK_Up: command.position = E_TEP_BACKWARD_LINE; break;
+ case GDK_Down: command.position = E_TEP_FORWARD_LINE; break;
+ case GDK_Left:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Right:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_FORWARD_WORD;
+ else
+ command.position = E_TEP_FORWARD_CHARACTER;
+ break;
+
+ case GDK_BackSpace:
+ command.action = E_TEP_DELETE;
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Clear:
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Insert:
+ if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_PASTE;
+ command.position = E_TEP_SELECTION;
+ } else if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_COPY;
+ command.position = E_TEP_SELECTION;
+ } else {
+ /* gtk_toggle_insert(text) -- IMPLEMENT */
+ }
+ break;
+ case GDK_Delete:
+ if (key.state & GDK_CONTROL_MASK){
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_WORD;
+ } else if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_COPY;
+
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_CHARACTER;
+ }
+ break;
+ case GDK_Tab:
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\t";
+ break;
+ case GDK_Return:
+ if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_ACTIVATE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\n";
+ }
+ break;
+ case GDK_Escape:
+ command.action = E_TEP_NOP;
+ command.position = E_TEP_SELECTION;
+ /* Don't insert literally */
+ break;
+
+ default:
+ if (key.state & GDK_CONTROL_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = control_keys[(int) (key.keyval - 'a')].position;
+ if (control_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = control_keys[(int) (key.keyval - 'a')].action;
+ command.value = control_keys[(int) (key.keyval - 'a')].value;
+ command.string = control_keys[(int) (key.keyval - 'a')].string;
+ }
+
+ if (key.keyval == 'x') {
+ }
+
+ break;
+ } else if (key.state & GDK_MOD1_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = alt_keys[(int) (key.keyval - 'a')].position;
+ if (alt_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = alt_keys[(int) (key.keyval - 'a')].action;
+ command.value = alt_keys[(int) (key.keyval - 'a')].value;
+ command.string = alt_keys[(int) (key.keyval - 'a')].string;
+ }
+ } else if (key.length > 0) {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = strlen(key.string);
+ command.string = key.string;
+
+ } else {
+ command.action = E_TEP_NOP;
+ }
+ }
+ break;
+ case GDK_KEY_RELEASE:
+ command.action = E_TEP_NOP;
+ break;
+ default:
+ command.action = E_TEP_NOP;
+ break;
+ }
+ }
+ if (command.action != E_TEP_NOP) {
+ gtk_signal_emit_by_name (GTK_OBJECT (tep), "command", &command);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ETextEventProcessor *
+e_text_event_processor_emacs_like_new (void)
+{
+ ETextEventProcessorEmacsLike *retval = gtk_type_new (e_text_event_processor_emacs_like_get_type ());
+ return E_TEXT_EVENT_PROCESSOR (retval);
+}
+
diff --git a/widgets/e-text-event-processor-emacs-like.h b/widgets/e-text-event-processor-emacs-like.h
new file mode 100644
index 0000000000..651bb552b3
--- /dev/null
+++ b/widgets/e-text-event-processor-emacs-like.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor-emacs-like.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+#define __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessorEmacsLike - Turns events on a text widget into commands. Uses an emacs-ish interface.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE (e_text_event_processor_emacs_like_get_type ())
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLike))
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLikeClass))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+
+
+typedef struct _ETextEventProcessorEmacsLike ETextEventProcessorEmacsLike;
+typedef struct _ETextEventProcessorEmacsLikeClass ETextEventProcessorEmacsLikeClass;
+
+struct _ETextEventProcessorEmacsLike
+{
+ ETextEventProcessor parent;
+
+ /* object specific fields */
+ gboolean mouse_down;
+};
+
+struct _ETextEventProcessorEmacsLikeClass
+{
+ ETextEventProcessorClass parent_class;
+};
+
+
+GtkType e_text_event_processor_emacs_like_get_type (void);
+ETextEventProcessor *e_text_event_processor_emacs_like_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__ */
diff --git a/widgets/e-text-event-processor-types.h b/widgets/e-text-event-processor-types.h
new file mode 100644
index 0000000000..30b7bcafc9
--- /dev/null
+++ b/widgets/e-text-event-processor-types.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+#define __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <gdk/gdktypes.h>
+
+typedef enum _ETextEventProcessorCommandPosition ETextEventProcessorCommandPosition;
+typedef enum _ETextEventProcessorCommandAction ETextEventProcessorCommandAction;
+typedef struct _ETextEventProcessorCommand ETextEventProcessorCommand;
+
+typedef union _ETextEventProcessorEvent ETextEventProcessorEvent;
+typedef struct _ETextEventProcessorEventButton ETextEventProcessorEventButton;
+typedef struct _ETextEventProcessorEventKey ETextEventProcessorEventKey;
+typedef struct _ETextEventProcessorEventMotion ETextEventProcessorEventMotion;
+
+enum _ETextEventProcessorCommandPosition {
+ E_TEP_VALUE,
+ E_TEP_SELECTION,
+
+ E_TEP_START_OF_BUFFER,
+ E_TEP_END_OF_BUFFER,
+
+ E_TEP_START_OF_LINE,
+ E_TEP_END_OF_LINE,
+
+ E_TEP_FORWARD_CHARACTER,
+ E_TEP_BACKWARD_CHARACTER,
+
+ E_TEP_FORWARD_WORD,
+ E_TEP_BACKWARD_WORD,
+
+ E_TEP_FORWARD_LINE,
+ E_TEP_BACKWARD_LINE,
+
+ E_TEP_FORWARD_PARAGRAPH,
+ E_TEP_BACKWARD_PARAGRAPH,
+
+ E_TEP_FORWARD_PAGE,
+ E_TEP_BACKWARD_PAGE
+};
+
+enum _ETextEventProcessorCommandAction {
+ E_TEP_MOVE,
+ E_TEP_SELECT,
+ E_TEP_DELETE,
+
+ E_TEP_INSERT,
+ E_TEP_COPY,
+ E_TEP_PASTE,
+ E_TEP_SET_SELECT_BY_WORD,
+ E_TEP_ACTIVATE,
+
+ E_TEP_NOP
+};
+
+struct _ETextEventProcessorCommand {
+ ETextEventProcessorCommandPosition position;
+ ETextEventProcessorCommandAction action;
+ int value;
+ char *string;
+};
+
+struct _ETextEventProcessorEventButton {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint button;
+ gint position;
+};
+
+struct _ETextEventProcessorEventKey {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint keyval;
+ gint length;
+ gchar *string;
+};
+
+struct _ETextEventProcessorEventMotion {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ gint position;
+};
+
+union _ETextEventProcessorEvent {
+ GdkEventType type;
+ ETextEventProcessorEventButton button;
+ ETextEventProcessorEventKey key;
+ ETextEventProcessorEventMotion motion;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_TYPES_H__ */
diff --git a/widgets/e-text-event-processor.c b/widgets/e-text-event-processor.c
new file mode 100644
index 0000000000..47f028ca62
--- /dev/null
+++ b/widgets/e-text-event-processor.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+static void e_text_event_processor_init (ETextEventProcessor *card);
+static void e_text_event_processor_class_init (ETextEventProcessorClass *klass);
+
+static GtkObjectClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+enum {
+ E_TEP_EVENT,
+ E_TEP_LAST_SIGNAL
+};
+
+static guint e_tep_signals[E_TEP_LAST_SIGNAL] = { 0 };
+
+GtkType
+e_text_event_processor_get_type (void)
+{
+ static GtkType text_event_processor_type = 0;
+
+ if (!text_event_processor_type)
+ {
+ static const GtkTypeInfo text_event_processor_info =
+ {
+ "ETextEventProcessor",
+ sizeof (ETextEventProcessor),
+ sizeof (ETextEventProcessorClass),
+ (GtkClassInitFunc) e_text_event_processor_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_type = gtk_type_unique (gtk_object_get_type (), &text_event_processor_info);
+ }
+
+ return text_event_processor_type;
+}
+
+static void
+e_text_event_processor_class_init (ETextEventProcessorClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ e_tep_signals[E_TEP_EVENT] =
+ gtk_signal_new ("command",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (ETextEventProcessorClass, command),
+ gtk_marshal_NONE__POINTER,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ gtk_object_class_add_signals (object_class, e_tep_signals, E_TEP_LAST_SIGNAL);
+
+ klass->event = NULL;
+ klass->command = NULL;
+}
+
+static void
+e_text_event_processor_init (ETextEventProcessor *tep)
+{
+}
+
+gint
+e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ if (E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event) {
+ return E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event(tep, event);
+ } else {
+ return 0;
+ }
+}
diff --git a/widgets/e-text-event-processor.h b/widgets/e-text-event-processor.h
new file mode 100644
index 0000000000..1fc79f3f70
--- /dev/null
+++ b/widgets/e-text-event-processor.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_H__
+#define __E_TEXT_EVENT_PROCESSOR_H__
+
+#include <gnome.h>
+#include "e-text-event-processor-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessor - Turns events on a text widget into commands.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_TYPE (e_text_event_processor_get_type ())
+#define E_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessor))
+#define E_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
+#define E_IS_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+
+
+typedef struct _ETextEventProcessor ETextEventProcessor;
+typedef struct _ETextEventProcessorClass ETextEventProcessorClass;
+
+struct _ETextEventProcessor
+{
+ GtkObject parent;
+
+ /* object specific fields */
+
+};
+
+struct _ETextEventProcessorClass
+{
+ GtkObjectClass parent_class;
+
+ /* signals */
+ void (* command) (ETextEventProcessor *tep, ETextEventProcessorCommand *command);
+
+ /* virtual functions */
+ gint (* event) (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+};
+
+
+GtkType e_text_event_processor_get_type (void);
+gint e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_H__ */
diff --git a/widgets/e-text.c b/widgets/e-text.c
index b88130e3c8..f6daa3f3cf 100644
--- a/widgets/e-text.c
+++ b/widgets/e-text.c
@@ -18,12 +18,15 @@
#include <config.h>
#include <math.h>
+#include <ctype.h>
#include "e-text.h"
#include <gdk/gdkx.h> /* for BlackPixel */
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_rgb.h>
#include <libart_lgpl/art_rgb_bitmap_affine.h>
+#include "e-text-event-processor-emacs-like.h"
+
/* This defines a line of text */
@@ -58,6 +61,7 @@ enum {
ARG_FILL_STIPPLE,
ARG_TEXT_WIDTH,
ARG_TEXT_HEIGHT,
+ ARG_EDITABLE,
ARG_USE_ELLIPSIS,
ARG_ELLIPSIS
};
@@ -80,6 +84,9 @@ static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, i
static void e_text_bounds (GnomeCanvasItem *item,
double *x1, double *y1, double *x2, double *y2);
static void e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static gint e_text_event (GnomeCanvasItem *item, GdkEvent *event);
+
+static void e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
static ETextSuckFont *e_suck_font (GdkFont *font);
static void e_suck_font_free (ETextSuckFont *suckfont);
@@ -171,6 +178,8 @@ e_text_class_init (ETextClass *class)
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_WIDTH);
gtk_object_add_arg_type ("EText::text_height",
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_HEIGHT);
+ gtk_object_add_arg_type ("EText::editable",
+ GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
gtk_object_add_arg_type ("EText::use_ellipsis",
GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS);
gtk_object_add_arg_type ("EText::ellipsis",
@@ -187,6 +196,7 @@ e_text_class_init (ETextClass *class)
item_class->point = e_text_point;
item_class->bounds = e_text_bounds;
item_class->render = e_text_render;
+ item_class->event = e_text_event;
}
/* Object initialization function for the text item */
@@ -201,9 +211,18 @@ e_text_init (EText *text)
text->clip_height = 0.0;
text->xofs = 0.0;
text->yofs = 0.0;
+
text->ellipsis = NULL;
text->use_ellipsis = FALSE;
text->ellipsis_width = 0;
+
+ text->editable = FALSE;
+ text->editing = FALSE;
+ text->xofs_edit = 0;
+
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
}
/* Destroy handler for the text item */
@@ -456,7 +475,8 @@ calc_line_widths (EText *text)
}
if (text->clip &&
- text->use_ellipsis &&
+ text->use_ellipsis &&
+ ! text->editing &&
lines->width > text->clip_width) {
if (text->font) {
lines->ellipsis_length = 0;
@@ -729,6 +749,10 @@ e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE);
break;
+ case ARG_EDITABLE:
+ text->editable = GTK_VALUE_BOOL (*arg);
+ break;
+
case ARG_USE_ELLIPSIS:
text->use_ellipsis = GTK_VALUE_BOOL (*arg);
calc_line_widths (text);
@@ -839,6 +863,10 @@ e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit;
break;
+ case ARG_EDITABLE:
+ GTK_VALUE_BOOL (*arg) = text->editable;
+ break;
+
case ARG_USE_ELLIPSIS:
GTK_VALUE_BOOL (*arg) = text->use_ellipsis;
break;
@@ -1016,6 +1044,19 @@ get_line_xpos (EText *text, struct line *line)
return x;
}
+static void
+_get_tep(EText *text)
+{
+ if (!text->tep) {
+ text->tep = e_text_event_processor_emacs_like_new();
+ gtk_signal_connect(GTK_OBJECT(text->tep),
+ "command",
+ GTK_SIGNAL_FUNC(e_text_command),
+ (gpointer) text);
+
+ }
+}
+
/* Draw handler for the text item */
static void
e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
@@ -1026,8 +1067,14 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
struct line *lines;
int i;
int xpos, ypos;
+ int start_char, end_char;
+ int sel_start, sel_end;
+ GdkRectangle sel_rect;
+ GdkGC *fg_gc;
+ GnomeCanvas *canvas;
text = E_TEXT (item);
+ canvas = GNOME_CANVAS_ITEM(text)->canvas;
if (!text->text || !text->font)
return;
@@ -1039,6 +1086,7 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
rect.height = text->clip_cheight;
gdk_gc_set_clip_rectangle (text->gc, &rect);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED], &rect);
}
lines = text->lines;
ypos = text->cy + text->font->ascent;
@@ -1049,39 +1097,122 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
for (i = 0; i < text->num_lines; i++) {
if (lines->length != 0) {
xpos = get_line_xpos (text, lines);
- if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->ellipsis_length);
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x +
- lines->width - text->ellipsis_width,
- ypos - y,
- text->ellipsis ? text->ellipsis : "...",
- text->ellipsis ? strlen (text->ellipsis) : 3);
- } else
-
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->length);
+ if (text->editing) {
+ xpos -= text->xofs_edit;
+ start_char = lines->text - text->text;
+ end_char = start_char + lines->length;
+ sel_start = text->selection_start;
+ sel_end = text->selection_end;
+ if (sel_start > sel_end ) {
+ sel_start ^= sel_end;
+ sel_end ^= sel_start;
+ sel_start ^= sel_end;
+ }
+ if ( sel_start < start_char )
+ sel_start = start_char;
+ if ( sel_end > end_char )
+ sel_end = end_char;
+ if ( sel_start < sel_end ) {
+ sel_rect.x = xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char);
+ sel_rect.y = ypos - y - text->font->ascent;
+ sel_rect.width = gdk_text_width (text->font,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ sel_rect.height = text->font->ascent + text->font->descent;
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ sel_rect.x,
+ sel_rect.y,
+ sel_rect.width,
+ sel_rect.height);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ sel_start - start_char);
+ fg_gc = GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED];
+ gdk_draw_text (drawable,
+ text->font,
+ fg_gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_end - start_char),
+ ypos - y,
+ lines->text + sel_end - start_char,
+ end_char - sel_end);
+ } else {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
+ if (text->selection_start == text->selection_end &&
+ text->selection_start >= start_char &&
+ text->selection_start <= end_char) {
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y - text->font->ascent,
+ 1,
+ text->font->ascent + text->font->descent);
+ }
+ } else {
+ if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->ellipsis_length);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x +
+ lines->width - text->ellipsis_width,
+ ypos - y,
+ text->ellipsis ? text->ellipsis : "...",
+ text->ellipsis ? strlen (text->ellipsis) : 3);
+ } else
+
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
}
ypos += text->font->ascent + text->font->descent;
lines++;
}
- if (text->clip)
+ if (text->clip) {
gdk_gc_set_clip_rectangle (text->gc, NULL);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(GNOME_CANVAS_ITEM(text)->canvas)->style->fg_gc[GTK_STATE_SELECTED], NULL);
+ }
}
/* Render handler for the text item */
@@ -1308,6 +1439,285 @@ e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double
*y2 = *y1 + height;
}
+static gint
+_get_position_from_xy (EText *text, gint x, gint y)
+{
+ int i, j;
+ int ypos = text->cy;
+ int xpos;
+ struct line *lines;
+ j = 0;
+ while (y > ypos)
+ {
+ ypos += text->font->ascent + text->font->descent;
+ j ++;
+ }
+ j--;
+ if (j >= text->num_lines)
+ j = text->num_lines - 1;
+ if (j < 0)
+ j = 0;
+ i = 0;
+ lines = text->lines;
+ lines += j;
+ xpos = get_line_xpos (text, lines);
+ for(i = 0; i < lines->length; i++) {
+ int charwidth = gdk_text_width(text->font,
+ lines->text + i,
+ 1);
+ xpos += charwidth / 2;
+ if (xpos > x)
+ break;
+ xpos += (charwidth + 1) / 2;
+ }
+ return lines->text + i - text->text;
+}
+
+static gint
+e_text_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EText *text = E_TEXT(item);
+ ETextEventProcessorEvent e_tep_event;
+
+ gint return_val;
+
+ e_tep_event.type = event->type;
+ switch (event->type) {
+ case GDK_FOCUS_CHANGE:
+ if (text->editable) {
+ GdkEventFocus *focus_event;
+ focus_event = (GdkEventFocus *) event;
+ if (focus_event->in) {
+ if(!text->editing) {
+ text->editing = TRUE;
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
+ text->xofs_edit = 0;
+ }
+ } else {
+ text->editing = FALSE;
+ }
+ calc_line_widths (text);
+ }
+ return_val = 0;
+ break;
+ case GDK_KEY_PRESS: /* Fall Through */
+ case GDK_KEY_RELEASE:
+ if (text->editing) {
+ GdkEventKey key = event->key;
+ e_tep_event.key.time = key.time;
+ e_tep_event.key.state = key.state;
+ e_tep_event.key.keyval = key.keyval;
+ e_tep_event.key.length = key.length;
+ e_tep_event.key.string = key.string;
+ _get_tep(text);
+ return e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ else
+ return 0;
+ break;
+ case GDK_BUTTON_PRESS: /* Fall Through */
+ case GDK_BUTTON_RELEASE:
+ if (text->editing) {
+ GdkEventButton button = event->button;
+ e_tep_event.button.time = button.time;
+ e_tep_event.button.state = button.state;
+ e_tep_event.button.button = button.button;
+ e_tep_event.button.position = _get_position_from_xy(text, button.x, button.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ } else if (text->editable && event->type == GDK_BUTTON_RELEASE) {
+ gnome_canvas_item_grab_focus (item);
+ return 1;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (text->editing) {
+ GdkEventMotion motion = event->motion;
+ e_tep_event.motion.time = motion.time;
+ e_tep_event.motion.state = motion.state;
+ e_tep_event.motion.position = _get_position_from_xy(text, motion.x, motion.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ break;
+ default:
+ break;
+ }
+ if (return_val)
+ return return_val;
+ if (GNOME_CANVAS_ITEM_CLASS(parent_class)->event)
+ return GNOME_CANVAS_ITEM_CLASS(parent_class)->event(item, event);
+ else
+ return 0;
+}
+
+static int
+_get_position(EText *text, ETextEventProcessorCommand *command)
+{
+ int i;
+ int length;
+
+ switch (command->position) {
+
+ case E_TEP_VALUE:
+ return command->value;
+
+ case E_TEP_SELECTION:
+ return text->selection_end;
+
+ case E_TEP_START_OF_BUFFER:
+ return 0;
+ case E_TEP_END_OF_BUFFER:
+ return strlen(text->text);
+
+ case E_TEP_START_OF_LINE:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (text->text[i] == '\n') {
+ i++;
+ break;
+ }
+ return i;
+ case E_TEP_END_OF_LINE:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (text->text[i] == '\n') {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+
+ case E_TEP_FORWARD_CHARACTER:
+ length = strlen(text->text);
+ i = text->selection_end + 1;
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_CHARACTER:
+ i = text->selection_end - 1;
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_WORD:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (isspace(text->text[i])) {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_WORD:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (isspace(text->text[i])) {
+ i++;
+ break;
+ }
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_LINE:
+ case E_TEP_BACKWARD_LINE:
+
+ case E_TEP_FORWARD_PARAGRAPH:
+ case E_TEP_BACKWARD_PARAGRAPH:
+
+ case E_TEP_FORWARD_PAGE:
+ case E_TEP_BACKWARD_PAGE:
+ return text->selection_end;
+ default:
+ return text->selection_end;
+ }
+}
+
+static void
+_delete_selection(EText *text)
+{
+ gint length = strlen(text->text);
+ if (text->selection_end == text->selection_start)
+ return;
+ if (text->selection_end < text->selection_start) {
+ text->selection_end ^= text->selection_start;
+ text->selection_start ^= text->selection_end;
+ text->selection_end ^= text->selection_start;
+ }
+ memmove( text->text + text->selection_start,
+ text->text + text->selection_end,
+ length - text->selection_end + 1 );
+ length -= text->selection_end - text->selection_start;
+ text->selection_end = text->selection_start;
+}
+
+static void
+_insert(EText *text, char *string, int value)
+{
+ if (value > 0) {
+ char *temp;
+ gint length = strlen(text->text);
+ temp = g_new(gchar, length + value + 1);
+ strncpy(temp, text->text, text->selection_start);
+ strncpy(temp + text->selection_start, string, value);
+ strcpy(temp + text->selection_start + value, text->text + text->selection_start);
+ g_free(text->text);
+ text->text = temp;
+ text->selection_start += value;
+ text->selection_end = text->selection_start;
+ }
+}
+
+static void
+e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data)
+{
+ EText *text = E_TEXT(data);
+ switch (command->action) {
+ case E_TEP_MOVE:
+ text->selection_start = _get_position(text, command);
+ text->selection_end = text->selection_start;
+ break;
+ case E_TEP_SELECT:
+ text->selection_end = _get_position(text, command);
+ break;
+ case E_TEP_DELETE:
+ if (text->selection_end == text->selection_start) {
+ text->selection_end = _get_position(text, command);
+ }
+ _delete_selection(text);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+
+ case E_TEP_INSERT:
+ if (text->selection_end != text->selection_start) {
+ _delete_selection(text);
+ }
+ _insert(text, command->string, command->value);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+ case E_TEP_COPY:
+ if (text->selection_end != text->selection_start) {
+ }
+ break;
+ case E_TEP_PASTE:
+ break;
+ case E_TEP_ACTIVATE:
+ break;
+ case E_TEP_SET_SELECT_BY_WORD:
+ text->select_by_word = command->value;
+ break;
+ case E_TEP_NOP:
+ break;
+ }
+ gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
+}
+
/* Routines for sucking fonts from the X server */
diff --git a/widgets/e-text.h b/widgets/e-text.h
index e14199f16e..b18b93d7f2 100644
--- a/widgets/e-text.h
+++ b/widgets/e-text.h
@@ -20,6 +20,7 @@
#define E_TEXT_H
#include <gnome.h>
+#include "e-text-event-processor.h"
BEGIN_GNOME_DECLS
@@ -59,8 +60,15 @@ BEGIN_GNOME_DECLS
* text_height double R Used to query the rendered height of the text
*
* These are ignored in the AA version:
+ * editable boolean RW Can this item be edited
* use_ellipsis boolean RW Whether to use ellipsises if text gets cut off. Meaningless if clip == false.
* ellipsis string RW The characters to use as ellipsis. NULL = "...".
+ *
+ * These are not implemented yet:
+ * multi_line boolean RW Line wrap when not editing.
+ * multi_line_on_edit boolean RW Switch to line wrap when editing.
+ * background boolean RW Draw a background rectangle.
+ * background_on_edit boolean RW Draw a background when editing.
*/
#define E_TYPE_TEXT (e_text_get_type ())
@@ -129,6 +137,18 @@ struct _EText {
char *ellipsis; /* The ellipsis characters. NULL = "...". */
double ellipsis_width; /* The width of the ellipsis. */
gboolean use_ellipsis; /* Whether to use the ellipsis. */
+
+ gboolean editable; /* Item is editable */
+ gboolean editing; /* Item is currently being edited */
+
+ int xofs_edit; /* Offset because of editing */
+
+ /* This needs to be reworked a bit once we get line wrapping. */
+ int selection_start; /* Start of selection */
+ int selection_end; /* End of selection */
+ gboolean select_by_word; /* Current selection is by word */
+
+ ETextEventProcessor *tep; /* Text Event Processor */
};
struct _ETextClass {
diff --git a/widgets/e-text/e-text-event-processor-emacs-like.c b/widgets/e-text/e-text-event-processor-emacs-like.c
new file mode 100644
index 0000000000..1d7d36d45f
--- /dev/null
+++ b/widgets/e-text/e-text-event-processor-emacs-like.c
@@ -0,0 +1,327 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor-emacs-like.h"
+static void e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *card);
+static void e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass);
+static gint e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+static ETextEventProcessorClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+static const ETextEventProcessorCommand control_keys[26] =
+{
+ { E_TEP_START_OF_LINE, E_TEP_MOVE, 0, "" }, /* a */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_COPY, 0, "" }, /* c */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_END_OF_LINE, E_TEP_MOVE, 0, "" }, /* e */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_END_OF_LINE, E_TEP_DELETE, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_FORWARD_LINE, E_TEP_MOVE, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_BACKWARD_LINE, E_TEP_MOVE, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_START_OF_LINE, E_TEP_DELETE, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* v */
+ { E_TEP_BACKWARD_WORD, E_TEP_DELETE, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+};
+
+static const ETextEventProcessorCommand alt_keys[26] =
+{
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* a */
+ { E_TEP_BACKWARD_WORD, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* c */
+ { E_TEP_FORWARD_WORD, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* e */
+ { E_TEP_FORWARD_WORD, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* v */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+
+};
+
+GtkType
+e_text_event_processor_emacs_like_get_type (void)
+{
+ static GtkType text_event_processor_emacs_like_type = 0;
+
+ if (!text_event_processor_emacs_like_type)
+ {
+ static const GtkTypeInfo text_event_processor_emacs_like_info =
+ {
+ "ETextEventProcessorEmacsLike",
+ sizeof (ETextEventProcessorEmacsLike),
+ sizeof (ETextEventProcessorEmacsLikeClass),
+ (GtkClassInitFunc) e_text_event_processor_emacs_like_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_emacs_like_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_emacs_like_type = gtk_type_unique (e_text_event_processor_get_type (), &text_event_processor_emacs_like_info);
+ }
+
+ return text_event_processor_emacs_like_type;
+}
+
+static void
+e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass)
+{
+ GtkObjectClass *object_class;
+ ETextEventProcessorClass *processor_class;
+
+ object_class = (GtkObjectClass*) klass;
+ processor_class = (ETextEventProcessorClass*) klass;
+
+ parent_class = gtk_type_class (e_text_event_processor_get_type ());
+
+ processor_class->event = e_text_event_processor_emacs_like_event;
+}
+
+static void
+e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *tep)
+{
+}
+
+static gint
+e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ ETextEventProcessorCommand command;
+ ETextEventProcessorEmacsLike *tep_el = E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(tep);
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 1) {
+ if (event->button.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ command.position = E_TEP_VALUE;
+ command.value = event->button.position;
+ tep_el->mouse_down = TRUE;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 1) {
+ tep_el->mouse_down = FALSE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (tep_el->mouse_down) {
+ command.action = E_TEP_SELECT;
+ command.position = E_TEP_VALUE;
+ command.value = event->motion.position;
+ }
+ break;
+ case GDK_KEY_PRESS:
+ {
+ ETextEventProcessorEventKey key = event->key;
+ if (key.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ switch(key.keyval) {
+ case GDK_Home:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_START_OF_BUFFER;
+ else
+ command.position = E_TEP_START_OF_LINE;
+ break;
+ case GDK_End:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_END_OF_BUFFER;
+ else
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Page_Up: command.position = E_TEP_BACKWARD_PAGE; break;
+ case GDK_Page_Down: command.position = E_TEP_FORWARD_PAGE; break;
+ /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
+ case GDK_Up: command.position = E_TEP_BACKWARD_LINE; break;
+ case GDK_Down: command.position = E_TEP_FORWARD_LINE; break;
+ case GDK_Left:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Right:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_FORWARD_WORD;
+ else
+ command.position = E_TEP_FORWARD_CHARACTER;
+ break;
+
+ case GDK_BackSpace:
+ command.action = E_TEP_DELETE;
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Clear:
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Insert:
+ if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_PASTE;
+ command.position = E_TEP_SELECTION;
+ } else if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_COPY;
+ command.position = E_TEP_SELECTION;
+ } else {
+ /* gtk_toggle_insert(text) -- IMPLEMENT */
+ }
+ break;
+ case GDK_Delete:
+ if (key.state & GDK_CONTROL_MASK){
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_WORD;
+ } else if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_COPY;
+
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_CHARACTER;
+ }
+ break;
+ case GDK_Tab:
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\t";
+ break;
+ case GDK_Return:
+ if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_ACTIVATE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\n";
+ }
+ break;
+ case GDK_Escape:
+ command.action = E_TEP_NOP;
+ command.position = E_TEP_SELECTION;
+ /* Don't insert literally */
+ break;
+
+ default:
+ if (key.state & GDK_CONTROL_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = control_keys[(int) (key.keyval - 'a')].position;
+ if (control_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = control_keys[(int) (key.keyval - 'a')].action;
+ command.value = control_keys[(int) (key.keyval - 'a')].value;
+ command.string = control_keys[(int) (key.keyval - 'a')].string;
+ }
+
+ if (key.keyval == 'x') {
+ }
+
+ break;
+ } else if (key.state & GDK_MOD1_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = alt_keys[(int) (key.keyval - 'a')].position;
+ if (alt_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = alt_keys[(int) (key.keyval - 'a')].action;
+ command.value = alt_keys[(int) (key.keyval - 'a')].value;
+ command.string = alt_keys[(int) (key.keyval - 'a')].string;
+ }
+ } else if (key.length > 0) {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = strlen(key.string);
+ command.string = key.string;
+
+ } else {
+ command.action = E_TEP_NOP;
+ }
+ }
+ break;
+ case GDK_KEY_RELEASE:
+ command.action = E_TEP_NOP;
+ break;
+ default:
+ command.action = E_TEP_NOP;
+ break;
+ }
+ }
+ if (command.action != E_TEP_NOP) {
+ gtk_signal_emit_by_name (GTK_OBJECT (tep), "command", &command);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ETextEventProcessor *
+e_text_event_processor_emacs_like_new (void)
+{
+ ETextEventProcessorEmacsLike *retval = gtk_type_new (e_text_event_processor_emacs_like_get_type ());
+ return E_TEXT_EVENT_PROCESSOR (retval);
+}
+
diff --git a/widgets/e-text/e-text-event-processor-emacs-like.h b/widgets/e-text/e-text-event-processor-emacs-like.h
new file mode 100644
index 0000000000..651bb552b3
--- /dev/null
+++ b/widgets/e-text/e-text-event-processor-emacs-like.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor-emacs-like.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+#define __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessorEmacsLike - Turns events on a text widget into commands. Uses an emacs-ish interface.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE (e_text_event_processor_emacs_like_get_type ())
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLike))
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLikeClass))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+
+
+typedef struct _ETextEventProcessorEmacsLike ETextEventProcessorEmacsLike;
+typedef struct _ETextEventProcessorEmacsLikeClass ETextEventProcessorEmacsLikeClass;
+
+struct _ETextEventProcessorEmacsLike
+{
+ ETextEventProcessor parent;
+
+ /* object specific fields */
+ gboolean mouse_down;
+};
+
+struct _ETextEventProcessorEmacsLikeClass
+{
+ ETextEventProcessorClass parent_class;
+};
+
+
+GtkType e_text_event_processor_emacs_like_get_type (void);
+ETextEventProcessor *e_text_event_processor_emacs_like_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__ */
diff --git a/widgets/e-text/e-text-event-processor-types.h b/widgets/e-text/e-text-event-processor-types.h
new file mode 100644
index 0000000000..30b7bcafc9
--- /dev/null
+++ b/widgets/e-text/e-text-event-processor-types.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+#define __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <gdk/gdktypes.h>
+
+typedef enum _ETextEventProcessorCommandPosition ETextEventProcessorCommandPosition;
+typedef enum _ETextEventProcessorCommandAction ETextEventProcessorCommandAction;
+typedef struct _ETextEventProcessorCommand ETextEventProcessorCommand;
+
+typedef union _ETextEventProcessorEvent ETextEventProcessorEvent;
+typedef struct _ETextEventProcessorEventButton ETextEventProcessorEventButton;
+typedef struct _ETextEventProcessorEventKey ETextEventProcessorEventKey;
+typedef struct _ETextEventProcessorEventMotion ETextEventProcessorEventMotion;
+
+enum _ETextEventProcessorCommandPosition {
+ E_TEP_VALUE,
+ E_TEP_SELECTION,
+
+ E_TEP_START_OF_BUFFER,
+ E_TEP_END_OF_BUFFER,
+
+ E_TEP_START_OF_LINE,
+ E_TEP_END_OF_LINE,
+
+ E_TEP_FORWARD_CHARACTER,
+ E_TEP_BACKWARD_CHARACTER,
+
+ E_TEP_FORWARD_WORD,
+ E_TEP_BACKWARD_WORD,
+
+ E_TEP_FORWARD_LINE,
+ E_TEP_BACKWARD_LINE,
+
+ E_TEP_FORWARD_PARAGRAPH,
+ E_TEP_BACKWARD_PARAGRAPH,
+
+ E_TEP_FORWARD_PAGE,
+ E_TEP_BACKWARD_PAGE
+};
+
+enum _ETextEventProcessorCommandAction {
+ E_TEP_MOVE,
+ E_TEP_SELECT,
+ E_TEP_DELETE,
+
+ E_TEP_INSERT,
+ E_TEP_COPY,
+ E_TEP_PASTE,
+ E_TEP_SET_SELECT_BY_WORD,
+ E_TEP_ACTIVATE,
+
+ E_TEP_NOP
+};
+
+struct _ETextEventProcessorCommand {
+ ETextEventProcessorCommandPosition position;
+ ETextEventProcessorCommandAction action;
+ int value;
+ char *string;
+};
+
+struct _ETextEventProcessorEventButton {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint button;
+ gint position;
+};
+
+struct _ETextEventProcessorEventKey {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint keyval;
+ gint length;
+ gchar *string;
+};
+
+struct _ETextEventProcessorEventMotion {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ gint position;
+};
+
+union _ETextEventProcessorEvent {
+ GdkEventType type;
+ ETextEventProcessorEventButton button;
+ ETextEventProcessorEventKey key;
+ ETextEventProcessorEventMotion motion;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_TYPES_H__ */
diff --git a/widgets/e-text/e-text-event-processor.c b/widgets/e-text/e-text-event-processor.c
new file mode 100644
index 0000000000..47f028ca62
--- /dev/null
+++ b/widgets/e-text/e-text-event-processor.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+static void e_text_event_processor_init (ETextEventProcessor *card);
+static void e_text_event_processor_class_init (ETextEventProcessorClass *klass);
+
+static GtkObjectClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+enum {
+ E_TEP_EVENT,
+ E_TEP_LAST_SIGNAL
+};
+
+static guint e_tep_signals[E_TEP_LAST_SIGNAL] = { 0 };
+
+GtkType
+e_text_event_processor_get_type (void)
+{
+ static GtkType text_event_processor_type = 0;
+
+ if (!text_event_processor_type)
+ {
+ static const GtkTypeInfo text_event_processor_info =
+ {
+ "ETextEventProcessor",
+ sizeof (ETextEventProcessor),
+ sizeof (ETextEventProcessorClass),
+ (GtkClassInitFunc) e_text_event_processor_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_type = gtk_type_unique (gtk_object_get_type (), &text_event_processor_info);
+ }
+
+ return text_event_processor_type;
+}
+
+static void
+e_text_event_processor_class_init (ETextEventProcessorClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ e_tep_signals[E_TEP_EVENT] =
+ gtk_signal_new ("command",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (ETextEventProcessorClass, command),
+ gtk_marshal_NONE__POINTER,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ gtk_object_class_add_signals (object_class, e_tep_signals, E_TEP_LAST_SIGNAL);
+
+ klass->event = NULL;
+ klass->command = NULL;
+}
+
+static void
+e_text_event_processor_init (ETextEventProcessor *tep)
+{
+}
+
+gint
+e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ if (E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event) {
+ return E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event(tep, event);
+ } else {
+ return 0;
+ }
+}
diff --git a/widgets/e-text/e-text-event-processor.h b/widgets/e-text/e-text-event-processor.h
new file mode 100644
index 0000000000..1fc79f3f70
--- /dev/null
+++ b/widgets/e-text/e-text-event-processor.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_H__
+#define __E_TEXT_EVENT_PROCESSOR_H__
+
+#include <gnome.h>
+#include "e-text-event-processor-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessor - Turns events on a text widget into commands.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_TYPE (e_text_event_processor_get_type ())
+#define E_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessor))
+#define E_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
+#define E_IS_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+
+
+typedef struct _ETextEventProcessor ETextEventProcessor;
+typedef struct _ETextEventProcessorClass ETextEventProcessorClass;
+
+struct _ETextEventProcessor
+{
+ GtkObject parent;
+
+ /* object specific fields */
+
+};
+
+struct _ETextEventProcessorClass
+{
+ GtkObjectClass parent_class;
+
+ /* signals */
+ void (* command) (ETextEventProcessor *tep, ETextEventProcessorCommand *command);
+
+ /* virtual functions */
+ gint (* event) (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+};
+
+
+GtkType e_text_event_processor_get_type (void);
+gint e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_H__ */
diff --git a/widgets/e-text/e-text.c b/widgets/e-text/e-text.c
index b88130e3c8..f6daa3f3cf 100644
--- a/widgets/e-text/e-text.c
+++ b/widgets/e-text/e-text.c
@@ -18,12 +18,15 @@
#include <config.h>
#include <math.h>
+#include <ctype.h>
#include "e-text.h"
#include <gdk/gdkx.h> /* for BlackPixel */
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_rgb.h>
#include <libart_lgpl/art_rgb_bitmap_affine.h>
+#include "e-text-event-processor-emacs-like.h"
+
/* This defines a line of text */
@@ -58,6 +61,7 @@ enum {
ARG_FILL_STIPPLE,
ARG_TEXT_WIDTH,
ARG_TEXT_HEIGHT,
+ ARG_EDITABLE,
ARG_USE_ELLIPSIS,
ARG_ELLIPSIS
};
@@ -80,6 +84,9 @@ static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, i
static void e_text_bounds (GnomeCanvasItem *item,
double *x1, double *y1, double *x2, double *y2);
static void e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static gint e_text_event (GnomeCanvasItem *item, GdkEvent *event);
+
+static void e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
static ETextSuckFont *e_suck_font (GdkFont *font);
static void e_suck_font_free (ETextSuckFont *suckfont);
@@ -171,6 +178,8 @@ e_text_class_init (ETextClass *class)
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_WIDTH);
gtk_object_add_arg_type ("EText::text_height",
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_HEIGHT);
+ gtk_object_add_arg_type ("EText::editable",
+ GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
gtk_object_add_arg_type ("EText::use_ellipsis",
GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS);
gtk_object_add_arg_type ("EText::ellipsis",
@@ -187,6 +196,7 @@ e_text_class_init (ETextClass *class)
item_class->point = e_text_point;
item_class->bounds = e_text_bounds;
item_class->render = e_text_render;
+ item_class->event = e_text_event;
}
/* Object initialization function for the text item */
@@ -201,9 +211,18 @@ e_text_init (EText *text)
text->clip_height = 0.0;
text->xofs = 0.0;
text->yofs = 0.0;
+
text->ellipsis = NULL;
text->use_ellipsis = FALSE;
text->ellipsis_width = 0;
+
+ text->editable = FALSE;
+ text->editing = FALSE;
+ text->xofs_edit = 0;
+
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
}
/* Destroy handler for the text item */
@@ -456,7 +475,8 @@ calc_line_widths (EText *text)
}
if (text->clip &&
- text->use_ellipsis &&
+ text->use_ellipsis &&
+ ! text->editing &&
lines->width > text->clip_width) {
if (text->font) {
lines->ellipsis_length = 0;
@@ -729,6 +749,10 @@ e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE);
break;
+ case ARG_EDITABLE:
+ text->editable = GTK_VALUE_BOOL (*arg);
+ break;
+
case ARG_USE_ELLIPSIS:
text->use_ellipsis = GTK_VALUE_BOOL (*arg);
calc_line_widths (text);
@@ -839,6 +863,10 @@ e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit;
break;
+ case ARG_EDITABLE:
+ GTK_VALUE_BOOL (*arg) = text->editable;
+ break;
+
case ARG_USE_ELLIPSIS:
GTK_VALUE_BOOL (*arg) = text->use_ellipsis;
break;
@@ -1016,6 +1044,19 @@ get_line_xpos (EText *text, struct line *line)
return x;
}
+static void
+_get_tep(EText *text)
+{
+ if (!text->tep) {
+ text->tep = e_text_event_processor_emacs_like_new();
+ gtk_signal_connect(GTK_OBJECT(text->tep),
+ "command",
+ GTK_SIGNAL_FUNC(e_text_command),
+ (gpointer) text);
+
+ }
+}
+
/* Draw handler for the text item */
static void
e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
@@ -1026,8 +1067,14 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
struct line *lines;
int i;
int xpos, ypos;
+ int start_char, end_char;
+ int sel_start, sel_end;
+ GdkRectangle sel_rect;
+ GdkGC *fg_gc;
+ GnomeCanvas *canvas;
text = E_TEXT (item);
+ canvas = GNOME_CANVAS_ITEM(text)->canvas;
if (!text->text || !text->font)
return;
@@ -1039,6 +1086,7 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
rect.height = text->clip_cheight;
gdk_gc_set_clip_rectangle (text->gc, &rect);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED], &rect);
}
lines = text->lines;
ypos = text->cy + text->font->ascent;
@@ -1049,39 +1097,122 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
for (i = 0; i < text->num_lines; i++) {
if (lines->length != 0) {
xpos = get_line_xpos (text, lines);
- if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->ellipsis_length);
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x +
- lines->width - text->ellipsis_width,
- ypos - y,
- text->ellipsis ? text->ellipsis : "...",
- text->ellipsis ? strlen (text->ellipsis) : 3);
- } else
-
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->length);
+ if (text->editing) {
+ xpos -= text->xofs_edit;
+ start_char = lines->text - text->text;
+ end_char = start_char + lines->length;
+ sel_start = text->selection_start;
+ sel_end = text->selection_end;
+ if (sel_start > sel_end ) {
+ sel_start ^= sel_end;
+ sel_end ^= sel_start;
+ sel_start ^= sel_end;
+ }
+ if ( sel_start < start_char )
+ sel_start = start_char;
+ if ( sel_end > end_char )
+ sel_end = end_char;
+ if ( sel_start < sel_end ) {
+ sel_rect.x = xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char);
+ sel_rect.y = ypos - y - text->font->ascent;
+ sel_rect.width = gdk_text_width (text->font,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ sel_rect.height = text->font->ascent + text->font->descent;
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ sel_rect.x,
+ sel_rect.y,
+ sel_rect.width,
+ sel_rect.height);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ sel_start - start_char);
+ fg_gc = GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED];
+ gdk_draw_text (drawable,
+ text->font,
+ fg_gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_end - start_char),
+ ypos - y,
+ lines->text + sel_end - start_char,
+ end_char - sel_end);
+ } else {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
+ if (text->selection_start == text->selection_end &&
+ text->selection_start >= start_char &&
+ text->selection_start <= end_char) {
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y - text->font->ascent,
+ 1,
+ text->font->ascent + text->font->descent);
+ }
+ } else {
+ if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->ellipsis_length);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x +
+ lines->width - text->ellipsis_width,
+ ypos - y,
+ text->ellipsis ? text->ellipsis : "...",
+ text->ellipsis ? strlen (text->ellipsis) : 3);
+ } else
+
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
}
ypos += text->font->ascent + text->font->descent;
lines++;
}
- if (text->clip)
+ if (text->clip) {
gdk_gc_set_clip_rectangle (text->gc, NULL);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(GNOME_CANVAS_ITEM(text)->canvas)->style->fg_gc[GTK_STATE_SELECTED], NULL);
+ }
}
/* Render handler for the text item */
@@ -1308,6 +1439,285 @@ e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double
*y2 = *y1 + height;
}
+static gint
+_get_position_from_xy (EText *text, gint x, gint y)
+{
+ int i, j;
+ int ypos = text->cy;
+ int xpos;
+ struct line *lines;
+ j = 0;
+ while (y > ypos)
+ {
+ ypos += text->font->ascent + text->font->descent;
+ j ++;
+ }
+ j--;
+ if (j >= text->num_lines)
+ j = text->num_lines - 1;
+ if (j < 0)
+ j = 0;
+ i = 0;
+ lines = text->lines;
+ lines += j;
+ xpos = get_line_xpos (text, lines);
+ for(i = 0; i < lines->length; i++) {
+ int charwidth = gdk_text_width(text->font,
+ lines->text + i,
+ 1);
+ xpos += charwidth / 2;
+ if (xpos > x)
+ break;
+ xpos += (charwidth + 1) / 2;
+ }
+ return lines->text + i - text->text;
+}
+
+static gint
+e_text_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EText *text = E_TEXT(item);
+ ETextEventProcessorEvent e_tep_event;
+
+ gint return_val;
+
+ e_tep_event.type = event->type;
+ switch (event->type) {
+ case GDK_FOCUS_CHANGE:
+ if (text->editable) {
+ GdkEventFocus *focus_event;
+ focus_event = (GdkEventFocus *) event;
+ if (focus_event->in) {
+ if(!text->editing) {
+ text->editing = TRUE;
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
+ text->xofs_edit = 0;
+ }
+ } else {
+ text->editing = FALSE;
+ }
+ calc_line_widths (text);
+ }
+ return_val = 0;
+ break;
+ case GDK_KEY_PRESS: /* Fall Through */
+ case GDK_KEY_RELEASE:
+ if (text->editing) {
+ GdkEventKey key = event->key;
+ e_tep_event.key.time = key.time;
+ e_tep_event.key.state = key.state;
+ e_tep_event.key.keyval = key.keyval;
+ e_tep_event.key.length = key.length;
+ e_tep_event.key.string = key.string;
+ _get_tep(text);
+ return e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ else
+ return 0;
+ break;
+ case GDK_BUTTON_PRESS: /* Fall Through */
+ case GDK_BUTTON_RELEASE:
+ if (text->editing) {
+ GdkEventButton button = event->button;
+ e_tep_event.button.time = button.time;
+ e_tep_event.button.state = button.state;
+ e_tep_event.button.button = button.button;
+ e_tep_event.button.position = _get_position_from_xy(text, button.x, button.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ } else if (text->editable && event->type == GDK_BUTTON_RELEASE) {
+ gnome_canvas_item_grab_focus (item);
+ return 1;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (text->editing) {
+ GdkEventMotion motion = event->motion;
+ e_tep_event.motion.time = motion.time;
+ e_tep_event.motion.state = motion.state;
+ e_tep_event.motion.position = _get_position_from_xy(text, motion.x, motion.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ break;
+ default:
+ break;
+ }
+ if (return_val)
+ return return_val;
+ if (GNOME_CANVAS_ITEM_CLASS(parent_class)->event)
+ return GNOME_CANVAS_ITEM_CLASS(parent_class)->event(item, event);
+ else
+ return 0;
+}
+
+static int
+_get_position(EText *text, ETextEventProcessorCommand *command)
+{
+ int i;
+ int length;
+
+ switch (command->position) {
+
+ case E_TEP_VALUE:
+ return command->value;
+
+ case E_TEP_SELECTION:
+ return text->selection_end;
+
+ case E_TEP_START_OF_BUFFER:
+ return 0;
+ case E_TEP_END_OF_BUFFER:
+ return strlen(text->text);
+
+ case E_TEP_START_OF_LINE:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (text->text[i] == '\n') {
+ i++;
+ break;
+ }
+ return i;
+ case E_TEP_END_OF_LINE:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (text->text[i] == '\n') {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+
+ case E_TEP_FORWARD_CHARACTER:
+ length = strlen(text->text);
+ i = text->selection_end + 1;
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_CHARACTER:
+ i = text->selection_end - 1;
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_WORD:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (isspace(text->text[i])) {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_WORD:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (isspace(text->text[i])) {
+ i++;
+ break;
+ }
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_LINE:
+ case E_TEP_BACKWARD_LINE:
+
+ case E_TEP_FORWARD_PARAGRAPH:
+ case E_TEP_BACKWARD_PARAGRAPH:
+
+ case E_TEP_FORWARD_PAGE:
+ case E_TEP_BACKWARD_PAGE:
+ return text->selection_end;
+ default:
+ return text->selection_end;
+ }
+}
+
+static void
+_delete_selection(EText *text)
+{
+ gint length = strlen(text->text);
+ if (text->selection_end == text->selection_start)
+ return;
+ if (text->selection_end < text->selection_start) {
+ text->selection_end ^= text->selection_start;
+ text->selection_start ^= text->selection_end;
+ text->selection_end ^= text->selection_start;
+ }
+ memmove( text->text + text->selection_start,
+ text->text + text->selection_end,
+ length - text->selection_end + 1 );
+ length -= text->selection_end - text->selection_start;
+ text->selection_end = text->selection_start;
+}
+
+static void
+_insert(EText *text, char *string, int value)
+{
+ if (value > 0) {
+ char *temp;
+ gint length = strlen(text->text);
+ temp = g_new(gchar, length + value + 1);
+ strncpy(temp, text->text, text->selection_start);
+ strncpy(temp + text->selection_start, string, value);
+ strcpy(temp + text->selection_start + value, text->text + text->selection_start);
+ g_free(text->text);
+ text->text = temp;
+ text->selection_start += value;
+ text->selection_end = text->selection_start;
+ }
+}
+
+static void
+e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data)
+{
+ EText *text = E_TEXT(data);
+ switch (command->action) {
+ case E_TEP_MOVE:
+ text->selection_start = _get_position(text, command);
+ text->selection_end = text->selection_start;
+ break;
+ case E_TEP_SELECT:
+ text->selection_end = _get_position(text, command);
+ break;
+ case E_TEP_DELETE:
+ if (text->selection_end == text->selection_start) {
+ text->selection_end = _get_position(text, command);
+ }
+ _delete_selection(text);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+
+ case E_TEP_INSERT:
+ if (text->selection_end != text->selection_start) {
+ _delete_selection(text);
+ }
+ _insert(text, command->string, command->value);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+ case E_TEP_COPY:
+ if (text->selection_end != text->selection_start) {
+ }
+ break;
+ case E_TEP_PASTE:
+ break;
+ case E_TEP_ACTIVATE:
+ break;
+ case E_TEP_SET_SELECT_BY_WORD:
+ text->select_by_word = command->value;
+ break;
+ case E_TEP_NOP:
+ break;
+ }
+ gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
+}
+
/* Routines for sucking fonts from the X server */
diff --git a/widgets/e-text/e-text.h b/widgets/e-text/e-text.h
index e14199f16e..b18b93d7f2 100644
--- a/widgets/e-text/e-text.h
+++ b/widgets/e-text/e-text.h
@@ -20,6 +20,7 @@
#define E_TEXT_H
#include <gnome.h>
+#include "e-text-event-processor.h"
BEGIN_GNOME_DECLS
@@ -59,8 +60,15 @@ BEGIN_GNOME_DECLS
* text_height double R Used to query the rendered height of the text
*
* These are ignored in the AA version:
+ * editable boolean RW Can this item be edited
* use_ellipsis boolean RW Whether to use ellipsises if text gets cut off. Meaningless if clip == false.
* ellipsis string RW The characters to use as ellipsis. NULL = "...".
+ *
+ * These are not implemented yet:
+ * multi_line boolean RW Line wrap when not editing.
+ * multi_line_on_edit boolean RW Switch to line wrap when editing.
+ * background boolean RW Draw a background rectangle.
+ * background_on_edit boolean RW Draw a background when editing.
*/
#define E_TYPE_TEXT (e_text_get_type ())
@@ -129,6 +137,18 @@ struct _EText {
char *ellipsis; /* The ellipsis characters. NULL = "...". */
double ellipsis_width; /* The width of the ellipsis. */
gboolean use_ellipsis; /* Whether to use the ellipsis. */
+
+ gboolean editable; /* Item is editable */
+ gboolean editing; /* Item is currently being edited */
+
+ int xofs_edit; /* Offset because of editing */
+
+ /* This needs to be reworked a bit once we get line wrapping. */
+ int selection_start; /* Start of selection */
+ int selection_end; /* End of selection */
+ gboolean select_by_word; /* Current selection is by word */
+
+ ETextEventProcessor *tep; /* Text Event Processor */
};
struct _ETextClass {
diff --git a/widgets/test-minicard.c b/widgets/test-minicard.c
index 4f56fbe936..79077c4b2d 100644
--- a/widgets/test-minicard.c
+++ b/widgets/test-minicard.c
@@ -61,11 +61,6 @@ static void about_callback( GtkWidget *widget, gpointer data )
gtk_widget_show (about);
}
-static void button_press_callback( GtkWidget *widget, gpointer data )
-{
- gnome_canvas_item_grab_focus( card );
-}
-
int main( int argc, char *argv[] )
{
GtkWidget *app;
@@ -102,7 +97,6 @@ int main( int argc, char *argv[] )
gnome_app_set_contents( GNOME_APP( app ), canvas );
-
/* Connect the signals */
gtk_signal_connect( GTK_OBJECT( app ), "destroy",
GTK_SIGNAL_FUNC( destroy_callback ),
@@ -112,10 +106,6 @@ int main( int argc, char *argv[] )
GTK_SIGNAL_FUNC( allocate_callback ),
( gpointer ) app );
- gtk_signal_connect( GTK_OBJECT( canvas ), "button_press_event",
- GTK_SIGNAL_FUNC( button_press_callback ),
- ( gpointer ) app );
-
gtk_widget_show_all( app );
gtk_main();
diff --git a/widgets/text/e-text-event-processor-emacs-like.c b/widgets/text/e-text-event-processor-emacs-like.c
new file mode 100644
index 0000000000..1d7d36d45f
--- /dev/null
+++ b/widgets/text/e-text-event-processor-emacs-like.c
@@ -0,0 +1,327 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor-emacs-like.h"
+static void e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *card);
+static void e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass);
+static gint e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+static ETextEventProcessorClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+static const ETextEventProcessorCommand control_keys[26] =
+{
+ { E_TEP_START_OF_LINE, E_TEP_MOVE, 0, "" }, /* a */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_COPY, 0, "" }, /* c */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_END_OF_LINE, E_TEP_MOVE, 0, "" }, /* e */
+ { E_TEP_FORWARD_CHARACTER, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_BACKWARD_CHARACTER, E_TEP_DELETE, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_END_OF_LINE, E_TEP_DELETE, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_FORWARD_LINE, E_TEP_MOVE, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_BACKWARD_LINE, E_TEP_MOVE, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_START_OF_LINE, E_TEP_DELETE, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* v */
+ { E_TEP_BACKWARD_WORD, E_TEP_DELETE, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_PASTE, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+};
+
+static const ETextEventProcessorCommand alt_keys[26] =
+{
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* a */
+ { E_TEP_BACKWARD_WORD, E_TEP_MOVE, 0, "" }, /* b */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* c */
+ { E_TEP_FORWARD_WORD, E_TEP_DELETE, 0, "" }, /* d */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* e */
+ { E_TEP_FORWARD_WORD, E_TEP_MOVE, 0, "" }, /* f */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* g */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* h */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* i */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* j */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* k */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* l */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* m */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* n */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* o */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* p */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* q */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* r */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* s */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* t */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* u */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* v */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* w */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* x */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" }, /* y */
+ { E_TEP_SELECTION, E_TEP_NOP, 0, "" } /* z */
+
+};
+
+GtkType
+e_text_event_processor_emacs_like_get_type (void)
+{
+ static GtkType text_event_processor_emacs_like_type = 0;
+
+ if (!text_event_processor_emacs_like_type)
+ {
+ static const GtkTypeInfo text_event_processor_emacs_like_info =
+ {
+ "ETextEventProcessorEmacsLike",
+ sizeof (ETextEventProcessorEmacsLike),
+ sizeof (ETextEventProcessorEmacsLikeClass),
+ (GtkClassInitFunc) e_text_event_processor_emacs_like_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_emacs_like_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_emacs_like_type = gtk_type_unique (e_text_event_processor_get_type (), &text_event_processor_emacs_like_info);
+ }
+
+ return text_event_processor_emacs_like_type;
+}
+
+static void
+e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass *klass)
+{
+ GtkObjectClass *object_class;
+ ETextEventProcessorClass *processor_class;
+
+ object_class = (GtkObjectClass*) klass;
+ processor_class = (ETextEventProcessorClass*) klass;
+
+ parent_class = gtk_type_class (e_text_event_processor_get_type ());
+
+ processor_class->event = e_text_event_processor_emacs_like_event;
+}
+
+static void
+e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike *tep)
+{
+}
+
+static gint
+e_text_event_processor_emacs_like_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ ETextEventProcessorCommand command;
+ ETextEventProcessorEmacsLike *tep_el = E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(tep);
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (event->button.button == 1) {
+ if (event->button.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ command.position = E_TEP_VALUE;
+ command.value = event->button.position;
+ tep_el->mouse_down = TRUE;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 1) {
+ tep_el->mouse_down = FALSE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (tep_el->mouse_down) {
+ command.action = E_TEP_SELECT;
+ command.position = E_TEP_VALUE;
+ command.value = event->motion.position;
+ }
+ break;
+ case GDK_KEY_PRESS:
+ {
+ ETextEventProcessorEventKey key = event->key;
+ if (key.state & GDK_SHIFT_MASK)
+ command.action = E_TEP_SELECT;
+ else
+ command.action = E_TEP_MOVE;
+ switch(key.keyval) {
+ case GDK_Home:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_START_OF_BUFFER;
+ else
+ command.position = E_TEP_START_OF_LINE;
+ break;
+ case GDK_End:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_END_OF_BUFFER;
+ else
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Page_Up: command.position = E_TEP_BACKWARD_PAGE; break;
+ case GDK_Page_Down: command.position = E_TEP_FORWARD_PAGE; break;
+ /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
+ case GDK_Up: command.position = E_TEP_BACKWARD_LINE; break;
+ case GDK_Down: command.position = E_TEP_FORWARD_LINE; break;
+ case GDK_Left:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Right:
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_FORWARD_WORD;
+ else
+ command.position = E_TEP_FORWARD_CHARACTER;
+ break;
+
+ case GDK_BackSpace:
+ command.action = E_TEP_DELETE;
+ if (key.state & GDK_CONTROL_MASK)
+ command.position = E_TEP_BACKWARD_WORD;
+ else
+ command.position = E_TEP_BACKWARD_CHARACTER;
+ break;
+ case GDK_Clear:
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_END_OF_LINE;
+ break;
+ case GDK_Insert:
+ if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_PASTE;
+ command.position = E_TEP_SELECTION;
+ } else if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_COPY;
+ command.position = E_TEP_SELECTION;
+ } else {
+ /* gtk_toggle_insert(text) -- IMPLEMENT */
+ }
+ break;
+ case GDK_Delete:
+ if (key.state & GDK_CONTROL_MASK){
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_WORD;
+ } else if (key.state & GDK_SHIFT_MASK) {
+ command.action = E_TEP_COPY;
+
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_DELETE;
+ command.position = E_TEP_FORWARD_CHARACTER;
+ }
+ break;
+ case GDK_Tab:
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\t";
+ break;
+ case GDK_Return:
+ if (key.state & GDK_CONTROL_MASK) {
+ command.action = E_TEP_ACTIVATE;
+ command.position = E_TEP_SELECTION;
+ } else {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = 1;
+ command.string = "\n";
+ }
+ break;
+ case GDK_Escape:
+ command.action = E_TEP_NOP;
+ command.position = E_TEP_SELECTION;
+ /* Don't insert literally */
+ break;
+
+ default:
+ if (key.state & GDK_CONTROL_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = control_keys[(int) (key.keyval - 'a')].position;
+ if (control_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = control_keys[(int) (key.keyval - 'a')].action;
+ command.value = control_keys[(int) (key.keyval - 'a')].value;
+ command.string = control_keys[(int) (key.keyval - 'a')].string;
+ }
+
+ if (key.keyval == 'x') {
+ }
+
+ break;
+ } else if (key.state & GDK_MOD1_MASK) {
+ if ((key.keyval >= 'A') && (key.keyval <= 'Z'))
+ key.keyval -= 'A' - 'a';
+
+ if ((key.keyval >= 'a') && (key.keyval <= 'z')) {
+ command.position = alt_keys[(int) (key.keyval - 'a')].position;
+ if (alt_keys[(int) (key.keyval - 'a')].action != E_TEP_MOVE)
+ command.action = alt_keys[(int) (key.keyval - 'a')].action;
+ command.value = alt_keys[(int) (key.keyval - 'a')].value;
+ command.string = alt_keys[(int) (key.keyval - 'a')].string;
+ }
+ } else if (key.length > 0) {
+ command.action = E_TEP_INSERT;
+ command.position = E_TEP_SELECTION;
+ command.value = strlen(key.string);
+ command.string = key.string;
+
+ } else {
+ command.action = E_TEP_NOP;
+ }
+ }
+ break;
+ case GDK_KEY_RELEASE:
+ command.action = E_TEP_NOP;
+ break;
+ default:
+ command.action = E_TEP_NOP;
+ break;
+ }
+ }
+ if (command.action != E_TEP_NOP) {
+ gtk_signal_emit_by_name (GTK_OBJECT (tep), "command", &command);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ETextEventProcessor *
+e_text_event_processor_emacs_like_new (void)
+{
+ ETextEventProcessorEmacsLike *retval = gtk_type_new (e_text_event_processor_emacs_like_get_type ());
+ return E_TEXT_EVENT_PROCESSOR (retval);
+}
+
diff --git a/widgets/text/e-text-event-processor-emacs-like.h b/widgets/text/e-text-event-processor-emacs-like.h
new file mode 100644
index 0000000000..651bb552b3
--- /dev/null
+++ b/widgets/text/e-text-event-processor-emacs-like.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor-emacs-like.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+#define __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessorEmacsLike - Turns events on a text widget into commands. Uses an emacs-ish interface.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE (e_text_event_processor_emacs_like_get_type ())
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLike))
+#define E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE, ETextEventProcessorEmacsLikeClass))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_EMACS_LIKE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_TYPE))
+
+
+typedef struct _ETextEventProcessorEmacsLike ETextEventProcessorEmacsLike;
+typedef struct _ETextEventProcessorEmacsLikeClass ETextEventProcessorEmacsLikeClass;
+
+struct _ETextEventProcessorEmacsLike
+{
+ ETextEventProcessor parent;
+
+ /* object specific fields */
+ gboolean mouse_down;
+};
+
+struct _ETextEventProcessorEmacsLikeClass
+{
+ ETextEventProcessorClass parent_class;
+};
+
+
+GtkType e_text_event_processor_emacs_like_get_type (void);
+ETextEventProcessor *e_text_event_processor_emacs_like_new (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_EMACS_LIKE_H__ */
diff --git a/widgets/text/e-text-event-processor-types.h b/widgets/text/e-text-event-processor-types.h
new file mode 100644
index 0000000000..30b7bcafc9
--- /dev/null
+++ b/widgets/text/e-text-event-processor-types.h
@@ -0,0 +1,131 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+#define __E_TEXT_EVENT_PROCESSOR_TYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <gdk/gdktypes.h>
+
+typedef enum _ETextEventProcessorCommandPosition ETextEventProcessorCommandPosition;
+typedef enum _ETextEventProcessorCommandAction ETextEventProcessorCommandAction;
+typedef struct _ETextEventProcessorCommand ETextEventProcessorCommand;
+
+typedef union _ETextEventProcessorEvent ETextEventProcessorEvent;
+typedef struct _ETextEventProcessorEventButton ETextEventProcessorEventButton;
+typedef struct _ETextEventProcessorEventKey ETextEventProcessorEventKey;
+typedef struct _ETextEventProcessorEventMotion ETextEventProcessorEventMotion;
+
+enum _ETextEventProcessorCommandPosition {
+ E_TEP_VALUE,
+ E_TEP_SELECTION,
+
+ E_TEP_START_OF_BUFFER,
+ E_TEP_END_OF_BUFFER,
+
+ E_TEP_START_OF_LINE,
+ E_TEP_END_OF_LINE,
+
+ E_TEP_FORWARD_CHARACTER,
+ E_TEP_BACKWARD_CHARACTER,
+
+ E_TEP_FORWARD_WORD,
+ E_TEP_BACKWARD_WORD,
+
+ E_TEP_FORWARD_LINE,
+ E_TEP_BACKWARD_LINE,
+
+ E_TEP_FORWARD_PARAGRAPH,
+ E_TEP_BACKWARD_PARAGRAPH,
+
+ E_TEP_FORWARD_PAGE,
+ E_TEP_BACKWARD_PAGE
+};
+
+enum _ETextEventProcessorCommandAction {
+ E_TEP_MOVE,
+ E_TEP_SELECT,
+ E_TEP_DELETE,
+
+ E_TEP_INSERT,
+ E_TEP_COPY,
+ E_TEP_PASTE,
+ E_TEP_SET_SELECT_BY_WORD,
+ E_TEP_ACTIVATE,
+
+ E_TEP_NOP
+};
+
+struct _ETextEventProcessorCommand {
+ ETextEventProcessorCommandPosition position;
+ ETextEventProcessorCommandAction action;
+ int value;
+ char *string;
+};
+
+struct _ETextEventProcessorEventButton {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint button;
+ gint position;
+};
+
+struct _ETextEventProcessorEventKey {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ guint keyval;
+ gint length;
+ gchar *string;
+};
+
+struct _ETextEventProcessorEventMotion {
+ GdkEventType type;
+ guint32 time;
+ guint state;
+ gint position;
+};
+
+union _ETextEventProcessorEvent {
+ GdkEventType type;
+ ETextEventProcessorEventButton button;
+ ETextEventProcessorEventKey key;
+ ETextEventProcessorEventMotion motion;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_TYPES_H__ */
diff --git a/widgets/text/e-text-event-processor.c b/widgets/text/e-text-event-processor.c
new file mode 100644
index 0000000000..47f028ca62
--- /dev/null
+++ b/widgets/text/e-text-event-processor.c
@@ -0,0 +1,103 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.c
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gnome.h>
+#include "e-text-event-processor.h"
+static void e_text_event_processor_init (ETextEventProcessor *card);
+static void e_text_event_processor_class_init (ETextEventProcessorClass *klass);
+
+static GtkObjectClass *parent_class = NULL;
+
+/* The arguments we take */
+enum {
+ ARG_0
+};
+
+enum {
+ E_TEP_EVENT,
+ E_TEP_LAST_SIGNAL
+};
+
+static guint e_tep_signals[E_TEP_LAST_SIGNAL] = { 0 };
+
+GtkType
+e_text_event_processor_get_type (void)
+{
+ static GtkType text_event_processor_type = 0;
+
+ if (!text_event_processor_type)
+ {
+ static const GtkTypeInfo text_event_processor_info =
+ {
+ "ETextEventProcessor",
+ sizeof (ETextEventProcessor),
+ sizeof (ETextEventProcessorClass),
+ (GtkClassInitFunc) e_text_event_processor_class_init,
+ (GtkObjectInitFunc) e_text_event_processor_init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ text_event_processor_type = gtk_type_unique (gtk_object_get_type (), &text_event_processor_info);
+ }
+
+ return text_event_processor_type;
+}
+
+static void
+e_text_event_processor_class_init (ETextEventProcessorClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ e_tep_signals[E_TEP_EVENT] =
+ gtk_signal_new ("command",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (ETextEventProcessorClass, command),
+ gtk_marshal_NONE__POINTER,
+ GTK_TYPE_NONE, 1,
+ GTK_TYPE_POINTER);
+
+ gtk_object_class_add_signals (object_class, e_tep_signals, E_TEP_LAST_SIGNAL);
+
+ klass->event = NULL;
+ klass->command = NULL;
+}
+
+static void
+e_text_event_processor_init (ETextEventProcessor *tep)
+{
+}
+
+gint
+e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event)
+{
+ if (E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event) {
+ return E_TEXT_EVENT_PROCESSOR_CLASS(GTK_OBJECT(tep)->klass)->event(tep, event);
+ } else {
+ return 0;
+ }
+}
diff --git a/widgets/text/e-text-event-processor.h b/widgets/text/e-text-event-processor.h
new file mode 100644
index 0000000000..1fc79f3f70
--- /dev/null
+++ b/widgets/text/e-text-event-processor.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-text-event-processor.h
+ * Copyright (C) 2000 Helix Code, Inc.
+ * Author: Chris Lahey <clahey@helixcode.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __E_TEXT_EVENT_PROCESSOR_H__
+#define __E_TEXT_EVENT_PROCESSOR_H__
+
+#include <gnome.h>
+#include "e-text-event-processor-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* ETextEventProcessor - Turns events on a text widget into commands.
+ *
+ */
+
+#define E_TEXT_EVENT_PROCESSOR_TYPE (e_text_event_processor_get_type ())
+#define E_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_CAST ((obj), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessor))
+#define E_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TEXT_EVENT_PROCESSOR_TYPE, ETextEventProcessorClass))
+#define E_IS_TEXT_EVENT_PROCESSOR(obj) (GTK_CHECK_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+#define E_IS_TEXT_EVENT_PROCESSOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TEXT_EVENT_PROCESSOR_TYPE))
+
+
+typedef struct _ETextEventProcessor ETextEventProcessor;
+typedef struct _ETextEventProcessorClass ETextEventProcessorClass;
+
+struct _ETextEventProcessor
+{
+ GtkObject parent;
+
+ /* object specific fields */
+
+};
+
+struct _ETextEventProcessorClass
+{
+ GtkObjectClass parent_class;
+
+ /* signals */
+ void (* command) (ETextEventProcessor *tep, ETextEventProcessorCommand *command);
+
+ /* virtual functions */
+ gint (* event) (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+};
+
+
+GtkType e_text_event_processor_get_type (void);
+gint e_text_event_processor_handle_event (ETextEventProcessor *tep, ETextEventProcessorEvent *event);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __E_TEXT_EVENT_PROCESSOR_H__ */
diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c
index b88130e3c8..f6daa3f3cf 100644
--- a/widgets/text/e-text.c
+++ b/widgets/text/e-text.c
@@ -18,12 +18,15 @@
#include <config.h>
#include <math.h>
+#include <ctype.h>
#include "e-text.h"
#include <gdk/gdkx.h> /* for BlackPixel */
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_rgb.h>
#include <libart_lgpl/art_rgb_bitmap_affine.h>
+#include "e-text-event-processor-emacs-like.h"
+
/* This defines a line of text */
@@ -58,6 +61,7 @@ enum {
ARG_FILL_STIPPLE,
ARG_TEXT_WIDTH,
ARG_TEXT_HEIGHT,
+ ARG_EDITABLE,
ARG_USE_ELLIPSIS,
ARG_ELLIPSIS
};
@@ -80,6 +84,9 @@ static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, i
static void e_text_bounds (GnomeCanvasItem *item,
double *x1, double *y1, double *x2, double *y2);
static void e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static gint e_text_event (GnomeCanvasItem *item, GdkEvent *event);
+
+static void e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
static ETextSuckFont *e_suck_font (GdkFont *font);
static void e_suck_font_free (ETextSuckFont *suckfont);
@@ -171,6 +178,8 @@ e_text_class_init (ETextClass *class)
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_WIDTH);
gtk_object_add_arg_type ("EText::text_height",
GTK_TYPE_DOUBLE, GTK_ARG_READABLE, ARG_TEXT_HEIGHT);
+ gtk_object_add_arg_type ("EText::editable",
+ GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EDITABLE);
gtk_object_add_arg_type ("EText::use_ellipsis",
GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS);
gtk_object_add_arg_type ("EText::ellipsis",
@@ -187,6 +196,7 @@ e_text_class_init (ETextClass *class)
item_class->point = e_text_point;
item_class->bounds = e_text_bounds;
item_class->render = e_text_render;
+ item_class->event = e_text_event;
}
/* Object initialization function for the text item */
@@ -201,9 +211,18 @@ e_text_init (EText *text)
text->clip_height = 0.0;
text->xofs = 0.0;
text->yofs = 0.0;
+
text->ellipsis = NULL;
text->use_ellipsis = FALSE;
text->ellipsis_width = 0;
+
+ text->editable = FALSE;
+ text->editing = FALSE;
+ text->xofs_edit = 0;
+
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
}
/* Destroy handler for the text item */
@@ -456,7 +475,8 @@ calc_line_widths (EText *text)
}
if (text->clip &&
- text->use_ellipsis &&
+ text->use_ellipsis &&
+ ! text->editing &&
lines->width > text->clip_width) {
if (text->font) {
lines->ellipsis_length = 0;
@@ -729,6 +749,10 @@ e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE);
break;
+ case ARG_EDITABLE:
+ text->editable = GTK_VALUE_BOOL (*arg);
+ break;
+
case ARG_USE_ELLIPSIS:
text->use_ellipsis = GTK_VALUE_BOOL (*arg);
calc_line_widths (text);
@@ -839,6 +863,10 @@ e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit;
break;
+ case ARG_EDITABLE:
+ GTK_VALUE_BOOL (*arg) = text->editable;
+ break;
+
case ARG_USE_ELLIPSIS:
GTK_VALUE_BOOL (*arg) = text->use_ellipsis;
break;
@@ -1016,6 +1044,19 @@ get_line_xpos (EText *text, struct line *line)
return x;
}
+static void
+_get_tep(EText *text)
+{
+ if (!text->tep) {
+ text->tep = e_text_event_processor_emacs_like_new();
+ gtk_signal_connect(GTK_OBJECT(text->tep),
+ "command",
+ GTK_SIGNAL_FUNC(e_text_command),
+ (gpointer) text);
+
+ }
+}
+
/* Draw handler for the text item */
static void
e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
@@ -1026,8 +1067,14 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
struct line *lines;
int i;
int xpos, ypos;
+ int start_char, end_char;
+ int sel_start, sel_end;
+ GdkRectangle sel_rect;
+ GdkGC *fg_gc;
+ GnomeCanvas *canvas;
text = E_TEXT (item);
+ canvas = GNOME_CANVAS_ITEM(text)->canvas;
if (!text->text || !text->font)
return;
@@ -1039,6 +1086,7 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
rect.height = text->clip_cheight;
gdk_gc_set_clip_rectangle (text->gc, &rect);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED], &rect);
}
lines = text->lines;
ypos = text->cy + text->font->ascent;
@@ -1049,39 +1097,122 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
for (i = 0; i < text->num_lines; i++) {
if (lines->length != 0) {
xpos = get_line_xpos (text, lines);
- if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->ellipsis_length);
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x +
- lines->width - text->ellipsis_width,
- ypos - y,
- text->ellipsis ? text->ellipsis : "...",
- text->ellipsis ? strlen (text->ellipsis) : 3);
- } else
-
- gdk_draw_text (drawable,
- text->font,
- text->gc,
- xpos - x,
- ypos - y,
- lines->text,
- lines->length);
+ if (text->editing) {
+ xpos -= text->xofs_edit;
+ start_char = lines->text - text->text;
+ end_char = start_char + lines->length;
+ sel_start = text->selection_start;
+ sel_end = text->selection_end;
+ if (sel_start > sel_end ) {
+ sel_start ^= sel_end;
+ sel_end ^= sel_start;
+ sel_start ^= sel_end;
+ }
+ if ( sel_start < start_char )
+ sel_start = start_char;
+ if ( sel_end > end_char )
+ sel_end = end_char;
+ if ( sel_start < sel_end ) {
+ sel_rect.x = xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char);
+ sel_rect.y = ypos - y - text->font->ascent;
+ sel_rect.width = gdk_text_width (text->font,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ sel_rect.height = text->font->ascent + text->font->descent;
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ sel_rect.x,
+ sel_rect.y,
+ sel_rect.width,
+ sel_rect.height);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ sel_start - start_char);
+ fg_gc = GTK_WIDGET(canvas)->style->fg_gc[GTK_STATE_SELECTED];
+ gdk_draw_text (drawable,
+ text->font,
+ fg_gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y,
+ lines->text + sel_start - start_char,
+ sel_end - sel_start);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_end - start_char),
+ ypos - y,
+ lines->text + sel_end - start_char,
+ end_char - sel_end);
+ } else {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
+ if (text->selection_start == text->selection_end &&
+ text->selection_start >= start_char &&
+ text->selection_start <= end_char) {
+ gdk_draw_rectangle (drawable,
+ text->gc,
+ TRUE,
+ xpos - x + gdk_text_width (text->font,
+ lines->text,
+ sel_start - start_char),
+ ypos - y - text->font->ascent,
+ 1,
+ text->font->ascent + text->font->descent);
+ }
+ } else {
+ if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) {
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->ellipsis_length);
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x +
+ lines->width - text->ellipsis_width,
+ ypos - y,
+ text->ellipsis ? text->ellipsis : "...",
+ text->ellipsis ? strlen (text->ellipsis) : 3);
+ } else
+
+ gdk_draw_text (drawable,
+ text->font,
+ text->gc,
+ xpos - x,
+ ypos - y,
+ lines->text,
+ lines->length);
+ }
}
ypos += text->font->ascent + text->font->descent;
lines++;
}
- if (text->clip)
+ if (text->clip) {
gdk_gc_set_clip_rectangle (text->gc, NULL);
+ gdk_gc_set_clip_rectangle (GTK_WIDGET(GNOME_CANVAS_ITEM(text)->canvas)->style->fg_gc[GTK_STATE_SELECTED], NULL);
+ }
}
/* Render handler for the text item */
@@ -1308,6 +1439,285 @@ e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double
*y2 = *y1 + height;
}
+static gint
+_get_position_from_xy (EText *text, gint x, gint y)
+{
+ int i, j;
+ int ypos = text->cy;
+ int xpos;
+ struct line *lines;
+ j = 0;
+ while (y > ypos)
+ {
+ ypos += text->font->ascent + text->font->descent;
+ j ++;
+ }
+ j--;
+ if (j >= text->num_lines)
+ j = text->num_lines - 1;
+ if (j < 0)
+ j = 0;
+ i = 0;
+ lines = text->lines;
+ lines += j;
+ xpos = get_line_xpos (text, lines);
+ for(i = 0; i < lines->length; i++) {
+ int charwidth = gdk_text_width(text->font,
+ lines->text + i,
+ 1);
+ xpos += charwidth / 2;
+ if (xpos > x)
+ break;
+ xpos += (charwidth + 1) / 2;
+ }
+ return lines->text + i - text->text;
+}
+
+static gint
+e_text_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EText *text = E_TEXT(item);
+ ETextEventProcessorEvent e_tep_event;
+
+ gint return_val;
+
+ e_tep_event.type = event->type;
+ switch (event->type) {
+ case GDK_FOCUS_CHANGE:
+ if (text->editable) {
+ GdkEventFocus *focus_event;
+ focus_event = (GdkEventFocus *) event;
+ if (focus_event->in) {
+ if(!text->editing) {
+ text->editing = TRUE;
+ text->selection_start = 0;
+ text->selection_end = 0;
+ text->select_by_word = FALSE;
+ text->xofs_edit = 0;
+ }
+ } else {
+ text->editing = FALSE;
+ }
+ calc_line_widths (text);
+ }
+ return_val = 0;
+ break;
+ case GDK_KEY_PRESS: /* Fall Through */
+ case GDK_KEY_RELEASE:
+ if (text->editing) {
+ GdkEventKey key = event->key;
+ e_tep_event.key.time = key.time;
+ e_tep_event.key.state = key.state;
+ e_tep_event.key.keyval = key.keyval;
+ e_tep_event.key.length = key.length;
+ e_tep_event.key.string = key.string;
+ _get_tep(text);
+ return e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ else
+ return 0;
+ break;
+ case GDK_BUTTON_PRESS: /* Fall Through */
+ case GDK_BUTTON_RELEASE:
+ if (text->editing) {
+ GdkEventButton button = event->button;
+ e_tep_event.button.time = button.time;
+ e_tep_event.button.state = button.state;
+ e_tep_event.button.button = button.button;
+ e_tep_event.button.position = _get_position_from_xy(text, button.x, button.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ } else if (text->editable && event->type == GDK_BUTTON_RELEASE) {
+ gnome_canvas_item_grab_focus (item);
+ return 1;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (text->editing) {
+ GdkEventMotion motion = event->motion;
+ e_tep_event.motion.time = motion.time;
+ e_tep_event.motion.state = motion.state;
+ e_tep_event.motion.position = _get_position_from_xy(text, motion.x, motion.y);
+ _get_tep(text);
+ return_val = e_text_event_processor_handle_event (text->tep,
+ &e_tep_event);
+ }
+ break;
+ default:
+ break;
+ }
+ if (return_val)
+ return return_val;
+ if (GNOME_CANVAS_ITEM_CLASS(parent_class)->event)
+ return GNOME_CANVAS_ITEM_CLASS(parent_class)->event(item, event);
+ else
+ return 0;
+}
+
+static int
+_get_position(EText *text, ETextEventProcessorCommand *command)
+{
+ int i;
+ int length;
+
+ switch (command->position) {
+
+ case E_TEP_VALUE:
+ return command->value;
+
+ case E_TEP_SELECTION:
+ return text->selection_end;
+
+ case E_TEP_START_OF_BUFFER:
+ return 0;
+ case E_TEP_END_OF_BUFFER:
+ return strlen(text->text);
+
+ case E_TEP_START_OF_LINE:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (text->text[i] == '\n') {
+ i++;
+ break;
+ }
+ return i;
+ case E_TEP_END_OF_LINE:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (text->text[i] == '\n') {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+
+ case E_TEP_FORWARD_CHARACTER:
+ length = strlen(text->text);
+ i = text->selection_end + 1;
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_CHARACTER:
+ i = text->selection_end - 1;
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_WORD:
+ length = strlen(text->text);
+ for (i = text->selection_end + 1; i < length; i++)
+ if (isspace(text->text[i])) {
+ break;
+ }
+ if (i > length)
+ i = length;
+ return i;
+ case E_TEP_BACKWARD_WORD:
+ for (i = text->selection_end - 2; i > 0; i--)
+ if (isspace(text->text[i])) {
+ i++;
+ break;
+ }
+ if (i < 0)
+ i = 0;
+ return i;
+
+ case E_TEP_FORWARD_LINE:
+ case E_TEP_BACKWARD_LINE:
+
+ case E_TEP_FORWARD_PARAGRAPH:
+ case E_TEP_BACKWARD_PARAGRAPH:
+
+ case E_TEP_FORWARD_PAGE:
+ case E_TEP_BACKWARD_PAGE:
+ return text->selection_end;
+ default:
+ return text->selection_end;
+ }
+}
+
+static void
+_delete_selection(EText *text)
+{
+ gint length = strlen(text->text);
+ if (text->selection_end == text->selection_start)
+ return;
+ if (text->selection_end < text->selection_start) {
+ text->selection_end ^= text->selection_start;
+ text->selection_start ^= text->selection_end;
+ text->selection_end ^= text->selection_start;
+ }
+ memmove( text->text + text->selection_start,
+ text->text + text->selection_end,
+ length - text->selection_end + 1 );
+ length -= text->selection_end - text->selection_start;
+ text->selection_end = text->selection_start;
+}
+
+static void
+_insert(EText *text, char *string, int value)
+{
+ if (value > 0) {
+ char *temp;
+ gint length = strlen(text->text);
+ temp = g_new(gchar, length + value + 1);
+ strncpy(temp, text->text, text->selection_start);
+ strncpy(temp + text->selection_start, string, value);
+ strcpy(temp + text->selection_start + value, text->text + text->selection_start);
+ g_free(text->text);
+ text->text = temp;
+ text->selection_start += value;
+ text->selection_end = text->selection_start;
+ }
+}
+
+static void
+e_text_command(ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data)
+{
+ EText *text = E_TEXT(data);
+ switch (command->action) {
+ case E_TEP_MOVE:
+ text->selection_start = _get_position(text, command);
+ text->selection_end = text->selection_start;
+ break;
+ case E_TEP_SELECT:
+ text->selection_end = _get_position(text, command);
+ break;
+ case E_TEP_DELETE:
+ if (text->selection_end == text->selection_start) {
+ text->selection_end = _get_position(text, command);
+ }
+ _delete_selection(text);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+
+ case E_TEP_INSERT:
+ if (text->selection_end != text->selection_start) {
+ _delete_selection(text);
+ }
+ _insert(text, command->string, command->value);
+ split_into_lines (text);
+ recalc_bounds (text);
+ break;
+ case E_TEP_COPY:
+ if (text->selection_end != text->selection_start) {
+ }
+ break;
+ case E_TEP_PASTE:
+ break;
+ case E_TEP_ACTIVATE:
+ break;
+ case E_TEP_SET_SELECT_BY_WORD:
+ text->select_by_word = command->value;
+ break;
+ case E_TEP_NOP:
+ break;
+ }
+ gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(text));
+}
+
/* Routines for sucking fonts from the X server */
diff --git a/widgets/text/e-text.h b/widgets/text/e-text.h
index e14199f16e..b18b93d7f2 100644
--- a/widgets/text/e-text.h
+++ b/widgets/text/e-text.h
@@ -20,6 +20,7 @@
#define E_TEXT_H
#include <gnome.h>
+#include "e-text-event-processor.h"
BEGIN_GNOME_DECLS
@@ -59,8 +60,15 @@ BEGIN_GNOME_DECLS
* text_height double R Used to query the rendered height of the text
*
* These are ignored in the AA version:
+ * editable boolean RW Can this item be edited
* use_ellipsis boolean RW Whether to use ellipsises if text gets cut off. Meaningless if clip == false.
* ellipsis string RW The characters to use as ellipsis. NULL = "...".
+ *
+ * These are not implemented yet:
+ * multi_line boolean RW Line wrap when not editing.
+ * multi_line_on_edit boolean RW Switch to line wrap when editing.
+ * background boolean RW Draw a background rectangle.
+ * background_on_edit boolean RW Draw a background when editing.
*/
#define E_TYPE_TEXT (e_text_get_type ())
@@ -129,6 +137,18 @@ struct _EText {
char *ellipsis; /* The ellipsis characters. NULL = "...". */
double ellipsis_width; /* The width of the ellipsis. */
gboolean use_ellipsis; /* Whether to use the ellipsis. */
+
+ gboolean editable; /* Item is editable */
+ gboolean editing; /* Item is currently being edited */
+
+ int xofs_edit; /* Offset because of editing */
+
+ /* This needs to be reworked a bit once we get line wrapping. */
+ int selection_start; /* Start of selection */
+ int selection_end; /* End of selection */
+ gboolean select_by_word; /* Current selection is by word */
+
+ ETextEventProcessor *tep; /* Text Event Processor */
};
struct _ETextClass {