forked from qt-creator/qt-creator
QmlDesigner: Add Loader and Repeater to component library
Also fixes some issues with Repeater usage. Fixes: QDS-5149 Change-Id: I259dcb73be634150dd0c5e602165b63112ec958c Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -1287,8 +1287,15 @@ PixmapChangedCommand NodeInstanceServer::createPixmapChangedCommand(const QList<
|
|||||||
QVector<ImageContainer> imageVector;
|
QVector<ImageContainer> imageVector;
|
||||||
|
|
||||||
for (const ServerNodeInstance &instance : instanceList) {
|
for (const ServerNodeInstance &instance : instanceList) {
|
||||||
if (instance.isValid() && instance.hasContent())
|
if (!instance.isValid())
|
||||||
imageVector.append(ImageContainer(instance.instanceId(), instance.renderImage(), instance.instanceId()));
|
continue;
|
||||||
|
|
||||||
|
QImage renderImage;
|
||||||
|
// We need to return empty image if instance has no content to correctly update the
|
||||||
|
// item image in case the instance changed from having content to not having content.
|
||||||
|
if (instance.hasContent())
|
||||||
|
renderImage = instance.renderImage();
|
||||||
|
imageVector.append(ImageContainer(instance.instanceId(), renderImage, instance.instanceId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return PixmapChangedCommand(imageVector);
|
return PixmapChangedCommand(imageVector);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <addimportcontainer.h>
|
#include <addimportcontainer.h>
|
||||||
#include <createscenecommand.h>
|
#include <createscenecommand.h>
|
||||||
#include <reparentinstancescommand.h>
|
#include <reparentinstancescommand.h>
|
||||||
|
#include <removeinstancescommand.h>
|
||||||
#include <clearscenecommand.h>
|
#include <clearscenecommand.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -193,6 +194,19 @@ QList<QQuickItem*> Qt5NodeInstanceServer::allItems() const
|
|||||||
return QList<QQuickItem*>();
|
return QList<QQuickItem*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qt5NodeInstanceServer::markRepeaterParentDirty(qint32 id) const
|
||||||
|
{
|
||||||
|
if (!hasInstanceForId(id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If a Repeater instance was moved/removed, the old parent must be marked dirty to rerender it
|
||||||
|
ServerNodeInstance instance = instanceForId(id);
|
||||||
|
if (instance.isValid() && instance.isSubclassOf("QQuickRepeater") && instance.hasParent()) {
|
||||||
|
ServerNodeInstance parentInstance = instance.parent();
|
||||||
|
DesignerSupport::addDirty(parentInstance.rootQuickItem(), QQuickDesignerSupport::Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Qt5NodeInstanceServer::initRhi(RenderViewData &viewData)
|
bool Qt5NodeInstanceServer::initRhi(RenderViewData &viewData)
|
||||||
{
|
{
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
@@ -523,9 +537,23 @@ void Qt5NodeInstanceServer::clearScene(const ClearSceneCommand &command)
|
|||||||
|
|
||||||
void Qt5NodeInstanceServer::reparentInstances(const ReparentInstancesCommand &command)
|
void Qt5NodeInstanceServer::reparentInstances(const ReparentInstancesCommand &command)
|
||||||
{
|
{
|
||||||
|
const QVector<ReparentContainer> &containerVector = command.reparentInstances();
|
||||||
|
for (const ReparentContainer &container : containerVector)
|
||||||
|
markRepeaterParentDirty(container.instanceId());
|
||||||
|
|
||||||
NodeInstanceServer::reparentInstances(command.reparentInstances());
|
NodeInstanceServer::reparentInstances(command.reparentInstances());
|
||||||
startRenderTimer();
|
startRenderTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qt5NodeInstanceServer::removeInstances(const RemoveInstancesCommand &command)
|
||||||
|
{
|
||||||
|
const QVector<qint32> &idVector = command.instanceIds();
|
||||||
|
for (const qint32 id : idVector)
|
||||||
|
markRepeaterParentDirty(id);
|
||||||
|
|
||||||
|
NodeInstanceServer::removeInstances(command);
|
||||||
|
startRenderTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // QmlDesigner
|
} // QmlDesigner
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public:
|
|||||||
void createScene(const CreateSceneCommand &command) override;
|
void createScene(const CreateSceneCommand &command) override;
|
||||||
void clearScene(const ClearSceneCommand &command) override;
|
void clearScene(const ClearSceneCommand &command) override;
|
||||||
void reparentInstances(const ReparentInstancesCommand &command) override;
|
void reparentInstances(const ReparentInstancesCommand &command) override;
|
||||||
|
void removeInstances(const RemoveInstancesCommand &command) override;
|
||||||
|
|
||||||
QImage grabWindow() override;
|
QImage grabWindow() override;
|
||||||
QImage grabItem(QQuickItem *item) override;
|
QImage grabItem(QQuickItem *item) override;
|
||||||
@@ -79,6 +80,7 @@ protected:
|
|||||||
void resetAllItems();
|
void resetAllItems();
|
||||||
void setupScene(const CreateSceneCommand &command) override;
|
void setupScene(const CreateSceneCommand &command) override;
|
||||||
QList<QQuickItem*> allItems() const;
|
QList<QQuickItem*> allItems() const;
|
||||||
|
void markRepeaterParentDirty(qint32 id) const;
|
||||||
|
|
||||||
struct RenderViewData {
|
struct RenderViewData {
|
||||||
QPointer<QQuickWindow> window = nullptr;
|
QPointer<QQuickWindow> window = nullptr;
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Section {
|
||||||
|
caption: qsTr("Loader")
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Active")
|
||||||
|
tooltip: qsTr("This property is true if the Loader is currently active.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.active.valueToString
|
||||||
|
backendValue: backendValues.active
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Source")
|
||||||
|
tooltip: qsTr("This property holds the URL of the QML component to instantiate.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
UrlChooser {
|
||||||
|
filter: "*.qml"
|
||||||
|
backendValue: backendValues.source
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Source Component")
|
||||||
|
tooltip: qsTr("This property holds the component to instantiate.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
ItemFilterComboBox {
|
||||||
|
typeFilter: "Component"
|
||||||
|
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
|
||||||
|
backendValue: backendValues.sourceComponent
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Asynchronous")
|
||||||
|
tooltip: qsTr("This property holds whether the component will be instantiated asynchronously.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.asynchronous.valueToString
|
||||||
|
backendValue: backendValues.asynchronous
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Section {
|
||||||
|
caption: qsTr("Repeater")
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Model")
|
||||||
|
tooltip: qsTr("The model providing data for the repeater. This can simply specify the number of delegate instances to create or it can be bound to an actual model.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
LineEdit {
|
||||||
|
backendValue: backendValues.model
|
||||||
|
showTranslateCheckBox: false
|
||||||
|
writeAsExpression: true
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
width: implicitWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Delegate")
|
||||||
|
tooltip: qsTr("The delegate provides a template defining each object instantiated by the repeater.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
ItemFilterComboBox {
|
||||||
|
typeFilter: "Component"
|
||||||
|
validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
|
||||||
|
backendValue: backendValues.delegate
|
||||||
|
implicitWidth: StudioTheme.Values.singleControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,6 +91,9 @@ void FormEditorView::modelAttached(Model *model)
|
|||||||
//This function does the setup of the initial FormEditorItem tree in the scene
|
//This function does the setup of the initial FormEditorItem tree in the scene
|
||||||
void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode)
|
void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode)
|
||||||
{
|
{
|
||||||
|
if (!qmlItemNode.hasFormEditorItem())
|
||||||
|
return;
|
||||||
|
|
||||||
if (qmlItemNode.isFlowTransition()) {
|
if (qmlItemNode.isFlowTransition()) {
|
||||||
m_scene->addFormEditorItem(qmlItemNode, FormEditorScene::FlowTransition);
|
m_scene->addFormEditorItem(qmlItemNode, FormEditorScene::FlowTransition);
|
||||||
if (qmlItemNode.hasNodeParent())
|
if (qmlItemNode.hasNodeParent())
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
bool canBeDroppedInView3D() const;
|
bool canBeDroppedInView3D() const;
|
||||||
bool isMovable() const;
|
bool isMovable() const;
|
||||||
bool isResizable() const;
|
bool isResizable() const;
|
||||||
|
bool hasFormEditorItem() const;
|
||||||
bool isStackedContainer() const;
|
bool isStackedContainer() const;
|
||||||
bool canBeReparentedTo(const ModelNode &potenialParent);
|
bool canBeReparentedTo(const ModelNode &potenialParent);
|
||||||
QString indexPropertyForStackedContainer() const;
|
QString indexPropertyForStackedContainer() const;
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ public:
|
|||||||
bool modelIsResizable() const;
|
bool modelIsResizable() const;
|
||||||
bool modelIsRotatable() const;
|
bool modelIsRotatable() const;
|
||||||
bool modelIsInLayout() const;
|
bool modelIsInLayout() const;
|
||||||
|
bool hasFormEditorItem() const;
|
||||||
|
|
||||||
QRectF instanceBoundingRect() const;
|
QRectF instanceBoundingRect() const;
|
||||||
QRectF instanceSceneBoundingRect() const;
|
QRectF instanceSceneBoundingRect() const;
|
||||||
|
|||||||
@@ -183,6 +183,11 @@ bool NodeHints::isResizable() const
|
|||||||
return evaluateBooleanExpression("isResizable", true);
|
return evaluateBooleanExpression("isResizable", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodeHints::hasFormEditorItem() const
|
||||||
|
{
|
||||||
|
return evaluateBooleanExpression("hasFormEditorItem", true);
|
||||||
|
}
|
||||||
|
|
||||||
bool NodeHints::isStackedContainer() const
|
bool NodeHints::isStackedContainer() const
|
||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
|
|||||||
@@ -395,6 +395,11 @@ bool QmlItemNode::modelIsInLayout() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QmlItemNode::hasFormEditorItem() const
|
||||||
|
{
|
||||||
|
return NodeHints::fromModelNode(modelNode()).hasFormEditorItem();
|
||||||
|
}
|
||||||
|
|
||||||
QRectF QmlItemNode::instanceBoundingRect() const
|
QRectF QmlItemNode::instanceBoundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(QPointF(0, 0), nodeInstance().size());
|
return QRectF(QPointF(0, 0), nodeInstance().size());
|
||||||
|
|||||||
@@ -448,4 +448,35 @@ MetaInfo {
|
|||||||
version: "2.0"
|
version: "2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
name: "QtQuick.Loader"
|
||||||
|
icon: ":/qtquickplugin/images/item-icon16.png"
|
||||||
|
|
||||||
|
ItemLibraryEntry {
|
||||||
|
name: "Loader"
|
||||||
|
category: "e.Qt Quick - Component"
|
||||||
|
libraryIcon: ":/qtquickplugin/images/item-icon.png"
|
||||||
|
version: "2.0"
|
||||||
|
Property { name: "width"; type: "int"; value: 200; }
|
||||||
|
Property { name: "height"; type: "int"; value: 200; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
name: "QtQuick.Repeater"
|
||||||
|
icon: ":/qtquickplugin/images/item-icon16.png"
|
||||||
|
|
||||||
|
Hints {
|
||||||
|
canBeDroppedInFormEditor: false
|
||||||
|
hasFormEditorItem: false
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemLibraryEntry {
|
||||||
|
name: "Repeater"
|
||||||
|
category: "e.Qt Quick - Component"
|
||||||
|
libraryIcon: ":/qtquickplugin/images/item-icon.png"
|
||||||
|
version: "2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user