/* dia-shape.c * Copyright (C) 2000 Arjan Molenaar * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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 "dia-shape.h" #include "dia-canvas.h" #include #include #include static void dia_shape_path_free (DiaShapePath *path); static void dia_shape_bezier_free (DiaShapeBezier *bezier); static void dia_shape_ellipse_free (DiaShapeEllipse *ellipse); static void dia_shape_text_free (DiaShapeText *text); static void dia_shape_image_free (DiaShapeImage *image); /* * DiaShape -- updates */ static inline void request_update (DiaShape *shape) { // if (!shape->update_cnt) // shape->update_cnt = g_list_length (shape->view_info); } void dia_shape_request_update (DiaShape *shape) { request_update (shape); } gboolean dia_shape_need_update (DiaShape *shape) { g_return_val_if_fail (shape != NULL, FALSE); return TRUE; (shape->update_cnt > 0 ? TRUE : FALSE); } void dia_shape_is_updated (DiaShape *shape) { g_return_if_fail (shape != NULL); if (shape->update_cnt > 0) shape->update_cnt--; } /* * DiaShape -- creation and destruction */ GType dia_shape_get_type (DiaShape *shape) { g_return_val_if_fail (shape != NULL, 0); switch (shape->type) { case DIA_SHAPE_PATH: return DIA_TYPE_SHAPE_PATH; case DIA_SHAPE_BEZIER: return DIA_TYPE_SHAPE_BEZIER; case DIA_SHAPE_ELLIPSE: return DIA_TYPE_SHAPE_ELLIPSE; case DIA_SHAPE_TEXT: return DIA_TYPE_SHAPE_TEXT; case DIA_SHAPE_IMAGE: return DIA_TYPE_SHAPE_IMAGE; default: g_warning("No GType for shape type %d", shape->type); } return 0; } DiaShape* dia_shape_new (DiaShapeType type) { DiaShape *shape = NULL; DiaShapePath *path; DiaShapeBezier *bezier; DiaShapeEllipse *ellipse; DiaShapeText *text; DiaShapeImage *image; DiaShapeClip *clip; switch (type) { case DIA_SHAPE_PATH: path = g_new0 (DiaShapePath, 1); shape = (DiaShape*) path; path->fill_color = DIA_COLOR_A(0,0,0,0); path->fill = DIA_FILL_NONE; path->join = DIA_JOIN_ROUND; path->cap = DIA_CAP_ROUND; path->cyclic = FALSE; path->clipping = FALSE; path->line_width = 0.1; path->dash.offset = 0.0; path->dash.n_dash = 0; path->dash.dash = NULL; break; case DIA_SHAPE_BEZIER: bezier = g_new0 (DiaShapeBezier, 1); shape = (DiaShape*) bezier; bezier->join = DIA_JOIN_ROUND; bezier->cap = DIA_CAP_ROUND; bezier->line_width = 0.1; bezier->fill = DIA_FILL_NONE; bezier->fill_color = DIA_COLOR_A(0,0,0,0); bezier->cyclic = FALSE; bezier->clipping = FALSE; bezier->dash.offset = 0.0; bezier->dash.n_dash = 0; bezier->dash.dash = NULL; break; case DIA_SHAPE_ELLIPSE: ellipse = g_new0 (DiaShapeEllipse, 1); shape = (DiaShape*) ellipse; ellipse->center.x = 0.0; ellipse->center.y = 0.0; ellipse->width = 1.0; ellipse->height = 1.0; ellipse->line_width = 0.1; ellipse->fill = DIA_FILL_NONE; ellipse->fill_color = DIA_COLOR_A(0, 0, 0, 0); ellipse->clipping = FALSE; ellipse->dash.offset = 0.0; ellipse->dash.n_dash = 0; ellipse->dash.dash = NULL; break; case DIA_SHAPE_TEXT: text = g_new0 (DiaShapeText, 1); shape = (DiaShape*) text; text->font_desc = NULL; text->text = NULL; text->need_free = TRUE; text->justify = FALSE; text->markup = TRUE; text->wrap_mode = DIA_WRAP_WORD; text->line_spacing = 0; text->alignment = PANGO_ALIGN_LEFT; text->max_width = G_MAXINT; text->max_height = G_MAXINT; text->text_width = 0.0; art_affine_identity (text->affine); text->cursor = -1; break; case DIA_SHAPE_IMAGE: image = g_new0 (DiaShapeImage, 1); shape = (DiaShape*) image; image->pixbuf = NULL; art_affine_identity (image->affine); break; case DIA_SHAPE_WIDGET: //shape = g_new0 (DiaShapeWidget, 1); break; case DIA_SHAPE_CLIP: clip = g_new0 (DiaShapeClip, 1); shape = (DiaShape*) clip; clip->clip.x0 = clip->clip.x1 = 0.0; clip->clip.y0 = clip->clip.y1 = 0.0; break; default: g_assert_not_reached (); } g_assert (shape != NULL); /* Those initializations don't need to take place: */ shape->type = type; shape->color = DIA_COLOR (0, 0, 0); shape->update_cnt = 0; shape->ref_cnt = 1; shape->visibility = DIA_SHAPE_VISIBLE; return shape; } static void dia_shape_destroy (DiaShape *shape) { g_return_if_fail (shape != NULL); switch (shape->type) { case DIA_SHAPE_PATH: dia_shape_path_free ((DiaShapePath*) shape); break; case DIA_SHAPE_BEZIER: dia_shape_bezier_free ((DiaShapeBezier*) shape); break; case DIA_SHAPE_ELLIPSE: dia_shape_ellipse_free ((DiaShapeEllipse*) shape); break; case DIA_SHAPE_TEXT: dia_shape_text_free ((DiaShapeText*) shape); break; case DIA_SHAPE_IMAGE: dia_shape_image_free ((DiaShapeImage*) shape); break; default: break; } g_free (shape); } DiaShape* dia_shape_ref (DiaShape *shape) { g_return_if_fail (shape != NULL); shape->ref_cnt++; return shape; } void dia_shape_unref (DiaShape *shape) { g_return_if_fail (shape != NULL); shape->ref_cnt--; if (shape->ref_cnt == 0) dia_shape_destroy (shape); } void dia_shape_free (DiaShape *shape) { dia_shape_unref (shape); } /* * Generic attributes */ void dia_shape_set_visibility (DiaShape *shape, DiaShapeVisibility vis) { g_return_if_fail (shape != NULL); shape->visibility = vis; request_update (shape); } void dia_shape_set_color (DiaShape *shape, DiaColor color) { g_return_if_fail (shape != NULL); shape->color = color; request_update (shape); } gboolean dia_shape_get_bounds (DiaShape *shape, DiaRectangle *bb) { if (!shape) return FALSE; return FALSE; } /* * Path like shapes */ static void dia_shape_path_free (DiaShapePath *path) { if (path->vpath) art_free (path->vpath); path->vpath = NULL; } void dia_shape_line (DiaShape *shape, DiaPoint *start, DiaPoint *end) { DiaShapePath *path = (DiaShapePath*) shape; ArtVpath *vpath; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); g_return_if_fail (start != NULL); g_return_if_fail (end != NULL); if (path->vpath) vpath = path->vpath = art_renew (path->vpath, ArtVpath, 3); else vpath = path->vpath = art_new (ArtVpath, 3); vpath[0].code = ART_MOVETO; vpath[0].x = start->x; vpath[0].y = start->y; vpath[1].code = ART_LINETO; vpath[1].x = end->x; vpath[1].y = end->y; vpath[2].code = ART_END; vpath[2].x = 0; vpath[2].y = 0; dia_shape_path_set_cyclic (shape, FALSE); request_update (shape); } void dia_shape_rectangle (DiaShape *shape, DiaPoint *upper_left, DiaPoint *lower_right) { DiaShapePath *path = (DiaShapePath*) shape; ArtVpath *vpath; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); g_return_if_fail (upper_left != NULL); g_return_if_fail (lower_right != NULL); if (path->vpath) vpath = path->vpath = art_renew (path->vpath, ArtVpath, 5); else vpath = path->vpath = art_new (ArtVpath, 5); vpath[0].code = ART_MOVETO; vpath[0].x = upper_left->x; vpath[0].y = upper_left->y; vpath[1].code = ART_LINETO; vpath[1].x = lower_right->x; vpath[1].y = upper_left->y; vpath[2].code = ART_LINETO; vpath[2].x = lower_right->x; vpath[2].y = lower_right->y; vpath[3].code = ART_LINETO; vpath[3].x = upper_left->x; vpath[3].y = lower_right->y; vpath[4].code = ART_END; vpath[4].x = 0; vpath[4].y = 0; dia_shape_path_set_cyclic (shape, TRUE); request_update (shape); } /** * dia_shape_polyline: * @shape: * @n_points: * @points: * * Create a line with @n_points elements. @points is an array of @n_points * #DiaPoint elements. **/ void dia_shape_polyline (DiaShape *shape, guint n_points, DiaPoint *points) { DiaShapePath *path = (DiaShapePath*) shape; ArtVpath *vpath; guint i; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); g_return_if_fail (n_points > 0); g_return_if_fail (points != NULL); if (path->vpath) vpath = path->vpath = art_renew (path->vpath, ArtVpath, n_points + 1); else vpath = path->vpath = art_new (ArtVpath, n_points + 1); vpath[0].code = ART_MOVETO; vpath[0].x = points[0].x; vpath[0].y = points[0].y; for (i = 1; i < n_points; i++) { vpath[i].code = ART_LINETO; vpath[i].x = points[i].x; vpath[i].y = points[i].y; } vpath[i].code = ART_END; vpath[i].x = 0.0; vpath[i].y = 0.0; dia_shape_path_set_cyclic (shape, FALSE); request_update (shape); } /** * dia_shape_polygon: * @shape: * @n_points: * @points: * * Like dia_shape_polyline(), but in this case the line is closed. **/ void dia_shape_polygon (DiaShape *shape, guint n_points, DiaPoint *points) { DiaShapePath* path = (DiaShapePath*) shape; ArtVpath *vpath; guint i; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); g_return_if_fail (n_points > 0); g_return_if_fail (points != NULL); if (path->vpath) vpath = path->vpath = art_renew (path->vpath, ArtVpath, n_points + 1); else vpath = path->vpath = art_new (ArtVpath, n_points + 1); vpath[0].code = ART_MOVETO; vpath[0].x = points[0].x; vpath[0].y = points[0].y; for (i = 1; i < n_points; i++) { vpath[i].code = ART_LINETO; vpath[i].x = points[i].x; vpath[i].y = points[i].y; } vpath[i].code = ART_END; vpath[i].x = 0.0; vpath[i].y = 0.0; dia_shape_path_set_cyclic (shape, TRUE); request_update (shape); } /** * dia_shape_arc: * @shape: * @begin: * @middle: * @end: * * Not implemented yet. **/ void dia_shape_arc (DiaShape *shape, DiaPoint *begin, DiaPoint *middle, DiaPoint *end) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); request_update (shape); } /** * dia_shape_path_set_fill_color: * @shape: * @fill_color: * * Set the color that is to be used if the shape is to be filled. The fill * style can be set with dia_shape_path_set_fill(). **/ void dia_shape_path_set_fill_color (DiaShape *shape, DiaColor fill_color) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->fill_color = fill_color; request_update (shape); } /** * dia_shape_path_set_line_width: * @shape: * @line_width: * * Set the line width for a path like shape. **/ void dia_shape_path_set_line_width (DiaShape *shape, gdouble line_width) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); g_return_if_fail (line_width > 0.0); ((DiaShapePath*) shape)->line_width = line_width; request_update (shape); } /** * dia_shape_path_set_fill: * @shape: * @fill: * * Set the fill style for the path. **/ void dia_shape_path_set_fill (DiaShape *shape, DiaFillStyle fill) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->fill = fill; request_update (shape); } /** * dia_shape_path_set_cyclic: * @shape: * @cyclic: * * Set the path to cyclic. Cyclic paths are closed. **/ void dia_shape_path_set_cyclic (DiaShape *shape, gboolean cyclic) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->cyclic = cyclic; request_update (shape); } /** * dia_shape_path_set_clipping: * @shape: * @clipping: * * If the clipping attribute is set, the shape will be used as a clipping path * Note that clipping paths can also contain a path including filling. **/ void dia_shape_path_set_clipping (DiaShape *shape, gboolean clipping) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->clipping = clipping; request_update (shape); } /** * dia_shape_path_set_dash: * @shape: * @offset: * @n_dash: * @dash: * * Set the dash style for the line. **/ void dia_shape_path_set_dash (DiaShape *shape, gdouble offset, guint n_dash, gdouble *dash) { DiaShapePath* path = (DiaShapePath*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); if (path->dash.dash) g_free (path->dash.dash); path->dash.offset = offset; path->dash.n_dash = n_dash; if (n_dash > 0) { path->dash.dash = g_new (gdouble, n_dash); memcpy (path->dash.dash, dash, n_dash * sizeof(gdouble)); } else path->dash.dash = NULL; request_update (shape); } /** * dia_shape_path_set_join: * @shape: * @join: * * Set the join style for a line. **/ void dia_shape_path_set_join (DiaShape *shape, DiaJoinStyle join) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->join = join; request_update (shape); } /** * dia_shape_path_set_cap: * @shape: * @cap: * * The the line end (cap) style for a line, thsi property is not very useful * if a path is set to cyclic. **/ void dia_shape_path_set_cap (DiaShape *shape, DiaCapStyle cap) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_PATH); ((DiaShapePath*) shape)->cap = cap; request_update (shape); } /** * dia_shape_path_is_clip_path: * @shape: * * * * Return value: TRUE if the path is indeed a clip path. **/ gboolean dia_shape_path_is_clip_path (DiaShape *shape) { return ((shape->type == DIA_SHAPE_PATH) && ((DiaShapePath*) shape)->clipping); } /* * Bezier */ static void dia_shape_bezier_free (DiaShapeBezier *bezier) { if (bezier->bpath); art_free (bezier->bpath); bezier->bpath = NULL; } /** * dia_shape_bezier: * @shape: * @start: starting point for the bezier curve. * @n_points: the number of points, should be a multiple of 3. * @points: Array of @n_points points * * Create a bezier shape. @points should contain the amount of points as * specified by @n_points. For each point in the bezier curve three points * are used: one for the actual point on the line and two for the weight * of the curve. **/ void dia_shape_bezier (DiaShape *shape, DiaPoint *start, guint n_points, DiaPoint *points) { DiaShapeBezier *bezier = (DiaShapeBezier*) shape; ArtBpath *path; guint i, n; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); g_return_if_fail (n_points % 3 == 0); if (bezier->bpath) path = bezier->bpath = art_renew (bezier->bpath, ArtBpath, n_points / 3 + 2); else path = bezier->bpath = art_new (ArtBpath, n_points / 3 + 2); path[0].code = ART_MOVETO; path[0].x1 = 0.0; path[0].y1 = 0.0; path[0].x2 = 0.0; path[0].y2 = 0.0; path[0].x3 = start->x; path[0].y3 = start->y; for (i = 1, n = 0; n < n_points; i++) { path[i].code = ART_CURVETO; path[i].x1 = points[n].x; path[i].y1 = points[n++].y; path[i].x2 = points[n].x; path[i].y2 = points[n++].y; path[i].x3 = points[n].x; path[i].y3 = points[n++].y; } path[i].code = ART_END; path[i].x1 = 0.0; path[i].y1 = 0.0; path[i].x2 = 0.0; path[i].y2 = 0.0; path[i].x3 = 0.0; //points[n_points - 1].x; path[i].y3 = 0.0; //points[n_points - 1].y; request_update (shape); } void dia_shape_bezier_set_fill_color (DiaShape *shape, DiaColor fill_color) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->fill_color = fill_color; request_update (shape); } void dia_shape_bezier_set_fill (DiaShape *shape, DiaFillStyle fill) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->fill = fill; request_update (shape); } void dia_shape_bezier_set_line_width (DiaShape *shape, gdouble line_width) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); g_return_if_fail (line_width > 0.0); ((DiaShapeBezier*) shape)->line_width = line_width; request_update (shape); } void dia_shape_bezier_set_join (DiaShape *shape, DiaJoinStyle join) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->join = join; request_update (shape); } void dia_shape_bezier_set_cap (DiaShape *shape, DiaCapStyle cap) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->cap = cap; request_update (shape); } void dia_shape_bezier_set_cyclic (DiaShape *shape, gboolean cyclic) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->cyclic = cyclic; request_update (shape); } void dia_shape_bezier_set_clipping (DiaShape *shape, gboolean clipping) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); ((DiaShapeBezier*) shape)->clipping = clipping; request_update (shape); } void dia_shape_bezier_set_dash (DiaShape *shape, gdouble offset, guint n_dash, gdouble *dash) { DiaShapeBezier* path = (DiaShapeBezier*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_BEZIER); if (path->dash.dash) g_free (path->dash.dash); path->dash.offset = offset; path->dash.n_dash = n_dash; if (n_dash > 0) { path->dash.dash = g_new (gdouble, n_dash); memcpy (path->dash.dash, dash, n_dash * sizeof(gdouble)); } else path->dash.dash = NULL; request_update (shape); } gboolean dia_shape_bezier_is_clip_path (DiaShape *shape) { return ((shape->type == DIA_SHAPE_BEZIER) && ((DiaShapeBezier*) shape)->clipping); } /* * Ellipse */ static void dia_shape_ellipse_free (DiaShapeEllipse *ellipse) { } void dia_shape_ellipse (DiaShape *shape, DiaPoint *center, gdouble width, gdouble height) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); g_return_if_fail (center != NULL); ((DiaShapeEllipse*) shape)->center = *center; ((DiaShapeEllipse*) shape)->width = width; ((DiaShapeEllipse*) shape)->height = height; request_update (shape); } void dia_shape_ellipse_set_fill_color (DiaShape *shape, DiaColor fill_color) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); ((DiaShapeEllipse*) shape)->fill_color = fill_color; request_update (shape); } void dia_shape_ellipse_set_line_width (DiaShape *shape, gdouble line_width) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); g_return_if_fail (line_width > 0.0); ((DiaShapeEllipse*) shape)->line_width = line_width; request_update (shape); } void dia_shape_ellipse_set_fill (DiaShape *shape, DiaFillStyle fill) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); ((DiaShapeEllipse*) shape)->fill = fill; request_update (shape); } void dia_shape_ellipse_set_clipping (DiaShape *shape, gboolean clipping) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); ((DiaShapeEllipse*) shape)->clipping = clipping; request_update (shape); } void dia_shape_ellipse_set_dash (DiaShape *shape, gdouble offset, guint n_dash, gdouble *dash) { DiaShapeEllipse* ellipse = (DiaShapeEllipse*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_ELLIPSE); if (ellipse->dash.dash) g_free (ellipse->dash.dash); ellipse->dash.offset = offset; ellipse->dash.n_dash = n_dash; if (n_dash > 0) { ellipse->dash.dash = g_new (gdouble, n_dash); memcpy (ellipse->dash.dash, dash, n_dash * sizeof(gdouble)); } else ellipse->dash.dash = NULL; request_update (shape); } gboolean dia_shape_ellipse_is_clip_path (DiaShape *shape) { return ((shape->type == DIA_SHAPE_ELLIPSE) && ((DiaShapeEllipse*) shape)->clipping); } /* * Text */ static void dia_shape_text_free (DiaShapeText *text) { if (text->text && text->need_free) g_free (text->text); text->text = NULL; if (text->font_desc) pango_font_description_free (text->font_desc); text->font_desc = NULL; } static void dia_shape_text_real_set_text (DiaShapeText *stext, const gchar* text) { if (stext->text && stext->need_free) g_free (stext->text); stext->text = (gchar*) text; } void dia_shape_text (DiaShape *shape, PangoFontDescription *font_desc, const gchar *text) { DiaShapeText *stext = (DiaShapeText*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (text != NULL); dia_shape_text_real_set_text (stext, text ? g_strdup (text) : NULL); stext->need_free = TRUE; dia_shape_text_set_font_description (shape, font_desc); request_update (shape); } void dia_shape_text_set_font_description (DiaShape *shape, PangoFontDescription *font_desc) { DiaShapeText *text = (DiaShapeText*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); if (text->font_desc) { pango_font_description_free (text->font_desc); text->font_desc = NULL; } if (font_desc != NULL) { text->font_desc = pango_font_description_copy (font_desc); if (!pango_font_description_get_size_is_absolute(text->font_desc)) { double size = (double)pango_font_description_get_size(text->font_desc); pango_font_description_set_absolute_size(text->font_desc, size); } } request_update (shape); } void dia_shape_text_set_text (DiaShape *shape, const gchar *text) { DiaShapeText *stext = (DiaShapeText*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (text != NULL); dia_shape_text_real_set_text (stext, text ? g_strdup (text) : NULL); stext->need_free = TRUE; request_update (shape); } void dia_shape_text_set_static_text (DiaShape *shape, const gchar *text) { DiaShapeText *stext = (DiaShapeText*) shape; g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (text != NULL); dia_shape_text_real_set_text (stext, text); stext->need_free = FALSE; request_update (shape); } void dia_shape_text_set_affine (DiaShape *shape, gdouble affine[6]) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (affine != NULL); memcpy (((DiaShapeText*) shape)->affine, affine, 6 * sizeof (gdouble)); request_update (shape); } void dia_shape_text_set_pos (DiaShape *shape, DiaPoint *pos) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->affine[4] = pos->x; ((DiaShapeText*) shape)->affine[5] = pos->y; request_update (shape); } /** * dia_shape_text_set_max_width: * @shape: * @width: * * Set the max width of the text box. If the text is wider than @width, * the text is clipped at @width. **/ void dia_shape_text_set_max_width (DiaShape *shape, gdouble width) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (width >= 0); ((DiaShapeText*) shape)->max_width = width; request_update (shape); } /** * dia_shape_text_set_max_height: * @shape: * @height: * * Set the height of the text box. **/ void dia_shape_text_set_max_height (DiaShape *shape, gdouble height) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (height >= 0); ((DiaShapeText*) shape)->max_height = height; request_update (shape); } /** * dia_shape_text_set_text_width: * @shape: * @width: * * Set the width of the text. Text will be word wrapped if that option is * enabled and the text is actually longer than the @text_width. **/ void dia_shape_text_set_text_width (DiaShape *shape, gdouble width) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); g_return_if_fail (width >= 0); ((DiaShapeText*) shape)->text_width = width; request_update (shape); } /** * dia_shape_text_set_line_spacing: * @shape: * @line_spacing: * * **/ void dia_shape_text_set_line_spacing (DiaShape *shape, gdouble line_spacing) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->line_spacing = line_spacing; request_update (shape); } /** * dia_shape_text_set_justify: * @shape: * @justify: * * **/ void dia_shape_text_set_justify (DiaShape *shape, gboolean justify) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->justify = justify; request_update (shape); } void dia_shape_text_set_markup (DiaShape *shape, gboolean markup) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->markup = markup; request_update (shape); } /** * dia_shape_text_set_wrap_mode: * @shape: * @wrap_mode: * * Set the wrapping mode for the text shape. **/ void dia_shape_text_set_wrap_mode (DiaShape *shape, DiaWrapMode wrap_mode) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->wrap_mode = wrap_mode; request_update (shape); } /** * dia_shape_text_set_alignment: * @shape: * @alignment: * * Set the text alignment for a shape (left, right, center, justified). **/ void dia_shape_text_set_alignment (DiaShape *shape, PangoAlignment alignment) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_TEXT); ((DiaShapeText*) shape)->alignment = alignment; request_update (shape); } /** * dia_shape_text_to_pango_layout: * @shape: * @fill: Add information of teh @shape to the #PangoLayout. * * Create a #PangoLayout based on the information of the @shape. The maximum * width and height, nor the affine transformation are added to the layout. * * Return value: A new #PangoLayout. **/ PangoLayout* dia_shape_text_to_pango_layout (DiaShape *shape, gboolean fill) { PangoLayout *layout; g_return_val_if_fail (shape != NULL, NULL); g_return_val_if_fail (shape->type == DIA_SHAPE_TEXT, NULL); layout = dia_canvas_get_pango_layout (); g_return_val_if_fail (layout != NULL, NULL); if (fill) dia_shape_text_fill_pango_layout (shape, layout); return layout; } /** * dia_shape_text_fill_pango_layout: * @shape: * @layout: * * Create a #PangoLayout object from a #DiaShapeText. **/ void dia_shape_text_fill_pango_layout (DiaShape *shape, PangoLayout *layout) { DiaShapeText *text = (DiaShapeText*) shape; PangoFontDescription *font_desc; if (text->font_desc) font_desc = pango_font_description_copy_static (text->font_desc); else font_desc = pango_font_description_copy_static (pango_context_get_font_description (pango_layout_get_context (layout))); pango_layout_set_font_description (layout, font_desc); pango_font_description_free (font_desc); if (text->text) { if (text->markup) pango_layout_set_markup (layout, text->text, -1); else pango_layout_set_text (layout, text->text, -1); } if (text->text_width > 0.0) pango_layout_set_width (layout, ceil(text->text_width * PANGO_SCALE)); else pango_layout_set_width (layout, -1); pango_layout_set_justify (layout, text->justify); switch (text->wrap_mode) { case DIA_WRAP_CHAR: pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); break; default: pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); break; } pango_layout_set_spacing (layout, (gint) text->line_spacing * PANGO_SCALE); pango_layout_set_alignment (layout, text->alignment); } /** * dia_shape_text_cursor_from_pos: * @shape: A #DiaShapeText * @pos: cursor position, in item relative coordinates. * @cursor: Set the cursor. * * Find the cursor position belonging to the position @pos. * * Return value: **/ gboolean dia_shape_text_cursor_from_pos (DiaShape *shape, DiaPoint *pos, gint *cursor) { DiaShapeText *text = (DiaShapeText*) shape; PangoLayout *layout; DiaPoint cursor_pos; gint index, trailing; gboolean in; gdouble inv[6]; g_return_val_if_fail (shape != NULL, FALSE); g_return_val_if_fail (shape->type == DIA_SHAPE_TEXT, FALSE); g_return_val_if_fail (pos != NULL, FALSE); g_return_val_if_fail (cursor != NULL, FALSE); g_warning (G_STRLOC": Do no longer use this function!!"); layout = dia_shape_text_to_pango_layout (shape, TRUE); g_assert (layout != NULL); art_affine_invert (inv, text->affine); /* Compensate centered and right aligned text: */ if (text->alignment != PANGO_ALIGN_LEFT) { gint w; gdouble dw; pango_layout_get_size (layout, &w, NULL); pango_layout_set_width (layout, w); w = (w + PANGO_SCALE / 2) / PANGO_SCALE; dw = (gdouble) w - ceil (text->max_width); if (text->alignment == PANGO_ALIGN_CENTER) dw /= 2.0; inv[4] += dw; } cursor_pos.x = pos->x * inv[0] + pos->y * inv[2] + inv[4]; cursor_pos.y = pos->x * inv[1] + pos->y * inv[3] + inv[5]; in = pango_layout_xy_to_index (layout, (int) (cursor_pos.x * PANGO_SCALE), (int) (cursor_pos.y * PANGO_SCALE), &index, &trailing); g_object_unref (layout); *cursor = index + trailing; return in; } /* * Image */ static void dia_shape_image_free (DiaShapeImage *image) { if (image->pixbuf) gdk_pixbuf_unref (image->pixbuf); image->pixbuf = NULL; } void dia_shape_image (DiaShape *shape, GdkPixbuf *image) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_IMAGE); g_return_if_fail (GDK_IS_PIXBUF (image)); if (((DiaShapeImage*)shape)->pixbuf) gdk_pixbuf_unref (((DiaShapeImage*)shape)->pixbuf); ((DiaShapeImage*)shape)->pixbuf = image; gdk_pixbuf_ref (image); request_update (shape); } void dia_shape_image_set_pos (DiaShape *shape, DiaPoint *pos) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_IMAGE); g_return_if_fail (pos != NULL); ((DiaShapeImage*) shape)->affine[4] = pos->x; ((DiaShapeImage*) shape)->affine[5] = pos->y; request_update (shape); } void dia_shape_image_set_affine (DiaShape *shape, gdouble affine[6]) { g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_IMAGE); g_return_if_fail (affine != NULL); memcpy (((DiaShapeImage*) shape)->affine, affine, 6 * sizeof (gdouble)); request_update (shape); } /* * Clip path */ void dia_shape_clip (DiaShape *shape, gdouble left, gdouble top, gdouble right, gdouble bottom) { g_warning ("DiaShapeClip is now obsolete, use DiaShapePath with clipping==TRUE"); g_return_if_fail (shape != NULL); g_return_if_fail (shape->type == DIA_SHAPE_CLIP); ((DiaShapeClip*) shape)->clip.x0 = left; ((DiaShapeClip*) shape)->clip.y0 = top; ((DiaShapeClip*) shape)->clip.x1 = right; ((DiaShapeClip*) shape)->clip.y1 = bottom; request_update (shape); }