diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml index c832b2f3708..aefffcc6bcc 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml @@ -21,6 +21,7 @@ Column { readonly property int updateDelay: 100 readonly property int previewMargin: 5 + readonly property int extraMargin: 200 property real previewScale: 1 @@ -246,6 +247,8 @@ Column { layer.enabled: true layer.mipmap: true layer.smooth: true + layer.sourceRect: Qt.rect(-root.extraMargin, -root.extraMargin, + width + root.extraMargin * 2, height + root.extraMargin * 2) visible: false Image { @@ -347,10 +350,6 @@ Column { width: source.width height: source.height anchors.centerIn: parent - // Cache the layer. This way heavy shaders rendering doesn't - // slow down code editing & rest of the UI. - layer.enabled: true - layer.smooth: true } } diff --git a/src/plugins/effectcomposer/compositionnode.cpp b/src/plugins/effectcomposer/compositionnode.cpp index 108eb5801d8..d939e2283af 100644 --- a/src/plugins/effectcomposer/compositionnode.cpp +++ b/src/plugins/effectcomposer/compositionnode.cpp @@ -113,6 +113,9 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + if (json.contains("extraMargin")) + m_extraMargin = json.value("extraMargin").toInt(); + if (json.contains("enabled")) m_isEnabled = json["enabled"].toBool(); diff --git a/src/plugins/effectcomposer/compositionnode.h b/src/plugins/effectcomposer/compositionnode.h index b3348bb38fc..433468688a2 100644 --- a/src/plugins/effectcomposer/compositionnode.h +++ b/src/plugins/effectcomposer/compositionnode.h @@ -52,6 +52,8 @@ public: int decRefCount(); void setRefCount(int count); + int extraMargin() const { return m_extraMargin; } + signals: void uniformsModelChanged(); void isEnabledChanged(); @@ -70,6 +72,7 @@ private: QString m_id; bool m_isEnabled = true; int m_refCount = 0; + int m_extraMargin = 0; QList m_uniforms; diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 092df2b3e4a..394b85aa552 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -490,6 +490,8 @@ QJsonObject nodeToJson(const CompositionNode &node) nodeObject.insert("enabled", node.isEnabled()); nodeObject.insert("version", 1); nodeObject.insert("id", node.id()); + if (node.extraMargin()) + nodeObject.insert("extraMargin", node.extraMargin()); // Add properties QJsonArray propertiesArray; @@ -676,10 +678,44 @@ R"( )"; s += frameProp.arg(tr("Frame"), tr("This property allows explicit control of current animation frame.")); } + s += " }\n"; s += " }\n"; } + if (m_shaderFeatures.enabled(ShaderFeatures::Source) && m_extraMargin) { + QString generalSection = + R"( + Section { + caption: "%1" + width: parent.width + + SectionLayout { + PropertyLabel { + text: "%2" + tooltip: "%3" + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 1000 + decimals: 0 + stepSize: 1 + sliderIndicatorVisible: true + backendValue: backendValues.extraMargin + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + ExpandingSpacer {} + } + } + } +)"; + s += generalSection.arg(tr("General"), tr("Extra Margin"), + tr("This property specifies how much of extra space is reserved for the effect outside the parent geometry.")); + } + for (const auto &node : std::as_const(m_nodes)) { const QList uniforms = static_cast( node->uniformsModel())->uniforms(); @@ -739,8 +775,34 @@ Item { s += header; if (m_shaderFeatures.enabled(ShaderFeatures::Source)) { - s += " // This is the main source for the effect. Set internally to the current parent item. Do not modify.\n"; - s += " property Item source: null\n"; + QString sourceStr{ +R"( + // This is the main source for the effect. Set internally to the current parent item. Do not modify. + property Item source: null +)" + }; + + QString extraMarginStr{ +R"( + // This property specifies how much of extra space is reserved for the effect outside the parent geometry. + // It should be sufficient for most use cases but if the application uses extreme values it may be necessary to + // increase this value. + property int extraMargin: %1 + + onExtraMarginChanged: setupSourceRect() + + function setupSourceRect() { + if (rootItem.source) { + var width = source.width + extraMargin * 2 + var height = source.height + extraMargin * 2 + source.layer.sourceRect = Qt.rect(-extraMargin, -extraMargin, width, height) + } + } +)" + }; + s += sourceStr; + if (m_extraMargin) + s += extraMarginStr.arg(m_extraMargin); } if (m_shaderFeatures.enabled(ShaderFeatures::Time) || m_shaderFeatures.enabled(ShaderFeatures::Frame)) { @@ -773,6 +835,7 @@ R"( parent.layer.effect = effectComponent } %1 + %3 } } @@ -781,6 +844,7 @@ R"( parent.layer.enabled = true parent.layer.effect = effectComponent source = parent + %3 } else { parent.layer.enabled = false parent.layer.effect = null @@ -805,10 +869,13 @@ R"( parentChanged = parentChanged.arg(mipmap1, mipmap2); } - parentChanged = parentChanged.arg(m_shaderFeatures.enabled(ShaderFeatures::Source) - ? QString("source = parent") : QString(), - m_shaderFeatures.enabled(ShaderFeatures::Source) - ? QString("source = null") : QString()); + if (m_shaderFeatures.enabled(ShaderFeatures::Source)) { + parentChanged = parentChanged.arg(QString("source = parent"), + QString("source = null"), + m_extraMargin ? QString("setupSourceRect()") : QString()); + } else { + parentChanged = parentChanged.arg(QString(), QString(), QString()); + } s += parentChanged; // Custom properties @@ -854,6 +921,8 @@ void EffectComposerModel::saveComposition(const QString &name) return; } + updateExtraMargin(); + QJsonObject json; // File format version json.insert("version", 1); @@ -1844,6 +1913,12 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles) s += l2 + "vertexShader: 'file:///" + vertFile + "'\n"; s += l2 + "fragmentShader: 'file:///" + fragFile + "'\n"; s += l2 + "anchors.fill: " + (localFiles ? "rootItem.source" : "parent") + "\n"; + if (localFiles) { + if (m_extraMargin) + s += l2 + "anchors.margins: -rootItem.extraMargin\n"; + } else { + s += l2 + "anchors.margins: -root.extraMargin\n"; + } if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) { QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth()) .arg(m_shaderFeatures.gridMeshHeight()); @@ -1879,6 +1954,13 @@ void EffectComposerModel::connectCompositionNode(CompositionNode *node) }); } +void EffectComposerModel::updateExtraMargin() +{ + m_extraMargin = 0; + for (CompositionNode *node : std::as_const(m_nodes)) + m_extraMargin = qMax(node->extraMargin(), m_extraMargin); +} + QString EffectComposerModel::currentComposition() const { return m_currentComposition; diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index 3dca41abf9e..e92213d12a5 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -181,6 +181,7 @@ private: QString getDesignerSpecifics() const; void connectCompositionNode(CompositionNode *node); + void updateExtraMargin(); QList m_nodes; @@ -218,6 +219,7 @@ private: bool m_hasValidTarget = false; QString m_currentComposition; QTimer m_rebakeTimer; + int m_extraMargin = 0; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); };