diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-05-17 14:48:10 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2018-05-18 10:03:12 +0000 |
commit | fd479ad9ead764461f4dc44e0e40ecd277d8b1a4 (patch) | |
tree | f1b702d0fe144e32af1b6ed34b6a687cdbdd230e /src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp | |
parent | f03ae7fbc3dc5ad1ddd8bba0e56c5b556160628b (diff) |
Drag move and selection improvements
- Allow moving multiselection
- Disallow multiselection of layers, materials, scripts, and effects
- Disallow moving materials at all
- Disallow moving a single row so that it's place doesn't change
- When dragging from external palette, show rowmover only when drop
is valid.
Task-number: QT3DS-1526
Task-number: QT3DS-1675
Change-Id: Iccdfbdeac4aeea07659e21cee9b36dc152ff48da
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp')
-rw-r--r-- | src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp | 174 |
1 files changed, 91 insertions, 83 deletions
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp index c13b237f..e8f824f6 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp @@ -68,6 +68,11 @@ RowTree *RowMover::insertionParent() const return m_insertionParent; } +QVector<RowTree *> RowMover::sourceRows() const +{ + return m_sourceRows; +} + void RowMover::resetInsertionParent(RowTree *newParent) { if (m_insertionParent) { @@ -83,24 +88,34 @@ void RowMover::resetInsertionParent(RowTree *newParent) } } -RowTree *RowMover::sourceRow() const -{ - return m_sourceRow; -} - bool RowMover::isActive() { return m_active; } -void RowMover::start(RowTree *row) +void RowMover::start(const QVector<RowTree *> &rows) { - m_active = true; - - if (row) { - m_sourceRow = row; - m_sourceRow->setMoveSourceRecursive(true); - qApp->setOverrideCursor(Qt::ClosedHandCursor); + m_sourceRows.clear(); + if (!rows.isEmpty()) { + // Remove rows that have an ancestor included in the selection or ones that are of + // invalid type for moving + for (auto candidateRow : rows) { + bool omit = !candidateRow->draggable(); + if (!omit) { + for (auto checkRow : rows) { + if (candidateRow->isDecendentOf(checkRow)) + omit = true; + } + if (!omit) + m_sourceRows.append(candidateRow); + } + } + if (!m_sourceRows.isEmpty()) { + m_active = true; + for (auto row : qAsConst(m_sourceRows)) + row->setMoveSourceRecursive(true); + qApp->setOverrideCursor(Qt::ClosedHandCursor); + } } } @@ -108,10 +123,9 @@ void RowMover::end(bool force) { if (m_active || force) { m_active = false; - if (m_sourceRow) { - m_sourceRow->setMoveSourceRecursive(false); - m_sourceRow = nullptr; - } + for (auto row : qAsConst(m_sourceRows)) + row->setMoveSourceRecursive(false); + m_sourceRows.clear(); setVisible(false); resetInsertionParent(); @@ -141,26 +155,20 @@ RowTree *RowMover::getRowAtPos(const QPointF &scenePos) return nullptr; } -void RowMover::updateTargetRow(const QPointF &scenePos) +// rowType parameter is used to highlight the target row when RowMover is not active, +// i.e. when dragging from project or basic objects palettes +void RowMover::updateTargetRow(const QPointF &scenePos, EStudioObjectType rowType) { + EStudioObjectType theRowType = rowType; + if (theRowType == OBJTYPE_UNKNOWN && m_sourceRows.size() == 1) + theRowType = m_sourceRows[0]->rowType(); + // row will be inserted just below rowInsert1 and just above rowInsert2 (if it exists) RowTree *rowInsert1 = getRowAtPos(scenePos + QPointF(0, TimelineConstants::ROW_H * -.5)); RowTree *rowInsert2 = getRowAtPos(scenePos + QPointF(0, TimelineConstants::ROW_H * .5)); - bool valid = rowInsert1 - - // not moving an ancestor into a decendent - && (!m_sourceRow || !rowInsert1->isDecendentOf(m_sourceRow)) - - // not inserting as a first child of self - && (!m_sourceRow || !(rowInsert1 == m_sourceRow && !rowInsert1->empty())) - - // not inserting non-layer at root level - && !((!m_sourceRow || m_sourceRow->rowType() != OBJTYPE_LAYER) - && rowInsert1->rowType() == OBJTYPE_SCENE) - - // Layer cases - && validLayerMove(rowInsert1, rowInsert2); + bool valid = rowInsert1 && theRowType != OBJTYPE_MATERIAL + && theRowType != OBJTYPE_CUSTOMMATERIAL; if (valid) { // if dragging over a property or a parent of a property, move to the first row @@ -175,19 +183,17 @@ void RowMover::updateTargetRow(const QPointF &scenePos) // calc insertion depth int depth; - int depthMin = rowInsert2 ? rowInsert2->depth() : 3; + int depthMin = rowInsert2 ? rowInsert2->depth() : (theRowType == OBJTYPE_LAYER ? 2 : 3); int depthMax = rowInsert1->depth(); - if (rowInsert1->isContainer() && rowInsert1 != m_sourceRow) + if (rowInsert1->isContainer() && !m_sourceRows.contains(rowInsert1)) depthMax++; // Container: allow insertion as a child else if (rowInsert1->isPropertyOrMaterial() && !rowInsert1->parentRow()->isContainer()) depthMax--; // non-container with properties and/or a material - if (m_sourceRow && m_sourceRow->rowType() == OBJTYPE_LAYER) { + if (theRowType == OBJTYPE_LAYER) { depth = 2; // layers can only be moved on depth 2 - } else if (m_sourceRow && m_sourceRow->rowType() == OBJTYPE_EFFECT) { + } else if (theRowType == OBJTYPE_EFFECT) { depth = 3; // effects can only be moved on depth 3 (layer direct child) - } else if (m_sourceRow && m_sourceRow->rowType() == OBJTYPE_MATERIAL) { - depth = m_sourceRow->depth(); // materials cannot change parent } else { static const int LEFT_MARGIN = 20; depth = (scenePos.x() - LEFT_MARGIN) / TimelineConstants::ROW_DEPTH_STEP; @@ -201,41 +207,63 @@ void RowMover::updateTargetRow(const QPointF &scenePos) resetInsertionParent(insertParent); - if (depth < depthMin || depth > depthMax) + if (depth < depthMin || depth > depthMax + || (theRowType != OBJTYPE_UNKNOWN + && !CStudioObjectTypes::AcceptableParent(theRowType, + m_insertionParent->rowType()))) { valid = false; + } - if (m_sourceRow && m_sourceRow->rowType() == OBJTYPE_MATERIAL - && m_sourceRow->parentRow() != m_insertionParent) { - valid = false; // not moving a material row outside its parent + // Don't insert master slide object into non-master slide object + // or object under itself, or under unacceptable parent + for (auto sourceRow : qAsConst(m_sourceRows)) { + if ((sourceRow->isMaster() && sourceRow->rowType() != OBJTYPE_LAYER + && !m_insertionParent->isMaster()) + || m_insertionParent->isDecendentOf(sourceRow) + || m_insertionParent == sourceRow + || !CStudioObjectTypes::AcceptableParent(sourceRow->rowType(), + m_insertionParent->rowType())) { + valid = false; + break; + } } - if (m_sourceRow && m_sourceRow->isMaster() && !m_insertionParent->isMaster()) - valid = false; // don't insert master slide object into non-master slide object - - if (valid) { - // calc insertion target and type - if (rowInsert1 == m_insertionParent) { - if (m_insertionParent->expanded() && !m_insertionParent->childRows().empty()) { - m_insertionTarget = m_insertionParent->childRows().at(0); - m_insertType = Q3DStudio::DocumentEditorInsertType::PreviousSibling; - } else { - m_insertionTarget = m_insertionParent; - m_insertType = Q3DStudio::DocumentEditorInsertType::LastChild; - } - } else if (rowInsert1->isProperty() && depth == rowInsert1->depth()) { + // calc insertion target and type + if (rowInsert1 == m_insertionParent) { + if (m_insertionParent->expanded() && !m_insertionParent->childRows().empty()) { m_insertionTarget = m_insertionParent->childRows().at(0); m_insertType = Q3DStudio::DocumentEditorInsertType::PreviousSibling; } else { - m_insertionTarget = rowInsert1; - m_insertType = Q3DStudio::DocumentEditorInsertType::NextSibling; - if (depth < rowInsert1->depth()) { - for (int i = depth; i < rowInsert1->depth(); ++i) - m_insertionTarget = m_insertionTarget->parentRow(); - } + m_insertionTarget = m_insertionParent; + m_insertType = Q3DStudio::DocumentEditorInsertType::LastChild; } - - updateState(depth, rowInsert1->y() + TimelineConstants::ROW_H); + } else if (rowInsert1->isProperty() && depth == rowInsert1->depth()) { + if (m_insertionParent->childRows().isEmpty()) { + m_insertionTarget = m_insertionParent; + m_insertType = Q3DStudio::DocumentEditorInsertType::LastChild; + } else { + m_insertionTarget = m_insertionParent->childRows().at(0); + m_insertType = Q3DStudio::DocumentEditorInsertType::PreviousSibling; + } + } else { + m_insertionTarget = rowInsert1; + m_insertType = Q3DStudio::DocumentEditorInsertType::NextSibling; + if (depth < rowInsert1->depth()) { + for (int i = depth; i < rowInsert1->depth(); ++i) + m_insertionTarget = m_insertionTarget->parentRow(); + } + } + // Don't allow single move right next to moving row at same depth + if (m_sourceRows.size() == 1 + && (m_insertionTarget == m_sourceRows[0] + || ((m_insertType == Q3DStudio::DocumentEditorInsertType::NextSibling + && m_sourceRows[0]->index() - m_insertionTarget->index() == 1) + || (m_insertType == Q3DStudio::DocumentEditorInsertType::PreviousSibling + && m_insertionTarget->index() - m_sourceRows[0]->index() == 1)))) { + valid = false; } + if (valid) + updateState(depth, rowInsert1->y() + TimelineConstants::ROW_H); } if (!valid) { @@ -244,26 +272,6 @@ void RowMover::updateTargetRow(const QPointF &scenePos) } } -bool RowMover::validLayerMove(RowTree *rowAtIndex, RowTree *nextRowAtIndex) -{ - // we don't care about non-layers in this method - if (!m_sourceRow || m_sourceRow->rowType() != OBJTYPE_LAYER) - return true; - - if (rowAtIndex->rowType() == OBJTYPE_SCENE) - return true; - - if (rowAtIndex->rowType() == OBJTYPE_LAYER) - return rowAtIndex->empty() || !rowAtIndex->expanded(); - - if (!nextRowAtIndex || (nextRowAtIndex->depth() <= rowAtIndex->depth() - && nextRowAtIndex->depth() == 2)) { - return true; - } - - return false; -} - int RowMover::type() const { // Enable the use of qgraphicsitem_cast with this item. |