Questions on dragging link segments

The basic one is how can I know which handle on a link is being dragged by user.

In GoDiagram 2.5, user can drag orthogonal link segments (by unseen
resize handles) besides other standard visible handles to change link path.

In my development, I need to let user change the number of segments and
segment positions on a link by dragging one of the unseen and standard
resize handles.

So how can I know which unseen segment handle or standard handle is being dragged by user, so that I can dynamically add or remove segments from the link (by adding or removing points).

And also I don’t know to add the unseen segment handles on the
dynamically created segments and which HandleID should I use for all
these unseen and standard resize handles on a link. From my investigation, I know RelinkableFromHandle and RelinkableToHandle are used for the diamond shaped handles. But I don’t know what handle id should be used for other handles and how to add the unseen handle on a link segment.

It’ll be very helpful if Walter or any one else give me some ideas. Many thanks.

Which handle is being dragged is given by the “whichHandle” argument to your override of DoResize.
Deciding which handles to add, and what properties they have, is the responsibility of your override of AddSelectionHandles.
I see that the documentation is lacking for the parameters for GoLink.DoResize. It didn’t even inherit their descriptions from GoObject.DoResize. Nor does it give a link to the parent class’es description of the method. Here’s some improved documentation:

Parameters

view
the GoView whose GoToolResizing is calling this method
origRect
the original Bounds of the object, but probably not useful for links
newPoint
the PointF, in document coordinates, to which the resize handle is being dragged
whichHandle
The IGoHandle.HandleID of the handle being dragged. Possible values include:
  • GoObject.MiddleTop - movement of this handle near the FromPort is constrained to be in the vertical direction because this link is Orthogonal
  • GoObject.MiddleLeft - movement of this handle near the FromPort is constrained to be in the horizontal direction because this link is Orthogonal
  • GoObject.MiddleBottom - movement of this handle near the ToPort is constrained to be in the vertical direction because this link is Orthogonal
  • GoObject.MiddleRight - movement of this handle near the ToPort is constrained to be in the horizontal direction because this link is Orthogonal
  • GoObject.LastHandle + 1000000, or more - move both ends of the segment starting with the point whose index is the value minus GoObject.LastHandle minus 1000000, because Orthogonal and DraggableOrthogonalSegments are both true
  • GoObject.LastHandle or more - set the point whose index is the value minus GoObject.LastHandle
  • GoLink.RelinkableFromHandle - this case is normally handled by GoToolRelinking rather than by this method
  • GoLink.RelinkableToHandle - this case is normally handled by GoToolRelinking rather than by this method
  • GoObject.NoHandle - this case usually means that the GoHandle should not be dragged
evttype
  • GoInputState.Start - when called from Start
  • GoInputState.Continue - when called from DoMouseMove
  • GoInputState.Finish - when called from DoMouseUp
  • GoInputState.Cancel - when the DoCancelMouse
min
the value of GoToolResizing.MinimumSize, but probably not useful for links
max
the value of GoToolResizing.MaximumSize, but probably not useful for links

Regarding what you want to do, one possibility is that you implement an override of DoResize just to add a segment (or two if Orthogonal) when view.LastInput.Control is true. Although I haven’t tried this yet, I believe it will be easy to implement and intuitive for the user, where she is used to using a Control-drag to mean “copy”.
Alternatively, assuming GoLink.DraggableOrthogonalSegments is not relevant, you could always add some small resize handles in the middle of each segment. (Hmmm, GoStrokeStyle.Bezier style strokes would require some more work. Again, I haven’t actually tried this either.) You would override AddSelectionHandles to call the base method and then add the additional resize handles, perhaps with HandleID == LastHandle + index + 1000000. You would also override DoResize to recognize when the “whichHandle” argument was >= LastHandle + 1000000, and call InsertPoint. Hmmm, you’ll then need to know that you have already inserted a point/segment and not do it again when your DoResize method is called again with the original resize handle.

Thank you very much. This is of great help to me. Actually I was trying to catch the handle being dragged in a derived GoToolDragging class.
Overriding DoResize will make my work much easier.

I add or remove points when evttyp == Finish.

To make all segments draggable, I played a small trick.
First I moved the diamond handle to the first and last point on the link, which was I needed. They originally are on the second (to last ) point on the link.

Then in the places the original diamond handles should be, I added two same points (overlapped). When the segment dragged away, another overlapped point was added.

OK, this was another fun thing to try. I implemented my second suggestion.
The following code assumes the link is not Orthogonal and that ResizesRealtime is true (which it is by default).
I also added code to automatically remove segments if moving a vertex caused both adjacent segments to make a straight line or close to it.
public override void AddSelectionHandles(GoSelection sel, GoObject selectedObj) {
base.AddSelectionHandles(sel, selectedObj);
GoView view = sel.View;
bool canresize = CanResize() && (view == null || view.CanResizeObjects());
bool canreshape = CanReshape() && (view == null || view.CanReshapeObjects());
if (canresize && canreshape && !this.Orthogonal && this.ResizesRealtime) {
// for each point, create an extra handle in the middle of each segment
for (int i = this.FirstPickIndex; i < this.LastPickIndex; i++) {
PointF a = GetPoint(i);
PointF b = GetPoint(i+1);
PointF p = new PointF((a.X+b.X)/2, (a.Y+b.Y)/2);
GoHandle h = sel.CreateResizeHandle(this, selectedObj, p, LastHandle + 2000000 + i, true) as GoHandle;
if (h != null) { // make handle smaller than the default for this view
h.Size = new SizeF(sel.View.ResizeHandleWidth2/3, sel.View.ResizeHandleHeight2/3);
h.Center = p;
}
}
}
}
public override void DoResize(GoView view, RectangleF origRect, PointF newPoint, int whichHandle, GoInputState evttype, SizeF min, SizeF max) {
if (whichHandle < LastHandle + 2000000) {
base.DoResize(view, origRect, newPoint, whichHandle, evttype, min, max);
// maybe remove a point if it results in two consecutive segments in an almost straight line
int i = whichHandle - LastHandle;
if (evttype == GoInputState.Finish && i > 0 && i < this.PointsCount-1) {
PointF a = GetPoint(i-1);
PointF b = GetPoint(i);
PointF c = GetPoint(i+1);
PointF q; // the closest point to B on the line between A and C
bool between = GoStroke.NearestPointOnLine(a, c, b, out q);
// if B is within 3 units of the line from A to C, and if Q is between A and C,
// remove that point from the stroke
if (between && ((q.X-b.X)(q.X-b.X) + (q.Y-b.Y)(q.Y-b.Y)) < this.PickMargin*this.PickMargin) {
RemovePoint(i);
}
}
} else {
// this code assumes !this.Orthogonal and this.ResizesRealtime, enforced in AddSelectionHandles
// insert the point in the stroke AFTER the point index given by whichHandle
int i = whichHandle - LastHandle - 2000000 + 1;
if (evttype == GoInputState.Start)
InsertPoint(i, newPoint);
else if (evttype == GoInputState.Cancel)
RemovePoint(i);
else
SetPoint(i, newPoint);
}
}

Hi. I’m interested to hear if you have tried this, and if you found this is one way to satisfy your requirements.

Because in my application only Orthogonal link can be used, I haven’t tried your code. Actually I’ve been being busy with many other issues in my development. Some of these issues are about GoDiagram, just because out clients need some special features that are not straight in GoDiagram. I will put some of these issues in another new post.

Anyhow, thank you very much for your effects to help me.

<span style=“font-size: 12pt; line-height: 150%; font-family: “Times New Roman”;”>

Hi Walter, Thanks you so much for the code it worked out for me. :)