summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2018-06-28 17:03:55 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2018-06-29 12:04:24 +0000
commitd2d0866310998b65ea8cf656c3d35d6fb803fbab (patch)
treef3cd8cc5fb15cd51af1f868fd95a5836c3a6ccf1
parent43fa674645ed9ebf5414ec2598858554b4c76c50 (diff)
Add support for grouping and ungrouping selected items
Ctrl-G will group 2 or more selected items under a newly created group item. Same shortcut when an single group is selected will move the group's children up one level and delete the group. Task-number: QT3DS-1283 Change-Id: Ife0fa6f0c35a4d37f7e76c7233e79c9f38d98a02 Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r--src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp55
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h3
-rw-r--r--src/Authoring/Studio/Application/StudioApp.cpp44
-rw-r--r--src/Authoring/Studio/Application/StudioApp.h4
-rw-r--r--src/Authoring/Studio/MainFrm.cpp21
-rw-r--r--src/Authoring/Studio/MainFrm.h1
-rw-r--r--src/Authoring/Studio/MainFrm.ui4
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h2
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp26
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp56
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp9
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp31
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h24
16 files changed, 257 insertions, 35 deletions
diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
index f2441067..d7e18cee 100644
--- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
@@ -2326,6 +2326,61 @@ public:
}
}
+ // Move all children out of a given parent instances and delete the instances.
+ // Typically the parent instances are groups as the function name implies.
+ void ungroupObjects(const TInstanceHandleList &inInstances) override
+ {
+ for (size_t idx = 0, end = inInstances.size(); idx < end; ++idx) {
+ TInstanceHandle selected = inInstances[idx];
+ if (selected.Valid()) {
+ TInstanceHandleList childHandles;
+ CGraphIterator children;
+ GetAssetChildrenInActiveSlide(selected, children);
+ for (; !children.IsDone(); ++children) {
+ TInstanceHandle child = children.GetCurrent();
+ childHandles.push_back(child);
+ }
+
+ // Rename the selected and to-be deleted instance so that it is less likely to cause
+ // name clash when its children are moved to the same level
+ CString name = GetName(selected);
+ name.append("@@to_be_deleted@@");
+ SetName(selected, name);
+
+ // Move group's children directly below the group item
+ RearrangeObjects(childHandles, selected, DocumentEditorInsertType::NextSibling,
+ true);
+
+ // Delete the group
+ DeleteInstance(selected);
+
+ // Select ungrouped instances
+ for (size_t i = 0, end = childHandles.size(); i < end; ++i) {
+ if (i == 0 && idx == 0)
+ m_Doc.SelectDataModelObject(childHandles[i]);
+ else
+ m_Doc.ToggleDataModelObjectToSelection(childHandles[i]);
+ }
+ }
+ }
+ }
+
+ // Creates a new group object and moves the specified objects as its children
+ void groupObjects(const TInstanceHandleList &inInstances) override
+ {
+ TInstanceHandleList sortedList(ToGraphOrdering(inInstances));
+
+ // Create a new group next to the topmost item in the graph
+ TInstanceHandle sibling = sortedList.front();
+ Qt3DSDMSlideHandle slide = GetActiveSlide(sibling);
+ TInstanceHandle group = CreateSceneGraphInstance(ComposerObjectTypes::Group, sibling, slide,
+ DocumentEditorInsertType::PreviousSibling,
+ CPt(), PRIMITIVETYPE_UNKNOWN, -1);
+
+ // Move items into the group
+ RearrangeObjects(sortedList, group, DocumentEditorInsertType::LastChild, true);
+ }
+
Qt3DSDMInstanceHandle MakeComponent(const qt3dsdm::TInstanceHandleList &inInstances) override
{
if (inInstances.empty())
diff --git a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
index 3e73cf7b..5ab7b02d 100644
--- a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
+++ b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
@@ -286,6 +286,9 @@ public:
RearrangeObjects(theInstances, inDest, inInsertType, checkUniqueName);
}
+ virtual void ungroupObjects(const qt3dsdm::TInstanceHandleList &inInstances) = 0;
+ virtual void groupObjects(const qt3dsdm::TInstanceHandleList &inInstances) = 0;
+
// Returns the new component.
virtual TInstanceHandle MakeComponent(const qt3dsdm::TInstanceHandleList &inInstances) = 0;
diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp
index 53692d5e..afde7d6e 100644
--- a/src/Authoring/Studio/Application/StudioApp.cpp
+++ b/src/Authoring/Studio/Application/StudioApp.cpp
@@ -996,6 +996,50 @@ QString CStudioApp::getDeleteType() const
return {};
}
+bool CStudioApp::canGroupSelectedObjects() const
+{
+ // Grouping is never just one row, we always deal with multiple selected items
+ qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
+ ->GetSelectedValue().GetSelectedInstances();
+ return (selected.size() > 1);
+}
+
+bool CStudioApp::canUngroupSelectedObjects() const
+{
+ qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
+ ->GetSelectedValue().GetSelectedInstances();
+ if (selected.size() == 1) {
+ qt3dsdm::Qt3DSDMInstanceHandle first = selected[0];
+ return (first.Valid() && m_core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()
+ ->GetObjectType(first) == OBJTYPE_GROUP);
+ }
+ return false;
+}
+
+bool CStudioApp::groupSelectedObjects() const
+{
+ if (canGroupSelectedObjects()) {
+ qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
+ ->GetSelectedValue().GetSelectedInstances();
+ SCOPED_DOCUMENT_EDITOR(*m_core->GetDoc(),
+ QObject::tr("Group objects"))->groupObjects(selected);
+ return true;
+ }
+ return false;
+}
+
+bool CStudioApp::ungroupSelectedObjects() const
+{
+ if (canUngroupSelectedObjects()) {
+ qt3dsdm::TInstanceHandleList selected = m_core->GetDoc()
+ ->GetSelectedValue().GetSelectedInstances();
+ SCOPED_DOCUMENT_EDITOR(*m_core->GetDoc(),
+ QObject::tr("Ungroup objects"))->ungroupObjects(selected);
+ return true;
+ }
+ return false;
+}
+
//=============================================================================
/**
* Cuts the selected object or keys
diff --git a/src/Authoring/Studio/Application/StudioApp.h b/src/Authoring/Studio/Application/StudioApp.h
index bc6a594b..530be0f4 100644
--- a/src/Authoring/Studio/Application/StudioApp.h
+++ b/src/Authoring/Studio/Application/StudioApp.h
@@ -165,6 +165,10 @@ public:
QString GetCopyType();
QString getDuplicateType() const;
QString getDeleteType() const;
+ bool canGroupSelectedObjects() const;
+ bool canUngroupSelectedObjects() const;
+ bool groupSelectedObjects() const;
+ bool ungroupSelectedObjects() const;
void OnCut();
bool CanCut();
void OnPaste();
diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp
index 48cd8842..76008d96 100644
--- a/src/Authoring/Studio/MainFrm.cpp
+++ b/src/Authoring/Studio/MainFrm.cpp
@@ -125,7 +125,7 @@ CMainFrame::CMainFrame()
this, &CMainFrame::onEditPasteToMaster);
connect(m_ui->action_Duplicate_Object, &QAction::triggered, this, &CMainFrame::OnEditDuplicate);
connect(m_ui->actionDelete, &QAction::triggered, this, &CMainFrame::onEditDelete);
-// connect(m_ui->actionGroup, &QAction::triggered, this, &CMainFrame::onEditGroup); // TODO: Implement
+ connect(m_ui->actionGroup, &QAction::triggered, this, &CMainFrame::onEditGroup);
// connect(m_ui->actionParent, &QAction::triggered, this, &CMainFrame::onEditParent); // TODO: Implement
// connect(m_ui->actionUnparent, &QAction::triggered, this, &CMainFrame::onEditUnparent); // TODO: Implement
connect(m_ui->actionStudio_Preferences, &QAction::triggered,
@@ -133,7 +133,6 @@ CMainFrame::CMainFrame()
connect(m_ui->actionPresentation_Settings, &QAction::triggered,
this, &CMainFrame::OnEditPresentationPreferences);
connect(m_ui->menu_Edit, &QMenu::aboutToShow, [this]() {
- // Enable/disable delete and duplicate
QString type = g_StudioApp.getDuplicateType();
QString label = tr("Duplicate %1").arg(type);
m_ui->action_Duplicate_Object->setText(label);
@@ -143,11 +142,20 @@ CMainFrame::CMainFrame()
label = tr("Delete %1").arg(type);
m_ui->actionDelete->setText(label);
m_ui->actionDelete->setEnabled(!type.isEmpty());
+
+ if (g_StudioApp.canUngroupSelectedObjects()) {
+ m_ui->actionGroup->setText(tr("Ungroup Objects"));
+ m_ui->actionGroup->setEnabled(true);
+ } else {
+ m_ui->actionGroup->setText(tr("Group Objects"));
+ m_ui->actionGroup->setEnabled(g_StudioApp.canGroupSelectedObjects());
+ }
});
connect(m_ui->menu_Edit, &QMenu::aboutToHide, [this]() {
- // Enable delete and duplicate so hotkeys will work
+ // Enable potentially disabled items so hotkeys will work
m_ui->action_Duplicate_Object->setEnabled(true);
m_ui->actionDelete->setEnabled(true);
+ m_ui->actionGroup->setEnabled(true);
});
// View Menu
@@ -237,7 +245,6 @@ CMainFrame::CMainFrame()
// Hide unimplemented menu items
m_ui->actionRepeat->setVisible(false);
- m_ui->actionGroup->setVisible(false);
m_ui->actionParent->setVisible(false);
m_ui->actionUnparent->setVisible(false);
m_ui->actionFit_all->setVisible(false);
@@ -709,6 +716,12 @@ void CMainFrame::onEditDelete()
g_StudioApp.DeleteSelectedObject();
}
+void CMainFrame::onEditGroup()
+{
+ if (!g_StudioApp.groupSelectedObjects())
+ g_StudioApp.ungroupSelectedObjects();
+}
+
/**
* Command handler for the File Open menu and toolbar options.
* This will save the file, if the file has not been saved before this will
diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h
index bf71bf1b..b660dc73 100644
--- a/src/Authoring/Studio/MainFrm.h
+++ b/src/Authoring/Studio/MainFrm.h
@@ -126,6 +126,7 @@ public:
void OnUpdateEditPaste();
void OnEditDuplicate();
void onEditDelete();
+ void onEditGroup();
void timerEvent(QTimerEvent *event) override;
void showEvent(QShowEvent *event) override;
diff --git a/src/Authoring/Studio/MainFrm.ui b/src/Authoring/Studio/MainFrm.ui
index 04083c42..570262da 100644
--- a/src/Authoring/Studio/MainFrm.ui
+++ b/src/Authoring/Studio/MainFrm.ui
@@ -45,7 +45,7 @@ Project palette using Import functionality.</string>
<x>0</x>
<y>0</y>
<width>1400</width>
- <height>17</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@@ -885,7 +885,7 @@ Project palette using Import functionality.</string>
</action>
<action name="actionGroup">
<property name="enabled">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<property name="text">
<string>Group</string>
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
index 2e804d85..0ee1a0de 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
@@ -71,6 +71,8 @@ public:
EUserTransaction_Delete,
EUserTransaction_MakeComponent,
EUserTransaction_EditComponent,
+ EUserTransaction_Group,
+ EUserTransaction_Ungroup,
};
public:
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp
index 8a106d1a..5956c78d 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp
@@ -576,6 +576,12 @@ bool Qt3DSDMTimelineItemBinding::IsValidTransaction(EUserTransaction inTransacti
case EUserTransaction_EditComponent:
return (GetObjectType() == OBJTYPE_COMPONENT);
+ case EUserTransaction_Group:
+ return g_StudioApp.canGroupSelectedObjects();
+
+ case EUserTransaction_Ungroup:
+ return g_StudioApp.canUngroupSelectedObjects();
+
default: // not handled
break;
}
@@ -602,6 +608,16 @@ inline void DoMakeComponent(CDoc &inDoc, const qt3dsdm::TInstanceHandleList &inI
SCOPED_DOCUMENT_EDITOR(inDoc, QObject::tr("Make Component"))->MakeComponent(inInstances);
}
+inline void DoGroupObjects(CDoc &inDoc, const qt3dsdm::TInstanceHandleList &inInstances)
+{
+ g_StudioApp.groupSelectedObjects();
+}
+
+inline void DoUngroupObjects(CDoc &inDoc, const qt3dsdm::TInstanceHandleList &inInstances)
+{
+ g_StudioApp.ungroupSelectedObjects();
+}
+
void Qt3DSDMTimelineItemBinding::PerformTransaction(EUserTransaction inTransaction)
{
CDoc *theDoc = m_TransMgr->GetDoc();
@@ -638,7 +654,15 @@ void Qt3DSDMTimelineItemBinding::PerformTransaction(EUserTransaction inTransacti
case EUserTransaction_MakeComponent: {
theDispatch.FireOnAsynchronousCommand(
std::bind(DoMakeComponent, std::ref(*theDoc), theInstances));
- }
+ } break;
+ case EUserTransaction_Group: {
+ theDispatch.FireOnAsynchronousCommand(
+ std::bind(DoGroupObjects, std::ref(*theDoc), theInstances));
+ } break;
+ case EUserTransaction_Ungroup: {
+ theDispatch.FireOnAsynchronousCommand(
+ std::bind(DoUngroupObjects, std::ref(*theDoc), theInstances));
+ } break;
default: // not handled
break;
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
index d78bed7f..6618e218 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
@@ -55,6 +55,11 @@ RowManager::RowManager(TimelineGraphicsScene *scene, QGraphicsLinearLayout *layo
}
+RowManager::~RowManager()
+{
+ finalizeRowDeletions();
+}
+
void RowManager::recreateRowsFromBinding(ITimelineItemBinding *rootBinding)
{
removeAllRows();
@@ -309,32 +314,51 @@ void RowManager::deleteRow(RowTree *row)
if (row->parentRow())
row->parentRow()->removeChild(row);
- deleteRowRecursive(row);
+ deleteRowRecursive(row, true);
}
}
-void RowManager::deleteRowRecursive(RowTree *row)
+void RowManager::finalizeRowDeletions()
{
- if (!row->childProps().empty()) {
- const auto childProps = row->childProps();
- for (auto child : childProps)
- deleteRowRecursive(child);
- }
+ for (auto row : qAsConst(m_deletedRows)) {
+ // If the row has been reparented, no need to delete it
+ if (!row->parentRow())
+ deleteRowRecursive(row, false);
+ }
+ m_deletedRows.clear();
+}
- if (!row->childRows().empty()) {
- const auto childRows = row->childRows();
- for (auto child : childRows)
- deleteRowRecursive(child);
- }
+void RowManager::deleteRowRecursive(RowTree *row, bool deferChildRows)
+{
+ if (!row->childProps().empty()) {
+ const auto childProps = row->childProps();
+ for (auto child : childProps)
+ deleteRowRecursive(child, false);
+ }
+
+ if (!row->childRows().empty()) {
+ const auto childRows = row->childRows();
+ for (auto child : childRows) {
+ if (deferChildRows) {
+ // Let's not delete child rows just yet, there may be a pending move for them.
+ // This happens when the same transaction contains parent deletion and child row
+ // move, such as ungrouping items.
+ child->setParentRow(nullptr);
+ m_deletedRows.append(child);
+ } else {
+ deleteRowRecursive(child, false);
+ }
+ }
+ }
- m_selectedRows.removeAll(row);
+ m_selectedRows.removeAll(row);
- m_scene->keyframeManager()->deleteKeyframes(row->rowTimeline(), false);
+ m_scene->keyframeManager()->deleteKeyframes(row->rowTimeline(), false);
- if (row->getBinding())
+ if (row->getBinding())
static_cast<Qt3DSDMTimelineItemBinding *>(row->getBinding())->setRowTree(nullptr);
- delete row;
+ delete row;
}
RowTree *RowManager::selectedRow() const
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h
index 21b8417e..c7f98423 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h
@@ -46,10 +46,12 @@ class RowManager
public:
RowManager(TimelineGraphicsScene *scene, QGraphicsLinearLayout *layoutLabels,
QGraphicsLinearLayout *layoutTimeline);
+ ~RowManager();
void selectRow(RowTree *row, bool multiSelect = false);
void setRowSelection(RowTree *row, bool selected);
void deleteRow(RowTree *row);
+ void finalizeRowDeletions();
void clearSelection();
void updateFiltering(RowTree *rowTree = nullptr);
void recreateRowsFromBinding(ITimelineItemBinding *rootBinding);
@@ -72,7 +74,7 @@ public:
private:
int getLastChildIndex(RowTree *row, int index = -1);
- void deleteRowRecursive(RowTree *row);
+ void deleteRowRecursive(RowTree *row, bool deferChildRows);
void updateRowFilterRecursive(RowTree *row);
void createRowsFromBindingRecursive(ITimelineItemBinding *binding,
RowTree *parentRow = nullptr);
@@ -82,6 +84,7 @@ private:
TimelineGraphicsScene *m_scene;
QGraphicsLinearLayout *m_layoutTree;
QGraphicsLinearLayout *m_layoutTimeline;
+ QVector<RowTree *> m_deletedRows;
};
#endif // ROWMANAGER_H
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
index 2f71366d..44f837ac 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
@@ -517,6 +517,9 @@ void TimelineWidget::onAssetDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
m_graphicsScene->rowManager()->deleteRow(row);
m_handlesMap.remove(inInstance);
m_graphicsScene->expandMap().remove(inInstance);
+ // Ensure row deletions are finalized
+ if (!m_asyncUpdateTimer.isActive())
+ m_asyncUpdateTimer.start();
}
}
@@ -574,8 +577,10 @@ void TimelineWidget::onAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentIns
if (propBinding && !propAnimated) {
m_graphicsScene->rowManager()->deleteRow(propBinding->getRowTree());
-
binding->RemovePropertyRow(property);
+ // Ensure row deletions are finalized
+ if (!m_asyncUpdateTimer.isActive())
+ m_asyncUpdateTimer.start();
}
}
}
@@ -732,6 +737,7 @@ void TimelineWidget::onAsyncUpdate()
rowParent->addChildAt(row, indexIt.key());
}
}
+ rowParent->updateExpandStatus(RowTree::ExpandState::Expanded, false);
}
}
// Make sure selections on UI matches bindings
@@ -810,6 +816,7 @@ void TimelineWidget::onAsyncUpdate()
m_moveMap.clear();
m_actionChanges.clear();
m_keyframeChangesMap.clear();
+ m_graphicsScene->rowManager()->finalizeRowDeletions();
}
void TimelineWidget::onActionEvent(qt3dsdm::Qt3DSDMActionHandle inAction,
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
index 8be884f8..8fa51365 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
@@ -417,6 +417,11 @@ void RowTree::setTimelineRow(RowTimeline *rowTimeline)
m_rowTimeline = rowTimeline;
}
+void RowTree::setParentRow(RowTree *parent)
+{
+ m_parentRow = parent;
+}
+
void RowTree::selectLabel()
{
m_labelItem.setEnabled(true);
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
index 0b837f96..5e735335 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
@@ -85,7 +85,7 @@ public:
QWidget *widget = nullptr) override;
void setState(State state) override;
void setTimelineRow(RowTimeline *rowTimeline);
- void setParent(RowTree *parent);
+ void setParentRow(RowTree *parent);
void addChild(RowTree *child);
void addChildAt(RowTree *child, int index);
void removeChild(RowTree *child);
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
index 37e2c903..78ceb59d 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
@@ -62,6 +62,12 @@ void RowTreeContextMenu::initialize()
connect(m_deleteAction, &QAction::triggered, this, &RowTreeContextMenu::deleteObject);
addAction(m_deleteAction);
+ m_groupAction = new QAction(tr("Group Objects"), this);
+ m_groupAction->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_G));
+ m_groupAction->setShortcutVisibleInContextMenu(true);
+ connect(m_groupAction, &QAction::triggered, this, &RowTreeContextMenu::groupObjects);
+ addAction(m_groupAction);
+
addSeparator();
m_copyAction = new QAction(tr("Copy"), this);
@@ -113,6 +119,11 @@ void RowTreeContextMenu::showEvent(QShowEvent *event)
m_renameAction->setEnabled(canRenameObject());
m_duplicateAction->setEnabled(canDuplicateObject());
m_deleteAction->setEnabled(canDeleteObject());
+ m_canGroupObjects = canGroupObjects();
+ m_canUngroupObjects = canUngroupObjects();
+ m_groupAction->setEnabled(m_canUngroupObjects || m_canGroupObjects);
+ if (m_canUngroupObjects)
+ m_groupAction->setText(tr("Ungroup Objects"));
m_cutAction->setEnabled(canCutObject());
m_copyAction->setEnabled(canCopyObject());
@@ -152,12 +163,32 @@ bool RowTreeContextMenu::canDeleteObject()
ITimelineItemBinding::EUserTransaction_Delete);
}
+bool RowTreeContextMenu::canGroupObjects()
+{
+ return m_TimelineItemBinding->IsValidTransaction(
+ ITimelineItemBinding::EUserTransaction_Group);
+}
+
+bool RowTreeContextMenu::canUngroupObjects()
+{
+ return m_TimelineItemBinding->IsValidTransaction(
+ ITimelineItemBinding::EUserTransaction_Ungroup);
+}
+
void RowTreeContextMenu::deleteObject()
{
m_TimelineItemBinding->PerformTransaction(
ITimelineItemBinding::EUserTransaction_Delete);
}
+void RowTreeContextMenu::groupObjects()
+{
+ if (m_canGroupObjects)
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Group);
+ else if (m_canUngroupObjects)
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Ungroup);
+}
+
bool RowTreeContextMenu::canInspectComponent()
{
return m_TimelineItemBinding->IsValidTransaction(
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
index 11bcbe72..290257c8 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
@@ -50,6 +50,7 @@ private Q_SLOTS:
void renameObject();
void duplicateObject();
void deleteObject();
+ void groupObjects();
void inspectComponent();
void makeComponent();
void copyObject();
@@ -62,6 +63,8 @@ private:
bool canRenameObject();
bool canDuplicateObject();
bool canDeleteObject();
+ bool canGroupObjects();
+ bool canUngroupObjects();
bool canInspectComponent();
bool canMakeComponent();
bool canCopyObject();
@@ -70,14 +73,17 @@ private:
RowTree *m_RowTree;
ITimelineItemBinding *m_TimelineItemBinding;
- QAction *m_renameAction;
- QAction *m_duplicateAction;
- QAction *m_deleteAction;
- QAction *m_inspectAction;
- QAction *m_makeAction;
- QAction *m_copyPathAction;
- QAction *m_cutAction;
- QAction *m_copyAction;
- QAction *m_pasteAction;
+ QAction *m_renameAction = nullptr;
+ QAction *m_duplicateAction = nullptr;
+ QAction *m_deleteAction = nullptr;
+ QAction *m_groupAction = nullptr;
+ QAction *m_inspectAction = nullptr;
+ QAction *m_makeAction = nullptr;
+ QAction *m_copyPathAction = nullptr;
+ QAction *m_cutAction = nullptr;
+ QAction *m_copyAction = nullptr;
+ QAction *m_pasteAction = nullptr;
+ bool m_canGroupObjects = false;
+ bool m_canUngroupObjects = false;
};
#endif // ROWTREECONTEXTMENU_H