From 045dbd46344e3ca3c53f678c2d3b4087fbbcacb7 Mon Sep 17 00:00:00 2001 From: cilix42 Date: Tue, 22 Jul 2008 13:09:59 +0000 Subject: [PATCH] New CanvasText item; TODO: works quite well but updating may be incorrect since update() is called before render() but only the latter gets passed the cairo context from which we can compute the text extents (we use a slightly kludgy workaround now) --- src/display/Makefile_insert | 2 + src/display/canvas-text.cpp | 262 ++++++++++++++++++++++++++++++++++++ src/display/canvas-text.h | 61 +++++++++ 3 files changed, 325 insertions(+) create mode 100644 src/display/canvas-text.cpp create mode 100644 src/display/canvas-text.h diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index bc74c6f22..40eea17c0 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -44,6 +44,8 @@ display_libspdisplay_a_SOURCES = \ display/canvas-temporary-item.h \ display/canvas-temporary-item-list.cpp \ display/canvas-temporary-item-list.h \ + display/canvas-text.cpp \ + display/canvas-text.h \ display/curve.cpp \ display/curve.h \ display/display-forward.h \ diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp new file mode 100644 index 000000000..c38d16d65 --- /dev/null +++ b/src/display/canvas-text.cpp @@ -0,0 +1,262 @@ +#define __SP_CANVASTEXT_C__ + +/* + * Canvas text + * + * Authors: + * Lauris Kaplinski + * Maximilian Albert + * + * Copyright (C) 2000-2002 Lauris Kaplinski + * Copyright (C) 2008 Maximilian Albert + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "display-forward.h" +#include "sp-canvas-util.h" +#include "canvas-text.h" +#include "display/inkscape-cairo.h" +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include +#include + +static void sp_canvastext_class_init (SPCanvasTextClass *klass); +static void sp_canvastext_init (SPCanvasText *canvastext); +static void sp_canvastext_destroy (GtkObject *object); + +static void sp_canvastext_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags); +static void sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf); + +static SPCanvasItemClass *parent_class_ct; + +GtkType +sp_canvastext_get_type (void) +{ + static GtkType type = 0; + + if (!type) { + GtkTypeInfo info = { + "SPCanvasText", + sizeof (SPCanvasText), + sizeof (SPCanvasTextClass), + (GtkClassInitFunc) sp_canvastext_class_init, + (GtkObjectInitFunc) sp_canvastext_init, + NULL, NULL, NULL + }; + type = gtk_type_unique (SP_TYPE_CANVAS_ITEM, &info); + } + return type; +} + +static void +sp_canvastext_class_init (SPCanvasTextClass *klass) +{ + GtkObjectClass *object_class = (GtkObjectClass *) klass; + SPCanvasItemClass *item_class = (SPCanvasItemClass *) klass; + + parent_class_ct = (SPCanvasItemClass*)gtk_type_class (SP_TYPE_CANVAS_ITEM); + + object_class->destroy = sp_canvastext_destroy; + + item_class->update = sp_canvastext_update; + item_class->render = sp_canvastext_render; +} + +static void +sp_canvastext_init (SPCanvasText *canvastext) +{ + canvastext->rgba = 0x0000ff7f; + canvastext->s[NR::X] = canvastext->s[NR::Y] = 0.0; + canvastext->affine = NR::identity(); + canvastext->fontsize = 10.0; + canvastext->item = NULL; + canvastext->text = NULL; +} + +static void +sp_canvastext_destroy (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (SP_IS_CANVASTEXT (object)); + + SPCanvasText *canvastext = SP_CANVASTEXT (object); + + canvastext->item=NULL; + + if (GTK_OBJECT_CLASS (parent_class_ct)->destroy) + (* GTK_OBJECT_CLASS (parent_class_ct)->destroy) (object); +} + +// FIXME: remove this as soon as we know how to correctly determine the text extent +static const double arbitrary_factor = 0.7; + +// these are set in sp_canvastext_update() and then re-used in sp_canvastext_render(), which is called afterwards +static double anchor_offset_x = 0; +static double anchor_offset_y = 0; + +static void +sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf) +{ + SPCanvasText *cl = SP_CANVASTEXT (item); + + if (!buf->ct) + return; + + guint32 rgba = cl->rgba; + cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba)); + + NR::Point s = cl->s * cl->affine; + double offsetx = s[NR::X] - buf->rect.x0; + double offsety = s[NR::Y] - buf->rect.y0; + offsetx -= anchor_offset_x; + offsety += anchor_offset_y; + + cairo_move_to(buf->ct, offsetx, offsety); + cairo_set_font_size(buf->ct, cl->fontsize); + cairo_show_text(buf->ct, cl->text); + cairo_stroke(buf->ct); + + cairo_new_path(buf->ct); +} + +static void +sp_canvastext_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags) +{ + SPCanvasText *cl = SP_CANVASTEXT (item); + + sp_canvas_request_redraw (item->canvas, (int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2); + + if (parent_class_ct->update) + (* parent_class_ct->update) (item, affine, flags); + + sp_canvas_item_reset_bounds (item); + + cl->affine = affine; + + NR::Point s = cl->s * affine; + + // set up a temporary cairo_t to measure the text extents; it would be better to compute this in the render() + // method but update() seems to be called before so we don't have the information available when we need it + /** + cairo_t tmp_buf; + cairo_text_extents_t bbox; + cairo_text_extents(&tmp_buf, cl->text, &bbox); + **/ + item->x1 = s[NR::X] + 0; + item->y1 = s[NR::Y] - cl->fontsize; + item->x2 = s[NR::X] + cl->fontsize * strlen(cl->text); + item->y2 = s[NR::Y] + cl->fontsize * 0.5; // for letters below the baseline + + // adjust update region according to anchor shift + // FIXME: use the correct text extent + anchor_offset_x = arbitrary_factor * cl->fontsize * strlen(cl->text) * (cl->anchor_x + 1.0) / 2.0; + anchor_offset_y = cl->fontsize * (cl->anchor_y + 1.0) / 2.0; + item->x1 -= anchor_offset_x; + item->x2 -= anchor_offset_x; + item->y1 += anchor_offset_y; + item->y2 += anchor_offset_y; + + sp_canvas_request_redraw (item->canvas, (int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2); +} + +SPCanvasItem * +sp_canvastext_new(SPCanvasGroup *parent, Geom::Point pos, char *new_text) +{ + SPCanvasItem *item = sp_canvas_item_new(parent, SP_TYPE_CANVASTEXT, NULL); + + SPCanvasText *ct = SP_CANVASTEXT(item); + + ct->s = pos; + g_free(ct->text); + ct->text = g_strdup(new_text); + + // TODO: anything else to do? + + return item; +} + + +void +sp_canvastext_set_rgba32 (SPCanvasText *ct, guint32 rgba) +{ + g_return_if_fail (ct != NULL); + g_return_if_fail (SP_IS_CANVASTEXT (ct)); + + if (rgba != ct->rgba) { + SPCanvasItem *item; + ct->rgba = rgba; + item = SP_CANVAS_ITEM (ct); + sp_canvas_request_redraw (item->canvas, (int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2); + } + sp_canvas_item_request_update (SP_CANVAS_ITEM (ct)); +} + +#define EPSILON 1e-6 +#define DIFFER(a,b) (fabs ((a) - (b)) > EPSILON) + +void +sp_canvastext_set_coords (SPCanvasText *ct, gdouble x0, gdouble y0) +{ + g_return_if_fail (ct != NULL); + g_return_if_fail (SP_IS_CANVASTEXT (ct)); + + if (DIFFER (x0, ct->s[NR::X]) || DIFFER (y0, ct->s[NR::Y])) { + ct->s[NR::X] = x0; + ct->s[NR::Y] = y0; + sp_canvas_item_request_update (SP_CANVAS_ITEM (ct)); + } + sp_canvas_item_request_update (SP_CANVAS_ITEM (ct)); +} + +void +sp_canvastext_set_coords (SPCanvasText *ct, const NR::Point start) +{ + sp_canvastext_set_coords(ct, start[0], start[1]); +} + +void +sp_canvastext_set_text (SPCanvasText *ct, const char* new_text) +{ + g_free (ct->text); + ct->text = g_strdup(new_text); + sp_canvas_item_request_update (SP_CANVAS_ITEM (ct)); +} + +void +sp_canvastext_set_number_as_text (SPCanvasText *ct, int num) +{ + std::ostringstream number; + number << num; + sp_canvastext_set_text(ct, number.str().c_str()); +} + +void +sp_canvastext_set_fontsize (SPCanvasText *ct, double size) +{ + ct->fontsize = size; +} + +void +sp_canvastext_set_anchor (SPCanvasText *ct, double anchor_x, double anchor_y) +{ + ct->anchor_x = anchor_x; + ct->anchor_y = anchor_y; +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/display/canvas-text.h b/src/display/canvas-text.h new file mode 100644 index 000000000..7d1da46f5 --- /dev/null +++ b/src/display/canvas-text.h @@ -0,0 +1,61 @@ +#ifndef __SP_CANVASTEXT_H__ +#define __SP_CANVASTEXT_H__ + +/* + * Canvas text. + * + * Authors: + * Lauris Kaplinski + * Maximilian Albert + * + * Copyright (C) 2000-2002 Lauris Kaplinski + * Copyright (C) 2008 Maximilian Albert + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "sp-canvas.h" + +struct SPItem; + +#define SP_TYPE_CANVASTEXT (sp_canvastext_get_type ()) +#define SP_CANVASTEXT(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_CANVASTEXT, SPCanvasText)) +#define SP_IS_CANVASTEXT(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_CANVASTEXT)) + +struct SPCanvasText : public SPCanvasItem{ + SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users + guint32 rgba; + + char* text; + NR::Point s; + NR::Matrix affine; + double fontsize; + double anchor_x; + double anchor_y; +}; +struct SPCanvasTextClass : public SPCanvasItemClass{}; + +GtkType sp_canvastext_get_type (void); + +SPCanvasItem *sp_canvastext_new(SPCanvasGroup *parent, Geom::Point pos, char *text); + +void sp_canvastext_set_rgba32 (SPCanvasText *ct, guint32 rgba); +void sp_canvastext_set_coords (SPCanvasText *ct, gdouble x0, gdouble y0); +void sp_canvastext_set_coords (SPCanvasText *ct, const NR::Point start); +void sp_canvastext_set_text (SPCanvasText *ct, const char* new_text); +void sp_canvastext_set_number_as_text (SPCanvasText *ct, int num); +void sp_canvastext_set_fontsize (SPCanvasText *ct, double size); +void sp_canvastext_set_anchor (SPCanvasText *ct, double anchor_x, double anchor_y); + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- 2.30.2