// Generate a list of valid groups for a button: disallowing already-used groups // and also ancestors of earlier buttons and descendants of later buttons. // "context" is the button to generate the list for. // Pass null for the Add Group button. private List <GroupingType> GetRemainingGroupTypes(Button context) { List <GroupingType> remainingGroupTypes = new List <GroupingType>(potentialGroups); foreach (GroupingType customField in customFields) { remainingGroupTypes.Add(customField); } // Remove group types which are not relevant to any of the things being searched for. foreach (GroupingType gt in remainingGroupTypes.ToArray()) { if (!WantGroupingType(gt)) { remainingGroupTypes.Remove(gt); } } int posRelativeToContext = -1; // -1 for before; 0 for context itself; +1 for after foreach (Button button in groups) { if (button == context) { posRelativeToContext = 0; } else if (posRelativeToContext == 0) { posRelativeToContext = 1; } GroupingType groupType = button.Tag as GroupingType; if (groupType == null) { continue; } // Remove the button type itself. remainingGroupTypes.Remove(groupType); // Also if we are still to the left of context, also remove ancestor types of this button; // conversely, if we are to the right of context, remove descendant types of this button. // Also having Folder on another button precludes all other choices. foreach (GroupingType gt in remainingGroupTypes.ToArray()) { if (posRelativeToContext == -1 && groupType.IsDescendantOf(gt) || posRelativeToContext == 1 && gt.IsDescendantOf(groupType) || posRelativeToContext != 0 && groupType is FolderGroupingType) { remainingGroupTypes.Remove(gt); } } } return(remainingGroupTypes); }
public override bool IsDescendantOf(GroupingType gt) { return(gt == parent || (parent != null && parent.IsDescendantOf(gt))); }
void button_MouseMove(object sender, MouseEventArgs e) { if (draggedButton == null) { return; } Point OnScreen = draggedButton.PointToScreen(e.Location); if (!dragging && Math.Abs(clickPoint.X - OnScreen.X) < 5) { return; } dragging = true; draggedButton.BringToFront(); // Now we need to figure out where to move it, // both on the screen and in the internal array of buttons. // We need to take into account which buttons we have dragged it past, // and which buttons it's allowed to pass given the grouping hierarchy. // Note that if buttons are already out of order (legacy configuration), // we don't force them back in order, but they can't get any worse. GroupingType draggedGroupType = draggedButton.Tag as GroupingType; int draggedButtonLeft = draggedButton.Left; int draggedButtonRight = draggedButton.Left + draggedButton.Width; int draggedButtonIndex = groups.IndexOf(draggedButton); int offset = 0; int leftBarrier = -1; int swapWith = -1; int rightBarrier = -1; Button[] groupsArray = groups.ToArray(); foreach (Button candidateButton in groupsArray) { GroupingType candidateGroupType = candidateButton.Tag as GroupingType; int candidateButtonMiddle = offset + (candidateButton.Width / 2); int candidateButtonIndex = groups.IndexOf(candidateButton); if (draggedGroupType != null && candidateGroupType != null) { if (candidateButtonIndex < draggedButtonIndex) { if (draggedGroupType.IsDescendantOf(candidateGroupType)) { leftBarrier = candidateButtonIndex; } } else if (candidateButtonIndex > draggedButtonIndex) { if (candidateGroupType.IsDescendantOf(draggedGroupType)) { rightBarrier = candidateButtonIndex; } } } if (swapWith == -1 && candidateButtonMiddle > draggedButtonLeft && candidateButtonMiddle < draggedButtonRight) { swapWith = candidateButtonIndex; } offset += candidateButton.Width + innerGutter; } Point InControl = PointToClient(OnScreen); int potentialLocation = InControl.X - dragOffset; bool movedLeft = (swapWith >= 0 && swapWith < draggedButtonIndex); bool movedRight = (swapWith >= 0 && swapWith > draggedButtonIndex); bool movedNeither = !movedLeft && !movedRight; if (movedRight || movedNeither) { int maxRight = 0; if (rightBarrier >= 0) { if (swapWith >= 0 && swapWith >= rightBarrier) { swapWith = rightBarrier - 1; } maxRight = groupsArray[rightBarrier].Left - draggedButton.Width - innerGutter; } else if (groupsArray.Length >= 2) { maxRight = groupsArray[groupsArray.Length - 2].Right + innerGutter; } if (potentialLocation > maxRight) { potentialLocation = maxRight; } } if (movedLeft || movedNeither) { int maxLeft = 0; if (leftBarrier >= 0) { if (swapWith >= 0 && swapWith <= leftBarrier) { swapWith = leftBarrier + 1; } maxLeft = groupsArray[leftBarrier].Right + innerGutter; } if (potentialLocation < maxLeft) { potentialLocation = maxLeft; } } draggedButton.Left = potentialLocation; if (swapWith >= 0 && swapWith != draggedButtonIndex) { groups.Remove(draggedButton); groups.Insert(swapWith, draggedButton); Setup(); } }