forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/8.0' into 9.0
Conflicts: src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp Change-Id: I38f196e8f42cf11f7b613e7a723745600e35c5e9
This commit is contained in:
BIN
doc/qtdesignstudio/images/3d-view-context-menu.png
Normal file
BIN
doc/qtdesignstudio/images/3d-view-context-menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
@@ -16,10 +16,18 @@
|
|||||||
|
|
||||||
\image studio-qtquick-3d-components.png "Qt Quick 3D components in Components"
|
\image studio-qtquick-3d-components.png "Qt Quick 3D components in Components"
|
||||||
|
|
||||||
Add a camera by dragging-and-dropping one of the camera components from
|
To add a camera component to your UI, do one of the following:
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D} > \uicontrol
|
\list
|
||||||
{Qt Quick 3D} to the \l {3D} view or to a 3D view in \l Navigator.
|
\li Drag a camera component from \uicontrol Components >
|
||||||
If the cameras are not displayed in \uicontrol {Components}, add the
|
\uicontrol {Qt Quick 3D} to the \l {3D} view or to
|
||||||
|
\l Navigator > \uicontrol {View3D} > \uicontrol Scene.
|
||||||
|
\li Right-click in the \uicontrol 3D view and select
|
||||||
|
\uicontrol Create > \uicontrol Cameras from the context menu.
|
||||||
|
\note You can only create \uicontrol {Camera Perspective} and
|
||||||
|
\uicontrol {Camera Ortographic} this way.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
If you cannot find the camera components in \uicontrol {Components}, add the
|
||||||
\uicontrol QtQuick3D module to your project, as described in
|
\uicontrol QtQuick3D module to your project, as described in
|
||||||
\l {Adding and Removing Modules}.
|
\l {Adding and Removing Modules}.
|
||||||
|
|
||||||
|
@@ -48,6 +48,16 @@
|
|||||||
Additionally, you can toggle the visibility of the grid, selection boxes,
|
Additionally, you can toggle the visibility of the grid, selection boxes,
|
||||||
icon gizmos, and camera frustums in the 3D scene.
|
icon gizmos, and camera frustums in the 3D scene.
|
||||||
|
|
||||||
|
There is a context menu in the \uicontrol 3D view. To open it, right-click
|
||||||
|
in the \uicontrol 3D view. From the context menu you can:
|
||||||
|
\list
|
||||||
|
\li Create cameras, lights, and models.
|
||||||
|
\li Open \uicontrol {Material Editor} and edit materials.
|
||||||
|
\li Delete components
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
\image 3d-view-context-menu.png
|
||||||
|
|
||||||
To refresh the contents of the \uicontrol{3D} view, press \key P or
|
To refresh the contents of the \uicontrol{3D} view, press \key P or
|
||||||
select the \inlineimage icons/reset.png
|
select the \inlineimage icons/reset.png
|
||||||
(\uicontrol {Reset View}) button.
|
(\uicontrol {Reset View}) button.
|
||||||
|
@@ -12,9 +12,14 @@
|
|||||||
As a secondary light source, you can use \l{Setting the Light Probe}
|
As a secondary light source, you can use \l{Setting the Light Probe}
|
||||||
{image-based lighting}.
|
{image-based lighting}.
|
||||||
|
|
||||||
To add light components to your UI, drag-and-drop them from
|
To add a light component to your UI, do one of the following:
|
||||||
\uicontrol Components > \uicontrol {Qt Quick 3D} to the \l {3D} view or to
|
\list
|
||||||
\l Navigator > \uicontrol {Scene Environment} > \uicontrol Scene.
|
\li Drag a light component from \uicontrol Components >
|
||||||
|
\uicontrol {Qt Quick 3D} to the \l {3D} view or to
|
||||||
|
\l Navigator > \uicontrol {View3D} > \uicontrol Scene.
|
||||||
|
\li Right-click in the \uicontrol 3D view and select
|
||||||
|
\uicontrol Create > \uicontrol Lights from the context menu.
|
||||||
|
\endlist
|
||||||
|
|
||||||
If you cannot find the light components in \uicontrol {Components}, add the
|
If you cannot find the light components in \uicontrol {Components}, add the
|
||||||
\uicontrol {Qt Quick 3D} module to your project as instructed in
|
\uicontrol {Qt Quick 3D} module to your project as instructed in
|
||||||
|
@@ -13,14 +13,21 @@
|
|||||||
|
|
||||||
\image studio-3d-models.png "Various 3D models in the 3D view"
|
\image studio-3d-models.png "Various 3D models in the 3D view"
|
||||||
|
|
||||||
A Model component loads mesh data from a file. You can modify how the
|
A model component loads mesh data from a file. You can modify how the
|
||||||
component is shaded by using materials. For more information, see
|
component is shaded by using materials. For more information, see
|
||||||
\l {Materials and Shaders} and \l {Creating Custom Materials}.
|
\l {Materials and Shaders} and \l {Creating Custom Materials}.
|
||||||
|
|
||||||
You can drag-and-drop a model from \uicontrol Components
|
To add a model component to your UI, do one of the following:
|
||||||
> \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to the \l {3D} view or
|
\list
|
||||||
to \l Navigator > \uicontrol {Scene Environment} > \uicontrol Scene. If the
|
\li Drag a model component from \uicontrol Components >
|
||||||
models are not displayed in \uicontrol {Components}, you should add the
|
\uicontrol {Qt Quick 3D} to the \l {3D} view or to
|
||||||
|
\l Navigator > \uicontrol {View3D} > \uicontrol Scene.
|
||||||
|
\li Right-click in the \uicontrol 3D view and select
|
||||||
|
\uicontrol Create > \uicontrol Primitives from the context menu.
|
||||||
|
\note You can not create \uicontrol Empty models this way.
|
||||||
|
\endlist
|
||||||
|
|
||||||
|
If you cannot find the model components in \uicontrol {Components}, add the
|
||||||
\uicontrol QtQuick3D module to your project, as described in
|
\uicontrol QtQuick3D module to your project, as described in
|
||||||
\l {Adding and Removing Modules}.
|
\l {Adding and Removing Modules}.
|
||||||
|
|
||||||
|
@@ -511,7 +511,7 @@ void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImpor
|
|||||||
quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject());
|
quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject());
|
||||||
|
|
||||||
m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl());
|
m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl());
|
||||||
m_importComponentObject = m_importComponent->create();
|
m_importComponentObject = m_importComponent->create(engine()->rootContext());
|
||||||
|
|
||||||
Q_ASSERT(m_importComponent && m_importComponentObject);
|
Q_ASSERT(m_importComponent && m_importComponentObject);
|
||||||
Q_ASSERT_X(m_importComponent->errors().isEmpty(), __FUNCTION__, m_importComponent->errorString().toLatin1());
|
Q_ASSERT_X(m_importComponent->errors().isEmpty(), __FUNCTION__, m_importComponent->errorString().toLatin1());
|
||||||
|
@@ -94,5 +94,21 @@ bool QmlStateNodeInstance::resetStateProperty(const ObjectNodeInstance::Pointer
|
|||||||
return QmlPrivateGate::States::resetStateProperty(object(), target->object(), propertyName, resetValue);
|
return QmlPrivateGate::States::resetStateProperty(object(), target->object(), propertyName, resetValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlStateNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParentInstance,
|
||||||
|
const PropertyName &oldParentProperty,
|
||||||
|
const ObjectNodeInstance::Pointer &newParentInstance,
|
||||||
|
const PropertyName &newParentProperty)
|
||||||
|
{
|
||||||
|
ServerNodeInstance oldState = nodeInstanceServer()->activeStateInstance();
|
||||||
|
|
||||||
|
ObjectNodeInstance::reparent(oldParentInstance,
|
||||||
|
oldParentProperty,
|
||||||
|
newParentInstance,
|
||||||
|
newParentProperty);
|
||||||
|
|
||||||
|
if (oldState.isValid())
|
||||||
|
oldState.activateState();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -27,6 +27,10 @@ public:
|
|||||||
bool updateStateBinding(const ObjectNodeInstance::Pointer &target, const PropertyName &propertyName, const QString &expression) override;
|
bool updateStateBinding(const ObjectNodeInstance::Pointer &target, const PropertyName &propertyName, const QString &expression) override;
|
||||||
bool resetStateProperty(const ObjectNodeInstance::Pointer &target, const PropertyName &propertyName, const QVariant &resetValue) override;
|
bool resetStateProperty(const ObjectNodeInstance::Pointer &target, const PropertyName &propertyName, const QVariant &resetValue) override;
|
||||||
|
|
||||||
|
void reparent(const ObjectNodeInstance::Pointer &oldParentInstance,
|
||||||
|
const PropertyName &oldParentProperty,
|
||||||
|
const ObjectNodeInstance::Pointer &newParentInstance,
|
||||||
|
const PropertyName &newParentProperty) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QmlStateNodeInstance(QObject *object);
|
QmlStateNodeInstance(QObject *object);
|
||||||
|
@@ -15,12 +15,13 @@ Quick3DMaterialNodeInstance::~Quick3DMaterialNodeInstance()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quick3DMaterialNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
void Quick3DMaterialNodeInstance::invokeDummyViewCreate() const
|
||||||
InstanceContainer::NodeFlags flags)
|
|
||||||
{
|
{
|
||||||
m_dummyRootViewCreateFunction = "createViewForMaterial";
|
QMetaObject::invokeMethod(m_dummyRootView, "createViewForMaterial",
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(object())),
|
||||||
Quick3DRenderableNodeInstance::initialize(objectNodeInstance, flags);
|
Q_ARG(QVariant, ""),
|
||||||
|
Q_ARG(QVariant, ""),
|
||||||
|
Q_ARG(QVariant, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
Quick3DMaterialNodeInstance::Pointer Quick3DMaterialNodeInstance::create(QObject *object)
|
Quick3DMaterialNodeInstance::Pointer Quick3DMaterialNodeInstance::create(QObject *object)
|
||||||
|
@@ -19,11 +19,10 @@ public:
|
|||||||
|
|
||||||
~Quick3DMaterialNodeInstance() override;
|
~Quick3DMaterialNodeInstance() override;
|
||||||
static Pointer create(QObject *objectToBeWrapped);
|
static Pointer create(QObject *objectToBeWrapped);
|
||||||
void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
|
||||||
InstanceContainer::NodeFlags flags) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Quick3DMaterialNodeInstance(QObject *node);
|
explicit Quick3DMaterialNodeInstance(QObject *node);
|
||||||
|
void invokeDummyViewCreate() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -24,6 +24,12 @@ Quick3DNodeInstance::Quick3DNodeInstance(QObject *node)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Quick3DNodeInstance::invokeDummyViewCreate() const
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(m_dummyRootView, "createViewForNode",
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(object())));
|
||||||
|
}
|
||||||
|
|
||||||
Quick3DNodeInstance::~Quick3DNodeInstance()
|
Quick3DNodeInstance::~Quick3DNodeInstance()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -58,8 +64,6 @@ void Quick3DNodeInstance::initialize(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dummyRootViewCreateFunction = "createViewForNode";
|
|
||||||
|
|
||||||
Quick3DRenderableNodeInstance::initialize(objectNodeInstance, flags);
|
Quick3DRenderableNodeInstance::initialize(objectNodeInstance, flags);
|
||||||
#endif // QUICK3D_MODULE
|
#endif // QUICK3D_MODULE
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Quick3DNodeInstance(QObject *node);
|
explicit Quick3DNodeInstance(QObject *node);
|
||||||
|
void invokeDummyViewCreate() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQuick3DNode *quick3DNode() const;
|
QQuick3DNode *quick3DNode() const;
|
||||||
|
@@ -45,8 +45,7 @@ void Quick3DRenderableNodeInstance::initialize(const ObjectNodeInstance::Pointer
|
|||||||
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"));
|
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"));
|
||||||
m_dummyRootView = qobject_cast<QQuickItem *>(component.create());
|
m_dummyRootView = qobject_cast<QQuickItem *>(component.create());
|
||||||
|
|
||||||
QMetaObject::invokeMethod(m_dummyRootView, m_dummyRootViewCreateFunction,
|
invokeDummyViewCreate();
|
||||||
Q_ARG(QVariant, QVariant::fromValue(object())));
|
|
||||||
|
|
||||||
nodeInstanceServer()->setRootItem(m_dummyRootView);
|
nodeInstanceServer()->setRootItem(m_dummyRootView);
|
||||||
}
|
}
|
||||||
@@ -192,6 +191,10 @@ Qt5NodeInstanceServer *Quick3DRenderableNodeInstance::qt5NodeInstanceServer() co
|
|||||||
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Quick3DRenderableNodeInstance::invokeDummyViewCreate() const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|
||||||
|
@@ -35,10 +35,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
explicit Quick3DRenderableNodeInstance(QObject *node);
|
explicit Quick3DRenderableNodeInstance(QObject *node);
|
||||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||||
|
virtual void invokeDummyViewCreate() const;
|
||||||
|
|
||||||
QByteArray m_dummyRootViewCreateFunction;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QQuickItem *m_dummyRootView = nullptr;
|
QQuickItem *m_dummyRootView = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -846,6 +846,10 @@ void QuickItemNodeInstance::setPropertyVariant(const PropertyName &name, const Q
|
|||||||
|
|
||||||
void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression)
|
void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression)
|
||||||
{
|
{
|
||||||
|
static QList<PropertyName> anchorsTargets = {"anchors.top",
|
||||||
|
"acnhors.bottom",
|
||||||
|
"anchors.left",
|
||||||
|
"achors.right"};
|
||||||
if (ignoredProperties().contains(name))
|
if (ignoredProperties().contains(name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -857,7 +861,15 @@ void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const Q
|
|||||||
|
|
||||||
markRepeaterParentDirty();
|
markRepeaterParentDirty();
|
||||||
|
|
||||||
|
if (anchorsTargets.contains(name)) {
|
||||||
|
//When resolving anchor targets we have to provide the root context the ids are defined in.
|
||||||
|
QmlPrivateGate::setPropertyBinding(object(),
|
||||||
|
context()->engine()->rootContext(),
|
||||||
|
name,
|
||||||
|
expression);
|
||||||
|
} else {
|
||||||
ObjectNodeInstance::setPropertyBinding(name, expression);
|
ObjectNodeInstance::setPropertyBinding(name, expression);
|
||||||
|
}
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
|
@@ -414,10 +414,12 @@ Item {
|
|||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
SearchBox {
|
StudioControls.SearchBox {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
|
|
||||||
width: parent.width - addAssetButton.width - 5
|
width: parent.width - addAssetButton.width - 5
|
||||||
|
|
||||||
|
onSearchChanged: (searchText) => rootView.handleSearchFilterChanged(searchText)
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
|
@@ -199,10 +199,12 @@ Item {
|
|||||||
Row {
|
Row {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
SearchBox {
|
StudioControls.SearchBox {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
|
|
||||||
width: parent.width - addModuleButton.width - 5
|
width: parent.width - addModuleButton.width - 5
|
||||||
|
|
||||||
|
onSearchChanged: (searchText) => rootView.handleSearchFilterChanged(searchText)
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
|
@@ -208,10 +208,12 @@ Item {
|
|||||||
width: root.width
|
width: root.width
|
||||||
enabled: !materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
enabled: !materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
||||||
|
|
||||||
SearchBox {
|
StudioControls.SearchBox {
|
||||||
id: searchBox
|
id: searchBox
|
||||||
|
|
||||||
width: root.width - addMaterialButton.width
|
width: root.width - addMaterialButton.width
|
||||||
|
|
||||||
|
onSearchChanged: (searchText) => rootView.handleSearchFilterChanged(searchText)
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
IconButton {
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import StatesEditor
|
import StatesEditor
|
||||||
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
import StudioControls 1.0 as StudioControls
|
import StudioControls 1.0 as StudioControls
|
||||||
import StudioTheme as StudioTheme
|
import StudioTheme as StudioTheme
|
||||||
|
|
||||||
@@ -369,6 +370,23 @@ Rectangle {
|
|||||||
width: stateGroupLabel.visible ? StudioTheme.Values.defaultControlWidth
|
width: stateGroupLabel.visible ? StudioTheme.Values.defaultControlWidth
|
||||||
: root.width - 2 * root.padding
|
: root.width - 2 * root.padding
|
||||||
|
|
||||||
|
HelperWidgets.Tooltip { id: comboBoxTooltip }
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: stateGroupComboBox.hovered
|
||||||
|
onTriggered: comboBoxTooltip.showText(stateGroupComboBox,
|
||||||
|
hoverHandler.point.position,
|
||||||
|
qsTr("Switch State Group"))
|
||||||
|
}
|
||||||
|
|
||||||
|
onHoverChanged: {
|
||||||
|
if (!stateGroupComboBox.hovered)
|
||||||
|
comboBoxTooltip.hideText()
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler { id: hoverHandler }
|
||||||
|
|
||||||
popup.onOpened: editDialog.close()
|
popup.onOpened: editDialog.close()
|
||||||
|
|
||||||
// currentIndex needs special treatment, because if model is changed, it will be
|
// currentIndex needs special treatment, because if model is changed, it will be
|
||||||
@@ -398,25 +416,28 @@ Rectangle {
|
|||||||
spacing: StudioTheme.Values.toolbarSpacing
|
spacing: StudioTheme.Values.toolbarSpacing
|
||||||
leftPadding: toolBar.doubleRow ? root.padding : 0
|
leftPadding: toolBar.doubleRow ? root.padding : 0
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
buttonIcon: StudioTheme.Constants.plus
|
buttonIcon: StudioTheme.Constants.plus
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
tooltip: qsTr("Create State Group")
|
||||||
onClicked: statesEditorModel.addStateGroup("stateGroup")
|
onClicked: statesEditorModel.addStateGroup("stateGroup")
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
buttonIcon: StudioTheme.Constants.minus
|
buttonIcon: StudioTheme.Constants.minus
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: statesEditorModel.activeStateGroupIndex !== 0
|
enabled: statesEditorModel.activeStateGroupIndex !== 0
|
||||||
|
tooltip: qsTr("Remove State Group")
|
||||||
onClicked: statesEditorModel.removeStateGroup()
|
onClicked: statesEditorModel.removeStateGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
id: editButton
|
id: editButton
|
||||||
buttonIcon: StudioTheme.Constants.edit
|
buttonIcon: StudioTheme.Constants.edit
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: statesEditorModel.activeStateGroupIndex !== 0
|
enabled: statesEditorModel.activeStateGroupIndex !== 0
|
||||||
checked: editDialog.visible
|
checked: editDialog.visible
|
||||||
|
tooltip: qsTr("Rename State Group")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (editDialog.opened)
|
if (editDialog.opened)
|
||||||
editDialog.close()
|
editDialog.close()
|
||||||
@@ -439,20 +460,22 @@ Rectangle {
|
|||||||
spacing: StudioTheme.Values.toolbarSpacing
|
spacing: StudioTheme.Values.toolbarSpacing
|
||||||
rightPadding: root.padding
|
rightPadding: root.padding
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
buttonIcon: StudioTheme.Constants.gridView
|
buttonIcon: StudioTheme.Constants.gridView
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: !root.tinyMode
|
enabled: !root.tinyMode
|
||||||
|
tooltip: qsTr("Show thumbnails")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
for (var i = 0; i < statesRepeater.count; ++i)
|
for (var i = 0; i < statesRepeater.count; ++i)
|
||||||
statesRepeater.itemAt(i).setPropertyChangesVisible(false)
|
statesRepeater.itemAt(i).setPropertyChangesVisible(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
buttonIcon: StudioTheme.Constants.textFullJustification
|
buttonIcon: StudioTheme.Constants.textFullJustification
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: !root.tinyMode
|
enabled: !root.tinyMode
|
||||||
|
tooltip: qsTr("Show property changes")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
for (var i = 0; i < statesRepeater.count; ++i)
|
for (var i = 0; i < statesRepeater.count; ++i)
|
||||||
statesRepeater.itemAt(i).setPropertyChangesVisible(true)
|
statesRepeater.itemAt(i).setPropertyChangesVisible(true)
|
||||||
@@ -503,6 +526,7 @@ Rectangle {
|
|||||||
anchors.leftMargin: root.leftMargin
|
anchors.leftMargin: root.leftMargin
|
||||||
|
|
||||||
ScrollBar.horizontal: StateScrollBar {
|
ScrollBar.horizontal: StateScrollBar {
|
||||||
|
id: horizontalBar
|
||||||
parent: scrollView
|
parent: scrollView
|
||||||
x: scrollView.leftPadding
|
x: scrollView.leftPadding
|
||||||
y: scrollView.height - height
|
y: scrollView.height - height
|
||||||
@@ -511,6 +535,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScrollBar.vertical: StateScrollBar {
|
ScrollBar.vertical: StateScrollBar {
|
||||||
|
id: verticalBar
|
||||||
parent: scrollView
|
parent: scrollView
|
||||||
x: scrollView.mirrored ? 0 : scrollView.width - width
|
x: scrollView.mirrored ? 0 : scrollView.width - width
|
||||||
y: scrollView.topPadding
|
y: scrollView.topPadding
|
||||||
@@ -568,6 +593,7 @@ Rectangle {
|
|||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
properties: "x,y"
|
properties: "x,y"
|
||||||
easing.type: Easing.OutQuad
|
easing.type: Easing.OutQuad
|
||||||
|
duration: 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,11 +602,6 @@ Rectangle {
|
|||||||
|
|
||||||
property int grabIndex: -1
|
property int grabIndex: -1
|
||||||
|
|
||||||
function executeDrop(from, to) {
|
|
||||||
statesEditorModel.drop(from, to)
|
|
||||||
statesRepeater.grabIndex = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
model: statesEditorModel
|
model: statesEditorModel
|
||||||
|
|
||||||
onItemAdded: root.responsiveResize(root.width, root.height)
|
onItemAdded: root.responsiveResize(root.width, root.height)
|
||||||
@@ -623,24 +644,27 @@ Rectangle {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
statesEditorModel.move(
|
statesEditorModel.move(dragSource.visualIndex,
|
||||||
(drag.source as StateThumbnail).visualIndex,
|
|
||||||
stateThumbnail.visualIndex)
|
stateThumbnail.visualIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropped: function (drop) {
|
onDropped: function (drop) {
|
||||||
let dragSource = (drop.source as StateThumbnail)
|
let dropSource = (drop.source as StateThumbnail)
|
||||||
|
|
||||||
if (dragSource === undefined)
|
if (dropSource === undefined)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (dragSource.extendString !== stateThumbnail.extendString
|
if (dropSource.extendString !== stateThumbnail.extendString
|
||||||
|| stateThumbnail.extendedState) {
|
|| stateThumbnail.extendedState) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
statesRepeater.executeDrop(statesRepeater.grabIndex,
|
if (statesRepeater.grabIndex === dropSource.visualIndex)
|
||||||
stateThumbnail.visualIndex)
|
return
|
||||||
|
|
||||||
|
statesEditorModel.drop(statesRepeater.grabIndex,
|
||||||
|
dropSource.visualIndex)
|
||||||
|
statesRepeater.grabIndex = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend Groups Visualization
|
// Extend Groups Visualization
|
||||||
@@ -742,6 +766,10 @@ Rectangle {
|
|||||||
|
|
||||||
hasWhenCondition: delegateRoot.hasWhenCondition
|
hasWhenCondition: delegateRoot.hasWhenCondition
|
||||||
|
|
||||||
|
scrollViewActive: horizontalBar.active || verticalBar.active
|
||||||
|
|
||||||
|
dragParent: scrollView
|
||||||
|
|
||||||
// Fix ScrollView taking over the dragging event
|
// Fix ScrollView taking over the dragging event
|
||||||
onGrabbing: {
|
onGrabbing: {
|
||||||
frame.interactive = false
|
frame.interactive = false
|
||||||
@@ -749,14 +777,6 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
onLetGo: frame.interactive = true
|
onLetGo: frame.interactive = true
|
||||||
|
|
||||||
// Fix for ScrollView clipping while dragging of StateThumbnail
|
|
||||||
onDragActiveChanged: {
|
|
||||||
if (stateThumbnail.dragActive)
|
|
||||||
parent = scrollViewWrapper
|
|
||||||
else
|
|
||||||
parent = delegateRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
stateName: delegateRoot.stateName
|
stateName: delegateRoot.stateName
|
||||||
thumbnailImageSource: delegateRoot.stateImageSource
|
thumbnailImageSource: delegateRoot.stateImageSource
|
||||||
whenCondition: delegateRoot.whenConditionString
|
whenCondition: delegateRoot.whenConditionString
|
||||||
@@ -771,15 +791,16 @@ Rectangle {
|
|||||||
|
|
||||||
onClone: root.cloneState(delegateRoot.internalNodeId)
|
onClone: root.cloneState(delegateRoot.internalNodeId)
|
||||||
onExtend: root.extendState(delegateRoot.internalNodeId)
|
onExtend: root.extendState(delegateRoot.internalNodeId)
|
||||||
onRemove: root.deleteState(delegateRoot.internalNodeId)
|
onRemove: {
|
||||||
|
if (delegateRoot.isDefault)
|
||||||
|
statesEditorModel.resetDefaultState()
|
||||||
|
|
||||||
|
root.deleteState(delegateRoot.internalNodeId)
|
||||||
|
}
|
||||||
|
|
||||||
onStateNameFinished: statesEditorModel.renameState(
|
onStateNameFinished: statesEditorModel.renameState(
|
||||||
delegateRoot.internalNodeId,
|
delegateRoot.internalNodeId,
|
||||||
stateThumbnail.stateName)
|
stateThumbnail.stateName)
|
||||||
|
|
||||||
onWhenConditionFinished: statesEditorModel.setWhenCondition(
|
|
||||||
delegateRoot.internalNodeId,
|
|
||||||
stateThumbnail.whenCondition)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,19 +36,19 @@ T.ScrollBar {
|
|||||||
implicitContentHeight + topPadding + bottomPadding)
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
contentItem: Rectangle {
|
contentItem: Rectangle {
|
||||||
implicitWidth: scrollBar.interactive ? 6 : 2
|
implicitWidth: scrollBar.interactive ? 14 : 8
|
||||||
implicitHeight: scrollBar.interactive ? 6 : 2
|
implicitHeight: scrollBar.interactive ? 14 : 8
|
||||||
radius: width / 2
|
radius: width / 2
|
||||||
opacity: 0.0
|
opacity: 0.0
|
||||||
color: scrollBar.pressed ? StudioTheme.Values.themeSliderActiveTrackHover
|
color: scrollBar.pressed ? StudioTheme.Values.themeScrollBarHandle //"#4C4C4C"//DARK
|
||||||
: StudioTheme.Values.themeSliderHandle
|
: StudioTheme.Values.themeScrollBarTrack //"#3E3E3E"//DARK
|
||||||
|
|
||||||
states: State {
|
states: State {
|
||||||
name: "active"
|
name: "active"
|
||||||
when: scrollBar.active && scrollBar.size < 1.0
|
when: scrollBar.active && scrollBar.size < 1.0
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: scrollBar.contentItem
|
target: scrollBar.contentItem
|
||||||
opacity: 0.75
|
opacity: 0.9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,9 +25,9 @@
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import StudioTheme 1.0 as StudioTheme
|
import HelperWidgets 2.0 as HelperWidgets
|
||||||
import StudioControls 1.0 as StudioControls
|
import StudioControls 1.0 as StudioControls
|
||||||
import QtQuick.Layouts 6.0
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -55,6 +55,10 @@ Item {
|
|||||||
|
|
||||||
property bool hasWhenCondition: false
|
property bool hasWhenCondition: false
|
||||||
|
|
||||||
|
property bool scrollViewActive: false
|
||||||
|
|
||||||
|
property Item dragParent
|
||||||
|
|
||||||
property int visualIndex: 0
|
property int visualIndex: 0
|
||||||
|
|
||||||
property int internalNodeId
|
property int internalNodeId
|
||||||
@@ -65,7 +69,6 @@ Item {
|
|||||||
signal extend
|
signal extend
|
||||||
signal remove
|
signal remove
|
||||||
signal stateNameFinished
|
signal stateNameFinished
|
||||||
signal whenConditionFinished
|
|
||||||
|
|
||||||
signal grabbing
|
signal grabbing
|
||||||
signal letGo
|
signal letGo
|
||||||
@@ -88,7 +91,7 @@ Item {
|
|||||||
|
|
||||||
DragHandler {
|
DragHandler {
|
||||||
id: dragHandler
|
id: dragHandler
|
||||||
enabled: !root.baseState && !root.extendedState
|
enabled: !root.baseState && !root.extendedState && !root.scrollViewActive
|
||||||
onGrabChanged: function (transition, point) {
|
onGrabChanged: function (transition, point) {
|
||||||
if (transition === PointerDevice.GrabPassive
|
if (transition === PointerDevice.GrabPassive
|
||||||
|| transition === PointerDevice.GrabExclusive)
|
|| transition === PointerDevice.GrabExclusive)
|
||||||
@@ -148,13 +151,14 @@ Item {
|
|||||||
rows: 1
|
rows: 1
|
||||||
spacing: stateBackground.thumbSpacing
|
spacing: stateBackground.thumbSpacing
|
||||||
|
|
||||||
StudioControls.AbstractButton {
|
HelperWidgets.AbstractButton {
|
||||||
id: defaultButton
|
id: defaultButton
|
||||||
width: 50
|
width: 50
|
||||||
height: stateBackground.controlHeight
|
height: stateBackground.controlHeight
|
||||||
checkedInverted: true
|
checkedInverted: true
|
||||||
buttonIcon: qsTr("Default")
|
buttonIcon: qsTr("Default")
|
||||||
iconFont: StudioTheme.Constants.font
|
iconFont: StudioTheme.Constants.font
|
||||||
|
tooltip: qsTr("Set State as default")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.defaultClicked()
|
root.defaultClicked()
|
||||||
root.focusSignal()
|
root.focusSignal()
|
||||||
@@ -607,8 +611,16 @@ Item {
|
|||||||
running: false
|
running: false
|
||||||
interval: 50
|
interval: 50
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: statesEditorModel.setWhenCondition(root.internalNodeId,
|
onTriggered: {
|
||||||
|
if (whenCondition.previousCondition === bindingEditor.newWhenCondition)
|
||||||
|
return
|
||||||
|
|
||||||
|
if ( bindingEditor.newWhenCondition !== "")
|
||||||
|
statesEditorModel.setWhenCondition(root.internalNodeId,
|
||||||
bindingEditor.newWhenCondition)
|
bindingEditor.newWhenCondition)
|
||||||
|
else
|
||||||
|
statesEditorModel.resetWhenCondition(root.internalNodeId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stateModelNodeProperty: statesEditorModel.stateModelNode(root.internalNodeId)
|
stateModelNodeProperty: statesEditorModel.stateModelNode(root.internalNodeId)
|
||||||
@@ -634,6 +646,8 @@ Item {
|
|||||||
indicatorVisible: true
|
indicatorVisible: true
|
||||||
indicator.icon.text: StudioTheme.Constants.edit
|
indicator.icon.text: StudioTheme.Constants.edit
|
||||||
indicator.onClicked: {
|
indicator.onClicked: {
|
||||||
|
whenCondition.previousCondition = whenCondition.text
|
||||||
|
|
||||||
bindingEditor.showWidget()
|
bindingEditor.showWidget()
|
||||||
bindingEditor.text = whenCondition.text
|
bindingEditor.text = whenCondition.text
|
||||||
bindingEditor.prepareBindings()
|
bindingEditor.prepareBindings()
|
||||||
@@ -650,13 +664,18 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
if (whenCondition.previousCondition === whenCondition.text)
|
// The check for contenxtMenuAboutToShow is necessary in order to make a the
|
||||||
|
// popup stay open if the when condition was changed. Otherwise editingFinished
|
||||||
|
// will be called and the model will be reset. The popup will trigger a focus
|
||||||
|
// change and editingFinished is triggered.
|
||||||
|
if (whenCondition.previousCondition === whenCondition.text
|
||||||
|
|| whenCondition.contextMenuAboutToShow)
|
||||||
return
|
return
|
||||||
|
|
||||||
whenCondition.previousCondition = whenCondition.text
|
whenCondition.previousCondition = whenCondition.text
|
||||||
|
|
||||||
if (whenCondition.text !== "")
|
if (whenCondition.text !== "")
|
||||||
root.whenConditionFinished()
|
statesEditorModel.setWhenCondition(root.internalNodeId, root.whenCondition)
|
||||||
else
|
else
|
||||||
statesEditorModel.resetWhenCondition(root.internalNodeId)
|
statesEditorModel.resetWhenCondition(root.internalNodeId)
|
||||||
|
|
||||||
@@ -750,6 +769,11 @@ Item {
|
|||||||
name: "drag"
|
name: "drag"
|
||||||
when: dragHandler.active
|
when: dragHandler.active
|
||||||
|
|
||||||
|
ParentChange {
|
||||||
|
target: root
|
||||||
|
parent: root.dragParent
|
||||||
|
}
|
||||||
|
|
||||||
AnchorChanges {
|
AnchorChanges {
|
||||||
target: root
|
target: root
|
||||||
anchors.horizontalCenter: undefined
|
anchors.horizontalCenter: undefined
|
||||||
|
@@ -0,0 +1,109 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2022 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
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import HelperWidgets 2.0
|
||||||
|
import StudioControls 1.0 as StudioControls
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Section {
|
||||||
|
caption: qsTr("Timer")
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
SectionLayout {
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Interval")
|
||||||
|
tooltip: qsTr("Sets the interval between triggers, in milliseconds.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
SpinBox {
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: 9999999
|
||||||
|
backendValue: backendValues.interval
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Repeat")
|
||||||
|
tooltip: qsTr("Sets whether the timer is triggered repeatedly at the specified interval or just once.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.repeat.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.repeat
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Running")
|
||||||
|
tooltip: qsTr("Sets whether the timer is running or not.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.running.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.running
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyLabel {
|
||||||
|
text: qsTr("Triggered on start")
|
||||||
|
tooltip: qsTr("Sets the timer to trigger when started.")
|
||||||
|
}
|
||||||
|
|
||||||
|
SecondColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
text: backendValues.triggeredOnStart.valueToString
|
||||||
|
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||||
|
+ StudioTheme.Values.actionIndicatorWidth
|
||||||
|
backendValue: backendValues.triggeredOnStart
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpandingSpacer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -135,6 +135,7 @@ Section {
|
|||||||
BoolButtonRowButton {
|
BoolButtonRowButton {
|
||||||
visible: section.showEasingCurve
|
visible: section.showEasingCurve
|
||||||
buttonIcon: StudioTheme.Constants.curveDesigner
|
buttonIcon: StudioTheme.Constants.curveDesigner
|
||||||
|
checkable: false
|
||||||
|
|
||||||
EasingCurveEditor {
|
EasingCurveEditor {
|
||||||
id: easingCurveEditor
|
id: easingCurveEditor
|
||||||
|
@@ -266,15 +266,6 @@ SecondColumnLayout {
|
|||||||
id: spacer
|
id: spacer
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.Menu {
|
|
||||||
id: contextMenu
|
|
||||||
|
|
||||||
StudioControls.MenuItem {
|
|
||||||
text: qsTr("Open Color Dialog")
|
|
||||||
onTriggered: colorPalette.showColorDialog(colorEditor.color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: popupLoader.determineActiveColorMode()
|
Component.onCompleted: popupLoader.determineActiveColorMode()
|
||||||
|
|
||||||
onBackendValueChanged: {
|
onBackendValueChanged: {
|
||||||
|
@@ -178,6 +178,15 @@ T.Popup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StudioControls.Menu {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
StudioControls.MenuItem {
|
||||||
|
text: qsTr("Open Color Dialog")
|
||||||
|
onTriggered: colorPalette.showColorDialog(colorEditor.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GradientModel {
|
GradientModel {
|
||||||
id: gradientModel
|
id: gradientModel
|
||||||
anchorBackendProperty: anchorBackend
|
anchorBackendProperty: anchorBackend
|
||||||
|
@@ -61,7 +61,6 @@ RoundedPanel 2.0 RoundedPanel.qml
|
|||||||
ScrollView 2.0 ScrollView.qml
|
ScrollView 2.0 ScrollView.qml
|
||||||
SecondColumnLayout 2.0 SecondColumnLayout.qml
|
SecondColumnLayout 2.0 SecondColumnLayout.qml
|
||||||
Section 2.0 Section.qml
|
Section 2.0 Section.qml
|
||||||
SearchBox 2.0 SearchBox.qml
|
|
||||||
SectionLayout 2.0 SectionLayout.qml
|
SectionLayout 2.0 SectionLayout.qml
|
||||||
Spacer 2.0 Spacer.qml
|
Spacer 2.0 Spacer.qml
|
||||||
SpinBox 2.0 SpinBox.qml
|
SpinBox 2.0 SpinBox.qml
|
||||||
|
@@ -11,6 +11,8 @@ Item {
|
|||||||
|
|
||||||
property alias text: searchFilterText.text
|
property alias text: searchFilterText.text
|
||||||
|
|
||||||
|
signal searchChanged(string searchText);
|
||||||
|
|
||||||
function clear()
|
function clear()
|
||||||
{
|
{
|
||||||
searchFilterText.text = "";
|
searchFilterText.text = "";
|
||||||
@@ -58,7 +60,7 @@ Item {
|
|||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onTextChanged: rootView.handleSearchfilterChanged(text)
|
onTextChanged: root.searchChanged(text)
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: StudioTheme.Constants.search
|
text: StudioTheme.Constants.search
|
@@ -28,6 +28,8 @@ T.TextField {
|
|||||||
|
|
||||||
property string preFocusText: ""
|
property string preFocusText: ""
|
||||||
|
|
||||||
|
property bool contextMenuAboutToShow: false
|
||||||
|
|
||||||
horizontalAlignment: Qt.AlignLeft
|
horizontalAlignment: Qt.AlignLeft
|
||||||
verticalAlignment: Qt.AlignVCenter
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ T.TextField {
|
|||||||
|
|
||||||
readOnly: false
|
readOnly: false
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
persistentSelection: focus // QTBUG-73807
|
persistentSelection: contextMenu.visible || root.focus
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
width: StudioTheme.Values.defaultControlWidth
|
width: StudioTheme.Values.defaultControlWidth
|
||||||
@@ -56,28 +58,28 @@ T.TextField {
|
|||||||
enabled: true
|
enabled: true
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
propagateComposedEvents: true
|
propagateComposedEvents: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.NoButton
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onPressed: function(mouse) {
|
}
|
||||||
if (mouse.button === Qt.RightButton)
|
|
||||||
|
onPressed: function(event) {
|
||||||
|
if (event.button === Qt.RightButton)
|
||||||
contextMenu.popup(root)
|
contextMenu.popup(root)
|
||||||
|
|
||||||
mouse.accepted = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onPersistentSelectionChanged: {
|
|
||||||
if (!persistentSelection)
|
|
||||||
root.deselect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextMenu {
|
ContextMenu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
myTextEdit: root
|
myTextEdit: root
|
||||||
|
|
||||||
|
onClosed: root.forceActiveFocus()
|
||||||
|
onAboutToShow: root.contextMenuAboutToShow = true
|
||||||
|
onAboutToHide: root.contextMenuAboutToShow = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if (root.activeFocus)
|
// OtherFocusReason in this case means, if the TextField gets focus after the context menu
|
||||||
|
// was closed due to an menu item click.
|
||||||
|
if (root.activeFocus && root.focusReason !== Qt.OtherFocusReason)
|
||||||
root.preFocusText = root.text
|
root.preFocusText = root.text
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ T.TextField {
|
|||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: "default"
|
name: "default"
|
||||||
when: root.enabled && !root.hover && !root.edit
|
when: root.enabled && !root.hover && !root.edit && !contextMenu.visible
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: textFieldBackground
|
target: textFieldBackground
|
||||||
color: StudioTheme.Values.themeControlBackground
|
color: StudioTheme.Values.themeControlBackground
|
||||||
@@ -162,7 +164,7 @@ T.TextField {
|
|||||||
State {
|
State {
|
||||||
name: "globalHover"
|
name: "globalHover"
|
||||||
when: (actionIndicator.hover || translationIndicator.hover || indicator.hover)
|
when: (actionIndicator.hover || translationIndicator.hover || indicator.hover)
|
||||||
&& !root.edit && root.enabled
|
&& !root.edit && root.enabled && !contextMenu.visible
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: textFieldBackground
|
target: textFieldBackground
|
||||||
color: StudioTheme.Values.themeControlBackgroundGlobalHover
|
color: StudioTheme.Values.themeControlBackgroundGlobalHover
|
||||||
@@ -177,7 +179,7 @@ T.TextField {
|
|||||||
State {
|
State {
|
||||||
name: "hover"
|
name: "hover"
|
||||||
when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover
|
when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover
|
||||||
&& !indicator.hover && !root.edit && root.enabled
|
&& !indicator.hover && !root.edit && root.enabled && !contextMenu.visible
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: textFieldBackground
|
target: textFieldBackground
|
||||||
color: StudioTheme.Values.themeControlBackgroundHover
|
color: StudioTheme.Values.themeControlBackgroundHover
|
||||||
@@ -191,7 +193,7 @@ T.TextField {
|
|||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: "edit"
|
name: "edit"
|
||||||
when: root.edit
|
when: root.edit || contextMenu.visible
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: textFieldBackground
|
target: textFieldBackground
|
||||||
color: StudioTheme.Values.themeControlBackgroundInteraction
|
color: StudioTheme.Values.themeControlBackgroundInteraction
|
||||||
|
@@ -30,6 +30,7 @@ RealSpinBoxIndicator 1.0 RealSpinBoxIndicator.qml
|
|||||||
RealSpinBoxInput 1.0 RealSpinBoxInput.qml
|
RealSpinBoxInput 1.0 RealSpinBoxInput.qml
|
||||||
ScrollBar 1.0 ScrollBar.qml
|
ScrollBar 1.0 ScrollBar.qml
|
||||||
ScrollView 1.0 ScrollView.qml
|
ScrollView 1.0 ScrollView.qml
|
||||||
|
SearchBox 1.0 SearchBox.qml
|
||||||
SecondColumnLayout 1.0 SecondColumnLayout.qml
|
SecondColumnLayout 1.0 SecondColumnLayout.qml
|
||||||
Section 1.0 Section.qml
|
Section 1.0 Section.qml
|
||||||
SectionLabel 1.0 SectionLabel.qml
|
SectionLabel 1.0 SectionLabel.qml
|
||||||
|
@@ -84,8 +84,8 @@ DSsliderHandleHover=ff606060
|
|||||||
DSsliderHandleFocus=ff0492c9
|
DSsliderHandleFocus=ff0492c9
|
||||||
DSsliderHandleInteraction=ff2aafd3
|
DSsliderHandleInteraction=ff2aafd3
|
||||||
|
|
||||||
DSscrollBarTrack=ff404040
|
DSscrollBarTrack=ff3E3E3E
|
||||||
DSscrollBarHandle=ff505050
|
DSscrollBarHandle=ff4C4C4C
|
||||||
|
|
||||||
DSsectionHeadBackground=ff1f1f1f
|
DSsectionHeadBackground=ff1f1f1f
|
||||||
|
|
||||||
|
@@ -86,8 +86,8 @@ DSsliderHandleHover=ff606060
|
|||||||
DSsliderHandleFocus=ff0492c9
|
DSsliderHandleFocus=ff0492c9
|
||||||
DSsliderHandleInteraction=ff2aafd3
|
DSsliderHandleInteraction=ff2aafd3
|
||||||
|
|
||||||
DSscrollBarTrack=ff404040
|
DSscrollBarTrack=ff3E3E3E
|
||||||
DSscrollBarHandle=ff505050
|
DSscrollBarHandle=ff4C4C4C
|
||||||
|
|
||||||
DSsectionHeadBackground=ff1f1f1f
|
DSsectionHeadBackground=ff1f1f1f
|
||||||
|
|
||||||
|
@@ -88,8 +88,8 @@ DSsliderHandleHover=ff606060
|
|||||||
DSsliderHandleFocus=ff0492c9
|
DSsliderHandleFocus=ff0492c9
|
||||||
DSsliderHandleInteraction=ff2aafd3
|
DSsliderHandleInteraction=ff2aafd3
|
||||||
|
|
||||||
DSscrollBarTrack=ff404040
|
DSscrollBarTrack=ff3E3E3E
|
||||||
DSscrollBarHandle=ff505050
|
DSscrollBarHandle=ff4C4C4C
|
||||||
|
|
||||||
DSsectionHeadBackground=ff1f1f1f
|
DSsectionHeadBackground=ff1f1f1f
|
||||||
|
|
||||||
|
@@ -82,8 +82,8 @@ DSsliderHandleHover=ff606060
|
|||||||
DSsliderHandleFocus=ff0492c9
|
DSsliderHandleFocus=ff0492c9
|
||||||
DSsliderHandleInteraction=ff2aafd3
|
DSsliderHandleInteraction=ff2aafd3
|
||||||
|
|
||||||
DSscrollBarTrack=ff404040
|
DSscrollBarTrack=ff3E3E3E
|
||||||
DSscrollBarHandle=ff505050
|
DSscrollBarHandle=ff4C4C4C
|
||||||
|
|
||||||
DSsectionHeadBackground=ff1f1f1f
|
DSsectionHeadBackground=ff1f1f1f
|
||||||
|
|
||||||
|
@@ -166,7 +166,7 @@ QList<QToolButton *> AssetsLibraryWidget::createToolBarWidgets()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsLibraryWidget::handleSearchfilterChanged(const QString &filterText)
|
void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText)
|
||||||
{
|
{
|
||||||
if (filterText == m_filterText || (m_assetsModel->isEmpty() && filterText.contains(m_filterText)))
|
if (filterText == m_filterText || (m_assetsModel->isEmpty() && filterText.contains(m_filterText)))
|
||||||
return;
|
return;
|
||||||
|
@@ -56,7 +56,7 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
|
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
|
||||||
Q_INVOKABLE void handleAddAsset();
|
Q_INVOKABLE void handleAddAsset();
|
||||||
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
|
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
||||||
Q_INVOKABLE void handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
|
Q_INVOKABLE void handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
|
||||||
const QList<QUrl> &complexFilePaths,
|
const QList<QUrl> &complexFilePaths,
|
||||||
const QString &targetDirPath = {});
|
const QString &targetDirPath = {});
|
||||||
|
@@ -292,4 +292,68 @@ void ActionEditor::updateWindowName(const QString &targetName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActionEditor::invokeEditor(SignalHandlerProperty signalHandler,
|
||||||
|
std::function<void(SignalHandlerProperty)> onReject,
|
||||||
|
QObject * parent)
|
||||||
|
{
|
||||||
|
if (!signalHandler.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ModelNode connectionNode = signalHandler.parentModelNode();
|
||||||
|
if (!connectionNode.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!connectionNode.bindingProperty("target").isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ModelNode targetNode = connectionNode.bindingProperty("target").resolveToModelNode();
|
||||||
|
if (!targetNode.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString source = signalHandler.source();
|
||||||
|
|
||||||
|
QPointer<ActionEditor> editor = new ActionEditor(parent);
|
||||||
|
|
||||||
|
editor->showWidget();
|
||||||
|
editor->setModelNode(connectionNode);
|
||||||
|
editor->setConnectionValue(source);
|
||||||
|
editor->prepareConnections();
|
||||||
|
editor->updateWindowName(targetNode.validId() + "." + signalHandler.name());
|
||||||
|
|
||||||
|
QObject::connect(editor, &ActionEditor::accepted, [=]() {
|
||||||
|
if (!editor)
|
||||||
|
return;
|
||||||
|
if (editor->m_modelNode.isValid()) {
|
||||||
|
editor->m_modelNode.view()->executeInTransaction("ActionEditor::"
|
||||||
|
"invokeEditorAccepted",
|
||||||
|
[=]() {
|
||||||
|
editor->m_modelNode
|
||||||
|
.signalHandlerProperty(
|
||||||
|
signalHandler.name())
|
||||||
|
.setSource(
|
||||||
|
editor->connectionValue());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//closing editor widget somewhy triggers rejected() signal. Lets disconect before it affects us:
|
||||||
|
editor->disconnect();
|
||||||
|
editor->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(editor, &ActionEditor::rejected, [=]() {
|
||||||
|
if (!editor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (onReject) {
|
||||||
|
editor->m_modelNode.view()->executeInTransaction("ActionEditor::"
|
||||||
|
"invokeEditorOnRejectFunc",
|
||||||
|
[=]() { onReject(signalHandler); });
|
||||||
|
}
|
||||||
|
|
||||||
|
//closing editor widget somewhy triggers rejected() signal 2nd time. Lets disconect before it affects us:
|
||||||
|
editor->disconnect();
|
||||||
|
editor->deleteLater();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // QmlDesigner namespace
|
} // QmlDesigner namespace
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#include <bindingeditor/actioneditordialog.h>
|
#include <bindingeditor/actioneditordialog.h>
|
||||||
#include <qmldesignercorelib_global.h>
|
#include <qmldesignercorelib_global.h>
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
|
#include <signalhandlerproperty.h>
|
||||||
|
|
||||||
#include <QtQml>
|
#include <QtQml>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
@@ -44,6 +45,10 @@ public:
|
|||||||
|
|
||||||
Q_INVOKABLE void updateWindowName(const QString &targetName = {});
|
Q_INVOKABLE void updateWindowName(const QString &targetName = {});
|
||||||
|
|
||||||
|
static void invokeEditor(SignalHandlerProperty signalHandler,
|
||||||
|
std::function<void(SignalHandlerProperty)> onReject = nullptr,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void accepted();
|
void accepted();
|
||||||
void rejected();
|
void rejected();
|
||||||
|
@@ -12,6 +12,7 @@ namespace ComponentCoreConstants {
|
|||||||
const char rootCategory[] = "";
|
const char rootCategory[] = "";
|
||||||
|
|
||||||
const char selectionCategory[] = "Selection";
|
const char selectionCategory[] = "Selection";
|
||||||
|
const char connectionsCategory[] = "Connections";
|
||||||
const char arrangeCategory[] = "Arrange";
|
const char arrangeCategory[] = "Arrange";
|
||||||
const char qmlPreviewCategory[] = "QmlPreview";
|
const char qmlPreviewCategory[] = "QmlPreview";
|
||||||
const char editCategory[] = "Edit";
|
const char editCategory[] = "Edit";
|
||||||
@@ -76,6 +77,7 @@ const char openSignalDialogCommandId[] = "OpenSignalDialog";
|
|||||||
const char update3DAssetCommandId[] = "Update3DAsset";
|
const char update3DAssetCommandId[] = "Update3DAsset";
|
||||||
|
|
||||||
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
|
const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection");
|
||||||
|
const char connectionsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connections");
|
||||||
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
|
const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect");
|
||||||
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
|
const char selectEffectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select Effect");
|
||||||
const char arrangeCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Arrange");
|
const char arrangeCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Arrange");
|
||||||
@@ -183,6 +185,7 @@ const char editListModelDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMen
|
|||||||
|
|
||||||
const int priorityFirst = 280;
|
const int priorityFirst = 280;
|
||||||
const int prioritySelectionCategory = 220;
|
const int prioritySelectionCategory = 220;
|
||||||
|
const int priorityConnectionsCategory = 210;
|
||||||
const int priorityQmlPreviewCategory = 200;
|
const int priorityQmlPreviewCategory = 200;
|
||||||
const int priorityStackCategory = 180;
|
const int priorityStackCategory = 180;
|
||||||
const int priorityEditCategory = 160;
|
const int priorityEditCategory = 160;
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
#include <documentmanager.h>
|
#include <documentmanager.h>
|
||||||
#include <qmldesignerplugin.h>
|
#include <qmldesignerplugin.h>
|
||||||
#include <viewmanager.h>
|
#include <viewmanager.h>
|
||||||
|
#include <actioneditor.h>
|
||||||
|
|
||||||
#include <listmodeleditor/listmodeleditordialog.h>
|
#include <listmodeleditor/listmodeleditordialog.h>
|
||||||
#include <listmodeleditor/listmodeleditormodel.h>
|
#include <listmodeleditor/listmodeleditormodel.h>
|
||||||
@@ -433,6 +434,302 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QString prependSignal(QString signalHandlerName)
|
||||||
|
{
|
||||||
|
if (signalHandlerName.isNull() || signalHandlerName.isEmpty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QChar firstChar = signalHandlerName.at(0).toUpper();
|
||||||
|
signalHandlerName[0] = firstChar;
|
||||||
|
signalHandlerName.prepend(QLatin1String("on"));
|
||||||
|
|
||||||
|
return signalHandlerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList getSignalsList(const ModelNode &node)
|
||||||
|
{
|
||||||
|
if (!node.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!node.hasMetaInfo())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QStringList signalsList;
|
||||||
|
NodeMetaInfo nodeMetaInfo = node.metaInfo();
|
||||||
|
|
||||||
|
for (const auto &signalName : nodeMetaInfo.signalNames()) {
|
||||||
|
signalsList << QString::fromUtf8(signalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//on...Changed are the most regular signals, we assign them the lowest priority,
|
||||||
|
//we don't need them right now
|
||||||
|
// QStringList signalsWithChanged = signalsList.filter("Changed");
|
||||||
|
|
||||||
|
//these are item specific, like MouseArea.clicked, they have higher priority
|
||||||
|
QStringList signalsWithoutChanged = signalsList;
|
||||||
|
signalsWithoutChanged.removeIf([](QString str) {
|
||||||
|
if (str.endsWith("Changed"))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
QStringList finalResult;
|
||||||
|
finalResult.append(signalsWithoutChanged);
|
||||||
|
|
||||||
|
|
||||||
|
if (finalResult.isEmpty())
|
||||||
|
finalResult = signalsList;
|
||||||
|
|
||||||
|
finalResult.removeDuplicates();
|
||||||
|
|
||||||
|
return finalResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SlotEntry
|
||||||
|
{
|
||||||
|
QString category;
|
||||||
|
QString name;
|
||||||
|
std::function<void(SignalHandlerProperty)> action;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<SlotEntry> getSlotsLists(const ModelNode &node)
|
||||||
|
{
|
||||||
|
if (!node.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!node.view()->rootModelNode().isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QList<SlotEntry> resultList;
|
||||||
|
|
||||||
|
ModelNode rootNode = node.view()->rootModelNode();
|
||||||
|
QmlObjectNode rootObjectNode(rootNode);
|
||||||
|
|
||||||
|
const QString stateCategory = "Change State";
|
||||||
|
|
||||||
|
//For now we are using category as part of the state name
|
||||||
|
//We should change it, once we extend number of categories
|
||||||
|
const SlotEntry defaultState = {stateCategory,
|
||||||
|
(stateCategory + " to " + "Default State"),
|
||||||
|
[rootNode](SignalHandlerProperty signalHandler) {
|
||||||
|
signalHandler.setSource(
|
||||||
|
QString("%1.state = \"\"").arg(rootNode.id()));
|
||||||
|
}};
|
||||||
|
resultList.push_back(defaultState);
|
||||||
|
|
||||||
|
for (const auto &stateName : rootObjectNode.states().names()) {
|
||||||
|
SlotEntry entry = {stateCategory,
|
||||||
|
(stateCategory + " to " + stateName),
|
||||||
|
[rootNode, stateName](SignalHandlerProperty signalHandler) {
|
||||||
|
signalHandler.setSource(
|
||||||
|
QString("%1.state = \"%2\"").arg(rootNode.id(), stateName));
|
||||||
|
}};
|
||||||
|
|
||||||
|
resultList.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//creates connection without signalHandlerProperty
|
||||||
|
ModelNode createNewConnection(ModelNode targetNode)
|
||||||
|
{
|
||||||
|
NodeMetaInfo connectionsMetaInfo = targetNode.view()->model()->metaInfo("QtQuick.Connections");
|
||||||
|
ModelNode newConnectionNode = targetNode.view()
|
||||||
|
->createModelNode("QtQuick.Connections",
|
||||||
|
connectionsMetaInfo.majorVersion(),
|
||||||
|
connectionsMetaInfo.minorVersion());
|
||||||
|
if (QmlItemNode::isValidQmlItemNode(targetNode))
|
||||||
|
targetNode.nodeAbstractProperty("data").reparentHere(newConnectionNode);
|
||||||
|
|
||||||
|
newConnectionNode.bindingProperty("target").setExpression(targetNode.id());
|
||||||
|
|
||||||
|
return newConnectionNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSignal(SignalHandlerProperty signalHandler)
|
||||||
|
{
|
||||||
|
auto connectionNode = signalHandler.parentModelNode();
|
||||||
|
auto connectionSignals = connectionNode.signalProperties();
|
||||||
|
if (connectionSignals.size() > 1) {
|
||||||
|
if (connectionSignals.contains(signalHandler))
|
||||||
|
connectionNode.removeProperty(signalHandler.name());
|
||||||
|
} else {
|
||||||
|
connectionNode.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConnectionsModelNodeActionGroup : public ActionGroup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectionsModelNodeActionGroup(const QString &displayName,
|
||||||
|
const QByteArray &menuId,
|
||||||
|
int priority)
|
||||||
|
: ActionGroup(displayName,
|
||||||
|
menuId,
|
||||||
|
priority,
|
||||||
|
&SelectionContextFunctors::always,
|
||||||
|
&SelectionContextFunctors::selectionEnabled)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void updateContext() override
|
||||||
|
{
|
||||||
|
menu()->clear();
|
||||||
|
|
||||||
|
const auto selection = selectionContext();
|
||||||
|
if (!selection.isValid())
|
||||||
|
return;
|
||||||
|
if (!selection.singleNodeIsSelected())
|
||||||
|
return;
|
||||||
|
if (!action()->isEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ModelNode currentNode = selection.currentSingleSelectedNode();
|
||||||
|
QmlObjectNode currentObjectNode(currentNode);
|
||||||
|
|
||||||
|
QStringList signalsList = getSignalsList(currentNode);
|
||||||
|
QList<SlotEntry> slotsList = getSlotsLists(currentNode);
|
||||||
|
currentNode.validId();
|
||||||
|
|
||||||
|
for (const ModelNode &connectionNode : currentObjectNode.getAllConnections()) {
|
||||||
|
for (const AbstractProperty &property : connectionNode.properties()) {
|
||||||
|
if (property.isSignalHandlerProperty() && property.name() != "target") {
|
||||||
|
const auto signalHandler = property.toSignalHandlerProperty();
|
||||||
|
|
||||||
|
const QString propertyName = QString::fromUtf8(signalHandler.name());
|
||||||
|
|
||||||
|
QMenu *activeSignalHandlerGroup = new QMenu(propertyName, menu());
|
||||||
|
|
||||||
|
QMenu *editSignalGroup = new QMenu("Change Signal", menu());
|
||||||
|
|
||||||
|
for (const auto &signalStr : signalsList) {
|
||||||
|
if (prependSignal(signalStr).toUtf8() == signalHandler.name())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ActionTemplate *newSignalAction = new ActionTemplate(
|
||||||
|
(signalStr + "Id").toLatin1(),
|
||||||
|
signalStr,
|
||||||
|
[signalStr, signalHandler](const SelectionContext &) {
|
||||||
|
signalHandler.parentModelNode().view()->executeInTransaction(
|
||||||
|
"ConnectionsModelNodeActionGroup::"
|
||||||
|
"changeSignal",
|
||||||
|
[signalStr, signalHandler]() {
|
||||||
|
auto connectionNode = signalHandler.parentModelNode();
|
||||||
|
auto newHandler = connectionNode.signalHandlerProperty(
|
||||||
|
prependSignal(signalStr).toLatin1());
|
||||||
|
newHandler.setSource(signalHandler.source());
|
||||||
|
connectionNode.removeProperty(signalHandler.name());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
editSignalGroup->addAction(newSignalAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSignalHandlerGroup->addMenu(editSignalGroup);
|
||||||
|
|
||||||
|
if (!slotsList.isEmpty()) {
|
||||||
|
QMenu *editSlotGroup = new QMenu("Change Slot", menu());
|
||||||
|
|
||||||
|
for (const auto &slot : slotsList) {
|
||||||
|
ActionTemplate *newSlotAction = new ActionTemplate(
|
||||||
|
(slot.name + "Id").toLatin1(),
|
||||||
|
slot.name,
|
||||||
|
[slot, signalHandler](const SelectionContext &) {
|
||||||
|
signalHandler.parentModelNode()
|
||||||
|
.view()
|
||||||
|
->executeInTransaction("ConnectionsModelNodeActionGroup::"
|
||||||
|
"changeSlot",
|
||||||
|
[slot, signalHandler]() {
|
||||||
|
slot.action(signalHandler);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
editSlotGroup->addAction(newSlotAction);
|
||||||
|
}
|
||||||
|
activeSignalHandlerGroup->addMenu(editSlotGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionTemplate *openEditorAction = new ActionTemplate(
|
||||||
|
(propertyName + "OpenEditorId").toLatin1(),
|
||||||
|
QString(
|
||||||
|
QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Connections Editor")),
|
||||||
|
[=](const SelectionContext &) {
|
||||||
|
signalHandler.parentModelNode().view()->executeInTransaction(
|
||||||
|
"ConnectionsModelNodeActionGroup::"
|
||||||
|
"openConnectionsEditor",
|
||||||
|
[signalHandler]() { ActionEditor::invokeEditor(signalHandler); });
|
||||||
|
});
|
||||||
|
|
||||||
|
activeSignalHandlerGroup->addAction(openEditorAction);
|
||||||
|
|
||||||
|
ActionTemplate *removeSignalHandlerAction = new ActionTemplate(
|
||||||
|
(propertyName + "RemoveSignalHandlerId").toLatin1(),
|
||||||
|
QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Remove this handler")),
|
||||||
|
[signalHandler](const SelectionContext &) {
|
||||||
|
signalHandler.parentModelNode().view()->executeInTransaction(
|
||||||
|
"ConnectionsModelNodeActionGroup::"
|
||||||
|
"removeSignalHandler",
|
||||||
|
[signalHandler]() {
|
||||||
|
removeSignal(signalHandler);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
activeSignalHandlerGroup->addAction(removeSignalHandlerAction);
|
||||||
|
|
||||||
|
menu()->addMenu(activeSignalHandlerGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//singular add connection:
|
||||||
|
QMenu *addConnection = new QMenu(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
|
||||||
|
"Add signal handler")),
|
||||||
|
menu());
|
||||||
|
|
||||||
|
for (const auto &signalStr : signalsList) {
|
||||||
|
QMenu *newSignal = new QMenu(signalStr, addConnection);
|
||||||
|
|
||||||
|
for (const auto &slot : slotsList) {
|
||||||
|
ActionTemplate *newSlot = new ActionTemplate(
|
||||||
|
QString(signalStr + slot.name + "Id").toLatin1(),
|
||||||
|
slot.name,
|
||||||
|
[=](const SelectionContext &) {
|
||||||
|
currentNode.view()->executeInTransaction(
|
||||||
|
"ConnectionsModelNodeActionGroup::addConnection", [=]() {
|
||||||
|
ModelNode newConnectionNode = createNewConnection(currentNode);
|
||||||
|
slot.action(newConnectionNode.signalHandlerProperty(
|
||||||
|
prependSignal(signalStr).toLatin1()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
newSignal->addAction(newSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionTemplate *openEditorAction = new ActionTemplate(
|
||||||
|
(signalStr + "OpenEditorId").toLatin1(),
|
||||||
|
QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Connections Editor")),
|
||||||
|
[=](const SelectionContext &) {
|
||||||
|
currentNode.view()->executeInTransaction(
|
||||||
|
"ConnectionsModelNodeActionGroup::"
|
||||||
|
"openConnectionsEditor",
|
||||||
|
[=]() {
|
||||||
|
ModelNode newConnectionNode = createNewConnection(currentNode);
|
||||||
|
|
||||||
|
SignalHandlerProperty newHandler
|
||||||
|
= newConnectionNode.signalHandlerProperty(
|
||||||
|
prependSignal(signalStr).toLatin1());
|
||||||
|
|
||||||
|
newHandler.setSource(
|
||||||
|
QString("console.log(\"%1.%2\")").arg(currentNode.id(), signalStr));
|
||||||
|
ActionEditor::invokeEditor(newHandler, removeSignal);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
newSignal->addAction(openEditorAction);
|
||||||
|
|
||||||
|
addConnection->addMenu(newSignal);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu()->addMenu(addConnection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DocumentError : public std::exception
|
class DocumentError : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -953,6 +1250,11 @@ void DesignerActionManager::createDefaultDesignerActions()
|
|||||||
selectionCategory,
|
selectionCategory,
|
||||||
prioritySelectionCategory));
|
prioritySelectionCategory));
|
||||||
|
|
||||||
|
addDesignerAction(new ConnectionsModelNodeActionGroup(
|
||||||
|
connectionsCategoryDisplayName,
|
||||||
|
connectionsCategory,
|
||||||
|
priorityConnectionsCategory));
|
||||||
|
|
||||||
addDesignerAction(new ActionGroup(
|
addDesignerAction(new ActionGroup(
|
||||||
arrangeCategoryDisplayName,
|
arrangeCategoryDisplayName,
|
||||||
arrangeCategory,
|
arrangeCategory,
|
||||||
|
@@ -527,9 +527,17 @@ void DebugView::instancesToken(const QString &/*tokenName*/, int /*tokenNumber*/
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugView::currentStateChanged(const ModelNode &/*node*/)
|
void DebugView::currentStateChanged(const ModelNode &node)
|
||||||
{
|
{
|
||||||
|
if (isDebugViewEnabled()) {
|
||||||
|
QTextStream message;
|
||||||
|
QString string;
|
||||||
|
message.setString(&string);
|
||||||
|
|
||||||
|
message << node;
|
||||||
|
|
||||||
|
log("::currentStateChanged:", string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugView::nodeOrderChanged([[maybe_unused]] const NodeListProperty &listProperty)
|
void DebugView::nodeOrderChanged([[maybe_unused]] const NodeListProperty &listProperty)
|
||||||
|
@@ -205,7 +205,7 @@ QList<QToolButton *> ItemLibraryWidget::createToolBarWidgets()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText)
|
void ItemLibraryWidget::handleSearchFilterChanged(const QString &filterText)
|
||||||
{
|
{
|
||||||
if (filterText != m_filterText) {
|
if (filterText != m_filterText) {
|
||||||
m_filterText = filterText;
|
m_filterText = filterText;
|
||||||
|
@@ -69,7 +69,7 @@ public:
|
|||||||
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
|
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
|
||||||
Q_INVOKABLE void removeImport(const QString &importUrl);
|
Q_INVOKABLE void removeImport(const QString &importUrl);
|
||||||
Q_INVOKABLE void addImportForItem(const QString &importUrl);
|
Q_INVOKABLE void addImportForItem(const QString &importUrl);
|
||||||
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
|
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
||||||
Q_INVOKABLE void handleAddImport(int index);
|
Q_INVOKABLE void handleAddImport(int index);
|
||||||
Q_INVOKABLE void goIntoComponent(const QString &source);
|
Q_INVOKABLE void goIntoComponent(const QString &source);
|
||||||
|
|
||||||
|
@@ -97,8 +97,9 @@ QString BundleImporter::importComponent(const QString &qmlFile,
|
|||||||
FilePath qmlSourceFile = bundleImportPath.resolvePath(FilePath::fromString(qmlFile));
|
FilePath qmlSourceFile = bundleImportPath.resolvePath(FilePath::fromString(qmlFile));
|
||||||
const bool qmlFileExists = qmlSourceFile.exists();
|
const bool qmlFileExists = qmlSourceFile.exists();
|
||||||
const QString qmlType = qmlSourceFile.baseName();
|
const QString qmlType = qmlSourceFile.baseName();
|
||||||
m_pendingTypes.append(QStringLiteral("%1.%2")
|
m_pendingTypes.append(QStringLiteral("%1.%2.%3")
|
||||||
.arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), qmlType));
|
.arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
|
||||||
|
m_bundleId, qmlType));
|
||||||
if (!qmldirContent.contains(qmlFile)) {
|
if (!qmldirContent.contains(qmlFile)) {
|
||||||
qmldirContent.append(qmlType);
|
qmldirContent.append(qmlType);
|
||||||
qmldirContent.append(" 1.0 ");
|
qmldirContent.append(" 1.0 ");
|
||||||
@@ -159,10 +160,6 @@ QString BundleImporter::importComponent(const QString &qmlFile,
|
|||||||
// If import is not yet possible, import statement needs to be added asynchronously to
|
// If import is not yet possible, import statement needs to be added asynchronously to
|
||||||
// avoid errors, as code model update takes a while.
|
// avoid errors, as code model update takes a while.
|
||||||
m_importAddPending = true;
|
m_importAddPending = true;
|
||||||
|
|
||||||
// Full reset is not necessary if new import directory appearing will trigger scanning,
|
|
||||||
// but if directory existed but was not valid possible import, we need to do a reset.
|
|
||||||
m_fullReset = bundleImportPathExists;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_importTimerCount = 0;
|
m_importTimerCount = 0;
|
||||||
|
@@ -30,9 +30,10 @@ namespace QmlDesigner {
|
|||||||
BundleMaterial::BundleMaterial(QObject *parent,
|
BundleMaterial::BundleMaterial(QObject *parent,
|
||||||
const QString &name,
|
const QString &name,
|
||||||
const QString &qml,
|
const QString &qml,
|
||||||
|
const TypeName &type,
|
||||||
const QUrl &icon,
|
const QUrl &icon,
|
||||||
const QStringList &files)
|
const QStringList &files)
|
||||||
: QObject(parent), m_name(name), m_qml(qml), m_icon(icon), m_files(files) {}
|
: QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files) {}
|
||||||
|
|
||||||
bool BundleMaterial::filter(const QString &searchText)
|
bool BundleMaterial::filter(const QString &searchText)
|
||||||
{
|
{
|
||||||
@@ -54,6 +55,11 @@ QString BundleMaterial::qml() const
|
|||||||
return m_qml;
|
return m_qml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeName BundleMaterial::type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList BundleMaterial::files() const
|
QStringList BundleMaterial::files() const
|
||||||
{
|
{
|
||||||
return m_files;
|
return m_files;
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "qmldesignercorelib_global.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
@@ -43,6 +45,7 @@ public:
|
|||||||
BundleMaterial(QObject *parent,
|
BundleMaterial(QObject *parent,
|
||||||
const QString &name,
|
const QString &name,
|
||||||
const QString &qml,
|
const QString &qml,
|
||||||
|
const TypeName &type,
|
||||||
const QUrl &icon,
|
const QUrl &icon,
|
||||||
const QStringList &files);
|
const QStringList &files);
|
||||||
|
|
||||||
@@ -50,6 +53,7 @@ public:
|
|||||||
|
|
||||||
QUrl icon() const;
|
QUrl icon() const;
|
||||||
QString qml() const;
|
QString qml() const;
|
||||||
|
TypeName type() const;
|
||||||
QStringList files() const;
|
QStringList files() const;
|
||||||
bool visible() const;
|
bool visible() const;
|
||||||
|
|
||||||
@@ -59,6 +63,7 @@ signals:
|
|||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_qml;
|
QString m_qml;
|
||||||
|
TypeName m_type;
|
||||||
QUrl m_icon;
|
QUrl m_icon;
|
||||||
QStringList m_files;
|
QStringList m_files;
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "bundleimporter.h"
|
#include "bundleimporter.h"
|
||||||
#include "bundlematerial.h"
|
#include "bundlematerial.h"
|
||||||
#include "bundlematerialcategory.h"
|
#include "bundlematerialcategory.h"
|
||||||
|
#include "qmldesignerconstants.h"
|
||||||
#include "utils/qtcassert.h"
|
#include "utils/qtcassert.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -121,6 +122,8 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
|
|
||||||
m_matBundleExists = true;
|
m_matBundleExists = true;
|
||||||
|
|
||||||
|
const QString bundleId = m_matBundleObj.value("id").toString();
|
||||||
|
|
||||||
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
|
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
|
||||||
const QStringList categories = catsObj.keys();
|
const QStringList categories = catsObj.keys();
|
||||||
for (const QString &cat : categories) {
|
for (const QString &cat : categories) {
|
||||||
@@ -136,8 +139,14 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr)
|
for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr)
|
||||||
files.append(asset.toString());
|
files.append(asset.toString());
|
||||||
|
|
||||||
auto bundleMat = new BundleMaterial(category, mat, matObj.value("qml").toString(),
|
QUrl icon = QUrl::fromLocalFile(matBundleDir.filePath(matObj.value("icon").toString()));
|
||||||
QUrl::fromLocalFile(matBundleDir.filePath(matObj.value("icon").toString())), files);
|
QString qml = matObj.value("qml").toString();
|
||||||
|
TypeName type = QLatin1String("%1.%2.%3").arg(
|
||||||
|
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
|
||||||
|
bundleId,
|
||||||
|
qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
||||||
|
|
||||||
|
auto bundleMat = new BundleMaterial(category, mat, qml, type, icon, files);
|
||||||
|
|
||||||
category->addBundleMaterial(bundleMat);
|
category->addBundleMaterial(bundleMat);
|
||||||
}
|
}
|
||||||
@@ -149,7 +158,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
|
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
|
||||||
sharedFiles.append(file.toString());
|
sharedFiles.append(file.toString());
|
||||||
|
|
||||||
m_importer = new Internal::BundleImporter(matBundleDir.path(), "MaterialBundle", sharedFiles);
|
m_importer = new Internal::BundleImporter(matBundleDir.path(), bundleId, sharedFiles);
|
||||||
connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||||
if (metaInfo.isValid())
|
if (metaInfo.isValid())
|
||||||
emit addBundleMaterialToProjectRequested(metaInfo);
|
emit addBundleMaterialToProjectRequested(metaInfo);
|
||||||
@@ -223,7 +232,10 @@ void MaterialBrowserBundleModel::applyToSelected(BundleMaterial *mat, bool add)
|
|||||||
|
|
||||||
void MaterialBrowserBundleModel::addMaterial(BundleMaterial *mat)
|
void MaterialBrowserBundleModel::addMaterial(BundleMaterial *mat)
|
||||||
{
|
{
|
||||||
m_importer->importComponent(mat->qml(), mat->files());
|
QString err = m_importer->importComponent(mat->qml(), mat->files());
|
||||||
|
|
||||||
|
if (!err.isEmpty())
|
||||||
|
qWarning() << __FUNCTION__ << err;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -266,8 +266,7 @@ void MaterialBrowserModel::removeMaterial(const ModelNode &material)
|
|||||||
|
|
||||||
void MaterialBrowserModel::deleteSelectedMaterial()
|
void MaterialBrowserModel::deleteSelectedMaterial()
|
||||||
{
|
{
|
||||||
if (isValidIndex(m_selectedIndex))
|
deleteMaterial(m_selectedIndex);
|
||||||
m_materialList[m_selectedIndex].destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserModel::updateSelectedMaterial()
|
void MaterialBrowserModel::updateSelectedMaterial()
|
||||||
@@ -365,7 +364,11 @@ void MaterialBrowserModel::pasteMaterialProperties(int idx)
|
|||||||
|
|
||||||
void MaterialBrowserModel::deleteMaterial(int idx)
|
void MaterialBrowserModel::deleteMaterial(int idx)
|
||||||
{
|
{
|
||||||
m_materialList[idx].destroy();
|
if (isValidIndex(idx)) {
|
||||||
|
ModelNode node = m_materialList[idx];
|
||||||
|
if (node.isValid())
|
||||||
|
QmlObjectNode(node).destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserModel::renameMaterial(int idx, const QString &newName)
|
void MaterialBrowserModel::renameMaterial(int idx, const QString &newName)
|
||||||
|
@@ -93,6 +93,8 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
mat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
|
mat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
|
||||||
else if (prop.isBindingProperty())
|
else if (prop.isBindingProperty())
|
||||||
mat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
|
mat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
|
||||||
|
else if (!all)
|
||||||
|
mat.removeProperty(prop.name());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -105,33 +107,62 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
MaterialBrowserBundleModel *matBrowserBundleModel = m_widget->materialBrowserBundleModel().data();
|
MaterialBrowserBundleModel *matBrowserBundleModel = m_widget->materialBrowserBundleModel().data();
|
||||||
|
|
||||||
connect(matBrowserBundleModel, &MaterialBrowserBundleModel::applyToSelectedTriggered, this,
|
connect(matBrowserBundleModel, &MaterialBrowserBundleModel::applyToSelectedTriggered, this,
|
||||||
[&] (BundleMaterial *material, bool add) {
|
[&] (BundleMaterial *bundleMat, bool add) {
|
||||||
if (!m_selectedModel.isValid())
|
if (!m_selectedModel.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_bundleMaterialDropTarget = m_selectedModel;
|
m_bundleMaterialDropTarget = m_selectedModel;
|
||||||
m_bundleMaterialAddToSelected = add;
|
m_bundleMaterialAddToSelected = add;
|
||||||
m_widget->materialBrowserBundleModel()->addMaterial(material);
|
|
||||||
|
ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type());
|
||||||
|
if (defaultMat.isValid())
|
||||||
|
applyBundleMaterialToDropTarget(defaultMat);
|
||||||
|
else
|
||||||
|
m_widget->materialBrowserBundleModel()->addMaterial(bundleMat);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(matBrowserBundleModel, &MaterialBrowserBundleModel::addBundleMaterialToProjectRequested, this,
|
connect(matBrowserBundleModel, &MaterialBrowserBundleModel::addBundleMaterialToProjectRequested, this,
|
||||||
[&] (const QmlDesigner::NodeMetaInfo &metaInfo) {
|
[&] (const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||||
|
applyBundleMaterialToDropTarget({}, metaInfo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return createWidgetInfo(m_widget.data(),
|
||||||
|
"MaterialBrowser",
|
||||||
|
WidgetInfo::LeftPane,
|
||||||
|
0,
|
||||||
|
tr("Material Browser"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialBrowserView::applyBundleMaterialToDropTarget(const ModelNode &bundleMat,
|
||||||
|
const NodeMetaInfo &metaInfo)
|
||||||
|
{
|
||||||
|
if (!bundleMat.isValid() && !metaInfo.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
ModelNode matLib = materialLibraryNode();
|
ModelNode matLib = materialLibraryNode();
|
||||||
if (!matLib.isValid())
|
if (!matLib.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
executeInTransaction("MaterialBrowserView::widgetInfo", [&] {
|
executeInTransaction("MaterialBrowserView::applyBundleMaterialToDropTarget", [&] {
|
||||||
ModelNode newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(),
|
ModelNode newMatNode;
|
||||||
|
if (metaInfo.isValid()) {
|
||||||
|
newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(),
|
||||||
metaInfo.minorVersion());
|
metaInfo.minorVersion());
|
||||||
matLib.defaultNodeListProperty().reparentHere(newMatNode);
|
matLib.defaultNodeListProperty().reparentHere(newMatNode);
|
||||||
|
|
||||||
static QRegularExpression rgx("([A-Z])([a-z]*)");
|
static QRegularExpression rgx("([A-Z])([a-z]*)");
|
||||||
QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed();
|
QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed();
|
||||||
|
if (newName.endsWith(" Material"))
|
||||||
|
newName.chop(9); // remove trailing " Material"
|
||||||
QString newId = model()->generateIdFromName(newName, "material");
|
QString newId = model()->generateIdFromName(newName, "material");
|
||||||
newMatNode.setIdWithRefactoring(newId);
|
newMatNode.setIdWithRefactoring(newId);
|
||||||
|
|
||||||
VariantProperty objNameProp = newMatNode.variantProperty("objectName");
|
VariantProperty objNameProp = newMatNode.variantProperty("objectName");
|
||||||
objNameProp.setValue(newName);
|
objNameProp.setValue(newName);
|
||||||
|
} else {
|
||||||
|
newMatNode = bundleMat;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_bundleMaterialDropTarget.isValid()) {
|
if (m_bundleMaterialDropTarget.isValid()) {
|
||||||
QmlObjectNode qmlObjNode(m_bundleMaterialDropTarget);
|
QmlObjectNode qmlObjNode(m_bundleMaterialDropTarget);
|
||||||
@@ -164,19 +195,11 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
} else {
|
} else {
|
||||||
qmlObjNode.setBindingProperty("materials", newMatNode.id());
|
qmlObjNode.setBindingProperty("materials", newMatNode.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bundleMaterialDropTarget = {};
|
m_bundleMaterialDropTarget = {};
|
||||||
}
|
|
||||||
|
|
||||||
m_bundleMaterialAddToSelected = false;
|
m_bundleMaterialAddToSelected = false;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return createWidgetInfo(m_widget.data(),
|
|
||||||
"MaterialBrowser",
|
|
||||||
WidgetInfo::LeftPane,
|
|
||||||
0,
|
|
||||||
tr("Material Browser"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserView::modelAttached(Model *model)
|
void MaterialBrowserView::modelAttached(Model *model)
|
||||||
@@ -347,6 +370,28 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups()
|
|||||||
m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath);
|
m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelNode MaterialBrowserView::getBundleMaterialDefaultInstance(const TypeName &type)
|
||||||
|
{
|
||||||
|
const QList<ModelNode> materials = m_widget->materialBrowserModel()->materials();
|
||||||
|
for (const ModelNode &mat : materials) {
|
||||||
|
if (mat.type() == type) {
|
||||||
|
bool isDefault = true;
|
||||||
|
const QList<AbstractProperty> props = mat.properties();
|
||||||
|
for (const AbstractProperty &prop : props) {
|
||||||
|
if (prop.name() != "objectName") {
|
||||||
|
isDefault = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefault)
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
|
void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
|
||||||
[[maybe_unused]] const QList<Import> &removedImports)
|
[[maybe_unused]] const QList<Import> &removedImports)
|
||||||
{
|
{
|
||||||
@@ -383,7 +428,14 @@ void MaterialBrowserView::customNotification(const AbstractView *view,
|
|||||||
m_widget->materialBrowserModel()->deleteSelectedMaterial();
|
m_widget->materialBrowserModel()->deleteSelectedMaterial();
|
||||||
} else if (identifier == "drop_bundle_material") {
|
} else if (identifier == "drop_bundle_material") {
|
||||||
m_bundleMaterialDropTarget = nodeList.first();
|
m_bundleMaterialDropTarget = nodeList.first();
|
||||||
|
|
||||||
|
|
||||||
|
ModelNode defaultMat = getBundleMaterialDefaultInstance(m_draggedBundleMaterial->type());
|
||||||
|
if (defaultMat.isValid())
|
||||||
|
applyBundleMaterialToDropTarget(defaultMat);
|
||||||
|
else
|
||||||
m_widget->materialBrowserBundleModel()->addMaterial(m_draggedBundleMaterial);
|
m_widget->materialBrowserBundleModel()->addMaterial(m_draggedBundleMaterial);
|
||||||
|
|
||||||
m_draggedBundleMaterial = nullptr;
|
m_draggedBundleMaterial = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <abstractview.h>
|
#include "abstractview.h"
|
||||||
|
#include "nodemetainfo.h"
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@ private:
|
|||||||
void refreshModel(bool updateImages);
|
void refreshModel(bool updateImages);
|
||||||
bool isMaterial(const ModelNode &node) const;
|
bool isMaterial(const ModelNode &node) const;
|
||||||
void loadPropertyGroups();
|
void loadPropertyGroups();
|
||||||
|
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {});
|
||||||
|
ModelNode getBundleMaterialDefaultInstance(const TypeName &type);
|
||||||
|
|
||||||
QPointer<MaterialBrowserWidget> m_widget;
|
QPointer<MaterialBrowserWidget> m_widget;
|
||||||
ModelNode m_bundleMaterialDropTarget;
|
ModelNode m_bundleMaterialDropTarget;
|
||||||
|
@@ -192,7 +192,7 @@ void MaterialBrowserWidget::contextHelp(const Core::IContext::HelpCallback &call
|
|||||||
callback({});
|
callback({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserWidget::handleSearchfilterChanged(const QString &filterText)
|
void MaterialBrowserWidget::handleSearchFilterChanged(const QString &filterText)
|
||||||
{
|
{
|
||||||
if (filterText != m_filterText) {
|
if (filterText != m_filterText) {
|
||||||
m_filterText = filterText;
|
m_filterText = filterText;
|
||||||
|
@@ -51,7 +51,7 @@ public:
|
|||||||
QPointer<MaterialBrowserBundleModel> materialBrowserBundleModel() const;
|
QPointer<MaterialBrowserBundleModel> materialBrowserBundleModel() const;
|
||||||
void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap);
|
void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap);
|
||||||
|
|
||||||
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
|
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
||||||
Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos);
|
Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos);
|
||||||
Q_INVOKABLE void startDragBundleMaterial(QmlDesigner::BundleMaterial *bundleMat, const QPointF &mousePos);
|
Q_INVOKABLE void startDragBundleMaterial(QmlDesigner::BundleMaterial *bundleMat, const QPointF &mousePos);
|
||||||
|
|
||||||
|
@@ -720,7 +720,7 @@ void StatesEditorView::propertiesRemoved(const QList<AbstractProperty>& property
|
|||||||
for (const AbstractProperty &property : propertyList) {
|
for (const AbstractProperty &property : propertyList) {
|
||||||
if (property.name() == "states" && property.parentModelNode() == activeStateGroup().modelNode())
|
if (property.name() == "states" && property.parentModelNode() == activeStateGroup().modelNode())
|
||||||
resetModel();
|
resetModel();
|
||||||
if (property.name() == "when"
|
if ((property.name() == "when" || property.name() == "name")
|
||||||
&& QmlModelState::isValidQmlModelState(property.parentModelNode()))
|
&& QmlModelState::isValidQmlModelState(property.parentModelNode()))
|
||||||
resetModel();
|
resetModel();
|
||||||
if (property.name() == "extend")
|
if (property.name() == "extend")
|
||||||
@@ -848,7 +848,8 @@ void StatesEditorView::variantPropertiesChanged(const QList<VariantProperty> &pr
|
|||||||
auto guard = qScopeGuard([&]() { m_block = false; });
|
auto guard = qScopeGuard([&]() { m_block = false; });
|
||||||
|
|
||||||
for (const VariantProperty &property : propertyList) {
|
for (const VariantProperty &property : propertyList) {
|
||||||
if (property.name() == "name" && QmlModelState::isValidQmlModelState(property.parentModelNode()))
|
if (property.name() == "name"
|
||||||
|
&& QmlModelState::isValidQmlModelState(property.parentModelNode()))
|
||||||
resetModel();
|
resetModel();
|
||||||
else if (property.name() == "state"
|
else if (property.name() == "state"
|
||||||
&& property.parentModelNode() == activeStateGroup().modelNode())
|
&& property.parentModelNode() == activeStateGroup().modelNode())
|
||||||
|
@@ -35,11 +35,13 @@ void MeshImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
if (file.open()) {
|
if (file.open()) {
|
||||||
QString qtQuickVersion;
|
QString qtQuickVersion;
|
||||||
QString qtQuick3DVersion;
|
QString qtQuick3DVersion;
|
||||||
|
if (target()) {
|
||||||
QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit());
|
QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit());
|
||||||
if (qtVersion && qtVersion->qtVersion() < QVersionNumber(6, 0, 0)) {
|
if (qtVersion && qtVersion->qtVersion() < QVersionNumber(6, 0, 0)) {
|
||||||
qtQuickVersion = "2.15";
|
qtQuickVersion = "2.15";
|
||||||
qtQuick3DVersion = "1.15";
|
qtQuick3DVersion = "1.15";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString content{
|
QString content{
|
||||||
R"(import QtQuick %1
|
R"(import QtQuick %1
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
#ifndef STYLESHEETMERGER_H
|
#ifndef STYLESHEETMERGER_H
|
||||||
#define STYLESHEETMERGER_H
|
#define STYLESHEETMERGER_H
|
||||||
|
|
||||||
|
#include "qmldesignercorelib_global.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
@@ -19,8 +21,8 @@ struct ReparentInfo {
|
|||||||
bool alreadyReparented;
|
bool alreadyReparented;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QMLDESIGNERCORE_EXPORT StylesheetMerger
|
||||||
class StylesheetMerger {
|
{
|
||||||
public:
|
public:
|
||||||
StylesheetMerger(AbstractView*, AbstractView*);
|
StylesheetMerger(AbstractView*, AbstractView*);
|
||||||
void merge();
|
void merge();
|
||||||
|
@@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
#include "texttomodelmerger.h"
|
#include "texttomodelmerger.h"
|
||||||
#include "modeltotextmerger.h"
|
#include "modeltotextmerger.h"
|
||||||
|
#include "model_p.h"
|
||||||
|
|
||||||
#include <bindingproperty.h>
|
#include <bindingproperty.h>
|
||||||
#include <customnotifications.h>
|
#include <customnotifications.h>
|
||||||
#include <filemanager/astobjecttextextractor.h>
|
#include <filemanager/astobjecttextextractor.h>
|
||||||
#include <filemanager/firstdefinitionfinder.h>
|
#include <filemanager/firstdefinitionfinder.h>
|
||||||
#include <filemanager/objectlengthcalculator.h>
|
#include <filemanager/objectlengthcalculator.h>
|
||||||
#include <model_p.h>
|
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
#include <modelnodepositionstorage.h>
|
#include <modelnodepositionstorage.h>
|
||||||
#include <nodeproperty.h>
|
#include <nodeproperty.h>
|
||||||
|
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-16px.png
Normal file
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-16px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 339 B |
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-24px.png
Normal file
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-24px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 712 B |
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-24px@2x.png
Normal file
BIN
src/plugins/qmldesigner/qtquickplugin/images/timer-24px@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@@ -98,5 +98,8 @@
|
|||||||
<file>images/timeline-16px.png</file>
|
<file>images/timeline-16px.png</file>
|
||||||
<file>images/keyframe-16px.png</file>
|
<file>images/keyframe-16px.png</file>
|
||||||
<file>images/timeline-animation-16px.png</file>
|
<file>images/timeline-animation-16px.png</file>
|
||||||
|
<file>images/timer-16px.png</file>
|
||||||
|
<file>images/timer-24px.png</file>
|
||||||
|
<file>images/timer-24px@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -487,6 +487,25 @@ MetaInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type {
|
||||||
|
name: "QtQml.Timer"
|
||||||
|
icon: ":/qtquickplugin/images/timer-16px.png"
|
||||||
|
|
||||||
|
Hints {
|
||||||
|
visibleInNavigator: true
|
||||||
|
canBeDroppedInNavigator: true
|
||||||
|
canBeDroppedInFormEditor: false
|
||||||
|
canBeContainer: false
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemLibraryEntry {
|
||||||
|
name: "Timer"
|
||||||
|
category: "d.Qt Quick - Animation"
|
||||||
|
libraryIcon: ":/qtquickplugin/images/timer-24px.png"
|
||||||
|
version: "2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type {
|
Type {
|
||||||
name: "QtQml.Component"
|
name: "QtQml.Component"
|
||||||
icon: ":/qtquickplugin/images/component-icon16.png"
|
icon: ":/qtquickplugin/images/component-icon16.png"
|
||||||
|
@@ -21,7 +21,14 @@ FileStoreIo::FileStoreIo(const QString &fileName)
|
|||||||
|
|
||||||
QByteArray FileStoreIo::read() const
|
QByteArray FileStoreIo::read() const
|
||||||
{
|
{
|
||||||
m_file->open(QFile::ReadOnly | QFile::Text);
|
if (!m_file->exists())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!m_file->open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qWarning() << "Cannot load User Preset(s)";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray data = m_file->readAll();
|
QByteArray data = m_file->readAll();
|
||||||
m_file->close();
|
m_file->close();
|
||||||
|
|
||||||
@@ -30,7 +37,11 @@ QByteArray FileStoreIo::read() const
|
|||||||
|
|
||||||
void FileStoreIo::write(const QByteArray &data)
|
void FileStoreIo::write(const QByteArray &data)
|
||||||
{
|
{
|
||||||
m_file->open(QFile::WriteOnly | QFile::Text);
|
if (!m_file->open(QFile::WriteOnly | QFile::Text)) {
|
||||||
|
qWarning() << "Cannot save User Preset(s)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_file->write(data);
|
m_file->write(data);
|
||||||
m_file->close();
|
m_file->close();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user