How to drag selection out of group?

Hello,

I am a Happy GoDiagram user an now I am prototyping a state machine editor with GoXam.



Each state is a group (can contain states). I must be able to drag a selection (several states and transitions) out of a group and drop the selection on the diagram or inside another state.



For example alt-Drag a selection must give the source group a red color to show the user is dragging the selection out of group and give the target group a green color to show the user is dropping inside this group.



Could you please give me some directions (samples, snippets, etc) to study ?



Thanks



Sbisa

The Planogram sample demonstrates what you want.

However, it doesn’t include any links. And it is probably more complicated than you need because it supports two different kinds of groups (“Racks” and “Shelves”) with different kinds of behaviors. And the sample of course includes controls for things that you probably don’t want users to modify, such as the grid cell size, frequency, or color.

Thanks Walter,

Looking at the Sample and reading the “Groups as Independent Containers” section of the GoXamIntro helped me a lot.



So, to choose if children nodes must be moved inside the group or dragged out the group I must change the value of the ‘SurroundsMembersAfterDrop’ field of the Group’s GroupPanel.



Now as a GoXam newbie, I am looking for an elegant way to set the SurroundsMembersAfterDrop to True when the user performs an ALT-Drag operation.



Some advises ?



Thanks



SBisa

It sounds like you want to customize the DraggingTool.

It would be easy except that you need to handle the case(s) where the user presses or releases the ALT key during drag, perhaps repeatedly.

And you need to handle the case where the drag is cancelled.

So you might want to add a property that is a HashSet of the Groups for which you have changed the Group.SurroundsMembersAfterDrop property.

And add a property so that you know whether you have updated those Groups, so that you won’t do it on every mouse move event, but only when the ALT key changes state. Use the DiagramTool.IsAltKeyDown() predicate.

Override DraggingTool.DragOver to call the base method and then check whether you need to update all of the Groups in the HashSet. If the HashSet doesn’t exist yet, you can create it and initialize it by looking at all of the Parts that are in either DraggingTool.DraggedParts or CopiedParts, depending on whether the tool is moving or copying.

Override DraggingTool.DoStop to reset all of the Groups and remove the HashSet.

Thank you so much Walter, it is exactly what I call an elegant solution.



My implementation :



public class CustomDraggingTool : DraggingTool

{

private HashSet m_AltDragOriginGroups = null;

private bool m_OriginGroupsInAltDragMode = false;



protected override void DragOver(Point pt, bool moving, bool copying)

{

base.DragOver(pt, moving, copying);



// If drag origin group set does not exist, create and populate it

if (m_AltDragOriginGroups == null)

{

m_AltDragOriginGroups = new HashSet();



foreach (Part l_DraggedPart in DraggedParts.Keys)

{

if (l_DraggedPart.ContainingSubGraph != null)

{

m_AltDragOriginGroups.Add(l_DraggedPart.ContainingSubGraph);

}

}

}



// According to Alt key state, set groups property to enable/disable drag out of group

bool l_AltKeyIsDown = IsAltKeyDown();

if (l_AltKeyIsDown != m_OriginGroupsInAltDragMode)

{

m_OriginGroupsInAltDragMode = l_AltKeyIsDown;

foreach (Group l_Group in m_AltDragOriginGroups)

{

l_Group.GroupPanel.SurroundsMembersAfterDrop = l_AltKeyIsDown;

}

}

}



public override void DoStop()

{

base.DoStop();



// Drag done or canceled, set all groups to original state and delete set

foreach (Group l_Group in m_AltDragOriginGroups)

{

l_Group.GroupPanel.SurroundsMembersAfterDrop = false;

}

m_AltDragOriginGroups = null;

m_OriginGroupsInAltDragMode = false;



}

}



One more thing. After changing Alt key state, I must move the mouse to change the state of groups. It will be cool to have an event notifying the DraggingTool that the Alt key state is changed instead of polling in DragOver. Some way to do that ?



Well, the obvious solution is to override DoKeyDown and DoKeyUp, and if the ALT key has changed state, call DoMouseMove. (Or maybe call DragOver directly?)

But the ALT key is somewhat special, so this might not work. And it probably works differently on WPF (because of commands) than on Silverlight. I don’t even know which platform you are targeting.

I use WPF platform.



My implementation :



public class CustomDraggingTool : DraggingTool

{

private HashSet m_AltDragOriginGroups = null;

private bool m_OriginGroupsInAltDragMode = false;



protected override void DragOver(Point pt, bool moving, bool copying)

{

base.DragOver(pt, moving, copying);



// If drag origin group set does not exist, create and populate it

if (m_AltDragOriginGroups == null)

{

m_AltDragOriginGroups = new HashSet();



foreach (Part l_DraggedPart in DraggedParts.Keys)

{

if (l_DraggedPart.ContainingSubGraph != null)

{

m_AltDragOriginGroups.Add(l_DraggedPart.ContainingSubGraph);

}

}

}

}



public override void DoStop()

{

base.DoStop();



// Drag done or canceled, set all groups to original state and delete set

foreach (Group l_Group in m_AltDragOriginGroups)

{

l_Group.GroupPanel.SurroundsMembersAfterDrop = false;

}

m_AltDragOriginGroups = null;

m_OriginGroupsInAltDragMode = false;

}



private void ChangeAltDragOriginGroupsMode (bool altKeyDown)

{

// According to Alt key state, set groups property to enable/disable drag out of group

if (altKeyDown != m_OriginGroupsInAltDragMode)

{

m_OriginGroupsInAltDragMode = altKeyDown;

foreach (Group l_Group in m_AltDragOriginGroups)

{

l_Group.GroupPanel.SurroundsMembersAfterDrop = altKeyDown;

}

}

}



public override void DoKeyDown(KeyEventArgs e)

{

base.DoKeyDown(e);

if (e.SystemKey == Key.RightAlt || e.SystemKey == Key.LeftAlt)

{

Console.Out.WriteLine(“Alt Down”);

ChangeAltDragOriginGroupsMode(true);

}

}



public override void DoKeyUp(KeyEventArgs e)

{

base.DoKeyUp(e);

if (e.SystemKey == Key.RightAlt || e.SystemKey == Key.LeftAlt)

{

Console.Out.WriteLine(“Alt Up”);

ChangeAltDragOriginGroupsMode(false);

}

}

}



No, in fact there is still a problem: even receiving Alt Key events and changing Origin Groups mode, the visual effect of changing the mode is not effective until the mouse move. I will ingestigate…



Thanks for help and good week-end



Ah, without the member nodes moving (or changing size), the containing GroupPanel’s size won’t be updated.

So try calling InvalidateMeasure() on the GroupPanel after you change the value of GroupPanel.SurroundsMembersAfterDrop.

This seems like a bug that we can fix for v1.2.

Yes! It works :



private void ChangeAltDragOriginGroupsMode (bool altKeyDown)

{

// According to Alt key state, set groups property to enable/disable drag out of group

if (altKeyDown != m_OriginGroupsInAltDragMode)

{

m_OriginGroupsInAltDragMode = altKeyDown;

foreach (Group l_Group in m_AltDragOriginGroups)

{

l_Group.GroupPanel.SurroundsMembersAfterDrop = altKeyDown;

l_Group.GroupPanel.InvalidateMeasure(); <—

}

}

}



Ok, I think we are done for this Topic



Thanks!

From version V1.2.24 remove the



l_Group.GroupPanel.InvalidateMeasure();



line to have a correct behavior.