forked from qt-creator/qt-creator
QmlDesigner: Add lock feature support to 3D editor
Added lock feature support for 3D editor. Also refactored the hide support, since the two use largely similar logic. Task-number: QDS-2915 Change-Id: I627848f3a3a73881427a03aeec6793fd26a1885a Reviewed-by: Henning Gründl <henning.gruendl@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
committed by
Miikka Heikkinen
parent
3d78fef4ef
commit
f2883c19b1
@@ -46,8 +46,8 @@ IconGizmo {
|
||||
frustum.targetNode = targetNode;
|
||||
frustum.targetNode = Qt.binding(function() {return targetNode;});
|
||||
|
||||
frustum.visible = visible;
|
||||
frustum.visible = Qt.binding(function() {return visible;});
|
||||
frustum.visible = visible || (targetNode && selected && activeScene === scene);
|
||||
frustum.visible = Qt.binding(function() {return visible || (targetNode && selected && activeScene === scene);});
|
||||
}
|
||||
|
||||
onActiveSceneChanged: {
|
||||
|
||||
@@ -263,11 +263,16 @@ Item {
|
||||
|
||||
function handleObjectClicked(object, multi)
|
||||
{
|
||||
var theObject = object;
|
||||
var clickedObject;
|
||||
|
||||
// Click on locked object is treated same as click on empty space
|
||||
if (!_generalHelper.isLocked(object))
|
||||
clickedObject = object;
|
||||
|
||||
if (selectionMode === EditView3D.SelectionMode.Group) {
|
||||
while (theObject && theObject !== activeScene
|
||||
&& (activeScene instanceof Model || theObject.parent !== activeScene)) {
|
||||
theObject = theObject.parent;
|
||||
while (clickedObject && clickedObject !== activeScene
|
||||
&& (activeScene instanceof Model || clickedObject.parent !== activeScene)) {
|
||||
clickedObject = clickedObject.parent;
|
||||
}
|
||||
}
|
||||
// Object selection logic:
|
||||
@@ -276,20 +281,20 @@ Item {
|
||||
// One or more objects selected: Multiselect
|
||||
// Null object always clears entire selection
|
||||
var newSelection = [];
|
||||
if (object !== null) {
|
||||
if (clickedObject) {
|
||||
if (multi && selectedNodes.length > 0) {
|
||||
var deselect = false;
|
||||
for (var i = 0; i < selectedNodes.length; ++i) {
|
||||
// Multiselecting already selected object clears that object from selection
|
||||
if (selectedNodes[i] !== object)
|
||||
if (selectedNodes[i] !== clickedObject)
|
||||
newSelection[newSelection.length] = selectedNodes[i];
|
||||
else
|
||||
deselect = true;
|
||||
}
|
||||
if (!deselect)
|
||||
newSelection[newSelection.length] = object;
|
||||
newSelection[newSelection.length] = clickedObject;
|
||||
} else {
|
||||
newSelection[0] = theObject;
|
||||
newSelection[0] = clickedObject;
|
||||
}
|
||||
}
|
||||
selectObjects(newSelection);
|
||||
@@ -312,16 +317,22 @@ Item {
|
||||
if (slotFound !== -1) {
|
||||
lightIconGizmos[slotFound].scene = scene;
|
||||
lightIconGizmos[slotFound].targetNode = obj;
|
||||
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||
_generalHelper.registerGizmoTarget(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
// No free gizmos available, create a new one
|
||||
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
|
||||
if (gizmoComponent.status === Component.Ready) {
|
||||
_generalHelper.registerGizmoTarget(obj);
|
||||
var gizmo = gizmoComponent.createObject(overlayView,
|
||||
{"view3D": overlayView, "targetNode": obj,
|
||||
"selectedNodes": selectedNodes, "scene": scene,
|
||||
"activeScene": activeScene});
|
||||
"activeScene": activeScene,
|
||||
"locked": _generalHelper.isLocked(obj),
|
||||
"hidden": _generalHelper.isHidden(obj)});
|
||||
lightIconGizmos[lightIconGizmos.length] = gizmo;
|
||||
gizmo.clicked.connect(handleObjectClicked);
|
||||
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
|
||||
@@ -345,6 +356,9 @@ Item {
|
||||
if (slotFound !== -1) {
|
||||
cameraGizmos[slotFound].scene = scene;
|
||||
cameraGizmos[slotFound].targetNode = obj;
|
||||
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
|
||||
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
|
||||
_generalHelper.registerGizmoTarget(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -352,6 +366,7 @@ Item {
|
||||
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
|
||||
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
|
||||
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
|
||||
_generalHelper.registerGizmoTarget(obj);
|
||||
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
|
||||
var frustum = frustumComponent.createObject(
|
||||
overlayScene,
|
||||
@@ -359,7 +374,8 @@ Item {
|
||||
var gizmo = gizmoComponent.createObject(
|
||||
overlayView,
|
||||
{"view3D": overlayView, "targetNode": obj,
|
||||
"selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene});
|
||||
"selectedNodes": selectedNodes, "scene": scene, "activeScene": activeScene,
|
||||
"locked": _generalHelper.isLocked(obj), "hidden": _generalHelper.isHidden(obj)});
|
||||
|
||||
cameraGizmos[cameraGizmos.length] = gizmo;
|
||||
gizmo.clicked.connect(handleObjectClicked);
|
||||
@@ -376,6 +392,7 @@ Item {
|
||||
if (lightIconGizmos[i].targetNode === obj) {
|
||||
lightIconGizmos[i].scene = null;
|
||||
lightIconGizmos[i].targetNode = null;
|
||||
_generalHelper.unregisterGizmoTarget(obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -387,6 +404,7 @@ Item {
|
||||
if (cameraGizmos[i].targetNode === obj) {
|
||||
cameraGizmos[i].scene = null;
|
||||
cameraGizmos[i].targetNode = null;
|
||||
_generalHelper.unregisterGizmoTarget(obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -423,6 +441,40 @@ Item {
|
||||
onWidthChanged: _generalHelper.requestOverlayUpdate()
|
||||
onHeightChanged: _generalHelper.requestOverlayUpdate()
|
||||
|
||||
Connections {
|
||||
target: _generalHelper
|
||||
function onLockedStateChanged(node)
|
||||
{
|
||||
for (var i = 0; i < cameraGizmos.length; ++i) {
|
||||
if (cameraGizmos[i].targetNode === node) {
|
||||
cameraGizmos[i].locked = _generalHelper.isLocked(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < lightIconGizmos.length; ++i) {
|
||||
if (lightIconGizmos[i].targetNode === node) {
|
||||
lightIconGizmos[i].locked = _generalHelper.isLocked(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function onHiddenStateChanged(node)
|
||||
{
|
||||
for (var i = 0; i < cameraGizmos.length; ++i) {
|
||||
if (cameraGizmos[i].targetNode === node) {
|
||||
cameraGizmos[i].hidden = _generalHelper.isHidden(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < lightIconGizmos.length; ++i) {
|
||||
if (lightIconGizmos[i].targetNode === node) {
|
||||
lightIconGizmos[i].hidden = _generalHelper.isHidden(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node {
|
||||
id: overlayScene
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ Item {
|
||||
return false;
|
||||
}
|
||||
property bool hasMouse: false
|
||||
property bool hidden: false
|
||||
property bool locked: false
|
||||
|
||||
property alias iconSource: iconImage.source
|
||||
|
||||
@@ -53,7 +55,7 @@ Item {
|
||||
hasMouse = false;
|
||||
}
|
||||
|
||||
visible: activeScene === scene && (targetNode ? targetNode.visible : false)
|
||||
visible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false)
|
||||
|
||||
Overlay2D {
|
||||
id: iconOverlay
|
||||
@@ -70,7 +72,7 @@ Item {
|
||||
y: -height / 2
|
||||
color: "transparent"
|
||||
border.color: "#7777ff"
|
||||
border.width: iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0
|
||||
border.width: !iconGizmo.locked && iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0
|
||||
radius: 5
|
||||
opacity: iconGizmo.selected ? 0.2 : 1
|
||||
Image {
|
||||
|
||||
@@ -244,6 +244,40 @@ QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
|
||||
return pickNode;
|
||||
}
|
||||
|
||||
void GeneralHelper::registerGizmoTarget(QQuick3DNode *node)
|
||||
{
|
||||
if (!m_gizmoTargets.contains(node)) {
|
||||
m_gizmoTargets.insert(node);
|
||||
node->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralHelper::unregisterGizmoTarget(QQuick3DNode *node)
|
||||
{
|
||||
if (m_gizmoTargets.contains(node)) {
|
||||
m_gizmoTargets.remove(node);
|
||||
node->removeEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool GeneralHelper::isLocked(QQuick3DNode *node)
|
||||
{
|
||||
if (node) {
|
||||
QVariant lockValue = node->property("_edit3dLocked");
|
||||
return lockValue.isValid() && lockValue.toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeneralHelper::isHidden(QQuick3DNode *node)
|
||||
{
|
||||
if (node) {
|
||||
QVariant hideValue = node->property("_edit3dHidden");
|
||||
return hideValue.isValid() && hideValue.toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state,
|
||||
int delay)
|
||||
{
|
||||
@@ -322,6 +356,21 @@ bool GeneralHelper::isMacOS() const
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GeneralHelper::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::DynamicPropertyChange) {
|
||||
auto node = qobject_cast<QQuick3DNode *>(obj);
|
||||
if (m_gizmoTargets.contains(node)) {
|
||||
auto de = static_cast<QDynamicPropertyChangeEvent *>(event);
|
||||
if (de->propertyName() == "_edit3dLocked")
|
||||
emit lockedStateChanged(node);
|
||||
else if (de->propertyName() == "_edit3dHidden")
|
||||
emit hiddenStateChanged(node);
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void GeneralHelper::handlePendingToolStateUpdate()
|
||||
{
|
||||
m_toolStateUpdateTimer.stop();
|
||||
|
||||
@@ -74,6 +74,12 @@ public:
|
||||
Q_INVOKABLE void delayedPropertySet(QObject *obj, int delay, const QString &property,
|
||||
const QVariant& value);
|
||||
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
|
||||
|
||||
Q_INVOKABLE void registerGizmoTarget(QQuick3DNode *node);
|
||||
Q_INVOKABLE void unregisterGizmoTarget(QQuick3DNode *node);
|
||||
Q_INVOKABLE bool isLocked(QQuick3DNode *node);
|
||||
Q_INVOKABLE bool isHidden(QQuick3DNode *node);
|
||||
|
||||
Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool,
|
||||
const QVariant &state, int delayEmit = 0);
|
||||
void initToolStates(const QString &sceneId, const QVariantMap &toolStates);
|
||||
@@ -90,6 +96,11 @@ public:
|
||||
signals:
|
||||
void overlayUpdateNeeded();
|
||||
void toolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState);
|
||||
void hiddenStateChanged(QQuick3DNode *node);
|
||||
void lockedStateChanged(QQuick3DNode *node);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
private:
|
||||
void handlePendingToolStateUpdate();
|
||||
@@ -98,6 +109,7 @@ private:
|
||||
QTimer m_toolStateUpdateTimer;
|
||||
QHash<QString, QVariantMap> m_toolStates;
|
||||
QHash<QString, QVariantMap> m_toolStatesPending;
|
||||
QSet<QQuick3DNode *> m_gizmoTargets;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -998,9 +998,17 @@ void NodeInstanceServer::setInstanceAuxiliaryData(const PropertyValueContainer &
|
||||
if (hasInstanceForId(auxiliaryContainer.instanceId())) {
|
||||
ServerNodeInstance instance = instanceForId(auxiliaryContainer.instanceId());
|
||||
if (!auxiliaryContainer.value().isNull())
|
||||
instance.setHideInEditor(auxiliaryContainer.value().toBool());
|
||||
instance.setHiddenInEditor(auxiliaryContainer.value().toBool());
|
||||
else
|
||||
instance.setHideInEditor(false);
|
||||
instance.setHiddenInEditor(false);
|
||||
}
|
||||
} else if (auxiliaryContainer.name() == "locked") {
|
||||
if (hasInstanceForId(auxiliaryContainer.instanceId())) {
|
||||
ServerNodeInstance instance = instanceForId(auxiliaryContainer.instanceId());
|
||||
if (!auxiliaryContainer.value().isNull())
|
||||
instance.setLockedInEditor(auxiliaryContainer.value().toBool());
|
||||
else
|
||||
instance.setLockedInEditor(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1480,4 +1488,14 @@ void NodeInstanceServer::initializeAuxiliaryViews()
|
||||
{
|
||||
}
|
||||
|
||||
void NodeInstanceServer::handleInstanceLocked(const ServerNodeInstance &/*instance*/, bool /*enable*/,
|
||||
bool /*checkAncestors*/)
|
||||
{
|
||||
}
|
||||
|
||||
void NodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &/*instance*/, bool /*enable*/,
|
||||
bool /*checkAncestors*/)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -208,6 +208,9 @@ public:
|
||||
|
||||
virtual void collectItemChangesAndSendChangeCommands() = 0;
|
||||
|
||||
virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
|
||||
virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
|
||||
|
||||
public slots:
|
||||
void refreshLocalFileProperty(const QString &path);
|
||||
void refreshDummyData(const QString &path);
|
||||
|
||||
@@ -392,8 +392,24 @@ PropertyNameList ObjectNodeInstance::ignoredProperties() const
|
||||
return PropertyNameList();
|
||||
}
|
||||
|
||||
void ObjectNodeInstance::setHideInEditor(bool)
|
||||
void ObjectNodeInstance::setHiddenInEditor(bool b)
|
||||
{
|
||||
m_isHiddenInEditor = b;
|
||||
}
|
||||
|
||||
bool ObjectNodeInstance::isHiddenInEditor() const
|
||||
{
|
||||
return m_isHiddenInEditor;
|
||||
}
|
||||
|
||||
void ObjectNodeInstance::setLockedInEditor(bool b)
|
||||
{
|
||||
m_isLockedInEditor = b;
|
||||
}
|
||||
|
||||
bool ObjectNodeInstance::isLockedInEditor() const
|
||||
{
|
||||
return m_isLockedInEditor;
|
||||
}
|
||||
|
||||
void ObjectNodeInstance::setModifiedFlag(bool b)
|
||||
|
||||
@@ -196,7 +196,11 @@ public:
|
||||
|
||||
virtual PropertyNameList ignoredProperties() const;
|
||||
|
||||
void virtual setHideInEditor(bool b);
|
||||
virtual void setHiddenInEditor(bool b);
|
||||
bool isHiddenInEditor() const;
|
||||
|
||||
virtual void setLockedInEditor(bool b);
|
||||
bool isLockedInEditor() const;
|
||||
|
||||
void setModifiedFlag(bool b);
|
||||
|
||||
@@ -213,6 +217,7 @@ protected:
|
||||
|
||||
void initializePropertyWatcher(const ObjectNodeInstance::Pointer &objectNodeInstance);
|
||||
void ensureVector3DDotProperties(PropertyNameList &list) const;
|
||||
|
||||
private:
|
||||
QString m_id;
|
||||
|
||||
@@ -227,6 +232,8 @@ private:
|
||||
bool m_deleteHeldInstance;
|
||||
bool m_isInLayoutable;
|
||||
bool m_isModified = false;
|
||||
bool m_isLockedInEditor = false;
|
||||
bool m_isHiddenInEditor = false;
|
||||
static QHash<EnumerationName, QVariant> m_enumationValueHash;
|
||||
};
|
||||
|
||||
|
||||
@@ -129,6 +129,12 @@ static bool imageHasContent(const QImage &image)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isQuick3DMode()
|
||||
{
|
||||
static bool mode3D = qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE");
|
||||
return mode3D;
|
||||
}
|
||||
|
||||
QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
|
||||
QQuickItem *&rootItem)
|
||||
{
|
||||
@@ -154,6 +160,23 @@ QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUr
|
||||
return view;
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances)
|
||||
{
|
||||
if (!isQuick3DMode())
|
||||
return;
|
||||
|
||||
// We only want to update the topmost parents in the set
|
||||
for (const auto &instance : instances) {
|
||||
if (instance.isValid()) {
|
||||
const auto parentInst = instance.parent();
|
||||
if (!parentInst.isValid() || !instances.contains(parentInst)) {
|
||||
handleInstanceHidden(instance, instance.internalInstance()->isHiddenInEditor(), true);
|
||||
handleInstanceLocked(instance, instance.internalInstance()->isLockedInEditor(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::createEditView3D()
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
@@ -860,7 +883,7 @@ QList<ServerNodeInstance> Qt5InformationNodeInstanceServer::createInstances(
|
||||
void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews()
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE")) {
|
||||
if (isQuick3DMode()) {
|
||||
createEditView3D();
|
||||
m_ModelNode3DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
|
||||
m_ModelNode3DImageViewRootItem);
|
||||
@@ -1243,6 +1266,7 @@ void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
||||
|
||||
if (!m_parentChangedSet.isEmpty()) {
|
||||
sendChildrenChangedCommand(QtHelpers::toList(m_parentChangedSet));
|
||||
updateLockedAndHiddenStates(m_parentChangedSet);
|
||||
m_parentChangedSet.clear();
|
||||
}
|
||||
|
||||
@@ -1307,7 +1331,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
|
||||
sendChildrenChangedCommand(instanceList);
|
||||
nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList));
|
||||
|
||||
if (qEnvironmentVariableIsSet("QMLDESIGNER_QUICK3D_MODE"))
|
||||
if (isQuick3DMode())
|
||||
setup3DEditView(instanceList, command.edit3dToolStates());
|
||||
|
||||
QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout,
|
||||
@@ -1621,6 +1645,110 @@ void Qt5InformationNodeInstanceServer::removeProperties(const RemovePropertiesCo
|
||||
render3DEditView();
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInstance &instance,
|
||||
bool enable, bool checkAncestors)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (!isQuick3DMode())
|
||||
return;
|
||||
|
||||
bool edit3dLocked = enable;
|
||||
if (!edit3dLocked || checkAncestors) {
|
||||
auto parentInst = instance.parent();
|
||||
while (!edit3dLocked && parentInst.isValid()) {
|
||||
edit3dLocked = parentInst.internalInstance()->isLockedInEditor();
|
||||
parentInst = parentInst.parent();
|
||||
}
|
||||
}
|
||||
|
||||
QObject *obj = instance.internalObject();
|
||||
auto node = qobject_cast<QQuick3DNode *>(obj);
|
||||
if (node)
|
||||
node->setProperty("_edit3dLocked", edit3dLocked);
|
||||
const auto children = obj->children();
|
||||
for (auto child : children) {
|
||||
if (hasInstanceForObject(child)) {
|
||||
const ServerNodeInstance childInstance = instanceForObject(child);
|
||||
if (childInstance.isValid()) {
|
||||
auto objInstance = childInstance.internalInstance();
|
||||
// Don't override explicit lock on children
|
||||
handleInstanceLocked(childInstance, edit3dLocked || objInstance->isLockedInEditor(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInstance &instance,
|
||||
bool enable, bool checkAncestors)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
if (!isQuick3DMode())
|
||||
return;
|
||||
|
||||
bool edit3dHidden = enable;
|
||||
if (!edit3dHidden || checkAncestors) {
|
||||
// We do not care about hidden status of non-3D ancestor nodes, as the 3D scene
|
||||
// can be considered a separate visual entity in the whole scene.
|
||||
auto parentInst = instance.parent();
|
||||
while (!edit3dHidden && parentInst.isValid() && qobject_cast<QQuick3DNode *>(parentInst.internalObject())) {
|
||||
edit3dHidden = parentInst.internalInstance()->isHiddenInEditor();
|
||||
parentInst = parentInst.parent();
|
||||
}
|
||||
}
|
||||
|
||||
auto node = qobject_cast<QQuick3DNode *>(instance.internalObject());
|
||||
if (node) {
|
||||
bool isInstanceHidden = false;
|
||||
auto getQuick3DInstanceAndHidden = [this, &isInstanceHidden](QQuick3DObject *obj) -> ServerNodeInstance {
|
||||
if (hasInstanceForObject(obj)) {
|
||||
const ServerNodeInstance instance = instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject())) {
|
||||
auto objInstance = instance.internalInstance();
|
||||
isInstanceHidden = objInstance->isHiddenInEditor();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
// Always make sure the hide status is correct on the node tree from this point on,
|
||||
// as changes in the node tree (reparenting, adding new nodes) can make the previously set
|
||||
// hide status based on ancestor unreliable.
|
||||
node->setProperty("_edit3dHidden", edit3dHidden);
|
||||
if (auto model = qobject_cast<QQuick3DModel *>(node))
|
||||
model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
const ServerNodeInstance quick3dInstance = getQuick3DInstanceAndHidden(childItem);
|
||||
if (quick3dInstance.isValid()) {
|
||||
// Don't override explicit hide in children
|
||||
handleInstanceHidden(quick3dInstance, edit3dHidden || isInstanceHidden, false);
|
||||
} else {
|
||||
// Children of components do not have instances, but will still need to be pickable
|
||||
std::function<void(QQuick3DNode *)> checkChildren;
|
||||
checkChildren = [&](QQuick3DNode *checkNode) {
|
||||
const auto childItems = checkNode->childItems();
|
||||
for (auto child : childItems) {
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(child))
|
||||
checkChildren(childNode);
|
||||
}
|
||||
if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) {
|
||||
QVariant value;
|
||||
if (!edit3dHidden)
|
||||
value = QVariant::fromValue(node);
|
||||
// Specify the actual pick target with dynamic property
|
||||
checkModel->setProperty("_pickTarget", value);
|
||||
checkModel->setPickable(!edit3dHidden);
|
||||
}
|
||||
};
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(childItem))
|
||||
checkChildren(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// update 3D view size when it changes in creator side
|
||||
void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewStateCommand &command)
|
||||
{
|
||||
|
||||
@@ -70,6 +70,9 @@ public:
|
||||
void changeState(const ChangeStateCommand &command) override;
|
||||
void removeProperties(const RemovePropertiesCommand &command) override;
|
||||
|
||||
void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override;
|
||||
void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override;
|
||||
|
||||
private slots:
|
||||
void handleSelectionChanged(const QVariant &objs);
|
||||
void handleObjectPropertyCommit(const QVariant &object, const QVariant &propName);
|
||||
@@ -127,6 +130,7 @@ private:
|
||||
void doRenderModelNode3DImageView();
|
||||
void doRenderModelNode2DImageView();
|
||||
QQuickView *createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem);
|
||||
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
|
||||
|
||||
QPointer<QQuickView> m_editView3D;
|
||||
QQuickItem *m_editView3DRootItem = nullptr;
|
||||
|
||||
@@ -57,7 +57,6 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo
|
||||
InstanceContainer::NodeFlags flags)
|
||||
{
|
||||
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
||||
setPickable(true, true, false);
|
||||
}
|
||||
|
||||
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
||||
@@ -74,71 +73,6 @@ QQuick3DNode *Quick3DNodeInstance::quick3DNode() const
|
||||
#endif
|
||||
}
|
||||
|
||||
void Quick3DNodeInstance::setPickable(bool enable, bool checkParent, bool applyToChildInstances)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
auto node = quick3DNode();
|
||||
if (node) {
|
||||
bool parentHidden = false;
|
||||
if (checkParent) {
|
||||
// First check if any parent node is already hidden. Never set pickable on that case.
|
||||
auto parentNode = node->parentNode();
|
||||
while (parentNode && !parentHidden) {
|
||||
parentHidden = QQuick3DNodePrivate::get(parentNode)->m_isHiddenInEditor;
|
||||
parentNode = parentNode->parentNode();
|
||||
}
|
||||
|
||||
}
|
||||
if (!parentHidden) {
|
||||
auto getQuick3DInstance = [this](QQuick3DObject *obj) -> Quick3DNodeInstance * {
|
||||
if (nodeInstanceServer()->hasInstanceForObject(obj)) {
|
||||
ServerNodeInstance instance = nodeInstanceServer()->instanceForObject(obj);
|
||||
if (instance.isValid() && qobject_cast<QQuick3DNode *>(instance.internalObject()))
|
||||
return static_cast<Quick3DNodeInstance *>(instance.internalInstance().data());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto childItems = node->childItems();
|
||||
for (auto childItem : childItems) {
|
||||
if (auto quick3dInstance = getQuick3DInstance(childItem)) {
|
||||
if (applyToChildInstances) {
|
||||
// Don't override explicit block in children
|
||||
if (!QQuick3DNodePrivate::get(quick3dInstance->quick3DNode())->m_isHiddenInEditor)
|
||||
quick3dInstance->setPickable(enable, false, true);
|
||||
}
|
||||
} else {
|
||||
// Children of components do not have instances, but will still need to be
|
||||
// pickable. These need to be set even if applyToChildInstances is false.
|
||||
std::function<void(QQuick3DNode *)> checkChildren;
|
||||
checkChildren = [&](QQuick3DNode *checkNode) {
|
||||
const auto childItems = checkNode->childItems();
|
||||
for (auto child : childItems) {
|
||||
if (auto childNode = qobject_cast<QQuick3DNode *>(child))
|
||||
checkChildren(childNode);
|
||||
}
|
||||
if (auto checkModel = qobject_cast<QQuick3DModel *>(checkNode)) {
|
||||
QVariant value;
|
||||
if (enable)
|
||||
value = QVariant::fromValue(node);
|
||||
// Specify the actual pick target with dynamic property
|
||||
checkModel->setProperty("_pickTarget", value);
|
||||
checkModel->setPickable(enable);
|
||||
}
|
||||
};
|
||||
checkChildren(node);
|
||||
}
|
||||
}
|
||||
if (qobject_cast<QQuick3DModel *>(node))
|
||||
setPropertyVariant("pickable", enable); // allow 3D objects to receive mouse clicks
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(enable)
|
||||
Q_UNUSED(checkParent)
|
||||
Q_UNUSED(applyToChildInstances)
|
||||
#endif
|
||||
}
|
||||
|
||||
Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object)
|
||||
{
|
||||
Pointer instance(new Quick3DNodeInstance(object));
|
||||
@@ -146,18 +80,13 @@ Quick3DNodeInstance::Pointer Quick3DNodeInstance::create(QObject *object)
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Quick3DNodeInstance::setHideInEditor(bool b)
|
||||
void Quick3DNodeInstance::setHiddenInEditor(bool b)
|
||||
{
|
||||
ObjectNodeInstance::setHiddenInEditor(b);
|
||||
#ifdef QUICK3D_MODULE
|
||||
QQuick3DNodePrivate *privateNode = QQuick3DNodePrivate::get(quick3DNode());
|
||||
if (privateNode) {
|
||||
if (privateNode)
|
||||
privateNode->setIsHiddenInEditor(b);
|
||||
|
||||
// Hidden objects should not be pickable
|
||||
setPickable(!b, true, true);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(b)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
~Quick3DNodeInstance() override;
|
||||
static Pointer create(QObject *objectToBeWrapped);
|
||||
void setHideInEditor(bool b) override;
|
||||
void setHiddenInEditor(bool b) override;
|
||||
void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
||||
InstanceContainer::NodeFlags flags) override;
|
||||
|
||||
@@ -53,7 +53,6 @@ protected:
|
||||
private:
|
||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||
QQuick3DNode *quick3DNode() const;
|
||||
void setPickable(bool enable, bool checkParent, bool applyToChildInstances);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -270,6 +270,9 @@ ServerNodeInstance ServerNodeInstance::create(NodeInstanceServer *nodeInstanceSe
|
||||
|
||||
instance.internalInstance()->initialize(instance.m_nodeInstance, instanceContainer.metaFlags());
|
||||
|
||||
// Handle hidden state to initialize pickable state
|
||||
nodeInstanceServer->handleInstanceHidden(instance, false, false);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -346,9 +349,16 @@ void ServerNodeInstance::setPropertyBinding(const PropertyName &name, const QStr
|
||||
m_nodeInstance->setPropertyBinding(name, expression);
|
||||
}
|
||||
|
||||
void ServerNodeInstance::setHideInEditor(bool b)
|
||||
void ServerNodeInstance::setHiddenInEditor(bool b)
|
||||
{
|
||||
m_nodeInstance->setHideInEditor(b);
|
||||
m_nodeInstance->setHiddenInEditor(b);
|
||||
m_nodeInstance->nodeInstanceServer()->handleInstanceHidden(*this, b, true);
|
||||
}
|
||||
|
||||
void ServerNodeInstance::setLockedInEditor(bool b)
|
||||
{
|
||||
m_nodeInstance->setLockedInEditor(b);
|
||||
m_nodeInstance->nodeInstanceServer()->handleInstanceLocked(*this, b, true);
|
||||
}
|
||||
|
||||
void ServerNodeInstance::resetProperty(const PropertyName &name)
|
||||
|
||||
@@ -185,7 +185,8 @@ private: // functions
|
||||
|
||||
void setPropertyBinding(const PropertyName &name, const QString &expression);
|
||||
|
||||
void setHideInEditor(bool b);
|
||||
void setHiddenInEditor(bool b);
|
||||
void setLockedInEditor(bool b);
|
||||
|
||||
void resetProperty(const PropertyName &name);
|
||||
void refreshProperty(const PropertyName &name);
|
||||
|
||||
@@ -102,14 +102,21 @@ void Edit3DCanvas::resizeEvent(QResizeEvent *e)
|
||||
|
||||
void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e)
|
||||
{
|
||||
QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"));
|
||||
if (!data.isEmpty()) {
|
||||
QDataStream stream(data);
|
||||
stream >> m_itemLibraryEntry;
|
||||
bool canDrop = NodeHints::fromItemLibraryEntry(m_itemLibraryEntry).canBeDroppedInView3D();
|
||||
// Block all drags if scene root node is locked
|
||||
ModelNode node;
|
||||
if (m_parent->view()->hasModelNodeForInternalId(m_activeScene))
|
||||
node = m_parent->view()->modelNodeForInternalId(m_activeScene);
|
||||
|
||||
if (canDrop)
|
||||
e->accept();
|
||||
// Allow drop when there is no valid active scene, as the drop goes under the root node of
|
||||
// the document in that case.
|
||||
if (!node.isValid() || !ModelNode::isThisOrAncestorLocked(node)) {
|
||||
QByteArray data = e->mimeData()->data(QStringLiteral("application/vnd.bauhaus.itemlibraryinfo"));
|
||||
if (!data.isEmpty()) {
|
||||
QDataStream stream(data);
|
||||
stream >> m_itemLibraryEntry;
|
||||
if (NodeHints::fromItemLibraryEntry(m_itemLibraryEntry).canBeDroppedInView3D())
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user