Page Index Toggle Pages: [1] 2  Send TopicPrint
Hot Topic (More than 10 Replies) Snapping the mouse preview (Read 8468 times)
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Snapping the mouse preview
Oct 9th, 2013 at 8:47am
Print Post  
Hi there Stoyan,

At the moment i've got 2 functions in my programm.

One for aligning nodes to another node which consists of this method:

Code
Select All
protected void AlignToNearestPoint(Point current, InteractionState ist)
        {
            if (ist.AdjustmentHandle == 8) // If the node is moved
            {
                var nearbyNode = Parent.GetNearestNode(current, 30, this);

                if (nearbyNode != null)
                {
                    /* If the nearest node has multiple points to connect to, the connection Points
                     * will be stored here and used later to calculate to which point to snap to.
                     */
                    Point[] targetPoints;

                    var bounds_nearby_node = nearbyNode.Bounds;
                    double x_coord = 0;
                    double y_coord = 0;

                    var bounds_this_node = this.Bounds;
                    double x_coord2 = 0;
                    double y_coord2 = 0;

                    double dx = 0;
                    double dy = 0;

                    if (nearbyNode is If_Shape)
                    {
                        // Calculate the point of the nearby node to connect to, default is bottom
                        x_coord = bounds_nearby_node.X + bounds_nearby_node.Width / 2;
                        y_coord = bounds_nearby_node.Bottom - bounds_nearby_node.Height / 90;
                        var targetPoint = new Point(x_coord, y_coord);

                        // Calculate the point of this node to connect to the nearby node
                        x_coord2 = bounds_this_node.X + bounds_this_node.Width / 2;
                        y_coord2 = bounds_this_node.Y;
                        var pointToSnap = new Point(x_coord2, y_coord2);

                        double then_x = bounds_nearby_node.X + bounds_nearby_node.Width / 1.43;
                        double then_y = bounds_nearby_node.Bottom - bounds_nearby_node.Height / 1.18;
                        Point then_statement = new Point(then_x, then_y);
                        double else_x = bounds_nearby_node.X + bounds_nearby_node.Width / 1.43;
                        double else_y = bounds_nearby_node.Bottom - bounds_nearby_node.Height / 2.3;
                        Point else_statement = new Point(else_x, else_y);
                        Point bottom = new Point(bounds_nearby_node.X + bounds_nearby_node.Width / 2,
                            bounds_nearby_node.Bottom - bounds_nearby_node.Height / 90);
                        double minDistance = double.MaxValue;
                        targetPoints = new Point[3] { then_statement, else_statement, bottom };

                        // Check the distance of each targetpoint and the pointToSnap for the closest point
                        foreach (var s in targetPoints)
                        {
                            // Calculate the distancen between the points
                            double distance_squared = (pointToSnap.X - s.X) * (pointToSnap.X - s.X) + (pointToSnap.Y - s.Y) * (pointToSnap.Y - s.Y);
                            double distance = Math.Sqrt(distance_squared); //Utilities.Distance(pointToSnap, s);
                            if (distance < minDistance)
                            {
                                minDistance = distance;
                                targetPoint = s;
                            }
                        }

                        // Calculate the distance of the two points
                        dx = targetPoint.X - pointToSnap.X;
                        dy = targetPoint.Y - pointToSnap.Y;

                        // Move this node by the calculated distance
                        bounds_this_node.Offset(dx, dy);
                        SetBounds(bounds_this_node, true, true);

                        // Lastly, set the connectednode of the nearest node to this node
                        BR_Shape nearby_Node = nearbyNode as BR_Shape;
                        nearby_Node.connected_node = this;
                    }
                    if (nearbyNode is Action_Shape)
                    {
                        // Calculate the point of the nearby node to connect to
                        x_coord = bounds_nearby_node.X + bounds_nearby_node.Width / 2;
                        y_coord = bounds_nearby_node.Bottom - bounds_nearby_node.Height / 90;
                        var targetPoint = new Point(x_coord, y_coord);

                        // Calculate the point of this node to connect to the nearby node
                        x_coord2 = bounds_this_node.X + bounds_this_node.Width / 2;
                        y_coord2 = bounds_this_node.Y;
                        var pointToSnap = new Point(x_coord2, y_coord2);

                        // Calculate the distance of the two points
                        dx = targetPoint.X - pointToSnap.X;
                        dy = targetPoint.Y - pointToSnap.Y;

                        // Move this node by the calculated distance
                        bounds_this_node.Offset(dx, dy);
                        SetBounds(bounds_this_node, true, true);

                        // Lastly, set the connectednode of the nearest node to this node
                        BR_Shape nearby_Node = nearbyNode as BR_Shape;
                        nearby_Node.connected_node = this;
                    }
                }
            }
        } 



