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
This commit is contained in:
Chris Lahey
2000-01-11 06:44:57 +00:00
parent b2a25c6add
commit a01de808cd
36 changed files with 4231 additions and 122 deletions

View File

@ -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

View File

@ -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 )

View File

@ -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();

View File

@ -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 )

View File

@ -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();

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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 \

View File

@ -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 )

View File

@ -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 )

View File

@ -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();

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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 */
@ -457,6 +476,7 @@ calc_line_widths (EText *text)
if (text->clip &&
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,6 +1097,86 @@ 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->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,
@ -1075,13 +1203,16 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
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 */

View File

@ -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 {

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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 */
@ -457,6 +476,7 @@ calc_line_widths (EText *text)
if (text->clip &&
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,6 +1097,86 @@ 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->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,
@ -1075,13 +1203,16 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
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 */

View File

@ -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 {

View File

@ -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();

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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__ */

View File

@ -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 */
@ -457,6 +476,7 @@ calc_line_widths (EText *text)
if (text->clip &&
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,6 +1097,86 @@ 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->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,
@ -1075,13 +1203,16 @@ e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
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 */

View File

@ -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 {