DiaObject * create_standard_path_from_text (const Text *text) { DiaObject *obj = NULL; GArray *points = g_array_new (FALSE, FALSE, sizeof(BezPoint)); if (text_to_path (text, points)) obj = create_standard_path (points->len, &g_array_index (points, BezPoint, 0)); g_array_free (points, TRUE); if (obj) { StdPath *path = (StdPath *)obj; Rectangle text_box; const Rectangle *pbb = &path->object.bounding_box; real sx, sy; Point pos; path->stroke_or_fill = PDO_FILL; path->fill_color = text->color; /* scale to fit the original size */ text_calc_boundingbox ((Text *)text, &text_box); pos.x = text_box.left; pos.y = text_box.top; sx = (text_box.right - text_box.left) / (pbb->right - pbb->left); sy = (text_box.bottom - text_box.top) / (pbb->bottom - pbb->top); _stdpath_scale (path, sx, sy); /* also adjust top left corner - calling update, too */ stdpath_move (path, &pos); } return obj; }
/*! * \brief Move one of the objects handles * \memberof StdPath */ static ObjectChange* stdpath_move_handle (StdPath *stdpath, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { DiaObject *obj = &stdpath->object; Point p0 = obj->position; if (stdpath->move_reason != reason) { if (HANDLE_MOVE_USER == reason) g_print ("move-user"); else if (HANDLE_MOVE_USER_FINAL == reason) g_print ("move-user-final\n"); else if (HANDLE_MOVE_CONNECTED == reason) g_print ("move-connected\n"); else g_print ("move-?reason?\n"); stdpath->move_reason = reason; } else { g_print ("*"); } if (handle->id == HANDLE_RESIZE_SE) { /* scale both directions - keep aspect ratio? */ Point p1 = stdpath->handles[7].pos; real sx, sy; g_assert(stdpath->handles[7].id == handle->id); sx = (to->x - p0.x) / (p1.x - p0.x); sy = (to->y - p0.y) / (p1.y - p0.y); _stdpath_scale (stdpath, sx, sy); stdpath_update_data (stdpath); } else if (handle->id == HANDLE_RESIZE_S) { /* scale height */ Point p1 = stdpath->handles[6].pos; real sy; int i; g_assert(stdpath->handles[6].id == handle->id); sy = (to->y - p0.y) / (p1.y - p0.y); for (i = 0; i < stdpath->num_points; ++i) { BezPoint *bp = &stdpath->points[i]; bp->p1.y = p0.y + (bp->p1.y - p0.y) * sy; bp->p2.y = p0.y + (bp->p2.y - p0.y) * sy; bp->p3.y = p0.y + (bp->p3.y - p0.y) * sy; } stdpath_update_data (stdpath); } else if (handle->id == HANDLE_RESIZE_E) { /* scale width */ Point p1 = stdpath->handles[4].pos; real sx; int i; g_assert(stdpath->handles[4].id == handle->id); sx = (to->x - p0.x) / (p1.x - p0.x); for (i = 0; i < stdpath->num_points; ++i) { BezPoint *bp = &stdpath->points[i]; bp->p1.x = p0.x + (bp->p1.x - p0.x) * sx; bp->p2.x = p0.x + (bp->p2.x - p0.x) * sx; bp->p3.x = p0.x + (bp->p3.x - p0.x) * sx; } stdpath_update_data (stdpath); } else if (handle->id == _HANDLE_SHEAR) { /* apply horizontal shear weighted by the vertical distance */ Point p1 = stdpath->handles[2].pos; Point pr = stdpath->handles[5].pos; real dx; /* delta x */ real rd = (pr.y - p0.y); /* reference distance */ int i; gboolean revert = FALSE; g_assert(stdpath->handles[2].id == handle->id); g_assert(stdpath->handles[3].id == _HANDLE_REF_POS); g_return_val_if_fail(rd > 0, NULL); dx = to->x - p1.x; /* move_handle needs to be reversible, so do not move more than * the sheared bounding box allows */ do { for (i = 0; i < stdpath->num_points; ++i) { BezPoint *bp = &stdpath->points[i]; real sw; /* scaling weight [0..1] to not move the left boundary */ sw = (pr.y - bp->p1.y) / rd; bp->p1.x += dx * sw; sw = (pr.y - bp->p2.y) / rd; bp->p2.x += dx * sw; sw = (pr.y - bp->p3.y) / rd; bp->p3.x += dx * sw; } stdpath_update_data (stdpath); if (!revert && (fabs(stdpath->handles[2].pos.x - (p1.x + dx)) > 0.05)) { dx = -dx; revert = TRUE; } else { revert = FALSE; } } while (revert); } else if (handle->id == _HANDLE_ROTATE) { Point p1 = stdpath->handles[1].pos; Point pr = stdpath->handles[3].pos; Point pc = {stdpath->handles[1].pos.x, stdpath->handles[3].pos.y }; real dx = to->x - p1.x; real dy = pr.y - p1.y; DiaMatrix m; int i; g_assert(stdpath->handles[1].id == handle->id); if (fabs(dx) < 0.001) return NULL; dia_matrix_set_angle_and_scales (&m, -atan2 (dy, dx), 1.0, 1.0); for (i = 0; i < stdpath->num_points; ++i) { BezPoint *bp = &stdpath->points[i]; int j; for (j = 0; j < 3; ++j) { Point *p = j == 0 ? &bp->p1 : (j == 1 ? &bp->p2 : &bp->p3); real w, h; w = p->x - pc.x; h = p->y - pc.y; p->x = pc.x + w * m.xx + h * m.xy; p->y = pc.y + w * m.yx + h * m.yy; } } stdpath_update_data (stdpath); } else if (handle->id == _HANDLE_PERSPECTIVE) { Point p1 = stdpath->handles[5].pos; Point pr = stdpath->handles[3].pos; Point cp = { stdpath->handles[1].pos.x, pr.y }; real h2 = p1.y - pr.y; /* relative movement against center and original pos */ real td = (cp.x - to->x) / (cp.x - p1.x) - 1.0; int i; g_assert(stdpath->handles[5].id == handle->id); for (i = 0; i < stdpath->num_points; ++i) { BezPoint *bp = &stdpath->points[i]; Point *p; for (p = &bp->p1; p <= &bp->p3; ++p) { /* the vertical distance from the center point decides about the strength */ real vd = (p->y - cp.y) / h2; /* normalized */ /* the horizontal distance from center gets modified */ real hd = (p->x - cp.x); p->x += (hd * vd * td); } } stdpath_update_data (stdpath); } else if (handle->type != HANDLE_NON_MOVABLE) { g_warning ("stdpath_move_handle() %d not moving", handle->id); } return NULL; }
/*! * \brief Move one of the objects handles * \memberof _StdPath */ static ObjectChange* stdpath_move_handle (StdPath *stdpath, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { const real EPSILON = 0.01; /* move_handle is supposed to be just moving that and related handles (e.g. * when N is moved NE and NW will move too). But 'opposite' handles are not * to be moved at all. So our transformation is invariant to the opposite * point of the path, not the object position. * * Another issue is limit checking. The path object must not get too small, * otherwise it can not be restored by reverse move_handle. So implement a * minimum distance between the moving and the opposite handle. */ if (handle->id == HANDLE_RESIZE_NW) { Point p0 = stdpath->handles[7].pos; /* SE */ Point p1 = stdpath->handles[0].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[0].id == handle->id); g_assert(stdpath->handles[7].id == HANDLE_RESIZE_SE); if (to->x + EPSILON > p0.x) sx = 1.0; if (to->y + EPSILON > p0.y) sy = 1.0; _stdpath_scale (stdpath, sx, sy, &p0); } else if (handle->id == HANDLE_RESIZE_N) { Point p0 = stdpath->handles[6].pos; /* S */ Point p1 = stdpath->handles[1].pos; real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[1].id == handle->id); g_assert(stdpath->handles[6].id == HANDLE_RESIZE_S); if (to->y + EPSILON > p0.y) sy = 1.0; _stdpath_scale (stdpath, 1.0, sy, &p0); } else if (handle->id == HANDLE_RESIZE_NE) { Point p0 = stdpath->handles[5].pos; /* SW */ Point p1 = stdpath->handles[2].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[2].id == handle->id); g_assert(stdpath->handles[5].id == HANDLE_RESIZE_SW); if (to->x - EPSILON < p0.x) sx = 1.0; if (to->y + EPSILON > p0.y) sy = 1.0; _stdpath_scale (stdpath, sx, sy, &p0); } else if (handle->id == HANDLE_RESIZE_W) { /* scale width */ Point p0 = stdpath->handles[4].pos; /* E */ Point p1 = stdpath->handles[3].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); g_assert(stdpath->handles[3].id == handle->id); g_assert(stdpath->handles[4].id == HANDLE_RESIZE_E); if (to->x + EPSILON > p0.x) sx = 1.0; _stdpath_scale (stdpath, sx, 1.0, &p0); } else if (handle->id == HANDLE_RESIZE_E) { /* scale width */ Point p0 = stdpath->handles[3].pos; /* W */ Point p1 = stdpath->handles[4].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); g_assert(stdpath->handles[4].id == handle->id); g_assert(stdpath->handles[3].id == HANDLE_RESIZE_W); if (to->x - EPSILON < p0.x) sx = 1.0; _stdpath_scale (stdpath, sx, 1.0, &p0); } else if (handle->id == HANDLE_RESIZE_SW) { Point p0 = stdpath->handles[2].pos; /* NE */ Point p1 = stdpath->handles[5].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[5].id == handle->id); g_assert(stdpath->handles[2].id == HANDLE_RESIZE_NE); if (to->x + EPSILON > p0.x) sx = 1.0; if (to->y - EPSILON < p0.y) sy = 1.0; _stdpath_scale (stdpath, sx, sy, &p0); } else if (handle->id == HANDLE_RESIZE_S) { /* scale height */ Point p0 = stdpath->handles[1].pos; /* N */ Point p1 = stdpath->handles[6].pos; real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[6].id == handle->id); g_assert(stdpath->handles[1].id == HANDLE_RESIZE_N); if (to->y - EPSILON < p0.y) sy = 1.0; _stdpath_scale (stdpath, 1.0, sy, &p0); } else if (handle->id == HANDLE_RESIZE_SE) { /* scale both directions - keep aspect ratio? */ Point p0 = stdpath->handles[0].pos; /* NW */ Point p1 = stdpath->handles[7].pos; real sx = (to->x - p0.x) / (p1.x - p0.x); real sy = (to->y - p0.y) / (p1.y - p0.y); g_assert(stdpath->handles[7].id == handle->id); g_assert(stdpath->handles[0].id == HANDLE_RESIZE_NW); if (to->x - EPSILON < p0.x) sx = 1.0; if (to->y - EPSILON < p0.y) sy = 1.0; _stdpath_scale (stdpath, sx, sy, &p0); } else if (handle->type != HANDLE_NON_MOVABLE) { g_warning ("stdpath_move_handle() %d not moving", handle->id); } stdpath_update_data (stdpath); return NULL; }