#include "INodeEditor.h" #include "undo/UndoCommands.h" INodeEditor::INodeEditor(QWidget *pParent) : QMainWindow(pParent), mShowGizmo(false), mGizmoHovering(false), mGizmoTransforming(false), mTranslateSpace(eWorldTransform), mRotateSpace(eWorldTransform) { // Create undo actions QAction *pUndoAction = mUndoStack.createUndoAction(this); QAction *pRedoAction = mUndoStack.createRedoAction(this); pUndoAction->setShortcut(QKeySequence("Ctrl+Z")); pRedoAction->setShortcut(QKeySequence("Ctrl+Y")); mUndoActions.push_back(pUndoAction); mUndoActions.push_back(pRedoAction); // Create gizmo actions mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/SelectMode.png"), "Select Objects", this)); mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Translate.png"), "Translate", this)); mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Rotate.png"), "Rotate", this)); mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Scale.png"), "Scale", this)); mGizmoActions[0]->setShortcut(QKeySequence("Ctrl+Q")); mGizmoActions[1]->setShortcut(QKeySequence("Ctrl+W")); mGizmoActions[2]->setShortcut(QKeySequence("Ctrl+E")); mGizmoActions[3]->setShortcut(QKeySequence("Ctrl+R")); mpGizmoGroup = new QActionGroup(this); foreach (QAction *pAction, mGizmoActions) { pAction->setCheckable(true); mpGizmoGroup->addAction(pAction); } mGizmoActions[0]->setChecked(true); // Create transform combo box mpTransformCombo = new QComboBox(this); mpTransformCombo->addItem("World"); mpTransformCombo->addItem("Local"); // Connect signals and slots connect(mGizmoActions[0], SIGNAL(triggered()), this, SLOT(OnSelectObjectsTriggered())); connect(mGizmoActions[1], SIGNAL(triggered()), this, SLOT(OnTranslateTriggered())); connect(mGizmoActions[2], SIGNAL(triggered()), this, SLOT(OnRotateTriggered())); connect(mGizmoActions[3], SIGNAL(triggered()), this, SLOT(OnScaleTriggered())); connect(mpTransformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnTransformSpaceChanged(int))); } INodeEditor::~INodeEditor() { } QUndoStack* INodeEditor::UndoStack() { return &mUndoStack; } CSceneManager* INodeEditor::Scene() { return &mScene; } CGizmo* INodeEditor::Gizmo() { return &mGizmo; } bool INodeEditor::IsGizmoVisible() { return (mShowGizmo && !mSelection.empty()); } void INodeEditor::BeginGizmoTransform() { mGizmoTransforming = true; foreach (QAction *pAction, mGizmoActions) pAction->setEnabled(false); } void INodeEditor::EndGizmoTransform() { mGizmoTransforming = false; foreach (QAction *pAction, mGizmoActions) pAction->setEnabled(true); if (mGizmo.Mode() == CGizmo::eTranslate) mUndoStack.push(CTranslateNodeCommand::End()); else if (mGizmo.Mode() == CGizmo::eRotate) mUndoStack.push(CRotateNodeCommand::End()); else if (mGizmo.Mode() == CGizmo::eScale) mUndoStack.push(CScaleNodeCommand::End()); } ETransformSpace INodeEditor::CurrentTransformSpace() { switch (mGizmo.Mode()) { case CGizmo::eTranslate: return mTranslateSpace; case CGizmo::eRotate: return mRotateSpace; case CGizmo::eScale: return eLocalTransform; default: return eWorldTransform; } } void INodeEditor::RecalculateSelectionBounds() { mSelectionBounds = CAABox::skInfinite; foreach (CSceneNode *pNode, mSelection) ExpandSelectionBounds(pNode); } void INodeEditor::ExpandSelectionBounds(CSceneNode *pNode) { mSelectionBounds.ExpandBounds(pNode->AABox()); if (pNode->NodeType() == eScriptNode) { CScriptNode *pScript = static_cast(pNode); if (pScript->HasPreviewVolume()) mSelectionBounds.ExpandBounds(pScript->PreviewVolumeAABox()); } } void INodeEditor::SelectNode(CSceneNode *pNode) { if (!pNode->IsSelected()) mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection)); emit SelectionModified(); } void INodeEditor::DeselectNode(CSceneNode *pNode) { if (pNode->IsSelected()) mUndoStack.push(new CDeselectNodeCommand(this, pNode, mSelection)); emit SelectionModified(); } void INodeEditor::ClearSelection() { if (!mSelection.empty()) mUndoStack.push(new CClearSelectionCommand(this, mSelection)); emit SelectionModified(); } void INodeEditor::ClearAndSelectNode(CSceneNode *pNode) { if (mSelection.empty()) mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection)); else if ((mSelection.size() == 1) && (mSelection.front() == pNode)) return; else { mUndoStack.beginMacro("Select"); mUndoStack.push(new CClearSelectionCommand(this, mSelection)); mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection)); mUndoStack.endMacro(); } emit SelectionModified(); } // ************ PUBLIC SLOTS ************ void INodeEditor::OnGizmoMoved() { switch (mGizmo.Mode()) { case CGizmo::eTranslate: { CVector3f delta = mGizmo.DeltaTranslation(); mUndoStack.push(new CTranslateNodeCommand(this, mSelection, delta, mTranslateSpace)); break; } case CGizmo::eRotate: { CQuaternion delta = mGizmo.DeltaRotation(); mUndoStack.push(new CRotateNodeCommand(this, mSelection, CVector3f::skZero, delta, mRotateSpace)); break; } case CGizmo::eScale: { CVector3f delta = mGizmo.DeltaScale(); mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta)); break; } } RecalculateSelectionBounds(); UpdateGizmoUI(); } // ************ PRIVATE SLOTS ************ void INodeEditor::OnSelectObjectsTriggered() { mGizmo.SetMode(CGizmo::eOff); mGizmo.SetTransformSpace(eWorldTransform); mShowGizmo = false; mpTransformCombo->setEnabled(false); mpTransformCombo->blockSignals(true); mpTransformCombo->setCurrentIndex(0); mpTransformCombo->blockSignals(false); GizmoModeChanged(CGizmo::eOff); UpdateGizmoUI(); } void INodeEditor::OnTranslateTriggered() { mGizmo.SetMode(CGizmo::eTranslate); mGizmo.SetTransformSpace(mTranslateSpace); mShowGizmo = true; mpTransformCombo->setEnabled(true); mpTransformCombo->blockSignals(true); mpTransformCombo->setCurrentIndex( (mTranslateSpace == eWorldTransform) ? 0 : 1 ); mpTransformCombo->blockSignals(false); GizmoModeChanged(CGizmo::eTranslate); UpdateGizmoUI(); } void INodeEditor::OnRotateTriggered() { mGizmo.SetMode(CGizmo::eRotate); mGizmo.SetTransformSpace(mRotateSpace); mShowGizmo = true; mpTransformCombo->setEnabled(true); mpTransformCombo->blockSignals(true); mpTransformCombo->setCurrentIndex( (mRotateSpace == eWorldTransform) ? 0 : 1 ); mpTransformCombo->blockSignals(false); GizmoModeChanged(CGizmo::eRotate); UpdateGizmoUI(); } void INodeEditor::OnScaleTriggered() { mGizmo.SetMode(CGizmo::eScale); mGizmo.SetTransformSpace(eLocalTransform); mShowGizmo = true; mpTransformCombo->setEnabled(false); mpTransformCombo->blockSignals(true); mpTransformCombo->setCurrentIndex(1); mpTransformCombo->blockSignals(false); GizmoModeChanged(CGizmo::eScale); UpdateGizmoUI(); } void INodeEditor::OnTransformSpaceChanged(int spaceIndex) { if ((mGizmo.Mode() == CGizmo::eScale) || (mGizmo.Mode() == CGizmo::eOff)) return; ETransformSpace space = (spaceIndex == 0 ? eWorldTransform : eLocalTransform); if (mGizmo.Mode() == CGizmo::eTranslate) mTranslateSpace = space; else mRotateSpace = space; mGizmo.SetTransformSpace(space); }