And the second for having a drag and drop preview, which consists of 3 methods:

Code
Select All
        // This method is called when the cursor enters the corresponding window
        private void OnDiagramDragEnter(object sender, DragEventArgs e)
        {

            // The if statement checks if dragIndicator is empty and if there is a dragNode present
            if (dragIndicator == null && e.Data.GetDataPresent(typeof(DraggedNode)))
            {
                // var data gets present node that is dragable
                // var position gets the current position of the node that can be dragged
                var data = (DraggedNode)e.Data.GetData(typeof(DraggedNode));
                var position = e.GetPosition(this.DocumentPlane);


                dragIndicator = (BR_Shape)data.Node.Clone(false);
                dragIndicator.Move(position.X, position.Y); // Keeps track of the position
                dragIndicator.Opacity = 0.5; // Changes the opacity of the node so that it looks transparent
                this.Nodes.Add(dragIndicator); // Node is being added to the diagram - this = the diagram
                e.Effects = DragDropEffects.Copy;
                e.Handled = true;
            }
        }

        // This method is called when the cursor moves inside the cursor moves inside the corresponding window
        public void OnDiagramDragOver(object sender, DragEventArgs e)
        {
            BR_Shape snap = new BR_Shape();

            if (dragIndicator != null)
            {
                var position = e.GetPosition(this.DocumentPlane);
                dragIndicator.Move(position.X, position.Y);
                e.Effects = DragDropEffects.Copy;
                e.Handled = true;

            }
        }

        // Removes the contents of the dragIndicator, so it can be use again
        private void OnNodeCreated(object sender, NodeEventArgs e)
        {
            if (dragIndicator != null)
            {
                this.Nodes.Remove(dragIndicator);
                dragIndicator = null;
            }
        }
 



So, both function are working individually. The thing is, if i drag a node on to my Diagram field i want to be able to snap it directly instead of having to place it in the Diagram field and than to drag it to a different node to snap it.

Is there any way to do this?

Greets,

Sander
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #1 - Oct 9th, 2013 at 9:20am
Print Post  
Hi Sander,

Use an InteractionState object to (indirectly) call your nodes' UpdateModify method, which does the alignment.

Code
Select All
DiagramNode dragIndicator = null;
InteractionState dragInteraction = null;

private void OnDiagramDragEnter(object sender, DragEventArgs e)
{
	if (dragIndicator == null &&
		e.Data.GetDataPresent(typeof(DraggedNode)))
	{
		var data = (DraggedNode)e.Data.GetData(typeof(DraggedNode));
		var position = e.GetPosition(diagram.DocumentPlane);
		dragIndicator = (DiagramNode)data.Node.Clone(false);
		dragIndicator.Move(position.X, position.Y);
		dragInteraction = new InteractionState(dragIndicator, 8, Action.Modify);
		dragInteraction.Start(position, diagram);
		dragIndicator.Opacity = 0.5;
		diagram.Nodes.Add(dragIndicator);
		e.Effects = DragDropEffects.Copy;
		e.Handled = true;
	}
}

void OnDiagramDragOver(object sender, DragEventArgs e)
{
	if (dragIndicator != null)
	{
		var position = e.GetPosition(diagram.DocumentPlane);
		// no longer calling Move directly
		dragInteraction.Update(position, diagram);
		e.Effects = DragDropEffects.Copy;
		e.Handled = true;
	}
}

private void OnNodeCreated(object sender, NodeEventArgs e)
{
	// NodeListView creates an instance automatically, so remove the indicator
	if (dragIndicator != null)
	{
		e.Node.Bounds = dragIndicator.Bounds;
		diagram.Nodes.Remove(dragIndicator);
		dragIndicator = null;
	}
} 



