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:
Eike Ziller
2022-09-27 10:03:37 +02:00
61 changed files with 932 additions and 201 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -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}.

View File

@@ -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.

View File

@@ -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

View File

@@ -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}.

View File

@@ -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());

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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
} }

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}; };

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)
} }
} }
} }

View File

@@ -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
} }
} }

View File

@@ -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

View File

@@ -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 {}
}
}
}
}

View File

@@ -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

View File

@@ -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: {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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 = {});

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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,

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
} }
} }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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())

View File

@@ -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

View File

@@ -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();

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -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>

View File

@@ -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"

View File

@@ -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();
} }