summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Qt3DStudio/Palettes/Action
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Qt3DStudio/Palettes/Action')
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.cpp43
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.h42
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.cpp235
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.h77
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionView.cpp1203
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionView.h231
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/ActionView.qml468
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowser.qml169
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.cpp109
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.h79
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.cpp276
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.h97
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerBaseMultilineText.qml87
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerEmitSignal.qml51
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerFireEvent.qml55
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericBaseColor.qml91
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericCheckbox.qml59
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericColor.qml55
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericFloat.qml63
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericText.qml56
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerGoToSlide.qml62
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerMultilineText.qml60
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerProperty.qml290
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseSlider.qml241
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXY.qml80
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXYZ.qml98
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyCombo.qml60
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertySlider.qml67
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyXYZ.qml64
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.cpp255
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.h108
31 files changed, 4931 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.cpp
new file mode 100644
index 00000000..1e194d79
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.cpp
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2005 NVIDIA Corporation.
+** Copyright (C) 2017 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 "Qt3DSCommonPrecompile.h"
+
+#include "ActionContextMenu.h"
+#include "StudioClipboard.h"
+
+CActionContextMenu::CActionContextMenu(QList<QAction *> actions, QWidget *parent)
+ : QMenu(parent)
+{
+ addActions(actions);
+}
+
+CActionContextMenu::~CActionContextMenu()
+{
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.h b/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.h
new file mode 100644
index 00000000..99d785aa
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionContextMenu.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2005 NVIDIA Corporation.
+** Copyright (C) 2017 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 INCLUDED_ACTION_CONTEXT_MENU_H
+#define INCLUDED_ACTION_CONTEXT_MENU_H 1
+
+#include <QtWidgets/qmenu.h>
+
+class CActionContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ explicit CActionContextMenu(QList<QAction *> actions, QWidget *parent = nullptr);
+ virtual ~CActionContextMenu();
+};
+#endif // INCLUDED_ACTION_CONTEXT_MENU_H
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.cpp
new file mode 100644
index 00000000..556215de
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "ActionModel.h"
+
+#include "Qt3DSCommonPrecompile.h"
+#include "ClientDataModelBridge.h"
+#include "CmdDataModelActionSetValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "Qt3DSDMActionSystem.h"
+#include "Qt3DSDMStudioSystem.h"
+
+ActionModel::ActionModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void ActionModel::setInstanceHandle(const qt3dsdm::Qt3DSDMInstanceHandle &handle)
+{
+ beginResetModel();
+ m_handle = handle;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ m_actions.clear();
+ if (handle.Valid()) {
+ doc->GetStudioSystem()->GetActionSystem()->GetActions(doc->GetActiveSlide(),
+ handle, m_actions);
+ }
+
+ endResetModel();
+}
+
+QHash<int, QByteArray> ActionModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(DescriptionRole, "description");
+ names.insert(VisibleRole, "visible");
+
+ return names;
+}
+
+
+int ActionModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return int(m_actions.size());
+}
+
+QVariant ActionModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto action = m_actions.at(index.row());
+ auto system = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ if (action.Valid()) {
+ auto actionCore = system->GetActionCore();
+
+ // Ensure the handle is still valid on the back-end, as some undo scenarios may cause this
+ // function to be called for already deleted actions
+ if (actionCore->HandleValid(action)) {
+ switch (role)
+ {
+ case DescriptionRole:
+ return actionString(action);
+ case VisibleRole:
+ return system->GetActionSystem()->GetActionEyeballValue(activeSlide(), action);
+ default:
+ return {};
+ }
+ }
+ }
+ return {};
+}
+
+bool ActionModel::setData(const QModelIndex &index, const QVariant &data, int role)
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return false;
+
+ const auto action = m_actions.at(index.row());
+
+ if (role == VisibleRole) {
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ CCmd *theCmd = new CCmdDataModelActionSetEyeball(doc, activeSlide(), action, data.toBool());
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ Q_EMIT dataChanged(index, index, {VisibleRole});
+ }
+
+
+ return false;
+}
+
+void ActionModel::addAction(const Qt3DSDMActionHandle &action)
+{
+ if (std::find(m_actions.begin(), m_actions.end(), action) == m_actions.end()) {
+ const auto count = rowCount();
+ beginInsertRows({}, count, count);
+ m_actions.push_back(action);
+ endInsertRows();
+ }
+}
+
+void ActionModel::removeAction(const Qt3DSDMActionHandle &action)
+{
+ // KDAB_FIXME use beginRemoveRows
+ beginResetModel();
+ m_actions.erase(std::remove(m_actions.begin(), m_actions.end(), action), m_actions.end());
+ endResetModel();
+}
+
+void ActionModel::updateAction(const Qt3DSDMActionHandle &action)
+{
+ for (unsigned i = 0; i < m_actions.size(); i++) {
+ if (m_actions[i] == action) {
+ auto idx = index(i, 0);
+ Q_EMIT dataChanged(idx, idx, {});
+ }
+ }
+}
+
+const Qt3DSDMActionHandle ActionModel::actionAt(int row)
+{
+ if (row >= 0 && static_cast<unsigned>(row) < m_actions.size())
+ return m_actions[row];
+
+ return {};
+}
+
+const SActionInfo ActionModel::actionInfoAt(int row)
+{
+ const auto action = actionAt(row);
+ if (!action.Valid())
+ return {};
+ auto actionCore = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetActionCore();
+ return actionCore->GetActionInfo(action);
+}
+
+qt3dsdm::IActionSystem *ActionModel::actionSystem() const
+{
+ return g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetActionSystem();
+}
+
+qt3dsdm::Qt3DSDMSlideHandle ActionModel::activeSlide() const
+{
+ return g_StudioApp.GetCore()->GetDoc()->GetActiveSlide();
+}
+
+QString ActionModel::actionString(const Qt3DSDMActionHandle &action) const
+{
+ QString result;
+ if (action.Valid()) {
+ auto core = g_StudioApp.GetCore();
+ auto doc = core->GetDoc();
+ auto actionCore = doc->GetStudioSystem()->GetActionCore();
+ auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+
+ const SActionInfo &actionInfo = actionCore->GetActionInfo(action);
+
+ // Query the event name
+ QString eventFormalName(tr("[Unknown Event]"));
+ Qt3DSDMEventHandle eventHandle = bridge->ResolveEvent(actionInfo);
+ if (eventHandle.Valid())
+ eventFormalName =
+ QString::fromWCharArray(bridge->GetEventInfo(eventHandle).m_FormalName.wide_str());
+
+ // Query the asset name
+ QString assetName = tr("[Unknown]");
+ assetName = bridge->GetName(actionInfo.m_Owner).toQString();
+
+ const auto sourceInstance =
+ bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+ const auto targetInstance =
+ bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+ QString sourceName = sourceInstance.Valid()
+ ? bridge->GetName(sourceInstance).toQString()
+ : tr("[Unknown Source]");
+ QString targetName = targetInstance.Valid()
+ ? bridge->GetName(targetInstance).toQString()
+ : tr("[Unknown Target]");
+
+ // Query the action name
+ QString handlerFormalName(tr("[Unknown Handler]"));
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ if (handlerHandle.Valid())
+ handlerFormalName = QString::fromWCharArray(bridge->GetHandlerInfo(handlerHandle).m_FormalName.wide_str());
+
+ // Format the strings
+ if (actionInfo.m_Owner == sourceInstance) {
+ if (sourceInstance == targetInstance) {
+ result = tr("Listen for '%1', '%2'").arg(eventFormalName, handlerFormalName);
+ } else {
+ result = tr("Listen for '%1', tell %2 to '%3'").arg(eventFormalName, targetName,
+ handlerFormalName);
+ }
+ } else if (actionInfo.m_Owner == targetInstance) {
+ result = tr("Listen to '%1' for '%2', '%3'").arg(sourceName, eventFormalName,
+ handlerFormalName);
+ } else {
+ result = tr("Listen to '%1' for '%2', tell %3 to '%4'").arg(sourceName,
+ eventFormalName,
+ targetName,
+ handlerFormalName);
+ }
+ }
+ return result;
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.h b/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.h
new file mode 100644
index 00000000..966c5782
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionModel.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 ACTIONMODEL_H
+#define ACTIONMODEL_H
+
+#include <QAbstractListModel>
+
+#include "Qt3DSDMActionInfo.h"
+#include "Qt3DSDMHandles.h"
+
+namespace qt3dsdm {
+ class IActionSystem;
+}
+
+class ActionModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit ActionModel(QObject *parent = nullptr);
+
+ void setInstanceHandle(const qt3dsdm::Qt3DSDMInstanceHandle &handle);
+
+ enum Roles {
+ DescriptionRole = Qt::DisplayRole,
+ VisibleRole = Qt::UserRole + 1,
+
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override;
+
+ void addAction(const qt3dsdm::Qt3DSDMActionHandle &action);
+ void removeAction(const qt3dsdm::Qt3DSDMActionHandle &action);
+ void updateAction(const qt3dsdm::Qt3DSDMActionHandle &action);
+ const qt3dsdm::Qt3DSDMActionHandle actionAt(int row);
+ const qt3dsdm::SActionInfo actionInfoAt(int row);
+
+private:
+ qt3dsdm::IActionSystem *actionSystem() const;
+ qt3dsdm::Qt3DSDMSlideHandle activeSlide() const;
+ QString actionString(const qt3dsdm::Qt3DSDMActionHandle &action) const;
+
+ qt3dsdm::Qt3DSDMInstanceHandle m_handle;
+ qt3dsdm::TActionHandleList m_actions;
+};
+
+#endif // ACTIONMODEL_H
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.cpp
new file mode 100644
index 00000000..41d67789
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.cpp
@@ -0,0 +1,1203 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "ActionView.h"
+#include "ActionContextMenu.h"
+#include "ActionModel.h"
+#include "CmdDataModelActionSetValue.h"
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Dialogs.h"
+#include "Dispatch.h"
+#include "Doc.h"
+#include "IDocumentEditor.h"
+#include "IDocumentReader.h"
+#include "IObjectReferenceHelper.h"
+#include "Literals.h"
+#include "ObjectListModel.h"
+#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "StudioClipboard.h"
+#include "StudioObjectTypes.h"
+#include "StudioPreferences.h"
+#include "Qt3DSFileTools.h"
+#include "Qt3DSDMActionCore.h"
+#include "Qt3DSDMDataTypes.h"
+#include "Qt3DSDMSlides.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtCore/qtimer.h>
+#include <QtWidgets/qdesktopwidget.h>
+
+ActionView::ActionView(const QSize &preferredSize, QWidget *parent)
+ : QQuickWidget(parent)
+ , TabNavigable()
+ , m_actionsModel(new ActionModel(this))
+ , m_preferredSize(preferredSize)
+{
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ActionView::initialize);
+
+ g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
+
+ connect(this, &ActionView::actionChanged, this, [this] {
+ if (!m_itemHandle.Valid())
+ return;
+
+ if (!m_propertyModel)
+ m_propertyModel = new PropertyModel(this);
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler == L"Set Property") {
+ setPropertyValueInvalid(true);
+ m_currentPropertyNameHandle = actionInfo.m_HandlerArgs.at(0);
+ m_currentPropertyValueHandle = actionInfo.m_HandlerArgs.at(1);
+ m_propertyModel->setAction(m_actionsModel->actionAt(m_currentActionIndex));
+ m_propertyModel->setNameHandle(m_currentPropertyNameHandle);
+ m_propertyModel->setValueHandle(m_currentPropertyValueHandle);
+ m_currentPropertyIndex = m_propertyModel->defaultPropertyIndex();
+ Q_EMIT propertyChanged();
+ Q_EMIT propertyModelChanged();
+ setPropertyValueInvalid(false);
+ }
+ });
+
+ m_actionChangedCompressionTimer.setInterval(20);
+ m_actionChangedCompressionTimer.setSingleShot(true);
+ connect(&m_actionChangedCompressionTimer, &QTimer::timeout, this, [this] {
+ updateHandlerArguments();
+ updateFiredEvent();
+ Q_EMIT actionChanged();
+ });
+
+ QString ctrlKey(QStringLiteral("Ctrl+"));
+ QString shiftKey(QStringLiteral("Shift+"));
+#ifdef Q_OS_MACOS
+ ctrlKey = "⌘";
+ shiftKey = "⇧";
+#endif
+
+ // These actions will be passed to the context menu. Some of them need to me members, as we
+ // have to change their enabled state based on selection and previous actions.
+ QAction *action = new QAction(tr("New Action\t%1A").arg(shiftKey));
+ action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_A));
+ connect(action, &QAction::triggered, this, &ActionView::addAction);
+ QQuickWidget::addAction(action);
+
+ m_actionCopy = new QAction(tr("Copy Action\t%1C").arg(ctrlKey));
+ connect(m_actionCopy, &QAction::triggered, this, &ActionView::copyAction);
+ QQuickWidget::addAction(m_actionCopy);
+
+ m_actionPaste = new QAction(tr("Paste Action\t%1V").arg(ctrlKey));
+ connect(m_actionPaste, &QAction::triggered, this, &ActionView::pasteAction);
+ QQuickWidget::addAction(m_actionPaste);
+
+ m_actionCut = new QAction(tr("Cut Action\t%1X").arg(ctrlKey));
+ connect(m_actionCut, &QAction::triggered, this, &ActionView::cutAction);
+ QQuickWidget::addAction(m_actionCut);
+
+ m_actionDel = new QAction(tr("Delete Action\tDel"));
+ connect(m_actionDel, &QAction::triggered, [=](){ deleteAction(m_currentActionIndex); });
+ QQuickWidget::addAction(m_actionDel);
+}
+
+ActionView::~ActionView()
+{
+}
+
+QSize ActionView::sizeHint() const
+{
+ return m_preferredSize;
+}
+
+void ActionView::focusInEvent(QFocusEvent *event)
+{
+ updateActionStates();
+ QQuickWidget::focusInEvent(event);
+}
+
+void ActionView::mousePressEvent(QMouseEvent *event)
+{
+ g_StudioApp.setLastActiveView(this);
+ QQuickWidget::mousePressEvent(event);
+}
+
+bool ActionView::event(QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (m_currentActionIndex >= 0 && (ke->key() == Qt::Key_Delete
+ || (ke->modifiers() == Qt::ControlModifier
+ && (ke->key() == Qt::Key_C || ke->key() == Qt::Key_V
+ || ke->key() == Qt::Key_X)))) {
+ auto focusItem = quickWindow()->activeFocusItem();
+ if (focusItem && (focusItem->objectName() == QStringLiteral("actionListDelegate")
+ || focusItem->objectName() == QStringLiteral("focusEater"))) {
+ if (ke->key() == Qt::Key_Delete) {
+ if (m_actionDel->isEnabled())
+ deleteAction(m_currentActionIndex);
+ } else if (ke->modifiers() == Qt::ControlModifier) {
+ if (ke->key() == Qt::Key_C) {
+ if (m_actionCopy->isEnabled())
+ copyAction();
+ } else if (ke->key() == Qt::Key_V) {
+ if (m_actionPaste->isEnabled())
+ pasteAction();
+ } else if (ke->key() == Qt::Key_X) {
+ if (m_actionCut->isEnabled())
+ cutAction();
+ }
+ }
+ event->accept();
+ return true;
+ }
+ }
+ }
+ return QQuickWidget::event(event);
+}
+
+void ActionView::setItem(const qt3dsdm::Qt3DSDMInstanceHandle &handle)
+{
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+
+ m_objRefHelper = GetDoc()->GetDataModelObjectReferenceHelper();
+ m_itemHandle = handle;
+ m_actionsModel->setInstanceHandle(handle);
+ if (m_itemHandle.Valid() != m_hasItem) {
+ m_hasItem = m_itemHandle.Valid();
+ Q_EMIT hasItemChanged();
+ }
+ emitActionChanged();
+ Q_EMIT itemChanged();
+ Q_EMIT itemTextChanged();
+}
+
+QString ActionView::itemIcon() const
+{
+ if (!m_itemHandle.Valid())
+ return QString();
+
+ auto info = m_objRefHelper->GetInfo(m_itemHandle);
+ return CStudioObjectTypes::GetNormalIconName(info.m_Type);
+}
+
+QString ActionView::itemText() const
+{
+ if (!m_itemHandle.Valid())
+ return tr("No Object Selected");
+
+ const auto data = m_objRefHelper->GetInfo(m_itemHandle);
+ return data.m_Name.toQString();
+}
+
+QColor ActionView::itemColor() const
+{
+ if (!m_itemHandle.Valid())
+ return Qt::white;
+
+ auto info = m_objRefHelper->GetInfo(m_itemHandle);
+ if (info.m_Master)
+ return CStudioPreferences::masterColor();
+ else
+ return CStudioPreferences::textColor();
+}
+
+QAbstractItemModel *ActionView::actionsModel() const
+{
+ return m_actionsModel;
+}
+
+QAbstractItemModel *ActionView::propertyModel() const
+{
+ return m_propertyModel;
+}
+
+QString ActionView::targetObjectName() const
+{
+ if (!GetDoc()->isValid() || !m_itemHandle.Valid())
+ return QString();
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ const auto targetInstance =
+ GetBridge()->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ QString targetName = targetInstance.Valid()
+ ? GetBridge()->GetName(targetInstance).toQString()
+ : tr("[Unknown Target]");
+
+ return targetName;
+}
+
+QString ActionView::triggerObjectName() const
+{
+ if (!GetDoc()->isValid() || !m_itemHandle.Valid())
+ return QString();
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ const auto sourceInstance =
+ GetBridge()->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+
+ QString sourceName = sourceInstance.Valid()
+ ? GetBridge()->GetName(sourceInstance).toQString()
+ : tr("[Unknown Source]");
+
+ return sourceName;
+}
+
+QString ActionView::eventName() const
+{
+ if (!GetDoc()->isValid() || !m_itemHandle.Valid())
+ return QString();
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto eventHandle = bridge->ResolveEvent(actionInfo);
+ const auto eventInfo = bridge->GetEventInfo(eventHandle);
+
+ const QString formalName = QString::fromWCharArray(eventInfo.m_FormalName.wide_str());
+ return formalName.isEmpty() ? tr("[Unknown Event]") : formalName;
+}
+
+QString ActionView::handlerName() const
+{
+ if (!GetDoc()->isValid() || !m_itemHandle.Valid())
+ return QString();
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+
+ if (handlerHandle.Valid()) {
+ const auto handlerInfo = bridge->GetHandlerInfo(handlerHandle);
+ return QString::fromWCharArray(handlerInfo.m_FormalName.wide_str());
+ }
+
+ return tr("[Unknown Handler]");
+}
+
+QVariantList ActionView::handlerArguments() const
+{
+ return m_handlerArguments;
+}
+
+PropertyInfo ActionView::property() const
+{
+ if (!m_propertyModel)
+ return {};
+ return m_propertyModel->property(m_currentPropertyIndex);
+}
+
+bool ActionView::isPropertyValueInvalid() const
+{
+ return m_propertyValueInvalid;
+}
+
+void ActionView::setCurrentActionIndex(int index)
+{
+ if (index == m_currentActionIndex)
+ return;
+
+ m_currentActionIndex = index;
+ emitActionChanged();
+
+ updateActionStates();
+}
+
+void ActionView::setCurrentPropertyIndex(int handle, int index)
+{
+ setPropertyValueInvalid(true);
+ // Make sure propertymodel name & value handles are always up-to-date,
+ // even when index is same as before
+ m_currentPropertyValueHandle = 0;
+ m_currentPropertyNameHandle = handle;
+ for (int i = 0; i < m_handlerArguments.size(); ++i) {
+ auto handlerArg = m_handlerArguments[i].value<HandlerArgument>();
+ if (handlerArg.m_handle.GetHandleValue() == handle && i < m_handlerArguments.size() - 1) {
+ m_currentPropertyValueHandle
+ = m_handlerArguments[i + 1].value<HandlerArgument>().m_handle;
+ if (m_propertyModel) {
+ m_propertyModel->setNameHandle(m_currentPropertyNameHandle);
+ m_propertyModel->setValueHandle(m_currentPropertyValueHandle);
+ }
+ }
+ }
+
+ if (index == m_currentPropertyIndex)
+ return;
+
+ m_currentPropertyIndex = index;
+
+ // set the property for the handler
+ if (m_propertyModel && handle != 0) {
+ qt3dsdm::SValue sValue(QVariant(m_propertyModel->property(index).m_nameId));
+ qt3dsdm::SValue oldValue;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
+
+ if (!Equals(oldValue, sValue)) {
+ CCmd *theCmd =
+ new CCmdDataModelActionSetArgumentValue(GetDoc(), handle, sValue);
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ }
+ }
+
+ Q_EMIT propertyChanged();
+ // Clear the value invalid flag asynchronously as the value doesn't actually change until
+ // backend tells us it does
+ QTimer::singleShot(0, this, &ActionView::clearPropertyValueInvalid);
+}
+
+void ActionView::addAction()
+{
+ if (m_itemHandle.Valid()) {
+ // Query data model bridge to see the applicable events and actions for this instance.
+ CClientDataModelBridge *theBridge = GetBridge();
+
+ std::wstring theEventName = theBridge->GetDefaultEvent(m_itemHandle);
+ std::wstring theHandlerName = theBridge->GetDefaultHandler(m_itemHandle);
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Add Action"))
+ ->AddAction(GetDoc()->GetActiveSlide(), m_itemHandle, theEventName,
+ theHandlerName);
+ }
+ updateActionStates();
+}
+
+void ActionView::deleteAction(int index)
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ const auto action = m_actionsModel->actionAt(index);
+ if (action.Valid()) {
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(),
+ QObject::tr("Delete Action"))->DeleteAction(action);
+ emitActionChanged();
+ }
+ updateActionStates();
+}
+
+QObject *ActionView::showTriggerObjectBrowser(const QPoint &point)
+{
+ if (!m_itemHandle.Valid())
+ return nullptr;
+
+ if (!m_objectsModel) {
+ m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(),
+ GetDoc()->GetSceneInstance(), this);
+ }
+
+ if (!m_triggerObjectBrowser)
+ m_triggerObjectBrowser = new ObjectBrowserView(this);
+
+ m_triggerObjectBrowser->setModel(m_objectsModel);
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto instanceHandle = GetBridge()->GetInstance(actionInfo.m_Owner,
+ actionInfo.m_TriggerObject);
+ m_triggerObjectBrowser->disconnect();
+ m_triggerObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ CDialogs::showWidgetBrowser(this, m_triggerObjectBrowser, point);
+ m_activeBrowser = m_triggerObjectBrowser;
+
+ connect(m_triggerObjectBrowser, &ObjectBrowserView::selectionChanged,
+ this, &ActionView::OnTriggerSelectionChanged);
+ // update also pathtype in the trigger object when changed from UI
+ connect(m_triggerObjectBrowser, &ObjectBrowserView::pathTypeChanged,
+ this, &ActionView::OnTriggerSelectionChanged);
+
+ return m_triggerObjectBrowser;
+}
+
+QObject *ActionView::showTargetObjectBrowser(const QPoint &point)
+{
+ if (!m_itemHandle.Valid())
+ return nullptr;
+
+ if (!m_objectsModel) {
+ m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(),
+ GetDoc()->GetSceneInstance(), this);
+ }
+
+ if (!m_targetObjectBrowser)
+ m_targetObjectBrowser = new ObjectBrowserView(this);
+
+ m_targetObjectBrowser->setModel(m_objectsModel);
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto instanceHandle = GetBridge()->GetInstance(actionInfo.m_Owner,
+ actionInfo.m_TargetObject);
+ m_targetObjectBrowser->disconnect();
+ m_targetObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ CDialogs::showWidgetBrowser(this, m_targetObjectBrowser, point);
+ m_activeBrowser = m_targetObjectBrowser;
+
+ connect(m_targetObjectBrowser, &ObjectBrowserView::selectionChanged,
+ this, &ActionView::OnTargetSelectionChanged);
+ // update also pathtype in the target object when changed from UI
+ connect(m_targetObjectBrowser, &ObjectBrowserView::pathTypeChanged,
+ this, &ActionView::OnTargetSelectionChanged);
+
+ return m_targetObjectBrowser;
+}
+
+void ActionView::OnTargetSelectionChanged()
+{
+ auto selectedItem = m_targetObjectBrowser->selectedHandle();
+ setTargetObject(m_objRefHelper->GetAssetRefValue(
+ selectedItem, m_itemHandle,
+ (CRelativePathTools::EPathType)(m_targetObjectBrowser->pathType())));
+ resetFiredEvent();
+}
+
+void ActionView::OnTriggerSelectionChanged()
+{
+ auto selectedItem = m_triggerObjectBrowser->selectedHandle();
+ setTriggerObject(m_objRefHelper->GetAssetRefValue(
+ selectedItem, m_itemHandle,
+ (CRelativePathTools::EPathType)(m_triggerObjectBrowser->pathType())));
+ resetFiredEvent();
+}
+
+void ActionView::showContextMenu(int x, int y)
+{
+ updateActionStates();
+ CActionContextMenu contextMenu(QQuickWidget::actions(), this);
+ contextMenu.exec(mapToGlobal({x, y}));
+}
+
+QObject *ActionView::showEventBrowser(const QPoint &point)
+{
+ if (!m_itemHandle.Valid())
+ return nullptr;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_eventsModel)
+ m_eventsModel = new EventsModel(this);
+
+ qt3dsdm::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ m_eventsModel->setEventList(eventList);
+
+ if (!m_eventsBrowser)
+ m_eventsBrowser = new EventsBrowserView(this);
+
+ m_eventsBrowser->setModel(m_eventsModel);
+
+ m_eventsBrowser->disconnect();
+ m_eventsBrowser->selectAndExpand(QString::fromStdWString(actionInfo.m_Event));
+ CDialogs::showWidgetBrowser(this, m_eventsBrowser, point);
+ m_activeBrowser = m_eventsBrowser;
+
+ connect(m_eventsBrowser, &EventsBrowserView::selectionChanged,
+ this, [this] {
+ if (m_eventsBrowser->canCommit())
+ setEvent(qt3dsdm::Qt3DSDMEventHandle(m_eventsBrowser->selectedHandle()));
+ });
+
+ return m_eventsBrowser;
+}
+
+QObject *ActionView::showHandlerBrowser(const QPoint &point)
+{
+ if (!m_itemHandle.Valid())
+ return nullptr;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_handlersModel)
+ m_handlersModel = new EventsModel(this);
+
+ qt3dsdm::THandlerHandleList handlerList;
+ bridge->GetHandlers(instanceHandle, handlerList);
+ m_handlersModel->setHandlerList(handlerList);
+
+ if (!m_handlerBrowser)
+ m_handlerBrowser = new EventsBrowserView(this);
+
+ m_handlerBrowser->setModel(m_handlersModel);
+
+ m_handlerBrowser->disconnect();
+ m_handlerBrowser->selectAndExpand(QString::fromStdWString(actionInfo.m_Handler));
+ CDialogs::showWidgetBrowser(this, m_handlerBrowser, point);
+ m_activeBrowser = m_handlerBrowser;
+
+ connect(m_handlerBrowser, &EventsBrowserView::selectionChanged,
+ this, [this] {
+ if (m_handlerBrowser->canCommit())
+ setHandler(qt3dsdm::Qt3DSDMHandlerHandle(m_handlerBrowser->selectedHandle()));
+ });
+
+ return m_handlerBrowser;
+}
+
+QObject *ActionView::showEventBrowserForArgument(int handle, const QPoint &point)
+{
+ if (!m_itemHandle.Valid())
+ return nullptr;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_fireEventsModel)
+ m_fireEventsModel = new EventsModel(this);
+
+ qt3dsdm::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ m_fireEventsModel->setEventList(eventList);
+
+ if (!m_fireEventsBrowser)
+ m_fireEventsBrowser = new EventsBrowserView(this);
+
+ m_fireEventsBrowser->setModel(m_fireEventsModel);
+ m_fireEventsBrowser->setHandle(handle);
+
+ qt3dsdm::SValue oldValue;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
+
+ QString eventName;
+ for (Qt3DSDMEventHandle eventHandle : eventList) {
+ if (oldValue == eventHandle.GetHandleValue()) {
+ qt3dsdm::SEventInfo eventInfo = bridge->GetEventInfo(eventHandle);
+ eventName = QString::fromWCharArray(eventInfo.m_FormalName.wide_str());
+ if (eventName.isEmpty())
+ eventName = QString::fromWCharArray(eventInfo.m_Name.wide_str());
+ }
+ }
+ m_fireEventsBrowser->disconnect();
+ m_fireEventsBrowser->selectAndExpand(eventName);
+ CDialogs::showWidgetBrowser(this, m_fireEventsBrowser, point);
+ m_activeBrowser = m_fireEventsBrowser;
+
+ connect(m_fireEventsBrowser, &EventsBrowserView::selectionChanged,
+ this, [this, handle] {
+ setArgumentValue(handle, qt3dsdm::Qt3DSDMEventHandle(
+ m_fireEventsBrowser->selectedHandle()).GetHandleValue());
+ });
+
+ return m_fireEventsBrowser;
+}
+
+void ActionView::updateFiredEvent()
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler != L"Fire Event") {
+ m_firedEvent = tr("[Unknown event]");
+ return;
+ }
+
+ const auto doc = GetDoc();
+ if (!doc->isValid())
+ return;
+
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ IActionCore *actionCore = doc->GetStudioSystem()->GetActionCore();
+
+ if (handlerHandle.Valid()) {
+ for (const auto &argHandle: actionInfo.m_HandlerArgs) {
+ const auto &argumentInfo = actionCore->GetHandlerArgumentInfo(argHandle);
+ DataModelDataType::Value theArgType(GetValueType(argumentInfo.m_Value));
+ SValue theArgValue(argumentInfo.m_Value);
+ if (argumentInfo.m_ArgType == HandlerArgumentType::Event) {
+ theArgType = DataModelDataType::String;
+ auto theEventHandle = get<qt3ds::QT3DSI32>(argumentInfo.m_Value);
+ theArgValue = SValue(std::make_shared<CDataStr>(
+ bridge->GetEventInfo(theEventHandle).m_Name.wide_str()));
+ m_firedEvent = theArgValue.toQVariant().toString();
+ Q_EMIT firedEventChanged();
+ }
+ }
+ }
+}
+
+void ActionView::updateFiredEventFromHandle(int handle)
+{
+ m_firedEvent = QString::fromWCharArray(
+ GetBridge()->GetEventInfo(handle).m_FormalName.wide_str());
+ Q_EMIT firedEventChanged();
+}
+
+void ActionView::resetFiredEvent()
+{
+ m_firedEvent = tr("[Unknown Event]");
+ Q_EMIT firedEventChanged();
+}
+
+void ActionView::OnNewPresentation()
+{
+ // Register callback
+ qt3dsdm::IStudioFullSystemSignalProvider *theSignalProvider =
+ g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+ m_connections.push_back(theSignalProvider->ConnectActionCreated(
+ std::bind(&ActionView::OnActionAdded, this,
+ std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_connections.push_back(theSignalProvider->ConnectActionDeleted(
+ std::bind(&ActionView::OnActionDeleted, this,
+ std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_connections.push_back(theSignalProvider->ConnectTriggerObjectSet(
+ std::bind(&ActionView::OnActionModified, this,
+ std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectTargetObjectSet(
+ std::bind(&ActionView::OnActionModified, this,
+ std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectEventSet(
+ std::bind(&ActionView::OnActionModified, this,
+ std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectHandlerSet(
+ std::bind(&ActionView::OnActionModified, this,
+ std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectHandlerArgumentValueSet(
+ std::bind(&ActionView::OnHandlerArgumentModified, this,
+ std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectInstancePropertyValue(
+ std::bind(&ActionView::OnInstancePropertyValueChanged, this,
+ std::placeholders::_1,
+ std::placeholders::_2)));
+ m_connections.push_back(theSignalProvider->ConnectInstanceDeleted(
+ std::bind(&ActionView::OnInstanceDeleted, this,
+ std::placeholders::_1)));
+ CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
+ m_connections.push_back(theDispatch->ConnectSelectionChange(
+ std::bind(&ActionView::OnSelectionSet, this,
+ std::placeholders::_1)));
+
+ auto assetGraph = g_StudioApp.GetCore()->GetDoc()->GetAssetGraph();
+ m_connections.push_back(assetGraph->ConnectChildAdded(
+ std::bind(&ActionView::onAssetGraphChanged, this)));
+ m_connections.push_back(assetGraph->ConnectChildRemoved(
+ std::bind(&ActionView::onAssetGraphChanged, this)));
+}
+
+void ActionView::OnClosingPresentation()
+{
+ m_connections.clear();
+}
+
+void ActionView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
+{
+ qt3dsdm::Qt3DSDMInstanceHandle theInstance;
+ std::vector<qt3dsdm::Qt3DSDMInstanceHandle> instances;
+
+ switch (inSelectable.getType()) {
+ case Q3DStudio::SelectedValueTypes::Instance:
+ theInstance = inSelectable.getData<qt3dsdm::Qt3DSDMInstanceHandle>();
+ break;
+ case Q3DStudio::SelectedValueTypes::MultipleInstances:
+ instances = inSelectable.getData<std::vector<qt3dsdm::Qt3DSDMInstanceHandle>>();
+ // handling only if we have one selected element.
+ if (instances.size() == 1)
+ theInstance = instances[0];
+ break;
+ case Q3DStudio::SelectedValueTypes::Slide: {
+ qt3dsdm::Qt3DSDMSlideHandle theSlideHandle =
+ inSelectable.getData<Q3DStudio::SSlideInstanceWrapper>().m_Slide;
+ // Get the owning component instance
+ CClientDataModelBridge *theBridge = GetBridge();
+ qt3dsdm::SLong4 theComponentGuid = theBridge->GetComponentGuid(theSlideHandle);
+ Q_ASSERT(theComponentGuid.Valid());
+ theInstance = theBridge->GetInstanceByGUID(theComponentGuid);
+ Q_ASSERT(theInstance.Valid());
+ }
+ break;
+ default:
+ // Clear selection on selecting other types or nothing at all
+ break;
+ };
+
+ setItem(theInstance);
+}
+
+void ActionView::OnActionAdded(qt3dsdm::Qt3DSDMActionHandle inAction,
+ qt3dsdm::Qt3DSDMSlideHandle inSlide,
+ qt3dsdm::Qt3DSDMInstanceHandle inOwner)
+{
+ CDoc *theDoc = GetDoc();
+ qt3dsdm::CStudioSystem *theStudioSystem = theDoc->GetStudioSystem();
+
+ qt3dsdm::Qt3DSDMSlideHandle theCurrentSlide = theDoc->GetActiveSlide();
+ qt3dsdm::Qt3DSDMSlideHandle theMasterSlideOfAction =
+ theStudioSystem->GetSlideSystem()->GetMasterSlide(inSlide);
+ qt3dsdm::Qt3DSDMSlideHandle theMasterOfCurrentSlide =
+ theStudioSystem->GetSlideSystem()->GetMasterSlide(theCurrentSlide);
+
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+
+ if (inOwner == m_itemHandle // the action is added to current viewed instance
+ && (theCurrentSlide == inSlide // and is added to the current viewed slide
+ || (theMasterSlideOfAction == inSlide
+ && theMasterOfCurrentSlide == theMasterSlideOfAction))) {
+ // or it is added to the master of the current viewed slide
+ m_actionsModel->addAction(inAction);
+ }
+}
+
+void ActionView::OnActionDeleted(qt3dsdm::Qt3DSDMActionHandle inAction,
+ qt3dsdm::Qt3DSDMSlideHandle inSlide,
+ qt3dsdm::Qt3DSDMInstanceHandle inOwner)
+{
+ Q_UNUSED(inSlide);
+ Q_UNUSED(inOwner);
+
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+ m_actionsModel->removeAction(inAction);
+}
+
+void ActionView::OnActionModified(qt3dsdm::Qt3DSDMActionHandle inAction)
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ if (GetDoc()->GetStudioSystem()->GetActionCore()->HandleValid(inAction)) {
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (!actionInfo.m_Instance.Valid()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ } else {
+ // Update the selection in an active browser dialog
+ if (m_activeBrowser == m_triggerObjectBrowser) {
+ const auto instanceHandle = GetBridge()->GetInstance(
+ actionInfo.m_Owner, actionInfo.m_TriggerObject);
+ m_triggerObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ } else if (m_activeBrowser == m_targetObjectBrowser) {
+ const auto instanceHandle = GetBridge()->GetInstance(
+ actionInfo.m_Owner, actionInfo.m_TargetObject);
+ m_targetObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ } else if (m_activeBrowser == m_eventsBrowser) {
+ m_eventsBrowser->selectAndExpand(QString::fromStdWString(actionInfo.m_Event));
+ } else if (m_activeBrowser == m_handlerBrowser) {
+ m_handlerBrowser->selectAndExpand(
+ QString::fromStdWString(actionInfo.m_Handler));
+ }
+ }
+ }
+ m_actionsModel->updateAction(inAction);
+ emitActionChanged();
+ }
+}
+
+void ActionView::OnHandlerArgumentModified(qt3dsdm::Qt3DSDMHandlerArgHandle inHandlerArgument)
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ if (!m_fireEventsBrowser.isNull() && m_activeBrowser == m_fireEventsBrowser
+ && m_activeBrowser->isVisible()) {
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ // m_fireEventsBrowser needs to be closed if another type of target handler is chosen.
+ // Other browsers will remain valid always as long as the action is selected.
+ if (actionInfo.m_Handler != L"Fire Event") {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ } else {
+ // Update the selection in an active browser dialog
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner,
+ actionInfo.m_TargetObject);
+ qt3dsdm::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ qt3dsdm::SValue value;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(
+ m_fireEventsBrowser->handle(), value);
+ QString eventName;
+ for (Qt3DSDMEventHandle eventHandle : eventList) {
+ if (value == eventHandle.GetHandleValue()) {
+ qt3dsdm::SEventInfo eventInfo = bridge->GetEventInfo(eventHandle);
+ eventName = QString::fromWCharArray(eventInfo.m_FormalName.wide_str());
+ if (eventName.isEmpty())
+ eventName = QString::fromWCharArray(eventInfo.m_Name.wide_str());
+ }
+ }
+ m_fireEventsBrowser->selectAndExpand(eventName);
+ }
+ }
+ emitActionChanged();
+}
+
+void ActionView::OnInstancePropertyValueChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty)
+{
+ if (!m_itemHandle.Valid() || m_itemHandle != inInstance)
+ return;
+
+ auto bridge = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+ if (inProperty == bridge->GetNameProperty())
+ Q_EMIT itemTextChanged();
+
+ emitActionChanged();
+}
+
+void ActionView::OnInstanceDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
+{
+ // Clear the model on instance deletion
+ if (inInstance == m_itemHandle) {
+ qt3dsdm::Qt3DSDMInstanceHandle noInstance;
+ setItem(noInstance);
+ }
+}
+
+void ActionView::copyAction()
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ auto theTempAPFile =
+ GetDoc()->GetDocumentReader().CopyAction(m_actionsModel->actionAt(m_currentActionIndex),
+ GetDoc()->GetActiveSlide());
+ Qt3DSFile theFile(theTempAPFile);
+ CStudioClipboard::CopyActionToClipboard(theFile);
+ updateActionStates();
+}
+
+void ActionView::cutAction()
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ copyAction();
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Cut Action"))->DeleteAction(action);
+ updateActionStates();
+}
+
+void ActionView::pasteAction()
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ Qt3DSFile theTempAPFile = CStudioClipboard::GetActionFromClipboard();
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Paste Action"))
+ ->PasteAction(theTempAPFile.GetAbsolutePath(), m_itemHandle);
+ updateActionStates();
+}
+
+void ActionView::setTriggerObject(const qt3dsdm::SObjectRefType &object)
+{
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ if (!action.Valid())
+ return;
+
+ if (!m_triggerObjectBrowser.isNull() && m_triggerObjectBrowser->canCommit()) {
+ auto core = g_StudioApp.GetCore();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTriggerObject(GetDoc(), action, object);
+ const SActionInfo &theActionInfo
+ = GetDoc()->GetStudioSystem()->GetActionCore()->GetActionInfo(action);
+
+ Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
+ theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance) {
+ theCmd->ResetEvent(
+ theBridge->GetDefaultEvent(theObjectInstance, theActionInfo.m_Event));
+ }
+
+ core->ExecuteCommand(theCmd);
+ }
+ emitActionChanged();
+}
+
+void ActionView::setTargetObject(const qt3dsdm::SObjectRefType &object)
+{
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ if (!action.Valid())
+ return;
+
+ if (!m_targetObjectBrowser.isNull() && m_targetObjectBrowser->canCommit()) {
+ auto core = g_StudioApp.GetCore();
+ auto doc = GetDoc();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTargetObject(doc, action, object);
+ const SActionInfo &theActionInfo = doc->GetStudioSystem()->GetActionCore()->GetActionInfo(
+ action);
+
+ Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
+ theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance) {
+ theCmd->ResetHandler(
+ theBridge->GetDefaultHandler(theObjectInstance, theActionInfo.m_Handler));
+ }
+
+ core->ExecuteCommand(theCmd);
+ }
+ emitActionChanged();
+}
+
+void ActionView::setEvent(const Qt3DSDMEventHandle &event)
+{
+ if (!event.Valid())
+ return;
+
+ auto doc = GetDoc();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ CCmd *theCmd = new CCmdDataModelActionSetEvent(doc, action,
+ doc->GetStudioSystem()
+ ->GetActionMetaData()
+ ->GetEventInfo(event)
+ ->m_Name.wide_str());
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+}
+
+void ActionView::setHandler(const Qt3DSDMHandlerHandle &handler)
+{
+ if (!handler.Valid())
+ return;
+
+ auto doc = GetDoc();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ wstring handlerName(doc->GetStudioSystem()->GetActionMetaData()->GetHandlerInfo(handler)
+ ->m_Name.wide_str());
+ CCmdDataModelActionSetHandler *theCmd =
+ new CCmdDataModelActionSetHandler(doc, action, handlerName);
+ theCmd->ResetHandler(handlerName); // reset the handler args
+
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+}
+
+QVariant ActionView::handlerArgumentValue(int handle) const
+{
+ qt3dsdm::SValue value;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, value);
+ return value.toQVariant();
+}
+
+void ActionView::updateHandlerArguments()
+{
+ m_currentPropertyValueHandle = 0;
+ m_currentPropertyNameHandle = 0;
+ m_handlerArguments.clear();
+ const auto doc = GetDoc();
+ if (!doc->isValid() || !m_itemHandle.Valid())
+ return;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ IActionCore *actionCore = doc->GetStudioSystem()->GetActionCore();
+
+ if (handlerHandle.Valid()) {
+ auto newMetaData = doc->GetStudioSystem()->GetActionMetaData();
+
+ for (const auto &argHandle: actionInfo.m_HandlerArgs) {
+ const auto &argumentInfo = actionCore->GetHandlerArgumentInfo(argHandle);
+ Option<SMetaDataHandlerArgumentInfo> argMetaData(
+ newMetaData->FindHandlerArgumentByName(handlerHandle, argumentInfo.m_Name));
+
+ HandlerArgument argument;
+ argument.m_handle = argHandle;
+ argument.m_type = argMetaData->m_ArgType;
+ argument.m_name = QString::fromWCharArray(argumentInfo.m_Name.wide_str());
+ argument.m_value = argumentInfo.m_Value.toQVariant();
+ argument.m_completeType = argMetaData->m_CompleteType;
+ m_handlerArguments.append(QVariant::fromValue(argument));
+ }
+ }
+}
+
+void ActionView::emitActionChanged()
+{
+ m_actionChangedCompressionTimer.start();
+}
+
+void ActionView::setArgumentValue(int handle, const QVariant &value)
+{
+ if (!m_itemHandle.Valid())
+ return;
+
+ if (handle == 0)
+ return;
+
+ qt3dsdm::SValue sValue(value);
+ qt3dsdm::SValue oldValue;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
+
+ if (!Equals(oldValue, sValue)) {
+ CCmd *theCmd =
+ new CCmdDataModelActionSetArgumentValue(GetDoc(), handle, sValue);
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ }
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler == L"Fire Event") {
+ if (value.toInt())
+ updateFiredEventFromHandle(value.toInt());
+ }
+}
+
+CDoc *ActionView::GetDoc()
+{
+ return g_StudioApp.GetCore()->GetDoc();
+}
+
+CClientDataModelBridge *ActionView::GetBridge()
+{
+ return GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+}
+
+void ActionView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty(QStringLiteral("_parentView"), this);
+ rootContext()->setContextProperty(QStringLiteral("_resDir"), StudioUtils::resourceImageUrl());
+ rootContext()->setContextProperty(QStringLiteral("_tabOrderHandler"), tabOrderHandler());
+ rootContext()->setContextProperty(QStringLiteral("_mouseHelper"), &m_mouseHelper);
+ m_mouseHelper.setWidget(this);
+
+ QString shiftKey(QStringLiteral("Shift+"));
+#ifdef Q_OS_MACOS
+ shiftKey = "⇧";
+#endif
+ rootContext()->setContextProperty(QStringLiteral("_shiftKey"), shiftKey);
+ qmlRegisterUncreatableType<qt3dsdm::HandlerArgumentType>(
+ "Qt3DStudio", 1, 0, "HandlerArgumentType",
+ QStringLiteral("HandlerArgumentType is an enum container"));
+ qmlRegisterUncreatableType<qt3dsdm::DataModelDataType>(
+ "Qt3DStudio", 1, 0, "DataModelDataType",
+ QStringLiteral("DataModelDataType is an enum container"));
+ qmlRegisterUncreatableType<qt3dsdm::AdditionalMetaDataType>(
+ "Qt3DStudio", 1, 0, "AdditionalMetaDataType",
+ QStringLiteral("AdditionalMetaDataType is an enum container"));
+ qmlRegisterUncreatableType<PropertyInfo>(
+ "Qt3DStudio", 1, 0, "PropertyInfo",
+ QStringLiteral("PropertyInfo is not creatable in QML"));
+ qmlRegisterUncreatableType<qt3dsdm::CompleteMetaDataType>(
+ "Qt3DStudio", 1, 0, "CompleteMetaDataType",
+ QStringLiteral("CompleteMetaDataType is an enum container"));
+ engine()->addImportPath(StudioUtils::qmlImportPath());
+ setSource(QUrl(QStringLiteral("qrc:/Palettes/Action/ActionView.qml")));
+}
+
+QStringList ActionView::slideNames()
+{
+ if (!m_itemHandle.Valid())
+ return {};
+
+ std::list<Q3DStudio::CString> outSlideNames;
+ QStringList slideNames;
+ CClientDataModelBridge *theBridge = GetBridge();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+
+ theBridge->GetSlideNamesOfAction(action, outSlideNames);
+
+ for (auto slideName : outSlideNames)
+ slideNames.append(slideName.toQString());
+
+ return slideNames;
+}
+
+int ActionView::slideNameToIndex(const QString &name)
+{
+ const auto slides = slideNames(); // KDAB_TODO cache it
+ return slides.indexOf(name);
+}
+
+bool ActionView::toolTipsEnabled()
+{
+ return CStudioPreferences::ShouldShowTooltips();
+}
+
+void ActionView::updateActionStates()
+{
+ bool hasValidAction = (m_currentActionIndex != -1) && m_itemHandle.Valid();
+ m_actionCopy->setEnabled(hasValidAction);
+ m_actionCut->setEnabled(hasValidAction);
+ m_actionDel->setEnabled(hasValidAction);
+ // Allow paste action even if item is not valid (list of actions is empty)
+ m_actionPaste->setEnabled(CStudioClipboard::CanPasteAction());
+}
+
+// m_propertyValueInvalid flag indicates that property value is changing and
+// may not be valid if queried at the moment. It is used to prevent QML errors
+// about invalid value types when changing property handlers.
+void ActionView::setPropertyValueInvalid(bool invalid)
+{
+ if (invalid != m_propertyValueInvalid) {
+ m_propertyValueInvalid = invalid;
+ Q_EMIT propertyValueInvalidChanged();
+ }
+}
+
+// This is used to set m_propertyValueInvalid to false asynchronously
+void ActionView::clearPropertyValueInvalid()
+{
+ setPropertyValueInvalid(false);
+}
+
+void ActionView::onAssetGraphChanged()
+{
+ // Changes to asset graph invalidate the object browser model, so close it if it is open
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()
+ && (m_activeBrowser == m_targetObjectBrowser
+ || m_activeBrowser == m_triggerObjectBrowser)) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.h b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.h
new file mode 100644
index 00000000..ab2976f3
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.h
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 ACTIONVIEW_H
+#define ACTIONVIEW_H
+
+#include <QtQuickWidgets/qquickwidget.h>
+#include <QtGui/qcolor.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+
+#include "Qt3DSCommonPrecompile.h"
+#include "DispatchListeners.h"
+#include "EventsBrowserView.h"
+#include "EventsModel.h"
+#include "ObjectBrowserView.h"
+#include "ObjectListModel.h"
+#include "PropertyModel.h"
+#include "SelectedValueImpl.h"
+#include "Qt3DSDMHandles.h"
+#include "Qt3DSDMSignals.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "Qt3DSDMMetaDataTypes.h"
+#include "TabOrderHandler.h"
+#include "MouseHelper.h"
+
+class ActionModel;
+class CClientDataModelBridge;
+class CCore;
+class CDoc;
+class IObjectReferenceHelper;
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+
+struct HandlerArgument {
+ Q_PROPERTY(qt3dsdm::HandlerArgumentType::Value type MEMBER m_type FINAL)
+ Q_PROPERTY(QString name MEMBER m_name FINAL)
+ Q_PROPERTY(int handle MEMBER m_handle FINAL)
+ Q_PROPERTY(QVariant value MEMBER m_value FINAL)
+ Q_PROPERTY(qt3dsdm::CompleteMetaDataType::Enum completeType MEMBER m_completeType FINAL)
+
+ qt3dsdm::Qt3DSDMHandlerArgHandle m_handle;
+ qt3dsdm::HandlerArgumentType::Value m_type;
+ qt3dsdm::CompleteMetaDataType::Enum m_completeType;
+ QString m_name;
+ QVariant m_value;
+
+ Q_GADGET
+};
+
+Q_DECLARE_METATYPE(HandlerArgument)
+
+class ActionView : public QQuickWidget,
+ public CPresentationChangeListener,
+ public TabNavigable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QAbstractItemModel *actionsModel READ actionsModel NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QAbstractItemModel *propertyModel READ propertyModel NOTIFY propertyModelChanged FINAL)
+ Q_PROPERTY(QString itemIcon READ itemIcon NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QString itemText READ itemText NOTIFY itemTextChanged FINAL)
+ Q_PROPERTY(QColor itemColor READ itemColor NOTIFY itemChanged FINAL)
+ Q_PROPERTY(bool hasItem MEMBER m_hasItem NOTIFY hasItemChanged FINAL)
+ Q_PROPERTY(QString triggerObjectName READ triggerObjectName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString targetObjectName READ targetObjectName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString eventName READ eventName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString handlerName READ handlerName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QVariantList handlerArguments READ handlerArguments NOTIFY actionChanged FINAL)
+ Q_PROPERTY(PropertyInfo property READ property NOTIFY propertyChanged FINAL)
+ Q_PROPERTY(QString firedEvent MEMBER m_firedEvent NOTIFY firedEventChanged FINAL)
+ Q_PROPERTY(bool propertyValueInvalid READ isPropertyValueInvalid NOTIFY propertyValueInvalidChanged FINAL)
+
+public:
+ ActionView(const QSize &preferredSize, QWidget *parent = nullptr);
+ ~ActionView() override;
+
+ QSize sizeHint() const override;
+
+ void setItem(const qt3dsdm::Qt3DSDMInstanceHandle &handle);
+ QString itemIcon() const;
+ QString itemText() const;
+ QColor itemColor() const;
+ QAbstractItemModel *actionsModel() const;
+ QAbstractItemModel *propertyModel() const;
+ QString targetObjectName() const;
+ QString triggerObjectName() const;
+ QString eventName() const;
+ QString handlerName() const;
+ QVariantList handlerArguments() const;
+ PropertyInfo property() const;
+ bool isPropertyValueInvalid() const;
+
+ Q_INVOKABLE void setCurrentActionIndex(int index);
+ Q_INVOKABLE void setCurrentPropertyIndex(int handle, int index);
+ Q_INVOKABLE void addAction();
+ Q_INVOKABLE void deleteAction(int index);
+ Q_INVOKABLE QObject *showTriggerObjectBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showTargetObjectBrowser(const QPoint &point);
+ Q_INVOKABLE void showContextMenu(int x, int y);
+ Q_INVOKABLE QObject *showEventBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showHandlerBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showEventBrowserForArgument(int handle, const QPoint &point);
+ Q_INVOKABLE void setArgumentValue(int handle, const QVariant &value);
+ Q_INVOKABLE QStringList slideNames();
+ Q_INVOKABLE int slideNameToIndex(const QString &name);
+ Q_INVOKABLE bool toolTipsEnabled();
+
+ // CPresentationChangeListener
+ void OnNewPresentation() override;
+ void OnClosingPresentation() override;
+
+ // ISelectionChangeListener
+ void OnSelectionSet(Q3DStudio::SSelectedValue inSelectable);
+
+ // Action callback
+ void OnActionAdded(qt3dsdm::Qt3DSDMActionHandle inAction, qt3dsdm::Qt3DSDMSlideHandle inSlide,
+ qt3dsdm::Qt3DSDMInstanceHandle inOwner);
+ void OnActionDeleted(qt3dsdm::Qt3DSDMActionHandle inAction, qt3dsdm::Qt3DSDMSlideHandle inSlide,
+ qt3dsdm::Qt3DSDMInstanceHandle inOwner);
+ void OnActionModified(qt3dsdm::Qt3DSDMActionHandle inAction);
+ void OnHandlerArgumentModified(qt3dsdm::Qt3DSDMHandlerArgHandle inHandlerArgument);
+ void OnInstancePropertyValueChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty);
+ void OnInstanceDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance);
+ void OnTargetSelectionChanged();
+ void OnTriggerSelectionChanged();
+
+protected:
+ void focusInEvent(QFocusEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ bool event(QEvent *event) override;
+
+Q_SIGNALS:
+ void itemChanged();
+ void itemTextChanged();
+ void actionChanged();
+ void propertyModelChanged();
+ void propertyChanged();
+ void firedEventChanged();
+ void hasItemChanged();
+ void propertyValueInvalidChanged();
+ void dialogCurrentColorChanged(const QColor &newColor);
+
+private Q_SLOTS:
+ void copyAction();
+ void cutAction();
+ void pasteAction();
+
+private:
+ void setTriggerObject(const qt3dsdm::SObjectRefType &object);
+ void setTargetObject(const qt3dsdm::SObjectRefType &object);
+ void setEvent(const qt3dsdm::Qt3DSDMEventHandle &event);
+ void setHandler(const qt3dsdm::Qt3DSDMHandlerHandle &handler);
+ QVariant handlerArgumentValue(int handle) const;
+ void updateHandlerArguments();
+ void emitActionChanged();
+ void updateFiredEvent();
+ void resetFiredEvent();
+ void updateFiredEventFromHandle(int handle);
+ void updateActionStates();
+ void setPropertyValueInvalid(bool invalid);
+ void clearPropertyValueInvalid();
+ void onAssetGraphChanged();
+
+ static CDoc *GetDoc();
+ static CClientDataModelBridge *GetBridge();
+
+ void initialize();
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QColor m_selectColor = Qt::transparent;
+ qt3dsdm::Qt3DSDMInstanceHandle m_itemHandle;
+ IObjectReferenceHelper *m_objRefHelper = nullptr;
+ ActionModel *m_actionsModel = nullptr;
+ PropertyModel *m_propertyModel = nullptr;
+ std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>>
+ m_connections; /// connections to the DataModel
+ QPointer<ObjectListModel> m_objectsModel;
+ QPointer<ObjectBrowserView> m_triggerObjectBrowser;
+ QPointer<ObjectBrowserView> m_targetObjectBrowser;
+ QPointer<EventsModel> m_eventsModel;
+ QPointer<EventsModel> m_handlersModel;
+ QPointer<EventsModel> m_fireEventsModel;
+ QPointer<EventsBrowserView> m_eventsBrowser;
+ QPointer<EventsBrowserView> m_handlerBrowser;
+ QPointer<EventsBrowserView> m_fireEventsBrowser;
+ int m_currentActionIndex = -1;
+ int m_currentPropertyIndex = -1;
+ qt3dsdm::Qt3DSDMHandlerArgHandle m_currentPropertyNameHandle;
+ qt3dsdm::Qt3DSDMHandlerArgHandle m_currentPropertyValueHandle;
+ QVariantList m_handlerArguments;
+ QTimer m_actionChangedCompressionTimer;
+ QString m_firedEvent;
+ MouseHelper m_mouseHelper;
+ QSize m_preferredSize;
+ bool m_hasItem = false;
+ QAction *m_actionDel;
+ QAction *m_actionCopy;
+ QAction *m_actionCut;
+ QAction *m_actionPaste;
+ bool m_propertyValueInvalid = true;
+ QColor m_currentColor;
+ QPointer<QWidget> m_activeBrowser = nullptr;
+};
+
+#endif // ACTIONVIEW_H
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.qml b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.qml
new file mode 100644
index 00000000..a5b905b3
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/ActionView.qml
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.2
+import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+
+ Item {
+ id: focusEater
+ objectName: "focusEater"
+ // Used to eat keyboard focus when user clicks outside any property control
+ }
+
+ Flickable {
+ id: actionFlickable
+ ScrollBar.vertical: ScrollBar {
+ id: scrollBar
+ visible: size < 1.0
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ z: -10
+ onPressed: {
+ mouse.accepted = false
+ focusEater.forceActiveFocus();
+ }
+ }
+
+ anchors.fill: parent
+ contentHeight: contentColumn.height
+
+ property bool scrollToBottom: false
+
+ onContentHeightChanged: {
+ if (scrollToBottom) {
+ scrollToBottom = false;
+ if (contentHeight > height)
+ contentY = contentHeight - height;
+ }
+ }
+
+ Column {
+ id: contentColumn
+ width: parent.width
+ spacing: 4
+
+ RowLayout {
+ height: _controlBaseHeight + 8
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 4
+ anchors.rightMargin: 12
+
+ Image {
+ id: headerImage
+ source: _parentView.itemIcon !== "" ? _resDir + _parentView.itemIcon : ""
+ }
+
+ StyledLabel {
+ Layout.fillWidth: true
+ text: _parentView.itemText
+ color: _parentView.itemColor
+ }
+
+ StyledToolButton {
+ enabled: actionsList.currentIndex !== -1
+ enabledImage: "Action-Trash-Normal.png"
+ disabledImage: "Action-Trash-Disabled.png"
+ toolTipText: qsTr("Delete (Del)")
+
+ onClicked: _parentView.deleteAction(actionsList.currentIndex)
+ }
+
+ StyledToolButton {
+ enabledImage: "add.png"
+ disabledImage: "add-disabled.png"
+ toolTipText: qsTr("New Action (") + _shiftKey + "A)"
+ enabled: _parentView.hasItem
+
+ onClicked: _parentView.addAction()
+ }
+ }
+ ListView {
+ id: actionsList
+ width: parent.width
+ height: count == 0 ? _controlBaseHeight : count * _controlBaseHeight
+ clip: true
+
+ Connections {
+ target: _parentView
+ // Clear the action selection on item selection change
+ onItemChanged: actionsList.currentIndex = -1
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ enabled: parent.count == 0
+
+ acceptedButtons: Qt.RightButton
+
+ onClicked: {
+ if (mouse.button == Qt.RightButton) {
+ var updateMousePosition = mapToItem(actionsList, mouse.x, mouse.y)
+ _parentView.showContextMenu(
+ updateMousePosition.x, updateMousePosition.y);
+ }
+ }
+ }
+ boundsBehavior: Flickable.StopAtBounds
+ model: _parentView.actionsModel
+
+ delegate: Rectangle {
+ id: delegateItem
+ objectName: "actionListDelegate"
+
+ width: actionsList.width
+ height: _controlBaseHeight
+ color: model.index === actionsList.currentIndex ? _selectionColor
+ : "transparent"
+
+ Row {
+ x: 10
+ y: 5
+ height: parent.height
+ width: parent.width - x
+ spacing: 4
+
+ Image {
+ id: visibilityIcon
+
+ source: model.visible ? _resDir + "Toggle-HideShow.png"
+ : _resDir + "Toggle-HideShow-disabled.png"
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.visible = !model.visible
+ }
+ }
+
+ StyledLabel {
+ text: model.description
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onPressed: {
+ actionsList.forceActiveFocus();
+ }
+
+ onClicked: {
+ actionFlickable.scrollToBottom = false;
+ actionsList.currentIndex = model.index;
+ _parentView.setCurrentActionIndex(model.index);
+ if (mouse.button == Qt.LeftButton && mouse.x < visibilityIcon.width + 10)
+ model.visible = !model.visible;
+
+ if (mouse.button == Qt.RightButton) {
+ var updateMousePosition = mapToItem(actionsList, mouse.x, mouse.y)
+ _parentView.showContextMenu(updateMousePosition.x, updateMousePosition.y);
+ }
+ }
+ onDoubleClicked: {
+ actionFlickable.scrollToBottom = false;
+ if (mouse.button == Qt.LeftButton && mouse.x > visibilityIcon.width + 10) {
+ // Scroll down to bottom to show properties on double click
+ if (actionFlickable.contentHeight > actionFlickable.height) {
+ actionFlickable.contentY = (actionFlickable.contentHeight
+ - actionFlickable.height)
+ }
+ // Since loading new property fields takes a moment, we want
+ // to keep the view scrolled to bottom
+ // when the content height changes the next time.
+ actionFlickable.scrollToBottom = true;
+ }
+ }
+ }
+ }
+
+ onCountChanged: {
+ if (currentIndex >= count)
+ currentIndex = count - 1;
+ }
+
+ onCurrentIndexChanged: _parentView.setCurrentActionIndex(currentIndex);
+ }
+
+ StyledMenuSeparator {
+ leftPadding: 12
+ rightPadding: 12
+ }
+
+ Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: childrenRect.height
+ visible: actionsList.currentIndex !== -1
+ spacing: 4
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Trigger Object")
+ }
+ BrowserCombo {
+ value: _parentView.triggerObjectName
+ onShowBrowser: activeBrowser = _parentView.showTriggerObjectBrowser(
+ mapToGlobal(width, 0));
+ }
+ }
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Event")
+ }
+ BrowserCombo {
+ value: _parentView.eventName
+ onShowBrowser: activeBrowser = _parentView.showEventBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ StyledMenuSeparator {
+ visible: actionsList.currentIndex !== -1
+ leftPadding: 12
+ rightPadding: 12
+ }
+
+ Column {
+ visible: actionsList.currentIndex !== -1
+ width: parent.width
+ height: childrenRect.height
+ spacing: 4
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Target Object")
+ }
+
+ BrowserCombo {
+ value: _parentView.targetObjectName
+ onShowBrowser: activeBrowser = _parentView.showTargetObjectBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Handler")
+ }
+
+ BrowserCombo {
+ value: _parentView.handlerName
+ onShowBrowser: activeBrowser = _parentView.showHandlerBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+
+ Component {
+ id: genericHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : ""
+
+ onEditingFinished: {
+ if (parent)
+ _parentView.setArgumentValue(parent.argument.handle, value)
+ }
+ }
+ }
+
+ Component {
+ id: floatHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : 0.0
+ validator: DoubleValidator {
+ decimals: 3
+ notation: DoubleValidator.StandardNotation
+ }
+
+ onEditingFinished: {
+ if (parent)
+ _parentView.setArgumentValue(parent.argument.handle, value)
+ }
+ }
+ }
+
+ Component {
+ id: signalHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : ""
+
+ onEditingFinished: {
+ if (parent)
+ _parentView.setArgumentValue(parent.argument.handle, value);
+ }
+ }
+ }
+
+ Component {
+ id: eventHandlerComponent
+
+ HandlerFireEvent {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: _parentView.firedEvent === "" ? qsTr("[Unknown Event]")
+ : _parentView.firedEvent
+
+ onShowBrowser: {
+ if (parent && parent.argument.handle) {
+ activeBrowser = _parentView.showEventBrowserForArgument(
+ parent.argument.handle, mapToGlobal(width, 0))
+ }
+ }
+ }
+ }
+
+ Component {
+ id: slideHandlerComponent
+
+ HandlerGoToSlide {
+ slideModel: _parentView.slideNames()
+ defaultSlideIndex: parent && parent.argument.value ? _parentView.slideNameToIndex(parent.argument.value)
+ : 0
+
+ onActivated: {
+ if (parent && parent.argument.handle && currentSlide)
+ _parentView.setArgumentValue(parent.argument.handle, currentSlide)
+ }
+ }
+ }
+
+ Component {
+ id: checkboxHandlerComponent
+
+ HandlerGenericCheckbox {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ checked: parent && parent.argument.value ? parent.argument.value : false
+
+ onClicked: {
+ if (parent && parent.argument.handle)
+ _parentView.setArgumentValue(parent.argument.handle, !checked)
+ }
+ }
+ }
+
+ Component {
+ id: propertyHandlerComponent
+
+ HandlerProperty {
+ propertyModel: _parentView.propertyModel
+ defaultPropertyIndex: propertyModel ? propertyModel.defaultPropertyIndex : 0
+
+ onPropertySelected: {
+ if (parent && parent.argument.handle)
+ _parentView.setCurrentPropertyIndex(parent.argument.handle, index);
+ }
+ }
+ }
+
+ Repeater {
+ model: _parentView.handlerArguments.length
+
+ Loader {
+ x: 12
+
+ readonly property var argument:_parentView.handlerArguments[model.index]
+
+ onLoaded: {
+ // HandlerProperty does its own tab order handling
+ if (argument.type !== HandlerArgumentType.Property) {
+ // Dynamic actions use group 0.
+ // We assume there is always just one tabbable argument per action,
+ // and the rest are dependent types.
+ _tabOrderHandler.clear();
+ if (item.tabItem1 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem1)
+ if (item.tabItem2 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem2)
+ if (item.tabItem3 !== undefined)
+ _tabOrderHandler.addItem(0, item.tabItem3)
+ }
+ }
+ }
+ }
+
+ sourceComponent: {
+ const handlerType = argument.type;
+ switch (handlerType) {
+ case HandlerArgumentType.None:
+ switch (argument.completeType) {
+ case CompleteMetaDataType.Boolean:
+ return checkboxHandlerComponent;
+ case CompleteMetaDataType.Float:
+ return floatHandlerComponent;
+ default:
+ return genericHandlerComponent;
+ }
+ case HandlerArgumentType.Event:
+ return eventHandlerComponent;
+ case HandlerArgumentType.Property:
+ return propertyHandlerComponent;
+ case HandlerArgumentType.Dependent:
+ return null; // no UI for Dependent type, they are the value for a property
+ case HandlerArgumentType.Signal:
+ return signalHandlerComponent;
+ case HandlerArgumentType.Slide:
+ return slideHandlerComponent
+ default: console.warn("KDAB_TODO implement handler for type: ", handlerType)
+ }
+ return null;
+ }
+ }
+ }
+ }
+
+ StyledMenuSeparator {
+ visible: actionsList.count > 0 && actionsList.currentIndex !== -1
+ leftPadding: 12
+ rightPadding: 12
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowser.qml b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowser.qml
new file mode 100644
index 00000000..e5cb3998
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowser.qml
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ ListView {
+ id: eventsList
+
+ Layout.margins: 5
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+ currentIndex: _eventsBrowserView.selection
+
+ model: _eventsBrowserView.model
+
+ delegate: Item {
+ id: delegateItem
+
+ readonly property bool isCategory: model.isCategory
+
+ width: parent.width
+ height: model.parentExpanded ? _controlBaseHeight : 0
+ visible: height > 0
+
+ Behavior on height {
+ NumberAnimation {
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: model.index === eventsList.currentIndex ? _selectionColor
+ : "transparent"
+ Row {
+ id: row
+ width: parent.width
+ height: parent.height
+ spacing: 5
+
+ Image {
+ id: arrow
+ anchors.verticalCenter: parent.verticalCenter
+ source: {
+ if (!delegateItem.isCategory)
+ return "";
+ model.expanded ? _resDir + "arrow_down.png"
+ : _resDir + "arrow.png";
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.expanded = !model.expanded
+ }
+ }
+
+ Image { // group icon
+ anchors.verticalCenter: parent.verticalCenter
+ source: model.icon
+ }
+
+ StyledLabel {
+ id: name
+ leftPadding: isCategory ? 0 : 45
+ anchors.verticalCenter: parent.verticalCenter
+ text: model.name
+ }
+ }
+
+ MouseArea {
+ id: delegateArea
+ anchors.fill: parent
+ anchors.leftMargin: arrow.width
+ hoverEnabled: true
+ onClicked: {
+ if (!delegateItem.isCategory)
+ eventsList.currentIndex = model.index;
+ }
+ onEntered: itemDescription.text = model.description
+ onExited: itemDescription.text = ""
+ onDoubleClicked: {
+ if (!delegateItem.isCategory) {
+ eventsList.currentIndex = model.index;
+ _eventsBrowserView.close();
+ } else {
+ model.expanded = !model.expanded
+ }
+ }
+ }
+ }
+
+ }
+ onCurrentIndexChanged: _eventsBrowserView.selection = currentIndex
+
+ Connections {
+ target: _eventsBrowserView
+ onSelectionChanged: {
+ if (eventsList.currentIndex !== _eventsBrowserView.selection)
+ eventsList.currentIndex = _eventsBrowserView.selection;
+ }
+ }
+ }
+
+ StyledMenuSeparator {
+ bottomPadding: 0
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.preferredHeight: _controlBaseHeight + 4
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 2
+
+ color: _backgroundColor
+
+ StyledLabel {
+ id: itemDescription
+ leftPadding: 6
+ anchors.fill: parent
+ }
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.cpp
new file mode 100644
index 00000000..b7151af2
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "EventsBrowserView.h"
+
+#include "EventsModel.h"
+#include "StudioUtils.h"
+#include "StudioPreferences.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+EventsBrowserView::EventsBrowserView(QWidget *parent) : QQuickWidget(parent)
+{
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &EventsBrowserView::initialize);
+}
+
+QAbstractItemModel *EventsBrowserView::model() const
+{
+ return m_model;
+}
+
+void EventsBrowserView::setModel(EventsModel *model)
+{
+ if (m_model != model) {
+ m_model = model;
+ Q_EMIT modelChanged();
+ }
+}
+
+qt3dsdm::CDataModelHandle EventsBrowserView::selectedHandle() const
+{
+ const auto handleId = m_model->handleForRow(m_selection);
+ return handleId;
+}
+
+void EventsBrowserView::selectAndExpand(const QString &event)
+{
+ // All categories are expanded by default, so let's just select
+ m_blockCommit = true;
+ setSelection(m_model->rowForEventName(event));
+ m_blockCommit = false;
+
+}
+
+void EventsBrowserView::setSelection(int index)
+{
+ auto handleId = m_model->handleForRow(index);
+ if (!handleId.Valid()) {
+ m_selection = -1;
+ Q_EMIT selectionChanged();
+ } else if (m_selection != index) {
+ m_selection = index;
+ Q_EMIT selectionChanged();
+ }
+}
+
+void EventsBrowserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &EventsBrowserView::close);
+}
+
+void EventsBrowserView::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Escape)
+ QTimer::singleShot(0, this, &EventsBrowserView::close);
+
+ QQuickWidget::keyPressEvent(event);
+}
+
+void EventsBrowserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty(QStringLiteral("_eventsBrowserView"), this);
+ rootContext()->setContextProperty(QStringLiteral("_resDir"),
+ StudioUtils::resourceImageUrl());
+ engine()->addImportPath(StudioUtils::qmlImportPath());
+ setSource(QUrl(QStringLiteral("qrc:/Palettes/Action/EventsBrowser.qml")));
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.h b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.h
new file mode 100644
index 00000000..f8a2b7fa
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/EventsBrowserView.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 EVENTSBROWSERVIEW_H
+#define EVENTSBROWSERVIEW_H
+
+#include <QQuickWidget>
+
+#include "Qt3DSDMHandles.h"
+
+class EventsModel;
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+
+class EventsBrowserView : 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:
+ explicit EventsBrowserView(QWidget *parent = nullptr);
+
+ QAbstractItemModel *model() const;
+ void setModel(EventsModel *model);
+ qt3dsdm::CDataModelHandle selectedHandle() const;
+
+ void selectAndExpand(const QString &event);
+
+ int selection() const { return m_selection; }
+ void setSelection(int index);
+
+ void setHandle(int handle) { m_handle = handle; }
+ int handle() const { return m_handle; }
+
+ bool canCommit() const { return !m_blockCommit; }
+
+Q_SIGNALS:
+ void modelChanged();
+ void selectionChanged();
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+
+private:
+ void initialize();
+ EventsModel *m_model = nullptr;
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QColor m_selectColor;
+ int m_selection = -1;
+ int m_handle = -1;
+ bool m_blockCommit = false;
+};
+
+#endif // EVENTSBROWSERVIEW_H
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.cpp
new file mode 100644
index 00000000..981ab95a
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "EventsModel.h"
+
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "Qt3DSDMStudioSystem.h"
+
+EventsModel::EventsModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void EventsModel::setEventList(const qt3dsdm::TEventHandleList &eventList)
+{
+ beginResetModel();
+
+ m_rowCount = 0;
+ m_events.clear();
+ m_categories.clear();
+
+ auto studioSystem = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ auto theBridge = studioSystem->GetClientDataModelBridge();
+ auto thePos = eventList.begin();
+ for (; thePos != eventList.end(); ++thePos) {
+ qt3dsdm::SEventInfo theEvent = theBridge->GetEventInfo(*thePos);
+
+ CategoryInfo category;
+ category.name = QString::fromWCharArray(theEvent.m_Category.wide_str());
+ if (!m_events.contains(category.name)) {
+ qt3dsdm::SCategoryInfo theCategoryMetaData = studioSystem->GetActionMetaData()
+ ->GetEventCategory(theEvent.m_Category);
+ category.icon = QString::fromWCharArray(theCategoryMetaData.m_Icon.wide_str());
+ category.highlightIcon = QString::fromWCharArray(theCategoryMetaData.m_HighlightIcon.wide_str());
+ category.description = QString::fromWCharArray(theCategoryMetaData.m_Description.wide_str());
+ m_categories.append(category);
+ m_rowCount++;
+ }
+
+ EventInfo eventInfo;
+ // Use the formal name to display, but if the formal name is not set, use the name instead
+ eventInfo.name = QString::fromWCharArray(theEvent.m_FormalName.wide_str());
+ if (eventInfo.name.isEmpty())
+ eventInfo.name = QString::fromWCharArray(theEvent.m_Name.wide_str());
+ eventInfo.handle = *thePos;
+
+ eventInfo.description = QString::fromWCharArray(theEvent.m_Description.wide_str());
+ m_events[category.name].append(eventInfo);
+ m_rowCount++;
+
+ //KDAB_TODO set the selection to the current event
+ }
+
+ endResetModel();
+}
+
+void EventsModel::setHandlerList(const qt3dsdm::THandlerHandleList &handlerList)
+{
+ beginResetModel();
+ m_rowCount = 0;
+ m_events.clear();
+ m_categories.clear();
+
+ auto studioSystem = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ auto theBridge = studioSystem->GetClientDataModelBridge();
+ auto thePos = handlerList.begin();
+ for (; thePos != handlerList.end(); ++thePos) {
+ qt3dsdm::SHandlerInfo handlerInfo = theBridge->GetHandlerInfo(*thePos);
+
+ CategoryInfo category;
+ category.name = QString::fromWCharArray(handlerInfo.m_Category.wide_str());
+ if (!m_events.contains(category.name)) {
+ qt3dsdm::SCategoryInfo theCategoryMetaData = studioSystem->GetActionMetaData()
+ ->GetHandlerCategory(handlerInfo.m_Category);
+ category.icon = QString::fromWCharArray(theCategoryMetaData.m_Icon.wide_str());
+ category.highlightIcon = QString::fromWCharArray(theCategoryMetaData.m_HighlightIcon.wide_str());
+ category.description = QString::fromWCharArray(theCategoryMetaData.m_Description.wide_str());
+ m_categories.append(category);
+ m_rowCount++;
+ }
+
+ EventInfo eventInfo;
+ // Use the formal name to display, but if the formal name is not set, use the name instead
+ eventInfo.name = QString::fromWCharArray(handlerInfo.m_FormalName.wide_str());
+ if (eventInfo.name.isEmpty())
+ eventInfo.name = QString::fromWCharArray(handlerInfo.m_Name.wide_str());
+ eventInfo.handle = *thePos;
+
+ eventInfo.description = QString::fromWCharArray(handlerInfo.m_Description.wide_str());
+ m_events[category.name].append(eventInfo);
+ m_rowCount++;
+
+ //KDAB_TODO set the selection to the current event
+ }
+
+ endResetModel();
+}
+
+int EventsModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_rowCount;
+}
+
+QVariant EventsModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto row = index.row();
+ auto category = categoryForRow(row);
+
+ bool isCategory = category.isValid();
+ EventInfo event;
+ if (!isCategory)
+ event = eventForRow(row);
+
+ switch (role) {
+ case NameRole:
+ return isCategory ? category.name : event.name;
+ case DescriptionRole:
+ return isCategory ? category.description: event.description;
+ case IconRole:
+ return isCategory ? StudioUtils::resourceImageUrl() + category.icon : QString();
+ case HighlightedIconRole:
+ return isCategory ? StudioUtils::resourceImageUrl() + category.highlightIcon : QString();
+ case ExpandedRole:
+ return isCategory ? category.expanded : false;
+ case ParentExpandedRole: {
+ if (isCategory)
+ return true;
+ for (int i = row - 1; i >= 0; i--) {
+ auto parentCategory = categoryForRow(i);
+ if (parentCategory.isValid())
+ return parentCategory.expanded;
+ }
+ return false;
+ }
+ case IsCategoryRole:
+ return isCategory;
+ }
+
+ return QVariant();
+}
+
+bool EventsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == ExpandedRole) {
+ int catRow = categoryRowForRow(index.row());
+ if (catRow != -1) {
+ auto category = &m_categories[catRow];
+ category->expanded = value.toBool();
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {});
+ return true;
+ }
+ }
+ return false;
+}
+
+QHash<int, QByteArray> EventsModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(DescriptionRole, "description");
+ names.insert(IconRole, "icon");
+ names.insert(HighlightedIconRole, "highlightedIcon");
+ names.insert(IsCategoryRole, "isCategory");
+ names.insert(ExpandedRole, "expanded");
+ names.insert(ParentExpandedRole, "parentExpanded");
+
+ return names;
+}
+
+qt3dsdm::CDataModelHandle EventsModel::handleForRow(int row) const
+{
+ if (row < 0 || row >= m_rowCount)
+ return {};
+
+ auto event = eventForRow(row);
+ if (event.isValid())
+ return event.handle;
+
+ return {};
+}
+
+int EventsModel::rowForEventName(const QString &event) const
+{
+ int i = 0;
+ for (const auto &category: m_categories) {
+ i++;
+ const auto events = m_events[category.name];
+ for (int j = 0; j < events.size(); j++, i++) {
+ if (events[j].name == event)
+ return i;
+ }
+ }
+ return i;
+}
+
+EventsModel::CategoryInfo EventsModel::categoryForRow(int row) const
+{
+ int i = 0;
+ for (const auto &category: m_categories) {
+ if (i == row)
+ return category;
+ i += m_events[category.name].size();
+ i++;
+ }
+
+ return {};
+}
+
+int EventsModel::categoryRowForRow(int row) const
+{
+ int i = 0;
+ int catRow = 0;
+ for (const auto &category: m_categories) {
+ if (i == row)
+ return catRow;
+ i += m_events[category.name].size();
+ i++;
+ catRow++;
+ }
+
+ return -1;
+}
+
+EventsModel::EventInfo EventsModel::eventForRow(int row) const
+{
+ if (row == 0) // first line is not an event, but a category
+ return {};
+
+ int i = 0;
+ for (const auto &category: m_categories) {
+ i++;
+ const auto events = m_events[category.name];
+ const int index = (row - i);
+ if (row < i + events.size() && (index >= 0) ) {
+ return events[index];
+ }
+ i += events.size();
+ }
+
+ return {};
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.h b/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.h
new file mode 100644
index 00000000..b0f2f4fb
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/EventsModel.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 EVENTSMODEL_H
+#define EVENTSMODEL_H
+
+#include <QAbstractListModel>
+
+#include "Qt3DSDMHandles.h"
+
+/** Model for both action events and action handlers */
+class EventsModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit EventsModel(QObject *parent = nullptr);
+
+ void setEventList(const qt3dsdm::TEventHandleList &eventList);
+ void setHandlerList(const qt3dsdm::THandlerHandleList &handlerList);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::EditRole) override;
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ DescriptionRole = Qt::UserRole + 1,
+ IconRole,
+ HighlightedIconRole,
+ ExpandedRole,
+ ParentExpandedRole,
+ IsCategoryRole
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+
+ qt3dsdm::CDataModelHandle handleForRow(int row) const;
+ int rowForEventName(const QString &event) const;
+
+private:
+ struct EventInfo {
+ qt3dsdm::CDataModelHandle handle;
+ QString name;
+ QString description;
+
+ bool isValid() const { return handle.Valid(); }
+ };
+
+ struct CategoryInfo {
+ QString name;
+ QString icon;
+ QString description;
+ QString highlightIcon;
+ bool expanded = true;
+
+ bool isValid() const { return !name.isEmpty(); }
+ };
+
+ CategoryInfo categoryForRow(int row) const;
+ int categoryRowForRow(int row) const;
+ EventInfo eventForRow(int row) const;
+
+ QHash<QString, QVector<EventInfo> > m_events;
+ QVector<CategoryInfo> m_categories;
+ int m_rowCount = 0;
+};
+
+#endif // EVENTSMODEL_H
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerBaseMultilineText.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerBaseMultilineText.qml
new file mode 100644
index 00000000..fbab75cb
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerBaseMultilineText.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+
+ScrollView {
+ id: root
+ signal editingFinished
+ signal textChanged
+ property alias value: textArea.text
+ property Item tabItem1: textArea
+
+ clip: true
+
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
+
+ TextArea {
+ id: textArea
+ property bool ignoreHotkeys: true
+
+ horizontalAlignment: TextInput.AlignLeft
+ verticalAlignment: TextInput.AlignTop
+ font.pixelSize: _fontSize
+ color: _textColor
+ selectionColor: _selectionColor
+ selectedTextColor: _textColor
+
+ topPadding: 6
+ bottomPadding: 6
+ rightPadding: 6
+
+ wrapMode: TextEdit.WrapAnywhere
+ background: Rectangle {
+ anchors.fill: parent
+ color: textArea.enabled ? _studioColor2 : "transparent"
+ border.width: textArea.activeFocus ? 1 : 0
+ border.color: textArea.activeFocus ? _selectionColor : _disabledColor
+ }
+
+ MouseArea {
+ id: mouseArea
+ property int clickedPos
+
+ anchors.fill: parent
+ preventStealing: true
+ onPressed: {
+ textArea.forceActiveFocus()
+ clickedPos = textArea.positionAt(mouse.x, mouse.y)
+ textArea.cursorPosition = clickedPos
+ }
+ onDoubleClicked: textArea.selectAll()
+ onPositionChanged: {
+ textArea.cursorPosition = textArea.positionAt(mouse.x, mouse.y)
+ textArea.select(clickedPos, textArea.cursorPosition)
+ }
+ }
+ onTextChanged: root.textChanged()
+ onEditingFinished: root.editingFinished()
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerEmitSignal.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerEmitSignal.qml
new file mode 100644
index 00000000..16eac96e
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerEmitSignal.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: textField.text
+ property Item tabItem1: textfield
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Signal Name")
+ }
+
+ StyledTextField {
+ id: textField
+ Layout.preferredWidth: _valueWidth
+ }
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerFireEvent.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerFireEvent.qml
new file mode 100644
index 00000000..5b2ca0f6
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerFireEvent.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: comboField.value
+ property alias activeBrowser: comboField.activeBrowser
+
+ signal showBrowser
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Event")
+ }
+
+ BrowserCombo {
+ id: comboField
+ Layout.preferredWidth: _valueWidth
+ value: qsTr("[Unknown Event]")
+ onShowBrowser: root.showBrowser()
+ }
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericBaseColor.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericBaseColor.qml
new file mode 100644
index 00000000..8c184409
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericBaseColor.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Dialogs 1.2
+import QtQuick.Layouts 1.3
+
+RowLayout {
+ id: root
+
+ property alias color: rect.color
+ property color selectedColor: "black"
+ property bool listenToColorChanges: false
+
+ signal colorSelected()
+ signal previewColorSelected()
+
+ Connections {
+ target: _parentView
+ onDialogCurrentColorChanged: {
+ if (root.listenToColorChanges) {
+ root.selectedColor = newColor;
+ root.previewColorSelected();
+ }
+ }
+ }
+
+ Rectangle {
+ id: rect
+
+ width: _valueWidth / 4
+ height: _controlBaseHeight
+
+ border {
+ width: 1
+ color: _studioColor2
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ onClicked: {
+ root.listenToColorChanges = true;
+ _inspectorModel.suspendMaterialRename(true);
+ root.selectedColor = _parentView.showColorDialog(rect.color, instance, handle);
+ root.listenToColorChanges = false;
+ _inspectorModel.suspendMaterialRename(false);
+ root.colorSelected();
+ }
+ }
+
+ Image {
+ id: img
+ // Source image size is 16x16 pixels
+ x: parent.width - 18
+ y: parent.height / 2 - 8
+ source: _resDir + "arrow_down.png"
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericCheckbox.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericCheckbox.qml
new file mode 100644
index 00000000..8446f761
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericCheckbox.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property bool checked: false
+ property alias label: labelField.text
+
+ signal clicked()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Pause")
+ }
+
+ Image {
+ source: _resDir + (checked ? "checkbox-checked.png" : "checkbox-unchecked.png")
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: root.clicked()
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericColor.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericColor.qml
new file mode 100644
index 00000000..cad079ee
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericColor.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias color: handlerGenericColor.color
+ property alias selectedColor: handlerGenericColor.selectedColor
+
+ signal colorSelected()
+ signal previewColorSelected()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("New Value")
+ }
+
+ HandlerGenericBaseColor {
+ id: handlerGenericColor
+
+ onColorSelected: root.colorSelected();
+ onPreviewColorSelected: root.previewColorSelected();
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericFloat.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericFloat.qml
new file mode 100644
index 00000000..11ac38a5
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericFloat.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property real desiredValue: Number(floatField.text)
+ property real value: 0
+ property int numberOfDecimal: 3
+ property Item tabItem1: floatField
+
+ signal editingFinished
+ signal previewValueChanged
+
+ onValueChanged: {
+ // FloatTextField can set its text internally, thus breaking the binding, so
+ // let's set the text value explicitly each time value changes
+ floatField.text = Number(value).toFixed(numberOfDecimal);
+ }
+
+ StyledLabel {
+ id: labelField
+ }
+
+ FloatTextField {
+ id: floatField
+ Layout.preferredWidth: _valueWidth
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericText.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericText.qml
new file mode 100644
index 00000000..738bf6a3
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGenericText.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: textField.text
+ property alias validator: textField.validator
+ property Item tabItem1: textField
+
+ signal editingFinished
+
+ onValueChanged: {
+ textField.text = value;
+ }
+
+ StyledLabel {
+ id: labelField
+ }
+
+ StyledTextField {
+ id: textField
+ onEditingFinished: root.editingFinished();
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGoToSlide.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGoToSlide.qml
new file mode 100644
index 00000000..6ad1564b
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerGoToSlide.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias slideModel: comboSlide.model
+ property string currentSlide
+ property int defaultSlideIndex: 0
+
+ signal activated()
+
+ onDefaultSlideIndexChanged: comboSlide.currentIndex = defaultSlideIndex
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Slide")
+ }
+
+ StyledComboBox {
+ id: comboSlide
+ Layout.preferredWidth: _valueWidth
+ model: slideModel
+
+ onActivated: {
+ currentSlide = comboSlide.textAt(currentIndex);
+ root.activated();
+ }
+ }
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerMultilineText.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerMultilineText.qml
new file mode 100644
index 00000000..834b1083
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerMultilineText.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: multiLine.value
+ property alias tabItem1: multiLine.tabItem1
+
+ signal editingFinished
+ signal textChanged
+
+ onValueChanged: {
+ multiLine.value = value;
+ }
+
+ StyledLabel {
+ id: labelField
+ }
+
+ HandlerBaseMultilineText {
+ id: multiLine
+
+ Layout.preferredWidth: _valueWidth
+ Layout.preferredHeight: _controlBaseHeight * 3
+
+ onTextChanged: root.textChanged();
+ onEditingFinished: root.editingFinished();
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerProperty.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerProperty.qml
new file mode 100644
index 00000000..a101488e
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerProperty.qml
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
+import "../controls"
+
+ColumnLayout {
+ id: root
+
+ property alias propertyModel: propertyCombo.model
+ property int defaultPropertyIndex: 0
+
+ signal propertySelected(int index)
+
+ onDefaultPropertyIndexChanged: propertyCombo.currentIndex = defaultPropertyIndex
+
+ RowLayout {
+
+ Layout.fillWidth: true
+
+ StyledLabel {
+ text: qsTr("Property")
+ }
+
+ StyledComboBox {
+ id: propertyCombo
+ textRole: "name"
+ onActivated: root.propertySelected(currentIndex)
+ onModelChanged: currentIndex = root.defaultPropertyIndex
+ }
+ }
+
+ Component {
+ id: multiLineComponent
+
+ HandlerMultilineText {
+ readonly property var actionProperty: parent ? _parentView.property : null
+
+ label: parent ? parent.label : ""
+ value: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined ? propertyModel.value : ""
+ onEditingFinished: _parentView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: fontSizeComponent
+
+ HandlerPropertyCombo {
+ readonly property var actionProperty: parent ? _parentView.property : null
+ property var propertyValue: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined
+ ? propertyModel.value : ""
+
+ label: parent ? parent.label : ""
+ comboModel: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26",
+ "28", "36", "48", "72", "96", "120"];
+
+ onValueChanged: _parentView.setArgumentValue(propertyModel.valueHandle, value)
+ onPropertyValueChanged: currentIndex = find(propertyValue)
+ }
+ }
+
+ Component {
+ id: xyzPropertyComponent
+
+ HandlerPropertyXYZ {
+ readonly property var propValue: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined
+ ? propertyModel.value : undefined
+ label: parent ? parent.label : ""
+ valueX: propValue !== undefined ? Number(propValue.x).toFixed(numberOfDecimal) : "0.000"
+ valueY: propValue !== undefined ? Number(propValue.y).toFixed(numberOfDecimal) : "0.000"
+ valueZ: propValue !== undefined ? Number(propValue.z).toFixed(numberOfDecimal) : "0.000"
+
+ onPropValueChanged: {
+ // FloatTextField can set its text internally, thus breaking the binding, so
+ // let's set the text value explicitly each time value changes
+ if (propValue !== undefined) {
+ valueX = Number(propValue.x).toFixed(numberOfDecimal);
+ valueY = Number(propValue.y).toFixed(numberOfDecimal);
+ valueZ = Number(propValue.z).toFixed(numberOfDecimal);
+ }
+ }
+
+ onEditingFinished: {
+ _parentView.setArgumentValue(propertyModel.valueHandle,
+ Qt.vector3d(valueX, valueY, valueZ), true);
+ }
+ }
+ }
+
+ Component {
+ id: sliderPropertyComponent
+
+ HandlerPropertySlider {
+ readonly property var actionProperty: parent ? _parentView.property : null
+
+ sliderMin: actionProperty ? actionProperty.min : 0
+ sliderMax: actionProperty ? actionProperty.max : 100
+ intSlider: actionProperty ? actionProperty.type === DataModelDataType.Long : false
+ value: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined ? propertyModel.value : sliderMin
+ label: parent ? parent.label : ""
+
+ // We don't need to care about preview for action sliders
+ onCommitValue: _parentView.setArgumentValue(propertyModel.valueHandle, desiredValue)
+ }
+ }
+
+ Component {
+ id: comboPropertyComponent
+
+ HandlerPropertyCombo {
+ readonly property var actionProperty: parent ? _parentView.property : null
+ property var propertyValue: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined
+ ? propertyModel.value : ""
+
+ label: parent ? parent.label : ""
+ comboModel: actionProperty ? actionProperty.possibleValues : null
+
+ onValueChanged: _parentView.setArgumentValue(propertyModel.valueHandle, value)
+ onPropertyValueChanged: currentIndex = find(propertyValue)
+ }
+ }
+
+ Component {
+ id: booleanComponent
+
+ HandlerGenericCheckbox {
+ label: parent ? parent.label : ""
+ checked: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined ? propertyModel.value : false
+
+ onClicked: {
+ _parentView.setArgumentValue(propertyModel.valueHandle, !checked)
+ }
+ }
+ }
+
+ Component {
+ id: colorBox
+
+ HandlerGenericColor {
+ readonly property var propValue: propertyModel && !_parentView.propertyValueInvalid
+ ? propertyModel.value : undefined
+
+ label: parent ? parent.label : ""
+ color: "black"
+ onColorSelected: {
+ color = selectedColor;
+ _parentView.setArgumentValue(propertyModel.valueHandle, selectedColor);
+ }
+ onPreviewColorSelected: color = selectedColor
+ onPropValueChanged: {
+ color = propValue ? Qt.rgba(propValue.x, propValue.y, propValue.z, 1)
+ : "black";
+ }
+ }
+ }
+
+ Component {
+ id: genericTextComponent
+
+ HandlerGenericText {
+ label: parent ? parent.label : ""
+ value: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined ? propertyModel.value : ""
+ onEditingFinished: _parentView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: floatPropertyComponent
+
+ HandlerGenericFloat {
+ label: parent ? parent.label : ""
+ value: propertyModel && !_parentView.propertyValueInvalid
+ && propertyModel.value !== undefined
+ ? Number(propertyModel.value).toFixed(numberOfDecimal) : 0
+
+ onEditingFinished: _parentView.setArgumentValue(propertyModel.valueHandle, desiredValue)
+ }
+ }
+
+ Loader {
+ readonly property string label: qsTr("New Value")
+ readonly property var actionProperty: _parentView.property
+
+ Layout.fillWidth: true
+
+ onLoaded: {
+ _tabOrderHandler.clear();
+ if (item.tabItem1 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem1)
+ if (item.tabItem2 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem2)
+ if (item.tabItem3 !== undefined)
+ _tabOrderHandler.addItem(0, item.tabItem3)
+ }
+ }
+ }
+
+ sourceComponent: {
+ // KDAB_TODO Handle additionaltype
+ switch (actionProperty.type) {
+ case DataModelDataType.Float:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.FontSize:
+ return fontSizeComponent;
+ case AdditionalMetaDataType.Range:
+ return sliderPropertyComponent;
+ default:
+ return floatPropertyComponent;
+ }
+ case DataModelDataType.Long:
+ return sliderPropertyComponent;
+ case DataModelDataType.Float3:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.None:
+ case AdditionalMetaDataType.Rotation:
+ return xyzPropertyComponent;
+ default:
+ console.warn("KDAB_TODO implement property handler for additional " +
+ "typeDataModelDataType.Float3: ", actionProperty.additionalType);
+ return xyzPropertyComponent;
+ }
+ case DataModelDataType.Float4:
+ if (actionProperty.additionalType === AdditionalMetaDataType.Color)
+ return colorBox;
+ break;
+
+ case DataModelDataType.String:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.StringList:
+ return comboPropertyComponent;
+ case AdditionalMetaDataType.MultiLine:
+ return multiLineComponent;
+ case AdditionalMetaDataType.Font:
+ return comboPropertyComponent;
+ case AdditionalMetaDataType.Import:
+ case AdditionalMetaDataType.Renderable:
+ case AdditionalMetaDataType.String:
+ return genericTextComponent;
+ default:
+ console.warn("KDAB_TODO implement property handler for additional type: ",
+ actionProperty.additionalType)
+ return null;
+ }
+ case DataModelDataType.Bool:
+ return booleanComponent;
+ case DataModelDataType.None:
+ return null;
+ default: console.warn("KDAB_TODO implement property handler for type: ",
+ actionProperty.type)
+
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseSlider.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseSlider.qml
new file mode 100644
index 00000000..7019dff2
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseSlider.qml
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/*
+* Use for: Opacity, Edge Tesselation Value, Inner Tesselation Value ...
+* For the latter two set sliderMax to 64
+*/
+
+Row {
+ id: root
+
+ property real value: 0 // This is the value coming from backend
+ property alias desiredValue: slider.value // This is value adjusted by user
+ property alias sliderMin: slider.from
+ property alias sliderMax: slider.to
+ property real sliderDecimals: -1
+ property bool intSlider: false
+ property int decimalSlider: sliderDecimals >= 0 ? sliderDecimals
+ : Math.min(precision(slider.stepSize), 3)
+ property Item tabItem1: textField
+
+ signal previewValue // Indicates desiredValue contains a preview value
+ signal commitValue // Indicates desiredValue contains a final value to be committed
+
+ spacing: 5
+ width: _valueWidth
+
+ function doCommitValue() {
+ wheelCommitTimer.stop();
+ if (rateLimiter.running)
+ rateLimiter.stop();
+ textField.setTextFieldValue();
+ root.commitValue();
+ }
+
+ // get the number of decimals in a float/double
+ function precision(a) {
+ if (!isFinite(a)) return 0;
+ var e = 1, p = 0;
+ while (Math.round(a * e) / e !== a) { e *= 10; p++; }
+ return p;
+ }
+
+ onValueChanged: {
+ slider.value = value;
+ textField.setTextFieldValue();
+ }
+
+ Keys.onPressed: {
+ if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) {
+ event.accepted = true
+ var delta = 1.0;
+ if (intSlider) {
+ if (event.key === Qt.Key_Down)
+ delta = -delta;
+ slider.value = Number(slider.value + delta).toFixed(0);
+ } else {
+ if (event.modifiers === Qt.ControlModifier)
+ delta = 0.1;
+ else if (event.modifiers === Qt.ShiftModifier)
+ delta = 10.0;
+ if (event.key === Qt.Key_Down)
+ delta = -delta;
+ slider.value = Number(slider.value + delta).toFixed(doubleValidator.decimals);
+ }
+ wheelCommitTimer.stop();
+ if (!rateLimiter.running)
+ rateLimiter.start();
+ textField.setTextFieldValue();
+ }
+ }
+
+ Slider {
+ id: slider
+
+ leftPadding: 0
+
+ background: Rectangle {
+ x: slider.leftPadding
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ implicitWidth: _valueWidth - textField.width - 5
+ implicitHeight: 6
+ height: implicitHeight
+ radius: 2
+ color: _studioColor2
+ }
+ handle: Rectangle {
+ x: slider.leftPadding + slider.visualPosition * slider.availableWidth
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ implicitWidth: 6
+ implicitHeight: 12
+ color: _studioColor3
+ radius: 2
+ }
+
+ from: 0
+ to: 100
+ stepSize: root.intSlider ? 1 : sliderStepFromRange(slider.to, slider.from, 100)
+ snapMode: root.intSlider ? Slider.SnapAlways : Slider.NoSnap
+
+ function sliderStepFromRange(top, bottom, steps) {
+ return ((top - bottom) / steps);
+ }
+
+ onMoved: {
+ wheelCommitTimer.stop();
+ if (!rateLimiter.running)
+ rateLimiter.start();
+ textField.setTextFieldValue();
+ }
+
+ // onPressedChanged is triggered both mouse clicks and arrow keys, so adjusting with arrow
+ // keys will create undo point for each tick slider moves (even when holding the key down)
+ onPressedChanged: {
+ if (!pressed)
+ root.doCommitValue();
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+
+ onWheel: {
+ var delta = (wheel.angleDelta.x != 0) ? wheel.angleDelta.x
+ : wheel.angleDelta.y;
+
+ if (delta > 0)
+ slider.increase();
+ else
+ slider.decrease();
+ if (!rateLimiter.running)
+ rateLimiter.start();
+ textField.setTextFieldValue();
+
+ // Leaving a transaction open can interfere with other editor functionality,
+ // so commit the wheel transaction after a brief delay
+ wheelCommitTimer.restart();
+ }
+ Timer {
+ id: wheelCommitTimer
+ interval: 1000
+ onTriggered: {
+ root.doCommitValue();
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: rateLimiter
+ interval: 10
+ onTriggered: {
+ root.previewValue();
+ }
+ }
+
+ DoubleValidator {
+ id: doubleValidator
+
+ decimals: decimalSlider
+ bottom: slider.from
+ top: slider.to
+ locale: "C"
+ }
+
+ IntValidator {
+ id: intValidator
+
+ bottom: slider.from
+ top: slider.to
+ }
+
+ StyledTextField {
+ id: textField
+
+ height: _controlBaseHeight
+ width: 55
+ text: intSlider ? slider.value.toFixed(0) : slider.value.toFixed(decimalSlider)
+
+ validator: intSlider ? intValidator : doubleValidator
+
+ onTextEdited: {
+ if (!intSlider && text.search(",")) {
+ text = text.replace(",",".")
+ }
+ if (intSlider) {
+ // handle limiting integer values when entered value is less than
+ // minimum value since IntValidator doesn't handle this
+ if (text.length >= sliderMin.toString().length && text < sliderMin)
+ text = text.substring(0, text.length - 1)
+ }
+ }
+
+ onEditingFinished: {
+ if (text > sliderMax)
+ text = sliderMax
+ else if (text < sliderMin)
+ text = sliderMin
+ slider.value = text
+ root.doCommitValue();
+ }
+
+ function setTextFieldValue() {
+ text = intSlider ? slider.value.toFixed(0) : slider.value.toFixed(decimalSlider)
+ }
+ onActiveFocusChanged: {
+ if (!activeFocus)
+ setTextFieldValue()
+ }
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXY.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXY.qml
new file mode 100644
index 00000000..4406703f
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXY.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+// Used for: Tiling
+
+RowLayout {
+ id: root
+
+ property alias valueX: textFieldX.text
+ property alias valueY: textFieldY.text
+ property int numberOfDecimal: 3
+ property Item tabItem1: textFieldX
+ property Item tabItem2: textFieldY
+
+ signal editingFinished
+ signal previewValueChanged
+
+ spacing: 0
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("X")
+ color: _xAxisColor
+ }
+
+ FloatTextField {
+ id: textFieldX
+ Layout.preferredWidth: (_valueWidth - 40) / 2
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+
+ Item { width: 20 }
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("Y")
+ color: _yAxisColor
+ }
+
+ FloatTextField {
+ id: textFieldY
+ Layout.preferredWidth: (_valueWidth - 40) / 2
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXYZ.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXYZ.qml
new file mode 100644
index 00000000..50440dba
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyBaseXYZ.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for: Position, Rotation, Scale, Pivot ... */
+
+RowLayout {
+ id: root
+
+ property alias valueX: textFieldX.text
+ property alias valueY: textFieldY.text
+ property alias valueZ: textFieldZ.text
+ property int numberOfDecimal: 3
+ property Item tabItem1: textFieldX
+ property Item tabItem2: textFieldY
+ property Item tabItem3: textFieldZ
+
+ signal editingFinished
+ signal previewValueChanged
+ transformOrigin: Item.Center
+ spacing: 0
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("X")
+ color: _xAxisColor
+ }
+
+ FloatTextField {
+ id: textFieldX
+ Layout.preferredWidth: (_valueWidth - 50) / 3
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+
+ Item { width: 10 }
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("Y")
+ color: _yAxisColor
+ }
+
+ FloatTextField {
+ id: textFieldY
+ Layout.preferredWidth: (_valueWidth - 50) / 3
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+
+ Item { width: 10 }
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("Z")
+ color: _zAxisColor
+ }
+
+ FloatTextField {
+ id: textFieldZ
+ Layout.preferredWidth: (_valueWidth - 50) / 3
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+}
+
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyCombo.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyCombo.qml
new file mode 100644
index 00000000..37e76aa9
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyCombo.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for Tesselation mode, Horizontal alignment, Vertical alignment ... */
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias comboModel : comboBox.model
+ property alias comboTextRole: comboBox.textRole
+ property alias currentIndex: comboBox.currentIndex
+ property string value
+
+ function find(text) {
+ return comboBox.find(text);
+ }
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("New Value")
+ }
+
+ StyledComboBox {
+ id: comboBox
+
+ Layout.fillWidth: true
+ onActivated: value = comboBox.textAt(currentIndex)
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertySlider.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertySlider.qml
new file mode 100644
index 00000000..db6f88f2
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertySlider.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/*
+* Use for: Opacity, Edge Tesselation Value, Inner Tesselation Value ...
+* For the latter two set sliderMax to 64
+*/
+
+GridLayout {
+ id: root
+
+ property alias value: propertySlider.value
+ property alias desiredValue: propertySlider.desiredValue
+ property alias sliderMin: propertySlider.sliderMin
+ property alias sliderMax: propertySlider.sliderMax
+ property alias label: labelItem.text
+ property alias intSlider: propertySlider.intSlider
+ property alias decimalSlider: propertySlider.decimalSlider
+ property alias tabItem1: propertySlider.tabItem1
+
+ signal previewValue
+ signal commitValue
+
+ columns: 3
+
+ StyledLabel {
+ id: labelItem
+ text: label
+ }
+
+ HandlerPropertyBaseSlider {
+ id: propertySlider
+ // proxy the signal upwards
+ onCommitValue: root.commitValue()
+ onPreviewValue: root.previewValue()
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyXYZ.qml b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyXYZ.qml
new file mode 100644
index 00000000..6571f1d0
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/HandlerPropertyXYZ.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for: Position, Rotation, Scale, Pivot ... */
+
+RowLayout {
+ id: root
+
+ property alias valueX: propertyXYZ.valueX
+ property alias valueY: propertyXYZ.valueY
+ property alias valueZ: propertyXYZ.valueZ
+ property alias label: labelItem.text
+ property alias tabItem1: propertyXYZ.tabItem1
+ property alias tabItem2: propertyXYZ.tabItem2
+ property alias tabItem3: propertyXYZ.tabItem3
+ property alias numberOfDecimal: propertyXYZ.numberOfDecimal
+
+ signal editingFinished
+ signal previewValueChanged
+
+ StyledLabel {
+ id: labelItem
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+ text: qsTr("New Value")
+ }
+
+ HandlerPropertyBaseXYZ {
+ id: propertyXYZ
+ Layout.alignment: Qt.AlignRight
+
+ onEditingFinished: root.editingFinished()
+ onPreviewValueChanged: root.previewValueChanged()
+ }
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.cpp b/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.cpp
new file mode 100644
index 00000000..8024204d
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "PropertyModel.h"
+
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+
+#include "Qt3DSDMActionCore.h"
+#include "Qt3DSDMActionInfo.h"
+#include "Qt3DSDMDataCore.h"
+#include "Qt3DSDMMetaData.h"
+#include "Qt3DSDMStudioSystem.h"
+
+
+PropertyModel::PropertyModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void PropertyModel::setAction(const qt3dsdm::Qt3DSDMActionHandle &action)
+{
+ beginResetModel();
+ m_action = action;
+ m_valueHandle = 0;
+ m_nameHandle = 0;
+ m_properties.clear();
+
+ if (action.Valid()) {
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ auto propertySystem = studioSystem->GetPropertySystem();
+ auto bridge = studioSystem->GetClientDataModelBridge();
+
+ auto actionInfo = studioSystem->GetActionCore()->GetActionInfo(action);
+
+ qt3dsdm::IMetaData &metaData(*studioSystem->GetActionMetaData());
+ qt3dsdm::TMetaDataPropertyHandleList metaProperties;
+ const auto instance = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+ if (instance.Valid()) {
+ metaData.GetMetaDataProperties(instance, metaProperties);
+
+ for (const auto &metaProperty: metaProperties) {
+ auto propertyMetaInfo = metaData.GetMetaDataPropertyInfo(metaProperty);
+ if (propertyMetaInfo->m_IsHidden == false) {
+ PropertyInfo property;
+ property.m_handle = propertyMetaInfo->m_Property;
+ property.m_name = QString::fromWCharArray(
+ propertySystem->GetFormalName(instance,
+ property.m_handle).wide_str());
+ property.m_nameId = QString::fromWCharArray(
+ propertySystem->GetName(property.m_handle).wide_str());
+ property.m_type = propertyMetaInfo->GetDataType();
+ property.m_additionalType = propertyMetaInfo->GetAdditionalType();
+
+ const auto additionalMetaDataType =
+ propertySystem->GetAdditionalMetaDataType(instance, property.m_handle);
+ switch (additionalMetaDataType) {
+ case qt3dsdm::AdditionalMetaDataType::Range: {
+ const qt3dsdm::TMetaDataData &metaDataData =
+ propertySystem->GetAdditionalMetaDataData(instance,
+ property.m_handle);
+ qt3dsdm::SMetaDataRange minMax =
+ qt3dsdm::get<qt3dsdm::SMetaDataRange>(metaDataData);
+ property.m_min = minMax.m_min;
+ property.m_max = minMax.m_max;
+ break;
+ }
+ case qt3dsdm::AdditionalMetaDataType::StringList: {
+ const qt3dsdm::TMetaDataData &metaDataData =
+ propertySystem->GetAdditionalMetaDataData(instance,
+ property.m_handle);
+ auto values = qt3dsdm::get<qt3dsdm::TMetaDataStringList>(metaDataData);
+ QStringList possibleValues;
+ for (const auto &value: values)
+ possibleValues.append(QString::fromWCharArray(value.wide_str()));
+ property.m_possibleValues = possibleValues;
+ break;
+ }
+ case qt3dsdm::AdditionalMetaDataType::Font: {
+ std::vector<QString> fontNames;
+ doc->GetProjectFonts(fontNames);
+ QStringList possibleValues;
+ for (const auto &fontName: fontNames)
+ possibleValues.append(fontName);
+ property.m_possibleValues = possibleValues;
+ break;
+ }
+ default:
+ break;
+ }
+ // Skip Name, we don't want to allow changing that
+ // TODO: To be localized when/if we add support for metadata localization
+ if (property.m_name != QLatin1String("Name"))
+ m_properties.append(property);
+ }
+ }
+ }
+ }
+ endResetModel();
+
+ Q_EMIT valueHandleChanged();
+}
+
+void PropertyModel::setNameHandle(const qt3dsdm::Qt3DSDMHandlerArgHandle &handle)
+{
+ m_nameHandle = handle;
+}
+
+void PropertyModel::setValueHandle(const qt3dsdm::Qt3DSDMHandlerArgHandle &handle)
+{
+ if (m_valueHandle != handle) {
+ m_valueHandle = handle;
+ updateDefaultPropertyIndex();
+ updateValue();
+ Q_EMIT valueHandleChanged();
+ }
+}
+
+int PropertyModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_properties.size();
+}
+
+
+QVariant PropertyModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto property = m_properties.at(index.row());
+
+ switch (role)
+ {
+ case NameRole:
+ return property.m_name;
+ case HandleRole:
+ return property.m_handle.GetHandleValue();
+ default:
+ return {};
+ }
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> PropertyModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(HandleRole, "handle");
+
+ return names;
+}
+
+PropertyInfo PropertyModel::property(int index) const
+{
+ if (index < 0 || index >= m_properties.size())
+ return {};
+ return m_properties[index];
+}
+
+int PropertyModel::valueHandle() const
+{
+ return m_valueHandle;
+}
+
+QVariant PropertyModel::value() const
+{
+ return m_value;
+}
+
+void PropertyModel::updateDefaultPropertyIndex()
+{
+ if (!m_nameHandle.Valid()) {
+ m_defaultPropertyIndex = -1;
+ Q_EMIT defaultPropertyIndexChanged();
+ return;
+ }
+
+ qt3dsdm::SValue sValue;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ studioSystem->GetActionCore()->GetHandlerArgumentValue(m_nameHandle, sValue);
+
+ if (sValue.getType() != qt3dsdm::DataModelDataType::String) {
+ m_defaultPropertyIndex = -1;
+ Q_EMIT defaultPropertyIndexChanged();
+ return;
+ }
+
+ auto propertyName = qt3dsdm::get<QString>(sValue);
+ auto iter = std::find_if(m_properties.constBegin(), m_properties.constEnd(),
+ [&propertyName](const PropertyInfo &info)
+ {
+ return (info.m_nameId == propertyName);
+ });
+
+ auto index = std::distance(m_properties.constBegin(), iter);
+
+ if (m_defaultPropertyIndex != index) {
+ m_defaultPropertyIndex = index;
+ Q_EMIT defaultPropertyIndexChanged();
+ }
+}
+
+int PropertyModel::defaultPropertyIndex() const
+{
+ return m_defaultPropertyIndex;
+}
+
+void PropertyModel::updateValue()
+{
+ const auto oldValue = m_value;
+ if (!m_valueHandle.Valid()) {
+ m_value.clear();
+ } else {
+ qt3dsdm::SValue sValue;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ studioSystem->GetActionCore()->GetHandlerArgumentValue(m_valueHandle, sValue);
+ m_value = sValue.toQVariant();
+ }
+ if (oldValue != m_value)
+ Q_EMIT valueChanged();
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.h b/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.h
new file mode 100644
index 00000000..a833752b
--- /dev/null
+++ b/src/Authoring/Qt3DStudio/Palettes/Action/PropertyModel.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 PROPERTYMODEL_H
+#define PROPERTYMODEL_H
+
+#include <QAbstractListModel>
+
+#include "Qt3DSDMHandles.h"
+#include "Qt3DSDMDataTypes.h"
+#include "Qt3DSDMMetaDataTypes.h"
+
+struct PropertyInfo {
+ Q_PROPERTY(QString name MEMBER m_name CONSTANT FINAL)
+ Q_PROPERTY(float min MEMBER m_min CONSTANT FINAL)
+ Q_PROPERTY(float max MEMBER m_max CONSTANT FINAL)
+ Q_PROPERTY(qt3dsdm::DataModelDataType::Value type MEMBER m_type CONSTANT FINAL)
+ Q_PROPERTY(qt3dsdm::AdditionalMetaDataType::Value additionalType MEMBER m_additionalType CONSTANT FINAL)
+ Q_PROPERTY(QStringList possibleValues MEMBER m_possibleValues CONSTANT FINAL)
+
+ qt3dsdm::Qt3DSDMPropertyHandle m_handle;
+ QString m_name;
+ QString m_nameId;
+ qt3dsdm::DataModelDataType::Value m_type;
+ qt3dsdm::AdditionalMetaDataType::Value m_additionalType;
+ QStringList m_possibleValues;
+ float m_min = 0.0f;
+ float m_max = 0.0f;
+
+ Q_GADGET
+};
+
+class PropertyModel : public QAbstractListModel
+{
+ Q_PROPERTY(int valueHandle READ valueHandle NOTIFY valueHandleChanged FINAL)
+ Q_PROPERTY(QVariant value READ value NOTIFY valueChanged FINAL)
+ Q_PROPERTY(int defaultPropertyIndex READ defaultPropertyIndex NOTIFY defaultPropertyIndexChanged FINAL)
+ Q_OBJECT
+
+public:
+ explicit PropertyModel(QObject *parent = nullptr);
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ HandleRole = Qt::UserRole + 1
+ };
+
+ void setAction(const qt3dsdm::Qt3DSDMActionHandle &action);
+ void setNameHandle(const qt3dsdm::Qt3DSDMHandlerArgHandle &valueHandle);
+ void setValueHandle(const qt3dsdm::Qt3DSDMHandlerArgHandle &valueHandle);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ PropertyInfo property(int index) const;
+ qt3dsdm::Qt3DSDMActionHandle action() const { return m_action; }
+ int valueHandle() const;
+
+ QVariant value() const;
+ int defaultPropertyIndex() const;
+
+Q_SIGNALS:
+ void valueHandleChanged();
+ void valueChanged();
+ void defaultPropertyIndexChanged();
+
+private:
+ void updateValue();
+ void updateDefaultPropertyIndex();
+
+ QVector<PropertyInfo> m_properties;
+ qt3dsdm::Qt3DSDMActionHandle m_action;
+ qt3dsdm::Qt3DSDMHandlerArgHandle m_nameHandle;
+ qt3dsdm::Qt3DSDMHandlerArgHandle m_valueHandle;
+ int m_defaultPropertyIndex = -1;
+ QVariant m_value;
+};
+
+Q_DECLARE_METATYPE(PropertyInfo)
+
+#endif // PROPERTYMODEL_H