I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #2 - Oct 9th, 2013 at 9:55am
Print Post  
Hi Stoyan,

Im getting a nullpointer exception at dragInteraction.Start(position, this);

Here is my current code, maybe I'm overlooking something. Btw, this is in the MC_Diagram : Diagram class.
Code
Select All
         private void OnDiagramDragEnter(object sender, DragEventArgs e)
        {

            present
            if (dragIndicator == null && e.Data.GetDataPresent(typeof(DraggedNode)))
            {

                var data = (DraggedNode)e.Data.GetData(typeof(DraggedNode));
                var position = e.GetPosition(this.DocumentPlane);


                dragIndicator = (BR_Shape)data.Node.Clone(false);
                dragIndicator.Move(position.X, position.Y); // Keeps track of the position

                dragInteraction = new InteractionState(dragIndicator, 8, MindFusion.Diagramming.Wpf.Action.Modify);
                dragInteraction.Start(position, this);

                dragIndicator.Opacity = 0.5;
                this.Nodes.Add(dragIndicator);
                e.Effects = DragDropEffects.Copy;
                e.Handled = true;
            }
        }


        public void OnDiagramDragOver(object sender, DragEventArgs e)
        {


            if (dragIndicator != null)
            {
                var position = e.GetPosition(this.DocumentPlane);
                dragInteraction.Update(position, this);

                //dragIndicator.Move(position.X, position.Y);
                e.Effects = DragDropEffects.Copy;
                e.Handled = true;

            }
        }


        private void OnNodeCreated(object sender, NodeEventArgs e)
        {
            if (dragIndicator != null)
            {
                e.Node.Bounds = dragIndicator.Bounds;
                this.Nodes.Remove(dragIndicator);
                dragIndicator = null;
            }
        } 



Greets,

Sander
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #3 - Oct 9th, 2013 at 11:12am
Print Post  
The node's StartModify code might be expecting that its parent diagram has already been set. Try moving the Nodes.Add(dragIndicator) call in front of interaction.Start.

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #4 - Oct 9th, 2013 at 11:20am
Print Post  
Hi Stoyan,

That fixed the NullPointerException, but now the next bug appeared ;p.

Instead of being able to align the node directly. Once i selected the desired node and dragged it on the Diagram field, it places a copy on the field where i drag it in (Didnt release my mousebutten) and it keeps a preview under the mouse which i can add aswell if i do release my mousebutton, so basically adding 2 nodes. But the node that is under my mouse doesnt align either.

Edit:

it does align, so only problem left is that it gives me 2 copies.

Greets,

Sander
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #5 - Oct 9th, 2013 at 11:28am
Print Post  
Hi,

You are getting one copy from the standard NodeListView drop handler, and one from the dragIndicator code in DragEnter. Are you calling Nodes.Remove(indicator) from NodeCreated handler as in the snippet above?

Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #6 - Oct 9th, 2013 at 11:36am
Print Post  
This is what i have.
Code
Select All
  private void OnNodeCreated(object sender, NodeEventArgs e)
        {
            if (dragIndicator != null)
            {
                e.Node.Bounds = dragIndicator.Bounds;
                this.Nodes.Remove(dragIndicator);
                dragIndicator = null;
            }
        }
 

  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #7 - Oct 9th, 2013 at 1:08pm
Print Post  
Also, according to my nodecounter, the 'Copy's' are not even there>.<

