diff options
author | Janne Kangas <janne.kangas@qt.io> | 2017-12-15 11:53:56 +0200 |
---|---|---|
committer | Janne Kangas <janne.kangas@qt.io> | 2018-01-19 10:17:42 +0000 |
commit | 337aaa465ac78ac72ca748f0c2d4c3b6257829b8 (patch) | |
tree | 538354b89f2a96d220f1137e8fba867400fcfa9d | |
parent | 849b12c5df97ec268c5efce27ea96daa7676e525 (diff) |
[DataInput] Add UI enablers for linking DataInput and Text
Add popup for text property that allows choosing a datainput in scene
to be controller for the property.
DataInput toggle icon and other functionality can be enabled by adding
'Controllable="True"' parameter to textstring property in MetaData.xml
Task-Id: QT3DS-337
Change-Id: I5ab25566866cb45134d36e025e21e94f98944eaf
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
15 files changed, 784 insertions, 47 deletions
diff --git a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp index b48cd318..b1e3c8c3 100644 --- a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp +++ b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp @@ -1343,7 +1343,7 @@ bool CClientDataModelBridge::IsDuplicateable(qt3dsdm::Qt3DSDMInstanceHandle inIn EStudioObjectType theObjectType = GetObjectType(inInstance); if (theObjectType == OBJTYPE_SCENE || theObjectType == OBJTYPE_MATERIAL - || theObjectType == OBJTYPE_IMAGE) + || theObjectType == OBJTYPE_IMAGE ||theObjectType == OBJTYPE_DATAINPUT) return false; // If we are delving inside component and selecting the component itself (the component is root // in timeline palette) diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp index 87662d5b..3ac72680 100644 --- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp +++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp @@ -32,6 +32,7 @@ #include "Doc.h" #include "Qt3DSFileTools.h" #include "StudioFullSystem.h" +#include "IObjectReferenceHelper.h" #include "foundation/Qt3DS.h" #include "foundation/Qt3DSAssert.h" #include "StudioCoreSystem.h" @@ -658,6 +659,40 @@ public: } } + // Resolve all instances that are controlled by datainput instance + void GetControlledInstancesAndProperties(TInstanceHandle dataInput, + TInstancePropertyPairList &ctrldInstsProps) + { + Q_ASSERT(m_Bridge.IsDataInputInstance(dataInput)); + IObjectReferenceHelper *objReferenceHelper = m_Doc.GetDataModelObjectReferenceHelper(); + + Option<SValue> controlledElemProp + = GetInstancePropertyValue( + dataInput, + m_Bridge.GetObjectDefinitions().m_DataInput.m_ControlledElemProp); + CString controlledElemPropStr = get<TDataStrPtr>(*controlledElemProp)->GetData(); + + std::string::size_type thePos = 0; + bool fullResolved = false; + CRelativePathTools::EPathType type; + // Controlled instance and property names are stored in "controlledelemprop" + // property as a single string, each item separated by whitespace. Parse + // names and get corresponding handles. + while (thePos < controlledElemPropStr.size()) { + CString theCurrentElemStr = controlledElemPropStr.substr( + thePos, controlledElemPropStr.find(' ', thePos) - thePos); + thePos += theCurrentElemStr.size() + 1; + CString theCurrentPropStr = controlledElemPropStr.substr( + thePos, controlledElemPropStr.find(' ', thePos) - thePos); + thePos += theCurrentPropStr.size() + 1; + TInstanceHandle currElement = CRelativePathTools::FindAssetInstanceByObjectPath( + &m_Doc, m_Doc.GetActiveRootInstance(), theCurrentElemStr, + type, fullResolved, objReferenceHelper); + TPropertyHandle currProp = FindProperty(currElement, theCurrentPropStr); + ctrldInstsProps.push_back(TInstancePropertyPair(currElement, currProp)); + } + } + bool IsInSceneGraph(TInstanceHandle child) const override { return m_AssetGraph.IsExist(child); } // If the path has any sub-path children, then yes it is externalizeable. @@ -729,7 +764,20 @@ public: return false; return m_AnimationCore.IsArtistEdited(animHandle); } - + bool IsControlled(TInstanceHandle instance) + { + // TODO This is Text element specific code + if (!m_Bridge.IsTextInstance(instance)) + return false; + Option<SValue> currentControlledProperty = GetInstancePropertyValue( + instance, m_Bridge.GetObjectDefinitions().m_Text.m_ControlledProperty); + if (!currentControlledProperty.hasValue()) + return false; + CString propStr = (get<TDataStrPtr>(*currentControlledProperty))->GetData(); + if (!propStr.IsEmpty()) + return true; + return false; + } pair<std::shared_ptr<qt3dsdm::IDOMWriter>, CFilePath> DoCopySceneGraphObject(const TInstanceHandleList &inInstances) { @@ -1049,6 +1097,7 @@ public: void DoDeleteInstance(Qt3DSDMInstanceHandle instance) { + IObjectReferenceHelper *objReferenceHelper = m_Doc.GetDataModelObjectReferenceHelper(); // For delete, the metadata needs to participate in the undo/redo system. m_MetaData.SetConsumer(m_StudioSystem.GetFullSystem()->GetConsumer()); TInstanceHandleList theDeleteDependentInstances; @@ -1167,16 +1216,40 @@ public: && theInstanceChildren[0] == instance)); theDeleteDependentInstances.push_back(theInstanceParent); } + } else if (m_Bridge.IsDataInputInstance(instance)) { + // When DataInput is deleted, we must set properties controlled by it + // in target instances to uncontrolled + TInstancePropertyPairList instPropPairList; + GetControlledInstancesAndProperties(instance, instPropPairList); + // Iterate through instance-property pairs and set to uncontrolled + for (size_t idx = 0, end = instPropPairList.size(); idx < end; ++idx) { + CString controlledElemStr = objReferenceHelper->GetObjectReferenceString( + m_Doc.GetSceneInstance(), CRelativePathTools::EPATHTYPE_GUID, + instPropPairList[idx].first); + SetInstancePropertyControlled(instPropPairList[idx].first, + controlledElemStr, + instPropPairList[idx].second, + 0, false); + } } // Note that the instance and its parents are still valid. // we delete from the bottom of the asset graph upwards. + // If any instance properties are controlled by a datainput, + // remove control first + if (IsControlled(instance)) + RemoveAllControlForInstance(instance); + m_DataCore.DeleteInstance(instance); + if (m_AssetGraph.IsExist(instance)) m_AssetGraph.RemoveNode(instance); for (size_t idx = 0; idx < theDeleteDependentInstances.size(); ++idx) { QT3DS_ASSERT(!m_AssetGraph.IsExist(theDeleteDependentInstances[idx])); + if (IsControlled(theDeleteDependentInstances[idx])) + RemoveAllControlForInstance(theDeleteDependentInstances[idx]); + m_DataCore.DeleteInstance(theDeleteDependentInstances[idx]); } } @@ -1372,54 +1445,175 @@ public: } SetName(theMaterial, materialName); } - + // Set a property in an instance to be controlled by datainput. + // We build two strings here. "Controlled element - controlled property" -string + // goes to controlling datainput and details all elements and their properties + // that a specified datainput should control. "Controlling datanode - controlled + // property" -string is specific for this (=controlled) instance and contains + // the path of controlling datanode and the controlled property(/-ies). void SetInstancePropertyControlled(TInstanceHandle instance, CString instancepath, TPropertyHandle propName, TInstanceHandle controller, bool controlled) override { SComposerObjectDefinitions &theDefinitions(m_Bridge.GetObjectDefinitions()); + IObjectReferenceHelper* objReferenceHelper = m_Doc.GetDataModelObjectReferenceHelper(); // get the name of controlled property auto metadataHandle = m_MetaData.GetMetaDataProperty(instance, propName); auto metadata = m_MetaData.GetMetaDataPropertyInfo(metadataHandle); const wchar_t *propname = metadata->m_Name.wide_str(); - qt3dsdm::SValue controlledProperty = std::make_shared<CDataStr>(propname); - // get existing string of controlled elements and properties from controlling - // datainput - qt3dsdm::SValue controlledElemProp; - m_DataCore.GetInstancePropertyValue( - controller, theDefinitions.m_DataInput.m_ControlledElemProp, controlledElemProp); - QString controlledElemPropStr = controlledElemProp.toQVariant().toString(); - - // build the controlled element - controlled property string specific for this element - instancepath.append(" "); - instancepath.append(propname); - instancepath.append(" "); - - // If property was set to controlled, append element - property string to the list - // held by the controlling datainput. Otherwise, remove this element-property -pair from it. - if (controlled) - controlledElemPropStr.append(instancepath.toQString()); - else - controlledElemPropStr.remove(instancepath.toQString()); + SValue controlledProperty; + Option<SValue> controlledElemProp; + CString controlledElemPropStr; + SValue controllerName; + + // Get the name of controller instance and build controller - controlled property + // string. + // If we are setting control on, we have incoming controller handle from + // dialog. + // If control is simply being set off from UI toggle, we need to get the current + // controlling instance from a property string held by this instance, for the purposes + // of removing the control target from the controller datainput + if (controlled) { + // controller instance must be valid when setting control to true + Q_ASSERT(controller != 0); + // get existing string of controlled elements and properties from controlling + // datainput + controlledElemProp = GetInstancePropertyValue( + controller, theDefinitions.m_DataInput.m_ControlledElemProp); + controlledElemPropStr = get<TDataStrPtr>(*controlledElemProp)->GetData(); + + // build the controlled element - controlled property string specific for this element + instancepath.append(" "); + instancepath.append(propname); + instancepath.append(" "); + + // append this element - property pair to existing items that datainput already controls + controlledElemPropStr.append(instancepath); + + // build the controller datainput - controlled property string + CString controlledElemStr = objReferenceHelper->GetObjectReferenceString( + m_Doc.GetSceneInstance(), CRelativePathTools::EPATHTYPE_GUID, controller); + controlledElemStr.append(" "); + controlledElemStr.append(metadata->m_Name.c_str()); + + controlledProperty = std::make_shared<CDataStr>(controlledElemStr); + // Text element -specific: show controlling datainput name in brackets + // as the textstring contents for clarity + controllerName = std::make_shared<CDataStr>("[" + m_Bridge.GetName(controller) + "]"); + } else { + // TODO: this is Text element-specific at the moment + // Get controller - property -pair for this element + Option<SValue> currentControlledProperty = GetInstancePropertyValue( + instance, theDefinitions.m_Text.m_ControlledProperty); + + TDataStrPtr theNamePtr(get<TDataStrPtr>(*currentControlledProperty)); + CString controllerNameStr = theNamePtr->GetData(); + + // Check if this property has a controlling datainput before trying + // to delete it from the list of controlled properties + if (controllerNameStr.size()) { + // get the controlling datainput name only + controllerNameStr = controllerNameStr.substr(0, controllerNameStr.find(" ")); + + bool theFullResolvedFlag; + CRelativePathTools::EPathType type; + controller = CRelativePathTools::FindAssetInstanceByObjectPath( + &m_Doc, m_Doc.GetActiveRootInstance(), controllerNameStr, + type, theFullResolvedFlag, objReferenceHelper); + + // get existing string of controlled elements and properties from controlling + // datainput + controlledElemProp = GetInstancePropertyValue( + controller, theDefinitions.m_DataInput.m_ControlledElemProp); + controlledElemPropStr = get<TDataStrPtr>(*controlledElemProp)->GetData(); + // build the string for this element-property -pair and remove it + // from items that datanode controls + instancepath.append(" "); + instancepath.append(metadata->m_Name.c_str()); + instancepath.append(" "); + controlledElemPropStr.Replace(instancepath, ""); + + // Set controller - property -string empty for this element. + // We need to explicitly set controlledProperty with an empty string initializer, + // otherwise it will have type "None" instead of "String". + // TODO: for now only a single textstring property can be controlled. For + // control of several properties in a single element, we must only remove + // a specific controller - property pair from controlledProperty string, not all. + controlledProperty = std::make_shared<CDataStr>(CString()); + + // Set the textstring content to default when disabling datainput control + // TODO: restore the previous text content prior to setting it to controlled + controllerName = theDefinitions.m_Text.m_TextString.m_DefaultValue.getValue(); + } else { + // We are trying to turn control off for property that had no existing control. + // This might happen when user toggles control on and off without setting + // the controller from the selection dialog. + // Nothing to do except to make sure that we set the textstring to default and + // controlledProperty to an empty string. + controlledProperty = std::make_shared<CDataStr>(CString()); + controllerName = theDefinitions.m_Text.m_TextString.m_DefaultValue.getValue(); + + m_DataCore.SetInstancePropertyValue(instance, + theDefinitions.m_Text.m_ControlledProperty, + controlledProperty); + SetInstancePropertyValue(instance, + theDefinitions.m_Text.m_TextString, + controllerName); + // early return to avoid trying to set property in the non-existent + // controller instance + return; + } + } - qCDebug(qt3ds::TRACE_INFO) << "SetInstance datainput controlledelemprop: instance " - << controller - << " property " << theDefinitions.m_DataInput.m_ControlledElemProp.m_Property - << " value " << controlledElemPropStr; + // Set properties both in the controller and the controlled instance + SValue finalControlledElemProp = std::make_shared<CDataStr>(controlledElemPropStr); - controlledElemProp = std::make_shared<CDataStr>(controlledElemPropStr.toStdWString().c_str()); // For DataInput and Alias, property values are set through datacore. // Set the newly built controlledelemprop string for the controlling datainput m_DataCore.SetInstancePropertyValue(controller, theDefinitions.m_DataInput.m_ControlledElemProp, - controlledElemProp); + finalControlledElemProp); // Set the controlledproperty string in the controlled element // TODO: For the moment this is Text element -specific only m_DataCore.SetInstancePropertyValue(instance, theDefinitions.m_Text.m_ControlledProperty, controlledProperty); + + // Show the controller name also in Inspector Text field as visual reminder. + // DataInput does not set any values to target in Editor; we need to show something + // to indicate where the values will be coming from during animation so we use + // controller name in brackets. + // Do not set this value directly via datacore so that the value updates in Studio UI. + if (m_Bridge.IsTextInstance(instance)) { + SetInstancePropertyValue(instance, + theDefinitions.m_Text.m_TextString, + controllerName); + } + } + + // Remove datainput control of all properties of this instance, + // for example when deleting the entire instance + void RemoveAllControlForInstance(TInstanceHandle instance) + { + SComposerObjectDefinitions &theDefinitions(m_Bridge.GetObjectDefinitions()); + IObjectReferenceHelper* objReferenceHelper = m_Doc.GetDataModelObjectReferenceHelper(); + + // TODO: text element-specific. Also, only removes a single controller-property + // pair as currently only textstring can be controlled. For generic + // implementation we need to iterate through all controller-property pairs + // and remove control for each of them separately (a single instance can have + // several different datainputs each controlling a single or multiple properties + // i.e. one-to-many mapping). + SetInstancePropertyControlled(instance, + objReferenceHelper->GetObjectReferenceString( + m_Doc.GetSceneInstance(), + CRelativePathTools::EPATHTYPE_GUID, + instance), + theDefinitions.m_Text.m_TextString, + 0, + false); } // Normal way in to the system. @@ -2385,9 +2579,18 @@ public: // messages. // The timeline, for instance, requires that before a create operation happens all remove // operations have happened. - + QList<CString> instancePaths; qt3dsdm::TInstanceHandleList sortableList(ToGraphOrdering(inInstances)); for (size_t idx = 0, end = sortableList.size(); idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance(sortableList[idx]); + instancePaths.push_back( + m_Doc.GetDataModelObjectReferenceHelper()->GetObjectReferenceString( + m_Doc.GetSceneInstance(), + CRelativePathTools::EPATHTYPE_GUID, + theInstance)); + } + + for (size_t idx = 0, end = sortableList.size(); idx < end; ++idx) { m_AssetGraph.RemoveChild(sortableList[idx], false); } @@ -2415,13 +2618,71 @@ public: else if (inInsertType == DocumentEditorInsertType::LastChild) m_AssetGraph.MoveTo(theInstance, inDest, COpaquePosition::LAST); } + + for (size_t idx = 0, end = sortableList.size(); idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance(sortableList[idx]); + if (inInsertType == DocumentEditorInsertType::NextSibling) + theInstance = sortableList[end - idx - 1]; + if (IsControlled(theInstance)) + UpdateDataInputTarget(theInstance, instancePaths[idx]); + } } + // Called when controlled instance is moved inside scene graph and + // controlling datanode must update the instance path + void UpdateDataInputTarget(TInstanceHandle instance, CString oldPath) + { + SComposerObjectDefinitions &objDefinitions(m_Bridge.GetObjectDefinitions()); + // TODO: Text-element specific code + Option<SValue> currentControlledProperty = GetInstancePropertyValue( + instance, objDefinitions.m_Text.m_ControlledProperty); + CString controllerNameStr + = (get<TDataStrPtr>(*currentControlledProperty))->GetData(); + + Q_ASSERT(controllerNameStr.size()); + + // get the controlling datainput name only + controllerNameStr = controllerNameStr.substr(0, controllerNameStr.find(" ")); + + bool theFullResolvedFlag; + CRelativePathTools::EPathType type; + TInstanceHandle controller = CRelativePathTools::FindAssetInstanceByObjectPath( + &m_Doc, m_Doc.GetActiveRootInstance(), controllerNameStr, + type, theFullResolvedFlag, m_Doc.GetDataModelObjectReferenceHelper()); + + // get existing string of controlled elements and properties from controlling + // datainput and replace old path with new + Option<SValue> controlledElemProp = GetInstancePropertyValue( + controller, objDefinitions.m_DataInput.m_ControlledElemProp); + CString controlledElemPropStr = get<TDataStrPtr>(*controlledElemProp)->GetData(); + + CString currentInstancePath = m_Doc.GetDataModelObjectReferenceHelper() + ->GetObjectReferenceString(m_Doc.GetSceneInstance(), + CRelativePathTools::EPATHTYPE_GUID, + instance); + controlledElemPropStr.Replace(oldPath, currentInstancePath); + + // Set the new controlled properties string to controlling datainput + SValue finalControlledElemProp = std::make_shared<CDataStr>(controlledElemPropStr); + + m_DataCore.SetInstancePropertyValue(controller, + objDefinitions.m_DataInput.m_ControlledElemProp, + finalControlledElemProp); + } Qt3DSDMInstanceHandle MakeComponent(const qt3dsdm::TInstanceHandleList &inInstances) override { if (inInstances.empty()) return Qt3DSDMInstanceHandle(); + // TODO: For now, we need to break control relationship for instances that are + // included in the newly made component as the binding goes wrong during + // instance "copy to mem - delete - insert" sequence needed for component creation. + // This means that at the moment, datainput cannot control a property + // within a component instance. + for (size_t idx = 0; idx < inInstances.size(); idx++) { + if (IsControlled(inInstances[idx])) + RemoveAllControlForInstance(inInstances[idx]); + } qt3dsdm::TInstanceHandleList theInstances = ToGraphOrdering(inInstances); // Do this in reverse order. // first add new component. diff --git a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h index 765c5b4c..500bf2a2 100644 --- a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h +++ b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h @@ -196,6 +196,10 @@ public: SetInstancePropertyValueAsRenderable(TInstanceHandle instance, TPropertyHandle propName, const Q3DStudio::CString &inSourcePath) = 0; + // Sets/unsets "instance" property "propName" to be controlled by datainput "controller" + // and adds element - property pair to controlling datainput control list. "Instancepath" + // must correspond to controlled instance path as it is the data used by controller to + // locate element when controlling the property value virtual void SetInstancePropertyControlled(TInstanceHandle instance, CString instancepath, TPropertyHandle propName, TInstanceHandle controller, diff --git a/src/Authoring/Client/Code/Core/Doc/RelativePathTools.cpp b/src/Authoring/Client/Code/Core/Doc/RelativePathTools.cpp index 6ea23673..03998b29 100644 --- a/src/Authoring/Client/Code/Core/Doc/RelativePathTools.cpp +++ b/src/Authoring/Client/Code/Core/Doc/RelativePathTools.cpp @@ -190,6 +190,10 @@ qt3dsdm::Qt3DSDMInstanceHandle CRelativePathTools::FindAssetInstanceByObjectPath outIsResolved = true; theFoundInstance = inRootInstance; outPathType = EPATHTYPE_RELATIVE; + } else if (theCurrentToken.Compare(CPathConstructionHelper::GetSceneString(), false)) { + outIsResolved = true; + theFoundInstance = inRootInstance; + outPathType = EPATHTYPE_RELATIVE; } else if (theCurrentToken.Compare(CPathConstructionHelper::GetParentString(), false)) { outIsResolved = true; theFoundInstance = theBridge->GetParentInstance(inRootInstance); diff --git a/src/Authoring/Studio/Palettes/Inspector/DataInputBrowser.qml b/src/Authoring/Studio/Palettes/Inspector/DataInputBrowser.qml new file mode 100644 index 00000000..d92a5b2d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/DataInputBrowser.qml @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 +import Qt3DStudio 1.0 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + spacing: 10 + + ListView { + id: browserList + + Layout.margins: 10 + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 80 + Layout.preferredHeight: count * 20 + Layout.preferredWidth: root.width + + ScrollBar.vertical: ScrollBar {} + + model: _dataInputChooserView.model + boundsBehavior: Flickable.StopAtBounds + clip: true + currentIndex: _dataInputChooserView.selection + + delegate: Item { + id: delegateItem + + x: model.depth * 20 + width: parent.width + height: model.parentExpanded ? typeIcon.height + 10 : 0 + + visible: height > 0 + + Behavior on height { + NumberAnimation { + duration: 100 + easing.type: Easing.OutQuad + } + } + + Row { + id: row + + height: typeIcon.height + spacing: 5 + + Image { + source: { + if (!model.hasChildren) + return ""; + model.expanded ? _resDir + "arrow_down.png" + : _resDir + "arrow.png"; + } + + MouseArea { + anchors.fill: parent + onClicked: model.expanded = !model.expanded + } + } + + Rectangle { + height: typeIcon.height + width: typeIcon.width + name.width + 10 + + color: model.index === browserList.currentIndex ? _selectionColor + : "transparent" + + Row { + spacing: 10 + Image { + id: typeIcon + + source: model.icon + } + + StyledLabel { + id: name + anchors.verticalCenter: typeIcon.verticalCenter + color: model.textColor + text: model.name + } + } + + MouseArea { + id: delegateArea + + anchors.fill: parent + onClicked: { + if (_dataInputChooserView.selectable(model.index)) + browserList.currentIndex = model.index; + } + onDoubleClicked: { + if (_dataInputChooserView.selectable(model.index)) { + browserList.currentIndex = model.index; + _dataInputChooserView.close(); + } + } + } + } + } + } + + onCurrentIndexChanged: _dataInputChooserView.selection = currentIndex + + Connections { + target: _dataInputChooserView + onSelectionChanged: { + if (browserList.currentIndex !== _dataInputChooserView.selection) + browserList.currentIndex = _dataInputChooserView.selection; + } + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.cpp new file mode 100644 index 00000000..142c39c4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "DataInputChooserView.h" + +#include "CColor.h" +#include "Literals.h" +#include "ObjectListModel.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +DataInputChooserView::DataInputChooserView(QWidget *parent) + : QQuickWidget(parent) +{ + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &DataInputChooserView::initialize); +} + +QAbstractItemModel *DataInputChooserView::model() const +{ + return m_model; +} + +void DataInputChooserView::setModel(ObjectListModel *model) +{ + if (!m_model) + m_model = new FlatObjectListModel(model, this); + + m_model->setSourceModel(model); + + Q_EMIT modelChanged(); +} + + +QSize DataInputChooserView::sizeHint() const +{ + return {500, 500}; +} + +QString DataInputChooserView::name(int index) const +{ + return m_model->index(index, 0).data(ObjectListModel::NameRole).toString(); +} + +QString DataInputChooserView::path(int index) const +{ + return m_model->index(index, 0).data(ObjectListModel::PathReferenceRole).toString(); +} + +bool DataInputChooserView::selectable(int index) const +{ + auto handleId = m_model->index(index, 0).data(ObjectListModel::HandleRole).toInt(); + auto handle = qt3dsdm::Qt3DSDMInstanceHandle(handleId); + return m_model->sourceModel()->selectable(handle); +} + +void DataInputChooserView::selectAndExpand(const qt3dsdm::Qt3DSDMInstanceHandle &handle) +{ + QModelIndex index = m_model->sourceModel()->indexForHandle(handle); + m_model->expandTo(QModelIndex(), index); + setSelection(m_model->rowForSourceIndex(index)); +} + +void DataInputChooserView::setSelection(int index) +{ + if (m_selection != index) { + m_selection = index; + Q_EMIT selectionChanged(); + } +} + +qt3dsdm::Qt3DSDMInstanceHandle DataInputChooserView::selectedHandle() const +{ + auto handleId = m_model->index(m_selection, 0).data(ObjectListModel::HandleRole).toInt(); + return qt3dsdm::Qt3DSDMInstanceHandle(handleId); +} + +void DataInputChooserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &DataInputChooserView::close); +} + +void DataInputChooserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_dataInputChooserView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + qmlRegisterUncreatableType<DataInputChooserView>( + "Qt3DStudio", 1, 0, "DataInputChooserView", + tr("Creation of DataInputChooserView not allowed from QML")); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Palettes/Inspector/DataInputBrowser.qml"_L1)); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.h b/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.h new file mode 100644 index 00000000..ce8ded82 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/DataInputChooserView.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef DATAINPUTCHOOSERVIEW_H +#define DATAINPUTCHOOSERVIEW_H + +#include <QQuickWidget> + +#include "RelativePathTools.h" +#include "Qt3DSDMHandles.h" + +#include <QColor> + +class ObjectListModel; +class FlatObjectListModel; + +QT_FORWARD_DECLARE_CLASS(QAbstractItemModel) + +class DataInputChooserView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL) + Q_PROPERTY(int selection READ selection WRITE setSelection NOTIFY selectionChanged FINAL) + +public: + DataInputChooserView(QWidget *parent = nullptr); + + enum PathType { + Name = CRelativePathTools::EPATHTYPE_GUID, + Relative = CRelativePathTools::EPATHTYPE_RELATIVE, + }; + Q_ENUM(PathType) + + QAbstractItemModel *model() const; + void setModel(ObjectListModel *model); + QSize sizeHint() const override; + + Q_INVOKABLE QString name(int index) const; + Q_INVOKABLE QString path(int index) const; + Q_INVOKABLE bool selectable(int index) const; + + void selectAndExpand(const qt3dsdm::Qt3DSDMInstanceHandle &handle); + + int selection() const { return m_selection; } + void setSelection(int index); + + qt3dsdm::Qt3DSDMInstanceHandle selectedHandle() const; + +Q_SIGNALS: + void modelChanged(); + void selectionChanged(); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void initialize(); + + FlatObjectListModel *m_model = nullptr; + QHash<int, ObjectListModel *> m_subModels; + QColor m_baseColor = QColor::fromRgb(75, 75, 75); + QColor m_selectColor; + int m_selection = -1; +}; + +#endif // DATAINPUTCHOOSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp index 53a16861..7ebb42ba 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp @@ -375,6 +375,8 @@ InspectorControlBase* InspectorControlModel::createItem(Qt3DSDMInspectable *insp Q3DStudio::CString propertyNameStr = metaProperty.m_Name.c_str(); // is this property controlled in this element? item->m_controlled = currPropValStr.contains(propertyNameStr.toQString()); + // This works for now because Text element textstring is only controllable property so far. + item->m_controlled = currPropValStr.contains(propertyNameStr.toQString()); m_controlledToggleConnection = signalProvider->ConnectControlledToggled( std::bind(&InspectorControlModel::updateControlledToggleState, @@ -916,7 +918,8 @@ void InspectorControlModel::setSlideSelection(long instance, int handle, int ind ->SetInstancePropertyValue(instance, handle, newSelectedData); } -void InspectorControlModel::setPropertyControlled(long instance, int property, bool controlled) +void InspectorControlModel::setPropertyControllerInstance(long instance, int property, + long controllerInstance, bool controlled) { CDoc *doc = g_StudioApp.GetCore()->GetDoc(); const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); @@ -926,25 +929,34 @@ void InspectorControlModel::setPropertyControlled(long instance, int property, b Q3DStudio::CString instancepath = Q3DStudio::CString( objRefHelper->GetObjectReferenceString(doc->GetSceneInstance(), CRelativePathTools::EPATHTYPE_GUID, instance)); - // TODO this is test code, hardwired for item named DataInput - // We need to have the datainput handle or name as input to this - // function, coming from dialog - Q3DStudio::CString controller = Q3DStudio::CString("this.DataInput"); - - bool theFullResolvedFlag; - CRelativePathTools::EPathType type; - qt3dsdm::Qt3DSDMInstanceHandle controllerhandle - = CRelativePathTools::FindAssetInstanceByObjectPath( - doc, doc->GetActiveRootInstance(), controller, - type, theFullResolvedFlag, objRefHelper); + Q_ASSERT(instancepath.size()); Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property Controlled")) ->SetInstancePropertyControlled(instance, instancepath, property, - controllerhandle, controlled); + controllerInstance, controlled); +} +void InspectorControlModel::setPropertyControlled(long instance, int property, bool controlled) +{ + const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); const auto signalSender = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalSender(); signalSender->SendControlledToggled(instance, property); + // If control is toggled on, we do not need to do anything here except toggle the UI icon, + // and set the controller to "None" as DataInput selector dialog will later call + // setPropertyControllerInstance() and set the correct controller handle and name. + // If we are setting control off, no need to find out the datainput that controls this pair. + // SetInstancePropertyControlled() will get the current controller from controlledProperty + // of this item and removes control. + if (controlled) { + Q3DStudio::SCOPED_DOCUMENT_EDITOR( + *g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property")) + ->SetInstancePropertyValue( + instance, property, std::make_shared<qt3dsdm::CDataStr>( + Q3DStudio::CString::fromQString(tr("[None]")))); + } else { + setPropertyControllerInstance(instance, property, 0, controlled); + } } void InspectorControlModel::setPropertyAnimated(long instance, int handle, bool animated) diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h index 36bfef06..bafe9753 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h @@ -124,13 +124,16 @@ public: QVariant getPropertyValue(long instance, int handle); qt3dsdm::SValue currentPropertyValue(long instance, int handle); + void setPropertyControllerInstance(long instance, int handle, + long controllerInstance, bool controlled); + Q_INVOKABLE void setMaterialTypeValue(long instance, int handle, const QVariant &value); Q_INVOKABLE void setRenderableValue(long instance, int handle, const QVariant &value); Q_INVOKABLE void setPropertyValue(long instance, int handle, const QVariant &value, bool commit = true); Q_INVOKABLE void setSlideSelection(long instance, int handle, int index, const QStringList &list); Q_INVOKABLE void setPropertyAnimated(long instance, int handle, bool animated); - Q_INVOKABLE void setPropertyControlled(long instance, int handle, bool controlled); + Q_INVOKABLE void setPropertyControlled(long instance, int property, bool controlled); private: void onSlideRearranged(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int inOldIndex, diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp index 99197d4f..c93c0539 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp @@ -42,6 +42,7 @@ #include "IDocumentEditor.h" #include "ImageChooserModel.h" #include "ImageChooserView.h" +#include "DataInputChooserView.h" #include "MeshChooserView.h" #include "TextureChooserView.h" #include "InspectableBase.h" @@ -460,6 +461,60 @@ QObject *InspectorControlView::showObjectReference(int handle, int instance, con return m_objectReferenceView; } +QObject *InspectorControlView::showDataInputChooser(int handle, int instance, const QPoint &point) +{ + CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + if (!m_objectReferenceModel) { + m_objectReferenceModel + = new ObjectListModel(g_StudioApp.GetCore(), doc->GetActiveRootInstance(), this); + } + if (!m_dataInputChooserView) + m_dataInputChooserView = new DataInputChooserView(this); + m_dataInputChooserView->setModel(m_objectReferenceModel); + + // TODO: for now datainput chooser can only be evoked from text element. + // Remove this restriction when other element types can also be controlled + if (doc->GetStudioSystem()->GetClientDataModelBridge() + ->GetObjectType(instance) == OBJTYPE_TEXT) { + QVector<EStudioObjectType> exclude; + exclude << OBJTYPE_ALIAS << OBJTYPE_BEHAVIOR << OBJTYPE_MODEL + << OBJTYPE_EFFECT << OBJTYPE_GUIDE << OBJTYPE_IMAGE << OBJTYPE_LAYER + << OBJTYPE_MATERIAL << OBJTYPE_REFERENCEDMATERIAL << OBJTYPE_CAMERA + << OBJTYPE_LIGHT << OBJTYPE_GROUP << OBJTYPE_TEXT + << OBJTYPE_COMPONENT << OBJTYPE_SLIDE << OBJTYPE_RENDERPLUGIN + << OBJTYPE_CUSTOMMATERIAL << OBJTYPE_PATH << OBJTYPE_PATHANCHORPOINT + << OBJTYPE_SUBPATH << OBJTYPE_SOUND << OBJTYPE_LIGHTMAPS; + m_objectReferenceModel->excludeObjectTypes(exclude); + } else { + m_objectReferenceModel->excludeObjectTypes(QVector<EStudioObjectType>()); + } + + disconnect(m_dataInputChooserView, nullptr, nullptr, nullptr); + + IObjectReferenceHelper *objRefHelper = doc->GetDataModelObjectReferenceHelper(); + if (objRefHelper) { + qt3dsdm::SValue value = m_inspectorControlModel->currentPropertyValue(instance, handle); + qt3dsdm::Qt3DSDMInstanceHandle refInstance = objRefHelper->Resolve(value, instance); + m_dataInputChooserView->selectAndExpand(refInstance); + } + + showBrowser(m_dataInputChooserView, point); + + connect(m_dataInputChooserView, &DataInputChooserView::selectionChanged, + this, [this, doc, handle, instance] { + auto selectedItem = m_dataInputChooserView->selectedHandle(); + qt3dsdm::SValue value = m_inspectorControlModel->currentPropertyValue(instance, handle); + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property")) + ->SetInstancePropertyValue(instance, handle, value); + + m_inspectorControlModel->setPropertyControllerInstance(instance, handle, + selectedItem, true); + }); + + return m_dataInputChooserView; +} + void InspectorControlView::showBrowser(QQuickWidget *browser, const QPoint &point) { QSize popupSize = CStudioPreferences::browserPopupSize(); diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h index 564f71c8..bccd2e91 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h @@ -41,6 +41,7 @@ class InspectorControlModel; QT_FORWARD_DECLARE_CLASS(QAbstractItemModel) class CInspectableBase; class ImageChooserView; +class DataInputChooserView; class ImageChooserModel; class MeshChooserView; class ObjectBrowserView; @@ -74,6 +75,7 @@ public: Q_INVOKABLE QObject *showMeshChooser(int handle, int instance, const QPoint &point); Q_INVOKABLE QObject *showObjectReference(int handle, int instance, const QPoint &point); Q_INVOKABLE QObject *showTextureChooser(int handle, int instance, const QPoint &point); + Q_INVOKABLE QObject *showDataInputChooser(int handle, int instance, const QPoint &point); Q_INVOKABLE void showDataInputDialog(); // IDataModelListener @@ -120,6 +122,7 @@ private: QPointer<MeshChooserView> m_meshChooserView; QPointer<FileChooserView> m_fileChooserView; QPointer<TextureChooserView> m_textureChooserView; + QPointer<DataInputChooserView> m_dataInputChooserView; QPointer<ObjectBrowserView> m_objectReferenceView; QPointer<ObjectListModel> m_objectReferenceModel; std::vector<Q3DStudio::CFilePath> m_fileList; diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml index 758572e2..e59577c3 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml @@ -207,7 +207,7 @@ Rectangle { _inspectorModel.setPropertyControlled( model.modelData.instance, model.modelData.handle, - !model.modelData.controlled) + !model.modelData.controlled); } else { const coords = mapToItem(root, mouse.x, mouse.y); groupDelegateItem.showContextMenu(coords); @@ -298,8 +298,12 @@ Rectangle { return renderableDropDown; if (modelData.propertyType === AdditionalMetaDataType.Mesh) return meshChooser; + // Show DataInput selector if this item is controlled if (modelData.propertyType === AdditionalMetaDataType.MultiLine) - return multiLine; + if (modelData.controlled) + return datainputChooser; + else + return multiLine; if (modelData.propertyType === AdditionalMetaDataType.Font) return comboDropDown; if (modelData.propertyType === AdditionalMetaDataType.Texture) @@ -801,6 +805,21 @@ Rectangle { } Component { + id: datainputChooser + + HandlerGenericChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showDataInputChooser(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { id: intSliderComponent HandlerPropertyBaseSlider { diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp index 612dd32c..609fb1d3 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp @@ -557,7 +557,11 @@ bool Qt3DSDMTimelineItemBinding::IsValidTransaction(EUserTransaction inTransacti qt3dsdm::Qt3DSDMInstanceHandle theInstance = GetInstance(); switch (inTransaction) { case EUserTransaction_Rename: - return (GetObjectType() != OBJTYPE_SCENE && GetObjectType() != OBJTYPE_IMAGE); + // DataInput renaming is forbidden by convention. DataInput name is + // permanently assigned when it is added to the scene from a fixed list of + // available datainputs + return (GetObjectType() != OBJTYPE_SCENE && GetObjectType() != OBJTYPE_IMAGE + && GetObjectType() != OBJTYPE_DATAINPUT); case EUserTransaction_Duplicate: if (theInstance.Valid()) @@ -589,11 +593,13 @@ bool Qt3DSDMTimelineItemBinding::IsValidTransaction(EUserTransaction inTransacti // component. // This may include behavior assets which may be directly attached to the Scene. // This is because by principal, components cannot exist on the Scene directly. + // DataInputs cannot reside inside component as they must be direct children + // of scene qt3dsdm::Qt3DSDMInstanceHandle theParentInstance = theBridge->GetParentInstance(theInstance); if (theObjectType != OBJTYPE_LAYER && theObjectType != OBJTYPE_SCENE && theObjectType != OBJTYPE_MATERIAL && theObjectType != OBJTYPE_IMAGE - && theObjectType != OBJTYPE_EFFECT + && theObjectType != OBJTYPE_EFFECT && theObjectType != OBJTYPE_DATAINPUT && (theParentInstance.Valid() && theBridge->GetObjectType(theParentInstance) != OBJTYPE_SCENE)) // This checks if the object is diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro index f3c3b379..cb617aa8 100644 --- a/src/Authoring/Studio/Qt3DStudio.pro +++ b/src/Authoring/Studio/Qt3DStudio.pro @@ -277,6 +277,7 @@ SOURCES += \ Palettes/Inspector/InspectorControlModel.cpp \ Palettes/Inspector/ObjectListModel.cpp \ Palettes/Inspector/ObjectBrowserView.cpp \ + Palettes/Inspector/DataInputChooserView.cpp \ Palettes/Inspector/TabOrderHandler.cpp \ Palettes/Inspector/MouseHelper.cpp \ Palettes/Project/ProjectView.cpp \ @@ -409,6 +410,7 @@ HEADERS += \ Palettes/Inspector/FileChooserView.h \ Palettes/Inspector/FileChooserModel.h \ Palettes/Inspector/TextureChooserView.h \ + Palettes/Inspector/DataInputChooserView.h \ Palettes/Inspector/TabOrderHandler.h \ Palettes/Inspector/MouseHelper.h \ Palettes/Project/ProjectView.h \ diff --git a/src/Authoring/Studio/qml.qrc b/src/Authoring/Studio/qml.qrc index fa0cc143..4a2ecb68 100644 --- a/src/Authoring/Studio/qml.qrc +++ b/src/Authoring/Studio/qml.qrc @@ -38,5 +38,6 @@ <file>Palettes/controls/StyledTooltip.qml</file> <file>Palettes/controls/StyledToolButton.qml</file> <file>Palettes/controls/StyledMenuSeparator.qml</file> + <file>Palettes/Inspector/DataInputBrowser.qml</file> </qresource> </RCC> |