QmlDesigner: Add anchor tracing

Change-Id: Ie687940dbedd820cbfd5deb9323f4bad3cac0ea2
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-05-24 01:06:58 +02:00
parent 18d65b4546
commit 244ed5008e
4 changed files with 319 additions and 111 deletions

View File

@@ -5,6 +5,8 @@
namespace QmlDesigner { namespace QmlDesigner {
static auto category = ModelTracing::category;
AnchorLine::AnchorLine() AnchorLine::AnchorLine()
: m_qmlItemNode(QmlItemNode()) : m_qmlItemNode(QmlItemNode())
, m_type(AnchorLineInvalid) , m_type(AnchorLineInvalid)
@@ -20,8 +22,11 @@ AnchorLineType AnchorLine::type() const
return m_type; return m_type;
} }
bool AnchorLine::isValid() const bool AnchorLine::isValid(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"anchor line is valid", category(), keyValue("caller location", sl)};
return m_type != AnchorLineInvalid && m_qmlItemNode.isValid(); return m_type != AnchorLineInvalid && m_qmlItemNode.isValid();
} }

View File

@@ -11,11 +11,14 @@ namespace QmlDesigner {
class QMLDESIGNER_EXPORT AnchorLine class QMLDESIGNER_EXPORT AnchorLine
{ {
protected:
using SL = ModelTracing::SourceLocation;
public: public:
AnchorLine(); AnchorLine();
AnchorLine(const QmlItemNode &qmlItemNode, AnchorLineType type); AnchorLine(const QmlItemNode &qmlItemNode, AnchorLineType type);
AnchorLineType type() const; AnchorLineType type() const;
bool isValid() const; bool isValid(SL sl = {}) const;
static bool isHorizontalAnchorLine(AnchorLineType anchorline); static bool isHorizontalAnchorLine(AnchorLineType anchorline);
static bool isVerticalAnchorLine(AnchorLineType anchorline); static bool isVerticalAnchorLine(AnchorLineType anchorline);

View File

@@ -9,6 +9,8 @@
namespace QmlDesigner { namespace QmlDesigner {
static auto category = ModelTracing::category;
static PropertyName lineTypeToString(AnchorLineType lineType) static PropertyName lineTypeToString(AnchorLineType lineType)
{ {
switch (lineType) { switch (lineType) {
@@ -114,19 +116,28 @@ QmlItemNode QmlAnchors::qmlItemNode() const
return m_qmlItemNode; return m_qmlItemNode;
} }
bool QmlAnchors::modelHasAnchors() const bool QmlAnchors::modelHasAnchors(SL sl) const
{ {
return modelHasAnchor(AnchorLineLeft) using NanotraceHR::keyValue;
|| modelHasAnchor(AnchorLineRight) NanotraceHR::Tracer tracer{"qml anchors has anchors",
|| modelHasAnchor(AnchorLineTop) category(),
|| modelHasAnchor(AnchorLineBottom) keyValue("model node", *this),
|| modelHasAnchor(AnchorLineHorizontalCenter) keyValue("caller location", sl)};
|| modelHasAnchor(AnchorLineVerticalCenter)
|| modelHasAnchor(AnchorLineBaseline); return modelHasAnchor(AnchorLineLeft) || modelHasAnchor(AnchorLineRight)
|| modelHasAnchor(AnchorLineTop) || modelHasAnchor(AnchorLineBottom)
|| modelHasAnchor(AnchorLineHorizontalCenter) || modelHasAnchor(AnchorLineVerticalCenter)
|| modelHasAnchor(AnchorLineBaseline);
} }
bool QmlAnchors::modelHasAnchor(AnchorLineType sourceAnchorLineType) const bool QmlAnchors::modelHasAnchor(AnchorLineType sourceAnchorLineType, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors has anchor",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLineType); const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLineType);
if (sourceAnchorLineType & AnchorLineFill) if (sourceAnchorLineType & AnchorLineFill)
@@ -138,20 +149,37 @@ bool QmlAnchors::modelHasAnchor(AnchorLineType sourceAnchorLineType) const
return qmlItemNode().modelNode().hasBindingProperty(anchorPropertyName(sourceAnchorLineType)); return qmlItemNode().modelNode().hasBindingProperty(anchorPropertyName(sourceAnchorLineType));
} }
AnchorLine QmlAnchors::modelAnchor(AnchorLineType sourceAnchorLineType) const AnchorLine QmlAnchors::modelAnchor(AnchorLineType sourceAnchorLineType, SL sl) const
{ {
QPair<PropertyName, ModelNode> targetAnchorLinePair; using NanotraceHR::keyValue;
if (sourceAnchorLineType & AnchorLineFill && qmlItemNode().modelNode().hasBindingProperty("anchors.fill")) { NanotraceHR::Tracer tracer{"qml anchors get anchor",
targetAnchorLinePair.second = qmlItemNode().modelNode().bindingProperty("anchors.fill").resolveToModelNode(); category(),
targetAnchorLinePair.first = lineTypeToString(sourceAnchorLineType); keyValue("model node", *this),
} else if (sourceAnchorLineType & AnchorLineCenter && qmlItemNode().modelNode().hasBindingProperty("anchors.centerIn")) { keyValue("caller location", sl)};
targetAnchorLinePair.second = qmlItemNode().modelNode().bindingProperty("anchors.centerIn").resolveToModelNode();
targetAnchorLinePair.first = lineTypeToString(sourceAnchorLineType); QPair<PropertyName, ModelNode> targetAnchorLinePair;
} else { if (sourceAnchorLineType & AnchorLineFill
AbstractProperty binding = qmlItemNode().modelNode().bindingProperty(anchorPropertyName(sourceAnchorLineType)).resolveToProperty(); && qmlItemNode().modelNode().hasBindingProperty("anchors.fill")) {
targetAnchorLinePair.first = binding.name().toByteArray(); targetAnchorLinePair.second = qmlItemNode()
targetAnchorLinePair.second = binding.parentModelNode(); .modelNode()
} .bindingProperty("anchors.fill")
.resolveToModelNode();
targetAnchorLinePair.first = lineTypeToString(sourceAnchorLineType);
} else if (sourceAnchorLineType & AnchorLineCenter
&& qmlItemNode().modelNode().hasBindingProperty("anchors.centerIn")) {
targetAnchorLinePair.second = qmlItemNode()
.modelNode()
.bindingProperty("anchors.centerIn")
.resolveToModelNode();
targetAnchorLinePair.first = lineTypeToString(sourceAnchorLineType);
} else {
AbstractProperty binding = qmlItemNode()
.modelNode()
.bindingProperty(anchorPropertyName(sourceAnchorLineType))
.resolveToProperty();
targetAnchorLinePair.first = binding.name().toByteArray();
targetAnchorLinePair.second = binding.parentModelNode();
}
AnchorLineType targetAnchorLine = propertyNameToLineType(targetAnchorLinePair.first); AnchorLineType targetAnchorLine = propertyNameToLineType(targetAnchorLinePair.first);
@@ -162,35 +190,53 @@ AnchorLine QmlAnchors::modelAnchor(AnchorLineType sourceAnchorLineType) const
return AnchorLine(QmlItemNode(targetAnchorLinePair.second), targetAnchorLine); return AnchorLine(QmlItemNode(targetAnchorLinePair.second), targetAnchorLine);
} }
bool QmlAnchors::isValid() const bool QmlAnchors::isValid(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors is valid",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return m_qmlItemNode.isValid(); return m_qmlItemNode.isValid();
} }
void QmlAnchors::setAnchor(AnchorLineType sourceAnchorLine, void QmlAnchors::setAnchor(AnchorLineType sourceAnchorLine,
const QmlItemNode &targetQmlItemNode, const QmlItemNode &targetQmlItemNode,
AnchorLineType targetAnchorLine) AnchorLineType targetAnchorLine,
SL sl)
{ {
qmlItemNode().view()->executeInTransaction("QmlAnchors::setAnchor", [this, sourceAnchorLine, targetQmlItemNode, targetAnchorLine](){ using NanotraceHR::keyValue;
if (qmlItemNode().isInBaseState()) { NanotraceHR::Tracer tracer{"qml anchors set anchor",
if ((qmlItemNode().nodeInstance().hasAnchor("anchors.fill") && (sourceAnchorLine & AnchorLineFill)) category(),
|| ((qmlItemNode().nodeInstance().hasAnchor("anchors.centerIn") && (sourceAnchorLine & AnchorLineCenter)))) { keyValue("model node", *this),
removeAnchor(sourceAnchorLine); keyValue("caller location", sl)};
}
const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLine); qmlItemNode().view()->executeInTransaction(
ModelNode targetModelNode = targetQmlItemNode.modelNode(); "QmlAnchors::setAnchor", [this, sourceAnchorLine, targetQmlItemNode, targetAnchorLine]() {
QString targetExpression = targetModelNode.validId(); if (qmlItemNode().isInBaseState()) {
if (targetQmlItemNode.modelNode() == qmlItemNode().modelNode().parentProperty().parentModelNode()) if ((qmlItemNode().nodeInstance().hasAnchor("anchors.fill")
targetExpression = QLatin1String("parent"); && (sourceAnchorLine & AnchorLineFill))
if (sourceAnchorLine != AnchorLineCenter && sourceAnchorLine != AnchorLineFill) || ((qmlItemNode().nodeInstance().hasAnchor("anchors.centerIn")
targetExpression = targetExpression + QLatin1Char('.') + QString::fromLatin1(lineTypeToString(targetAnchorLine)); && (sourceAnchorLine & AnchorLineCenter)))) {
qmlItemNode().modelNode().bindingProperty(propertyName).setExpression(targetExpression); removeAnchor(sourceAnchorLine);
} }
});
const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLine);
ModelNode targetModelNode = targetQmlItemNode.modelNode();
QString targetExpression = targetModelNode.validId();
if (targetQmlItemNode.modelNode()
== qmlItemNode().modelNode().parentProperty().parentModelNode())
targetExpression = QLatin1String("parent");
if (sourceAnchorLine != AnchorLineCenter && sourceAnchorLine != AnchorLineFill)
targetExpression = targetExpression + QLatin1Char('.')
+ QString::fromLatin1(lineTypeToString(targetAnchorLine));
qmlItemNode().modelNode().bindingProperty(propertyName).setExpression(targetExpression);
}
});
} }
bool detectHorizontalCycle(const ModelNode &node, QList<ModelNode> knownNodeList) static bool detectHorizontalCycle(const ModelNode &node, QList<ModelNode> knownNodeList)
{ {
if (knownNodeList.contains(node)) if (knownNodeList.contains(node))
return true; return true;
@@ -227,7 +273,7 @@ bool detectHorizontalCycle(const ModelNode &node, QList<ModelNode> knownNodeList
return false; return false;
} }
bool detectVerticalCycle(const ModelNode &node, QList<ModelNode> knownNodeList) static bool detectVerticalCycle(const ModelNode &node, QList<ModelNode> knownNodeList)
{ {
if (!node.isValid()) if (!node.isValid())
return false; return false;
@@ -267,8 +313,14 @@ bool detectVerticalCycle(const ModelNode &node, QList<ModelNode> knownNodeList)
return false; return false;
} }
bool QmlAnchors::canAnchor(const QmlItemNode &targetModelNode) const bool QmlAnchors::canAnchor(const QmlItemNode &targetModelNode, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors can anchor",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (!qmlItemNode().isInBaseState()) if (!qmlItemNode().isInBaseState())
return false; return false;
@@ -282,8 +334,15 @@ bool QmlAnchors::canAnchor(const QmlItemNode &targetModelNode) const
} }
AnchorLineType QmlAnchors::possibleAnchorLines(AnchorLineType sourceAnchorLineType, AnchorLineType QmlAnchors::possibleAnchorLines(AnchorLineType sourceAnchorLineType,
const QmlItemNode &targetQmlItemNode) const const QmlItemNode &targetQmlItemNode,
SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors possible anchor lines",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (!canAnchor(targetQmlItemNode)) if (!canAnchor(targetQmlItemNode))
return AnchorLineInvalid; return AnchorLineInvalid;
@@ -300,8 +359,14 @@ AnchorLineType QmlAnchors::possibleAnchorLines(AnchorLineType sourceAnchorLineTy
return AnchorLineInvalid; return AnchorLineInvalid;
} }
AnchorLine QmlAnchors::instanceAnchor(AnchorLineType sourceAnchorLine) const AnchorLine QmlAnchors::instanceAnchor(AnchorLineType sourceAnchorLine, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors get instance anchor",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
QPair<PropertyName, qint32> targetAnchorLinePair; QPair<PropertyName, qint32> targetAnchorLinePair;
if (qmlItemNode().nodeInstance().hasAnchor("anchors.fill") && (sourceAnchorLine & AnchorLineFill)) { if (qmlItemNode().nodeInstance().hasAnchor("anchors.fill") && (sourceAnchorLine & AnchorLineFill)) {
targetAnchorLinePair = qmlItemNode().nodeInstance().anchor("anchors.fill"); targetAnchorLinePair = qmlItemNode().nodeInstance().anchor("anchors.fill");
@@ -324,9 +389,15 @@ AnchorLine QmlAnchors::instanceAnchor(AnchorLineType sourceAnchorLine) const
return AnchorLine(QmlItemNode(qmlItemNode().nodeForInstance(qmlItemNode().nodeInstanceView()->instanceForId(targetAnchorLinePair.second))), targetAnchorLine); return AnchorLine(QmlItemNode(qmlItemNode().nodeForInstance(qmlItemNode().nodeInstanceView()->instanceForId(targetAnchorLinePair.second))), targetAnchorLine);
} }
void QmlAnchors::removeAnchor(AnchorLineType sourceAnchorLine) void QmlAnchors::removeAnchor(AnchorLineType sourceAnchorLine, SL sl)
{ {
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeAnchor", [this, sourceAnchorLine](){ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors remove anchor",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeAnchor", [this, sourceAnchorLine]() {
if (qmlItemNode().isInBaseState()) { if (qmlItemNode().isInBaseState()) {
const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLine); const PropertyNameView propertyName = anchorPropertyName(sourceAnchorLine);
if (qmlItemNode().modelNode().hasProperty("anchors.fill") if (qmlItemNode().modelNode().hasProperty("anchors.fill")
@@ -349,9 +420,15 @@ void QmlAnchors::removeAnchor(AnchorLineType sourceAnchorLine)
}); });
} }
void QmlAnchors::removeAnchors() void QmlAnchors::removeAnchors(SL sl)
{ {
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeAnchors", [this](){ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors remove anchors",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeAnchors", [this]() {
if (qmlItemNode().nodeInstance().hasAnchor("anchors.fill")) if (qmlItemNode().nodeInstance().hasAnchor("anchors.fill"))
qmlItemNode().modelNode().removeProperty("anchors.fill"); qmlItemNode().modelNode().removeProperty("anchors.fill");
if (qmlItemNode().nodeInstance().hasAnchor("anchors.centerIn")) if (qmlItemNode().nodeInstance().hasAnchor("anchors.centerIn"))
@@ -373,8 +450,14 @@ void QmlAnchors::removeAnchors()
}); });
} }
bool QmlAnchors::instanceHasAnchor(AnchorLineType sourceAnchorLine) const bool QmlAnchors::instanceHasAnchor(AnchorLineType sourceAnchorLine, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance has anchor",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (!qmlItemNode().isValid()) if (!qmlItemNode().isValid())
return false; return false;
@@ -390,55 +473,102 @@ bool QmlAnchors::instanceHasAnchor(AnchorLineType sourceAnchorLine) const
return qmlItemNode().nodeInstance().hasAnchor(propertyName); return qmlItemNode().nodeInstance().hasAnchor(propertyName);
} }
bool QmlAnchors::instanceHasAnchors() const bool QmlAnchors::instanceHasAnchors(SL sl) const
{ {
return instanceHasAnchor(AnchorLineLeft) || using NanotraceHR::keyValue;
instanceHasAnchor(AnchorLineRight) || NanotraceHR::Tracer tracer{"qml anchors instance has anchors",
instanceHasAnchor(AnchorLineTop) || category(),
instanceHasAnchor(AnchorLineBottom) || keyValue("model node", *this),
instanceHasAnchor(AnchorLineHorizontalCenter) || keyValue("caller location", sl)};
instanceHasAnchor(AnchorLineVerticalCenter) ||
instanceHasAnchor(AnchorLineBaseline); return instanceHasAnchor(AnchorLineLeft) || instanceHasAnchor(AnchorLineRight)
|| instanceHasAnchor(AnchorLineTop) || instanceHasAnchor(AnchorLineBottom)
|| instanceHasAnchor(AnchorLineHorizontalCenter)
|| instanceHasAnchor(AnchorLineVerticalCenter) || instanceHasAnchor(AnchorLineBaseline);
} }
QRectF contentRect(const NodeInstance &nodeInstance) static QRectF contentRect(const NodeInstance &nodeInstance)
{ {
QRectF contentRect(nodeInstance.position(), nodeInstance.size()); QRectF contentRect(nodeInstance.position(), nodeInstance.size());
return nodeInstance.contentTransform().mapRect(contentRect); return nodeInstance.contentTransform().mapRect(contentRect);
} }
double QmlAnchors::instanceLeftAnchorLine() const double QmlAnchors::instanceLeftAnchorLine(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance left anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return contentRect(qmlItemNode().nodeInstance()).x(); return contentRect(qmlItemNode().nodeInstance()).x();
} }
double QmlAnchors::instanceTopAnchorLine() const double QmlAnchors::instanceTopAnchorLine(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance top anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return contentRect(qmlItemNode().nodeInstance()).y(); return contentRect(qmlItemNode().nodeInstance()).y();
} }
double QmlAnchors::instanceRightAnchorLine() const double QmlAnchors::instanceRightAnchorLine(SL sl) const
{ {
return contentRect(qmlItemNode().nodeInstance()).x() + contentRect(qmlItemNode().nodeInstance()).width(); using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance right anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return contentRect(qmlItemNode().nodeInstance()).x()
+ contentRect(qmlItemNode().nodeInstance()).width();
} }
double QmlAnchors::instanceBottomAnchorLine() const double QmlAnchors::instanceBottomAnchorLine(SL sl) const
{ {
return contentRect(qmlItemNode().nodeInstance()).y() + contentRect(qmlItemNode().nodeInstance()).height(); using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance bottom anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return contentRect(qmlItemNode().nodeInstance()).y()
+ contentRect(qmlItemNode().nodeInstance()).height();
} }
double QmlAnchors::instanceHorizontalCenterAnchorLine() const double QmlAnchors::instanceHorizontalCenterAnchorLine(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance horizontal center anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return (instanceLeftAnchorLine() + instanceRightAnchorLine()) / 2.0; return (instanceLeftAnchorLine() + instanceRightAnchorLine()) / 2.0;
} }
double QmlAnchors::instanceVerticalCenterAnchorLine() const double QmlAnchors::instanceVerticalCenterAnchorLine(SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance vertical center anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return (instanceBottomAnchorLine() + instanceTopAnchorLine()) / 2.0; return (instanceBottomAnchorLine() + instanceTopAnchorLine()) / 2.0;
} }
double QmlAnchors::instanceAnchorLine(AnchorLineType anchorLine) const double QmlAnchors::instanceAnchorLine(AnchorLineType anchorLine, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance anchor line",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
switch (anchorLine) { switch (anchorLine) {
case AnchorLineLeft: return instanceLeftAnchorLine(); case AnchorLineLeft: return instanceLeftAnchorLine();
case AnchorLineTop: return instanceTopAnchorLine(); case AnchorLineTop: return instanceTopAnchorLine();
@@ -450,14 +580,26 @@ double QmlAnchors::instanceAnchorLine(AnchorLineType anchorLine) const
} }
} }
void QmlAnchors::setMargin(AnchorLineType sourceAnchorLineType, double margin) const void QmlAnchors::setMargin(AnchorLineType sourceAnchorLineType, double margin, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors set margin",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
PropertyNameView propertyName = marginPropertyName(sourceAnchorLineType); PropertyNameView propertyName = marginPropertyName(sourceAnchorLineType);
qmlItemNode().setVariantProperty(propertyName, qRound(margin)); qmlItemNode().setVariantProperty(propertyName, qRound(margin));
} }
bool QmlAnchors::instanceHasMargin(AnchorLineType sourceAnchorLineType) const bool QmlAnchors::instanceHasMargin(AnchorLineType sourceAnchorLineType, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance has margin",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return !qIsNull(instanceMargin(sourceAnchorLineType)); return !qIsNull(instanceMargin(sourceAnchorLineType));
} }
@@ -516,38 +658,68 @@ static bool checkForVerticalCycleRecusive(const QmlAnchors &anchors, QList<QmlIt
return false; return false;
} }
bool QmlAnchors::checkForHorizontalCycle(const QmlItemNode &sourceItem) const bool QmlAnchors::checkForHorizontalCycle(const QmlItemNode &sourceItem, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors check for horizontal cycle",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
QList<QmlItemNode> visitedItems; QList<QmlItemNode> visitedItems;
visitedItems.append(sourceItem); visitedItems.append(sourceItem);
return checkForHorizontalCycleRecusive(*this, visitedItems); return checkForHorizontalCycleRecusive(*this, visitedItems);
} }
bool QmlAnchors::checkForVerticalCycle(const QmlItemNode &sourceItem) const bool QmlAnchors::checkForVerticalCycle(const QmlItemNode &sourceItem, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors check for vertical cycle",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
QList<QmlItemNode> visitedItems; QList<QmlItemNode> visitedItems;
visitedItems.append(sourceItem); visitedItems.append(sourceItem);
return checkForVerticalCycleRecusive(*this, visitedItems); return checkForVerticalCycleRecusive(*this, visitedItems);
} }
double QmlAnchors::instanceMargin(AnchorLineType sourceAnchorLineType) const double QmlAnchors::instanceMargin(AnchorLineType sourceAnchorLineType, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors instance margin",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
return qmlItemNode().nodeInstance().property(marginPropertyName(sourceAnchorLineType)).toDouble(); return qmlItemNode().nodeInstance().property(marginPropertyName(sourceAnchorLineType)).toDouble();
} }
void QmlAnchors::removeMargin(AnchorLineType sourceAnchorLineType) void QmlAnchors::removeMargin(AnchorLineType sourceAnchorLineType, SL sl)
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors remove margin",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (qmlItemNode().isInBaseState()) { if (qmlItemNode().isInBaseState()) {
PropertyNameView propertyName = marginPropertyName(sourceAnchorLineType); PropertyNameView propertyName = marginPropertyName(sourceAnchorLineType);
qmlItemNode().modelNode().removeProperty(propertyName); qmlItemNode().modelNode().removeProperty(propertyName);
} }
} }
void QmlAnchors::removeMargins() void QmlAnchors::removeMargins(SL sl)
{ {
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeMargins", [this](){ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors remove margins",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
qmlItemNode().view()->executeInTransaction("QmlAnchors::removeMargins", [this]() {
removeMargin(AnchorLineLeft); removeMargin(AnchorLineLeft);
removeMargin(AnchorLineRight); removeMargin(AnchorLineRight);
removeMargin(AnchorLineTop); removeMargin(AnchorLineTop);
@@ -557,24 +729,42 @@ void QmlAnchors::removeMargins()
}); });
} }
void QmlAnchors::fill() void QmlAnchors::fill(SL sl)
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors fill",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (instanceHasAnchors()) if (instanceHasAnchors())
removeAnchors(); removeAnchors();
qmlItemNode().modelNode().bindingProperty("anchors.fill").setExpression(QLatin1String("parent")); qmlItemNode().modelNode().bindingProperty("anchors.fill").setExpression(QLatin1String("parent"));
} }
void QmlAnchors::centerIn() void QmlAnchors::centerIn(SL sl)
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors center in",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (instanceHasAnchors()) if (instanceHasAnchors())
removeAnchors(); removeAnchors();
qmlItemNode().modelNode().bindingProperty("anchors.centerIn").setExpression(QLatin1String("parent")); qmlItemNode().modelNode().bindingProperty("anchors.centerIn").setExpression(QLatin1String("parent"));
} }
bool QmlAnchors::checkForCycle(AnchorLineType anchorLineTyp, const QmlItemNode &sourceItem) const bool QmlAnchors::checkForCycle(AnchorLineType anchorLineTyp, const QmlItemNode &sourceItem, SL sl) const
{ {
using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"qml anchors check for cycle",
category(),
keyValue("model node", *this),
keyValue("caller location", sl)};
if (anchorLineTyp & AnchorLineHorizontalMask) if (anchorLineTyp & AnchorLineHorizontalMask)
return checkForHorizontalCycle(sourceItem); return checkForHorizontalCycle(sourceItem);
else else

View File

@@ -11,50 +11,60 @@ namespace QmlDesigner {
class QMLDESIGNER_EXPORT QmlAnchors class QMLDESIGNER_EXPORT QmlAnchors
{ {
protected:
using SL = ModelTracing::SourceLocation;
public: public:
QmlAnchors(const QmlItemNode &fxItemNode); QmlAnchors(const QmlItemNode &fxItemNode);
bool isValid() const; bool isValid(SL sl = {}) const;
void setAnchor(AnchorLineType sourceAnchorLineType, void setAnchor(AnchorLineType sourceAnchorLineType,
const QmlItemNode &targetModelNode, const QmlItemNode &targetModelNode,
AnchorLineType targetAnchorLineType); AnchorLineType targetAnchorLineType,
bool canAnchor(const QmlItemNode &targetModelNode) const; SL sl = {});
bool canAnchor(const QmlItemNode &targetModelNode, SL sl = {}) const;
AnchorLineType possibleAnchorLines(AnchorLineType sourceAnchorLineType, AnchorLineType possibleAnchorLines(AnchorLineType sourceAnchorLineType,
const QmlItemNode &targetModelNode) const; const QmlItemNode &targetModelNode,
AnchorLine instanceAnchor(AnchorLineType sourceAnchorLineType) const; SL sl = {}) const;
AnchorLine instanceAnchor(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
void removeAnchor(AnchorLineType sourceAnchorLineType); void removeAnchor(AnchorLineType sourceAnchorLineType, SL sl = {});
void removeAnchors(); void removeAnchors(SL sl = {});
bool instanceHasAnchor(AnchorLineType sourceAnchorLineType) const; bool instanceHasAnchor(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
bool instanceHasAnchors() const; bool instanceHasAnchors(SL sl = {}) const;
double instanceLeftAnchorLine() const; double instanceLeftAnchorLine(SL sl = {}) const;
double instanceTopAnchorLine() const; double instanceTopAnchorLine(SL sl = {}) const;
double instanceRightAnchorLine() const; double instanceRightAnchorLine(SL sl = {}) const;
double instanceBottomAnchorLine() const; double instanceBottomAnchorLine(SL sl = {}) const;
double instanceHorizontalCenterAnchorLine() const; double instanceHorizontalCenterAnchorLine(SL sl = {}) const;
double instanceVerticalCenterAnchorLine() const; double instanceVerticalCenterAnchorLine(SL sl = {}) const;
double instanceAnchorLine(AnchorLineType anchorLine) const; double instanceAnchorLine(AnchorLineType anchorLine, SL sl = {}) const;
void setMargin(AnchorLineType sourceAnchorLineType, double margin) const; void setMargin(AnchorLineType sourceAnchorLineType, double margin, SL sl = {}) const;
bool instanceHasMargin(AnchorLineType sourceAnchorLineType) const; bool instanceHasMargin(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
double instanceMargin(AnchorLineType sourceAnchorLineType) const; double instanceMargin(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
void removeMargin(AnchorLineType sourceAnchorLineType); void removeMargin(AnchorLineType sourceAnchorLineType, SL sl = {});
void removeMargins(); void removeMargins(SL sl = {});
void fill(); void fill(SL sl = {});
void centerIn(); void centerIn(SL sl = {});
bool checkForCycle(AnchorLineType anchorLineTyp, const QmlItemNode &sourceItem) const; bool checkForCycle(AnchorLineType anchorLineTyp, const QmlItemNode &sourceItem, SL sl = {}) const;
bool checkForHorizontalCycle(const QmlItemNode &sourceItem) const; bool checkForHorizontalCycle(const QmlItemNode &sourceItem, SL sl = {}) const;
bool checkForVerticalCycle(const QmlItemNode &sourceItem) const; bool checkForVerticalCycle(const QmlItemNode &sourceItem, SL sl = {}) const;
QmlItemNode qmlItemNode() const; QmlItemNode qmlItemNode() const;
bool modelHasAnchors() const; bool modelHasAnchors(SL sl = {}) const;
bool modelHasAnchor(AnchorLineType sourceAnchorLineType) const; bool modelHasAnchor(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
AnchorLine modelAnchor(AnchorLineType sourceAnchorLineType) const; AnchorLine modelAnchor(AnchorLineType sourceAnchorLineType, SL sl = {}) const;
template<typename String>
friend void convertToString(String &string, const QmlAnchors &anchors)
{
convertToString(string, anchors.m_qmlItemNode);
}
private: private:
QmlItemNode m_qmlItemNode; QmlItemNode m_qmlItemNode;