Code
Select All
private void get_current_nodes_in_diagram(object sender, RoutedEventArgs e)
        {
            int amount_of_nodes = 0;
            String description = "List of nodes:\n";
            foreach (ShapeNode sn in this.Nodes)
            {
                if (sn.GetType().ToString().Equals("MindFusion.Diagramming.Wpf.ShapeNode"))
                {
                    amount_of_nodes += 1;
                    description += amount_of_nodes + " : START\n";
                }
                else if (typeof(ShapeNode).IsAssignableFrom(typeof(BR_Shape)))
                {
                    BR_Shape brs = (BR_Shape)sn;
                    amount_of_nodes += 1;
                    description += amount_of_nodes + " : " + brs.type.ToString() + "\n";
                    if (brs.connected_node != null)
                        description += "    Connected node: " + brs.connected_node.type.ToString() + "\n";
                    else
                        description += "    Connected node: None\n";
                }
                else
                {
                    amount_of_nodes += 1;
                    description += amount_of_nodes + " : No specific type\n";                }

            }
            if (amount_of_nodes == 0)
                description += "No description";
            MessageBox.Show("Current amount of nodes in diagram:\n                                  " + amount_of_nodes.ToString() +
                "\n" + description);
        }  

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #8 - Oct 9th, 2013 at 2:14pm
Print Post  
I don't get any duplicates in my test project. See if you don't have duplicated Nodes.Add calls left after moving that line in front of Interaction.Start, or add breakpoints and see if the code is not executed twice for some reason.

Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #9 - Oct 9th, 2013 at 2:21pm
Print Post  
Hmm, checked for that, maybe its coming from somewhere else. I don't know. I couldn't find any duplicates in the code. Also tried it out in the project of somebody else, but he gets the exact same problem.

Code
Select All
         private void OnDiagramDragEnter(object sender, DragEventArgs e)
        {
            // The if statement checks if dragIndicator is empty and if there is a dragNode present
            if (dragIndicator == null && e.Data.GetDataPresent(typeof(DraggedNode)))
            {
                var data = (DraggedNode)e.Data.GetData(typeof(DraggedNode));
                var position = e.GetPosition(this.DocumentPlane);
                dragIndicator = (BR_Shape)data.Node.Clone(false);
                dragIndicator.Move(position.X, position.Y);
                e.Effects = DragDropEffects.Copy;
                this.Nodes.Add(dragIndicator); // Adds a copy !Problem?
                dragIndicator.Opacity = 0.5;
                dragInteraction = new InteractionState(dragIndicator, 8, MindFusion.Diagramming.Wpf.Action.Modify);
                dragInteraction.Start(position, this);
                e.Handled = true;
            }
        }
 

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #10 - Oct 9th, 2013 at 5:23pm
Print Post  
Add some debug logs to the beginning and end of all event handlers related to the drag operation, they should show where the second node is added:

Debug.WriteLine("OnDiagramDragEnter: start: " + diagram.Nodes.Count);
...
Debug.WriteLine("OnDiagramDragEnter: end: " + diagram.Nodes.Count);
...
Debug.WriteLine("OnDiagramDragOver: start: " + diagram.Nodes.Count);
...
Debug.WriteLine("OnDiagramDragOver: end: " + diagram.Nodes.Count);
...
NodeCreated, etc

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #11 - Oct 10th, 2013 at 8:43am
Print Post  
Hi Stoyan,

Here is my output on the case.

Code
Select All
OnDiagramDragEnter: Start:0
OnDiagramEnterMiddrag1: 0
OnDiagramEnterMiddrag2: 0 dragIndicator = (BR_Shape)data.Node.Clone(false);
OnDiagramEnterMiddrag3: 1
OnDiagramDragEnter: End:1
OnDiagramDragEnter: Start:1
Type:MindFusionDemo2.BR_Shapes.If_Shape
OnNodeCreated: Start:2
OnNodeCreated: End:1 



It keeps 1 node right from the start, but for some reason it has 2 nodes on creation and then it gets removed by 'Nodes.Remove(dragIndicator);' but it still shows 2 nodes on the diagramfield. It's really confusing. What's quite weird is that it calls the DragEnter method more than once.

