static ObjectChange* message_move_handle(Message *message, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(message!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { message->text_pos = *to; } else { endpoints = &message->connection.endpoints[0]; p1.x = 0.5*(endpoints[0].x + endpoints[1].x); p1.y = 0.5*(endpoints[0].y + endpoints[1].y); connection_move_handle(&message->connection, handle->id, to, cp, reason, modifiers); connection_adjust_for_autogap(&message->connection); p2.x = 0.5*(endpoints[0].x + endpoints[1].x); p2.y = 0.5*(endpoints[0].y + endpoints[1].y); point_sub(&p2, &p1); point_add(&message->text_pos, &p2); } message_update_data(message); return NULL; }
double distance_ellipse_point(const Point *centre, double width, double height, double line_width, const Point *point) { double w2 = width * width; double h2 = height * height; double scale; double rad; double dist; Point pt = *point; point_sub(&pt, centre); pt.setX( pt.x() * pt.x() ); pt.setY( pt.y() * pt.y() ); scale = w2 * h2 / ( 4 * h2 * pt.x() + 4 * w2 * pt.y() ); rad = sqrt( ( pt.x() + pt.y() ) * scale ) + line_width / 2; dist = sqrt( pt.x() + pt.y() ); if (dist <= rad) return 0.0; return dist - rad; }
static real arc_distance_from(Arc *arc, Point *point) { Point *endpoints; Point from_center; real angle; real d, d2; endpoints = &arc->connection.endpoints[0]; if (arc_is_line (arc)) return distance_line_point (&endpoints[0], &endpoints[1], arc->line_width, point); from_center = *point; point_sub(&from_center, &arc->center); angle = -atan2(from_center.y, from_center.x)*180.0/M_PI; if (angle<0) angle+=360.0; if (in_angle(angle, arc->angle1, arc->angle2)) { d = fabs(sqrt(point_dot(&from_center, &from_center)) - arc->radius); d -= arc->line_width/2.0; if (d<0) d = 0.0; return d; } else { d = distance_point_point(&endpoints[0], point); d2 = distance_point_point(&endpoints[1], point); return MIN(d,d2); } }
static ObjectChange* mbr_move_handle(Mbr *mbr, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; assert(mbr!=NULL); assert(handle!=NULL); assert(to!=NULL); if (handle->id == HANDLE_MOVE_MID_POINT) { mbr->pm = *to; } else { endpoints = &mbr->connection.endpoints[0]; p1.x = 0.5*(endpoints[0].x + endpoints[1].x); p1.y = 0.5*(endpoints[0].y + endpoints[1].y); connection_move_handle(&mbr->connection, handle->id, to, cp, reason, modifiers); p2.x = 0.5*(endpoints[0].x + endpoints[1].x); p2.y = 0.5*(endpoints[0].y + endpoints[1].y); point_sub(&p2, &p1); point_add(&mbr->pm, &p2); } mbr_update_data(mbr); return NULL; }
static void zigzagline_update_data(Zigzagline *zigzagline) { OrthConn *orth = &zigzagline->orth; DiaObject *obj = &orth->object; PolyBBExtras *extra = &orth->extra_spacing; orthconn_update_data(&zigzagline->orth); extra->start_long = extra->end_long = extra->middle_trans = extra->start_trans = extra->end_trans = (zigzagline->line_width / 2.0); orthconn_update_boundingbox(orth); if (zigzagline->start_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; Point to = orth->points[0]; Point from = orth->points[1]; calculate_arrow_point(&zigzagline->start_arrow, &to, &from, &move_arrow, &move_line, zigzagline->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox (&zigzagline->start_arrow, zigzagline->line_width, &to, &from, &bbox); rectangle_union (&obj->bounding_box, &bbox); } if (zigzagline->end_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; int n = orth->numpoints; Point to = orth->points[n-1]; Point from = orth->points[n-2]; calculate_arrow_point(&zigzagline->end_arrow, &to, &from, &move_arrow, &move_line, zigzagline->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox (&zigzagline->end_arrow, zigzagline->line_width, &to, &from, &bbox); rectangle_union (&obj->bounding_box, &bbox); } }
static void modify_button_press(ModifyTool *tool, GdkEventButton *event, DDisplay *ddisp) { Point clickedpoint; DiaObject *clicked_obj; gboolean some_selected; ddisplay_untransform_coords(ddisp, (int)event->x, (int)event->y, &clickedpoint.x, &clickedpoint.y); /* don't got to single handle movement if there is more than one object selected */ some_selected = g_list_length (ddisp->diagram->data->selected) > 1; if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event)) return; clicked_obj = click_select_object(ddisp, &clickedpoint, event); if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event)) return; if ( clicked_obj != NULL ) { tool->state = STATE_MOVE_OBJECT; tool->object = clicked_obj; tool->move_compensate = clicked_obj->position; point_sub(&tool->move_compensate, &clickedpoint); tool->break_connections = TRUE; /* unconnect when not grabbing handles, just setting to * FALSE is not enough. Need to refine the move op, too. */ gdk_pointer_grab (gtk_widget_get_window(ddisp->canvas), FALSE, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, NULL, event->time); tool->start_at = clickedpoint; tool->start_time = time_micro(); ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL)); } else { tool->state = STATE_BOX_SELECT; tool->start_box = clickedpoint; tool->end_box = clickedpoint; tool->x1 = tool->x2 = (int) event->x; tool->y1 = tool->y2 = (int) event->y; if (tool->gc == NULL) { tool->gc = gdk_gc_new(gtk_widget_get_window(ddisp->canvas)); gdk_gc_set_line_attributes(tool->gc, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER); gdk_gc_set_foreground(tool->gc, &color_gdk_white); gdk_gc_set_function(tool->gc, GDK_XOR); } gdk_draw_rectangle (gtk_widget_get_window (ddisp->canvas), tool->gc, FALSE, tool->x1, tool->y1, tool->x2 - tool->x1, tool->y2 - tool->y1); gdk_pointer_grab (gtk_widget_get_window (ddisp->canvas), FALSE, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, NULL, event->time); } }
/* * This function estimates the distance from a point to a line segment * specified by two endpoints. * If the point is on the line segment, 0.0 is returned. Otherwise the * distance in the R^2 metric from the point to the nearest point * on the line segment is returned. Does one sqrt per call. * Philosophical bug: line_width is ignored iff point is beyond * end of line segment. */ real distance_line_point(Point *line_start, Point *line_end, real line_width, Point *point) { Point v1, v2; real v1_lensq; real projlen; real perp_dist; v1 = *line_end; point_sub(&v1,line_start); v2 = *point; point_sub(&v2, line_start); v1_lensq = point_dot(&v1,&v1); if (v1_lensq<0.000001) { return sqrt(point_dot(&v2,&v2)); } projlen = point_dot(&v1,&v2) / v1_lensq; if (projlen<0.0) { return sqrt(point_dot(&v2,&v2)); } if (projlen>1.0) { Point v3 = *point; point_sub(&v3,line_end); return sqrt(point_dot(&v3,&v3)); } point_scale(&v1, projlen); point_sub(&v1, &v2); perp_dist = sqrt(point_dot(&v1,&v1)); perp_dist -= line_width / 2.0; if (perp_dist < 0.0) { perp_dist = 0.0; } return perp_dist; }
static void implements_update_data(Implements *implements) { Connection *conn = &implements->connection; Object *obj = (Object *) implements; Point delta; Point point; real len; Rectangle rect; obj->position = conn->endpoints[0]; implements->text_handle.pos = implements->text_pos; /* circle handle/center pos: */ delta = conn->endpoints[0]; point_sub(&delta, &conn->endpoints[1]); len = sqrt(point_dot(&delta, &delta)); delta.x /= len; delta.y /= len; point = delta; point_scale(&point, implements->circle_diameter); point_add(&point, &conn->endpoints[1]); implements->circle_handle.pos = point; point = delta; point_scale(&point, implements->circle_diameter/2.0); point_add(&point, &conn->endpoints[1]); implements->circle_center = point; connection_update_handles(conn); /* Boundingbox: */ connection_update_boundingbox(conn); /* Add boundingbox for circle: */ rect.left = implements->circle_center.x - implements->circle_diameter/2.0; rect.right = implements->circle_center.x + implements->circle_diameter/2.0; rect.top = implements->circle_center.y - implements->circle_diameter/2.0; rect.bottom = implements->circle_center.y + implements->circle_diameter/2.0; rectangle_union(&obj->bounding_box, &rect); /* Add boundingbox for text: */ rect.left = implements->text_pos.x; rect.right = rect.left + implements->text_width; rect.top = implements->text_pos.y - font_ascent(implements_font, IMPLEMENTS_FONTHEIGHT); rect.bottom = rect.top + IMPLEMENTS_FONTHEIGHT; rectangle_union(&obj->bounding_box, &rect); /* fix boundingbox for implements_width: */ obj->bounding_box.top -= IMPLEMENTS_WIDTH/2; obj->bounding_box.left -= IMPLEMENTS_WIDTH/2; obj->bounding_box.bottom += IMPLEMENTS_WIDTH/2; obj->bounding_box.right += IMPLEMENTS_WIDTH/2; }
static void draw_tunnel(DiaRenderer *renderer, Point *end, Point *vect, Color *col) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point vv,vp,vt1,vt2; BezPoint curve1[2]; BezPoint curve2[2]; real vlen; vv = *end; point_sub(&vv,vect); vlen = distance_point_point(vect,end); if (vlen < 1E-7) return; point_scale(&vv,1/vlen); vp.y = vv.x; vp.x = -vv.y; curve1[0].type = curve2[0].type = BEZ_MOVE_TO; curve1[0].p1 = curve2[0].p1 = *end; vt1 = vv; point_scale(&vt1,-ARROW_PARENS_LOFFSET - (.5*ARROW_PARENS_LENGTH)); point_add(&curve1[0].p1,&vt1); point_add(&curve2[0].p1,&vt1); /* gcc, work for me, please. */ vt2 = vp; point_scale(&vt2,ARROW_PARENS_WOFFSET); point_add(&curve1[0].p1,&vt2); point_sub(&curve2[0].p1,&vt2); vt2 = vp; vt1 = vv; point_scale(&vt1,2.0*ARROW_PARENS_LENGTH / 6.0); point_scale(&vt2,ARROW_PARENS_LENGTH / 6.0); curve1[1].type = curve2[1].type = BEZ_CURVE_TO; curve1[1].p1 = curve1[0].p1; curve2[1].p1 = curve2[0].p1; point_add(&curve1[1].p1,&vt1); point_add(&curve2[1].p1,&vt1); point_add(&curve1[1].p1,&vt2); point_sub(&curve2[1].p1,&vt2); curve1[1].p2 = curve1[1].p1; curve2[1].p2 = curve2[1].p1; point_add(&curve1[1].p2,&vt1); point_add(&curve2[1].p2,&vt1); curve1[1].p3 = curve1[1].p2; curve2[1].p3 = curve2[1].p2; point_add(&curve1[1].p3,&vt1); point_add(&curve2[1].p3,&vt1); point_sub(&curve1[1].p3,&vt2); point_add(&curve2[1].p3,&vt2); renderer_ops->draw_bezier(renderer,curve1,2,col); renderer_ops->draw_bezier(renderer,curve2,2,col); }
void find4thPoint(vector<float>& p4, vector<float>& p1, vector<float>& p2, vector<float>& p3, float dist, float ang, float dihed) { vector<float> n1(3), n2(3), a(3), b(3); point_sub(a, p1,p2); point_sub(b, p3,p2); cross_product(n1, a,b); normalize_point(n1,n1); cross_product(n2, b,n1); normalize_point(n2,n2); double Sang = sin( DEGREES_TO_RADIANS(ang) ); double Cang = cos( DEGREES_TO_RADIANS(ang) ); double Sdihed = sin( DEGREES_TO_RADIANS(dihed) ); double Cdihed = cos( DEGREES_TO_RADIANS(dihed) ); normalize_point(b,b); //cout << point_string(b) << point_string(n1) << point_string(n2) << endl; linear_combination(p4, Sang*Cdihed, n2, -1*Cang, b); linear_combination(p4, -1*Sang*Sdihed, n1, 1, p4); //cout << point_string(p4) << endl; linear_combination(p4, dist, p4, 1, p3); }
static real arc_compute_curve_distance(const Arc *arc, const Point *start, const Point *end, const Point *mid) { Point a,b; real tmp,cd; b = *mid; point_sub(&b, start); a = *end; point_sub(&a, start); tmp = point_dot(&a,&b); cd = sqrt(fabs(point_dot(&b,&b) - tmp*tmp/point_dot(&a,&a))); if (a.x*b.y - a.y*b.x < 0) cd = - cd; return cd; }
static void constraint_move(Constraint *constraint, Point *to) { Point start_to_end; Point *endpoints = &constraint->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&constraint->text_pos, &delta); constraint_update_data(constraint); }
static void message_move(Message *message, Point *to) { Point start_to_end; Point *endpoints = &message->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&message->text_pos, &delta); message_update_data(message); }
static ObjectChange* lifeline_move(Lifeline *lifeline, Point *to) { Point start_to_end; Point delta; Point *endpoints = &lifeline->connection.endpoints[0]; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); lifeline_update_data(lifeline); return NULL; }
static void modify_button_press(ModifyTool *tool, GdkEventButton *event, DDisplay *ddisp) { Point clickedpoint; DiaObject *clicked_obj; gboolean some_selected; ddisplay_untransform_coords(ddisp, (int)event->x, (int)event->y, &clickedpoint.x, &clickedpoint.y); /* don't got to single handle movement if there is more than one object selected */ some_selected = g_list_length (ddisp->diagram->data->selected) > 1; if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event)) return; clicked_obj = click_select_object(ddisp, &clickedpoint, event); if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event)) return; if ( clicked_obj != NULL ) { tool->state = STATE_MOVE_OBJECT; tool->object = clicked_obj; tool->move_compensate = clicked_obj->position; point_sub(&tool->move_compensate, &clickedpoint); tool->break_connections = TRUE; /* unconnect when not grabbing handles, just setting to * FALSE is not enough. Need to refine the move op, too. */ gdk_pointer_grab (gtk_widget_get_window(ddisp->canvas), FALSE, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, NULL, event->time); tool->start_at = clickedpoint; tool->start_time = time_micro(); ddisplay_set_all_cursor_name (NULL, "move"); } else { tool->state = STATE_BOX_SELECT; tool->start_box = clickedpoint; tool->end_box = clickedpoint; tool->x1 = tool->x2 = (int) event->x; tool->y1 = tool->y2 = (int) event->y; dia_interactive_renderer_set_selection (ddisp->renderer, TRUE, tool->x1, tool->y1, tool->x2 - tool->x1, tool->y2 - tool->y1); ddisplay_flush (ddisp); gdk_pointer_grab (gtk_widget_get_window (ddisp->canvas), FALSE, GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, NULL, event->time); } }
static void implements_move(Implements *implements, Point *to) { Point start_to_end; Point delta; Point *endpoints = &implements->connection.endpoints[0]; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&implements->text_pos, &delta); implements_update_data(implements); }
static ObjectChange* mbr_move(Mbr *mbr, Point *to) { Point start_to_end; Point *endpoints = &mbr->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&mbr->pm, &delta); mbr_update_data(mbr); return NULL; }
static ObjectChange* link_move(Link *link, Point *to) { Point start_to_end; Point *endpoints = &link->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&link->pm, &delta); link_update_data(link); return NULL; }
static ObjectChange* transition_move_handle(Transition* transition, Handle* handle, Point* newpos, ConnectionPoint* cp, HandleMoveReason reason, ModifierKeys modifiers) { ObjectChange *change = NULL; assert(transition != NULL); assert(handle != NULL); assert(newpos != NULL); switch (handle->id) { case HANDLE_MOVE_TRIGGER_TEXT: /* The trigger text is being moved */ transition->trigger_text_pos = *newpos; break; case HANDLE_MOVE_GUARD_TEXT: /* The guard text is being moved */ transition->guard_text_pos = *newpos; break; default: { int n = transition->orth.numpoints/2; Point p1, p2; p1.x = 0.5 * (transition->orth.points[n-1].x + transition->orth.points[n].x); p1.y = 0.5 * (transition->orth.points[n-1].y + transition->orth.points[n].y); /* Tell the connection that one of its handles is being moved */ orthconn_move_handle(&transition->orth, handle, newpos, cp, reason, modifiers); /* with auto-routing the number of points may have changed */ n = transition->orth.numpoints/2; p2.x = 0.5 * (transition->orth.points[n-1].x + transition->orth.points[n].x); p2.y = 0.5 * (transition->orth.points[n-1].y + transition->orth.points[n].y); point_sub(&p2, &p1); point_add(&transition->trigger_text_pos, &p2); point_add(&transition->guard_text_pos, &p2); } break; } /* Update ourselves to reflect the new handle position */ uml_transition_update_data(transition); return change; }
/** Scroll display to have the diagram point p at the center. * Returns TRUE if anything changed. */ gboolean ddisplay_scroll_center_point(DDisplay *ddisp, Point *p) { Point center; g_return_val_if_fail (ddisp != NULL, FALSE); /* Find current center */ center.x = (ddisp->visible.right+ddisp->visible.left)/2; center.y = (ddisp->visible.top+ddisp->visible.bottom)/2; point_sub(p, ¢er); return ddisplay_scroll(ddisp, p); }
/* finds the point intersecting the full circle * on the vector defined by the center and Point *to * that point is returned in Point *best if 1 is returned */ static int arc_find_radial(const Arc *arc, const Point *to, Point *best) { Point tmp; tmp = *to; point_sub(&tmp, &arc->center); point_normalize(&tmp); point_scale(&tmp,arc->radius); point_add(&tmp, &arc->center); *best = tmp; return 1; }
static void rendobj_move(RenderObject *rend_obj, Point *to) { Point p; p = rend_obj->desc->move_position; rend_obj->element.corner = *to; point_scale(&p, rend_obj->magnify); point_sub(&rend_obj->element.corner, &p); rendobj_update_data(rend_obj); }
static ObjectChange* annotation_move(Annotation *annotation, Point *to) { Point start_to_end; Point *endpoints = &annotation->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&annotation->text->position, &delta); annotation_update_data(annotation); return NULL; }
static ObjectChange* step_move(Step *step, Point *to) { Point delta = *to; point_sub(&delta,&step->element.corner); step->element.corner = *to; point_add(&step->north.pos,&delta); point_add(&step->south.pos,&delta); step_update_data(step); return NULL; }
static ObjectChange* flow_move(Flow *flow, Point *to) { Point start_to_end; Point *endpoints = &flow->connection.endpoints[0]; Point delta; delta = *to; point_sub(&delta, &endpoints[0]); start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); point_add(&flow->textpos, &delta); flow_update_data(flow); return NULL; }
/** rotates p around the center by an angle given in radians * a positive angle is ccw on the screen*/ static void rotate_point_around_point(Point *p, const Point *center, real angle) { real radius; real a; point_sub(p,center); radius = point_len(p); a = -atan2(p->y,p->x); /* y axis points down*/ a += angle; p->x = cos(a); p->y = -sin(a);/* y axis points down*/ point_scale(p,radius); point_add(p,center); }
static void line_move(Line *line, Point *to) { Point start_to_end; Point *endpoints = &line->connection.endpoints[0]; start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); line_update_data(line); }
static void arc_move(Arc *arc, Point *to) { Point start_to_end; Point *endpoints = &arc->connection.endpoints[0]; start_to_end = endpoints[1]; point_sub(&start_to_end, &endpoints[0]); endpoints[1] = endpoints[0] = *to; point_add(&endpoints[1], &start_to_end); arc_update_data(arc); }
void polyconn_move(PolyConn *poly, Point *to) { Point p; int i; p = *to; point_sub(&p, &poly->points[0]); poly->points[0] = *to; for (i=1;i<poly->numpoints;i++) { point_add(&poly->points[i], &p); } }
static ObjectChange* annotation_move_handle(Annotation *annotation, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { Point p1, p2; Point *endpoints; Connection *conn = (Connection *)annotation; g_assert(annotation!=NULL); g_assert(handle!=NULL); g_assert(to!=NULL); if (handle->id == HANDLE_MOVE_TEXT) { annotation->text->position = *to; } else { endpoints = &(conn->endpoints[0]); if (handle->id == HANDLE_MOVE_STARTPOINT) { p1 = endpoints[0]; connection_move_handle(conn, handle->id, to, cp, reason, modifiers); p2 = endpoints[0]; point_sub(&p2, &p1); point_add(&annotation->text->position, &p2); point_add(&p2,&(endpoints[1])); connection_move_handle(conn, HANDLE_MOVE_ENDPOINT, &p2, NULL, reason, 0); } else { p1 = endpoints[1]; connection_move_handle(conn, handle->id, to, cp, reason, modifiers); p2 = endpoints[1]; point_sub(&p2, &p1); point_add(&annotation->text->position, &p2); } } annotation_update_data(annotation); return NULL; }