#include "FractoriumPch.h" #include "LibraryTreeWidget.h" #include "Fractorium.h" /// /// Set a pointer to the main window. /// /// Pointer to the main Fractorium object void LibraryTreeWidget::SetMainWindow(Fractorium* f) { m_Fractorium = f; } /// /// Process the drop event to allow for moving items around inside of the tree. /// /// Pointer to the QDropEvent object void LibraryTreeWidget::dropEvent(QDropEvent* de) { const auto droppedIndex = indexAt(de->pos()); const auto items = selectionModel()->selectedRows(); if (!droppedIndex.isValid())//Don't process drop because it's outside of the droppable area. { de->ignore(); return; } else if (!items.empty())//Actually do the drop and move the item to a new location. { // get the list of the items that are about to be dragged int i, row = droppedIndex.row(); DropIndicatorPosition dp = dropIndicatorPosition(); QList dragItems = selectedItems(); if (dp == QAbstractItemView::BelowItem) row++; const auto itemat = this->itemFromIndex(droppedIndex); QTreeWidget::dropEvent(de);//This internally changes the order of the items. //Qt has a long standing major bug that rearranges the order of disjoint selections when //The drop location is in between the disjoint regions. //This is an attempt to correct for that bug by removing the dropped items, then re-inserting them //in the order they were selected. //This bug remains present as of Qt 5.8: https://bugreports.qt.io/browse/QTBUG-45320 if (const auto top = topLevelItem(0)) { if (itemat) { const auto offsetitem = this->indexFromItem(itemat); if (dp == QAbstractItemView::BelowItem) { const auto itemrow = offsetitem.row() + 1; for (i = 0; i < dragItems.size(); i++) { if (itemrow < top->childCount()) top->takeChild(itemrow); } for (i = 0; i < dragItems.size(); i++) { const auto offset = i + itemrow; if (offset <= top->childCount()) top->insertChild(offset, dragItems[i]); } } else { const auto itemrow = offsetitem.row();//Will be at least 1 if dropped above it. auto offset = itemrow; for (i = 0; i < dragItems.size() && offset > 0; i++) { offset--; if (offset < top->childCount()) top->takeChild(offset); } for (i = 0; i < dragItems.size(); i++) { if (offset <= top->childCount()) top->insertChild(offset, dragItems[i]); offset++; } } } } m_Fractorium->m_Controller->MoveLibraryItems(items, row); } } /// /// Set a pointer to the main window. /// /// Pointer to the main Fractorium object void InfoTreeWidget::SetMainWindow(Fractorium* f) { m_Fractorium = f; } /// /// Called on each mouse movement while dragging, validate whether the area /// being dragged over can be dropped on. /// Can only drop on like (pre/reg/post) variation section of the same xform /// of the variation being dragged. /// /// Pointer to the drag move event void InfoTreeWidget::dragMoveEvent(QDragMoveEvent* dme) { QModelIndex index = indexAt(dme->pos()); if (!index.isValid())//Don't process drop because it's outside of the droppable area. { dme->ignore(); return; } QList dragItems = selectedItems(); if (dragItems.size()) { auto drag0 = dragItems[0]; if (auto itemat = itemFromIndex(index)) { auto dragpre = drag0->text(0).startsWith("pre_", Qt::CaseInsensitive); auto droppre = itemat->text(0).startsWith("pre_", Qt::CaseInsensitive); auto dragpost = drag0->text(0).startsWith("post_", Qt::CaseInsensitive); auto droppost = itemat->text(0).startsWith("post_", Qt::CaseInsensitive); if (auto par = itemat->parent()) { if (drag0->parent() == par && (par->text(0).startsWith("xform ", Qt::CaseInsensitive) || par->text(0).startsWith("final", Qt::CaseInsensitive))) { if (auto vitemat = dynamic_cast(itemat)) { bool dopre = dragpre && droppre; bool dopost = dragpost && droppost; bool doreg = !dragpre && !droppre && !dragpost && !droppost; if (dopre || doreg || dopost) { QTreeWidget::dragMoveEvent(dme); return; } } } } } } dme->ignore(); } /// /// Process the drop event to allow for moving items around inside of the tree. /// This will only allow variations to be moved around within the variation section of the tree /// and nowhere else. /// /// Pointer to the QDropEvent object void InfoTreeWidget::dropEvent(QDropEvent* de) { QModelIndex droppedIndex = indexAt(de->pos()); auto items = selectionModel()->selectedRows(); if (!droppedIndex.isValid())//Don't process drop because it's outside of the droppable area. { de->ignore(); return; } else if (!items.empty())//Actually do the drop and move the item to a new location. { QList dragItems = selectedItems(); if (dragItems.size()) { auto drag0 = dragItems[0]; auto itemat = itemFromIndex(droppedIndex); if (auto par = itemat->parent()) { if (auto vdropitem = dynamic_cast(itemat)) { if (auto vdragitem = dynamic_cast(drag0)) { QTreeWidget::dropEvent(de);//This internally changes the order of the items. m_Fractorium->ReorderVariations(par); return; } } } } de->ignore(); } }