diff options
32 files changed, 9033 insertions, 1 deletions
diff --git a/addressbook/gui/minicard/e-minicard-label.c b/addressbook/gui/minicard/e-minicard-label.c new file mode 100644 index 0000000000..e3c61ff9bf --- /dev/null +++ b/addressbook/gui/minicard/e-minicard-label.c @@ -0,0 +1,331 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard-label.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-minicard-label.h" +static void e_minicard_label_init (EMinicardLabel *card); +static void e_minicard_label_class_init (EMinicardLabelClass *klass); +static void e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_label_realize (GnomeCanvasItem *item); +static void e_minicard_label_unrealize (GnomeCanvasItem *item); + +static void _update_label( EMinicardLabel *minicard_label ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_FIELD, + ARG_FIELDNAME +}; + +GtkType +e_minicard_label_get_type (void) +{ + static GtkType minicard_label_type = 0; + + if (!minicard_label_type) + { + static const GtkTypeInfo minicard_label_info = + { + "EMinicardLabel", + sizeof (EMinicardLabel), + sizeof (EMinicardLabelClass), + (GtkClassInitFunc) e_minicard_label_class_init, + (GtkObjectInitFunc) e_minicard_label_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_label_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_label_info); + } + + return minicard_label_type; +} + +static void +e_minicard_label_class_init (EMinicardLabelClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicardLabel::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicardLabel::height", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicardLabel::field", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELD); + gtk_object_add_arg_type ("EMinicardLabel::fieldname", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELDNAME); + + object_class->set_arg = e_minicard_label_set_arg; + object_class->get_arg = e_minicard_label_get_arg; + /* object_class->destroy = e_minicard_label_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_label_realize; + item_class->unrealize = e_minicard_label_unrealize; + item_class->event = e_minicard_label_event; +} + +static void +e_minicard_label_init (EMinicardLabel *minicard_label) +{ + GnomeCanvasGroup *group = GNOME_CANVAS_GROUP( minicard_label ); + minicard_label->width = 10; + minicard_label->height = 10; + minicard_label->rect = NULL; + minicard_label->fieldname = NULL; + minicard_label->field = NULL; + minicard_label->fieldname_text = NULL; + minicard_label->field_text = NULL; +} + +static void +e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicardLabel *e_minicard_label; + + item = GNOME_CANVAS_ITEM (o); + e_minicard_label = E_MINICARD_LABEL (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard_label->width = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_HEIGHT: + e_minicard_label->height = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + gnome_canvas_item_set( e_minicard_label->field, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->field_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + gnome_canvas_item_set( e_minicard_label->fieldname, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->fieldname_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + } +} + +static void +e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicardLabel *e_minicard_label; + char *temp; + + e_minicard_label = E_MINICARD_LABEL (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->height; + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->field ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->field_text ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->fieldname ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->fieldname_text ); + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_label_realize (GnomeCanvasItem *item) +{ + double ascent, descent; + EMinicardLabel *e_minicard_label; + GnomeCanvasGroup *group; + + e_minicard_label = E_MINICARD_LABEL (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) (item); + + e_minicard_label->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard_label->width - 1, + "y2", (double) e_minicard_label->height - 1, + "outline_color", NULL, + NULL ); + e_minicard_label->fieldname = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 2, + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard_label->width / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + if ( e_minicard_label->fieldname_text ) + { + gnome_canvas_item_set( e_minicard_label->fieldname, + "text", e_minicard_label->fieldname_text, + NULL ); + g_free( e_minicard_label->fieldname_text ); + } + e_minicard_label->field = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) ( e_minicard_label->width / 2 + 2 ), + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( ( e_minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + + if ( e_minicard_label->field_text ) + { + gnome_canvas_item_set( e_minicard_label->field, + "text", e_minicard_label->field_text, + NULL ); + g_free( e_minicard_label->field_text ); + } + if (!item->canvas->aa) + { + } + +} + +static void +e_minicard_label_unrealize (GnomeCanvasItem *item) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) (item); +} + +static gboolean +e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", "grey50", + "fill_color", "grey90", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", NULL, + "fill_color", NULL, + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_label( EMinicardLabel *minicard_label ) +{ + if ( GTK_OBJECT_FLAGS( minicard_label ) & GNOME_CANVAS_ITEM_REALIZED ) + { + gnome_canvas_item_set( minicard_label->rect, + "x2", (double) minicard_label->width - 1, + "y2", (double) minicard_label->height - 1, + NULL ); + gnome_canvas_item_set( minicard_label->fieldname, + "clip_width", (double) ( minicard_label->width / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + gnome_canvas_item_set( minicard_label->field, + "x", (double) ( minicard_label->width / 2 + 2 ), + "clip_width", (double) ( ( minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + } +} diff --git a/addressbook/gui/minicard/e-minicard-label.h b/addressbook/gui/minicard/e-minicard-label.h new file mode 100644 index 0000000000..dbf9c3944a --- /dev/null +++ b/addressbook/gui/minicard/e-minicard-label.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard-label.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_MINICARD_LABEL_H__ +#define __E_MINICARD_LABEL_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicardLabel - A label doing focus with non-marching ants. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the label + * height double R height of the label + * field string RW text in the field label + * fieldname string RW text in the fieldname label + */ + +#define E_MINICARD_LABEL_TYPE (e_minicard_label_get_type ()) +#define E_MINICARD_LABEL(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_LABEL_TYPE, EMinicardLabel)) +#define E_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_LABEL_TYPE, EMiniCardLabelClass)) +#define E_IS_MINICARD_LABEL(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_LABEL_TYPE)) +#define E_IS_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_LABEL_TYPE)) + + +typedef struct _EMinicardLabel EMinicardLabel; +typedef struct _EMinicardLabelClass EMinicardLabelClass; + +struct _EMinicardLabel +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + double width; + double height; + GnomeCanvasItem *fieldname; + GnomeCanvasItem *field; + GnomeCanvasItem *rect; + char *fieldname_text; + char *field_text; +}; + +struct _EMinicardLabelClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_label_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_LABEL_H__ */ diff --git a/addressbook/gui/minicard/e-minicard.c b/addressbook/gui/minicard/e-minicard.c new file mode 100644 index 0000000000..a5602baef4 --- /dev/null +++ b/addressbook/gui/minicard/e-minicard.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard.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-minicard.h" +#include "e-minicard-label.h" +static void e_minicard_init (EMinicard *card); +static void e_minicard_class_init (EMinicardClass *klass); +static void e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_realize (GnomeCanvasItem *item); +static void e_minicard_unrealize (GnomeCanvasItem *item); + +static void _update_card ( EMinicard *minicard ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_CARD +}; + +GtkType +e_minicard_get_type (void) +{ + static GtkType minicard_type = 0; + + if (!minicard_type) + { + static const GtkTypeInfo minicard_info = + { + "EMinicard", + sizeof (EMinicard), + sizeof (EMinicardClass), + (GtkClassInitFunc) e_minicard_class_init, + (GtkObjectInitFunc) e_minicard_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_info); + } + + return minicard_type; +} + +static void +e_minicard_class_init (EMinicardClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicard::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicard::height", GTK_TYPE_DOUBLE, + GTK_ARG_READABLE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicard::card", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_CARD); + + object_class->set_arg = e_minicard_set_arg; + object_class->get_arg = e_minicard_get_arg; + /* object_class->destroy = e_minicard_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_realize; + item_class->unrealize = e_minicard_unrealize; + item_class->event = e_minicard_event; +} + +static void +e_minicard_init (EMinicard *minicard) +{ + /* minicard->card = NULL;*/ + minicard->rect = NULL; + minicard->fields = NULL; + minicard->width = 10; + minicard->height = 10; +} + +static void +e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicard *e_minicard; + + item = GNOME_CANVAS_ITEM (o); + e_minicard = E_MINICARD (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard->width = GTK_VALUE_DOUBLE (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item); + break; + case ARG_CARD: + /* e_minicard->card = GTK_VALUE_POINTER (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item);*/ + break; + } +} + +static void +e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard->height; + break; + case ARG_CARD: + /* GTK_VALUE_POINTER (*arg) = e_minicard->card; */ + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_realize (GnomeCanvasItem *item) +{ + double text_height; + EMinicard *e_minicard; + GnomeCanvasGroup *group; + + e_minicard = E_MINICARD (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item); + + e_minicard->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard->width - 1, + "y2", (double) e_minicard->height - 1, + "outline_color", NULL, + NULL ); + + e_minicard->header_rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 2, + "y1", (double) 2, + "x2", (double) e_minicard->width - 3, + "y2", (double) e_minicard->height - 3, + "fill_color", "grey70", + NULL ); + + e_minicard->header_text = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 6, + "y", (double) 6, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard->width - 12 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-bold-10", + "fill_color", "black", + "text", "Chris Lahey", + NULL ); + + gtk_object_get( GTK_OBJECT( e_minicard->header_text ), + "text_height", &text_height, + NULL ); + + e_minicard->height = text_height + 12.0; + + gnome_canvas_item_set( e_minicard->header_rect, + "y2", text_height + 9.0, + NULL ); + + gnome_canvas_item_set( e_minicard->header_text, + "clip_height", text_height, + NULL ); + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4, + "height", text_height + 3, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ) ); + e_minicard->height += text_height + 3; + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4.0, + "height", text_height + 3.0, + "fieldname", "Email:", + "field", "clahey@helixcode.com", + NULL ) ); + e_minicard->height += text_height + 3; + e_minicard->height += 2; + + gnome_canvas_item_set( e_minicard->rect, + "y2", e_minicard->height - 1, + NULL ); + + if (!item->canvas->aa) + { + } +} + +static void +e_minicard_unrealize (GnomeCanvasItem *item) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); +} + +static gboolean +e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "darkblue", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "white", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", NULL, + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "black", + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_card( EMinicard *minicard ) +{ + if ( GTK_OBJECT_FLAGS( minicard ) & GNOME_CANVAS_ITEM_REALIZED ) + { + GList *field; + gnome_canvas_item_set( minicard->rect, + "x2", (double) minicard->width - 1.0, + "y2", (double) minicard->height - 1.0, + NULL ); + gnome_canvas_item_set( minicard->header_rect, + "x2", (double) minicard->width - 4.0, + NULL ); + gnome_canvas_item_set( minicard->header_text, + "clip_width", (double) minicard->width - 12, + NULL ); + for ( field = minicard->fields; field; field = g_list_next( field ) ) + { + gnome_canvas_item_set( GNOME_CANVAS_ITEM( field->data ), + "width", minicard->width - 4.0, + NULL ); + } + } +} diff --git a/addressbook/gui/minicard/e-minicard.h b/addressbook/gui/minicard/e-minicard.h new file mode 100644 index 0000000000..759cc4ffb7 --- /dev/null +++ b/addressbook/gui/minicard/e-minicard.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard.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_MINICARD_H__ +#define __E_MINICARD_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicard - A small card displaying information about a contact. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the card + * height double R height of the card + * card ECard* RW Pointer to the ECard + */ + +#define E_MINICARD_TYPE (e_minicard_get_type ()) +#define E_MINICARD(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_TYPE, EMinicard)) +#define E_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_TYPE, EMinicardClass)) +#define E_IS_MINICARD(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_TYPE)) +#define E_IS_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_TYPE)) + + +typedef struct _EMinicard EMinicard; +typedef struct _EMinicardClass EMinicardClass; + +struct _EMinicard +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + /* ECard *card; */ + + GnomeCanvasItem *rect; + GnomeCanvasItem *header_rect; + GnomeCanvasItem *header_text; + GList *fields; /* Of type GnomeCanvasItem. */ + + double width; + double height; +}; + +struct _EMinicardClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_H__ */ diff --git a/addressbook/gui/minicard/test-minicard-label.c b/addressbook/gui/minicard/test-minicard-label.c new file mode 100644 index 0000000000..67c17a0ace --- /dev/null +++ b/addressbook/gui/minicard/test-minicard-label.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard-label.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard-label.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *label; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( label, + "width", (double) allocation->width, + "height", (double) allocation->height, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Label Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard label canvas item" ), + NULL); + gtk_widget_show (about); +} + +static void button_press_callback( GtkWidget *widget, gpointer data ) +{ + gnome_canvas_item_grab_focus( label ); +} + +int main( int argc, char *argv[] ) +{ + GtkWidget *app; + GtkWidget *canvas; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Label Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Label Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + label = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_label_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + "height", (double) 100, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ); + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/addressbook/gui/minicard/test-minicard.c b/addressbook/gui/minicard/test-minicard.c new file mode 100644 index 0000000000..4f56fbe936 --- /dev/null +++ b/addressbook/gui/minicard/test-minicard.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *card; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( card, + "width", (double) allocation->width, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard canvas item" ), + NULL); + 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; + GtkWidget *canvas; + int i; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + for ( i = 0; i < 1; i++ ) + { + card = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + NULL ); + } + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/addressbook/gui/widgets/e-minicard-label.c b/addressbook/gui/widgets/e-minicard-label.c new file mode 100644 index 0000000000..e3c61ff9bf --- /dev/null +++ b/addressbook/gui/widgets/e-minicard-label.c @@ -0,0 +1,331 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard-label.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-minicard-label.h" +static void e_minicard_label_init (EMinicardLabel *card); +static void e_minicard_label_class_init (EMinicardLabelClass *klass); +static void e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_label_realize (GnomeCanvasItem *item); +static void e_minicard_label_unrealize (GnomeCanvasItem *item); + +static void _update_label( EMinicardLabel *minicard_label ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_FIELD, + ARG_FIELDNAME +}; + +GtkType +e_minicard_label_get_type (void) +{ + static GtkType minicard_label_type = 0; + + if (!minicard_label_type) + { + static const GtkTypeInfo minicard_label_info = + { + "EMinicardLabel", + sizeof (EMinicardLabel), + sizeof (EMinicardLabelClass), + (GtkClassInitFunc) e_minicard_label_class_init, + (GtkObjectInitFunc) e_minicard_label_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_label_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_label_info); + } + + return minicard_label_type; +} + +static void +e_minicard_label_class_init (EMinicardLabelClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicardLabel::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicardLabel::height", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicardLabel::field", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELD); + gtk_object_add_arg_type ("EMinicardLabel::fieldname", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELDNAME); + + object_class->set_arg = e_minicard_label_set_arg; + object_class->get_arg = e_minicard_label_get_arg; + /* object_class->destroy = e_minicard_label_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_label_realize; + item_class->unrealize = e_minicard_label_unrealize; + item_class->event = e_minicard_label_event; +} + +static void +e_minicard_label_init (EMinicardLabel *minicard_label) +{ + GnomeCanvasGroup *group = GNOME_CANVAS_GROUP( minicard_label ); + minicard_label->width = 10; + minicard_label->height = 10; + minicard_label->rect = NULL; + minicard_label->fieldname = NULL; + minicard_label->field = NULL; + minicard_label->fieldname_text = NULL; + minicard_label->field_text = NULL; +} + +static void +e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicardLabel *e_minicard_label; + + item = GNOME_CANVAS_ITEM (o); + e_minicard_label = E_MINICARD_LABEL (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard_label->width = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_HEIGHT: + e_minicard_label->height = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + gnome_canvas_item_set( e_minicard_label->field, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->field_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + gnome_canvas_item_set( e_minicard_label->fieldname, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->fieldname_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + } +} + +static void +e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicardLabel *e_minicard_label; + char *temp; + + e_minicard_label = E_MINICARD_LABEL (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->height; + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->field ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->field_text ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->fieldname ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->fieldname_text ); + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_label_realize (GnomeCanvasItem *item) +{ + double ascent, descent; + EMinicardLabel *e_minicard_label; + GnomeCanvasGroup *group; + + e_minicard_label = E_MINICARD_LABEL (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) (item); + + e_minicard_label->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard_label->width - 1, + "y2", (double) e_minicard_label->height - 1, + "outline_color", NULL, + NULL ); + e_minicard_label->fieldname = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 2, + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard_label->width / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + if ( e_minicard_label->fieldname_text ) + { + gnome_canvas_item_set( e_minicard_label->fieldname, + "text", e_minicard_label->fieldname_text, + NULL ); + g_free( e_minicard_label->fieldname_text ); + } + e_minicard_label->field = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) ( e_minicard_label->width / 2 + 2 ), + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( ( e_minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + + if ( e_minicard_label->field_text ) + { + gnome_canvas_item_set( e_minicard_label->field, + "text", e_minicard_label->field_text, + NULL ); + g_free( e_minicard_label->field_text ); + } + if (!item->canvas->aa) + { + } + +} + +static void +e_minicard_label_unrealize (GnomeCanvasItem *item) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) (item); +} + +static gboolean +e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", "grey50", + "fill_color", "grey90", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", NULL, + "fill_color", NULL, + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_label( EMinicardLabel *minicard_label ) +{ + if ( GTK_OBJECT_FLAGS( minicard_label ) & GNOME_CANVAS_ITEM_REALIZED ) + { + gnome_canvas_item_set( minicard_label->rect, + "x2", (double) minicard_label->width - 1, + "y2", (double) minicard_label->height - 1, + NULL ); + gnome_canvas_item_set( minicard_label->fieldname, + "clip_width", (double) ( minicard_label->width / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + gnome_canvas_item_set( minicard_label->field, + "x", (double) ( minicard_label->width / 2 + 2 ), + "clip_width", (double) ( ( minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + } +} diff --git a/addressbook/gui/widgets/e-minicard-label.h b/addressbook/gui/widgets/e-minicard-label.h new file mode 100644 index 0000000000..dbf9c3944a --- /dev/null +++ b/addressbook/gui/widgets/e-minicard-label.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard-label.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_MINICARD_LABEL_H__ +#define __E_MINICARD_LABEL_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicardLabel - A label doing focus with non-marching ants. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the label + * height double R height of the label + * field string RW text in the field label + * fieldname string RW text in the fieldname label + */ + +#define E_MINICARD_LABEL_TYPE (e_minicard_label_get_type ()) +#define E_MINICARD_LABEL(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_LABEL_TYPE, EMinicardLabel)) +#define E_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_LABEL_TYPE, EMiniCardLabelClass)) +#define E_IS_MINICARD_LABEL(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_LABEL_TYPE)) +#define E_IS_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_LABEL_TYPE)) + + +typedef struct _EMinicardLabel EMinicardLabel; +typedef struct _EMinicardLabelClass EMinicardLabelClass; + +struct _EMinicardLabel +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + double width; + double height; + GnomeCanvasItem *fieldname; + GnomeCanvasItem *field; + GnomeCanvasItem *rect; + char *fieldname_text; + char *field_text; +}; + +struct _EMinicardLabelClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_label_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_LABEL_H__ */ diff --git a/addressbook/gui/widgets/e-minicard.c b/addressbook/gui/widgets/e-minicard.c new file mode 100644 index 0000000000..a5602baef4 --- /dev/null +++ b/addressbook/gui/widgets/e-minicard.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard.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-minicard.h" +#include "e-minicard-label.h" +static void e_minicard_init (EMinicard *card); +static void e_minicard_class_init (EMinicardClass *klass); +static void e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_realize (GnomeCanvasItem *item); +static void e_minicard_unrealize (GnomeCanvasItem *item); + +static void _update_card ( EMinicard *minicard ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_CARD +}; + +GtkType +e_minicard_get_type (void) +{ + static GtkType minicard_type = 0; + + if (!minicard_type) + { + static const GtkTypeInfo minicard_info = + { + "EMinicard", + sizeof (EMinicard), + sizeof (EMinicardClass), + (GtkClassInitFunc) e_minicard_class_init, + (GtkObjectInitFunc) e_minicard_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_info); + } + + return minicard_type; +} + +static void +e_minicard_class_init (EMinicardClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicard::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicard::height", GTK_TYPE_DOUBLE, + GTK_ARG_READABLE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicard::card", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_CARD); + + object_class->set_arg = e_minicard_set_arg; + object_class->get_arg = e_minicard_get_arg; + /* object_class->destroy = e_minicard_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_realize; + item_class->unrealize = e_minicard_unrealize; + item_class->event = e_minicard_event; +} + +static void +e_minicard_init (EMinicard *minicard) +{ + /* minicard->card = NULL;*/ + minicard->rect = NULL; + minicard->fields = NULL; + minicard->width = 10; + minicard->height = 10; +} + +static void +e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicard *e_minicard; + + item = GNOME_CANVAS_ITEM (o); + e_minicard = E_MINICARD (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard->width = GTK_VALUE_DOUBLE (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item); + break; + case ARG_CARD: + /* e_minicard->card = GTK_VALUE_POINTER (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item);*/ + break; + } +} + +static void +e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard->height; + break; + case ARG_CARD: + /* GTK_VALUE_POINTER (*arg) = e_minicard->card; */ + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_realize (GnomeCanvasItem *item) +{ + double text_height; + EMinicard *e_minicard; + GnomeCanvasGroup *group; + + e_minicard = E_MINICARD (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item); + + e_minicard->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard->width - 1, + "y2", (double) e_minicard->height - 1, + "outline_color", NULL, + NULL ); + + e_minicard->header_rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 2, + "y1", (double) 2, + "x2", (double) e_minicard->width - 3, + "y2", (double) e_minicard->height - 3, + "fill_color", "grey70", + NULL ); + + e_minicard->header_text = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 6, + "y", (double) 6, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard->width - 12 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-bold-10", + "fill_color", "black", + "text", "Chris Lahey", + NULL ); + + gtk_object_get( GTK_OBJECT( e_minicard->header_text ), + "text_height", &text_height, + NULL ); + + e_minicard->height = text_height + 12.0; + + gnome_canvas_item_set( e_minicard->header_rect, + "y2", text_height + 9.0, + NULL ); + + gnome_canvas_item_set( e_minicard->header_text, + "clip_height", text_height, + NULL ); + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4, + "height", text_height + 3, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ) ); + e_minicard->height += text_height + 3; + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4.0, + "height", text_height + 3.0, + "fieldname", "Email:", + "field", "clahey@helixcode.com", + NULL ) ); + e_minicard->height += text_height + 3; + e_minicard->height += 2; + + gnome_canvas_item_set( e_minicard->rect, + "y2", e_minicard->height - 1, + NULL ); + + if (!item->canvas->aa) + { + } +} + +static void +e_minicard_unrealize (GnomeCanvasItem *item) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); +} + +static gboolean +e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "darkblue", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "white", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", NULL, + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "black", + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_card( EMinicard *minicard ) +{ + if ( GTK_OBJECT_FLAGS( minicard ) & GNOME_CANVAS_ITEM_REALIZED ) + { + GList *field; + gnome_canvas_item_set( minicard->rect, + "x2", (double) minicard->width - 1.0, + "y2", (double) minicard->height - 1.0, + NULL ); + gnome_canvas_item_set( minicard->header_rect, + "x2", (double) minicard->width - 4.0, + NULL ); + gnome_canvas_item_set( minicard->header_text, + "clip_width", (double) minicard->width - 12, + NULL ); + for ( field = minicard->fields; field; field = g_list_next( field ) ) + { + gnome_canvas_item_set( GNOME_CANVAS_ITEM( field->data ), + "width", minicard->width - 4.0, + NULL ); + } + } +} diff --git a/addressbook/gui/widgets/e-minicard.h b/addressbook/gui/widgets/e-minicard.h new file mode 100644 index 0000000000..759cc4ffb7 --- /dev/null +++ b/addressbook/gui/widgets/e-minicard.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard.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_MINICARD_H__ +#define __E_MINICARD_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicard - A small card displaying information about a contact. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the card + * height double R height of the card + * card ECard* RW Pointer to the ECard + */ + +#define E_MINICARD_TYPE (e_minicard_get_type ()) +#define E_MINICARD(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_TYPE, EMinicard)) +#define E_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_TYPE, EMinicardClass)) +#define E_IS_MINICARD(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_TYPE)) +#define E_IS_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_TYPE)) + + +typedef struct _EMinicard EMinicard; +typedef struct _EMinicardClass EMinicardClass; + +struct _EMinicard +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + /* ECard *card; */ + + GnomeCanvasItem *rect; + GnomeCanvasItem *header_rect; + GnomeCanvasItem *header_text; + GList *fields; /* Of type GnomeCanvasItem. */ + + double width; + double height; +}; + +struct _EMinicardClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_H__ */ diff --git a/addressbook/gui/widgets/test-minicard-label.c b/addressbook/gui/widgets/test-minicard-label.c new file mode 100644 index 0000000000..67c17a0ace --- /dev/null +++ b/addressbook/gui/widgets/test-minicard-label.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard-label.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard-label.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *label; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( label, + "width", (double) allocation->width, + "height", (double) allocation->height, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Label Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard label canvas item" ), + NULL); + gtk_widget_show (about); +} + +static void button_press_callback( GtkWidget *widget, gpointer data ) +{ + gnome_canvas_item_grab_focus( label ); +} + +int main( int argc, char *argv[] ) +{ + GtkWidget *app; + GtkWidget *canvas; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Label Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Label Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + label = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_label_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + "height", (double) 100, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ); + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/addressbook/gui/widgets/test-minicard.c b/addressbook/gui/widgets/test-minicard.c new file mode 100644 index 0000000000..4f56fbe936 --- /dev/null +++ b/addressbook/gui/widgets/test-minicard.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *card; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( card, + "width", (double) allocation->width, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard canvas item" ), + NULL); + 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; + GtkWidget *canvas; + int i; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + for ( i = 0; i < 1; i++ ) + { + card = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + NULL ); + } + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/widgets/.cvsignore b/widgets/.cvsignore index 0963d457d9..d32593e1fd 100644 --- a/widgets/.cvsignore +++ b/widgets/.cvsignore @@ -4,4 +4,5 @@ Makefile Makefile.in *.lo *.la -table-test +minicard-test +minicard-label-test diff --git a/widgets/Makefile.am b/widgets/Makefile.am index 0408acc872..76337f05a4 100644 --- a/widgets/Makefile.am +++ b/widgets/Makefile.am @@ -1,3 +1,46 @@ SUBDIRS = \ meeting-time-sel shortcut-bar e-table + +INCLUDES = \ + -I$(top_srcdir)/camel \ + -I$(top_builddir)/camel \ + $(GNOME_INCLUDEDIR) + +noinst_LIBRARIES = \ + libevolutionwidgets.a + +libevolutionwidgets_a_SOURCES = \ + e-cursors.c \ + e-cursors.h \ + e-minicard.c \ + e-minicard.h \ + e-minicard-label.c \ + e-minicard-label.h \ + e-text.c \ + e-text.h + +noinst_PROGRAMS = \ + minicard-label-test \ + minicard-test \ + focus-test + +minicard_label_test_SOURCES = \ + test-minicard-label.c + +minicard_label_test_LDADD = \ + $(EXTRA_GNOME_LIBS) \ + libevolutionwidgets.a + +minicard_test_SOURCES = \ + test-minicard.c + +minicard_test_LDADD = \ + $(EXTRA_GNOME_LIBS) \ + libevolutionwidgets.a + +focus_test_SOURCES = \ + test-focus.c + +focus_test_LDADD = \ + $(EXTRA_GNOME_LIBS) diff --git a/widgets/e-minicard-label.c b/widgets/e-minicard-label.c new file mode 100644 index 0000000000..e3c61ff9bf --- /dev/null +++ b/widgets/e-minicard-label.c @@ -0,0 +1,331 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard-label.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-minicard-label.h" +static void e_minicard_label_init (EMinicardLabel *card); +static void e_minicard_label_class_init (EMinicardLabelClass *klass); +static void e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_label_realize (GnomeCanvasItem *item); +static void e_minicard_label_unrealize (GnomeCanvasItem *item); + +static void _update_label( EMinicardLabel *minicard_label ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_FIELD, + ARG_FIELDNAME +}; + +GtkType +e_minicard_label_get_type (void) +{ + static GtkType minicard_label_type = 0; + + if (!minicard_label_type) + { + static const GtkTypeInfo minicard_label_info = + { + "EMinicardLabel", + sizeof (EMinicardLabel), + sizeof (EMinicardLabelClass), + (GtkClassInitFunc) e_minicard_label_class_init, + (GtkObjectInitFunc) e_minicard_label_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_label_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_label_info); + } + + return minicard_label_type; +} + +static void +e_minicard_label_class_init (EMinicardLabelClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicardLabel::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicardLabel::height", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicardLabel::field", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELD); + gtk_object_add_arg_type ("EMinicardLabel::fieldname", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELDNAME); + + object_class->set_arg = e_minicard_label_set_arg; + object_class->get_arg = e_minicard_label_get_arg; + /* object_class->destroy = e_minicard_label_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_label_realize; + item_class->unrealize = e_minicard_label_unrealize; + item_class->event = e_minicard_label_event; +} + +static void +e_minicard_label_init (EMinicardLabel *minicard_label) +{ + GnomeCanvasGroup *group = GNOME_CANVAS_GROUP( minicard_label ); + minicard_label->width = 10; + minicard_label->height = 10; + minicard_label->rect = NULL; + minicard_label->fieldname = NULL; + minicard_label->field = NULL; + minicard_label->fieldname_text = NULL; + minicard_label->field_text = NULL; +} + +static void +e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicardLabel *e_minicard_label; + + item = GNOME_CANVAS_ITEM (o); + e_minicard_label = E_MINICARD_LABEL (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard_label->width = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_HEIGHT: + e_minicard_label->height = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + gnome_canvas_item_set( e_minicard_label->field, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->field_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + gnome_canvas_item_set( e_minicard_label->fieldname, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->fieldname_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + } +} + +static void +e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicardLabel *e_minicard_label; + char *temp; + + e_minicard_label = E_MINICARD_LABEL (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->height; + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->field ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->field_text ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->fieldname ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->fieldname_text ); + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_label_realize (GnomeCanvasItem *item) +{ + double ascent, descent; + EMinicardLabel *e_minicard_label; + GnomeCanvasGroup *group; + + e_minicard_label = E_MINICARD_LABEL (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) (item); + + e_minicard_label->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard_label->width - 1, + "y2", (double) e_minicard_label->height - 1, + "outline_color", NULL, + NULL ); + e_minicard_label->fieldname = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 2, + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard_label->width / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + if ( e_minicard_label->fieldname_text ) + { + gnome_canvas_item_set( e_minicard_label->fieldname, + "text", e_minicard_label->fieldname_text, + NULL ); + g_free( e_minicard_label->fieldname_text ); + } + e_minicard_label->field = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) ( e_minicard_label->width / 2 + 2 ), + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( ( e_minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + + if ( e_minicard_label->field_text ) + { + gnome_canvas_item_set( e_minicard_label->field, + "text", e_minicard_label->field_text, + NULL ); + g_free( e_minicard_label->field_text ); + } + if (!item->canvas->aa) + { + } + +} + +static void +e_minicard_label_unrealize (GnomeCanvasItem *item) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) (item); +} + +static gboolean +e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", "grey50", + "fill_color", "grey90", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", NULL, + "fill_color", NULL, + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_label( EMinicardLabel *minicard_label ) +{ + if ( GTK_OBJECT_FLAGS( minicard_label ) & GNOME_CANVAS_ITEM_REALIZED ) + { + gnome_canvas_item_set( minicard_label->rect, + "x2", (double) minicard_label->width - 1, + "y2", (double) minicard_label->height - 1, + NULL ); + gnome_canvas_item_set( minicard_label->fieldname, + "clip_width", (double) ( minicard_label->width / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + gnome_canvas_item_set( minicard_label->field, + "x", (double) ( minicard_label->width / 2 + 2 ), + "clip_width", (double) ( ( minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + } +} diff --git a/widgets/e-minicard-label.h b/widgets/e-minicard-label.h new file mode 100644 index 0000000000..dbf9c3944a --- /dev/null +++ b/widgets/e-minicard-label.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard-label.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_MINICARD_LABEL_H__ +#define __E_MINICARD_LABEL_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicardLabel - A label doing focus with non-marching ants. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the label + * height double R height of the label + * field string RW text in the field label + * fieldname string RW text in the fieldname label + */ + +#define E_MINICARD_LABEL_TYPE (e_minicard_label_get_type ()) +#define E_MINICARD_LABEL(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_LABEL_TYPE, EMinicardLabel)) +#define E_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_LABEL_TYPE, EMiniCardLabelClass)) +#define E_IS_MINICARD_LABEL(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_LABEL_TYPE)) +#define E_IS_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_LABEL_TYPE)) + + +typedef struct _EMinicardLabel EMinicardLabel; +typedef struct _EMinicardLabelClass EMinicardLabelClass; + +struct _EMinicardLabel +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + double width; + double height; + GnomeCanvasItem *fieldname; + GnomeCanvasItem *field; + GnomeCanvasItem *rect; + char *fieldname_text; + char *field_text; +}; + +struct _EMinicardLabelClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_label_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_LABEL_H__ */ diff --git a/widgets/e-minicard.c b/widgets/e-minicard.c new file mode 100644 index 0000000000..a5602baef4 --- /dev/null +++ b/widgets/e-minicard.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard.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-minicard.h" +#include "e-minicard-label.h" +static void e_minicard_init (EMinicard *card); +static void e_minicard_class_init (EMinicardClass *klass); +static void e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_realize (GnomeCanvasItem *item); +static void e_minicard_unrealize (GnomeCanvasItem *item); + +static void _update_card ( EMinicard *minicard ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_CARD +}; + +GtkType +e_minicard_get_type (void) +{ + static GtkType minicard_type = 0; + + if (!minicard_type) + { + static const GtkTypeInfo minicard_info = + { + "EMinicard", + sizeof (EMinicard), + sizeof (EMinicardClass), + (GtkClassInitFunc) e_minicard_class_init, + (GtkObjectInitFunc) e_minicard_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_info); + } + + return minicard_type; +} + +static void +e_minicard_class_init (EMinicardClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicard::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicard::height", GTK_TYPE_DOUBLE, + GTK_ARG_READABLE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicard::card", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_CARD); + + object_class->set_arg = e_minicard_set_arg; + object_class->get_arg = e_minicard_get_arg; + /* object_class->destroy = e_minicard_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_realize; + item_class->unrealize = e_minicard_unrealize; + item_class->event = e_minicard_event; +} + +static void +e_minicard_init (EMinicard *minicard) +{ + /* minicard->card = NULL;*/ + minicard->rect = NULL; + minicard->fields = NULL; + minicard->width = 10; + minicard->height = 10; +} + +static void +e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicard *e_minicard; + + item = GNOME_CANVAS_ITEM (o); + e_minicard = E_MINICARD (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard->width = GTK_VALUE_DOUBLE (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item); + break; + case ARG_CARD: + /* e_minicard->card = GTK_VALUE_POINTER (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item);*/ + break; + } +} + +static void +e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard->height; + break; + case ARG_CARD: + /* GTK_VALUE_POINTER (*arg) = e_minicard->card; */ + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_realize (GnomeCanvasItem *item) +{ + double text_height; + EMinicard *e_minicard; + GnomeCanvasGroup *group; + + e_minicard = E_MINICARD (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item); + + e_minicard->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard->width - 1, + "y2", (double) e_minicard->height - 1, + "outline_color", NULL, + NULL ); + + e_minicard->header_rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 2, + "y1", (double) 2, + "x2", (double) e_minicard->width - 3, + "y2", (double) e_minicard->height - 3, + "fill_color", "grey70", + NULL ); + + e_minicard->header_text = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 6, + "y", (double) 6, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard->width - 12 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-bold-10", + "fill_color", "black", + "text", "Chris Lahey", + NULL ); + + gtk_object_get( GTK_OBJECT( e_minicard->header_text ), + "text_height", &text_height, + NULL ); + + e_minicard->height = text_height + 12.0; + + gnome_canvas_item_set( e_minicard->header_rect, + "y2", text_height + 9.0, + NULL ); + + gnome_canvas_item_set( e_minicard->header_text, + "clip_height", text_height, + NULL ); + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4, + "height", text_height + 3, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ) ); + e_minicard->height += text_height + 3; + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4.0, + "height", text_height + 3.0, + "fieldname", "Email:", + "field", "clahey@helixcode.com", + NULL ) ); + e_minicard->height += text_height + 3; + e_minicard->height += 2; + + gnome_canvas_item_set( e_minicard->rect, + "y2", e_minicard->height - 1, + NULL ); + + if (!item->canvas->aa) + { + } +} + +static void +e_minicard_unrealize (GnomeCanvasItem *item) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); +} + +static gboolean +e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "darkblue", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "white", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", NULL, + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "black", + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_card( EMinicard *minicard ) +{ + if ( GTK_OBJECT_FLAGS( minicard ) & GNOME_CANVAS_ITEM_REALIZED ) + { + GList *field; + gnome_canvas_item_set( minicard->rect, + "x2", (double) minicard->width - 1.0, + "y2", (double) minicard->height - 1.0, + NULL ); + gnome_canvas_item_set( minicard->header_rect, + "x2", (double) minicard->width - 4.0, + NULL ); + gnome_canvas_item_set( minicard->header_text, + "clip_width", (double) minicard->width - 12, + NULL ); + for ( field = minicard->fields; field; field = g_list_next( field ) ) + { + gnome_canvas_item_set( GNOME_CANVAS_ITEM( field->data ), + "width", minicard->width - 4.0, + NULL ); + } + } +} diff --git a/widgets/e-minicard.h b/widgets/e-minicard.h new file mode 100644 index 0000000000..759cc4ffb7 --- /dev/null +++ b/widgets/e-minicard.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard.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_MINICARD_H__ +#define __E_MINICARD_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicard - A small card displaying information about a contact. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the card + * height double R height of the card + * card ECard* RW Pointer to the ECard + */ + +#define E_MINICARD_TYPE (e_minicard_get_type ()) +#define E_MINICARD(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_TYPE, EMinicard)) +#define E_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_TYPE, EMinicardClass)) +#define E_IS_MINICARD(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_TYPE)) +#define E_IS_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_TYPE)) + + +typedef struct _EMinicard EMinicard; +typedef struct _EMinicardClass EMinicardClass; + +struct _EMinicard +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + /* ECard *card; */ + + GnomeCanvasItem *rect; + GnomeCanvasItem *header_rect; + GnomeCanvasItem *header_text; + GList *fields; /* Of type GnomeCanvasItem. */ + + double width; + double height; +}; + +struct _EMinicardClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_H__ */ diff --git a/widgets/e-minicard/e-minicard-label.c b/widgets/e-minicard/e-minicard-label.c new file mode 100644 index 0000000000..e3c61ff9bf --- /dev/null +++ b/widgets/e-minicard/e-minicard-label.c @@ -0,0 +1,331 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard-label.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-minicard-label.h" +static void e_minicard_label_init (EMinicardLabel *card); +static void e_minicard_label_class_init (EMinicardLabelClass *klass); +static void e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_label_realize (GnomeCanvasItem *item); +static void e_minicard_label_unrealize (GnomeCanvasItem *item); + +static void _update_label( EMinicardLabel *minicard_label ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_FIELD, + ARG_FIELDNAME +}; + +GtkType +e_minicard_label_get_type (void) +{ + static GtkType minicard_label_type = 0; + + if (!minicard_label_type) + { + static const GtkTypeInfo minicard_label_info = + { + "EMinicardLabel", + sizeof (EMinicardLabel), + sizeof (EMinicardLabelClass), + (GtkClassInitFunc) e_minicard_label_class_init, + (GtkObjectInitFunc) e_minicard_label_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_label_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_label_info); + } + + return minicard_label_type; +} + +static void +e_minicard_label_class_init (EMinicardLabelClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicardLabel::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicardLabel::height", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicardLabel::field", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELD); + gtk_object_add_arg_type ("EMinicardLabel::fieldname", GTK_TYPE_STRING, + GTK_ARG_READWRITE, ARG_FIELDNAME); + + object_class->set_arg = e_minicard_label_set_arg; + object_class->get_arg = e_minicard_label_get_arg; + /* object_class->destroy = e_minicard_label_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_label_realize; + item_class->unrealize = e_minicard_label_unrealize; + item_class->event = e_minicard_label_event; +} + +static void +e_minicard_label_init (EMinicardLabel *minicard_label) +{ + GnomeCanvasGroup *group = GNOME_CANVAS_GROUP( minicard_label ); + minicard_label->width = 10; + minicard_label->height = 10; + minicard_label->rect = NULL; + minicard_label->fieldname = NULL; + minicard_label->field = NULL; + minicard_label->fieldname_text = NULL; + minicard_label->field_text = NULL; +} + +static void +e_minicard_label_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicardLabel *e_minicard_label; + + item = GNOME_CANVAS_ITEM (o); + e_minicard_label = E_MINICARD_LABEL (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard_label->width = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_HEIGHT: + e_minicard_label->height = GTK_VALUE_DOUBLE (*arg); + _update_label( e_minicard_label ); + gnome_canvas_item_request_update (item); + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + gnome_canvas_item_set( e_minicard_label->field, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->field_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + gnome_canvas_item_set( e_minicard_label->fieldname, "text", GTK_VALUE_STRING (*arg), NULL ); + else + e_minicard_label->fieldname_text = g_strdup( GTK_VALUE_STRING (*arg) ); + break; + } +} + +static void +e_minicard_label_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicardLabel *e_minicard_label; + char *temp; + + e_minicard_label = E_MINICARD_LABEL (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard_label->height; + break; + case ARG_FIELD: + if ( e_minicard_label->field ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->field ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->field_text ); + break; + case ARG_FIELDNAME: + if ( e_minicard_label->fieldname ) + { + gtk_object_get( GTK_OBJECT( e_minicard_label->fieldname ), "text", &temp, NULL ); + GTK_VALUE_STRING (*arg) = temp; + } + else + GTK_VALUE_STRING (*arg) = g_strdup( e_minicard_label->fieldname_text ); + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_label_realize (GnomeCanvasItem *item) +{ + double ascent, descent; + EMinicardLabel *e_minicard_label; + GnomeCanvasGroup *group; + + e_minicard_label = E_MINICARD_LABEL (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->realize) (item); + + e_minicard_label->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard_label->width - 1, + "y2", (double) e_minicard_label->height - 1, + "outline_color", NULL, + NULL ); + e_minicard_label->fieldname = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 2, + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard_label->width / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + if ( e_minicard_label->fieldname_text ) + { + gnome_canvas_item_set( e_minicard_label->fieldname, + "text", e_minicard_label->fieldname_text, + NULL ); + g_free( e_minicard_label->fieldname_text ); + } + e_minicard_label->field = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) ( e_minicard_label->width / 2 + 2 ), + "y", (double) 1, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( ( e_minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( e_minicard_label->height - 3 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-10", + "fill_color", "black", + NULL ); + + if ( e_minicard_label->field_text ) + { + gnome_canvas_item_set( e_minicard_label->field, + "text", e_minicard_label->field_text, + NULL ); + g_free( e_minicard_label->field_text ); + } + if (!item->canvas->aa) + { + } + +} + +static void +e_minicard_label_unrealize (GnomeCanvasItem *item) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) + (* GNOME_CANVAS_ITEM_CLASS( parent_class )->unrealize) (item); +} + +static gboolean +e_minicard_label_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicardLabel *e_minicard_label; + + e_minicard_label = E_MINICARD_LABEL (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", "grey50", + "fill_color", "grey90", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard_label->rect, + "outline_color", NULL, + "fill_color", NULL, + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_label( EMinicardLabel *minicard_label ) +{ + if ( GTK_OBJECT_FLAGS( minicard_label ) & GNOME_CANVAS_ITEM_REALIZED ) + { + gnome_canvas_item_set( minicard_label->rect, + "x2", (double) minicard_label->width - 1, + "y2", (double) minicard_label->height - 1, + NULL ); + gnome_canvas_item_set( minicard_label->fieldname, + "clip_width", (double) ( minicard_label->width / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + gnome_canvas_item_set( minicard_label->field, + "x", (double) ( minicard_label->width / 2 + 2 ), + "clip_width", (double) ( ( minicard_label->width + 1 ) / 2 - 4 ), + "clip_height", (double) ( minicard_label->height - 3 ), + "fill_color", "black", + NULL ); + } +} diff --git a/widgets/e-minicard/e-minicard-label.h b/widgets/e-minicard/e-minicard-label.h new file mode 100644 index 0000000000..dbf9c3944a --- /dev/null +++ b/widgets/e-minicard/e-minicard-label.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard-label.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_MINICARD_LABEL_H__ +#define __E_MINICARD_LABEL_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicardLabel - A label doing focus with non-marching ants. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the label + * height double R height of the label + * field string RW text in the field label + * fieldname string RW text in the fieldname label + */ + +#define E_MINICARD_LABEL_TYPE (e_minicard_label_get_type ()) +#define E_MINICARD_LABEL(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_LABEL_TYPE, EMinicardLabel)) +#define E_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_LABEL_TYPE, EMiniCardLabelClass)) +#define E_IS_MINICARD_LABEL(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_LABEL_TYPE)) +#define E_IS_MINICARD_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_LABEL_TYPE)) + + +typedef struct _EMinicardLabel EMinicardLabel; +typedef struct _EMinicardLabelClass EMinicardLabelClass; + +struct _EMinicardLabel +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + double width; + double height; + GnomeCanvasItem *fieldname; + GnomeCanvasItem *field; + GnomeCanvasItem *rect; + char *fieldname_text; + char *field_text; +}; + +struct _EMinicardLabelClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_label_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_LABEL_H__ */ diff --git a/widgets/e-minicard/e-minicard.c b/widgets/e-minicard/e-minicard.c new file mode 100644 index 0000000000..a5602baef4 --- /dev/null +++ b/widgets/e-minicard/e-minicard.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-minicard.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-minicard.h" +#include "e-minicard-label.h" +static void e_minicard_init (EMinicard *card); +static void e_minicard_class_init (EMinicardClass *klass); +static void e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id); +static void e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static gboolean e_minicard_event (GnomeCanvasItem *item, GdkEvent *event); +static void e_minicard_realize (GnomeCanvasItem *item); +static void e_minicard_unrealize (GnomeCanvasItem *item); + +static void _update_card ( EMinicard *minicard ); + +static GnomeCanvasGroupClass *parent_class = NULL; + +/* The arguments we take */ +enum { + ARG_0, + ARG_WIDTH, + ARG_HEIGHT, + ARG_CARD +}; + +GtkType +e_minicard_get_type (void) +{ + static GtkType minicard_type = 0; + + if (!minicard_type) + { + static const GtkTypeInfo minicard_info = + { + "EMinicard", + sizeof (EMinicard), + sizeof (EMinicardClass), + (GtkClassInitFunc) e_minicard_class_init, + (GtkObjectInitFunc) e_minicard_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + minicard_type = gtk_type_unique (gnome_canvas_group_get_type (), &minicard_info); + } + + return minicard_type; +} + +static void +e_minicard_class_init (EMinicardClass *klass) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + item_class = (GnomeCanvasItemClass *) klass; + + parent_class = gtk_type_class (gnome_canvas_group_get_type ()); + + gtk_object_add_arg_type ("EMinicard::width", GTK_TYPE_DOUBLE, + GTK_ARG_READWRITE, ARG_WIDTH); + gtk_object_add_arg_type ("EMinicard::height", GTK_TYPE_DOUBLE, + GTK_ARG_READABLE, ARG_HEIGHT); + gtk_object_add_arg_type ("EMinicard::card", GTK_TYPE_OBJECT, + GTK_ARG_READWRITE, ARG_CARD); + + object_class->set_arg = e_minicard_set_arg; + object_class->get_arg = e_minicard_get_arg; + /* object_class->destroy = e_minicard_destroy; */ + + /* GnomeCanvasItem method overrides */ + item_class->realize = e_minicard_realize; + item_class->unrealize = e_minicard_unrealize; + item_class->event = e_minicard_event; +} + +static void +e_minicard_init (EMinicard *minicard) +{ + /* minicard->card = NULL;*/ + minicard->rect = NULL; + minicard->fields = NULL; + minicard->width = 10; + minicard->height = 10; +} + +static void +e_minicard_set_arg (GtkObject *o, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EMinicard *e_minicard; + + item = GNOME_CANVAS_ITEM (o); + e_minicard = E_MINICARD (o); + + switch (arg_id){ + case ARG_WIDTH: + e_minicard->width = GTK_VALUE_DOUBLE (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item); + break; + case ARG_CARD: + /* e_minicard->card = GTK_VALUE_POINTER (*arg); + _update_card(e_minicard); + gnome_canvas_item_request_update (item);*/ + break; + } +} + +static void +e_minicard_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (object); + + switch (arg_id) { + case ARG_WIDTH: + GTK_VALUE_DOUBLE (*arg) = e_minicard->width; + break; + case ARG_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = e_minicard->height; + break; + case ARG_CARD: + /* GTK_VALUE_POINTER (*arg) = e_minicard->card; */ + break; + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +static void +e_minicard_realize (GnomeCanvasItem *item) +{ + double text_height; + EMinicard *e_minicard; + GnomeCanvasGroup *group; + + e_minicard = E_MINICARD (item); + group = GNOME_CANVAS_GROUP( item ); + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item); + + e_minicard->rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) e_minicard->width - 1, + "y2", (double) e_minicard->height - 1, + "outline_color", NULL, + NULL ); + + e_minicard->header_rect = + gnome_canvas_item_new( group, + gnome_canvas_rect_get_type(), + "x1", (double) 2, + "y1", (double) 2, + "x2", (double) e_minicard->width - 3, + "y2", (double) e_minicard->height - 3, + "fill_color", "grey70", + NULL ); + + e_minicard->header_text = + gnome_canvas_item_new( group, + e_text_get_type(), + "x", (double) 6, + "y", (double) 6, + "anchor", GTK_ANCHOR_NW, + "clip_width", (double) ( e_minicard->width - 12 ), + "clip", TRUE, + "use_ellipsis", TRUE, + "font", "lucidasans-bold-10", + "fill_color", "black", + "text", "Chris Lahey", + NULL ); + + gtk_object_get( GTK_OBJECT( e_minicard->header_text ), + "text_height", &text_height, + NULL ); + + e_minicard->height = text_height + 12.0; + + gnome_canvas_item_set( e_minicard->header_rect, + "y2", text_height + 9.0, + NULL ); + + gnome_canvas_item_set( e_minicard->header_text, + "clip_height", text_height, + NULL ); + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4, + "height", text_height + 3, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ) ); + e_minicard->height += text_height + 3; + + e_minicard->fields = + g_list_append( e_minicard->fields, + gnome_canvas_item_new( group, + e_minicard_label_get_type(), + "x", (double) 2, + "y", e_minicard->height, + "width", e_minicard->width - 4.0, + "height", text_height + 3.0, + "fieldname", "Email:", + "field", "clahey@helixcode.com", + NULL ) ); + e_minicard->height += text_height + 3; + e_minicard->height += 2; + + gnome_canvas_item_set( e_minicard->rect, + "y2", e_minicard->height - 1, + NULL ); + + if (!item->canvas->aa) + { + } +} + +static void +e_minicard_unrealize (GnomeCanvasItem *item) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + if (!item->canvas->aa) + { + } + + if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) + (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item); +} + +static gboolean +e_minicard_event (GnomeCanvasItem *item, GdkEvent *event) +{ + EMinicard *e_minicard; + + e_minicard = E_MINICARD (item); + + switch( event->type ) + { + case GDK_FOCUS_CHANGE: + { + GdkEventFocus *focus_event = (GdkEventFocus *) event; + if ( focus_event->in ) + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "darkblue", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "white", + NULL ); + } + else + { + gnome_canvas_item_set( e_minicard->rect, + "outline_color", NULL, + NULL ); + gnome_canvas_item_set( e_minicard->header_rect, + "fill_color", "grey50", + NULL ); + gnome_canvas_item_set( e_minicard->header_text, + "fill_color", "black", + NULL ); + } + } + break; + default: + break; + } + + if (GNOME_CANVAS_ITEM_CLASS( parent_class )->event) + return (* GNOME_CANVAS_ITEM_CLASS( parent_class )->event) (item, event); + else + return 0; +} + +static void +_update_card( EMinicard *minicard ) +{ + if ( GTK_OBJECT_FLAGS( minicard ) & GNOME_CANVAS_ITEM_REALIZED ) + { + GList *field; + gnome_canvas_item_set( minicard->rect, + "x2", (double) minicard->width - 1.0, + "y2", (double) minicard->height - 1.0, + NULL ); + gnome_canvas_item_set( minicard->header_rect, + "x2", (double) minicard->width - 4.0, + NULL ); + gnome_canvas_item_set( minicard->header_text, + "clip_width", (double) minicard->width - 12, + NULL ); + for ( field = minicard->fields; field; field = g_list_next( field ) ) + { + gnome_canvas_item_set( GNOME_CANVAS_ITEM( field->data ), + "width", minicard->width - 4.0, + NULL ); + } + } +} diff --git a/widgets/e-minicard/e-minicard.h b/widgets/e-minicard/e-minicard.h new file mode 100644 index 0000000000..759cc4ffb7 --- /dev/null +++ b/widgets/e-minicard/e-minicard.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-minicard.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_MINICARD_H__ +#define __E_MINICARD_H__ + +#include <gnome.h> + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +/* EMinicard - A small card displaying information about a contact. + * + * The following arguments are available: + * + * name type read/write description + * -------------------------------------------------------------------------------- + * width double RW width of the card + * height double R height of the card + * card ECard* RW Pointer to the ECard + */ + +#define E_MINICARD_TYPE (e_minicard_get_type ()) +#define E_MINICARD(obj) (GTK_CHECK_CAST ((obj), E_MINICARD_TYPE, EMinicard)) +#define E_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_MINICARD_TYPE, EMinicardClass)) +#define E_IS_MINICARD(obj) (GTK_CHECK_TYPE ((obj), E_MINICARD_TYPE)) +#define E_IS_MINICARD_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_MINICARD_TYPE)) + + +typedef struct _EMinicard EMinicard; +typedef struct _EMinicardClass EMinicardClass; + +struct _EMinicard +{ + GnomeCanvasGroup parent; + + /* item specific fields */ + /* ECard *card; */ + + GnomeCanvasItem *rect; + GnomeCanvasItem *header_rect; + GnomeCanvasItem *header_text; + GList *fields; /* Of type GnomeCanvasItem. */ + + double width; + double height; +}; + +struct _EMinicardClass +{ + GnomeCanvasGroupClass parent_class; +}; + + +GtkType e_minicard_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __E_MINICARD_H__ */ diff --git a/widgets/e-minicard/test-minicard-label.c b/widgets/e-minicard/test-minicard-label.c new file mode 100644 index 0000000000..67c17a0ace --- /dev/null +++ b/widgets/e-minicard/test-minicard-label.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard-label.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard-label.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *label; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( label, + "width", (double) allocation->width, + "height", (double) allocation->height, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Label Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard label canvas item" ), + NULL); + gtk_widget_show (about); +} + +static void button_press_callback( GtkWidget *widget, gpointer data ) +{ + gnome_canvas_item_grab_focus( label ); +} + +int main( int argc, char *argv[] ) +{ + GtkWidget *app; + GtkWidget *canvas; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Label Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Label Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + label = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_label_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + "height", (double) 100, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ); + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/widgets/e-minicard/test-minicard.c b/widgets/e-minicard/test-minicard.c new file mode 100644 index 0000000000..4f56fbe936 --- /dev/null +++ b/widgets/e-minicard/test-minicard.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *card; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( card, + "width", (double) allocation->width, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard canvas item" ), + NULL); + 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; + GtkWidget *canvas; + int i; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + for ( i = 0; i < 1; i++ ) + { + card = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + NULL ); + } + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/widgets/e-text.c b/widgets/e-text.c new file mode 100644 index 0000000000..b88130e3c8 --- /dev/null +++ b/widgets/e-text.c @@ -0,0 +1,1411 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#include <config.h> +#include <math.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> + + + +/* This defines a line of text */ +struct line { + char *text; /* Line's text, it is a pointer into the text->text string */ + int length; /* Line's length in characters */ + int width; /* Line's width in pixels */ + int ellipsis_length; /* Length before adding ellipsis */ +}; + + + +/* Object argument IDs */ +enum { + ARG_0, + ARG_TEXT, + ARG_X, + ARG_Y, + ARG_FONT, + ARG_FONTSET, + ARG_FONT_GDK, + ARG_ANCHOR, + ARG_JUSTIFICATION, + ARG_CLIP_WIDTH, + ARG_CLIP_HEIGHT, + ARG_CLIP, + ARG_X_OFFSET, + ARG_Y_OFFSET, + ARG_FILL_COLOR, + ARG_FILL_COLOR_GDK, + ARG_FILL_COLOR_RGBA, + ARG_FILL_STIPPLE, + ARG_TEXT_WIDTH, + ARG_TEXT_HEIGHT, + ARG_USE_ELLIPSIS, + ARG_ELLIPSIS +}; + + +static void e_text_class_init (ETextClass *class); +static void e_text_init (EText *text); +static void e_text_destroy (GtkObject *object); +static void e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); + +static void e_text_update (GnomeCanvasItem *item, double *affine, + ArtSVP *clip_path, int flags); +static void e_text_realize (GnomeCanvasItem *item); +static void e_text_unrealize (GnomeCanvasItem *item); +static void e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height); +static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item); +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 ETextSuckFont *e_suck_font (GdkFont *font); +static void e_suck_font_free (ETextSuckFont *suckfont); + + +static GnomeCanvasItemClass *parent_class; + + + +/** + * e_text_get_type: + * @void: + * + * Registers the &EText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EText class. + **/ +GtkType +e_text_get_type (void) +{ + static GtkType text_type = 0; + + if (!text_type) { + GtkTypeInfo text_info = { + "EText", + sizeof (EText), + sizeof (ETextClass), + (GtkClassInitFunc) e_text_class_init, + (GtkObjectInitFunc) e_text_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + text_type = gtk_type_unique (gnome_canvas_item_get_type (), &text_info); + } + + return text_type; +} + +/* Class initialization function for the text item */ +static void +e_text_class_init (ETextClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type ()); + + gtk_object_add_arg_type ("EText::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("EText::x", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("EText::y", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("EText::font", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONT); + gtk_object_add_arg_type ("EText::fontset", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONTSET); + gtk_object_add_arg_type ("EText::font_gdk", + GTK_TYPE_GDK_FONT, GTK_ARG_READWRITE, ARG_FONT_GDK); + gtk_object_add_arg_type ("EText::anchor", + GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR); + gtk_object_add_arg_type ("EText::justification", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFICATION); + gtk_object_add_arg_type ("EText::clip_width", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_WIDTH); + gtk_object_add_arg_type ("EText::clip_height", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_HEIGHT); + gtk_object_add_arg_type ("EText::clip", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_CLIP); + gtk_object_add_arg_type ("EText::x_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X_OFFSET); + gtk_object_add_arg_type ("EText::y_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y_OFFSET); + gtk_object_add_arg_type ("EText::fill_color", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR); + gtk_object_add_arg_type ("EText::fill_color_gdk", + GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_FILL_COLOR_GDK); + gtk_object_add_arg_type ("EText::fill_color_rgba", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA); + gtk_object_add_arg_type ("EText::fill_stipple", + GTK_TYPE_GDK_WINDOW, GTK_ARG_READWRITE, ARG_FILL_STIPPLE); + gtk_object_add_arg_type ("EText::text_width", + 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::use_ellipsis", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS); + gtk_object_add_arg_type ("EText::ellipsis", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_ELLIPSIS); + + object_class->destroy = e_text_destroy; + object_class->set_arg = e_text_set_arg; + object_class->get_arg = e_text_get_arg; + + item_class->update = e_text_update; + item_class->realize = e_text_realize; + item_class->unrealize = e_text_unrealize; + item_class->draw = e_text_draw; + item_class->point = e_text_point; + item_class->bounds = e_text_bounds; + item_class->render = e_text_render; +} + +/* Object initialization function for the text item */ +static void +e_text_init (EText *text) +{ + text->x = 0.0; + text->y = 0.0; + text->anchor = GTK_ANCHOR_CENTER; + text->justification = GTK_JUSTIFY_LEFT; + text->clip_width = 0.0; + text->clip_height = 0.0; + text->xofs = 0.0; + text->yofs = 0.0; + text->ellipsis = NULL; + text->use_ellipsis = FALSE; + text->ellipsis_width = 0; +} + +/* Destroy handler for the text item */ +static void +e_text_destroy (GtkObject *object) +{ + EText *text; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNOME_IS_CANVAS_TEXT (object)); + + text = E_TEXT (object); + + if (text->text) + g_free (text->text); + + if (text->lines) + g_free (text->lines); + + if (text->font) + gdk_font_unref (text->font); + + if (text->suckfont) + e_suck_font_free (text->suckfont); + + if (text->stipple) + gdk_bitmap_unref (text->stipple); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +get_bounds_item_relative (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double x, y; + double clip_x, clip_y; + + item = GNOME_CANVAS_ITEM (text); + + x = text->x; + y = text->y; + + clip_x = x; + clip_y = y; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + clip_x -= text->clip_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + clip_x -= text->clip_width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + clip_y -= text->clip_height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + clip_y -= text->clip_height; + break; + } + + /* Bounds */ + + if (text->clip) { + /* maybe do bbox intersection here? */ + *px1 = clip_x; + *py1 = clip_y; + *px2 = clip_x + text->clip_width; + *py2 = clip_y + text->clip_height; + } else { + *px1 = x; + *py1 = y; + *px2 = x + text->max_width; + *py2 = y + text->height; + } +} + +static void +get_bounds (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double wx, wy; + + item = GNOME_CANVAS_ITEM (text); + + /* Get canvas pixel coordinates for text position */ + + wx = text->x; + wy = text->y; + gnome_canvas_item_i2w (item, &wx, &wy); + gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy); + + /* Get canvas pixel coordinates for clip rectangle position */ + + gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy); + text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit; + text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + text->cx -= text->max_width / 2; + text->clip_cx -= text->clip_cwidth / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + text->cx -= text->max_width; + text->clip_cx -= text->clip_cwidth; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + text->cy -= text->height / 2; + text->clip_cy -= text->clip_cheight / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + text->cy -= text->height; + text->clip_cy -= text->clip_cheight; + break; + } + + /* Bounds */ + + if (text->clip) { + *px1 = text->clip_cx; + *py1 = text->clip_cy; + *px2 = text->clip_cx + text->clip_cwidth; + *py2 = text->clip_cy + text->clip_cheight; + } else { + *px1 = text->cx; + *py1 = text->cy; + *px2 = text->cx + text->max_width; + *py2 = text->cy + text->height; + } +} + +/* Recalculates the bounding box of the text item. The bounding box is defined + * by the text's extents if the clip rectangle is disabled. If it is enabled, + * the bounding box is defined by the clip rectangle itself. + */ +static void +recalc_bounds (EText *text) +{ + GnomeCanvasItem *item; + + item = GNOME_CANVAS_ITEM (text); + + get_bounds (text, &item->x1, &item->y1, &item->x2, &item->y2); + + gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); +} + +static void +calc_ellipsis (EText *text) +{ + if (text->font) + text->ellipsis_width = + gdk_text_width (text->font, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); +} + +/* Calculates the line widths (in pixels) of the text's splitted lines */ +static void +calc_line_widths (EText *text) +{ + struct line *lines; + int i; + int j; + + lines = text->lines; + text->max_width = 0; + + if (!lines) + return; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + if (text->font) { + lines->width = gdk_text_width (text->font, + lines->text, lines->length); + lines->ellipsis_length = 0; + } else { + lines->width = 0; + } + + if (text->clip && + text->use_ellipsis && + lines->width > text->clip_width) { + if (text->font) { + lines->ellipsis_length = 0; + for (j = 0; j < lines->length; j++ ) { + if (gdk_text_width (text->font, lines->text, j) + text->ellipsis_width <= text->clip_width) + lines->ellipsis_length = j; + else + break; + } + } + else + lines->ellipsis_length = 0; + lines->width = gdk_text_width (text->font, lines->text, lines->ellipsis_length) + + text->ellipsis_width; + } + else + lines->ellipsis_length = lines->length; + + if (lines->width > text->max_width) + text->max_width = lines->width; + } + + lines++; + } +} + +/* Splits the text of the text item into lines */ +static void +split_into_lines (EText *text) +{ + char *p; + struct line *lines; + int len; + + /* Free old array of lines */ + + if (text->lines) + g_free (text->lines); + + text->lines = NULL; + text->num_lines = 0; + + if (!text->text) + return; + + /* First, count the number of lines */ + + for (p = text->text; *p; p++) + if (*p == '\n') + text->num_lines++; + + text->num_lines++; + + /* Allocate array of lines and calculate split positions */ + + text->lines = lines = g_new0 (struct line, text->num_lines); + len = 0; + + for (p = text->text; *p; p++) { + if (*p == '\n') { + lines->length = len; + lines++; + len = 0; + } else if (len == 0) { + len++; + lines->text = p; + } else + len++; + } + + lines->length = len; + + calc_line_widths (text); +} + +/* Convenience function to set the text's GC's foreground color */ +static void +set_text_gc_foreground (EText *text) +{ + GdkColor c; + + if (!text->gc) + return; + + c.pixel = text->pixel; + gdk_gc_set_foreground (text->gc, &c); +} + +/* Sets the stipple pattern for the text */ +static void +set_stipple (EText *text, GdkBitmap *stipple, int reconfigure) +{ + if (text->stipple && !reconfigure) + gdk_bitmap_unref (text->stipple); + + text->stipple = stipple; + if (stipple && !reconfigure) + gdk_bitmap_ref (stipple); + + if (text->gc) { + if (stipple) { + gdk_gc_set_stipple (text->gc, stipple); + gdk_gc_set_fill (text->gc, GDK_STIPPLED); + } else + gdk_gc_set_fill (text->gc, GDK_SOLID); + } +} + +/* Set_arg handler for the text item */ +static void +e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EText *text; + GdkColor color = { 0, 0, 0, 0, }; + GdkColor *pcolor; + gboolean color_changed; + int have_pixel; + + item = GNOME_CANVAS_ITEM (object); + text = E_TEXT (object); + + color_changed = FALSE; + have_pixel = FALSE; + + switch (arg_id) { + case ARG_TEXT: + if (text->text) + g_free (text->text); + + text->text = g_strdup (GTK_VALUE_STRING (*arg)); + split_into_lines (text); + recalc_bounds (text); + break; + + case ARG_X: + text->x = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y: + text->y = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FONT: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_font_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONTSET: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_fontset_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONT_GDK: + if (text->font) + gdk_font_unref (text->font); + + text->font = GTK_VALUE_BOXED (*arg); + gdk_font_ref (text->font); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ANCHOR: + text->anchor = GTK_VALUE_ENUM (*arg); + recalc_bounds (text); + break; + + case ARG_JUSTIFICATION: + text->justification = GTK_VALUE_ENUM (*arg); + break; + + case ARG_CLIP_WIDTH: + text->clip_width = fabs (GTK_VALUE_DOUBLE (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_CLIP_HEIGHT: + text->clip_height = fabs (GTK_VALUE_DOUBLE (*arg)); + recalc_bounds (text); + break; + + case ARG_CLIP: + text->clip = GTK_VALUE_BOOL (*arg); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_X_OFFSET: + text->xofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y_OFFSET: + text->yofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FILL_COLOR: + if (GTK_VALUE_STRING (*arg)) + gdk_color_parse (GTK_VALUE_STRING (*arg), &color); + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_GDK: + pcolor = GTK_VALUE_BOXED (*arg); + if (pcolor) { + color = *pcolor; + gdk_color_context_query_color (item->canvas->cc, &color); + have_pixel = TRUE; + } + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_RGBA: + text->rgba = GTK_VALUE_UINT (*arg); + color_changed = TRUE; + break; + + case ARG_FILL_STIPPLE: + set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE); + break; + + case ARG_USE_ELLIPSIS: + text->use_ellipsis = GTK_VALUE_BOOL (*arg); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ELLIPSIS: + if (text->ellipsis) + g_free (text->ellipsis); + + text->ellipsis = g_strdup (GTK_VALUE_STRING (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + default: + break; + } + + if (color_changed) { + if (have_pixel) + text->pixel = color.pixel; + else + text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba); + + if (!item->canvas->aa) + set_text_gc_foreground (text); + + gnome_canvas_item_request_update (item); + } +} + +/* Get_arg handler for the text item */ +static void +e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EText *text; + GdkColor *color; + + text = E_TEXT (object); + + switch (arg_id) { + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (text->text); + break; + + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = text->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = text->y; + break; + + case ARG_FONT_GDK: + GTK_VALUE_BOXED (*arg) = text->font; + break; + + case ARG_ANCHOR: + GTK_VALUE_ENUM (*arg) = text->anchor; + break; + + case ARG_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = text->justification; + break; + + case ARG_CLIP_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->clip_width; + break; + + case ARG_CLIP_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->clip_height; + break; + + case ARG_CLIP: + GTK_VALUE_BOOL (*arg) = text->clip; + break; + + case ARG_X_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->xofs; + break; + + case ARG_Y_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->yofs; + break; + + case ARG_FILL_COLOR_GDK: + color = g_new (GdkColor, 1); + color->pixel = text->pixel; + gdk_color_context_query_color (text->item.canvas->cc, color); + GTK_VALUE_BOXED (*arg) = color; + break; + + case ARG_FILL_COLOR_RGBA: + GTK_VALUE_UINT (*arg) = text->rgba; + break; + + case ARG_FILL_STIPPLE: + GTK_VALUE_BOXED (*arg) = text->stipple; + break; + + case ARG_TEXT_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->max_width / text->item.canvas->pixels_per_unit; + break; + + case ARG_TEXT_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit; + break; + + case ARG_USE_ELLIPSIS: + GTK_VALUE_BOOL (*arg) = text->use_ellipsis; + break; + + case ARG_ELLIPSIS: + GTK_VALUE_STRING (*arg) = g_strdup (text->ellipsis); + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/* Update handler for the text item */ +static void +e_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) +{ + EText *text; + double x1, y1, x2, y2; + ArtDRect i_bbox, c_bbox; + int i; + + text = E_TEXT (item); + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_path, flags); + + if (!item->canvas->aa) { + set_text_gc_foreground (text); + set_stipple (text, text->stipple, TRUE); + get_bounds (text, &x1, &y1, &x2, &y2); + + gnome_canvas_update_bbox (item, x1, y1, x2, y2); + } else { + /* aa rendering */ + for (i = 0; i < 6; i++) + text->affine[i] = affine[i]; + get_bounds_item_relative (text, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1); + art_drect_affine_transform (&c_bbox, &i_bbox, affine); + gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1); + + } +} + +/* Realize handler for the text item */ +static void +e_text_realize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + if (parent_class->realize) + (* parent_class->realize) (item); + + text->gc = gdk_gc_new (item->canvas->layout.bin_window); +} + +/* Unrealize handler for the text item */ +static void +e_text_unrealize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + gdk_gc_unref (text->gc); + text->gc = NULL; + + if (parent_class->unrealize) + (* parent_class->unrealize) (item); +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static double +get_line_xpos_item_relative (EText *text, struct line *line) +{ + double x; + + x = text->x; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + break; + } + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) * 0.5; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Calculates the y position of the first line of text. */ +static double +get_line_ypos_item_relative (EText *text) +{ + double y; + + y = text->y; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + break; + } + + return y; +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static int +get_line_xpos (EText *text, struct line *line) +{ + int x; + + x = text->cx; + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) / 2; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Draw handler for the text item */ +static void +e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + EText *text; + GdkRectangle rect; + struct line *lines; + int i; + int xpos, ypos; + + text = E_TEXT (item); + + if (!text->text || !text->font) + return; + + if (text->clip) { + rect.x = text->clip_cx - x; + rect.y = text->clip_cy - y; + rect.width = text->clip_cwidth; + rect.height = text->clip_cheight; + + gdk_gc_set_clip_rectangle (text->gc, &rect); + } + lines = text->lines; + ypos = text->cy + text->font->ascent; + + if (text->stipple) + gnome_canvas_set_stipple_origin (item->canvas, text->gc); + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + xpos = get_line_xpos (text, lines); + if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) { + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->ellipsis_length); + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x + + lines->width - text->ellipsis_width, + ypos - y, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); + } else + + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->length); + } + + ypos += text->font->ascent + text->font->descent; + lines++; + } + + if (text->clip) + gdk_gc_set_clip_rectangle (text->gc, NULL); +} + +/* Render handler for the text item */ +static void +e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) +{ + EText *text; + guint32 fg_color; + double xpos, ypos; + struct line *lines; + int i, j; + double affine[6]; + ETextSuckFont *suckfont; + int dx, dy; + ArtPoint start_i, start_c; + + text = E_TEXT (item); + + if (!text->text || !text->font || !text->suckfont) + return; + + suckfont = text->suckfont; + + fg_color = text->rgba; + + gnome_canvas_buf_ensure_buf (buf); + + lines = text->lines; + start_i.y = get_line_ypos_item_relative (text); + + art_affine_scale (affine, item->canvas->pixels_per_unit, item->canvas->pixels_per_unit); + for (i = 0; i < 6; i++) + affine[i] = text->affine[i]; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + start_i.x = get_line_xpos_item_relative (text, lines); + art_affine_point (&start_c, &start_i, text->affine); + xpos = start_c.x; + ypos = start_c.y; + + for (j = 0; j < lines->length; j++) { + ETextSuckChar *ch; + + ch = &suckfont->chars[(unsigned char)((lines->text)[j])]; + + affine[4] = xpos; + affine[5] = ypos; + art_rgb_bitmap_affine ( + buf->buf, + buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, + buf->buf_rowstride, + suckfont->bitmap + (ch->bitmap_offset >> 3), + ch->width, + suckfont->bitmap_height, + suckfont->bitmap_width >> 3, + fg_color, + affine, + ART_FILTER_NEAREST, NULL); + + dx = ch->left_sb + ch->width + ch->right_sb; + xpos += dx * affine[0]; + ypos += dx * affine[1]; + } + } + + dy = text->font->ascent + text->font->descent; + start_i.y += dy; + lines++; + } + + buf->is_bg = 0; +} + +/* Point handler for the text item */ +static double +e_text_point (GnomeCanvasItem *item, double x, double y, + int cx, int cy, GnomeCanvasItem **actual_item) +{ + EText *text; + int i; + struct line *lines; + int x1, y1, x2, y2; + int font_height; + int dx, dy; + double dist, best; + + text = E_TEXT (item); + + *actual_item = item; + + /* The idea is to build bounding rectangles for each of the lines of + * text (clipped by the clipping rectangle, if it is activated) and see + * whether the point is inside any of these. If it is, we are done. + * Otherwise, calculate the distance to the nearest rectangle. + */ + + if (text->font) + font_height = text->font->ascent + text->font->descent; + else + font_height = 0; + + best = 1.0e36; + + lines = text->lines; + + for (i = 0; i < text->num_lines; i++) { + /* Compute the coordinates of rectangle for the current line, + * clipping if appropriate. + */ + + x1 = get_line_xpos (text, lines); + y1 = text->cy + i * font_height; + x2 = x1 + lines->width; + y2 = y1 + font_height; + + if (text->clip) { + if (x1 < text->clip_cx) + x1 = text->clip_cx; + + if (y1 < text->clip_cy) + y1 = text->clip_cy; + + if (x2 > (text->clip_cx + text->clip_width)) + x2 = text->clip_cx + text->clip_width; + + if (y2 > (text->clip_cy + text->clip_height)) + y2 = text->clip_cy + text->clip_height; + + if ((x1 >= x2) || (y1 >= y2)) + continue; + } + + /* Calculate distance from point to rectangle */ + + if (cx < x1) + dx = x1 - cx; + else if (cx >= x2) + dx = cx - x2 + 1; + else + dx = 0; + + if (cy < y1) + dy = y1 - cy; + else if (cy >= y2) + dy = cy - y2 + 1; + else + dy = 0; + + if ((dx == 0) && (dy == 0)) + return 0.0; + + dist = sqrt (dx * dx + dy * dy); + if (dist < best) + best = dist; + + /* Next! */ + + lines++; + } + + return best / item->canvas->pixels_per_unit; +} + +/* Bounds handler for the text item */ +static void +e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + EText *text; + double width, height; + + text = E_TEXT (item); + + *x1 = text->x; + *y1 = text->y; + + if (text->clip) { + width = text->clip_width; + height = text->clip_height; + } else { + width = text->max_width / item->canvas->pixels_per_unit; + height = text->height / item->canvas->pixels_per_unit; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + *x1 -= width / 2.0; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + *x1 -= width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + *y1 -= height / 2.0; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + *y1 -= height; + break; + } + + *x2 = *x1 + width; + *y2 = *y1 + height; +} + + + +/* Routines for sucking fonts from the X server */ + +static ETextSuckFont * +e_suck_font (GdkFont *font) +{ + ETextSuckFont *suckfont; + int i; + int x, y; + char text[1]; + int lbearing, rbearing, ch_width, ascent, descent; + GdkPixmap *pixmap; + GdkColor black, white; + GdkImage *image; + GdkGC *gc; + guchar *bitmap, *line; + int width, height; + int black_pixel, pixel; + + if (!font) + return NULL; + + suckfont = g_new (ETextSuckFont, 1); + + height = font->ascent + font->descent; + x = 0; + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_text_extents (font, text, 1, + &lbearing, &rbearing, &ch_width, &ascent, &descent); + suckfont->chars[i].left_sb = lbearing; + suckfont->chars[i].right_sb = ch_width - rbearing; + suckfont->chars[i].width = rbearing - lbearing; + suckfont->chars[i].ascent = ascent; + suckfont->chars[i].descent = descent; + suckfont->chars[i].bitmap_offset = x; + x += (ch_width + 31) & -32; + } + + width = x; + + suckfont->bitmap_width = width; + suckfont->bitmap_height = height; + suckfont->ascent = font->ascent; + + pixmap = gdk_pixmap_new (NULL, suckfont->bitmap_width, + suckfont->bitmap_height, 1); + gc = gdk_gc_new (pixmap); + gdk_gc_set_font (gc, font); + + black_pixel = BlackPixel (gdk_display, DefaultScreen (gdk_display)); + black.pixel = black_pixel; + white.pixel = WhitePixel (gdk_display, DefaultScreen (gdk_display)); + gdk_gc_set_foreground (gc, &white); + gdk_draw_rectangle (pixmap, gc, 1, 0, 0, width, height); + + gdk_gc_set_foreground (gc, &black); + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_draw_text (pixmap, font, gc, + suckfont->chars[i].bitmap_offset - suckfont->chars[i].left_sb, + font->ascent, + text, 1); + } + + /* The handling of the image leaves me with distinct unease. But this + * is more or less copied out of gimp/app/text_tool.c, so it _ought_ to + * work. -RLL + */ + + image = gdk_image_get (pixmap, 0, 0, width, height); + suckfont->bitmap = g_malloc0 ((width >> 3) * height); + + line = suckfont->bitmap; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pixel = gdk_image_get_pixel (image, x, y); + if (pixel == black_pixel) + line[x >> 3] |= 128 >> (x & 7); + } + line += width >> 3; + } + + gdk_image_destroy (image); + + /* free the pixmap */ + gdk_pixmap_unref (pixmap); + + /* free the gc */ + gdk_gc_destroy (gc); + + return suckfont; +} + +static void +e_suck_font_free (ETextSuckFont *suckfont) +{ + g_free (suckfont->bitmap); + g_free (suckfont); +} diff --git a/widgets/e-text.h b/widgets/e-text.h new file mode 100644 index 0000000000..e14199f16e --- /dev/null +++ b/widgets/e-text.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#ifndef E_TEXT_H +#define E_TEXT_H + +#include <gnome.h> + + +BEGIN_GNOME_DECLS + + +/* Text item for the canvas. Text items are positioned by an anchor point and an anchor direction. + * + * A clipping rectangle may be specified for the text. The rectangle is anchored at the text's anchor + * point, and is specified by clipping width and height parameters. If the clipping rectangle is + * enabled, it will clip the text. + * + * In addition, x and y offset values may be specified. These specify an offset from the anchor + * position. If used in conjunction with the clipping rectangle, these could be used to implement + * simple scrolling of the text within the clipping rectangle. + * + * The following object arguments are available: + * + * name type read/write description + * ------------------------------------------------------------------------------------------ + * text string RW The string of the text label + * x double RW X coordinate of anchor point + * y double RW Y coordinate of anchor point + * font string W X logical font descriptor + * fontset string W X logical fontset descriptor + * font_gdk GdkFont* RW Pointer to a GdkFont + * anchor GtkAnchorType RW Anchor side for the text + * justification GtkJustification RW Justification for multiline text + * fill_color string W X color specification for text + * fill_color_gdk GdkColor* RW Pointer to an allocated GdkColor + * fill_stipple GdkBitmap* RW Stipple pattern for filling the text + * clip_width double RW Width of clip rectangle + * clip_height double RW Height of clip rectangle + * clip boolean RW Use clipping rectangle? + * x_offset double RW Horizontal offset distance from anchor position + * y_offset double RW Vertical offset distance from anchor position + * text_width double R Used to query the width of the rendered text + * text_height double R Used to query the rendered height of the text + * + * These are ignored in the AA version: + * 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 = "...". + */ + +#define E_TYPE_TEXT (e_text_get_type ()) +#define E_TEXT(obj) (GTK_CHECK_CAST ((obj), E_TYPE_TEXT, EText)) +#define E_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_TEXT, ETextClass)) +#define E_IS_TEXT(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_TEXT)) +#define E_IS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), E_TYPE_TEXT)) + + +typedef struct _EText EText; +typedef struct _ETextClass ETextClass; +typedef struct _ETextSuckFont ETextSuckFont; +typedef struct _ETextSuckChar ETextSuckChar; + +struct _ETextSuckChar { + int left_sb; + int right_sb; + int width; + int ascent; + int descent; + int bitmap_offset; /* in pixels */ +}; + +struct _ETextSuckFont { + guchar *bitmap; + gint bitmap_width; + gint bitmap_height; + gint ascent; + ETextSuckChar chars[256]; +}; + +struct _EText { + GnomeCanvasItem item; + + char *text; /* Text to display */ + gpointer lines; /* Text split into lines (private field) */ + int num_lines; /* Number of lines of text */ + + double x, y; /* Position at anchor */ + GdkFont *font; /* Font for text */ + GtkAnchorType anchor; /* Anchor side for text */ + GtkJustification justification; /* Justification for text */ + + double clip_width; /* Width of optional clip rectangle */ + double clip_height; /* Height of optional clip rectangle */ + + double xofs, yofs; /* Text offset distance from anchor position */ + + gulong pixel; /* Fill color */ + GdkBitmap *stipple; /* Stipple for text */ + GdkGC *gc; /* GC for drawing text */ + + int cx, cy; /* Top-left canvas coordinates for text */ + int clip_cx, clip_cy; /* Top-left canvas coordinates for clip rectangle */ + int clip_cwidth, clip_cheight; /* Size of clip rectangle in pixels */ + int max_width; /* Maximum width of text lines */ + int height; /* Rendered text height in pixels */ + + guint clip : 1; /* Use clip rectangle? */ + + /* Antialiased specific stuff follows */ + ETextSuckFont *suckfont; /* Sucked font */ + guint32 rgba; /* RGBA color for text */ + double affine[6]; /* The item -> canvas affine */ + + char *ellipsis; /* The ellipsis characters. NULL = "...". */ + double ellipsis_width; /* The width of the ellipsis. */ + gboolean use_ellipsis; /* Whether to use the ellipsis. */ +}; + +struct _ETextClass { + GnomeCanvasItemClass parent_class; +}; + + +/* Standard Gtk function */ +GtkType e_text_get_type (void); + + +END_GNOME_DECLS + +#endif diff --git a/widgets/e-text/e-text.c b/widgets/e-text/e-text.c new file mode 100644 index 0000000000..b88130e3c8 --- /dev/null +++ b/widgets/e-text/e-text.c @@ -0,0 +1,1411 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#include <config.h> +#include <math.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> + + + +/* This defines a line of text */ +struct line { + char *text; /* Line's text, it is a pointer into the text->text string */ + int length; /* Line's length in characters */ + int width; /* Line's width in pixels */ + int ellipsis_length; /* Length before adding ellipsis */ +}; + + + +/* Object argument IDs */ +enum { + ARG_0, + ARG_TEXT, + ARG_X, + ARG_Y, + ARG_FONT, + ARG_FONTSET, + ARG_FONT_GDK, + ARG_ANCHOR, + ARG_JUSTIFICATION, + ARG_CLIP_WIDTH, + ARG_CLIP_HEIGHT, + ARG_CLIP, + ARG_X_OFFSET, + ARG_Y_OFFSET, + ARG_FILL_COLOR, + ARG_FILL_COLOR_GDK, + ARG_FILL_COLOR_RGBA, + ARG_FILL_STIPPLE, + ARG_TEXT_WIDTH, + ARG_TEXT_HEIGHT, + ARG_USE_ELLIPSIS, + ARG_ELLIPSIS +}; + + +static void e_text_class_init (ETextClass *class); +static void e_text_init (EText *text); +static void e_text_destroy (GtkObject *object); +static void e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); + +static void e_text_update (GnomeCanvasItem *item, double *affine, + ArtSVP *clip_path, int flags); +static void e_text_realize (GnomeCanvasItem *item); +static void e_text_unrealize (GnomeCanvasItem *item); +static void e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height); +static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item); +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 ETextSuckFont *e_suck_font (GdkFont *font); +static void e_suck_font_free (ETextSuckFont *suckfont); + + +static GnomeCanvasItemClass *parent_class; + + + +/** + * e_text_get_type: + * @void: + * + * Registers the &EText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EText class. + **/ +GtkType +e_text_get_type (void) +{ + static GtkType text_type = 0; + + if (!text_type) { + GtkTypeInfo text_info = { + "EText", + sizeof (EText), + sizeof (ETextClass), + (GtkClassInitFunc) e_text_class_init, + (GtkObjectInitFunc) e_text_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + text_type = gtk_type_unique (gnome_canvas_item_get_type (), &text_info); + } + + return text_type; +} + +/* Class initialization function for the text item */ +static void +e_text_class_init (ETextClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type ()); + + gtk_object_add_arg_type ("EText::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("EText::x", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("EText::y", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("EText::font", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONT); + gtk_object_add_arg_type ("EText::fontset", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONTSET); + gtk_object_add_arg_type ("EText::font_gdk", + GTK_TYPE_GDK_FONT, GTK_ARG_READWRITE, ARG_FONT_GDK); + gtk_object_add_arg_type ("EText::anchor", + GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR); + gtk_object_add_arg_type ("EText::justification", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFICATION); + gtk_object_add_arg_type ("EText::clip_width", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_WIDTH); + gtk_object_add_arg_type ("EText::clip_height", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_HEIGHT); + gtk_object_add_arg_type ("EText::clip", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_CLIP); + gtk_object_add_arg_type ("EText::x_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X_OFFSET); + gtk_object_add_arg_type ("EText::y_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y_OFFSET); + gtk_object_add_arg_type ("EText::fill_color", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR); + gtk_object_add_arg_type ("EText::fill_color_gdk", + GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_FILL_COLOR_GDK); + gtk_object_add_arg_type ("EText::fill_color_rgba", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA); + gtk_object_add_arg_type ("EText::fill_stipple", + GTK_TYPE_GDK_WINDOW, GTK_ARG_READWRITE, ARG_FILL_STIPPLE); + gtk_object_add_arg_type ("EText::text_width", + 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::use_ellipsis", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS); + gtk_object_add_arg_type ("EText::ellipsis", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_ELLIPSIS); + + object_class->destroy = e_text_destroy; + object_class->set_arg = e_text_set_arg; + object_class->get_arg = e_text_get_arg; + + item_class->update = e_text_update; + item_class->realize = e_text_realize; + item_class->unrealize = e_text_unrealize; + item_class->draw = e_text_draw; + item_class->point = e_text_point; + item_class->bounds = e_text_bounds; + item_class->render = e_text_render; +} + +/* Object initialization function for the text item */ +static void +e_text_init (EText *text) +{ + text->x = 0.0; + text->y = 0.0; + text->anchor = GTK_ANCHOR_CENTER; + text->justification = GTK_JUSTIFY_LEFT; + text->clip_width = 0.0; + text->clip_height = 0.0; + text->xofs = 0.0; + text->yofs = 0.0; + text->ellipsis = NULL; + text->use_ellipsis = FALSE; + text->ellipsis_width = 0; +} + +/* Destroy handler for the text item */ +static void +e_text_destroy (GtkObject *object) +{ + EText *text; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNOME_IS_CANVAS_TEXT (object)); + + text = E_TEXT (object); + + if (text->text) + g_free (text->text); + + if (text->lines) + g_free (text->lines); + + if (text->font) + gdk_font_unref (text->font); + + if (text->suckfont) + e_suck_font_free (text->suckfont); + + if (text->stipple) + gdk_bitmap_unref (text->stipple); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +get_bounds_item_relative (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double x, y; + double clip_x, clip_y; + + item = GNOME_CANVAS_ITEM (text); + + x = text->x; + y = text->y; + + clip_x = x; + clip_y = y; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + clip_x -= text->clip_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + clip_x -= text->clip_width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + clip_y -= text->clip_height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + clip_y -= text->clip_height; + break; + } + + /* Bounds */ + + if (text->clip) { + /* maybe do bbox intersection here? */ + *px1 = clip_x; + *py1 = clip_y; + *px2 = clip_x + text->clip_width; + *py2 = clip_y + text->clip_height; + } else { + *px1 = x; + *py1 = y; + *px2 = x + text->max_width; + *py2 = y + text->height; + } +} + +static void +get_bounds (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double wx, wy; + + item = GNOME_CANVAS_ITEM (text); + + /* Get canvas pixel coordinates for text position */ + + wx = text->x; + wy = text->y; + gnome_canvas_item_i2w (item, &wx, &wy); + gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy); + + /* Get canvas pixel coordinates for clip rectangle position */ + + gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy); + text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit; + text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + text->cx -= text->max_width / 2; + text->clip_cx -= text->clip_cwidth / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + text->cx -= text->max_width; + text->clip_cx -= text->clip_cwidth; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + text->cy -= text->height / 2; + text->clip_cy -= text->clip_cheight / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + text->cy -= text->height; + text->clip_cy -= text->clip_cheight; + break; + } + + /* Bounds */ + + if (text->clip) { + *px1 = text->clip_cx; + *py1 = text->clip_cy; + *px2 = text->clip_cx + text->clip_cwidth; + *py2 = text->clip_cy + text->clip_cheight; + } else { + *px1 = text->cx; + *py1 = text->cy; + *px2 = text->cx + text->max_width; + *py2 = text->cy + text->height; + } +} + +/* Recalculates the bounding box of the text item. The bounding box is defined + * by the text's extents if the clip rectangle is disabled. If it is enabled, + * the bounding box is defined by the clip rectangle itself. + */ +static void +recalc_bounds (EText *text) +{ + GnomeCanvasItem *item; + + item = GNOME_CANVAS_ITEM (text); + + get_bounds (text, &item->x1, &item->y1, &item->x2, &item->y2); + + gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); +} + +static void +calc_ellipsis (EText *text) +{ + if (text->font) + text->ellipsis_width = + gdk_text_width (text->font, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); +} + +/* Calculates the line widths (in pixels) of the text's splitted lines */ +static void +calc_line_widths (EText *text) +{ + struct line *lines; + int i; + int j; + + lines = text->lines; + text->max_width = 0; + + if (!lines) + return; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + if (text->font) { + lines->width = gdk_text_width (text->font, + lines->text, lines->length); + lines->ellipsis_length = 0; + } else { + lines->width = 0; + } + + if (text->clip && + text->use_ellipsis && + lines->width > text->clip_width) { + if (text->font) { + lines->ellipsis_length = 0; + for (j = 0; j < lines->length; j++ ) { + if (gdk_text_width (text->font, lines->text, j) + text->ellipsis_width <= text->clip_width) + lines->ellipsis_length = j; + else + break; + } + } + else + lines->ellipsis_length = 0; + lines->width = gdk_text_width (text->font, lines->text, lines->ellipsis_length) + + text->ellipsis_width; + } + else + lines->ellipsis_length = lines->length; + + if (lines->width > text->max_width) + text->max_width = lines->width; + } + + lines++; + } +} + +/* Splits the text of the text item into lines */ +static void +split_into_lines (EText *text) +{ + char *p; + struct line *lines; + int len; + + /* Free old array of lines */ + + if (text->lines) + g_free (text->lines); + + text->lines = NULL; + text->num_lines = 0; + + if (!text->text) + return; + + /* First, count the number of lines */ + + for (p = text->text; *p; p++) + if (*p == '\n') + text->num_lines++; + + text->num_lines++; + + /* Allocate array of lines and calculate split positions */ + + text->lines = lines = g_new0 (struct line, text->num_lines); + len = 0; + + for (p = text->text; *p; p++) { + if (*p == '\n') { + lines->length = len; + lines++; + len = 0; + } else if (len == 0) { + len++; + lines->text = p; + } else + len++; + } + + lines->length = len; + + calc_line_widths (text); +} + +/* Convenience function to set the text's GC's foreground color */ +static void +set_text_gc_foreground (EText *text) +{ + GdkColor c; + + if (!text->gc) + return; + + c.pixel = text->pixel; + gdk_gc_set_foreground (text->gc, &c); +} + +/* Sets the stipple pattern for the text */ +static void +set_stipple (EText *text, GdkBitmap *stipple, int reconfigure) +{ + if (text->stipple && !reconfigure) + gdk_bitmap_unref (text->stipple); + + text->stipple = stipple; + if (stipple && !reconfigure) + gdk_bitmap_ref (stipple); + + if (text->gc) { + if (stipple) { + gdk_gc_set_stipple (text->gc, stipple); + gdk_gc_set_fill (text->gc, GDK_STIPPLED); + } else + gdk_gc_set_fill (text->gc, GDK_SOLID); + } +} + +/* Set_arg handler for the text item */ +static void +e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EText *text; + GdkColor color = { 0, 0, 0, 0, }; + GdkColor *pcolor; + gboolean color_changed; + int have_pixel; + + item = GNOME_CANVAS_ITEM (object); + text = E_TEXT (object); + + color_changed = FALSE; + have_pixel = FALSE; + + switch (arg_id) { + case ARG_TEXT: + if (text->text) + g_free (text->text); + + text->text = g_strdup (GTK_VALUE_STRING (*arg)); + split_into_lines (text); + recalc_bounds (text); + break; + + case ARG_X: + text->x = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y: + text->y = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FONT: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_font_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONTSET: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_fontset_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONT_GDK: + if (text->font) + gdk_font_unref (text->font); + + text->font = GTK_VALUE_BOXED (*arg); + gdk_font_ref (text->font); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ANCHOR: + text->anchor = GTK_VALUE_ENUM (*arg); + recalc_bounds (text); + break; + + case ARG_JUSTIFICATION: + text->justification = GTK_VALUE_ENUM (*arg); + break; + + case ARG_CLIP_WIDTH: + text->clip_width = fabs (GTK_VALUE_DOUBLE (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_CLIP_HEIGHT: + text->clip_height = fabs (GTK_VALUE_DOUBLE (*arg)); + recalc_bounds (text); + break; + + case ARG_CLIP: + text->clip = GTK_VALUE_BOOL (*arg); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_X_OFFSET: + text->xofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y_OFFSET: + text->yofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FILL_COLOR: + if (GTK_VALUE_STRING (*arg)) + gdk_color_parse (GTK_VALUE_STRING (*arg), &color); + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_GDK: + pcolor = GTK_VALUE_BOXED (*arg); + if (pcolor) { + color = *pcolor; + gdk_color_context_query_color (item->canvas->cc, &color); + have_pixel = TRUE; + } + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_RGBA: + text->rgba = GTK_VALUE_UINT (*arg); + color_changed = TRUE; + break; + + case ARG_FILL_STIPPLE: + set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE); + break; + + case ARG_USE_ELLIPSIS: + text->use_ellipsis = GTK_VALUE_BOOL (*arg); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ELLIPSIS: + if (text->ellipsis) + g_free (text->ellipsis); + + text->ellipsis = g_strdup (GTK_VALUE_STRING (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + default: + break; + } + + if (color_changed) { + if (have_pixel) + text->pixel = color.pixel; + else + text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba); + + if (!item->canvas->aa) + set_text_gc_foreground (text); + + gnome_canvas_item_request_update (item); + } +} + +/* Get_arg handler for the text item */ +static void +e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EText *text; + GdkColor *color; + + text = E_TEXT (object); + + switch (arg_id) { + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (text->text); + break; + + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = text->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = text->y; + break; + + case ARG_FONT_GDK: + GTK_VALUE_BOXED (*arg) = text->font; + break; + + case ARG_ANCHOR: + GTK_VALUE_ENUM (*arg) = text->anchor; + break; + + case ARG_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = text->justification; + break; + + case ARG_CLIP_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->clip_width; + break; + + case ARG_CLIP_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->clip_height; + break; + + case ARG_CLIP: + GTK_VALUE_BOOL (*arg) = text->clip; + break; + + case ARG_X_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->xofs; + break; + + case ARG_Y_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->yofs; + break; + + case ARG_FILL_COLOR_GDK: + color = g_new (GdkColor, 1); + color->pixel = text->pixel; + gdk_color_context_query_color (text->item.canvas->cc, color); + GTK_VALUE_BOXED (*arg) = color; + break; + + case ARG_FILL_COLOR_RGBA: + GTK_VALUE_UINT (*arg) = text->rgba; + break; + + case ARG_FILL_STIPPLE: + GTK_VALUE_BOXED (*arg) = text->stipple; + break; + + case ARG_TEXT_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->max_width / text->item.canvas->pixels_per_unit; + break; + + case ARG_TEXT_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit; + break; + + case ARG_USE_ELLIPSIS: + GTK_VALUE_BOOL (*arg) = text->use_ellipsis; + break; + + case ARG_ELLIPSIS: + GTK_VALUE_STRING (*arg) = g_strdup (text->ellipsis); + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/* Update handler for the text item */ +static void +e_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) +{ + EText *text; + double x1, y1, x2, y2; + ArtDRect i_bbox, c_bbox; + int i; + + text = E_TEXT (item); + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_path, flags); + + if (!item->canvas->aa) { + set_text_gc_foreground (text); + set_stipple (text, text->stipple, TRUE); + get_bounds (text, &x1, &y1, &x2, &y2); + + gnome_canvas_update_bbox (item, x1, y1, x2, y2); + } else { + /* aa rendering */ + for (i = 0; i < 6; i++) + text->affine[i] = affine[i]; + get_bounds_item_relative (text, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1); + art_drect_affine_transform (&c_bbox, &i_bbox, affine); + gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1); + + } +} + +/* Realize handler for the text item */ +static void +e_text_realize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + if (parent_class->realize) + (* parent_class->realize) (item); + + text->gc = gdk_gc_new (item->canvas->layout.bin_window); +} + +/* Unrealize handler for the text item */ +static void +e_text_unrealize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + gdk_gc_unref (text->gc); + text->gc = NULL; + + if (parent_class->unrealize) + (* parent_class->unrealize) (item); +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static double +get_line_xpos_item_relative (EText *text, struct line *line) +{ + double x; + + x = text->x; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + break; + } + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) * 0.5; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Calculates the y position of the first line of text. */ +static double +get_line_ypos_item_relative (EText *text) +{ + double y; + + y = text->y; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + break; + } + + return y; +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static int +get_line_xpos (EText *text, struct line *line) +{ + int x; + + x = text->cx; + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) / 2; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Draw handler for the text item */ +static void +e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + EText *text; + GdkRectangle rect; + struct line *lines; + int i; + int xpos, ypos; + + text = E_TEXT (item); + + if (!text->text || !text->font) + return; + + if (text->clip) { + rect.x = text->clip_cx - x; + rect.y = text->clip_cy - y; + rect.width = text->clip_cwidth; + rect.height = text->clip_cheight; + + gdk_gc_set_clip_rectangle (text->gc, &rect); + } + lines = text->lines; + ypos = text->cy + text->font->ascent; + + if (text->stipple) + gnome_canvas_set_stipple_origin (item->canvas, text->gc); + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + xpos = get_line_xpos (text, lines); + if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) { + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->ellipsis_length); + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x + + lines->width - text->ellipsis_width, + ypos - y, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); + } else + + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->length); + } + + ypos += text->font->ascent + text->font->descent; + lines++; + } + + if (text->clip) + gdk_gc_set_clip_rectangle (text->gc, NULL); +} + +/* Render handler for the text item */ +static void +e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) +{ + EText *text; + guint32 fg_color; + double xpos, ypos; + struct line *lines; + int i, j; + double affine[6]; + ETextSuckFont *suckfont; + int dx, dy; + ArtPoint start_i, start_c; + + text = E_TEXT (item); + + if (!text->text || !text->font || !text->suckfont) + return; + + suckfont = text->suckfont; + + fg_color = text->rgba; + + gnome_canvas_buf_ensure_buf (buf); + + lines = text->lines; + start_i.y = get_line_ypos_item_relative (text); + + art_affine_scale (affine, item->canvas->pixels_per_unit, item->canvas->pixels_per_unit); + for (i = 0; i < 6; i++) + affine[i] = text->affine[i]; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + start_i.x = get_line_xpos_item_relative (text, lines); + art_affine_point (&start_c, &start_i, text->affine); + xpos = start_c.x; + ypos = start_c.y; + + for (j = 0; j < lines->length; j++) { + ETextSuckChar *ch; + + ch = &suckfont->chars[(unsigned char)((lines->text)[j])]; + + affine[4] = xpos; + affine[5] = ypos; + art_rgb_bitmap_affine ( + buf->buf, + buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, + buf->buf_rowstride, + suckfont->bitmap + (ch->bitmap_offset >> 3), + ch->width, + suckfont->bitmap_height, + suckfont->bitmap_width >> 3, + fg_color, + affine, + ART_FILTER_NEAREST, NULL); + + dx = ch->left_sb + ch->width + ch->right_sb; + xpos += dx * affine[0]; + ypos += dx * affine[1]; + } + } + + dy = text->font->ascent + text->font->descent; + start_i.y += dy; + lines++; + } + + buf->is_bg = 0; +} + +/* Point handler for the text item */ +static double +e_text_point (GnomeCanvasItem *item, double x, double y, + int cx, int cy, GnomeCanvasItem **actual_item) +{ + EText *text; + int i; + struct line *lines; + int x1, y1, x2, y2; + int font_height; + int dx, dy; + double dist, best; + + text = E_TEXT (item); + + *actual_item = item; + + /* The idea is to build bounding rectangles for each of the lines of + * text (clipped by the clipping rectangle, if it is activated) and see + * whether the point is inside any of these. If it is, we are done. + * Otherwise, calculate the distance to the nearest rectangle. + */ + + if (text->font) + font_height = text->font->ascent + text->font->descent; + else + font_height = 0; + + best = 1.0e36; + + lines = text->lines; + + for (i = 0; i < text->num_lines; i++) { + /* Compute the coordinates of rectangle for the current line, + * clipping if appropriate. + */ + + x1 = get_line_xpos (text, lines); + y1 = text->cy + i * font_height; + x2 = x1 + lines->width; + y2 = y1 + font_height; + + if (text->clip) { + if (x1 < text->clip_cx) + x1 = text->clip_cx; + + if (y1 < text->clip_cy) + y1 = text->clip_cy; + + if (x2 > (text->clip_cx + text->clip_width)) + x2 = text->clip_cx + text->clip_width; + + if (y2 > (text->clip_cy + text->clip_height)) + y2 = text->clip_cy + text->clip_height; + + if ((x1 >= x2) || (y1 >= y2)) + continue; + } + + /* Calculate distance from point to rectangle */ + + if (cx < x1) + dx = x1 - cx; + else if (cx >= x2) + dx = cx - x2 + 1; + else + dx = 0; + + if (cy < y1) + dy = y1 - cy; + else if (cy >= y2) + dy = cy - y2 + 1; + else + dy = 0; + + if ((dx == 0) && (dy == 0)) + return 0.0; + + dist = sqrt (dx * dx + dy * dy); + if (dist < best) + best = dist; + + /* Next! */ + + lines++; + } + + return best / item->canvas->pixels_per_unit; +} + +/* Bounds handler for the text item */ +static void +e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + EText *text; + double width, height; + + text = E_TEXT (item); + + *x1 = text->x; + *y1 = text->y; + + if (text->clip) { + width = text->clip_width; + height = text->clip_height; + } else { + width = text->max_width / item->canvas->pixels_per_unit; + height = text->height / item->canvas->pixels_per_unit; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + *x1 -= width / 2.0; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + *x1 -= width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + *y1 -= height / 2.0; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + *y1 -= height; + break; + } + + *x2 = *x1 + width; + *y2 = *y1 + height; +} + + + +/* Routines for sucking fonts from the X server */ + +static ETextSuckFont * +e_suck_font (GdkFont *font) +{ + ETextSuckFont *suckfont; + int i; + int x, y; + char text[1]; + int lbearing, rbearing, ch_width, ascent, descent; + GdkPixmap *pixmap; + GdkColor black, white; + GdkImage *image; + GdkGC *gc; + guchar *bitmap, *line; + int width, height; + int black_pixel, pixel; + + if (!font) + return NULL; + + suckfont = g_new (ETextSuckFont, 1); + + height = font->ascent + font->descent; + x = 0; + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_text_extents (font, text, 1, + &lbearing, &rbearing, &ch_width, &ascent, &descent); + suckfont->chars[i].left_sb = lbearing; + suckfont->chars[i].right_sb = ch_width - rbearing; + suckfont->chars[i].width = rbearing - lbearing; + suckfont->chars[i].ascent = ascent; + suckfont->chars[i].descent = descent; + suckfont->chars[i].bitmap_offset = x; + x += (ch_width + 31) & -32; + } + + width = x; + + suckfont->bitmap_width = width; + suckfont->bitmap_height = height; + suckfont->ascent = font->ascent; + + pixmap = gdk_pixmap_new (NULL, suckfont->bitmap_width, + suckfont->bitmap_height, 1); + gc = gdk_gc_new (pixmap); + gdk_gc_set_font (gc, font); + + black_pixel = BlackPixel (gdk_display, DefaultScreen (gdk_display)); + black.pixel = black_pixel; + white.pixel = WhitePixel (gdk_display, DefaultScreen (gdk_display)); + gdk_gc_set_foreground (gc, &white); + gdk_draw_rectangle (pixmap, gc, 1, 0, 0, width, height); + + gdk_gc_set_foreground (gc, &black); + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_draw_text (pixmap, font, gc, + suckfont->chars[i].bitmap_offset - suckfont->chars[i].left_sb, + font->ascent, + text, 1); + } + + /* The handling of the image leaves me with distinct unease. But this + * is more or less copied out of gimp/app/text_tool.c, so it _ought_ to + * work. -RLL + */ + + image = gdk_image_get (pixmap, 0, 0, width, height); + suckfont->bitmap = g_malloc0 ((width >> 3) * height); + + line = suckfont->bitmap; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pixel = gdk_image_get_pixel (image, x, y); + if (pixel == black_pixel) + line[x >> 3] |= 128 >> (x & 7); + } + line += width >> 3; + } + + gdk_image_destroy (image); + + /* free the pixmap */ + gdk_pixmap_unref (pixmap); + + /* free the gc */ + gdk_gc_destroy (gc); + + return suckfont; +} + +static void +e_suck_font_free (ETextSuckFont *suckfont) +{ + g_free (suckfont->bitmap); + g_free (suckfont); +} diff --git a/widgets/e-text/e-text.h b/widgets/e-text/e-text.h new file mode 100644 index 0000000000..e14199f16e --- /dev/null +++ b/widgets/e-text/e-text.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#ifndef E_TEXT_H +#define E_TEXT_H + +#include <gnome.h> + + +BEGIN_GNOME_DECLS + + +/* Text item for the canvas. Text items are positioned by an anchor point and an anchor direction. + * + * A clipping rectangle may be specified for the text. The rectangle is anchored at the text's anchor + * point, and is specified by clipping width and height parameters. If the clipping rectangle is + * enabled, it will clip the text. + * + * In addition, x and y offset values may be specified. These specify an offset from the anchor + * position. If used in conjunction with the clipping rectangle, these could be used to implement + * simple scrolling of the text within the clipping rectangle. + * + * The following object arguments are available: + * + * name type read/write description + * ------------------------------------------------------------------------------------------ + * text string RW The string of the text label + * x double RW X coordinate of anchor point + * y double RW Y coordinate of anchor point + * font string W X logical font descriptor + * fontset string W X logical fontset descriptor + * font_gdk GdkFont* RW Pointer to a GdkFont + * anchor GtkAnchorType RW Anchor side for the text + * justification GtkJustification RW Justification for multiline text + * fill_color string W X color specification for text + * fill_color_gdk GdkColor* RW Pointer to an allocated GdkColor + * fill_stipple GdkBitmap* RW Stipple pattern for filling the text + * clip_width double RW Width of clip rectangle + * clip_height double RW Height of clip rectangle + * clip boolean RW Use clipping rectangle? + * x_offset double RW Horizontal offset distance from anchor position + * y_offset double RW Vertical offset distance from anchor position + * text_width double R Used to query the width of the rendered text + * text_height double R Used to query the rendered height of the text + * + * These are ignored in the AA version: + * 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 = "...". + */ + +#define E_TYPE_TEXT (e_text_get_type ()) +#define E_TEXT(obj) (GTK_CHECK_CAST ((obj), E_TYPE_TEXT, EText)) +#define E_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_TEXT, ETextClass)) +#define E_IS_TEXT(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_TEXT)) +#define E_IS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), E_TYPE_TEXT)) + + +typedef struct _EText EText; +typedef struct _ETextClass ETextClass; +typedef struct _ETextSuckFont ETextSuckFont; +typedef struct _ETextSuckChar ETextSuckChar; + +struct _ETextSuckChar { + int left_sb; + int right_sb; + int width; + int ascent; + int descent; + int bitmap_offset; /* in pixels */ +}; + +struct _ETextSuckFont { + guchar *bitmap; + gint bitmap_width; + gint bitmap_height; + gint ascent; + ETextSuckChar chars[256]; +}; + +struct _EText { + GnomeCanvasItem item; + + char *text; /* Text to display */ + gpointer lines; /* Text split into lines (private field) */ + int num_lines; /* Number of lines of text */ + + double x, y; /* Position at anchor */ + GdkFont *font; /* Font for text */ + GtkAnchorType anchor; /* Anchor side for text */ + GtkJustification justification; /* Justification for text */ + + double clip_width; /* Width of optional clip rectangle */ + double clip_height; /* Height of optional clip rectangle */ + + double xofs, yofs; /* Text offset distance from anchor position */ + + gulong pixel; /* Fill color */ + GdkBitmap *stipple; /* Stipple for text */ + GdkGC *gc; /* GC for drawing text */ + + int cx, cy; /* Top-left canvas coordinates for text */ + int clip_cx, clip_cy; /* Top-left canvas coordinates for clip rectangle */ + int clip_cwidth, clip_cheight; /* Size of clip rectangle in pixels */ + int max_width; /* Maximum width of text lines */ + int height; /* Rendered text height in pixels */ + + guint clip : 1; /* Use clip rectangle? */ + + /* Antialiased specific stuff follows */ + ETextSuckFont *suckfont; /* Sucked font */ + guint32 rgba; /* RGBA color for text */ + double affine[6]; /* The item -> canvas affine */ + + char *ellipsis; /* The ellipsis characters. NULL = "...". */ + double ellipsis_width; /* The width of the ellipsis. */ + gboolean use_ellipsis; /* Whether to use the ellipsis. */ +}; + +struct _ETextClass { + GnomeCanvasItemClass parent_class; +}; + + +/* Standard Gtk function */ +GtkType e_text_get_type (void); + + +END_GNOME_DECLS + +#endif diff --git a/widgets/test-minicard-label.c b/widgets/test-minicard-label.c new file mode 100644 index 0000000000..67c17a0ace --- /dev/null +++ b/widgets/test-minicard-label.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard-label.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard-label.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *label; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( label, + "width", (double) allocation->width, + "height", (double) allocation->height, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Label Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard label canvas item" ), + NULL); + gtk_widget_show (about); +} + +static void button_press_callback( GtkWidget *widget, gpointer data ) +{ + gnome_canvas_item_grab_focus( label ); +} + +int main( int argc, char *argv[] ) +{ + GtkWidget *app; + GtkWidget *canvas; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Label Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Label Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + label = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_label_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + "height", (double) 100, + "fieldname", "Full Name:", + "field", "Christopher James Lahey", + NULL ); + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/widgets/test-minicard.c b/widgets/test-minicard.c new file mode 100644 index 0000000000..4f56fbe936 --- /dev/null +++ b/widgets/test-minicard.c @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* test-minicard.c + * + * Copyright (C) 2000 Helix Code, Inc. + * Author: Chris Lahey <clahey@helixcode.com> + * + * This program 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, 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. + */ + + + +#include "config.h" + +#include <gnome.h> +#include "e-minicard.h" + +/* This is a horrible thing to do, but it is just a test. */ +GnomeCanvasItem *card; +GnomeCanvasItem *rect; + +static void destroy_callback(GtkWidget *app, gpointer data) +{ + exit(0); +} + +static void allocate_callback(GtkWidget *canvas, GtkAllocation *allocation, gpointer data) +{ + gnome_canvas_set_scroll_region(GNOME_CANVAS( canvas ), 0, 0, allocation->width, allocation->height ); + gnome_canvas_item_set( card, + "width", (double) allocation->width, + NULL ); + gnome_canvas_item_set( rect, + "x2", (double) allocation->width, + "y2", (double) allocation->height, + NULL ); +} + +static void about_callback( GtkWidget *widget, gpointer data ) +{ + + const gchar *authors[] = + { + "Christopher James Lahey <clahey@umich.edu>", + NULL + }; + + GtkWidget *about = + gnome_about_new ( _( "Minicard Test" ), VERSION, + _( "Copyright (C) 2000, Helix Code, Inc." ), + authors, + _( "This should test the minicard canvas item" ), + NULL); + 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; + GtkWidget *canvas; + int i; + + /* bindtextdomain (PACKAGE, GNOMELOCALEDIR); + textdomain (PACKAGE);*/ + + gnome_init( "Minicard Test", VERSION, argc, argv); + app = gnome_app_new("Minicard Test", NULL); + + canvas = gnome_canvas_new(); + rect = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + gnome_canvas_rect_get_type(), + "x1", (double) 0, + "y1", (double) 0, + "x2", (double) 100, + "y2", (double) 100, + "fill_color", "white", + NULL ); + for ( i = 0; i < 1; i++ ) + { + card = gnome_canvas_item_new( gnome_canvas_root( GNOME_CANVAS( canvas ) ), + e_minicard_get_type(), + "x", (double) 0, + "y", (double) 0, + "width", (double) 100, + NULL ); + } + gnome_canvas_set_scroll_region ( GNOME_CANVAS( canvas ), + 0, 0, + 100, 100 ); + + gnome_app_set_contents( GNOME_APP( app ), canvas ); + + + /* Connect the signals */ + gtk_signal_connect( GTK_OBJECT( app ), "destroy", + GTK_SIGNAL_FUNC( destroy_callback ), + ( gpointer ) app ); + + gtk_signal_connect( GTK_OBJECT( canvas ), "size_allocate", + 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(); + + /* Not reached. */ + return 0; +} diff --git a/widgets/text/e-text.c b/widgets/text/e-text.c new file mode 100644 index 0000000000..b88130e3c8 --- /dev/null +++ b/widgets/text/e-text.c @@ -0,0 +1,1411 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#include <config.h> +#include <math.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> + + + +/* This defines a line of text */ +struct line { + char *text; /* Line's text, it is a pointer into the text->text string */ + int length; /* Line's length in characters */ + int width; /* Line's width in pixels */ + int ellipsis_length; /* Length before adding ellipsis */ +}; + + + +/* Object argument IDs */ +enum { + ARG_0, + ARG_TEXT, + ARG_X, + ARG_Y, + ARG_FONT, + ARG_FONTSET, + ARG_FONT_GDK, + ARG_ANCHOR, + ARG_JUSTIFICATION, + ARG_CLIP_WIDTH, + ARG_CLIP_HEIGHT, + ARG_CLIP, + ARG_X_OFFSET, + ARG_Y_OFFSET, + ARG_FILL_COLOR, + ARG_FILL_COLOR_GDK, + ARG_FILL_COLOR_RGBA, + ARG_FILL_STIPPLE, + ARG_TEXT_WIDTH, + ARG_TEXT_HEIGHT, + ARG_USE_ELLIPSIS, + ARG_ELLIPSIS +}; + + +static void e_text_class_init (ETextClass *class); +static void e_text_init (EText *text); +static void e_text_destroy (GtkObject *object); +static void e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); +static void e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); + +static void e_text_update (GnomeCanvasItem *item, double *affine, + ArtSVP *clip_path, int flags); +static void e_text_realize (GnomeCanvasItem *item); +static void e_text_unrealize (GnomeCanvasItem *item); +static void e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height); +static double e_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, + GnomeCanvasItem **actual_item); +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 ETextSuckFont *e_suck_font (GdkFont *font); +static void e_suck_font_free (ETextSuckFont *suckfont); + + +static GnomeCanvasItemClass *parent_class; + + + +/** + * e_text_get_type: + * @void: + * + * Registers the &EText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &EText class. + **/ +GtkType +e_text_get_type (void) +{ + static GtkType text_type = 0; + + if (!text_type) { + GtkTypeInfo text_info = { + "EText", + sizeof (EText), + sizeof (ETextClass), + (GtkClassInitFunc) e_text_class_init, + (GtkObjectInitFunc) e_text_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + text_type = gtk_type_unique (gnome_canvas_item_get_type (), &text_info); + } + + return text_type; +} + +/* Class initialization function for the text item */ +static void +e_text_class_init (ETextClass *class) +{ + GtkObjectClass *object_class; + GnomeCanvasItemClass *item_class; + + object_class = (GtkObjectClass *) class; + item_class = (GnomeCanvasItemClass *) class; + + parent_class = gtk_type_class (gnome_canvas_item_get_type ()); + + gtk_object_add_arg_type ("EText::text", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); + gtk_object_add_arg_type ("EText::x", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X); + gtk_object_add_arg_type ("EText::y", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y); + gtk_object_add_arg_type ("EText::font", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONT); + gtk_object_add_arg_type ("EText::fontset", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FONTSET); + gtk_object_add_arg_type ("EText::font_gdk", + GTK_TYPE_GDK_FONT, GTK_ARG_READWRITE, ARG_FONT_GDK); + gtk_object_add_arg_type ("EText::anchor", + GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR); + gtk_object_add_arg_type ("EText::justification", + GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFICATION); + gtk_object_add_arg_type ("EText::clip_width", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_WIDTH); + gtk_object_add_arg_type ("EText::clip_height", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_CLIP_HEIGHT); + gtk_object_add_arg_type ("EText::clip", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_CLIP); + gtk_object_add_arg_type ("EText::x_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X_OFFSET); + gtk_object_add_arg_type ("EText::y_offset", + GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y_OFFSET); + gtk_object_add_arg_type ("EText::fill_color", + GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR); + gtk_object_add_arg_type ("EText::fill_color_gdk", + GTK_TYPE_GDK_COLOR, GTK_ARG_READWRITE, ARG_FILL_COLOR_GDK); + gtk_object_add_arg_type ("EText::fill_color_rgba", + GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA); + gtk_object_add_arg_type ("EText::fill_stipple", + GTK_TYPE_GDK_WINDOW, GTK_ARG_READWRITE, ARG_FILL_STIPPLE); + gtk_object_add_arg_type ("EText::text_width", + 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::use_ellipsis", + GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_USE_ELLIPSIS); + gtk_object_add_arg_type ("EText::ellipsis", + GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_ELLIPSIS); + + object_class->destroy = e_text_destroy; + object_class->set_arg = e_text_set_arg; + object_class->get_arg = e_text_get_arg; + + item_class->update = e_text_update; + item_class->realize = e_text_realize; + item_class->unrealize = e_text_unrealize; + item_class->draw = e_text_draw; + item_class->point = e_text_point; + item_class->bounds = e_text_bounds; + item_class->render = e_text_render; +} + +/* Object initialization function for the text item */ +static void +e_text_init (EText *text) +{ + text->x = 0.0; + text->y = 0.0; + text->anchor = GTK_ANCHOR_CENTER; + text->justification = GTK_JUSTIFY_LEFT; + text->clip_width = 0.0; + text->clip_height = 0.0; + text->xofs = 0.0; + text->yofs = 0.0; + text->ellipsis = NULL; + text->use_ellipsis = FALSE; + text->ellipsis_width = 0; +} + +/* Destroy handler for the text item */ +static void +e_text_destroy (GtkObject *object) +{ + EText *text; + + g_return_if_fail (object != NULL); + g_return_if_fail (GNOME_IS_CANVAS_TEXT (object)); + + text = E_TEXT (object); + + if (text->text) + g_free (text->text); + + if (text->lines) + g_free (text->lines); + + if (text->font) + gdk_font_unref (text->font); + + if (text->suckfont) + e_suck_font_free (text->suckfont); + + if (text->stipple) + gdk_bitmap_unref (text->stipple); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +get_bounds_item_relative (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double x, y; + double clip_x, clip_y; + + item = GNOME_CANVAS_ITEM (text); + + x = text->x; + y = text->y; + + clip_x = x; + clip_y = y; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + clip_x -= text->clip_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + clip_x -= text->clip_width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + clip_y -= text->clip_height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + clip_y -= text->clip_height; + break; + } + + /* Bounds */ + + if (text->clip) { + /* maybe do bbox intersection here? */ + *px1 = clip_x; + *py1 = clip_y; + *px2 = clip_x + text->clip_width; + *py2 = clip_y + text->clip_height; + } else { + *px1 = x; + *py1 = y; + *px2 = x + text->max_width; + *py2 = y + text->height; + } +} + +static void +get_bounds (EText *text, double *px1, double *py1, double *px2, double *py2) +{ + GnomeCanvasItem *item; + double wx, wy; + + item = GNOME_CANVAS_ITEM (text); + + /* Get canvas pixel coordinates for text position */ + + wx = text->x; + wy = text->y; + gnome_canvas_item_i2w (item, &wx, &wy); + gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy); + + /* Get canvas pixel coordinates for clip rectangle position */ + + gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy); + text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit; + text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit; + + /* Calculate text dimensions */ + + if (text->text && text->font) + text->height = (text->font->ascent + text->font->descent) * text->num_lines; + else + text->height = 0; + + /* Anchor text */ + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + text->cx -= text->max_width / 2; + text->clip_cx -= text->clip_cwidth / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + text->cx -= text->max_width; + text->clip_cx -= text->clip_cwidth; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + text->cy -= text->height / 2; + text->clip_cy -= text->clip_cheight / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + text->cy -= text->height; + text->clip_cy -= text->clip_cheight; + break; + } + + /* Bounds */ + + if (text->clip) { + *px1 = text->clip_cx; + *py1 = text->clip_cy; + *px2 = text->clip_cx + text->clip_cwidth; + *py2 = text->clip_cy + text->clip_cheight; + } else { + *px1 = text->cx; + *py1 = text->cy; + *px2 = text->cx + text->max_width; + *py2 = text->cy + text->height; + } +} + +/* Recalculates the bounding box of the text item. The bounding box is defined + * by the text's extents if the clip rectangle is disabled. If it is enabled, + * the bounding box is defined by the clip rectangle itself. + */ +static void +recalc_bounds (EText *text) +{ + GnomeCanvasItem *item; + + item = GNOME_CANVAS_ITEM (text); + + get_bounds (text, &item->x1, &item->y1, &item->x2, &item->y2); + + gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item); +} + +static void +calc_ellipsis (EText *text) +{ + if (text->font) + text->ellipsis_width = + gdk_text_width (text->font, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); +} + +/* Calculates the line widths (in pixels) of the text's splitted lines */ +static void +calc_line_widths (EText *text) +{ + struct line *lines; + int i; + int j; + + lines = text->lines; + text->max_width = 0; + + if (!lines) + return; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + if (text->font) { + lines->width = gdk_text_width (text->font, + lines->text, lines->length); + lines->ellipsis_length = 0; + } else { + lines->width = 0; + } + + if (text->clip && + text->use_ellipsis && + lines->width > text->clip_width) { + if (text->font) { + lines->ellipsis_length = 0; + for (j = 0; j < lines->length; j++ ) { + if (gdk_text_width (text->font, lines->text, j) + text->ellipsis_width <= text->clip_width) + lines->ellipsis_length = j; + else + break; + } + } + else + lines->ellipsis_length = 0; + lines->width = gdk_text_width (text->font, lines->text, lines->ellipsis_length) + + text->ellipsis_width; + } + else + lines->ellipsis_length = lines->length; + + if (lines->width > text->max_width) + text->max_width = lines->width; + } + + lines++; + } +} + +/* Splits the text of the text item into lines */ +static void +split_into_lines (EText *text) +{ + char *p; + struct line *lines; + int len; + + /* Free old array of lines */ + + if (text->lines) + g_free (text->lines); + + text->lines = NULL; + text->num_lines = 0; + + if (!text->text) + return; + + /* First, count the number of lines */ + + for (p = text->text; *p; p++) + if (*p == '\n') + text->num_lines++; + + text->num_lines++; + + /* Allocate array of lines and calculate split positions */ + + text->lines = lines = g_new0 (struct line, text->num_lines); + len = 0; + + for (p = text->text; *p; p++) { + if (*p == '\n') { + lines->length = len; + lines++; + len = 0; + } else if (len == 0) { + len++; + lines->text = p; + } else + len++; + } + + lines->length = len; + + calc_line_widths (text); +} + +/* Convenience function to set the text's GC's foreground color */ +static void +set_text_gc_foreground (EText *text) +{ + GdkColor c; + + if (!text->gc) + return; + + c.pixel = text->pixel; + gdk_gc_set_foreground (text->gc, &c); +} + +/* Sets the stipple pattern for the text */ +static void +set_stipple (EText *text, GdkBitmap *stipple, int reconfigure) +{ + if (text->stipple && !reconfigure) + gdk_bitmap_unref (text->stipple); + + text->stipple = stipple; + if (stipple && !reconfigure) + gdk_bitmap_ref (stipple); + + if (text->gc) { + if (stipple) { + gdk_gc_set_stipple (text->gc, stipple); + gdk_gc_set_fill (text->gc, GDK_STIPPLED); + } else + gdk_gc_set_fill (text->gc, GDK_SOLID); + } +} + +/* Set_arg handler for the text item */ +static void +e_text_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + GnomeCanvasItem *item; + EText *text; + GdkColor color = { 0, 0, 0, 0, }; + GdkColor *pcolor; + gboolean color_changed; + int have_pixel; + + item = GNOME_CANVAS_ITEM (object); + text = E_TEXT (object); + + color_changed = FALSE; + have_pixel = FALSE; + + switch (arg_id) { + case ARG_TEXT: + if (text->text) + g_free (text->text); + + text->text = g_strdup (GTK_VALUE_STRING (*arg)); + split_into_lines (text); + recalc_bounds (text); + break; + + case ARG_X: + text->x = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y: + text->y = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FONT: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_font_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONTSET: + if (text->font) + gdk_font_unref (text->font); + + text->font = gdk_fontset_load (GTK_VALUE_STRING (*arg)); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_FONT_GDK: + if (text->font) + gdk_font_unref (text->font); + + text->font = GTK_VALUE_BOXED (*arg); + gdk_font_ref (text->font); + + if (item->canvas->aa) { + if (text->suckfont) + e_suck_font_free (text->suckfont); + + text->suckfont = e_suck_font (text->font); + } + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ANCHOR: + text->anchor = GTK_VALUE_ENUM (*arg); + recalc_bounds (text); + break; + + case ARG_JUSTIFICATION: + text->justification = GTK_VALUE_ENUM (*arg); + break; + + case ARG_CLIP_WIDTH: + text->clip_width = fabs (GTK_VALUE_DOUBLE (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_CLIP_HEIGHT: + text->clip_height = fabs (GTK_VALUE_DOUBLE (*arg)); + recalc_bounds (text); + break; + + case ARG_CLIP: + text->clip = GTK_VALUE_BOOL (*arg); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_X_OFFSET: + text->xofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_Y_OFFSET: + text->yofs = GTK_VALUE_DOUBLE (*arg); + recalc_bounds (text); + break; + + case ARG_FILL_COLOR: + if (GTK_VALUE_STRING (*arg)) + gdk_color_parse (GTK_VALUE_STRING (*arg), &color); + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_GDK: + pcolor = GTK_VALUE_BOXED (*arg); + if (pcolor) { + color = *pcolor; + gdk_color_context_query_color (item->canvas->cc, &color); + have_pixel = TRUE; + } + + text->rgba = ((color.red & 0xff00) << 16 | + (color.green & 0xff00) << 8 | + (color.blue & 0xff00) | + 0xff); + color_changed = TRUE; + break; + + case ARG_FILL_COLOR_RGBA: + text->rgba = GTK_VALUE_UINT (*arg); + color_changed = TRUE; + break; + + case ARG_FILL_STIPPLE: + set_stipple (text, GTK_VALUE_BOXED (*arg), FALSE); + break; + + case ARG_USE_ELLIPSIS: + text->use_ellipsis = GTK_VALUE_BOOL (*arg); + calc_line_widths (text); + recalc_bounds (text); + break; + + case ARG_ELLIPSIS: + if (text->ellipsis) + g_free (text->ellipsis); + + text->ellipsis = g_strdup (GTK_VALUE_STRING (*arg)); + calc_ellipsis (text); + calc_line_widths (text); + recalc_bounds (text); + break; + + default: + break; + } + + if (color_changed) { + if (have_pixel) + text->pixel = color.pixel; + else + text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba); + + if (!item->canvas->aa) + set_text_gc_foreground (text); + + gnome_canvas_item_request_update (item); + } +} + +/* Get_arg handler for the text item */ +static void +e_text_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +{ + EText *text; + GdkColor *color; + + text = E_TEXT (object); + + switch (arg_id) { + case ARG_TEXT: + GTK_VALUE_STRING (*arg) = g_strdup (text->text); + break; + + case ARG_X: + GTK_VALUE_DOUBLE (*arg) = text->x; + break; + + case ARG_Y: + GTK_VALUE_DOUBLE (*arg) = text->y; + break; + + case ARG_FONT_GDK: + GTK_VALUE_BOXED (*arg) = text->font; + break; + + case ARG_ANCHOR: + GTK_VALUE_ENUM (*arg) = text->anchor; + break; + + case ARG_JUSTIFICATION: + GTK_VALUE_ENUM (*arg) = text->justification; + break; + + case ARG_CLIP_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->clip_width; + break; + + case ARG_CLIP_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->clip_height; + break; + + case ARG_CLIP: + GTK_VALUE_BOOL (*arg) = text->clip; + break; + + case ARG_X_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->xofs; + break; + + case ARG_Y_OFFSET: + GTK_VALUE_DOUBLE (*arg) = text->yofs; + break; + + case ARG_FILL_COLOR_GDK: + color = g_new (GdkColor, 1); + color->pixel = text->pixel; + gdk_color_context_query_color (text->item.canvas->cc, color); + GTK_VALUE_BOXED (*arg) = color; + break; + + case ARG_FILL_COLOR_RGBA: + GTK_VALUE_UINT (*arg) = text->rgba; + break; + + case ARG_FILL_STIPPLE: + GTK_VALUE_BOXED (*arg) = text->stipple; + break; + + case ARG_TEXT_WIDTH: + GTK_VALUE_DOUBLE (*arg) = text->max_width / text->item.canvas->pixels_per_unit; + break; + + case ARG_TEXT_HEIGHT: + GTK_VALUE_DOUBLE (*arg) = text->height / text->item.canvas->pixels_per_unit; + break; + + case ARG_USE_ELLIPSIS: + GTK_VALUE_BOOL (*arg) = text->use_ellipsis; + break; + + case ARG_ELLIPSIS: + GTK_VALUE_STRING (*arg) = g_strdup (text->ellipsis); + break; + + default: + arg->type = GTK_TYPE_INVALID; + break; + } +} + +/* Update handler for the text item */ +static void +e_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) +{ + EText *text; + double x1, y1, x2, y2; + ArtDRect i_bbox, c_bbox; + int i; + + text = E_TEXT (item); + + if (parent_class->update) + (* parent_class->update) (item, affine, clip_path, flags); + + if (!item->canvas->aa) { + set_text_gc_foreground (text); + set_stipple (text, text->stipple, TRUE); + get_bounds (text, &x1, &y1, &x2, &y2); + + gnome_canvas_update_bbox (item, x1, y1, x2, y2); + } else { + /* aa rendering */ + for (i = 0; i < 6; i++) + text->affine[i] = affine[i]; + get_bounds_item_relative (text, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1); + art_drect_affine_transform (&c_bbox, &i_bbox, affine); + gnome_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1); + + } +} + +/* Realize handler for the text item */ +static void +e_text_realize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + if (parent_class->realize) + (* parent_class->realize) (item); + + text->gc = gdk_gc_new (item->canvas->layout.bin_window); +} + +/* Unrealize handler for the text item */ +static void +e_text_unrealize (GnomeCanvasItem *item) +{ + EText *text; + + text = E_TEXT (item); + + gdk_gc_unref (text->gc); + text->gc = NULL; + + if (parent_class->unrealize) + (* parent_class->unrealize) (item); +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static double +get_line_xpos_item_relative (EText *text, struct line *line) +{ + double x; + + x = text->x; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + x -= text->max_width / 2; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + x -= text->max_width; + break; + } + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) * 0.5; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Calculates the y position of the first line of text. */ +static double +get_line_ypos_item_relative (EText *text) +{ + double y; + + y = text->y; + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + y -= text->height / 2; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + y -= text->height; + break; + } + + return y; +} + +/* Calculates the x position of the specified line of text, based on the text's justification */ +static int +get_line_xpos (EText *text, struct line *line) +{ + int x; + + x = text->cx; + + switch (text->justification) { + case GTK_JUSTIFY_RIGHT: + x += text->max_width - line->width; + break; + + case GTK_JUSTIFY_CENTER: + x += (text->max_width - line->width) / 2; + break; + + default: + /* For GTK_JUSTIFY_LEFT, we don't have to do anything. We do not support + * GTK_JUSTIFY_FILL, yet. + */ + break; + } + + return x; +} + +/* Draw handler for the text item */ +static void +e_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable, + int x, int y, int width, int height) +{ + EText *text; + GdkRectangle rect; + struct line *lines; + int i; + int xpos, ypos; + + text = E_TEXT (item); + + if (!text->text || !text->font) + return; + + if (text->clip) { + rect.x = text->clip_cx - x; + rect.y = text->clip_cy - y; + rect.width = text->clip_cwidth; + rect.height = text->clip_cheight; + + gdk_gc_set_clip_rectangle (text->gc, &rect); + } + lines = text->lines; + ypos = text->cy + text->font->ascent; + + if (text->stipple) + gnome_canvas_set_stipple_origin (item->canvas, text->gc); + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + xpos = get_line_xpos (text, lines); + if ( text->clip && text->use_ellipsis && lines->ellipsis_length < lines->length) { + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->ellipsis_length); + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x + + lines->width - text->ellipsis_width, + ypos - y, + text->ellipsis ? text->ellipsis : "...", + text->ellipsis ? strlen (text->ellipsis) : 3); + } else + + gdk_draw_text (drawable, + text->font, + text->gc, + xpos - x, + ypos - y, + lines->text, + lines->length); + } + + ypos += text->font->ascent + text->font->descent; + lines++; + } + + if (text->clip) + gdk_gc_set_clip_rectangle (text->gc, NULL); +} + +/* Render handler for the text item */ +static void +e_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf) +{ + EText *text; + guint32 fg_color; + double xpos, ypos; + struct line *lines; + int i, j; + double affine[6]; + ETextSuckFont *suckfont; + int dx, dy; + ArtPoint start_i, start_c; + + text = E_TEXT (item); + + if (!text->text || !text->font || !text->suckfont) + return; + + suckfont = text->suckfont; + + fg_color = text->rgba; + + gnome_canvas_buf_ensure_buf (buf); + + lines = text->lines; + start_i.y = get_line_ypos_item_relative (text); + + art_affine_scale (affine, item->canvas->pixels_per_unit, item->canvas->pixels_per_unit); + for (i = 0; i < 6; i++) + affine[i] = text->affine[i]; + + for (i = 0; i < text->num_lines; i++) { + if (lines->length != 0) { + start_i.x = get_line_xpos_item_relative (text, lines); + art_affine_point (&start_c, &start_i, text->affine); + xpos = start_c.x; + ypos = start_c.y; + + for (j = 0; j < lines->length; j++) { + ETextSuckChar *ch; + + ch = &suckfont->chars[(unsigned char)((lines->text)[j])]; + + affine[4] = xpos; + affine[5] = ypos; + art_rgb_bitmap_affine ( + buf->buf, + buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1, + buf->buf_rowstride, + suckfont->bitmap + (ch->bitmap_offset >> 3), + ch->width, + suckfont->bitmap_height, + suckfont->bitmap_width >> 3, + fg_color, + affine, + ART_FILTER_NEAREST, NULL); + + dx = ch->left_sb + ch->width + ch->right_sb; + xpos += dx * affine[0]; + ypos += dx * affine[1]; + } + } + + dy = text->font->ascent + text->font->descent; + start_i.y += dy; + lines++; + } + + buf->is_bg = 0; +} + +/* Point handler for the text item */ +static double +e_text_point (GnomeCanvasItem *item, double x, double y, + int cx, int cy, GnomeCanvasItem **actual_item) +{ + EText *text; + int i; + struct line *lines; + int x1, y1, x2, y2; + int font_height; + int dx, dy; + double dist, best; + + text = E_TEXT (item); + + *actual_item = item; + + /* The idea is to build bounding rectangles for each of the lines of + * text (clipped by the clipping rectangle, if it is activated) and see + * whether the point is inside any of these. If it is, we are done. + * Otherwise, calculate the distance to the nearest rectangle. + */ + + if (text->font) + font_height = text->font->ascent + text->font->descent; + else + font_height = 0; + + best = 1.0e36; + + lines = text->lines; + + for (i = 0; i < text->num_lines; i++) { + /* Compute the coordinates of rectangle for the current line, + * clipping if appropriate. + */ + + x1 = get_line_xpos (text, lines); + y1 = text->cy + i * font_height; + x2 = x1 + lines->width; + y2 = y1 + font_height; + + if (text->clip) { + if (x1 < text->clip_cx) + x1 = text->clip_cx; + + if (y1 < text->clip_cy) + y1 = text->clip_cy; + + if (x2 > (text->clip_cx + text->clip_width)) + x2 = text->clip_cx + text->clip_width; + + if (y2 > (text->clip_cy + text->clip_height)) + y2 = text->clip_cy + text->clip_height; + + if ((x1 >= x2) || (y1 >= y2)) + continue; + } + + /* Calculate distance from point to rectangle */ + + if (cx < x1) + dx = x1 - cx; + else if (cx >= x2) + dx = cx - x2 + 1; + else + dx = 0; + + if (cy < y1) + dy = y1 - cy; + else if (cy >= y2) + dy = cy - y2 + 1; + else + dy = 0; + + if ((dx == 0) && (dy == 0)) + return 0.0; + + dist = sqrt (dx * dx + dy * dy); + if (dist < best) + best = dist; + + /* Next! */ + + lines++; + } + + return best / item->canvas->pixels_per_unit; +} + +/* Bounds handler for the text item */ +static void +e_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2) +{ + EText *text; + double width, height; + + text = E_TEXT (item); + + *x1 = text->x; + *y1 = text->y; + + if (text->clip) { + width = text->clip_width; + height = text->clip_height; + } else { + width = text->max_width / item->canvas->pixels_per_unit; + height = text->height / item->canvas->pixels_per_unit; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_W: + case GTK_ANCHOR_SW: + break; + + case GTK_ANCHOR_N: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_S: + *x1 -= width / 2.0; + break; + + case GTK_ANCHOR_NE: + case GTK_ANCHOR_E: + case GTK_ANCHOR_SE: + *x1 -= width; + break; + } + + switch (text->anchor) { + case GTK_ANCHOR_NW: + case GTK_ANCHOR_N: + case GTK_ANCHOR_NE: + break; + + case GTK_ANCHOR_W: + case GTK_ANCHOR_CENTER: + case GTK_ANCHOR_E: + *y1 -= height / 2.0; + break; + + case GTK_ANCHOR_SW: + case GTK_ANCHOR_S: + case GTK_ANCHOR_SE: + *y1 -= height; + break; + } + + *x2 = *x1 + width; + *y2 = *y1 + height; +} + + + +/* Routines for sucking fonts from the X server */ + +static ETextSuckFont * +e_suck_font (GdkFont *font) +{ + ETextSuckFont *suckfont; + int i; + int x, y; + char text[1]; + int lbearing, rbearing, ch_width, ascent, descent; + GdkPixmap *pixmap; + GdkColor black, white; + GdkImage *image; + GdkGC *gc; + guchar *bitmap, *line; + int width, height; + int black_pixel, pixel; + + if (!font) + return NULL; + + suckfont = g_new (ETextSuckFont, 1); + + height = font->ascent + font->descent; + x = 0; + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_text_extents (font, text, 1, + &lbearing, &rbearing, &ch_width, &ascent, &descent); + suckfont->chars[i].left_sb = lbearing; + suckfont->chars[i].right_sb = ch_width - rbearing; + suckfont->chars[i].width = rbearing - lbearing; + suckfont->chars[i].ascent = ascent; + suckfont->chars[i].descent = descent; + suckfont->chars[i].bitmap_offset = x; + x += (ch_width + 31) & -32; + } + + width = x; + + suckfont->bitmap_width = width; + suckfont->bitmap_height = height; + suckfont->ascent = font->ascent; + + pixmap = gdk_pixmap_new (NULL, suckfont->bitmap_width, + suckfont->bitmap_height, 1); + gc = gdk_gc_new (pixmap); + gdk_gc_set_font (gc, font); + + black_pixel = BlackPixel (gdk_display, DefaultScreen (gdk_display)); + black.pixel = black_pixel; + white.pixel = WhitePixel (gdk_display, DefaultScreen (gdk_display)); + gdk_gc_set_foreground (gc, &white); + gdk_draw_rectangle (pixmap, gc, 1, 0, 0, width, height); + + gdk_gc_set_foreground (gc, &black); + for (i = 0; i < 256; i++) { + text[0] = i; + gdk_draw_text (pixmap, font, gc, + suckfont->chars[i].bitmap_offset - suckfont->chars[i].left_sb, + font->ascent, + text, 1); + } + + /* The handling of the image leaves me with distinct unease. But this + * is more or less copied out of gimp/app/text_tool.c, so it _ought_ to + * work. -RLL + */ + + image = gdk_image_get (pixmap, 0, 0, width, height); + suckfont->bitmap = g_malloc0 ((width >> 3) * height); + + line = suckfont->bitmap; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pixel = gdk_image_get_pixel (image, x, y); + if (pixel == black_pixel) + line[x >> 3] |= 128 >> (x & 7); + } + line += width >> 3; + } + + gdk_image_destroy (image); + + /* free the pixmap */ + gdk_pixmap_unref (pixmap); + + /* free the gc */ + gdk_gc_destroy (gc); + + return suckfont; +} + +static void +e_suck_font_free (ETextSuckFont *suckfont) +{ + g_free (suckfont->bitmap); + g_free (suckfont); +} diff --git a/widgets/text/e-text.h b/widgets/text/e-text.h new file mode 100644 index 0000000000..e14199f16e --- /dev/null +++ b/widgets/text/e-text.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* EText - Text item for evolution. + * Copyright (C) 2000 Helix Code, Inc. + * + * Author: Chris Lahey <clahey@umich.edu> + * + * A majority of code taken from: + * + * Text item type for GnomeCanvas widget + * + * GnomeCanvas is basically a port of the Tk toolkit's most excellent + * canvas widget. Tk is copyrighted by the Regents of the University + * of California, Sun Microsystems, and other parties. + * + * Copyright (C) 1998 The Free Software Foundation + * + * Author: Federico Mena <federico@nuclecu.unam.mx> */ + +#ifndef E_TEXT_H +#define E_TEXT_H + +#include <gnome.h> + + +BEGIN_GNOME_DECLS + + +/* Text item for the canvas. Text items are positioned by an anchor point and an anchor direction. + * + * A clipping rectangle may be specified for the text. The rectangle is anchored at the text's anchor + * point, and is specified by clipping width and height parameters. If the clipping rectangle is + * enabled, it will clip the text. + * + * In addition, x and y offset values may be specified. These specify an offset from the anchor + * position. If used in conjunction with the clipping rectangle, these could be used to implement + * simple scrolling of the text within the clipping rectangle. + * + * The following object arguments are available: + * + * name type read/write description + * ------------------------------------------------------------------------------------------ + * text string RW The string of the text label + * x double RW X coordinate of anchor point + * y double RW Y coordinate of anchor point + * font string W X logical font descriptor + * fontset string W X logical fontset descriptor + * font_gdk GdkFont* RW Pointer to a GdkFont + * anchor GtkAnchorType RW Anchor side for the text + * justification GtkJustification RW Justification for multiline text + * fill_color string W X color specification for text + * fill_color_gdk GdkColor* RW Pointer to an allocated GdkColor + * fill_stipple GdkBitmap* RW Stipple pattern for filling the text + * clip_width double RW Width of clip rectangle + * clip_height double RW Height of clip rectangle + * clip boolean RW Use clipping rectangle? + * x_offset double RW Horizontal offset distance from anchor position + * y_offset double RW Vertical offset distance from anchor position + * text_width double R Used to query the width of the rendered text + * text_height double R Used to query the rendered height of the text + * + * These are ignored in the AA version: + * 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 = "...". + */ + +#define E_TYPE_TEXT (e_text_get_type ()) +#define E_TEXT(obj) (GTK_CHECK_CAST ((obj), E_TYPE_TEXT, EText)) +#define E_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_TEXT, ETextClass)) +#define E_IS_TEXT(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_TEXT)) +#define E_IS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), E_TYPE_TEXT)) + + +typedef struct _EText EText; +typedef struct _ETextClass ETextClass; +typedef struct _ETextSuckFont ETextSuckFont; +typedef struct _ETextSuckChar ETextSuckChar; + +struct _ETextSuckChar { + int left_sb; + int right_sb; + int width; + int ascent; + int descent; + int bitmap_offset; /* in pixels */ +}; + +struct _ETextSuckFont { + guchar *bitmap; + gint bitmap_width; + gint bitmap_height; + gint ascent; + ETextSuckChar chars[256]; +}; + +struct _EText { + GnomeCanvasItem item; + + char *text; /* Text to display */ + gpointer lines; /* Text split into lines (private field) */ + int num_lines; /* Number of lines of text */ + + double x, y; /* Position at anchor */ + GdkFont *font; /* Font for text */ + GtkAnchorType anchor; /* Anchor side for text */ + GtkJustification justification; /* Justification for text */ + + double clip_width; /* Width of optional clip rectangle */ + double clip_height; /* Height of optional clip rectangle */ + + double xofs, yofs; /* Text offset distance from anchor position */ + + gulong pixel; /* Fill color */ + GdkBitmap *stipple; /* Stipple for text */ + GdkGC *gc; /* GC for drawing text */ + + int cx, cy; /* Top-left canvas coordinates for text */ + int clip_cx, clip_cy; /* Top-left canvas coordinates for clip rectangle */ + int clip_cwidth, clip_cheight; /* Size of clip rectangle in pixels */ + int max_width; /* Maximum width of text lines */ + int height; /* Rendered text height in pixels */ + + guint clip : 1; /* Use clip rectangle? */ + + /* Antialiased specific stuff follows */ + ETextSuckFont *suckfont; /* Sucked font */ + guint32 rgba; /* RGBA color for text */ + double affine[6]; /* The item -> canvas affine */ + + char *ellipsis; /* The ellipsis characters. NULL = "...". */ + double ellipsis_width; /* The width of the ellipsis. */ + gboolean use_ellipsis; /* Whether to use the ellipsis. */ +}; + +struct _ETextClass { + GnomeCanvasItemClass parent_class; +}; + + +/* Standard Gtk function */ +GtkType e_text_get_type (void); + + +END_GNOME_DECLS + +#endif |