QmlDesigner: Add positioning methods to QmlVisualNode

QmlVisualNode would be able to:
    1. Set a position for the visual node
    2. Translate the position of the visual node
    3. The visual node could be scattered
    4. Get the related position of visual node
All these methods will work for either 2D or 3D nodes.
Also, a potential bug has been fixed for the Position. It was assumed
that if a position equals to 0, it's not a valid position, but
now it's handled by this change.

Change-Id: I9dd59dbe0d14084087ff39bd14d2a783d24a5efd
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2022-11-07 16:50:23 +02:00
parent 0228cfef1c
commit c1f3dc4f54
2 changed files with 90 additions and 23 deletions

View File

@@ -26,23 +26,24 @@ class QMLDESIGNERCORE_EXPORT QmlVisualNode : public QmlObjectNode
friend class QmlAnchors; friend class QmlAnchors;
public: public:
class Position class Position : public QVector3D
{ {
friend class QmlVisualNode; friend class QmlVisualNode;
public: public:
Position() {} Position() {}
Position(const QPointF &position) : Position(const QPointF &position) :
m_2dPos(position) QVector3D(position)
{} {}
Position(const QVector3D &position) : Position(const QVector3D &position) :
m_3dPos(position) QVector3D(position),
m_is3D(true)
{} {}
bool is3D() const;
QList<QPair<PropertyName, QVariant>> propertyPairList() const; QList<QPair<PropertyName, QVariant>> propertyPairList() const;
private: private:
QPointF m_2dPos; bool m_is3D = false;
QVector3D m_3dPos;
}; };
QmlVisualNode() = default; QmlVisualNode() = default;
@@ -65,7 +66,10 @@ public:
void setVisibilityOverride(bool visible); void setVisibilityOverride(bool visible);
bool visibilityOverride() const; bool visibilityOverride() const;
void initializePosition(const Position &position); void scatter(const ModelNode &targetNode, const std::optional<int> &offset);
void translate(const QVector3D &vector);
void setPosition(const Position &position);
Position position() const;
static bool isItemOr3DNode(const ModelNode &modelNode); static bool isItemOr3DNode(const ModelNode &modelNode);

View File

@@ -23,6 +23,7 @@
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QFileInfo> #include <QFileInfo>
#include <QDir> #include <QDir>
#include <QRandomGenerator>
namespace QmlDesigner { namespace QmlDesigner {
@@ -156,21 +157,81 @@ bool QmlVisualNode::visibilityOverride() const
return false; return false;
} }
void QmlVisualNode::scatter(const ModelNode &targetNode, const std::optional<int> &offset)
{
if (!isValid())
return;
if (targetNode.metaInfo().isValid() && targetNode.metaInfo().isLayoutable())
return;
bool scatter = false;
const QList<ModelNode> targetDirectNodes = targetNode.directSubModelNodes();
for (const ModelNode &childNode : targetDirectNodes) {
if (childNode == modelNode())
continue;
if (isValidQmlVisualNode(childNode)) {
Position childPos = QmlVisualNode(childNode).position();
if (qFuzzyCompare(position().distanceToPoint(childPos), 0.f)) {
scatter = true;
break;
}
}
}
if (!scatter)
return;
if (offset.has_value()) { // offset
double offsetValue = offset.value();
this->translate(QVector3D(offsetValue, offsetValue, offsetValue));
} else { // scatter in range
const double scatterRange = 20.;
double x = QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2;
double y = QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2;
double z = (modelNode().metaInfo().isQtQuick3DNode())
? QRandomGenerator::global()->generateDouble() * scatterRange - scatterRange / 2
: 0.;
this->translate(QVector3D(x, y, z));
}
}
void QmlVisualNode::translate(const QVector3D &vector)
{
setPosition(position() + vector);
}
void QmlVisualNode::setDoubleProperty(const PropertyName &name, double value) void QmlVisualNode::setDoubleProperty(const PropertyName &name, double value)
{ {
modelNode().variantProperty(name).setValue(value); modelNode().variantProperty(name).setValue(value);
} }
void QmlVisualNode::initializePosition(const QmlVisualNode::Position &position) void QmlVisualNode::setPosition(const QmlVisualNode::Position &position)
{ {
if (!position.m_2dPos.isNull()) { if (!isValid())
setDoubleProperty("x", qRound(position.m_2dPos.x())); return;
setDoubleProperty("y", qRound(position.m_2dPos.y()));
} else if (!position.m_3dPos.isNull()) { setDoubleProperty("x", position.x());
setDoubleProperty("x", position.m_3dPos.x()); setDoubleProperty("y", position.y());
setDoubleProperty("y", position.m_3dPos.y());
setDoubleProperty("z", position.m_3dPos.z()); if (position.is3D() && modelNode().metaInfo().isQtQuick3DNode())
setDoubleProperty("z", position.z());
}
QmlVisualNode::Position QmlVisualNode::position() const
{
if (!isValid())
return {};
double x = modelNode().variantProperty("x").value().toDouble();
double y = modelNode().variantProperty("y").value().toDouble();
if (modelNode().metaInfo().isQtQuick3DModel()) {
double z = modelNode().variantProperty("z").value().toDouble();
return Position(QVector3D(x,y,z));
} }
return Position(QPointF(x,y));
} }
QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
@@ -230,7 +291,7 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view,
if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) { if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) {
ModelNode rootModelNode = rewriterView->rootModelNode(); ModelNode rootModelNode = rewriterView->rootModelNode();
inputModel->detachView(rewriterView.data()); inputModel->detachView(rewriterView.data());
QmlVisualNode(rootModelNode).initializePosition(position); QmlVisualNode(rootModelNode).setPosition(position);
ModelMerger merger(view); ModelMerger merger(view);
return merger.insertModel(rootModelNode); return merger.insertModel(rootModelNode);
} }
@@ -496,18 +557,20 @@ QmlModelState QmlModelStateGroup::state(const QString &name) const
return QmlModelState(); return QmlModelState();
} }
bool QmlVisualNode::Position::is3D() const
{
return m_is3D;
}
QList<QPair<PropertyName, QVariant> > QmlVisualNode::Position::propertyPairList() const QList<QPair<PropertyName, QVariant> > QmlVisualNode::Position::propertyPairList() const
{ {
QList<QPair<PropertyName, QVariant> > propertyPairList; QList<QPair<PropertyName, QVariant> > propertyPairList;
if (!m_2dPos.isNull()) { propertyPairList.append({"x", QVariant(qRound(x()))});
propertyPairList.append({"x", QVariant(qRound(m_2dPos.x()))}); propertyPairList.append({"y", QVariant(qRound(y()))});
propertyPairList.append({"y", QVariant(qRound(m_2dPos.y()))});
} else if (!m_3dPos.isNull()) { if (m_is3D)
propertyPairList.append({"x", QVariant(m_3dPos.x())}); propertyPairList.append({"z", QVariant(z())});
propertyPairList.append({"y", QVariant(m_3dPos.y())});
propertyPairList.append({"z", QVariant(m_3dPos.z())});
}
return propertyPairList; return propertyPairList;
} }