My full code for the 3 methods:
Code
Select All
        private void OnDiagramDragEnter(object sender, DragEventArgs e)
        {
            Debug.WriteLine("OnDiagramDragEnter: Start:" + this.Nodes.Count);
            foreach (DiagramNode dn in this.Nodes)
            {
                Debug.WriteLine("Type:" + dn.GetType());
            }
            // The if statement checks if dragIndicator is empty and if there is a dragNode present
            if (dragIndicator == null && e.Data.GetDataPresent(typeof(DraggedNode)))
            {

                var data = (DraggedNode)e.Data.GetData(typeof(DraggedNode));
                var position = e.GetPosition(this.DocumentPlane);

                Debug.WriteLine("OnDiagramEnterMiddrag1: " + this.Nodes.Count);

                dragIndicator = (BR_Shape)data.Node.Clone(false);

                Debug.WriteLine("OnDiagramEnterMiddrag2: " + this.Nodes.Count + " dragIndicator = (BR_Shape)data.Node.Clone(false);");

                dragIndicator.Move(position.X, position.Y);
                e.Effects = DragDropEffects.Copy;
                this.Nodes.Add(dragIndicator); // Adds a copy !Problem?

                Debug.WriteLine("OnDiagramEnterMiddrag3: " + this.Nodes.Count);

                dragIndicator.Opacity = 0.5;

                dragInteraction = new InteractionState(dragIndicator, 8, MindFusion.Diagramming.Wpf.Action.Modify);
                dragInteraction.Start(position,  this);

                e.Handled = true;
                Debug.WriteLine("OnDiagramDragEnter: End:" + this.Nodes.Count);
            }
        }

        //     This method is called when the cursor moves inside the corresponding window
        public void OnDiagramDragOver(object sender, DragEventArgs e)
        {
            // Checks whether the dragindicator is filled with the data of the node that is being dragged
            if (dragIndicator != null)
            {
                Debug.WriteLine("OnDiagramDragOver: Start:" + this.Nodes.Count);
                var position = e.GetPosition(this.DocumentPlane);

                dragInteraction.Update(position, this);
                //dragIndicator.Move(position.X, position.Y);
                e.Effects = DragDropEffects.Copy;
                e.Handled = true;

                Debug.WriteLine("OnDiagramDragOver: End:" + this.Nodes.Count);

            }
        }

        // Removes the contents of the dragIndicator, so it can be use again if
        private void OnNodeCreated(object sender, NodeEventArgs e)
        {
            if (dragIndicator != null)
            {
                Debug.WriteLine("OnNodeCreated: Start:" + this.Nodes.Count);
                e.Node.Bounds = dragIndicator.Bounds;

                Nodes.Remove(dragIndicator);
                dragIndicator = null;
                Debug.WriteLine("OnNodeCreated: End:" + this.Nodes.Count);
            }
        }       



Maybe you can get any words of wisdow out of this bitch:P Cry

Greets and thanks,

Sander
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #12 - Oct 10th, 2013 at 10:44am
Print Post  
Here's our test project, please let me know what we should change to see the doubled nodes:
https://mindfusion.eu/_samples/DragIndicator.zip

Stoyan
  
Back to top
 
IP Logged
 
Waterfiets
Junior Member
**
Offline


I Love MindFusion!

Posts: 78
Joined: Sep 27th, 2013
Re: Snapping the mouse preview
Reply #13 - Oct 10th, 2013 at 12:26pm
Print Post  

Hi Stoyan,

After getting your testproject i couldn't find any real differences. So i thought lets place the eventhandlers of the events in the mainwindow just like you did, just for the lulz, and it seems to work perfectly. This seems a bit strange to me, cause the location shouldn't really matter if its an instance of the same class thats being used.

In the attachment you can find our testproject. Maybe you can figure it out, or maybe its a bug?

Greets,

Sander
  

DragDropExample_-_Copy.zip (Attachment deleted)
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Snapping the mouse preview
Reply #14 - Oct 11th, 2013 at 5:44am
Print Post  
Hi,

That happens because of ModificationEffect.MoveShades: the original node stays in place and there is a separate shape moved to represent the drop position, but then the shade is not removed if you don't also call dragInteraction.Complete(). You probably don't want to see the original dragIndicator staying in place anyway, so you could toggle the ModificationEffect property value instead:

Code
Select All
private void OnDiagramDragEnter(object sender, DragEventArgs e)
{
    Debug.WriteLine("OnDiagramDragEnter: start: " + this.Nodes.Count);
    if (dragIndicator == null &&
        e.Data.GetDataPresent(typeof(DraggedNode)))
    {
        this.ModificationEffect = ModificationEffect.None;
        ...

private void OnNodeCreated(object sender, NodeEventArgs e)
{
    if (dragIndicator != null)
    {
        this.ModificationEffect = ModificationEffect.MoveShades;
        ...
 



I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: [1] 2 
Send TopicPrint