TreeView DragAndDrop: a couple questions


#1

I have implemented a little “rule” container for some data sorting in a project I’m working on. It works well, but there are a couple things i can’t seem to figure out in the drag-and-drop part of re-ordering the rules.
Here’s a gif showing the action:
DragAndDrop

Question #1) I can’t seem to figure out the rules used to determine the “insertIndex” parameter passed to itemDropped, so if I drag the first item to between the 1st and 2nd item (as shown at the start of the gif playback) or before the first item (to index 0), I have to have a specialized handler to place the item. And if I drag the last item to the after the first element, it gets moved to before the first element.
here’s what I’m doing to re-order the rules, which are stored in an std::vector<FretboardSortingRule> rules

void FretboardSortingRules::itemDropped(const DragAndDropTarget::SourceDetails &dragSourceDetails, int insertIndex)
{
    auto rules = ruleProvider->getRules();
    auto& treeView = *getOwnerView();
    const int numSelected = treeView.getNumSelectedItems();
    
    for (int i = 0; i < numSelected; ++i)
    {
        if (const FretboardSortingRule* selectedRule = dynamic_cast<FretboardSortingRule*> (treeView.getSelectedItem (i)))
        {
            DBG( "\nyou dragged " << selectedRule->name );
            DBG( "old index: " << selectedRule->getIndexInParent() );
            DBG( "new index: " << insertIndex );
            
            auto matchingRule = std::find_if(rules.begin(),
                                             rules.end(),
                                             [&selectedRule](const FretboardSortingRule& t)
            {
                return t.name == selectedRule->name;
            }
                                             );
            if( matchingRule != rules.end() )
            {
                auto droppedRule = *matchingRule;
                rules.erase(matchingRule); //remove rule from list
                
                if( insertIndex == 0 )
                {
                    rules.insert(rules.begin(), droppedRule); 
                }
                else
                {
                    /*
                     this -1 is here because of a weird "behavior" in the DragAndDrop tree
                     you can drop a rule "above" the highest rule, and when that happens, the insertIndex is 0.
                     likewise, if you drop a rule after the first item (item[0]), the index is 1.
                     However, visually what is happening is you're dropping the item between the First and Second item, so the order is actually not changed.
                     
                     Rule 1 [0]
                                <--- Rule 1 [0] dropped here, so its index is + 1
                     Rule 2 [1]
                     
                     */
                    rules.insert(rules.begin() + insertIndex - 1, droppedRule);
                }
                ruleProvider->updateRules(rules);
                break;
            }
        }
    }
    
    refresh();
}

void FretboardSortingRules::refresh()
{
    clearSubItems();
    
    if( ruleProvider == nullptr )
    {
        jassertfalse; //should never happen
        return;
    }
    
    const auto& rules = ruleProvider->getRules();
    for( const auto& rule : rules )
    {
        addSubItem(new FretboardSortingRule(rule.name, rule.apply) );
    }
}

Is there some special setting in TreeView that I missed that does this ‘reorder-via-drag-and-drop’ behavior automatically and correctly? I have 5 items and there are 6 locations that I can drop them, when ideally, there should only be 4 locations; you shouldn’t be allowed to drop an item at its existing location.


#2

Is there a way to make the TreeView delete a node as soon as it is dragged so it only appears attached to the cursor, and not still a part of the tree? I haven’t seen anything in TreeView, TreeViewItem, or DragAndDropContainer that will do this. The idea is that when you drag one of the nodes in the tree, it stops being included in the tree until you drop it at a different index.

If I had to equate the action to what happens in a DAW when you drag a region, think of it like when you do the following sequence:

current TreeView drag behavior:
1) select region
2) press Option/Alt key and click-drag to copy the region to a new location
3) release the mouse cursor after dropping the region at the new location
4) select the original region.  press delete.

ideal TreeView behavior:
1) select region
2) drag region to new location

Is there a way to make the TreeView do that?