/*! * \brief Convert _StdPath to one or more _BezierLine/BezierGon */ static ObjectChange * _convert_to_beziers_callback (DiaObject *obj, Point *clicked, gpointer data) { StdPath *stdpath = (StdPath *)obj; BezPoint *bezier = stdpath->points; GList *list = NULL; int i, n = 0; ObjectChange *change; for (i = 1; i < stdpath->num_points; ++i) { if (bezier[i].type == BEZ_MOVE_TO || i+1 == stdpath->num_points) { DiaObject *rep; int num = bezier[i].type == BEZ_MOVE_TO ? i - n : i - n + 1; if (stdpath->stroke_or_fill & PDO_FILL) rep = create_standard_beziergon (num, &bezier[n]); else rep = create_standard_bezierline (num, &bezier[n], NULL, NULL); if (!rep) /* no Standard objects? */ break; list = g_list_append (list, rep); n = i; } } if (!list) { change = change_list_create (); } else if (g_list_length (list) == 1) { change = object_substitute (obj, (DiaObject *)list->data); g_list_free (list); } else { change = object_substitute (obj, create_standard_group (list)); } return change; }
static ObjectChange * _textobj_convert_to_path_callback (DiaObject *obj, Point *clicked, gpointer data) { Textobj *textobj = (Textobj *)obj; const Text *text = textobj->text; DiaObject *path = NULL; if (!text_is_empty(text)) /* still screwed with empty lines ;) */ path = create_standard_path_from_text (text); if (path) { ObjectChange *change; Color bg = textobj->fill_color; /* FIXME: otherwise object_substitue() will tint the text with bg */ textobj->fill_color = text->color; change = object_substitute (obj, path); /* restore */ textobj->fill_color = bg; return change; } /* silently fail */ return change_list_create (); }
/*! * \brief Upgrade the Line to a Zigzagline * * Convert the _Line to a _Zigzagline with the position clicked (if near enough) * for the new segment. The result of this function is more favorable for connected * lines by autorouting. * * Further object properties are preserved by the use of object_substitute() * * @param obj self pointer * @param clicked last clicked point on canvas or NULL * @param data here unuesed user_data pointer * @return an _ObjectChange to support undo/redo * * \memberof Line */ static ObjectChange * _convert_to_zigzagline_callback (DiaObject *obj, Point *clicked, gpointer data) { DiaObject *zigzag; Line *line = (Line *)obj; Point points[4]; if (clicked) { points[0] = line->connection.endpoints[0]; points[3] = line->connection.endpoints[1]; /* not sure if we really want to give it a direction at all */ if (fabs(((points[0].x + points[3].x)/2) - clicked->x) > fabs(((points[0].y + points[3].y)/2) - clicked->y)) { points[1].x = points[2].x = clicked->x; points[1].y = points[0].y; points[2].y = points[3].y; } else { points[1].y = points[2].y = clicked->y; points[1].x = points[0].x; points[2].x = points[3].x; } zigzag = create_standard_zigzagline (4, points, &line->end_arrow, &line->start_arrow); } else { points[0] = line->connection.endpoints[0]; points[3] = line->connection.endpoints[1]; points[1].x = points[2].x = (points[0].x + points[3].x) / 2.0; points[1].y = points[0].y; points[2].y = points[3].y; zigzag = create_standard_zigzagline (4, points, &line->end_arrow, &line->start_arrow); } g_return_val_if_fail (zigzag != NULL, NULL); return object_substitute (obj, zigzag); }
static ObjectChange * _box_convert_to_path_callback (DiaObject *obj, Point *clicked, gpointer data) { const Box *box = (Box *)obj; const Element *elem = &box->element; DiaObject *path; int num_points; BezPoint *points; if (box->corner_radius > 0) { const real w = elem->width; const real h = elem->height; const real x = elem->corner.x; const real y = elem->corner.y; real r = box->corner_radius; num_points = 9; points = g_alloca (sizeof(BezPoint) * num_points); /* avoid r>w/w and r>h/2 */ r = (w > h ) ? (r > h/2 ? h/2 : r) : (r > w/2 ? w/2 : r); points[0].type = BEZ_MOVE_TO; points[0].p1.x = x + r; points[0].p1.y = y; /* top-left */ points[1].type = BEZ_LINE_TO; points[1].p1.x = x + w - r; points[1].p1.y = y; /* top-right */ points[2].type = BEZ_CURVE_TO; points[2].p1.x = x + w - r; points[2].p1.y = y; /* around */ points[2].p2.x = x + w; points[2].p2.y = y; points[2].p3.x = x + w; points[2].p3.y = y + r; points[3].type = BEZ_LINE_TO; points[3].p1.x = x + w; points[3].p1.y = y + h - r; /* bottom-right */ points[4].type = BEZ_CURVE_TO; points[4].p1.x = x + w; points[4].p1.y = y + h - r; /* around */ points[4].p2.x = x + w; points[4].p2.y = y + h; points[4].p3.x = x + w - r; points[4].p3.y = y + h; points[5].type = BEZ_LINE_TO; points[5].p1.x = x + r; points[5].p1.y = y + h; /* bottom-left */ points[6].type = BEZ_CURVE_TO; points[6].p1.x = x + r; points[6].p1.y = y + h; /* around */ points[6].p2.x = x; points[6].p2.y = y + h; points[6].p3.x = x; points[6].p3.y = y + h - r; points[7].type = BEZ_LINE_TO; points[7].p1.x = x; points[7].p1.y = y + r; /* top-left */ points[8].type = BEZ_CURVE_TO; points[8].p1.x = x; points[8].p1.y = y + r; /* around */ points[8].p2.x = x; points[8].p2.y = y; points[8].p3.x = x + r; points[8].p3.y = y; } else { num_points = 5; points = g_alloca (sizeof(BezPoint) * num_points); points[0].type = BEZ_MOVE_TO; points[0].p1 = elem->corner; points[1].type = points[2].type = points[3].type = points[4].type = BEZ_LINE_TO; points[1].p1.x = elem->corner.x + elem->width; points[1].p1.y = elem->corner.y; points[2].p1.x = elem->corner.x + elem->width; points[2].p1.y = elem->corner.y + elem->height; points[3].p1.x = elem->corner.x; points[3].p1.y = elem->corner.y + elem->height; points[4].p1 = elem->corner; } path = create_standard_path (num_points, points); if (path) return object_substitute (obj, path); /* Empty change */ return change_list_create (); }
/*! * \brief Upgrade the _Zigzagline to a _Bezierline * * Accessible through the object's context menu this function substitutes * the _Zigzagline with a _Bezierline. The function creates a favorable * representation of the original _OrthConn data of the given object. * * @param obj explicit this pointer * @param clicked last clicked point on the canvas or NULL * @param data a pointer to extra data, unused here * @return undo/redo information as _ObjectChange * * \memberof _Zigzagline */ static ObjectChange * _convert_to_bezierline_callback (DiaObject *obj, Point *clicked, gpointer data) { DiaObject *poly; Zigzagline *zigzagline = (Zigzagline *)obj; OrthConn *orth = &zigzagline->orth; BezPoint *bp; int i, j, num_points; DiaObject *bezier; num_points = (orth->numpoints + 1) / 2; bp = g_new(BezPoint, num_points); bp[0].type = BEZ_MOVE_TO; bp[0].p1 = orth->points[0]; for (i = 1, j = 1; i < num_points && j < orth->numpoints; ++i) { bp[i].type = BEZ_CURVE_TO; bp[i].p1 = orth->points[j++]; bp[i].p2 = orth->points[j++]; if (j + 2 < orth->numpoints) { /* if we have more than two points left, use the middle of the segment */ Point p = { (orth->points[j-1].x + orth->points[j].x) / 2.0, (orth->points[j-1].y + orth->points[j].y) / 2.0 }; bp[i].p3 = p; } else if (j + 2 == orth->numpoints) { /* if we one extra point left, use the middle of two segments */ Point p1 = { (orth->points[j-2].x + orth->points[j-1].x) / 2.0, (orth->points[j-2].y + orth->points[j-1].y) / 2.0 }; Point p2 = { (orth->points[j-1].x + orth->points[j].x) / 2.0, (orth->points[j-1].y + orth->points[j].y) / 2.0 }; Point p = { (p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0 }; bp[i].p3 = p; /* also adapt the previous control point */ bp[i].p2 = p1; /* and do the final bezpoint */ bp[i+1].type = BEZ_CURVE_TO; bp[i+1].p1 = p2; bp[i+1].p2 = orth->points[j]; bp[i+1].p3 = orth->points[j+1]; break; } else { bp[i].p3 = orth->points[j++]; } } bezier = create_standard_bezierline(num_points, bp, &zigzagline->end_arrow, &zigzagline->start_arrow); g_free(bp); return object_substitute (obj, bezier); }
/*! * \brief Convert _Beziergon to _Path * \memberof _Beziergon */ static ObjectChange * _beziergon_convert_to_path_callback (DiaObject *obj, Point *clicked, gpointer data) { Beziergon *beziergon = (Beziergon *) obj; BezierShape *bez = &beziergon->bezier; DiaObject *path = NULL; if (bez->bezier.num_points > 1) path = create_standard_path (bez->bezier.num_points, bez->bezier.points); if (path) return object_substitute (obj, path); /* just an empty change */ return change_list_create (); }
/*! * \brief Upgrade the Line to a Polyline * * Convert the _Line to a _Polyline with the position clicked as third point. * Further object properties are preserved by the use of object_substitute() * * @param obj self pointer * @param clicked last clicked point on canvas or NULL * @param data here unuesed user_data pointer * @return an _ObjectChange to support undo/redo * * \memberof Line */ static ObjectChange * _convert_to_polyline_callback (DiaObject *obj, Point *clicked, gpointer data) { DiaObject *poly; Line *line = (Line *)obj; Point points[3]; points[0] = line->connection.endpoints[0]; points[2] = line->connection.endpoints[1]; if (clicked) { points[1] = *clicked; } else { points[1].x = (points[0].x + points[2].x) / 2; points[1].y = (points[0].y + points[2].y) / 2; } poly = create_standard_polyline (3, points, &line->end_arrow, &line->start_arrow); g_return_val_if_fail (poly != NULL, NULL); return object_substitute (obj, poly); }