summaryrefslogtreecommitdiffstats
path: root/editorlib
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2016-06-13 10:14:04 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2016-06-14 11:37:55 +0000
commitaf16128e059d51bc41dccafdbe52e8461572fb6e (patch)
treedfb4f1b8d61fc9292a7c620c689ea987c46c3778 /editorlib
parent9b190770efe147d13df3eecfd1f725202d3f21c2 (diff)
Multiselect refactoring
Now store multiselection status and list on c++ side only to reduce problems from keeping them properly synchronized. Change-Id: If3277bb1eca5ffc7a7749e300e0cc6de4ccf9df2 Reviewed-by: Titta Heikkala <titta.heikkala@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'editorlib')
-rw-r--r--editorlib/qml/ComponentMenu.qml42
-rw-r--r--editorlib/qml/EntityTree.qml50
-rw-r--r--editorlib/qml/GeneralPropertyView.qml2
-rw-r--r--editorlib/qml/main.qml44
-rw-r--r--editorlib/src/editorscene.cpp273
-rw-r--r--editorlib/src/editorscene.h22
-rw-r--r--editorlib/src/editorsceneitemmodel.cpp19
-rw-r--r--editorlib/src/undohandler/resetentitycommand.cpp5
-rw-r--r--editorlib/src/undohandler/undohandler.cpp10
9 files changed, 243 insertions, 224 deletions
diff --git a/editorlib/qml/ComponentMenu.qml b/editorlib/qml/ComponentMenu.qml
index 63ce969..8a00107 100644
--- a/editorlib/qml/ComponentMenu.qml
+++ b/editorlib/qml/ComponentMenu.qml
@@ -67,7 +67,7 @@ Menu {
MenuItem {
text: qsTr("Object Picker") + editorScene.emptyString
iconSource: "images/picker.png"
- enabled: !entityTree.multiSelect
+ enabled: !editorScene.multiSelection
onTriggered: {
componentPropertiesView.model.appendNewComponent(sceneModel.ObjectPicker)
}
@@ -77,7 +77,7 @@ Menu {
EntityMenu {
iconSource: "images/plus.png"
- enabled: !entityTree.multiSelect && !entityTreeView.cameraSelected
+ enabled: !editorScene.multiSelection && !entityTreeView.cameraSelected
}
MenuItem {
text: qsTr("Remove") + editorScene.emptyString
@@ -85,13 +85,14 @@ Menu {
iconSource: "images/minus.png"
onTriggered: {
entityTreeView.editing = false
- if (entityTree.multiSelect) {
+ if (editorScene.multiSelection) {
// Handle multiselection removal
editorScene.undoHandler.beginMacro(text)
- var removeList = editorScene.sceneModel.parentList(selectionList)
+ var removeList = editorScene.sceneModel.parentList(editorScene.multiSelectionList)
for (var i = 0; i < removeList.length; ++i)
editorScene.undoHandler.createRemoveEntityCommand(removeList[i])
editorScene.undoHandler.endMacro()
+ entityTree.selectSceneRoot()
} else {
// Doublecheck that we don't try to remove the scene root
if (entityTreeView.selection.currentIndex !== editorScene.sceneModel.sceneEntityIndex())
@@ -104,13 +105,14 @@ Menu {
enabled: !entityTreeView.sceneRootSelected
iconSource: "images/duplicate.png"
onTriggered: {
- if (entityTree.multiSelect) {
+ if (editorScene.multiSelection) {
// Handle multiselection duplication
editorScene.undoHandler.beginMacro(text)
- var duplicateList = editorScene.sceneModel.parentList(selectionList)
+ var duplicateList = editorScene.sceneModel.parentList(editorScene.multiSelectionList)
for (var i = 0; i < duplicateList.length; ++i)
editorScene.undoHandler.createDuplicateEntityCommand(duplicateList[i])
editorScene.undoHandler.endMacro()
+ editorScene.restoreMultiSelection(editorScene.multiSelectionList)
} else {
var currentSelection = selectedEntity.entity()
editorScene.undoHandler.createDuplicateEntityCommand(selectedEntityName)
@@ -120,7 +122,7 @@ Menu {
}
MenuItem {
text: qsTr("Copy (Ctrl + c)") + editorScene.emptyString
- enabled: !entityTree.multiSelect && !entityTreeView.sceneRootSelected
+ enabled: !editorScene.multiSelection && !entityTreeView.sceneRootSelected
iconSource: "images/copy.png"
onTriggered: {
mainwindow.copyEntity(selectedEntityName)
@@ -128,7 +130,7 @@ Menu {
}
MenuItem {
text: qsTr("Cut (Ctrl + x)") + editorScene.emptyString
- enabled: !entityTree.multiSelect && !entityTreeView.sceneRootSelected
+ enabled: !editorScene.multiSelection && !entityTreeView.sceneRootSelected
iconSource: "images/cut.png"
onTriggered: {
mainwindow.cutEntity(selectedEntityName, selectedEntity)
@@ -136,7 +138,7 @@ Menu {
}
MenuItem {
text: qsTr("Paste (Ctrl + v)") + editorScene.emptyString
- enabled: trackMousePosition && !entityTree.multiSelect
+ enabled: trackMousePosition && !editorScene.multiSelection
&& (!entityTree.treeviewPasting || (entityTree.treeviewPasting
&& editorScene.sceneModel.canReparent(
editorScene.sceneModel.editorSceneItemFromIndex(
@@ -153,7 +155,7 @@ Menu {
MenuItem {
text: qsTr("Reset") + editorScene.emptyString
iconSource: "images/reset_all.png"
- enabled: !entityTree.multiSelect && !entityTreeView.sceneRootSelected
+ enabled: !editorScene.multiSelection && !entityTreeView.sceneRootSelected
onTriggered: {
editorScene.undoHandler.createResetEntityCommand(selectedEntityName)
}
@@ -161,7 +163,7 @@ Menu {
MenuItem {
text: qsTr("Reset Transform") + editorScene.emptyString
iconSource: "images/reset.png"
- enabled: !entityTree.multiSelect && !entityTreeView.sceneRootSelected
+ enabled: !editorScene.multiSelection && !entityTreeView.sceneRootSelected
&& !entityTreeView.cameraSelected
onTriggered: {
editorScene.undoHandler.createResetTransformCommand(selectedEntityName)
@@ -176,8 +178,8 @@ Menu {
// Copy list, as the original is emptied on insertEntity
var reparentList = []
var groupCenter
- if (entityTree.multiSelect) {
- reparentList = editorScene.sceneModel.parentList(selectionList)
+ if (editorScene.multiSelection) {
+ reparentList = editorScene.sceneModel.parentList(editorScene.multiSelectionList)
groupCenter = editorScene.getMultiSelectionCenter()
} else {
reparentList[0] = selectedEntityName
@@ -186,10 +188,6 @@ Menu {
// TODO: Allow creating groups under other entities?
- // Select scene root before doing reparenting to avoid having selection changes
- // while removing, as indexes can be corrupt during the removal
- entityTree.selectSceneRoot()
-
// Add new group
editorScene.undoHandler.createInsertEntityCommand(1, editorScene.sceneRootName(),
groupCenter)
@@ -199,11 +197,11 @@ Menu {
for (var i = 0; i < reparentList.length; ++i)
editorScene.undoHandler.createReparentEntityCommand(groupName, reparentList[i])
editorScene.undoHandler.endMacro()
- // Clear selection
- entityTree.multiSelect = false
- editorScene.multiSelection = []
- // Select the added group
- editorScene.selectIndex(index)
+
+ // Single-select the added group. Need to fetch group index again as reparenting
+ // resets the model.
+ editorScene.clearMultiSelection()
+ editorScene.selectIndex(editorScene.sceneModel.getModelIndexByName(groupName))
}
}
}
diff --git a/editorlib/qml/EntityTree.qml b/editorlib/qml/EntityTree.qml
index 4a726e2..3edb985 100644
--- a/editorlib/qml/EntityTree.qml
+++ b/editorlib/qml/EntityTree.qml
@@ -40,17 +40,16 @@ Item {
property alias view: entityTreeView
property alias menu: addComponentMenu
property bool treeviewPasting: false
- property bool multiSelect: false
- property bool multiSelectedCamera: false
Keys.onDeletePressed: {
- if (multiSelect) {
+ if (editorScene.multiSelection) {
// Handle multiselection removal
editorScene.undoHandler.beginMacro("Remove selected")
- var removeList = editorScene.sceneModel.parentList(selectionList)
+ var removeList = editorScene.sceneModel.parentList(editorScene.multiSelectionList)
for (var i = 0; i < removeList.length; ++i)
editorScene.undoHandler.createRemoveEntityCommand(removeList[i])
editorScene.undoHandler.endMacro()
+ selectSceneRoot()
} else {
// Doublecheck that we don't try to remove the scene root
if (entityTreeView.selection.currentIndex !== editorScene.sceneModel.sceneEntityIndex())
@@ -63,6 +62,7 @@ Item {
}
function selectSceneRoot() {
+ editorScene.clearMultiSelection()
entityTreeView.selection.setCurrentIndex(
editorScene.sceneModel.sceneEntityIndex(),
ItemSelectionModel.SelectCurrent)
@@ -74,6 +74,8 @@ Item {
var y = yPos ? yPos : -1
entityTreeView.editing = false
+ editorScene.clearMultiSelection()
+
// Never allow inserting to root
if (entityTreeView.selection.currentIndex.row === -1)
selectSceneRoot()
@@ -218,21 +220,16 @@ Item {
onPressed: {
if (mouse.modifiers & Qt.ControlModifier) {
// Handle multiselection
- // Prevent multiselecting scene root
- if (styleData.index !== editorScene.sceneModel.sceneEntityIndex()) {
- editorScene.addToMultiSelection(editorScene.sceneModel.entityName(
- styleData.index))
- }
- // If empty list, select scene root
- if (selectionList.length === 0) {
- selectedEntityName = ""
- selectSceneRoot()
+ // Prevent multiselecting scene root and toggling when singly selected
+ // entity is clicked again
+ if ((editorScene.multiSelection
+ || styleData.index !== entityTreeView.selection.currentIndex)
+ && styleData.index !== editorScene.sceneModel.sceneEntityIndex()) {
+ editorScene.toggleEntityMultiSelection(editorScene.sceneModel.entityName(
+ styleData.index))
}
} else {
- // Clear selectionList
- entityTreeView.selection.clear()
- selectionList.length = 0
- editorScene.multiSelection = selectionList
+ editorScene.clearMultiSelection()
entityTreeView.selection.setCurrentIndex(styleData.index,
ItemSelectionModel.SelectCurrent)
}
@@ -295,6 +292,7 @@ Item {
onDropped: {
if (isValidDropTarget(drop.source)) {
dragHighlight.visible = false
+ editorScene.clearMultiSelection()
entityTreeView.selection.setCurrentIndex(styleData.index,
ItemSelectionModel.SelectCurrent)
if (drop.source.drag.target.dragKey === "changeParent") {
@@ -432,14 +430,12 @@ Item {
target: entityTreeView.selection
onCurrentIndexChanged: {
entityTreeView.editing = false
- // If there is no current item selected for some reason, fall back to scene root
+ // If there is no current item selected for some reason, fall back to scene root,
+ // except when dealing with multiselection, during which currentIndex can become -1 temporarily.
if (entityTreeView.selection.currentIndex.row === -1) {
selectedEntityName = ""
- if (!selectionList.length) {
- editorScene.clearSelectionBoxes()
- selectedEntity.showSelectionBox = true
+ if (!editorScene.multiSelection)
selectSceneRoot()
- }
} else {
entityTreeView.sceneRootSelected =
(editorScene.sceneModel.sceneEntityIndex() === entityTreeView.selection.currentIndex)
@@ -452,17 +448,13 @@ Item {
selectedEntity.itemType() === EditorSceneItem.Group
selectedEntityName = editorScene.sceneModel.entityName(
entityTreeView.selection.currentIndex)
- // Don't clear selection boxes if there are items in multiselection list
- if (!selectionList.length) {
- editorScene.clearSelectionBoxes()
- selectedEntity.showSelectionBox = true
- }
} else {
// Should never get here
selectedEntityName = ""
- editorScene.clearSelectionBoxes()
+ selectSceneRoot()
}
- editorScene.selection = selectedEntity.entity()
+ if (!editorScene.multiSelection)
+ editorScene.selection = selectedEntity.entity()
}
}
}
diff --git a/editorlib/qml/GeneralPropertyView.qml b/editorlib/qml/GeneralPropertyView.qml
index 62a470f..d6e0be7 100644
--- a/editorlib/qml/GeneralPropertyView.qml
+++ b/editorlib/qml/GeneralPropertyView.qml
@@ -46,7 +46,7 @@ Item {
Layout.minimumHeight: componentHeight
Layout.maximumHeight: Layout.minimumHeight
- visible: !entityTree.multiSelect
+ visible: !editorScene.multiSelection
Component.onCompleted: {
componentHeight = columnLayout.y + columnLayout.height
diff --git a/editorlib/qml/main.qml b/editorlib/qml/main.qml
index 3d78a8d..85115a4 100644
--- a/editorlib/qml/main.qml
+++ b/editorlib/qml/main.qml
@@ -123,8 +123,6 @@ ApplicationWindow {
property real qlcControlHeight: 28
- property var selectionList: []
-
property string systemLanguage: editorScene.language
toolBar: EditorToolbar {}
@@ -250,7 +248,7 @@ ApplicationWindow {
sequence: StandardKey.Copy
onActivated: {
// Prevent copying multiselection (for now, at least)
- if (!selectionList.length)
+ if (!editorScene.multiSelection)
mainwindow.copyEntity(selectedEntityName)
}
}
@@ -276,7 +274,7 @@ ApplicationWindow {
sequence: StandardKey.Cut
onActivated: {
// Prevent cutting multiselection (for now, at least)
- if (!selectionList.length)
+ if (!editorScene.multiSelection)
mainwindow.cutEntity(selectedEntityName, selectedEntity)
}
}
@@ -329,29 +327,11 @@ ApplicationWindow {
freeView: true
onSelectionChanged: {
- if (multiSelection.length >= 1) {
- entityTree.multiSelect = true
- } else {
- selectionList.length = 0
- entityTree.multiSelect = false
- }
restoreSelection(selection)
}
- onMultiSelectionChanged: {
- selectionList = multiSelection
- entityTree.multiSelectedCamera = false
- // Deselect old ones
- entityTree.view.selection.clear()
- // Dig indexes of all selected entities and pass the selections to entitytree
- for (var i = 0; i < multiSelection.length; ++i) {
- var index = editorScene.sceneModel.getModelIndexByName(multiSelection[i])
- entityTree.view.selection.select(index, ItemSelectionModel.Select)
- if (editorScene.sceneModel.editorSceneItemFromIndex(index).itemType()
- === EditorSceneItem.Camera) {
- entityTree.multiSelectedCamera = true
- }
- }
+ onMultiSelectionListChanged: {
+ restoreMultiSelection(editorScene.multiSelectionList)
}
onErrorChanged: {
@@ -374,18 +354,28 @@ ApplicationWindow {
selectIndex(index)
}
+ function restoreMultiSelection(selectionList) {
+ // Deselect old ones
+ entityTree.view.selection.clear()
+ // Dig indexes of all selected entities and pass the selections to entitytree
+ for (var i = 0; i < selectionList.length; ++i) {
+ var index = editorScene.sceneModel.getModelIndexByName(multiSelectionList[i])
+ entityTree.view.selection.select(index, ItemSelectionModel.Select)
+ expandTo(index)
+ }
+ }
+
function selectIndex(index) {
expandTo(index)
entityTree.view.forceActiveFocus()
- if (!entityTree.multiSelect)
- entityTree.view.selection.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect)
+ entityTree.view.selection.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect)
}
function expandTo(index) {
var target = index
do {
- target = target.parent
entityTree.view.expand(target)
+ target = target.parent
} while (target.valid)
}
}
diff --git a/editorlib/src/editorscene.cpp b/editorlib/src/editorscene.cpp
index 1eb9cdd..d4ca572 100644
--- a/editorlib/src/editorscene.cpp
+++ b/editorlib/src/editorscene.cpp
@@ -120,8 +120,7 @@ EditorScene::EditorScene(QObject *parent)
, m_gridSize(3)
, m_duplicateCount(0)
, m_previousDuplicate(nullptr)
- , m_multiSelect(false)
- , m_previousSelectedEntity(nullptr)
+ , m_ctrlDownOnLastLeftPress(false)
, m_clipboardOperation(ClipboardNone)
{
setLanguage(language());
@@ -200,13 +199,6 @@ void EditorScene::addEntity(Qt3DCore::QEntity *entity, int index, Qt3DCore::QEnt
addEntity(childEntity);
}
}
-
- if (!m_selectedEntityNameList.isEmpty()) {
- // Clear multiselection list, otherwise treeview gets messed up
- m_selectedEntityNameList.clear();
- m_multiSelect = false;
- emit multiSelectionChanged(m_selectedEntityNameList);
- }
}
// Removed entity is deleted
@@ -243,7 +235,7 @@ void EditorScene::removeEntity(Qt3DCore::QEntity *entity)
m_sceneItems.remove(entity->id());
- if (m_sceneEntity && m_selectedEntity == entity)
+ if (!multiSelection() && m_sceneEntity && m_selectedEntity == entity)
setSelection(m_sceneEntity);
delete item;
@@ -1744,30 +1736,33 @@ Qt3DRender::QCamera *EditorScene::frameGraphCamera() const
void EditorScene::setSelection(Qt3DCore::QEntity *entity)
{
+ // Setting selection implies end to multiSelection
+ if (m_selectedEntityNameList.size())
+ clearMultiSelection();
EditorSceneItem *item = m_sceneItems.value(entity->id(), nullptr);
if (item) {
if (entity != m_selectedEntity) {
- if (m_selectedEntity)
- connectDragHandles(m_sceneItems.value(m_selectedEntity->id(), nullptr), false);
+ if (m_selectedEntity) {
+ EditorSceneItem *oldItem = m_sceneItems.value(m_selectedEntity->id(), nullptr);
+ if (oldItem) {
+ connectDragHandles(oldItem, false);
+ oldItem->setShowSelectionBox(false);
+ }
+ }
m_selectedEntity = entity;
if (m_selectedEntity) {
connectDragHandles(item, true);
+ if (m_selectedEntity != m_sceneEntity)
+ item->setShowSelectionBox(true);
m_selectedEntityTransform = EditorUtils::entityTransform(m_selectedEntity);
}
- if (!m_multiSelect && m_selectedEntity != m_rootEntity)
- m_previousSelectedEntity = m_selectedEntity;
- else
- m_previousSelectedEntity = nullptr;
-
// Emit signal to highlight the entity from the list
emit selectionChanged(m_selectedEntity);
- } else if (!m_multiSelect) {
- clearSelectionBoxes(m_selectedEntity);
}
- m_dragHandlesTransform->setEnabled(item->isSelectionBoxShowing() && !m_multiSelect);
+ m_dragHandlesTransform->setEnabled(item->isSelectionBoxShowing());
if (item->itemType() == EditorSceneItem::Camera) {
// Disable scale handles for cameras
@@ -1818,47 +1813,29 @@ void EditorScene::setSelection(Qt3DCore::QEntity *entity)
handleSelectionTransformChange();
} else {
m_dragHandlesTransform->setEnabled(false);
+ if (m_selectedEntity != m_sceneEntity)
+ setSelection(m_sceneEntity);
}
}
-QString EditorScene::previousSelectedEntityName() const {
- if (m_previousSelectedEntity)
- return m_previousSelectedEntity->objectName();
- else
- return QString();
-}
-
-void EditorScene::setMultiSelection(const QStringList &multiSelection)
-{
- if (m_selectedEntityNameList != multiSelection) {
- checkMultiSelectionHighlights(m_selectedEntityNameList, multiSelection);
- m_selectedEntityNameList = multiSelection;
- }
-}
-
-QStringList EditorScene::multiSelection()
-{
- return m_selectedEntityNameList;
-}
-
-void EditorScene::addToMultiSelection(const QString &name)
+void EditorScene::toggleEntityMultiSelection(const QString &name)
{
- QStringList oldList = m_selectedEntityNameList;
- // Add previously selected one, if different than new one and other than scene root.
- if (m_selectedEntityNameList.isEmpty() && m_pickedEntity != m_selectedEntity
- && m_selectedEntity != m_sceneEntity) {
- m_selectedEntityNameList.append(previousSelectedEntityName());
- }
// If the new one is already in, remove it. Otherwise add it.
- if (!m_selectedEntityNameList.contains(name))
- m_selectedEntityNameList.append(name);
+ if (m_selectedEntityNameList.contains(name))
+ removeEntityFromMultiSelection(name);
else
- m_selectedEntityNameList.removeOne(name);
+ addEntityToMultiSelection(name);
+}
- // Emit multiselection list if it changed
- if (oldList != m_selectedEntityNameList) {
+void EditorScene::clearMultiSelection()
+{
+ if (m_selectedEntityNameList.size() > 0) {
+ QStringList oldList = m_selectedEntityNameList;
+ m_selectedEntityNameList.clear();
checkMultiSelectionHighlights(oldList, m_selectedEntityNameList);
- emit multiSelectionChanged(m_selectedEntityNameList);
+ emit multiSelectionChanged(false);
+ emit multiSelectionListChanged();
+ setSelection(m_sceneEntity);
}
}
@@ -1875,6 +1852,69 @@ QVector3D EditorScene::getMultiSelectionCenter()
return m_selectedEntityNameList.size() ? (pos / m_selectedEntityNameList.size()) : QVector3D();
}
+void EditorScene::addEntityToMultiSelection(const QString &name)
+{
+ QStringList oldList = m_selectedEntityNameList;
+
+ if (oldList.size() == 0) {
+ // Do not add if multiselecting the currently selected entity as the first entity
+ if (m_selectedEntity->objectName() == name)
+ return;
+
+ if (m_selectedEntity != m_sceneEntity) {
+ m_selectedEntityNameList.append(m_selectedEntity->objectName());
+ m_dragHandlesTransform->setEnabled(false);
+ handleSelectionTransformChange();
+ m_selectedEntity = nullptr;
+ } else {
+ // Just single-select the new entity and return if the other entity was scene entity
+ EditorSceneItem *item = m_sceneModel->getItemByName(name);
+ if (item) {
+ setSelection(item->entity());
+ return;
+ }
+ }
+ }
+ m_selectedEntityNameList.append(name);
+
+ checkMultiSelectionHighlights(oldList, m_selectedEntityNameList);
+
+ if (oldList.size() == 0)
+ emit multiSelectionChanged(true);
+ emit multiSelectionListChanged();
+}
+
+void EditorScene::removeEntityFromMultiSelection(const QString &name)
+{
+ QStringList oldList = m_selectedEntityNameList;
+ bool removed = m_selectedEntityNameList.removeOne(name);
+
+ if (removed) {
+ checkMultiSelectionHighlights(oldList, m_selectedEntityNameList);
+ bool lastRemoved = m_selectedEntityNameList.size() == 1;
+ EditorSceneItem *lastItem = nullptr;
+ if (lastRemoved) {
+ lastItem = m_sceneModel->getItemByName(m_selectedEntityNameList.at(0));
+ m_selectedEntityNameList.clear();
+ emit multiSelectionChanged(false);
+ }
+ emit multiSelectionListChanged();
+ if (lastRemoved) {
+ if (lastItem)
+ setSelection(lastItem->entity());
+ else
+ setSelection(m_sceneEntity);
+ }
+ }
+}
+
+void EditorScene::renameEntityInMultiSelectionList(const QString &oldName, const QString &newName)
+{
+ int index = m_selectedEntityNameList.indexOf(oldName);
+ if (index > 0)
+ m_selectedEntityNameList.replace(index, newName);
+}
+
void EditorScene::setClipboardOperation(ClipboardOperation operation)
{
if (operation != m_clipboardOperation) {
@@ -1981,34 +2021,30 @@ void EditorScene::clearSelectionBoxes(Qt3DCore::QEntity *skipEntity)
void EditorScene::endSelectionHandling()
{
if (m_dragMode == DragNone && m_pickedEntity) {
- // Multiselection handling
- if (m_multiSelect)
- addToMultiSelection(m_pickedEntity->objectName());
- else
- m_selectedEntityNameList.clear();
-
- // Selection handling
- if (m_multiSelect && m_selectedEntityNameList.isEmpty())
- setSelection(m_sceneEntity);
- else
+ if (m_ctrlDownOnLastLeftPress) {
+ // Multiselection handling
+ toggleEntityMultiSelection(m_pickedEntity->objectName());
+ } else {
+ // Single selection handling
setSelection(m_pickedEntity);
- // Selecting an object also starts drag, if translate handle is enabled
- Qt3DRender::QCamera *cameraEntity = qobject_cast<Qt3DRender::QCamera *>(m_pickedEntity);
- bool viewCenterDrag = cameraEntity && m_cameraViewCenterSelected && !m_viewCenterLocked;
- bool entityDrag = m_dragHandleTranslateTransform->isEnabled()
- && m_dragHandlesTransform->isEnabled()
- && (!cameraEntity || !m_cameraViewCenterSelected);
- if (viewCenterDrag || entityDrag) {
- m_dragMode = DragTranslate;
- m_dragEntity = m_pickedEntity;
- if (cameraEntity) {
- if (viewCenterDrag)
- m_dragInitialTranslationValue = cameraEntity->viewCenter();
- else
- m_dragInitialTranslationValue = cameraEntity->position();
- } else {
- m_dragInitialTranslationValue = m_dragHandlesTransform->translation();
+ // Selecting an object also starts drag, if translate handle is enabled
+ Qt3DRender::QCamera *cameraEntity = qobject_cast<Qt3DRender::QCamera *>(m_pickedEntity);
+ bool viewCenterDrag = cameraEntity && m_cameraViewCenterSelected && !m_viewCenterLocked;
+ bool entityDrag = m_dragHandleTranslateTransform->isEnabled()
+ && m_dragHandlesTransform->isEnabled()
+ && (!cameraEntity || !m_cameraViewCenterSelected);
+ if (viewCenterDrag || entityDrag) {
+ m_dragMode = DragTranslate;
+ m_dragEntity = m_pickedEntity;
+ if (cameraEntity) {
+ if (viewCenterDrag)
+ m_dragInitialTranslationValue = cameraEntity->viewCenter();
+ else
+ m_dragInitialTranslationValue = cameraEntity->position();
+ } else {
+ m_dragInitialTranslationValue = m_dragHandlesTransform->translation();
+ }
}
}
m_pickedEntity = nullptr;
@@ -2021,6 +2057,14 @@ void EditorScene::handleSelectionTransformChange()
EditorSceneItem *item = nullptr;
if (m_selectedEntity && m_selectedEntity != m_sceneEntity)
item = m_sceneItems.value(m_selectedEntity->id(), nullptr);
+ QPoint translatePoint;
+ QPoint centerPoint;
+ QVector3D translateHandlePos;
+ QVector3D itemCenterHandlePos;
+ QVector3D rotateHandlePos;
+ QVector3D cornerHandlePositions[dragCornerHandleCount];
+ bool showCenterHandle = false;
+
if (item) {
Qt3DRender::QCamera *camera = frameGraphCamera();
resizeCameraViewCenterEntity();
@@ -2041,12 +2085,11 @@ void EditorScene::handleSelectionTransformChange()
// Find out x/y viewport positions of drag handles
- QVector3D translateHandlePos = EditorUtils::projectRay(
+ translateHandlePos = EditorUtils::projectRay(
camera->viewMatrix(), camera->projectionMatrix(),
m_viewport->width(), m_viewport->height(),
m_dragHandlesTransform->matrix() * QVector3D());
- QVector3D cornerHandlePositions[dragCornerHandleCount];
for (int i = 0; i < dragCornerHandleCount; i++) {
m_dragHandleScaleTransforms.at(i)->setTranslation(
translation * m_dragHandleCornerAdjustments.at(i));
@@ -2060,7 +2103,6 @@ void EditorScene::handleSelectionTransformChange()
// Try to position rotate handle to the upper right corner of the selection box, as
// drawn on the screen. However, we don't change the corner during drag-rotation.
- QVector3D rotateHandlePos;
const float handleDistance = 12.0f;
if (m_dragMode != DragRotate) {
float maxDelta = 0.0f;
@@ -2105,11 +2147,7 @@ void EditorScene::handleSelectionTransformChange()
rotateHandlePos += adjustVector;
}
- QPoint translatePoint(translateHandlePos.x(), translateHandlePos.y());
-
- QPoint centerPoint;
- QVector3D itemCenterHandlePos;
- bool showCenterHandle = false;
+ translatePoint = QPoint(translateHandlePos.x(), translateHandlePos.y());
if (item->itemType() != EditorSceneItem::Camera
&& item->itemType() != EditorSceneItem::Light) {
itemCenterHandlePos = EditorUtils::projectRay(
@@ -2117,11 +2155,9 @@ void EditorScene::handleSelectionTransformChange()
m_viewport->width(), m_viewport->height(),
m_dragHandlesTransform->matrix() * m_dragHandleTranslateTransform->matrix()
* QVector3D());
-
centerPoint = QPoint(itemCenterHandlePos.x(), itemCenterHandlePos.y());
showCenterHandle = translatePoint != centerPoint;
}
-
m_meshCenterIndicatorLine->setEnabled(showCenterHandle);
if (showCenterHandle) {
QQuaternion rot = QQuaternion::rotationTo(QVector3D(0.0f, 0.0f, 1.0f),
@@ -2132,34 +2168,33 @@ void EditorScene::handleSelectionTransformChange()
m_dragHandlesTransform->translation());
m_meshCenterIndicatorLineTransform->setScale(meshCenter.length());
}
-
- // Signal UI to reposition drag handles
- emit beginDragHandlesRepositioning();
- emit repositionDragHandle(DragTranslate, translatePoint,
- m_dragHandlesTransform->isEnabled()
- ? m_dragHandleTranslateTransform->isEnabled()
- && translateHandlePos.z() > 0.0f : false, 0,
- translateHandlePos.z());
- emit repositionDragHandle(DragTranslate, centerPoint,
- m_dragHandlesTransform->isEnabled()
- ? m_dragHandleTranslateTransform->isEnabled()
- && itemCenterHandlePos.z() > 0.0f && showCenterHandle : false,
- 1, itemCenterHandlePos.z());
- emit repositionDragHandle(DragRotate, QPoint(rotateHandlePos.x(), rotateHandlePos.y()),
+ }
+ // Signal UI to reposition drag handles
+ emit beginDragHandlesRepositioning();
+ emit repositionDragHandle(DragTranslate, translatePoint,
+ m_dragHandlesTransform->isEnabled()
+ ? m_dragHandleTranslateTransform->isEnabled()
+ && translateHandlePos.z() > 0.0f : false, 0,
+ translateHandlePos.z());
+ emit repositionDragHandle(DragTranslate, centerPoint,
+ m_dragHandlesTransform->isEnabled()
+ ? m_dragHandleTranslateTransform->isEnabled()
+ && itemCenterHandlePos.z() > 0.0f && showCenterHandle : false,
+ 1, itemCenterHandlePos.z());
+ emit repositionDragHandle(DragRotate, QPoint(rotateHandlePos.x(), rotateHandlePos.y()),
+ m_dragHandlesTransform->isEnabled()
+ ? m_dragHandleRotateTransform->isEnabled()
+ && rotateHandlePos.z() > 0.0f : false, 0, rotateHandlePos.z());
+ for (int i = 0; i < dragCornerHandleCount; i++) {
+ emit repositionDragHandle(DragScale,
+ QPoint(cornerHandlePositions[i].x(),
+ cornerHandlePositions[i].y()),
m_dragHandlesTransform->isEnabled()
- ? m_dragHandleRotateTransform->isEnabled()
- && rotateHandlePos.z() > 0.0f : false, 0, rotateHandlePos.z());
- for (int i = 0; i < dragCornerHandleCount; i++) {
- emit repositionDragHandle(DragScale,
- QPoint(cornerHandlePositions[i].x(),
- cornerHandlePositions[i].y()),
- m_dragHandlesTransform->isEnabled()
- ? m_dragHandleScaleTransforms.at(0)->isEnabled()
- && cornerHandlePositions[i].z() > 0.0f : false, i,
- cornerHandlePositions[i].z());
- }
- emit endDragHandlesRepositioning();
+ ? m_dragHandleScaleTransforms.at(0)->isEnabled()
+ && cornerHandlePositions[i].z() > 0.0f : false, i,
+ cornerHandlePositions[i].z());
}
+ emit endDragHandlesRepositioning();
}
void EditorScene::handlePickerPress(Qt3DRender::QPickEvent *event)
@@ -2235,12 +2270,8 @@ bool EditorScene::handleMousePress(QMouseEvent *event)
{
m_previousMousePosition = event->pos();
m_mouseButton = event->button();
- if (m_mouseButton == Qt::LeftButton) {
- m_multiSelect = event->modifiers() & Qt::ControlModifier;
- // Clear multiselection list if m_multiSelect is false
- if (!m_multiSelect)
- m_selectedEntityNameList.clear();
- }
+ if (m_mouseButton == Qt::LeftButton)
+ m_ctrlDownOnLastLeftPress = event->modifiers() & Qt::ControlModifier;
cancelDrag();
return false; // Never consume press event
}
diff --git a/editorlib/src/editorscene.h b/editorlib/src/editorscene.h
index b525c49..c1c0aa0 100644
--- a/editorlib/src/editorscene.h
+++ b/editorlib/src/editorscene.h
@@ -72,7 +72,8 @@ class EditorScene : public QObject
Q_OBJECT
Q_PROPERTY(EditorSceneItemModel *sceneModel READ sceneModel CONSTANT)
Q_PROPERTY(Qt3DCore::QEntity *selection READ selection WRITE setSelection NOTIFY selectionChanged)
- Q_PROPERTY(QStringList multiSelection READ multiSelection WRITE setMultiSelection NOTIFY multiSelectionChanged)
+ Q_PROPERTY(QStringList multiSelectionList READ multiSelectionList NOTIFY multiSelectionListChanged)
+ Q_PROPERTY(bool multiSelection READ multiSelection NOTIFY multiSelectionChanged)
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
Q_PROPERTY(int activeSceneCameraIndex READ activeSceneCameraIndex WRITE setActiveSceneCameraIndex NOTIFY activeSceneCameraIndexChanged)
Q_PROPERTY(EditorViewportItem *viewport READ viewport WRITE setViewport NOTIFY viewportChanged)
@@ -236,10 +237,14 @@ public:
Q_INVOKABLE void dragHandleMove(const QPoint &pos, bool shiftDown, bool ctrlDown, bool altDown);
Q_INVOKABLE void dragHandleRelease();
Q_INVOKABLE QString sceneRootName() const { return m_sceneEntity->objectName(); }
- Q_INVOKABLE QString previousSelectedEntityName() const;
- Q_INVOKABLE void addToMultiSelection(const QString &name);
+ Q_INVOKABLE void toggleEntityMultiSelection(const QString &name);
+ Q_INVOKABLE void clearMultiSelection();
Q_INVOKABLE QVector3D getMultiSelectionCenter();
+ void removeEntityFromMultiSelection(const QString &name);
+ void addEntityToMultiSelection(const QString &name);
+ void renameEntityInMultiSelectionList(const QString &oldName, const QString &newName);
+
ClipboardOperation clipboardOperation() { return m_clipboardOperation; }
void setClipboardOperation(ClipboardOperation operation);
@@ -256,8 +261,9 @@ public:
void setSelection(Qt3DCore::QEntity *entity);
Qt3DCore::QEntity *selection() const { return m_selectedEntity; }
- void setMultiSelection(const QStringList &multiSelection);
- QStringList multiSelection();
+ QStringList multiSelectionList() { return m_selectedEntityNameList; }
+
+ bool multiSelection() const { return m_selectedEntityNameList.size() > 0; }
const QString &error() const { return m_errorString; }
@@ -307,7 +313,8 @@ public slots:
signals:
void selectionChanged(Qt3DCore::QEntity *selection);
- void multiSelectionChanged(QStringList multiSelection);
+ void multiSelectionListChanged();
+ void multiSelectionChanged(bool multiSelection);
void errorChanged(const QString &error);
void freeViewChanged(bool enabled);
void activeSceneCameraIndexChanged(int index);
@@ -456,10 +463,9 @@ private:
int m_gridSize;
int m_duplicateCount;
Qt3DCore::QEntity *m_previousDuplicate;
- bool m_multiSelect;
+ bool m_ctrlDownOnLastLeftPress;
QStringList m_selectedEntityNameList;
Qt::MouseButton m_mouseButton;
- Qt3DCore::QEntity *m_previousSelectedEntity;
QString m_clipboardEntityName;
ClipboardOperation m_clipboardOperation;
diff --git a/editorlib/src/editorsceneitemmodel.cpp b/editorlib/src/editorsceneitemmodel.cpp
index b1cb8dd..5956c44 100644
--- a/editorlib/src/editorsceneitemmodel.cpp
+++ b/editorlib/src/editorsceneitemmodel.cpp
@@ -260,13 +260,13 @@ QHash<int, QByteArray> EditorSceneItemModel::roleNames() const
void EditorSceneItemModel::resetModel()
{
- beginResetModel();
+ QAbstractItemModel::beginResetModel();
// Reconnect all entities
disconnectEntity(m_scene->sceneEntityItem()->entity());
connectEntity(m_scene->sceneEntityItem()->entity());
- endResetModel();
+ QAbstractItemModel::endResetModel();
// Restore TreeView branch expansions, since resetting the model will collapse the branches
QModelIndexList expandedIndexList;
@@ -274,8 +274,9 @@ void EditorSceneItemModel::resetModel()
expandedIndexList.append(getModelIndexByName(entityName));
emit expandItems(expandedIndexList);
- // Select scene root after reset
- emit selectIndex(sceneEntityIndex());
+ // Select scene root after reset, unless multiselecting
+ if (!m_scene->multiSelection())
+ emit selectIndex(sceneEntityIndex());
}
EditorSceneItem *EditorSceneItemModel::editorSceneItemFromIndex(const QModelIndex &index) const
@@ -464,11 +465,7 @@ const QString EditorSceneItemModel::setEntityName(const QModelIndex &index, cons
setData(index, finalName, NameRole);
- QStringList multiSelection = m_scene->multiSelection();
- if (multiSelection.removeOne(oldName)) {
- multiSelection.append(finalName);
- m_scene->setMultiSelection(multiSelection);
- }
+ m_scene->renameEntityInMultiSelectionList(oldName, finalName);
if (oldName == m_scene->clipboardContent())
m_scene->setClipboardContent(name);
@@ -537,11 +534,13 @@ bool EditorSceneItemModel::canReparent(EditorSceneItem *newParentItem,
EditorSceneItem *movedItem, bool allowSameParent)
{
// Dropping into camera is invalid.
+ // Reparenting camera is invalid.
// Dropping into same parent is invalid.
// Dropping item into its descendant is invalid.
// If allowSameParent is true, "reparenting" under the same parent is allowed. This is useful
// for entity tree copy & paste functionality.
- bool reparentOk = !EditorUtils::entityCameraLens(newParentItem->entity())
+ bool reparentOk = newParentItem->itemType() != EditorSceneItem::Camera
+ && movedItem->itemType() != EditorSceneItem::Camera
&& movedItem != newParentItem
&& !EditorUtils::isDescendant(movedItem, newParentItem);
if (!allowSameParent)
diff --git a/editorlib/src/undohandler/resetentitycommand.cpp b/editorlib/src/undohandler/resetentitycommand.cpp
index e581488..536f15e 100644
--- a/editorlib/src/undohandler/resetentitycommand.cpp
+++ b/editorlib/src/undohandler/resetentitycommand.cpp
@@ -62,11 +62,6 @@ void ResetEntityCommand::undo()
m_sceneModel->insertExistingEntity(m_removedEntity, m_row, parentIndex);
m_removedEntity = nullptr;
- if (m_type == EditorUtils::InsertableEntities::LightEntity
- || m_type == EditorUtils::InsertableEntities::CameraEntity) {
- m_sceneModel->resetModel();
- }
-
emit m_sceneModel->selectIndex(m_sceneModel->getModelIndexByName(m_entityName));
}
}
diff --git a/editorlib/src/undohandler/undohandler.cpp b/editorlib/src/undohandler/undohandler.cpp
index 59adf79..9d6a270 100644
--- a/editorlib/src/undohandler/undohandler.cpp
+++ b/editorlib/src/undohandler/undohandler.cpp
@@ -42,6 +42,7 @@
#include "importentitycommand.h"
#include "resetentitycommand.h"
#include "resettransformcommand.h"
+#include "editorsceneitem.h"
#include <QtWidgets/QUndoStack>
@@ -235,7 +236,14 @@ void UndoHandler::createReparentEntityCommand(const QString &newParentName,
if (newParentName.isEmpty() || entityName.isEmpty())
return;
- m_undoStack->push(new ReparentEntityCommand(m_scene->sceneModel(), newParentName, entityName));
+ // Don't create commands for illegal reparentings
+ EditorSceneItem *newParentItem = m_scene->sceneModel()->getItemByName(newParentName);
+ EditorSceneItem *entityItem = m_scene->sceneModel()->getItemByName(entityName);
+
+ if (m_scene->sceneModel()->canReparent(newParentItem, entityItem)) {
+ m_undoStack->push(new ReparentEntityCommand(m_scene->sceneModel(), newParentName,
+ entityName));
+ }
}
void UndoHandler::createImportEntityCommand(const QUrl &url)