forked from qt-creator/qt-creator
QmlDesigner: Create a context menu for the 3D Editor
For now only 1 action is implemented (edit material), more actions are coming next. Task-number: QDS-7414 Task-number: QDS-7398 Change-Id: Id8e36c23d9a4d35ee94d55d3d6b15df78241a05d Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -291,6 +291,10 @@ void Qt5InformationNodeInstanceServer::handleInputEvents()
|
|||||||
// data stored internally in QMutableEventPoint to potentially be updated by system
|
// data stored internally in QMutableEventPoint to potentially be updated by system
|
||||||
// before the event is delivered.
|
// before the event is delivered.
|
||||||
QGuiApplication::sendEvent(m_editView3DData.window, me);
|
QGuiApplication::sendEvent(m_editView3DData.window, me);
|
||||||
|
|
||||||
|
// Context menu requested
|
||||||
|
if (command.button() == Qt::RightButton && command.modifiers() == Qt::NoModifier)
|
||||||
|
getModelAtPos(command.pos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,6 +409,29 @@ void Qt5InformationNodeInstanceServer::removeRotationBlocks(const QVector<qint32
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qt5InformationNodeInstanceServer::getModelAtPos(const QPointF &pos)
|
||||||
|
{
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
// pick a Quick3DModel at view position
|
||||||
|
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
|
||||||
|
if (!helper)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context());
|
||||||
|
QObject *obj = qvariant_cast<QObject *>(editViewProp.read());
|
||||||
|
QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj);
|
||||||
|
|
||||||
|
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
|
||||||
|
|
||||||
|
// filter out picks of models created dynamically or inside components
|
||||||
|
QQuick3DModel *resolvedPick = qobject_cast<QQuick3DModel *>(helper->resolvePick(hitModel));
|
||||||
|
|
||||||
|
QVariant instance = resolvedPick ? instanceForObject(resolvedPick).instanceId() : -1;
|
||||||
|
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ModelAtPos, instance});
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::createEditView3D()
|
void Qt5InformationNodeInstanceServer::createEditView3D()
|
||||||
{
|
{
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
@@ -2399,26 +2426,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
|
|||||||
#endif
|
#endif
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
case View3DActionCommand::GetModelAtPos: {
|
case View3DActionCommand::GetModelAtPos: {
|
||||||
// pick a Quick3DModel at view position
|
getModelAtPos(command.value().toPointF());
|
||||||
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
|
|
||||||
if (!helper)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QQmlProperty editViewProp(m_editView3DData.rootItem, "editView", context());
|
|
||||||
QObject *obj = qvariant_cast<QObject *>(editViewProp.read());
|
|
||||||
QQuick3DViewport *editView = qobject_cast<QQuick3DViewport *>(obj);
|
|
||||||
|
|
||||||
QPointF pos = command.value().toPointF();
|
|
||||||
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
|
|
||||||
|
|
||||||
// filter out picks of models created dynamically or inside components
|
|
||||||
QQuick3DModel *resolvedPick = qobject_cast<QQuick3DModel *>(helper->resolvePick(hitModel));
|
|
||||||
|
|
||||||
if (resolvedPick) {
|
|
||||||
ServerNodeInstance instance = instanceForObject(resolvedPick);
|
|
||||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
|
||||||
{PuppetToCreatorCommand::ModelAtPos, QVariant(instance.instanceId())});
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -148,6 +148,7 @@ private:
|
|||||||
void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges);
|
void updateMaterialPreviewData(const QVector<PropertyValueContainer> &valueChanges);
|
||||||
void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
|
void updateRotationBlocks(const QVector<PropertyValueContainer> &valueChanges);
|
||||||
void removeRotationBlocks(const QVector<qint32> &instanceIds);
|
void removeRotationBlocks(const QVector<qint32> &instanceIds);
|
||||||
|
void getModelAtPos(const QPointF &pos);
|
||||||
|
|
||||||
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
|
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
|
||||||
#ifdef QUICK3D_PARTICLES_MODULE
|
#ifdef QUICK3D_PARTICLES_MODULE
|
||||||
|
@@ -796,7 +796,11 @@ void addNewSignalHandler(const SelectionContext &selectionState)
|
|||||||
// Open a model's material in the material editor
|
// Open a model's material in the material editor
|
||||||
void editMaterial(const SelectionContext &selectionContext)
|
void editMaterial(const SelectionContext &selectionContext)
|
||||||
{
|
{
|
||||||
ModelNode modelNode = selectionContext.currentSingleSelectedNode();
|
ModelNode modelNode = selectionContext.targetNode();
|
||||||
|
|
||||||
|
if (!modelNode.isValid())
|
||||||
|
modelNode = selectionContext.currentSingleSelectedNode();
|
||||||
|
|
||||||
QTC_ASSERT(modelNode.isValid(), return);
|
QTC_ASSERT(modelNode.isValid(), return);
|
||||||
|
|
||||||
BindingProperty prop = modelNode.bindingProperty("materials");
|
BindingProperty prop = modelNode.bindingProperty("materials");
|
||||||
|
@@ -102,6 +102,9 @@ QWidget *Edit3DCanvas::busyIndicator() const
|
|||||||
|
|
||||||
void Edit3DCanvas::mousePressEvent(QMouseEvent *e)
|
void Edit3DCanvas::mousePressEvent(QMouseEvent *e)
|
||||||
{
|
{
|
||||||
|
if (e->button() == Qt::RightButton && e->modifiers() == Qt::NoModifier)
|
||||||
|
m_parent->view()->startContextMenu(e->pos());
|
||||||
|
|
||||||
m_parent->view()->sendInputEvent(e);
|
m_parent->view()->sendInputEvent(e);
|
||||||
QWidget::mousePressEvent(e);
|
QWidget::mousePressEvent(e);
|
||||||
}
|
}
|
||||||
|
@@ -239,15 +239,26 @@ void Edit3DView::customNotification(const AbstractView *view, const QString &ide
|
|||||||
resetPuppet();
|
resetPuppet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get model at position from puppet process
|
||||||
|
*
|
||||||
|
* Response from puppet process for the model at requested position
|
||||||
|
*
|
||||||
|
* @param modelNode 3D model picked at the requested position, invalid node if no model exists
|
||||||
|
*/
|
||||||
void Edit3DView::modelAtPosReady(const ModelNode &modelNode)
|
void Edit3DView::modelAtPosReady(const ModelNode &modelNode)
|
||||||
{
|
{
|
||||||
if (!m_droppedMaterial.isValid() || !modelNode.isValid())
|
if (m_modelAtPosReqType == ModelAtPosReqType::ContextMenu) {
|
||||||
return;
|
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode);
|
||||||
|
} else if (m_modelAtPosReqType == ModelAtPosReqType::MaterialDrop) {
|
||||||
|
if (m_droppedMaterial.isValid() && modelNode.isValid()) {
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
assignMaterialTo3dModel(modelNode, m_droppedMaterial);
|
assignMaterialTo3dModel(modelNode, m_droppedMaterial);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
m_modelAtPosReqType = ModelAtPosReqType::None;
|
||||||
|
}
|
||||||
|
|
||||||
void Edit3DView::sendInputEvent(QInputEvent *e) const
|
void Edit3DView::sendInputEvent(QInputEvent *e) const
|
||||||
{
|
{
|
||||||
@@ -631,8 +642,17 @@ void Edit3DView::addQuick3DImport()
|
|||||||
tr("Could not add QtQuick3D import to project."));
|
tr("Could not add QtQuick3D import to project."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method is called upon right-clicking the view to prepare for context-menu creation. The actual
|
||||||
|
// context menu is created when modelAtPosReady() is received from puppet
|
||||||
|
void Edit3DView::startContextMenu(const QPoint &pos)
|
||||||
|
{
|
||||||
|
m_contextMenuPos = pos;
|
||||||
|
m_modelAtPosReqType = ModelAtPosReqType::ContextMenu;
|
||||||
|
}
|
||||||
|
|
||||||
void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos)
|
void Edit3DView::dropMaterial(const ModelNode &matNode, const QPointF &pos)
|
||||||
{
|
{
|
||||||
|
m_modelAtPosReqType = ModelAtPosReqType::MaterialDrop;
|
||||||
m_droppedMaterial = matNode;
|
m_droppedMaterial = matNode;
|
||||||
QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos});
|
QmlDesignerPlugin::instance()->viewManager().nodeInstanceView()->view3DAction({View3DActionCommand::GetModelAtPos, pos});
|
||||||
}
|
}
|
||||||
|
@@ -79,9 +79,16 @@ public:
|
|||||||
void setSeeker(SeekerSlider *slider);
|
void setSeeker(SeekerSlider *slider);
|
||||||
|
|
||||||
void addQuick3DImport();
|
void addQuick3DImport();
|
||||||
|
void startContextMenu(const QPoint &pos);
|
||||||
void dropMaterial(const ModelNode &matNode, const QPointF &pos);
|
void dropMaterial(const ModelNode &matNode, const QPointF &pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class ModelAtPosReqType {
|
||||||
|
MaterialDrop,
|
||||||
|
ContextMenu,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
void createEdit3DWidget();
|
void createEdit3DWidget();
|
||||||
void checkImports();
|
void checkImports();
|
||||||
|
|
||||||
@@ -120,6 +127,8 @@ private:
|
|||||||
int particlemode;
|
int particlemode;
|
||||||
ModelCache<QImage> m_canvasCache;
|
ModelCache<QImage> m_canvasCache;
|
||||||
ModelNode m_droppedMaterial;
|
ModelNode m_droppedMaterial;
|
||||||
|
ModelAtPosReqType m_modelAtPosReqType;
|
||||||
|
QPoint m_contextMenuPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "edit3dwidget.h"
|
#include "edit3dwidget.h"
|
||||||
#include "edit3dvisibilitytogglesmenu.h"
|
#include "edit3dvisibilitytogglesmenu.h"
|
||||||
#include "metainfo.h"
|
#include "metainfo.h"
|
||||||
|
#include "modelnodeoperations.h"
|
||||||
#include "qmldesignerconstants.h"
|
#include "qmldesignerconstants.h"
|
||||||
#include "qmldesignerplugin.h"
|
#include "qmldesignerplugin.h"
|
||||||
#include "qmlvisualnode.h"
|
#include "qmlvisualnode.h"
|
||||||
@@ -49,8 +50,8 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
Edit3DWidget::Edit3DWidget(Edit3DView *view) :
|
Edit3DWidget::Edit3DWidget(Edit3DView *view)
|
||||||
m_view(view)
|
: m_view(view)
|
||||||
{
|
{
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
@@ -146,6 +147,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
|
|||||||
|
|
||||||
handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false);
|
handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false);
|
||||||
|
|
||||||
|
createContextMenu();
|
||||||
|
|
||||||
view->setSeeker(seeker);
|
view->setSeeker(seeker);
|
||||||
seeker->setToolTip(QLatin1String("Seek particle system time when paused."));
|
seeker->setToolTip(QLatin1String("Seek particle system time when paused."));
|
||||||
|
|
||||||
@@ -173,6 +176,18 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
|
|||||||
showCanvas(false);
|
showCanvas(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Edit3DWidget::createContextMenu()
|
||||||
|
{
|
||||||
|
m_contextMenu = new QMenu(this);
|
||||||
|
m_editMaterialAction = m_contextMenu->addAction(tr("Edit Material"), [&] {
|
||||||
|
SelectionContext selCtx(m_view);
|
||||||
|
selCtx.setTargetNode(m_contextMenuTarget);
|
||||||
|
ModelNodeOperations::editMaterial(selCtx);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: add more actions: delete, create, etc
|
||||||
|
}
|
||||||
|
|
||||||
void Edit3DWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
|
void Edit3DWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
|
||||||
{
|
{
|
||||||
if (m_view)
|
if (m_view)
|
||||||
@@ -221,6 +236,15 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos)
|
|||||||
m_backgroundColorMenu->close();
|
m_backgroundColorMenu->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode)
|
||||||
|
{
|
||||||
|
m_contextMenuTarget = modelNode;
|
||||||
|
|
||||||
|
m_editMaterialAction->setEnabled(modelNode.isValid());
|
||||||
|
|
||||||
|
m_contextMenu->popup(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
void Edit3DWidget::linkActivated(const QString &link)
|
void Edit3DWidget::linkActivated(const QString &link)
|
||||||
{
|
{
|
||||||
Q_UNUSED(link)
|
Q_UNUSED(link)
|
||||||
|
@@ -24,11 +24,13 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QtWidgets/qwidget.h>
|
#include <QLabel>
|
||||||
#include <QtWidgets/qlabel.h>
|
#include <QMenu>
|
||||||
#include <QtWidgets/qmenu.h>
|
#include <QPointer>
|
||||||
#include <QtCore/qpointer.h>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <coreplugin/icontext.h>
|
#include <coreplugin/icontext.h>
|
||||||
|
#include <modelnode.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -54,12 +56,15 @@ public:
|
|||||||
QMenu *backgroundColorMenu() const;
|
QMenu *backgroundColorMenu() const;
|
||||||
void showBackgroundColorMenu(bool show, const QPoint &pos);
|
void showBackgroundColorMenu(bool show, const QPoint &pos);
|
||||||
|
|
||||||
|
void showContextMenu(const QPoint &pos, const ModelNode &modelNode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
|
void dragEnterEvent(QDragEnterEvent *dragEnterEvent) override;
|
||||||
void dropEvent(QDropEvent *dropEvent) override;
|
void dropEvent(QDropEvent *dropEvent) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void linkActivated(const QString &link);
|
void linkActivated(const QString &link);
|
||||||
|
void createContextMenu();
|
||||||
|
|
||||||
QPointer<Edit3DView> m_edit3DView;
|
QPointer<Edit3DView> m_edit3DView;
|
||||||
QPointer<Edit3DView> m_view;
|
QPointer<Edit3DView> m_view;
|
||||||
@@ -69,6 +74,9 @@ private:
|
|||||||
Core::IContext *m_context = nullptr;
|
Core::IContext *m_context = nullptr;
|
||||||
QPointer<QMenu> m_visibilityTogglesMenu;
|
QPointer<QMenu> m_visibilityTogglesMenu;
|
||||||
QPointer<QMenu> m_backgroundColorMenu;
|
QPointer<QMenu> m_backgroundColorMenu;
|
||||||
|
QPointer<QMenu> m_contextMenu;
|
||||||
|
QPointer<QAction> m_editMaterialAction;
|
||||||
|
ModelNode m_contextMenuTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -1707,7 +1707,6 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
|
|||||||
emitImport3DSupportChanged(supportMap);
|
emitImport3DSupportChanged(supportMap);
|
||||||
} else if (command.type() == PuppetToCreatorCommand::ModelAtPos) {
|
} else if (command.type() == PuppetToCreatorCommand::ModelAtPos) {
|
||||||
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt());
|
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt());
|
||||||
if (modelNode.isValid())
|
|
||||||
emitModelAtPosResult(modelNode);
|
emitModelAtPosResult(modelNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user