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:
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.