summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp')
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp451
1 files changed, 0 insertions, 451 deletions
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp
deleted file mode 100644
index 3e96f2dc..00000000
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp
+++ /dev/null
@@ -1,451 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt 3D Studio.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "RowMover.h"
-#include "RowTree.h"
-#include "RowManager.h"
-#include "TimelineGraphicsScene.h"
-#include "TimelineConstants.h"
-#include "StudioPreferences.h"
-
-#include <QtGui/qpainter.h>
-#include <QtWidgets/qapplication.h>
-#include <QtWidgets/qgraphicsitem.h>
-#include <QtWidgets/qgraphicslinearlayout.h>
-
-RowMover::RowMover(TimelineGraphicsScene *scene)
- : TimelineItem()
- , m_scene(scene)
-{
- setZValue(99);
- setGeometry(0, 0, TimelineConstants::TREE_MAX_W, 10);
-
- m_autoExpandTimer.setSingleShot(true);
- connect(&m_autoExpandTimer, &QTimer::timeout, [this]() {
- if (m_rowAutoExpand) {
- m_rowAutoExpand->updateExpandStatus(RowTree::ExpandState::Expanded, true);
- // Update RowMover after the expansion. The +50 below is just a small margin to ensure
- // correct row heights before updateTargetRowLater is called.
- QTimer::singleShot(TimelineConstants::EXPAND_ANIMATION_DURATION + 50, [this]() {
- if (updateTargetRowLater)
- updateTargetRowLater();
- });
- }
- });
-}
-
-void RowMover::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
-{
- Q_UNUSED(option)
- Q_UNUSED(widget)
-
- static const QPolygon polygon({QPoint(0, 0), QPoint(0, 3), QPoint(7, 3), QPoint(7, 1),
- QPoint(int(TimelineConstants::TREE_BOUND_W), 1),
- QPoint(int(TimelineConstants::TREE_BOUND_W), 0)});
- painter->setPen(QPen(CStudioPreferences::timelineRowMoverColor(), 1));
- painter->setBrush(CStudioPreferences::timelineRowMoverColor());
- painter->drawConvexPolygon(polygon);
-}
-
-RowTree *RowMover::insertionTarget() const
-{
- return m_insertionTarget.data();
-}
-
-RowTree *RowMover::insertionParent() const
-{
- return m_insertionParent;
-}
-
-QVector<RowTree *> RowMover::sourceRows() const
-{
- return m_sourceRows;
-}
-
-void RowMover::removeSourceRow(RowTree *row)
-{
- m_sourceRows.remove(m_sourceRows.indexOf(row));
-}
-
-bool RowMover::shouldDeleteAfterMove() const
-{
- return m_deleteAfterMove;
-}
-
-void RowMover::resetInsertionParent(RowTree *newParent)
-{
- if (m_insertionParent) {
- m_insertionParent->setDnDState(RowTree::DnDState::None, RowTree::DnDState::Parent);
- m_insertionParent = nullptr;
- }
-
- if (newParent) {
- m_insertionParent = newParent;
- m_insertionParent->setDnDState(RowTree::DnDState::Parent, RowTree::DnDState::None);
- } else {
- m_insertionTarget = nullptr;
- }
-}
-
-bool RowMover::isActive() const
-{
- return m_active;
-}
-
-void RowMover::start(const QVector<RowTree *> &rows)
-{
- m_deleteAfterMove = false;
- 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->setDnDState(RowTree::DnDState::Source, RowTree::DnDState::None, true);
- qApp->setOverrideCursor(Qt::ClosedHandCursor);
- }
- }
-}
-
-void RowMover::end(bool force)
-{
- if (m_active || force) {
- m_active = false;
- for (auto row : qAsConst(m_sourceRows))
- row->setDnDState(RowTree::DnDState::None, RowTree::DnDState::Any, true);
-
- m_sourceRows.clear();
-
- if (!m_insertionTarget.isNull())
- m_insertionTarget->setDnDState(RowTree::DnDState::None);
-
- setVisible(false);
- resetInsertionParent();
- updateTargetRowLater = {};
- qApp->changeOverrideCursor(Qt::ArrowCursor);
- qApp->restoreOverrideCursor();
-
- m_autoExpandTimer.stop();
- }
-}
-
-void RowMover::updateState(int depth, double y)
-{
- setPos(24 + depth * TimelineConstants::ROW_DEPTH_STEP, y);
- setVisible(true);
-}
-
-bool RowMover::isNextSiblingRow(RowTree *rowMain, RowTree *rowSibling) const
-{
- // order matters, rowSibling is below rowMain
- return rowMain->parentRow() == rowSibling->parentRow()
- && rowSibling->index() - rowMain->index() == 1;
-}
-
-bool RowMover::sourceRowsHasMaster() const
-{
- for (auto sourceRow : qAsConst(m_sourceRows)) {
- if (sourceRow->isMaster() && sourceRow->objectType() != OBJTYPE_LAYER)
- return true;
- }
-
- return false;
-}
-
-bool RowMover::isSourceRowsDescendant(RowTree *row) const
-{
- if (row) {
- for (auto sourceRow : qAsConst(m_sourceRows)) {
- if (row == sourceRow || row->isDecendentOf(sourceRow))
- return true;
- }
- }
-
- return false;
-}
-
-// 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,
- Q3DStudio::DocumentEditorFileType::Enum fileType,
- bool firstTry)
-{
- // DnD a presentation / Qml stream from the project panel (to set it as a subpresentation)
- if (rowType & (OBJTYPE_PRESENTATION | OBJTYPE_QML_STREAM | OBJTYPE_MATERIALDATA)) {
- if (!m_insertionTarget.isNull())
- m_insertionTarget->setDnDState(RowTree::DnDState::None, RowTree::DnDState::SP_TARGET);
-
- RowTree *rowAtMouse = m_scene->rowManager()->getRowAtPos(scenePos);
- if (rowAtMouse) {
- // m_insertionTarget will go through CFileDropSource::ValidateTarget() which will
- // filter out invalid drop rows
- m_insertionTarget = rowAtMouse;
- m_insertType = Q3DStudio::DocumentEditorInsertType::LastChild;
-
- if (rowType == OBJTYPE_MATERIALDATA) {
- if (rowAtMouse->objectType() & OBJTYPE_IS_MATERIAL)
- m_insertionTarget->setDnDState(RowTree::DnDState::SP_TARGET);
- } else {
- if (rowAtMouse->objectType() & (OBJTYPE_LAYER | OBJTYPE_IS_MATERIAL | OBJTYPE_IMAGE)
- && !rowAtMouse->isDefaultMaterial()) {
- m_insertionTarget->setDnDState(RowTree::DnDState::SP_TARGET);
- }
- }
- m_rowAutoExpand = rowAtMouse;
- m_autoExpandTimer.start(TimelineConstants::AUTO_EXPAND_TIME);
- } else {
- m_rowAutoExpand = nullptr;
- m_autoExpandTimer.stop();
- }
- return;
- } else if (fileType == Q3DStudio::DocumentEditorFileType::Image) { // DnD an image
- if (!m_insertionTarget.isNull())
- m_insertionTarget->setDnDState(RowTree::DnDState::None, RowTree::DnDState::SP_TARGET);
- // if draggin in the middle of a layer, mat, or image row, set the image as a texture.
- RowTree *rowAtMouse = m_scene->rowManager()->getRowAtPos(scenePos);
- if (rowAtMouse) {
- double y = rowAtMouse->mapFromScene(scenePos).y();
- if (y > TimelineConstants::ROW_H * .25 && y < TimelineConstants::ROW_H * .75) {
- if (rowAtMouse->objectType() & (OBJTYPE_LAYER | OBJTYPE_IS_MATERIAL | OBJTYPE_IMAGE)
- && !rowAtMouse->isDefaultMaterial()) {
- m_rowAutoExpand = nullptr;
- m_autoExpandTimer.stop();
- setVisible(false);
- resetInsertionParent();
-
- m_insertionTarget = rowAtMouse;
- m_insertionTarget->setDnDState(RowTree::DnDState::SP_TARGET);
- m_insertType = Q3DStudio::DocumentEditorInsertType::LastChild;
- return;
- }
- }
- }
- }
-
- EStudioObjectType theRowType = rowType;
- if (theRowType == OBJTYPE_UNKNOWN && m_sourceRows.size() == 1)
- theRowType = m_sourceRows[0]->objectType();
-
- // row will be inserted just below rowInsert1 and just above rowInsert2 (if it exists)
- RowTree *rowInsert1 = m_scene->rowManager()
- ->getRowAtPos(scenePos + QPointF(0, TimelineConstants::ROW_H * -.5));
- RowTree *rowInsert2 = m_scene->rowManager()
- ->getRowAtPos(scenePos + QPointF(0, TimelineConstants::ROW_H * .5));
-
- // If on top half of the top row, adjust half row down, as we can never insert anything
- // above the top row
- if (!rowInsert1 && rowInsert2 && rowInsert2->index() == 0) {
- rowInsert1 = m_scene->rowManager()->getRowAtPos(scenePos);
- rowInsert2 = m_scene->rowManager()
- ->getRowAtPos(scenePos + QPointF(0, TimelineConstants::ROW_H));
- }
-
- bool valid = rowInsert1 != nullptr;
-
- if (valid) {
- // if dragging over a property or a parent of a property, move to the first row
- // after the property
- if (rowInsert1->isProperty()) {
- rowInsert1 = rowInsert1->parentRow()->childProps().last();
- rowInsert2 = m_scene->rowManager()
- ->getRowAtPos(QPointF(0, rowInsert1->y() + TimelineConstants::ROW_H));
- } else if (rowInsert1->hasPropertyChildren() && rowInsert1->expanded()) {
- rowInsert1 = rowInsert1->childProps().last();
- rowInsert2 = m_scene->rowManager()
- ->getRowAtPos(QPointF(0, rowInsert1->y() + TimelineConstants::ROW_H));
- }
-
- // calc insertion depth
- bool inAComponent = static_cast<RowTree *>(m_scene->layoutTree()->itemAt(1))->isComponent();
- int depth;
- int depthMin = 2;
- if (rowInsert2)
- depthMin = rowInsert2->depth();
- else if (theRowType != OBJTYPE_LAYER && !inAComponent)
- depthMin = 3;
-
- int depthMax = rowInsert1->depth();
- bool srcHasMaster = sourceRowsHasMaster();
- if (!rowInsert1->locked() && rowInsert1->isContainer() && !m_sourceRows.contains(rowInsert1)
- // prevent insertion a master row under a non-master unless under a component root
- && (!(srcHasMaster && !rowInsert1->isMaster()) || rowInsert1->isComponentRoot())) {
- depthMax++; // Container: allow insertion as a child
- } else {
- RowTree *row = rowInsert1->parentRow();
- if (rowInsert1->isPropertyOrMaterial() && !rowInsert1->parentRow()->isContainer()) {
- depthMax--; // non-container with properties and/or a material
- if (row)
- row = row->parentRow();
- }
- if (srcHasMaster) {
- while (row && !row->isMaster() && !row->isComponent()) {
- depthMax--;
- row = row->parentRow();
- }
- }
- }
-
- if (theRowType == OBJTYPE_LAYER) {
- depth = 2; // layers can only be moved on depth 2
- } else if (theRowType == OBJTYPE_EFFECT) {
- depth = 3; // effects can only be moved on depth 3 (layer direct child)
- } else {
- static const int LEFT_MARGIN = 20;
- depth = (int(scenePos.x()) - LEFT_MARGIN) / TimelineConstants::ROW_DEPTH_STEP;
- depth = qBound(depthMin, depth, depthMax);
- }
- // calc insertion parent
- RowTree *insertParent = rowInsert1;
- // If we are dragging objects to a component,
- // let insertParent be the component itself, not
- // the parent for the component and set the source rows
- // to be deleted soon (their duplicates will be inserted
- // in the component). Do this only if m_active is true
- // i.e. user is dragging a row within timeline (not from object/project panel)
- // AND drop depth is larger than for the component (user is dropping items _in_
- // the component, not at the same depth as the component itself)
- if (insertParent->isComponent() && !insertParent->isComponentRoot()
- && depth > insertParent->depth() && m_active) {
- m_deleteAfterMove = true;
- } else {
- m_deleteAfterMove = false;
- for (int i = rowInsert1->depth(); i >= depth; --i)
- insertParent = insertParent->parentRow();
- }
-
- resetInsertionParent(insertParent);
-
- if (depth < depthMin || depth > depthMax
- || (theRowType != OBJTYPE_UNKNOWN
- && !CStudioObjectTypes::AcceptableParent(theRowType,
- m_insertionParent->objectType()))
- || m_insertionParent->locked()) {
- valid = false;
- }
-
- for (auto sourceRow : qAsConst(m_sourceRows)) {
- if (m_insertionParent == sourceRow
- || m_insertionParent->isDecendentOf(sourceRow)
- || !CStudioObjectTypes::AcceptableParent(sourceRow->objectType(),
- m_insertionParent->objectType())) {
- // prevent insertion under itself, or under unacceptable parent
- valid = false;
- break;
- }
- }
-
- // 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()) {
- 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
- && isNextSiblingRow(m_insertionTarget, m_sourceRows[0]))
- || (m_insertType == Q3DStudio::DocumentEditorInsertType::PreviousSibling
- && isNextSiblingRow(m_sourceRows[0], m_insertionTarget))))) {
- valid = false;
- }
- if (valid) {
- updateState(depth, rowInsert1->y() + rowInsert1->size().height());
-
- // auto expand
- if (!rowInsert1->locked() && !rowInsert1->expanded() && rowInsert1->isContainer()
- && !rowInsert1->empty() && !isSourceRowsDescendant(rowInsert1)
- && depth == rowInsert1->depth() + 1) {
- updateTargetRowLater = std::bind(&RowMover::updateTargetRow, this,
- scenePos, rowType, fileType, true);
- m_rowAutoExpand = rowInsert1;
- m_autoExpandTimer.start(TimelineConstants::AUTO_EXPAND_TIME);
- } else {
- m_rowAutoExpand = nullptr;
- m_autoExpandTimer.stop();
- }
- } else if (firstTry && rowInsert2
- && m_scene->rowManager()->getRowAtPos(scenePos) == rowInsert2) {
- // If the current drop location turns out to be invalid and we are on the upper half of
- // a row, we try to resolve target row as if we were half row below. This allows drags
- // to be accepted over the entire row if inserting above the row is not valid.
- updateTargetRow(scenePos + QPointF(0, TimelineConstants::ROW_H * .5),
- rowType, fileType, false);
- valid = !m_insertionTarget.isNull();
- }
- }
-
- if (!valid) {
- m_rowAutoExpand = nullptr;
- m_autoExpandTimer.stop();
- setVisible(false);
- resetInsertionParent();
- }
-}
-
-int RowMover::type() const
-{
- // Enable the use of qgraphicsitem_cast with this item.
- return TypeRowMover;
-}
-
-Q3DStudio::DocumentEditorInsertType::Enum RowMover::insertionType() const
-{
- return m_insertType;
-}