diff options
Diffstat (limited to 'src/Authoring/Studio/Palettes')
263 files changed, 41225 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp new file mode 100644 index 00000000..d2957e8b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ActionContextMenu.h" +#include "StudioClipboard.h" + +//============================================================================== +/** + * Constructor + * + * @param inActionControl Owner Action Control (commonly known as the Action Palette) + *that will handle all cut/copy/paste/delete of Actions. + */ +CActionContextMenu::CActionContextMenu(QWidget *parent) + : QMenu(parent) +{ + QAction *action = new QAction(tr("Copy Action")); + connect(action, &QAction::triggered, this, &CActionContextMenu::copyAction); + addAction(action); + + action = new QAction(tr("Paste Action")); + action->setEnabled(CStudioClipboard::CanPasteAction()); + connect(action, &QAction::triggered, this, &CActionContextMenu::pasteAction); + addAction(action); + + action = new QAction(tr("Cut Action")); + connect(action, &QAction::triggered, this, &CActionContextMenu::cutAction); + addAction(action); + + action = new QAction(tr("Delete Action")); + connect(action, &QAction::triggered, this, &CActionContextMenu::deleteAction); + addAction(action); +} + +//============================================================================== +/** + * Destructor + */ +CActionContextMenu::~CActionContextMenu() +{ +} diff --git a/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h new file mode 100644 index 00000000..f413232d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_ACTION_CONTEXT_MENU_H +#define INCLUDED_ACTION_CONTEXT_MENU_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include <QMenu> + +//============================================================================== +/** + * Context menu that springs up on right mouseclick in the Action Palette. + */ +class CActionContextMenu : public QMenu +{ + Q_OBJECT +public: + explicit CActionContextMenu(QWidget *parent = nullptr); + virtual ~CActionContextMenu(); + +Q_SIGNALS: + void cutAction(); + void copyAction(); + void pasteAction(); + void deleteAction(); +}; +#endif // INCLUDED_ACTION_CONTEXT_MENU_H diff --git a/src/Authoring/Studio/Palettes/Action/ActionModel.cpp b/src/Authoring/Studio/Palettes/Action/ActionModel.cpp new file mode 100644 index 00000000..249aa636 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionModel.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** 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 "stdafx.h" +#include "ClientDataModelBridge.h" +#include "CmdDataModelActionSetValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "UICDMActionSystem.h" +#include "UICDMStudioSystem.h" + +ActionModel::ActionModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +void ActionModel::setInstanceHandle(const UICDM::CUICDMInstanceHandle &handle) +{ + beginResetModel(); + m_handle = handle; + auto doc = g_StudioApp.GetCore()->GetDoc(); + m_actions.clear(); + 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 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()); + switch (role) + { + case DescriptionRole: + return actionString(action); + case VisibleRole: + return actionSystem()->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 CUICDMActionHandle &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 CUICDMActionHandle &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 CUICDMActionHandle &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 CUICDMActionHandle 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); +} + +UICDM::IActionSystem *ActionModel::actionSystem() const +{ + return g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetActionSystem(); +} + +UICDM::CUICDMSlideHandle ActionModel::activeSlide() const +{ + return g_StudioApp.GetCore()->GetDoc()->GetActiveSlide(); +} + +QString ActionModel::actionString(const CUICDMActionHandle &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]")); + CUICDMEventHandle 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/Studio/Palettes/Action/ActionModel.h b/src/Authoring/Studio/Palettes/Action/ActionModel.h new file mode 100644 index 00000000..89a4586d --- /dev/null +++ b/src/Authoring/Studio/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 "UICDMActionInfo.h" +#include "UICDMHandles.h" + +namespace UICDM { + class IActionSystem; +} + +class ActionModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit ActionModel(QObject *parent = nullptr); + + void setInstanceHandle(const UICDM::CUICDMInstanceHandle &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 UICDM::CUICDMActionHandle &action); + void removeAction(const UICDM::CUICDMActionHandle &action); + void updateAction(const UICDM::CUICDMActionHandle &action); + const UICDM::CUICDMActionHandle actionAt(int row); + const UICDM::SActionInfo actionInfoAt(int row); + +private: + UICDM::IActionSystem *actionSystem() const; + UICDM::CUICDMSlideHandle activeSlide() const; + QString actionString(const UICDM::CUICDMActionHandle &action) const; + + UICDM::CUICDMInstanceHandle m_handle; + UICDM::TActionHandleList m_actions; +}; + +#endif // ACTIONMODEL_H diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.cpp b/src/Authoring/Studio/Palettes/Action/ActionView.cpp new file mode 100644 index 00000000..4aace20a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionView.cpp @@ -0,0 +1,848 @@ +/**************************************************************************** +** +** 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 "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 "UICFileTools.h" +#include "UICDMActionCore.h" +#include "UICDMDataTypes.h" +#include "UICDMSlides.h" + +#include <QCoreApplication> +#include <QQmlContext> +#include <QQmlEngine> +#include <QTimer> + +ActionView::ActionView(QWidget *parent) + : QQuickWidget(parent) + , TabNavigable() + , m_actionsModel(new ActionModel(this)) +{ + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &ActionView::initialize); + + g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this); + + connect(this, &ActionView::actionChanged, this, [this] { + if (!m_propertyModel) + m_propertyModel = new PropertyModel(this); + + const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex); + if (actionInfo.m_Handler == L"Set Property") { + 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); + + Q_EMIT propertyModelChanged(); + } + + }); + + m_actionChangedCompressionTimer.setInterval(500); + m_actionChangedCompressionTimer.setSingleShot(true); + connect(&m_actionChangedCompressionTimer, &QTimer::timeout, this, [this] { + updateHandlerArguments(); + updateFiredEvent(); + Q_EMIT actionChanged(); + }); +} + +ActionView::~ActionView() +{ + m_connections.clear(); +} + +QSize ActionView::sizeHint() const +{ + return {500, 500}; +} + +void ActionView::setItem(const UICDM::CUICDMInstanceHandle &handle) +{ + m_objRefHelper = GetDoc()->GetDataModelObjectReferenceHelper(); + m_itemHandle = handle; + m_actionsModel->setInstanceHandle(handle); + emitActionChanged(); + Q_EMIT itemChanged(); +} + +QString ActionView::itemIcon() const +{ + if (!m_itemHandle.Valid()) + return {}; + + 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()) + return {}; + + 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()) + return {}; + + 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()) + return {}; + + 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()) + return {}; + + 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); +} + +void ActionView::setCurrentActionIndex(int index) +{ + if (index == m_currentActionIndex) + return; + + m_currentActionIndex = index; + emitActionChanged(); +} + +void ActionView::setCurrentPropertyIndex(int handle, int index) +{ + if (index == m_currentPropertyIndex) + return; + + 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); + } + } + } + + m_currentPropertyIndex = index; + + // set the property for the handler + if (m_propertyModel && handle != 0) { + UICDM::SValue sValue(QVariant(m_propertyModel->property(index).m_nameId)); + UICDM::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(); +} + +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); + } +} + +void ActionView::deleteAction(int index) +{ + const auto action = m_actionsModel->actionAt(index); + if (action.Valid()) { + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Delete Action"))->DeleteAction(action); + } +} + +QObject *ActionView::showTriggerObjectBrowser(const QPoint &point) +{ + if (!m_objectsModel) { + m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(), + GetDoc()->GetActiveRootInstance(), this); + } + + if (!m_triggerObjectBrowser) + m_triggerObjectBrowser = new ObjectBrowserView(this); + + m_triggerObjectBrowser->setModel(m_objectsModel); + + showBrowser(m_triggerObjectBrowser, point); + + connect(m_triggerObjectBrowser, &ObjectBrowserView::selectionChanged, + this, [this] { + auto selectedItem = m_triggerObjectBrowser->selectedHandle(); + setTriggerObject(m_objRefHelper->GetAssetRefValue(selectedItem, + m_itemHandle, + (CRelativePathTools::EPathType)(m_triggerObjectBrowser->pathType()))); + }); + + return m_triggerObjectBrowser; +} + +QObject *ActionView::showTargetObjectBrowser(const QPoint &point) +{ + if (!m_objectsModel) { + m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(), + GetDoc()->GetActiveRootInstance(), this); + } + + if (!m_targetObjectBrowser) + m_targetObjectBrowser = new ObjectBrowserView(this); + + m_targetObjectBrowser->setModel(m_objectsModel); + + showBrowser(m_targetObjectBrowser, point); + + connect(m_targetObjectBrowser, &ObjectBrowserView::selectionChanged, + this, [this] { + auto selectedItem = m_targetObjectBrowser->selectedHandle(); + setTargetObject(m_objRefHelper->GetAssetRefValue(selectedItem, + m_itemHandle, + (CRelativePathTools::EPathType)(m_targetObjectBrowser->pathType()))); + resetFiredEvent(); + }); + + return m_targetObjectBrowser; +} + +void ActionView::showContextMenu(int x, int y) +{ + CActionContextMenu contextMenu(this); + + connect(&contextMenu, &CActionContextMenu::copyAction, this, &ActionView::copyAction); + connect(&contextMenu, &CActionContextMenu::pasteAction, this, &ActionView::pasteAction); + connect(&contextMenu, &CActionContextMenu::cutAction, this, &ActionView::cutAction); + connect(&contextMenu, &CActionContextMenu::deleteAction, this, [this] { + deleteAction(m_currentActionIndex); + }); + + contextMenu.exec(mapToGlobal({x, y})); +} + +QObject *ActionView::showEventBrowser(const QPoint &point) +{ + 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); + } + + UICDM::TEventHandleList eventList; + bridge->GetEvents(instanceHandle, eventList); + m_eventsModel->setEventList(eventList); + + if (!m_eventsBrowser) + m_eventsBrowser = new EventsBrowserView(this); + + m_eventsBrowser->setModel(m_eventsModel); + + showBrowser(m_eventsBrowser, point); + + connect(m_eventsBrowser, &EventsBrowserView::selectionChanged, + this, [this] { + setEvent(UICDM::CUICDMEventHandle(m_eventsBrowser->selectedHandle())); + }); + + return m_eventsBrowser; +} + +QObject *ActionView::showHandlerBrowser(const QPoint &point) +{ + 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); + } + + UICDM::THandlerHandleList handlerList; + bridge->GetHandlers(instanceHandle, handlerList); + m_handlersModel->setHandlerList(handlerList); + + if (!m_handlerBrowser) + m_handlerBrowser = new EventsBrowserView(this); + + m_handlerBrowser->setModel(m_handlersModel); + + showBrowser(m_handlerBrowser, point); + + connect(m_handlerBrowser, &EventsBrowserView::selectionChanged, + this, [this] { + setHandler(UICDM::CUICDMHandlerHandle(m_handlerBrowser->selectedHandle())); + }); + + return m_handlerBrowser; +} + +QObject *ActionView::showEventBrowserForArgument(int handle, const QPoint &point) +{ + 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); + } + + UICDM::TEventHandleList eventList; + bridge->GetEvents(instanceHandle, eventList); + m_fireEventsModel->setEventList(eventList); + + if (!m_fireEventsBrowser) + m_fireEventsBrowser = new EventsBrowserView(this); + + m_fireEventsBrowser->setModel(m_fireEventsModel); + + showBrowser(m_fireEventsBrowser, point); + + connect(m_fireEventsBrowser, &EventsBrowserView::selectionChanged, + this, [this, handle] { + setArgumentValue(handle, UICDM::CUICDMEventHandle(m_fireEventsBrowser->selectedHandle()).GetHandleValue()); + }); + + return m_fireEventsBrowser; +} + +void ActionView::showBrowser(QQuickWidget *browser, const QPoint &point) +{ + QSize popupSize = CStudioPreferences::browserPopupSize(); + browser->disconnect(); + browser->resize(popupSize); + browser->move(point - QPoint(popupSize.width(), popupSize.height())); + + // Show asynchronously to avoid flashing blank window on first show + QTimer::singleShot(0, this, [browser] { + browser->show(); + browser->activateWindow(); + browser->setFocus(); + }); +} + +void ActionView::updateFiredEvent() +{ + 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 + UICDM::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))); + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + m_connections.push_back(theDispatch->ConnectSelectionChange( + std::bind(&ActionView::OnSelectionSet, this, + std::placeholders::_1))); +} + +void ActionView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable) +{ + UICDM::CUICDMInstanceHandle theInstance; + std::vector<UICDM::CUICDMInstanceHandle> instances; + + switch (inSelectable.getType()) { + case Q3DStudio::SelectedValueTypes::Instance: + theInstance = inSelectable.getData<UICDM::CUICDMInstanceHandle>(); + break; + case Q3DStudio::SelectedValueTypes::MultipleInstances: + instances = inSelectable.getData<std::vector<UICDM::CUICDMInstanceHandle>>(); + // handling only if we have one selected element. + if (instances.size() == 1) + theInstance = instances[0]; + break; + case Q3DStudio::SelectedValueTypes::Slide: { + UICDM::CUICDMSlideHandle theSlideHandle = + inSelectable.getData<Q3DStudio::SSlideInstanceWrapper>().m_Slide; + // Get the owning component instance + CClientDataModelBridge *theBridge = GetBridge(); + UICDM::SLong4 theComponentGuid = theBridge->GetComponentGuid(theSlideHandle); + Q_ASSERT(GuidValid(theComponentGuid)); + theInstance = theBridge->GetInstanceByGUID(theComponentGuid); + Q_ASSERT(theInstance.Valid()); + } break; + }; + + setItem(theInstance); +} + +void ActionView::OnActionAdded(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, UICDM::CUICDMInstanceHandle inOwner) +{ + CDoc *theDoc = GetDoc(); + UICDM::CStudioSystem *theStudioSystem = theDoc->GetStudioSystem(); + + UICDM::CUICDMSlideHandle theCurrentSlide = theDoc->GetActiveSlide(); + UICDM::CUICDMSlideHandle theMasterSlideOfAction = + theStudioSystem->GetSlideSystem()->GetMasterSlide(inSlide); + UICDM::CUICDMSlideHandle theMasterOfCurrentSlide = + theStudioSystem->GetSlideSystem()->GetMasterSlide(theCurrentSlide); + + 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); +// KDAB_TODO SortActions(); + } +} + +void ActionView::OnActionDeleted(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, UICDM::CUICDMInstanceHandle inOwner) +{ + Q_UNUSED(inSlide); + Q_UNUSED(inOwner); + m_actionsModel->removeAction(inAction); +} + +void ActionView::OnActionModified(UICDM::CUICDMActionHandle inAction) +{ + if (GetDoc()->GetStudioSystem()->GetActionCore()->HandleValid(inAction)) { + m_actionsModel->updateAction(inAction); + emitActionChanged(); + } +} + +void ActionView::OnHandlerArgumentModified(UICDM::CUICDMHandlerArgHandle inHandlerArgument) +{ + emitActionChanged(); +} + +void ActionView::OnInstancePropertyValueChanged(UICDM::CUICDMInstanceHandle inInstance, UICDM::CUICDMPropertyHandle inProperty) +{ + emitActionChanged(); +} + +void ActionView::copyAction() +{ + auto theTempAPFile = + GetDoc()->GetDocumentReader().CopyAction(m_actionsModel->actionAt(m_currentActionIndex), + GetDoc()->GetActiveSlide()); + CUICFile theFile(theTempAPFile); + CStudioClipboard::CopyActionToClipboard(theFile); +} + +void ActionView::cutAction() +{ + copyAction(); + auto action = m_actionsModel->actionAt(m_currentActionIndex); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Cut Action"))->DeleteAction(action); +} + +void ActionView::pasteAction() +{ + CUICFile theTempAPFile = CStudioClipboard::GetActionFromClipboard(); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Paste Action")) + ->PasteAction(theTempAPFile.GetAbsolutePath(), m_itemHandle); +} + +void ActionView::setTriggerObject(const UICDM::SObjectRefType &object) +{ + auto action = m_actionsModel->actionAt(m_currentActionIndex); + if (!action.Valid()) + return; + + auto core = g_StudioApp.GetCore(); + auto theBridge = GetBridge(); + + auto theCmd = new CCmdDataModelActionSetTriggerObject(GetDoc(), action, object); + const SActionInfo &theActionInfo = GetDoc()->GetStudioSystem()->GetActionCore()->GetActionInfo(action); + + CUICDMInstanceHandle theBaseInstance = theActionInfo.m_Owner; + CUICDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object); + CUICDMInstanceHandle 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 UICDM::SObjectRefType &object) +{ + auto action = m_actionsModel->actionAt(m_currentActionIndex); + if (!action.Valid()) + return; + + 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); + + CUICDMInstanceHandle theBaseInstance = theActionInfo.m_Owner; + CUICDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object); + CUICDMInstanceHandle 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 CUICDMEventHandle &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 CUICDMHandlerHandle &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 +{ + UICDM::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()) + 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 (handle == 0) + return; + + UICDM::SValue sValue(value); + UICDM::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("_actionView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + rootContext()->setContextProperty("_tabOrderHandler"_L1, tabOrderHandler()); + qmlRegisterUncreatableType<UICDM::HandlerArgumentType>("Qt3DStudio", 1, 0, "HandlerArgumentType", + "HandlerArgumentType is an enum container"_L1); + qmlRegisterUncreatableType<UICDM::DataModelDataType>("Qt3DStudio", 1, 0, "DataModelDataType", + "DataModelDataType is an enum container"_L1); + qmlRegisterUncreatableType<UICDM::AdditionalMetaDataType>("Qt3DStudio", 1, 0, "AdditionalMetaDataType", + "AdditionalMetaDataType is an enum container"_L1); + qmlRegisterUncreatableType<PropertyInfo>("Qt3DStudio", 1, 0, "PropertyInfo", + "PropertyInfo is anot creatable in QML"_L1); + qmlRegisterUncreatableType<UICDM::CompleteMetaDataType>("Qt3DStudio", 1, 0, "CompleteMetaDataType", + "CompleteMetaDataType is an enum container"_L1); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Action/ActionView.qml"_L1)); +} + +QStringList ActionView::slideNames() +{ + 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); +} diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.h b/src/Authoring/Studio/Palettes/Action/ActionView.h new file mode 100644 index 00000000..dec7b078 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionView.h @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** 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 <QQuickWidget> +#include <QColor> +#include <QPointer> +#include <QTimer> + +#include "stdafx.h" +#include "DispatchListeners.h" +#include "EventsBrowserView.h" +#include "EventsModel.h" +#include "ObjectBrowserView.h" +#include "ObjectListModel.h" +#include "PropertyModel.h" +#include "SelectedValueImpl.h" +#include "UICDMHandles.h" +#include "UICDMSignals.h" +#include "UICDMStudioSystem.h" +#include "UICDMMetaDataTypes.h" +#include "TabOrderHandler.h" + +class ActionModel; +class CClientDataModelBridge; +class CCore; +class CDoc; +class IObjectReferenceHelper; + +class QAbstractItemModel; + +struct HandlerArgument { + Q_PROPERTY(UICDM::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(UICDM::CompleteMetaDataType::Enum completeType MEMBER m_completeType FINAL) + + UICDM::CUICDMHandlerArgHandle m_handle; + UICDM::HandlerArgumentType::Value m_type; + UICDM::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 itemChanged FINAL) + Q_PROPERTY(QColor itemColor READ itemColor NOTIFY itemChanged 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) + +public: + ActionView(QWidget *parent = nullptr); + ~ActionView(); + + QSize sizeHint() const override; + + void setItem(const UICDM::CUICDMInstanceHandle &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; + + 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); + + + // CPresentationChangeListener + void OnNewPresentation() override; + + // ISelectionChangeListener + void OnSelectionSet(Q3DStudio::SSelectedValue inSelectable); + + // Action callback + void OnActionAdded(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inOwner); + void OnActionDeleted(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inOwner); + void OnActionModified(UICDM::CUICDMActionHandle inAction); + void OnHandlerArgumentModified(UICDM::CUICDMHandlerArgHandle inHandlerArgument); + void OnInstancePropertyValueChanged(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + +Q_SIGNALS: + void itemChanged(); + void actionChanged(); + void propertyModelChanged(); + void propertyChanged(); + void firedEventChanged(); + +private Q_SLOTS: + void copyAction(); + void cutAction(); + void pasteAction(); + +private: + void setTriggerObject(const UICDM::SObjectRefType &object); + void setTargetObject(const UICDM::SObjectRefType &object); + void setEvent(const UICDM::CUICDMEventHandle &event); + void setHandler(const UICDM::CUICDMHandlerHandle &handler); + QVariant handlerArgumentValue(int handle) const; + void updateHandlerArguments(); + void emitActionChanged(); + void updateFiredEvent(); + void resetFiredEvent(); + void updateFiredEventFromHandle(int handle); + void showBrowser(QQuickWidget *browser, const QPoint &point); + + static CDoc *GetDoc(); + static CClientDataModelBridge *GetBridge(); + + void initialize(); + QColor m_baseColor = QColor::fromRgb(75, 75, 75); + QColor m_selectColor = Qt::transparent; + UICDM::CUICDMInstanceHandle m_itemHandle; + IObjectReferenceHelper *m_objRefHelper = nullptr; + ActionModel *m_actionsModel = nullptr; + PropertyModel *m_propertyModel = nullptr; + std::vector<std::shared_ptr<UICDM::ISignalConnection>> + m_connections; /// connections to the UICDM + 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; + UICDM::CUICDMHandlerArgHandle m_currentPropertyNameHandle; + UICDM::CUICDMHandlerArgHandle m_currentPropertyValueHandle; + QVariantList m_handlerArguments; + QTimer m_actionChangedCompressionTimer; + QString m_firedEvent; +}; + +#endif // ACTIONVIEW_H diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.qml b/src/Authoring/Studio/Palettes/Action/ActionView.qml new file mode 100644 index 00000000..c1debc3a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/ActionView.qml @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import Qt3DStudio 1.0 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + + Flickable { + id: actionFlickable + ScrollBar.vertical: ScrollBar { + id: scrollBar + visible: size < 1.0 + } + + 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 + anchors.margins * 2 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 4 + anchors.rightMargin: 12 + + Image { + id: headerImage + source: _actionView.itemIcon !== "" ? _resDir + _actionView.itemIcon : "" + } + + StyledLabel { + Layout.fillWidth: true + text: _actionView.itemText + color: _actionView.itemColor + } + + StyledToolButton { + enabled: actionsList.currentIndex !== -1 + enabledImage: "Action-Trash-Normal.png" + disabledImage: "Action-Trash-Disabled.png" + toolTipText: qsTr("Delete selected action") + + onClicked: _actionView.deleteAction(actionsList.currentIndex) + } + + StyledToolButton { + enabledImage: "add.png" + toolTipText: qsTr("Add new action") + + onClicked: _actionView.addAction() + } + } + ListView { + id: actionsList + width: parent.width + height: count * _controlBaseHeight + clip: true + + boundsBehavior: Flickable.StopAtBounds + model: _actionView.actionsModel + + delegate: Rectangle { + id: delegateItem + + 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 + + onClicked: { + actionFlickable.scrollToBottom = false; + actionsList.currentIndex = model.index; + _actionView.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) + _actionView.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: _actionView.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: _actionView.triggerObjectName + onShowBrowser: activeBrowser = _actionView.showTriggerObjectBrowser( + mapToGlobal(width, 0)); + } + } + + RowLayout { + x: 12 + StyledLabel { + text: qsTr("Event") + } + BrowserCombo { + value: _actionView.eventName + onShowBrowser: activeBrowser = _actionView.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: _actionView.targetObjectName + onShowBrowser: activeBrowser = _actionView.showTargetObjectBrowser( + mapToGlobal(width, 0)) + } + } + + RowLayout { + x: 12 + StyledLabel { + text: qsTr("Handler") + } + + BrowserCombo { + value: _actionView.handlerName + onShowBrowser: activeBrowser = _actionView.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) + _actionView.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) + _actionView.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) + _actionView.setArgumentValue(parent.argument.handle, value); + } + } + } + + Component { + id: eventHandlerComponent + + HandlerFireEvent { + label: parent && parent.argument.name ? parent.argument.name : "" + value: _actionView.firedEvent === "" ? qsTr("[Unknown Event]") + : _actionView.firedEvent + + onShowBrowser: { + if (parent && parent.argument.handle) { + activeBrowser = _actionView.showEventBrowserForArgument( + parent.argument.handle, mapToGlobal(width, 0)) + } + } + } + } + + Component { + id: slideHandlerComponent + + HandlerGoToSlide { + slideModel: _actionView.slideNames() + defaultSlideIndex: parent && parent.argument.value ? _actionView.slideNameToIndex(parent.argument.value) + : 0 + + onIndexChanged: { + if (parent && parent.argument.handle && currentSlide) + _actionView.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) + _actionView.setArgumentValue(parent.argument.handle, !checked) + } + } + } + + Component { + id: propertyHandlerComponent + + HandlerProperty { + propertyModel: _actionView.propertyModel + defaultPropertyIndex: propertyModel ? propertyModel.defaultPropertyIndex : 0 + + onPropertySelected: { + if (parent && parent.argument.handle) + _actionView.setCurrentPropertyIndex(parent.argument.handle, index); + } + } + } + + Repeater { + model: _actionView.handlerArguments.length + + Loader { + x: 12 + + readonly property var argument:_actionView.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/Studio/Palettes/Action/EventsBrowser.qml b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml new file mode 100644 index 00000000..63973ec7 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + ListView { + id: eventsList + + Layout.margins: 10 + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 80 + Layout.preferredHeight: count * 20 + Layout.preferredWidth: root.width + + ScrollBar.vertical: ScrollBar {} + + boundsBehavior: Flickable.StopAtBounds + clip: true + + model: _eventsBrowserView.model + + delegate: Item { + id: delegateItem + + readonly property bool isCategory: model.isCategory + + x: isCategory ? 0 : 50 + width: parent.width + height: model.parentExpanded ? 30 : 0 + visible: height > 0 + + Behavior on height { + NumberAnimation { + duration: 100 + easing.type: Easing.OutQuad + } + } + + Row { + id: row + + height: categoryIcon.height + spacing: 5 + + Image { + source: { + if (!delegateItem.isCategory) + return ""; + model.expanded ? _resDir + "arrow_down.png" + : _resDir + "arrow.png"; + } + + MouseArea { + anchors.fill: parent + onClicked: model.expanded = !model.expanded + } + } + + Rectangle { + height: name.height + width: categoryIcon.width + name.width + 10 + + color: model.index === eventsList.currentIndex ? _selectionColor + : "transparent" + + Row { + id: textRow + + spacing: 10 + Image { + id: categoryIcon + + source: model.icon + } + + StyledLabel { + id: name + anchors.verticalCenter: textRow.verticalCenter + text: model.name + } + } + + MouseArea { + id: delegateArea + + anchors.fill: parent + hoverEnabled: true + onClicked: eventsList.currentIndex = model.index + onEntered: itemDescription.text = model.description + onExited: itemDescription.text = "" + onDoubleClicked: { + eventsList.currentIndex = model.index; + _eventsBrowserView.close(); + } + } + } + } + + } + onCurrentIndexChanged: _eventsBrowserView.selection = currentIndex + } + + 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/Studio/Palettes/Action/EventsBrowserView.cpp b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp new file mode 100644 index 00000000..047a7b82 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 "CColor.h" +#include "EventsModel.h" +#include "Literals.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(); + } +} + +QSize EventsBrowserView::sizeHint() const +{ + return {500, 500}; +} + +UICDM::CDataModelHandle EventsBrowserView::selectedHandle() const +{ + const auto handleId = m_model->handleForRow(m_selection); + return handleId; +} + +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::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_eventsBrowserView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, + resourceImageUrl()); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Action/EventsBrowser.qml"_L1)); +} + diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h new file mode 100644 index 00000000..3902ca12 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 "UICDMHandles.h" + +class EventsModel; + +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); + QSize sizeHint() const override; + UICDM::CDataModelHandle selectedHandle() const; + + int selection() const { return m_selection; } + void setSelection(int index); + +Q_SIGNALS: + void modelChanged(); + void selectionChanged(); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void initialize(); + EventsModel *m_model = nullptr; + QColor m_baseColor = QColor::fromRgb(75, 75, 75); + QColor m_selectColor; + int m_selection = -1; +}; + +#endif // EVENTSBROWSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Action/EventsModel.cpp b/src/Authoring/Studio/Palettes/Action/EventsModel.cpp new file mode 100644 index 00000000..aa14ad81 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/EventsModel.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** 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 "UICDMStudioSystem.h" + +EventsModel::EventsModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +void EventsModel::setEventList(const UICDM::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) { + UICDM::SEventInfo theEvent = theBridge->GetEventInfo(*thePos); + + CategoryInfo category; + category.name = QString::fromWCharArray(theEvent.m_Category.wide_str()); + if (!m_events.contains(category.name)) { + UICDM::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 UICDM::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) { + UICDM::SHandlerInfo handlerInfo = theBridge->GetHandlerInfo(*thePos); + + CategoryInfo category; + category.name = QString::fromWCharArray(handlerInfo.m_Category.wide_str()); + if (!m_events.contains(category.name)) { + UICDM::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 ? resourceImageUrl() + category.icon : ""; + case HighlightedIconRole: + return isCategory ? resourceImageUrl() + category.highlightIcon : ""; + 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; +} + +UICDM::CDataModelHandle EventsModel::handleForRow(int row) const +{ + if (row < 0 || row >= m_rowCount) + return {}; + + auto event = eventForRow(row); + if (event.isValid()) + return event.handle; + + return {}; +} + +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/Studio/Palettes/Action/EventsModel.h b/src/Authoring/Studio/Palettes/Action/EventsModel.h new file mode 100644 index 00000000..ef458877 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/EventsModel.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 "UICDMHandles.h" + +/** Model for both action events and action handlers */ +class EventsModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit EventsModel(QObject *parent = nullptr); + + void setEventList(const UICDM::TEventHandleList &eventList); + void setHandlerList(const UICDM::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; + + UICDM::CDataModelHandle handleForRow(int row) const; + +private: + struct EventInfo { + UICDM::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/Studio/Palettes/Action/HandlerEmitSignal.qml b/src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml new file mode 100644 index 00000000..5917a9bd --- /dev/null +++ b/src/Authoring/Studio/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.1 +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/Studio/Palettes/Action/HandlerFireEvent.qml b/src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml new file mode 100644 index 00000000..e92d2265 --- /dev/null +++ b/src/Authoring/Studio/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.1 +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/Studio/Palettes/Action/HandlerGenericBaseColor.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml new file mode 100644 index 00000000..dbe097cb --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.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.1 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.3 + +RowLayout { + id: root + + property alias color: rect.color + property alias selectedColor: colorDialog.color + + signal colorSelected() + + Rectangle { + id: rect + + width: _valueWidth / 4 + height: _controlBaseHeight + + border { + width: 1 + color: _studioColor2 + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + onClicked: colorDialog.open() + } + + Image { + id: img + x: parent.width - sourceSize.width - 3 + y: (parent.height - sourceSize.height) / 2 + source: _resDir + "arrow_down.png" + } + } + + + Item { + Layout.fillWidth: true + } + + ColorDialog { + id: colorDialog + + color: rect.color + + onAccepted: root.colorSelected() + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml new file mode 100644 index 00000000..4b3b0ba4 --- /dev/null +++ b/src/Authoring/Studio/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.1 +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/Studio/Palettes/Action/HandlerGenericColor.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml new file mode 100644 index 00000000..378aa7b0 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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.1 +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() + + StyledLabel { + id: labelField + text: qsTr("New Value") + } + + HandlerGenericBaseColor { + id: handlerGenericColor + + onColorSelected: root.colorSelected(); + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml new file mode 100644 index 00000000..e33e170f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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.1 +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() + + StyledLabel { + id: labelField + text: qsTr("Argument") + } + + StyledTextField { + id: textField + onEditingFinished: root.editingFinished() + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml b/src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml new file mode 100644 index 00000000..ef76dfcb --- /dev/null +++ b/src/Authoring/Studio/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.1 +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 indexChanged() + + onDefaultSlideIndexChanged: comboSlide.currentIndex = defaultSlideIndex + + StyledLabel { + id: labelField + text: qsTr("Slide") + } + + StyledComboBox { + id: comboSlide + Layout.preferredWidth: _valueWidth + model: slideModel + + onCurrentIndexChanged: { + currentSlide = comboSlide.textAt(currentIndex); + indexChanged(); + } + } +} + diff --git a/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml b/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml new file mode 100644 index 00000000..2c7704a4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +RowLayout { + id: root + + property alias label: labelField.text + property alias value: textArea.text + property Item tabItem1: textArea + + signal editingFinished() + + StyledLabel { + id: labelField + text: qsTr("Argument") + } + + Flickable { + Layout.preferredWidth: _valueWidth + Layout.preferredHeight: textArea.height + + ScrollBar.vertical: ScrollBar {} + + TextArea.flickable: TextArea { + id: textArea + + horizontalAlignment: TextInput.AlignLeft + verticalAlignment: TextInput.AlignVCenter + implicitWidth: _valueWidth + font.pixelSize: _fontSize + color: _textColor + + topPadding: 6 + bottomPadding: 6 + rightPadding: 6 + + wrapMode: TextArea.Wrap + background: Rectangle { + color: textArea.enabled ? _studioColor2 : "transparent" + border.width: textArea.activeFocus ? 1 : 0 + border.color: textArea.activeFocus ? _selectionColor : _disabledColor + } + + onEditingFinished: root.editingFinished() + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + onPressed: parent.forceActiveFocus() + } + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml b/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml new file mode 100644 index 00000000..52d6265a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml @@ -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$ +** +****************************************************************************/ + +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" + onCurrentIndexChanged: root.propertySelected(currentIndex) + onModelChanged: currentIndex = root.defaultPropertyIndex + } + } + + Component { + id: multiLineComponent + + HandlerMultilineText { + readonly property var actionProperty: parent ? _actionView.property : null + + label: parent ? parent.label : "" + value: propertyModel && actionProperty && actionProperty.type === DataModelDataType.String + ? propertyModel.value : "" + onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value) + } + } + + Component { + id: fontSizeComponent + + HandlerPropertyCombo { + readonly property var actionProperty: parent ? _actionView.property : null + + label: parent ? parent.label : "" + comboModel: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72", "96", "120"]; + + onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value) + } + } + + Component { + id: xyzPropertyComponent + + HandlerPropertyXYZ { + readonly property var propValue: propertyModel && propertyModel.value.x ? + propertyModel.value + : undefined + label: parent ? parent.label : "" + valueX: propValue !== undefined ? propValue.x : 0 + valueY: propValue !== undefined ? propValue.y : 0 + valueZ: propValue !== undefined ? propValue.z : 0 + + onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, + Qt.vector3d(valueX, valueY, valueZ)) + } + } + + Component { + id: sliderPropertyComponent + + HandlerPropertySlider { + readonly property var actionProperty: parent ? _actionView.property : null + + sliderMin: actionProperty ? actionProperty.min : 0 + sliderMax: actionProperty ? actionProperty.max : 100 + intSlider: actionProperty ? actionProperty.type === DataModelDataType.Long : false + value: propertyModel ? propertyModel.value : 0 + + label: parent ? parent.label : "" + + onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value) + } + } + + Component { + id: comboPropertyComponent + + HandlerPropertyCombo { + readonly property var actionProperty: parent ? _actionView.property : null + + label: parent ? parent.label : "" + comboModel: actionProperty ? actionProperty.possibleValues : null + + onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value) + + } + } + + Component { + id: booleanComponent + + HandlerGenericCheckbox { + label: parent ? parent.label : "" + checked: propertyModel ? propertyModel.value : false + + onClicked: { + _actionView.setArgumentValue(propertyModel.valueHandle, !checked) + } + } + } + + Component { + id: colorBox + + HandlerGenericColor { + readonly property var propValue: propertyModel ? propertyModel.value : undefined + + label: parent ? parent.label : "" + color: propValue ? Qt.rgba(propValue.x, propValue.y, propValue.z, 1) : "black" + onColorSelected: { + _actionView.setArgumentValue(propertyModel.valueHandle, selectedColor) + } + } + } + + Component { + id: genericTextComponent + + HandlerGenericText { + label: parent ? parent.label : "" + value: propertyModel ? propertyModel.value : "" + onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value) + } + } + + Component { + id: floatPropertyComponent + + HandlerGenericText { + label: parent ? parent.label : "" + value: propertyModel ? propertyModel.value : "" + validator: DoubleValidator { + decimals: 3 + notation: DoubleValidator.StandardNotation + } + + onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value) + } + } + + Loader { + readonly property string label: qsTr("New Value") + readonly property var actionProperty: _actionView.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; + case AdditionalMetaDataType.Color: + return colorBox; + default: + console.warn("KDAB_TODO implement property handler for additional typeDataModelDataType.Float3: ", actionProperty.additionalType); + return xyzPropertyComponent; + } + 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: + 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/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml new file mode 100644 index 00000000..8fcf3511 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** 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.1 +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 alias value: slider.value + property int intValue: slider.value + property alias sliderMin: slider.from + property alias sliderMax: slider.to + property bool intSlider: false + property int decimalSlider: 3 + property Item tabItem1: textField + + signal editingFinished + signal sliderMoved + signal editingStarted + + spacing: 5 + width: _valueWidth + + Slider { + id: slider + + leftPadding: 0 + + background: Rectangle { + x: slider.leftPadding + y: slider.topPadding + slider.availableHeight / 2 - height / 2 + implicitWidth: _valueWidth / 2 - 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: 2 + + onMoved: { + if (!rateLimiter.running) { + rateLimiter.start(); + } + } + + onPressedChanged: { + if (pressed) + root.editingStarted(); + else + root.editingFinished(); + } + + 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(); + } + } + } + } + + Timer { + id: rateLimiter + interval: 50 + onTriggered: { + root.sliderMoved(); + } + } + + 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: _valueWidth / 2 + text: intSlider ? slider.value.toFixed(0) : slider.value.toFixed(decimalSlider) + + validator: intSlider ? intValidator : doubleValidator + + onActiveFocusChanged: { + if (activeFocus) + root.editingStarted(); + } + + onEditingFinished: { + if (textField.text > sliderMax) + textField.text = sliderMax + else if (textField.text < sliderMin) + textField.text = sliderMin + slider.value = textField.text + root.editingFinished() + } + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml new file mode 100644 index 00000000..fcabf271 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +/* Use for: Position, Rotation, Scale, Pivot ... */ + +GridLayout { + 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 + + columns: 2 + rowSpacing: 1 + + signal editingFinished + + StyledLabel { + Layout.preferredWidth: 10 + text: qsTr("X") + } + + FloatTextField { + id: textFieldX + + decimalValue: numberOfDecimal + onEditingFinished: root.editingFinished() + onWheelEventFinished: root.editingFinished() + } + + StyledLabel { + Layout.preferredWidth: 10 + text: qsTr("Y") + } + + FloatTextField { + id: textFieldY + + decimalValue: numberOfDecimal + onEditingFinished: root.editingFinished() + onWheelEventFinished: root.editingFinished() + } + + StyledLabel { + Layout.preferredWidth: 10 + text: qsTr("Z") + } + + FloatTextField { + id: textFieldZ + + decimalValue: numberOfDecimal + onEditingFinished: root.editingFinished() + onWheelEventFinished: root.editingFinished() + } +} + diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml new file mode 100644 index 00000000..1e60cf44 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.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.1 +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 string value + + StyledLabel { + id: labelField + text: qsTr("New Value") + } + + StyledComboBox { + id: comboBox + + Layout.fillWidth: true + onCurrentIndexChanged: value = comboBox.textAt(currentIndex) + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml new file mode 100644 index 00000000..aecdcfd4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.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.1 +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 sliderMin: propertySlider.sliderMin + property alias sliderMax: propertySlider.sliderMax + property alias label: labelItem.text + property bool intSlider: propertySlider.intSlider + property int decimalSlider: propertySlider.decimalSlider + property alias tabItem1: propertySlider.tabItem1 + + signal editingFinished + + columns: 3 + + StyledLabel { + id: labelItem + text: label + } + + HandlerPropertyBaseSlider { + id: propertySlider + // proxy the signal upwards + onEditingFinished: root.editingFinished() + } +} diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml new file mode 100644 index 00000000..eef611ce --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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.1 +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 + + signal editingFinished + + StyledLabel { + id: labelItem + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + text: qsTr("New Value") + } + + HandlerPropertyBaseXYZ { + id: propertyXYZ + Layout.alignment: Qt.AlignRight + + onEditingFinished: { + root.editingFinished(); + } + } +} diff --git a/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp b/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp new file mode 100644 index 00000000..5ee896c8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp @@ -0,0 +1,219 @@ +#include "PropertyModel.h" + +#include "ClientDataModelBridge.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" + +#include "UICDMActionCore.h" +#include "UICDMActionInfo.h" +#include "UICDMDataCore.h" +#include "UICDMMetaData.h" +#include "UICDMStudioSystem.h" + + +PropertyModel::PropertyModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +void PropertyModel::setAction(const UICDM::CUICDMActionHandle &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); + + UICDM::IMetaData &metaData(*studioSystem->GetActionMetaData()); + UICDM::TMetaDataPropertyHandleList metaProperties; + const auto instance = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject); + 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 UICDM::AdditionalMetaDataType::Range: { + const UICDM::TMetaDataData &metaDataData = + propertySystem->GetAdditionalMetaDataData(instance, property.m_handle); + UICDM::SMetaDataRange minMax = UICDM::get<UICDM::SMetaDataRange>(metaDataData); + property.m_min = minMax.m_Min; + property.m_max = minMax.m_Max; + break; + } + case UICDM::AdditionalMetaDataType::StringList: { + const UICDM::TMetaDataData &metaDataData = + propertySystem->GetAdditionalMetaDataData(instance, property.m_handle); + auto values = UICDM::get<UICDM::TMetaDataStringList>(metaDataData); + QStringList possibleValues; + for (const auto &value: values) { + possibleValues.append(QString::fromWCharArray(value.wide_str())); + } + property.m_possibleValues = possibleValues; + break; + } + case UICDM::AdditionalMetaDataType::Font: { + std::vector<Q3DStudio::CString> fontNames; + doc->GetProjectFonts(fontNames); + QStringList possibleValues; + for (const auto &fontName: fontNames) { + possibleValues.append(fontName.toQString()); + } + property.m_possibleValues = possibleValues; + break; + } + default:; + } + m_properties.append(property); + } + } + } + endResetModel(); + + Q_EMIT valueHandleChanged(); +} + +void PropertyModel::setNameHandle(const UICDM::CUICDMHandlerArgHandle &handle) +{ + m_nameHandle = handle; +} + +void PropertyModel::setValueHandle(const UICDM::CUICDMHandlerArgHandle &handle) +{ + m_valueHandle = handle; + + updateDefaultPropertyIndex(); + updateValue(); + if (m_valueHandle != handle) + 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; + } + + UICDM::SValue sValue; + auto doc = g_StudioApp.GetCore()->GetDoc(); + auto studioSystem = doc->GetStudioSystem(); + studioSystem->GetActionCore()->GetHandlerArgumentValue(m_nameHandle, sValue); + + if (sValue.getType() != UICDM::DataModelDataType::String) { + m_defaultPropertyIndex = -1; + Q_EMIT defaultPropertyIndexChanged(); + return; + } + + auto propertyName = UICDM::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 { + UICDM::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/Studio/Palettes/Action/PropertyModel.h b/src/Authoring/Studio/Palettes/Action/PropertyModel.h new file mode 100644 index 00000000..293e682e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Action/PropertyModel.h @@ -0,0 +1,80 @@ +#ifndef PROPERTYMODEL_H +#define PROPERTYMODEL_H + +#include <QAbstractListModel> + +#include "UICDMHandles.h" +#include "UICDMDataTypes.h" +#include "UICDMMetaDataTypes.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(UICDM::DataModelDataType::Value type MEMBER m_type CONSTANT FINAL) + Q_PROPERTY(UICDM::AdditionalMetaDataType::Value additionalType MEMBER m_additionalType CONSTANT FINAL) + Q_PROPERTY(QStringList possibleValues MEMBER m_possibleValues CONSTANT FINAL) + + UICDM::CUICDMPropertyHandle m_handle; + QString m_name; + QString m_nameId; + UICDM::DataModelDataType::Value m_type; + UICDM::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 UICDM::CUICDMActionHandle &action); + void setNameHandle(const UICDM::CUICDMHandlerArgHandle &valueHandle); + void setValueHandle(const UICDM::CUICDMHandlerArgHandle &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; + UICDM::CUICDMActionHandle 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; + UICDM::CUICDMActionHandle m_action; + UICDM::CUICDMHandlerArgHandle m_nameHandle; + UICDM::CUICDMHandlerArgHandle m_valueHandle; + int m_defaultPropertyIndex = -1; + QVariant m_value; +}; + +Q_DECLARE_METATYPE(PropertyInfo) + +#endif // PROPERTYMODEL_H diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp new file mode 100644 index 00000000..9ceee2d2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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 "BasicObjectsModel.h" +#include "DropSource.h" +#include "Literals.h" +#include "StudioUtils.h" + +#include <QCoreApplication> +#include <QDataStream> +#include <QMimeData> + +BasicObjectsModel::BasicObjectsModel(QObject *parent) : QAbstractListModel(parent) +{ + initialize(); +} + +void BasicObjectsModel::initialize() +{ + m_ObjectItems = { + {tr("Rectangle"), "Asset-Rectangle-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_RECT}, + {tr("Sphere"), "Asset-Sphere-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_SPHERE}, + {tr("Cube"), "Asset-Cube-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_BOX}, + {tr("Cylinder"), "Asset-Cylinder-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_CYLINDER}, + {tr("Cone"), "Asset-Cone-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_CONE}, + {tr("Component"), "Asset-Component-Normal.png"_L1, OBJTYPE_COMPONENT, PRIMITIVETYPE_UNKNOWN}, + {tr("Group"), "Asset-Group-Normal.png"_L1, OBJTYPE_GROUP, PRIMITIVETYPE_UNKNOWN}, + {tr("Text"), "Asset-Text-Normal.png"_L1, OBJTYPE_TEXT, PRIMITIVETYPE_UNKNOWN}, + {tr("Layer"), "Asset-Layer-Normal.png"_L1, OBJTYPE_LAYER, PRIMITIVETYPE_UNKNOWN}, + {tr("Camera"), "Asset-Camera-Normal.png"_L1, OBJTYPE_CAMERA, PRIMITIVETYPE_UNKNOWN}, + {tr("Light"), "Asset-Light-Normal.png"_L1, OBJTYPE_LIGHT, PRIMITIVETYPE_UNKNOWN}, + {tr("Alias"), "Asset-Alias-Normal.png"_L1, OBJTYPE_ALIAS, PRIMITIVETYPE_UNKNOWN} + }; +} + +QVariant BasicObjectsModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return {}; + + const auto row = index.row(); + + switch (role) { + case NameRole: return m_ObjectItems.at(row).name(); + case IconRole: return resourceImageUrl() + + m_ObjectItems.at(row).icon(); + case ObjectTypeRole: return m_ObjectItems.at(row).objectType(); + case PrimitiveTypeRole: return m_ObjectItems.at(row).primitiveType(); + } + + return {}; +} + +int BasicObjectsModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return m_ObjectItems.count(); +} + +QHash<int, QByteArray> BasicObjectsModel::roleNames() const +{ + auto names = QAbstractListModel::roleNames(); + names.insert(NameRole, "name"); + names.insert(IconRole, "icon"); + + return names; +} + +Qt::ItemFlags BasicObjectsModel::flags(const QModelIndex &index) const { + if (index.isValid()) + return Qt::ItemIsDragEnabled; + + return QAbstractListModel::flags(index); +} + +QStringList BasicObjectsModel::mimeTypes() const +{ + return { m_MimeType }; +} + +QMimeData *BasicObjectsModel::mimeData(const QModelIndexList &indexes) const +{ + + const auto row = indexes.first().row(); // we support only one item for D&D + auto object = m_ObjectItems.at(row); + + auto *data = CDropSourceFactory::Create(object.GetFlavor(), &object); + return data; +} + +BasicObjectItem::~BasicObjectItem() +{ +} diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h new file mode 100644 index 00000000..ccaf07d6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 BASICOBJECTSMODEL_H +#define BASICOBJECTSMODEL_H + +#include <QAbstractListModel> + +#include "IDragable.h" +#include "StudioObjectTypes.h" + +class BasicObjectItem : public IDragable { + +public: + BasicObjectItem() {} + BasicObjectItem(const QString &name, const QString &icon, + EStudioObjectType objectType, EPrimitiveType primitiveType) + : m_name(name), m_icon(icon) + , m_objectType(objectType), m_primitiveType(primitiveType) + { } + + virtual ~BasicObjectItem(); + + QString name() const { return m_name; } + QString icon() const { return m_icon; } + + EStudioObjectType objectType() const { return m_objectType; } + EPrimitiveType primitiveType() const { return m_primitiveType; } + + void setName(const QString &name) { m_name = name; } + void setIcon(const QString &icon) { m_icon = icon; } + void setObjectType(EStudioObjectType type) { m_objectType = type; } + void setPrimitveType(EPrimitiveType type) { m_primitiveType = type; } + + long GetFlavor() const override {return EUIC_FLAVOR_BASIC_OBJECTS;} + +private: + QString m_name; + QString m_icon; + EStudioObjectType m_objectType; + EPrimitiveType m_primitiveType; +}; + +class BasicObjectsModel : public QAbstractListModel +{ + Q_OBJECT +public: + BasicObjectsModel(QObject *parent = nullptr); + + enum Roles { + NameRole = Qt::DisplayRole, + IconRole = Qt::DecorationRole, + ObjectTypeRole = Qt::UserRole + 1, + PrimitiveTypeRole + }; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QHash<int, QByteArray> roleNames() const override; + + Qt::ItemFlags flags(const QModelIndex &index) const override; + QStringList mimeTypes() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + +private: + void initialize(); + + QVector<BasicObjectItem> m_ObjectItems; + + const QString m_MimeType = QLatin1String("application/x-basic-object"); +}; + +#endif // BASICOBJECTSMODEL_H diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp new file mode 100644 index 00000000..6834352a --- /dev/null +++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 "BasicObjectsView.h" +#include "BasicObjectsModel.h" +#include "CColor.h" +#include "Literals.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qtimer.h> +#include <QtGui/qdrag.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +BasicObjectsView::BasicObjectsView(QWidget *parent) : QQuickWidget(parent) + , m_ObjectsModel(new BasicObjectsModel(this)) + +{ + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &BasicObjectsView::initialize); +} + +QSize BasicObjectsView::sizeHint() const +{ + return {120, 600}; +} + +void BasicObjectsView::startDrag(int row) +{ + const auto index = m_ObjectsModel->index(row); + + QDrag drag(this); + drag.setMimeData(m_ObjectsModel->mimeData({index})); + drag.setPixmap(QPixmap(index.data(BasicObjectsModel::IconRole).toUrl().toLocalFile())); + drag.exec(Qt::CopyAction); +} + +void BasicObjectsView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_basicObjectsModel"_L1, m_ObjectsModel); + rootContext()->setContextProperty("_basicObjectsView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/BasicObjects/BasicObjectsView.qml"_L1)); +} diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h new file mode 100644 index 00000000..9317fc8f --- /dev/null +++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 BASICOBJECTSVIEW_H +#define BASICOBJECTSVIEW_H + +#include <QQuickWidget> + +class BasicObjectsModel; + +class BasicObjectsView : public QQuickWidget +{ + Q_OBJECT +public: + explicit BasicObjectsView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + + Q_INVOKABLE void startDrag(int row); +private: + void initialize(); + + BasicObjectsModel *m_ObjectsModel = nullptr; + QColor m_BaseColor = QColor::fromRgb(75, 75, 75); +}; + +#endif // BASICOBJECTSVIEW_H diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml new file mode 100644 index 00000000..ec2a0f6e --- /dev/null +++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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.1 +import "../controls" + +Rectangle { + + color: _backgroundColor + + ListView { + anchors { + fill: parent + leftMargin: 8 + } + boundsBehavior: Flickable.StopAtBounds + + model: _basicObjectsModel + spacing: 2 + + ScrollBar.vertical: ScrollBar {} + + delegate: Item { + height: contentRow.height + width: contentRow.width + Item { + id: dragItem + anchors.fill: parent + + Drag.active: dragArea.drag.active + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + + MouseArea { + id: dragArea + property bool dragging: false + anchors.fill: parent + drag.target: dragItem + } + + Drag.onDragStarted: _basicObjectsView.startDrag(model.index) + } + Row { + id: contentRow + spacing: 4 + Image { + id: assetIcon + width: 24 + height: 24 + fillMode: Image.Pad + source: model.icon + } + StyledLabel { + y: (assetIcon.height - height) / 2 + text: model.name + } + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml new file mode 100644 index 00000000..6ee4445c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: item + + signal clicked(string filePath) + signal doubleClicked(string filePath) + + width: parent.width + height: 20 + color: isCurrentFile ? _selectionColor : "transparent" + + Row { + x: depth*28 + anchors.verticalCenter: item.verticalCenter + + Image { + source: _resDir + (expanded ? "arrow_down.png" : "arrow.png") + opacity: isExpandable ? 1 : 0 + + MouseArea { + visible: isExpandable + anchors.fill: parent + onClicked: { + if (expanded) + listView.model.collapse(index) + else + listView.model.expand(index) + } + } + } + + Image { + source: fileIcon + } + + StyledLabel { + text: fileName + color: _textColor + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + visible: isSelectable + onClicked: item.clicked(filePath) + onDoubleClicked: item.doubleClicked(filePath) + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp new file mode 100644 index 00000000..87df1b45 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp @@ -0,0 +1,592 @@ +/**************************************************************************** +** +** 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 <QSet> + +#include "stdafx.h" + +#include "ChooserModelBase.h" +#include "Core.h" +#include "Dispatch.h" +#include "Doc.h" +#include "StudioUtils.h" +#include "UICFileTools.h" +#include "ImportUtils.h" +#include "StudioApp.h" + +ChooserModelBase::ChooserModelBase(QObject *parent) : QAbstractListModel(parent) + , m_model(new QFileSystemModel(this)) +{ + connect(m_model, &QAbstractItemModel::rowsInserted, this, &ChooserModelBase::modelRowsInserted); + connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ChooserModelBase::modelRowsRemoved); + connect(m_model, &QAbstractItemModel::layoutChanged, this, &ChooserModelBase::modelLayoutChanged); + + g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this); + + rebuild(); +} + +ChooserModelBase::~ChooserModelBase() +{ + g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this); +} + +QHash<int, QByteArray> ChooserModelBase::roleNames() const +{ + auto modelRoleNames = m_model->roleNames(); + modelRoleNames.insert(IsExpandableRole, "isExpandable"); + modelRoleNames.insert(DepthRole, "depth"); + modelRoleNames.insert(ExpandedRole, "expanded"); + modelRoleNames.insert(IsSelectableRole, "isSelectable"); + modelRoleNames.insert(IsCurrentFile, "isCurrentFile"); + return modelRoleNames; +} + +int ChooserModelBase::rowCount(const QModelIndex &) const +{ + return getFixedItems().count() + m_items.count(); +} + +QVariant ChooserModelBase::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + + const auto fixedItems = getFixedItems(); + const int fixedItemCount = fixedItems.count(); + + if (row < fixedItemCount) { + const auto &item = fixedItems.at(row); + + switch (role) { + case Qt::DecorationRole: + return resourceImageUrl() + CStudioObjectTypes::GetNormalIconName(item.iconType); + + case IsExpandableRole: + return false; + + case DepthRole: + return 0; + + case ExpandedRole: + return false; + + case IsSelectableRole: + return true; + + case IsCurrentFile: + return item.name == m_currentFile; + + default: + return item.name; + } + } else { + const auto &item = m_items.at(row - fixedItemCount); + + switch (role) { + case Qt::DecorationRole: { + QString path = item.index.data(QFileSystemModel::FilePathRole).toString(); + return resourceImageUrl() + getIconName(path); + } + + case IsExpandableRole: { + QFileInfo fileInfo(item.index.data(QFileSystemModel::FilePathRole).toString()); + return fileInfo.isDir(); + } + + case DepthRole: + return item.depth; + + case ExpandedRole: + return item.expanded; + + case IsSelectableRole: { + QFileInfo fileInfo(item.index.data(QFileSystemModel::FilePathRole).toString()); + return fileInfo.isFile(); + } + + case IsCurrentFile: { + QString path = item.index.data(QFileSystemModel::FilePathRole).toString(); + return path == m_currentFile; + } + + default: + return m_model->data(item.index, role); + } + } +} + +void ChooserModelBase::setCurrentFile(const QString &path) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const QDir documentDir(doc->GetDocumentDirectory().toQString()); + const QString fullPath = QDir::cleanPath(documentDir.filePath(path)); + + if (fullPath != m_currentFile) { + const auto fixedItems = getFixedItems(); + + const auto fileRow = [this, &fixedItems](const QString &path) + { + const int fixedItemCount = fixedItems.count(); + + for (int i = 0; i < fixedItemCount; ++i) { + const auto &item = fixedItems.at(i); + + if (item.name == path) + return i; + } + + const int itemCount = m_items.count(); + + for (int i = 0; i < itemCount; ++i) { + const auto &item = m_items.at(i); + + if (item.index.data(QFileSystemModel::FilePathRole).toString() == path) + return fixedItemCount + i; + } + + return -1; + }; + + int previousRow = fileRow(m_currentFile); + int currentRow = fileRow(fullPath); + + m_currentFile = fullPath; + + const int fixedItemCount = fixedItems.count(); + + if (previousRow != -1) + Q_EMIT dataChanged(index(previousRow), index(previousRow)); + + if (currentRow != -1) + Q_EMIT dataChanged(index(currentRow), index(currentRow)); + } + + // expand parent folder if current file is hidden + auto matched = m_model->match(m_rootIndex, QFileSystemModel::FilePathRole, path, 1, + Qt::MatchExactly|Qt::MatchRecursive); + if (!matched.isEmpty()) { + auto modelIndex = matched.first(); + if (modelIndexRow(modelIndex) == -1) + expand(m_model->parent(modelIndex)); + } +} + +void ChooserModelBase::expand(const QModelIndex &modelIndex) +{ + if (modelIndex == m_rootIndex) + return; + + int row = modelIndexRow(modelIndex); + if (row == -1) { + QModelIndex parentIndex = m_model->parent(modelIndex); + expand(parentIndex); + + row = modelIndexRow(modelIndex); + Q_ASSERT(row != -1); + } + + if (!m_items.at(row).expanded) + expand(row + getFixedItems().count()); +} + +void ChooserModelBase::setRootPath(const QString &path) +{ + setRootIndex(m_model->setRootPath(path)); +} + +void ChooserModelBase::setRootIndex(const QModelIndex &rootIndex) +{ + if (rootIndex != m_rootIndex) { + clearModelData(); + m_rootIndex = rootIndex; + showModelTopLevelItems(); + } +} + +void ChooserModelBase::clearModelData() +{ + if (!m_items.isEmpty()) { + const auto fixedItemCount = getFixedItems().count(); + beginRemoveRows({}, fixedItemCount, fixedItemCount + m_items.count() - 1); + m_items.clear(); + endRemoveRows(); + } +} + +void ChooserModelBase::showModelTopLevelItems() +{ + int rowCount = m_model->rowCount(m_rootIndex); + + if (rowCount == 0) { + if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex)) + m_model->fetchMore(m_rootIndex); + } else { + showModelChildItems(m_rootIndex, 0, rowCount - 1); + + for (int i = 0; i < rowCount; ++i) { + const auto &childIndex = m_model->index(i, 0, m_rootIndex); + if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex)) + m_model->fetchMore(childIndex); + } + } +} + +void ChooserModelBase::showModelChildItems(const QModelIndex &parentIndex, int start, int end) +{ + QVector<QModelIndex> rowsToInsert; + for (int i = start; i <= end; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (isVisible(childIndex)) + rowsToInsert.append(childIndex); + } + + const int insertCount = rowsToInsert.count(); + + if (insertCount != 0) { + TreeItem *parent; + int depth, startRow; + + if (parentIndex == m_rootIndex) { + parent = nullptr; + depth = 0; + startRow = 0; + } else { + const int parentRow = modelIndexRow(parentIndex); + Q_ASSERT(parentRow != -1 && isVisible(parentIndex)); + parent = &m_items[parentRow]; + depth = parent->depth + 1; + startRow = parentRow + parent->childCount + 1; + } + + const int fixedItemCount = getFixedItems().count(); + beginInsertRows({}, startRow + fixedItemCount, startRow + fixedItemCount + insertCount - 1); + + for (auto it = rowsToInsert.rbegin(); it != rowsToInsert.rend(); ++it) + m_items.insert(startRow, { *it, depth, false, parent, 0 }); + + for (; parent != nullptr; parent = parent->parent) + parent->childCount += insertCount; + + endInsertRows(); + } +} + +void ChooserModelBase::expand(int row) +{ + const int fixedItemCount = getFixedItems().count(); + Q_ASSERT(row >= fixedItemCount && row < fixedItemCount + m_items.count()); + + auto &item = m_items[row - fixedItemCount]; + Q_ASSERT(item.expanded == false); + + const auto &modelIndex = item.index; + + const int rowCount = m_model->rowCount(modelIndex); + if (rowCount == 0) { + if (m_model->hasChildren(modelIndex) && m_model->canFetchMore(modelIndex)) + m_model->fetchMore(modelIndex); + } else { + showModelChildItems(modelIndex, 0, rowCount - 1); + } + + item.expanded = true; + Q_EMIT dataChanged(index(row), index(row)); +} + +void ChooserModelBase::collapse(int row) +{ + const int fixedItemCount = getFixedItems().count(); + Q_ASSERT(row >= fixedItemCount && row < fixedItemCount + m_items.count()); + + auto &item = m_items[row - fixedItemCount]; + Q_ASSERT(item.expanded == true); + + const int childCount = item.childCount; + + if (childCount > 0) { + beginRemoveRows({}, row + 1, row + childCount); + + auto first = std::begin(m_items) + row - fixedItemCount + 1; + m_items.erase(first, first + childCount); + + for (auto parent = &item; parent != nullptr; parent = parent->parent) + parent->childCount -= childCount; + + endRemoveRows(); + } + + item.expanded = false; + Q_EMIT dataChanged(index(row), index(row)); +} + +void ChooserModelBase::OnNewPresentation() +{ + rebuild(); +} + +int ChooserModelBase::modelIndexRow(const QModelIndex &modelIndex) const +{ + auto it = std::find_if(std::begin(m_items), std::end(m_items), + [&modelIndex](const TreeItem &item) + { + return item.index == modelIndex; + }); + + return it != std::end(m_items) ? std::distance(std::begin(m_items), it) : -1; +} + +bool ChooserModelBase::isExpanded(const QModelIndex &modelIndex) const +{ + if (modelIndex == m_rootIndex) { + return true; + } else { + const int row = modelIndexRow(modelIndex); + return row != -1 && m_items.at(row).expanded; + } +} + +EStudioObjectType ChooserModelBase::getIconType(const QString &path) const +{ + return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(Q3DStudio::CFilePath::fromQString(path)).m_IconType; +} + +QString ChooserModelBase::getIconName(const QString &path) const +{ + QString iconName; + + QFileInfo fileInfo(path); + if (fileInfo.isFile()) { + EStudioObjectType type = getIconType(path); + if (type != OBJTYPE_UNKNOWN) + iconName = CStudioObjectTypes::GetNormalIconName(type); + else + iconName = QStringLiteral("Objects-Layer-Normal.png"); + } else { + iconName = QStringLiteral("Objects-Folder-Normal.png"); + } + + return iconName; +} + +bool ChooserModelBase::isVisible(const QModelIndex &modelIndex) const +{ + QString path = modelIndex.data(QFileSystemModel::FilePathRole).toString(); + QFileInfo fileInfo(path); + + if (fileInfo.isFile()) { + return isVisible(path); + } else { + return hasVisibleChildren(modelIndex); + } +} + +bool ChooserModelBase::hasVisibleChildren(const QModelIndex &modelIndex) const +{ + int rowCount = m_model->rowCount(modelIndex); + + for (int i = 0; i < rowCount; ++i) { + const auto &childIndex = m_model->index(i, 0, modelIndex); + + if (m_model->hasChildren(childIndex)) { + if (hasVisibleChildren(childIndex)) + return true; + } else { + QString path = childIndex.data(QFileSystemModel::FilePathRole).toString(); + QFileInfo fileInfo(path); + if (fileInfo.isFile() && isVisible(path)) + return true; + } + } + + return false; +} + +void ChooserModelBase::modelRowsInserted(const QModelIndex &parentIndex, int start, int end) +{ + if (!m_rootIndex.isValid()) + return; + + if (isExpanded(parentIndex)) { + showModelChildItems(parentIndex, start, end); + } else { + if (modelIndexRow(parentIndex) == -1) { + // parent wasn't inserted in model yet, check if any of the new rows is visible + + bool visible = false; + + for (int i = start; i <= end; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + QString path = childIndex.data(QFileSystemModel::FilePathRole).toString(); + QFileInfo fileInfo(path); + if (fileInfo.isFile() && isVisible(path)) { + visible = true; + break; + } + } + + // if any of the new rows is visible, insert parent folder index into model + + if (visible) { + QModelIndex index = parentIndex, parent = m_model->parent(parentIndex); + + while (parent != m_rootIndex && modelIndexRow(parent) == -1) { + index = parent; + parent = m_model->parent(parent); + } + + if (isExpanded(parent) && modelIndexRow(index) == -1) { + const int row = index.row(); + showModelChildItems(parent, row, row); + } + } + } + + // if one of the new rows is the current file expand parent folder + + bool containsCurrent = false; + + for (int i = start; i <= end; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (childIndex.data(QFileSystemModel::FilePathRole).toString() == m_currentFile) { + containsCurrent = true; + break; + } + } + + if (containsCurrent) + expand(parentIndex); + } + + // fetch children so we're notified when files are added or removed + + for (int i = start; i <= end; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex)) + m_model->fetchMore(childIndex); + } +} + +void ChooserModelBase::modelRowsRemoved(const QModelIndex &parentIndex, int start, int end) +{ + if (!m_rootIndex.isValid()) + return; + + if (isExpanded(parentIndex)) { + const auto fixedItems = getFixedItems(); + + const auto removeRow = [this, &fixedItems](int row) + { + const auto &item = m_items.at(row); + + const int fixedItemCount = fixedItems.count(); + beginRemoveRows({}, row + fixedItemCount, row + fixedItemCount + item.childCount); + + for (auto parent = item.parent; parent != nullptr; parent = parent->parent) + parent->childCount -= 1 + item.childCount; + + m_items.erase(std::begin(m_items) + row, std::begin(m_items) + row + item.childCount + 1); + + endRemoveRows(); + }; + + // remove rows + + for (int i = start; i <= end; ++i) { + const int row = modelIndexRow(m_model->index(i, 0, parentIndex)); + if (row != -1) + removeRow(row); + } + + // also remove folder row if there are no more visible children + + QModelIndex index = parentIndex; + + while (index != m_rootIndex && !hasVisibleChildren(index)) { + const int row = modelIndexRow(index); + Q_ASSERT(row != -1); + removeRow(row); + index = m_model->parent(index); + } + } +} + +void ChooserModelBase::modelLayoutChanged() +{ + if (!m_rootIndex.isValid()) + return; + + QSet<QPersistentModelIndex> expandedItems; + for (const auto &item : m_items) { + if (item.expanded) + expandedItems.insert(item.index); + } + + const std::function<int(const QModelIndex &, TreeItem *)> insertChildren = + [this, &expandedItems, &insertChildren](const QModelIndex &parentIndex, TreeItem *parent) + { + Q_ASSERT(parentIndex == m_rootIndex || isVisible(parentIndex)); + + const int rowCount = m_model->rowCount(parentIndex); + const int depth = parent == nullptr ? 0 : parent->depth + 1; + + int childCount = 0; + + for (int i = 0; i < rowCount; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (isVisible(childIndex)) { + const bool expanded = expandedItems.contains(childIndex); + m_items.append({ childIndex, depth, expanded, parent, 0 }); + auto &item = m_items.last(); + if (expanded) { + item.childCount = insertChildren(childIndex, &item); + childCount += item.childCount; + } + ++childCount; + } + } + + return childCount; + }; + + const int itemCount = m_items.count(); + + m_items.clear(); + m_items.reserve(itemCount); + + insertChildren(m_rootIndex, nullptr); + Q_ASSERT(m_items.count() == itemCount); + + const int fixedItemCount = getFixedItems().count(); + Q_EMIT dataChanged(index(fixedItemCount), index(fixedItemCount + itemCount - 1)); +} + +void ChooserModelBase::rebuild() +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const Q3DStudio::CFilePath path(doc->GetDocumentPath().GetAbsolutePath()); + setRootPath(path.GetDirectory().toQString()); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h new file mode 100644 index 00000000..547822ea --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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 CHOOSERMODELBASE_H +#define CHOOSERMODELBASE_H + +#include "DispatchListeners.h" +#include "StudioObjectTypes.h" + +#include <QFileSystemModel> +#include <QAbstractListModel> +#include <QList> +#include <QVector> + +class QFileSystemModel; + +class ChooserModelBase : public QAbstractListModel, public CPresentationChangeListener +{ + Q_OBJECT + +public: + explicit ChooserModelBase(QObject *parent = nullptr); + ~ChooserModelBase(); + + enum { + IsExpandableRole = QFileSystemModel::FilePermissions + 1, + DepthRole, + ExpandedRole, + IsSelectableRole, + IsCurrentFile + }; + + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role) const override; + + Q_INVOKABLE void expand(int row); + Q_INVOKABLE void collapse(int row); + + void setCurrentFile(const QString &path); + + // CPresentationChangeListener + void OnNewPresentation() override; + +Q_SIGNALS: + void modelChanged(QAbstractItemModel *model); + +protected: + EStudioObjectType getIconType(const QString &path) const; + + virtual bool isVisible(const QString &path) const = 0; + + struct FixedItem + { + EStudioObjectType iconType; + QString name; + }; + + virtual const QVector<FixedItem> getFixedItems() const = 0; + +private: + void setRootPath(const QString &path); + void setRootIndex(const QModelIndex &rootIndex); + void clearModelData(); + void showModelTopLevelItems(); + void showModelChildItems(const QModelIndex &parentItem, int start, int end); + int modelIndexRow(const QModelIndex &modelIndex) const; + bool isExpanded(const QModelIndex &modelIndex) const; + QString getIconName(const QString &path) const; + bool isVisible(const QModelIndex &modelIndex) const; + bool hasVisibleChildren(const QModelIndex &modelIndex) const; + void expand(const QModelIndex &modelIndex); + + void modelRowsInserted(const QModelIndex &parent, int start, int end); + void modelRowsRemoved(const QModelIndex &parent, int start, int end); + void modelRowsMoved(const QModelIndex &parent, int start, int end); + void modelLayoutChanged(); + + void rebuild(); + + struct TreeItem { + QPersistentModelIndex index; + int depth; + bool expanded; + TreeItem *parent; + int childCount; + }; + + QFileSystemModel *m_model; + QPersistentModelIndex m_rootIndex; + QList<TreeItem> m_items; + QString m_currentFile; +}; + +#endif // CHOOSERMODELBASE_H diff --git a/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp new file mode 100644 index 00000000..44b89904 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "EasyInspectorGroup.h" + +//============================================================================== +/** + * Constructor + */ +CEasyInspectorGroup::CEasyInspectorGroup(const QString &inName) + : CInspectorGroup() +{ + SetName(inName); +} + +//============================================================================== +/** + * + */ +CEasyInspectorGroup::~CEasyInspectorGroup() +{ +} diff --git a/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h new file mode 100644 index 00000000..62cc35a5 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_EASYINSPECTORGROUP_H +#define INCLUDED_EASYINSPECTORGROUP_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "InspectorGroup.h" + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** + * Simplest possible inspector group + */ +class CEasyInspectorGroup : public CInspectorGroup +{ +public: // Construction + CEasyInspectorGroup(const QString &inName); + ~CEasyInspectorGroup(); +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml b/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml new file mode 100644 index 00000000..2762af3a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + spacing: 10 + ListView { + id: listView + + anchors { + fill: parent + leftMargin: 8 + } + + boundsBehavior: Flickable.StopAtBounds + spacing: 4 + clip: true + + ScrollBar.vertical: ScrollBar {} + + model: _fileChooserModel + + delegate: ChooserDelegate { + onClicked: _fileChooserView.fileSelected(_fileChooserView.handle, _fileChooserView.instance, filePath) + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp new file mode 100644 index 00000000..6c57635b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 "FileChooserModel.h" + +FileChooserModel::FileChooserModel(QObject *parent) + : ChooserModelBase(parent) +{ + +} + +FileChooserModel::~FileChooserModel() +{ +} + +bool FileChooserModel::isVisible(const QString &path) const +{ + return getIconType(path) == OBJTYPE_GROUP; +} + +const QVector<ChooserModelBase::FixedItem> FileChooserModel::getFixedItems() const +{ + static const QVector<FixedItem> items = { { OBJTYPE_GROUP, tr("[None]") } }; + return items; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h new file mode 100644 index 00000000..c019c4a1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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 FILECHOOSERMODEL_H +#define FILECHOOSERMODEL_H + +#include "ChooserModelBase.h" + +class FileChooserModel : public ChooserModelBase +{ + Q_OBJECT + +public: + explicit FileChooserModel(QObject *parent = nullptr); + virtual ~FileChooserModel(); +private: + bool isVisible(const QString &path) const override; + const QVector<FixedItem> getFixedItems() const override; +}; + +#endif // IMAGECHOOSERMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp new file mode 100644 index 00000000..d5951e7c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp @@ -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$ +** +****************************************************************************/ + +#include "FileChooserView.h" +#include "FileChooserModel.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "IDocumentEditor.h" +#include "UICDMStudioSystem.h" +#include "UICDMValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "StudioPreferences.h" + +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> +#include <QtCore/qtimer.h> + +FileChooserView::FileChooserView(QWidget *parent) + : QQuickWidget(parent) + , m_model(new FileChooserModel(this)) +{ + setWindowTitle(tr("Imports")); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &FileChooserView::initialize); +} + +void FileChooserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_resDir"_L1, + resourceImageUrl()); + rootContext()->setContextProperty("_fileChooserView"_L1, this); + rootContext()->setContextProperty("_fileChooserModel"_L1, m_model); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/FileChooser.qml"_L1)); +} + +QSize FileChooserView::sizeHint() const +{ + return {500, 500}; +} + +void FileChooserView::setHandle(int handle) +{ + m_handle = handle; +} + +int FileChooserView::handle() const +{ + return m_handle; +} + +void FileChooserView::setInstance(int instance) +{ + m_instance = instance; +} + +int FileChooserView::instance() const +{ + return m_instance; +} + +void FileChooserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &FileChooserView::close); +} + +void FileChooserView::showEvent(QShowEvent *event) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + + UICDM::SValue value; + propertySystem->GetInstancePropertyValue(m_instance, m_handle, value); + + m_model->setCurrentFile(UICDM::get<QString>(value)); + + QQuickWidget::showEvent(event); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h new file mode 100644 index 00000000..400f9f1e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h @@ -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$ +** +****************************************************************************/ + +#ifndef FILECHOOSERVIEW_H +#define FILECHOOSERVIEW_H + +#include <QtQuickWidgets/qquickwidget.h> + +class FileChooserModel; + +class FileChooserView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(int instance READ instance) + Q_PROPERTY(int handle READ handle) + +public: + explicit FileChooserView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + + void setHandle(int handle); + int handle() const; + + void setInstance(int instance); + int instance() const; + +Q_SIGNALS: + void fileSelected(int handle, int instance, const QString &name); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void showEvent(QShowEvent *event) override; + void initialize(); + int m_handle = -1; + int m_instance = -1; + FileChooserModel *m_model = nullptr; +}; + +#endif // IMAGECHOOSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp new file mode 100644 index 00000000..f840d92f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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 "stdafx.h" +#include "GuideInspectable.h" +#include "InspectableBase.h" +#include "Core.h" +#include "Doc.h" +#include "UICDMGuides.h" +#include "EasyInspectorGroup.h" +#include "IDocumentEditor.h" +#include "UICDMDataTypes.h" +#include "IInspectableItem.h" +#include "UICDMValue.h" + +typedef std::function<UICDM::SValue()> TGetterFunc; +typedef std::function<void(UICDM::SValue)> TSetterFunc; +typedef std::function<void()> TCommitFunc; +typedef std::function<void()> TCancelFunc; + +struct SInspectableDataInfo +{ + Q3DStudio::CString m_Name; + Q3DStudio::CString m_FormalName; + Q3DStudio::CString m_Description; + TGetterFunc m_Getter; + TSetterFunc m_Setter; + TCommitFunc m_Commit; + TCancelFunc m_Cancel; + + SInspectableDataInfo(const Q3DStudio::CString &name, const Q3DStudio::CString &formalName, + const Q3DStudio::CString &description, TGetterFunc getter, TSetterFunc setter, + TCommitFunc commit, TCancelFunc inCancel) + : m_Name(name) + , m_FormalName(formalName) + , m_Description(description) + , m_Getter(getter) + , m_Setter(setter) + , m_Commit(commit) + , m_Cancel(inCancel) + { + } +}; + +struct SComboAttItem : public IInspectableAttributeItem +{ + SInspectableDataInfo m_BaseInspectableInfo; + UICDM::TMetaDataStringList m_MetaDataTypes; + SComboAttItem(const SInspectableDataInfo &inInfo, const UICDM::TMetaDataStringList &inTypes) + : m_BaseInspectableInfo(inInfo) + , m_MetaDataTypes(inTypes) + { + } + UICDM::HandlerArgumentType::Value GetInspectableSubType() const override + { + return UICDM::HandlerArgumentType::Property; + } + Q3DStudio::CString GetInspectableName() const override { return m_BaseInspectableInfo.m_Name; } + Q3DStudio::CString GetInspectableFormalName() const override + { + return m_BaseInspectableInfo.m_FormalName; + } + Q3DStudio::CString GetInspectableDescription() const override + { + return m_BaseInspectableInfo.m_Description; + } + + UICDM::SValue GetInspectableData() const override { return m_BaseInspectableInfo.m_Getter(); } + void SetInspectableData(const UICDM::SValue &inValue) override + { + m_BaseInspectableInfo.m_Setter(inValue); + m_BaseInspectableInfo.m_Commit(); + } + + float GetInspectableMin() const override { return 0; } + float GetInspectableMax() const override { return 0; } + UICDM::TMetaDataStringList GetInspectableList() const override { return m_MetaDataTypes; } + UICDM::DataModelDataType::Value GetInspectableType() const override + { + return UICDM::DataModelDataType::String; + } + UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const override + { + return UICDM::AdditionalMetaDataType::StringList; + } +}; + +struct SFloatIntItem : public IInspectableAttributeItem +{ + SInspectableDataInfo m_BaseInspectableInfo; + UICDM::DataModelDataType::Value m_DataType; + float m_Min; + float m_Max; + SFloatIntItem(const SInspectableDataInfo &inInfo, UICDM::DataModelDataType::Value inType, + float inMin = 0, float inMax = 0) + : m_BaseInspectableInfo(inInfo) + , m_DataType(inType) + , m_Min(inMin) + , m_Max(inMax) + { + } + UICDM::HandlerArgumentType::Value GetInspectableSubType() const override + { + return UICDM::HandlerArgumentType::Property; + } + Q3DStudio::CString GetInspectableName() const override { return m_BaseInspectableInfo.m_Name; } + Q3DStudio::CString GetInspectableFormalName() const override + { + return m_BaseInspectableInfo.m_FormalName; + } + Q3DStudio::CString GetInspectableDescription() const override + { + return m_BaseInspectableInfo.m_Description; + } + + UICDM::SValue GetInspectableData() const override { return m_BaseInspectableInfo.m_Getter(); } + void SetInspectableData(const UICDM::SValue &inValue) override + { + m_BaseInspectableInfo.m_Setter(inValue); + m_BaseInspectableInfo.m_Commit(); + } + + void ChangeInspectableData(const UICDM::SValue &inValue) override + { + m_BaseInspectableInfo.m_Setter(inValue); + } + void CancelInspectableData() override { m_BaseInspectableInfo.m_Cancel(); } + + float GetInspectableMin() const override { return m_Min; } + float GetInspectableMax() const override { return m_Max; } + UICDM::TMetaDataStringList GetInspectableList() const override + { + return UICDM::TMetaDataStringList(); + } + UICDM::DataModelDataType::Value GetInspectableType() const override { return m_DataType; } + UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const override + { + return UICDM::AdditionalMetaDataType::None; + } +}; + + +CInspectableBase *CGuideInspectable::CreateInspectable(CCore &inCore, + UICDM::CUICDMGuideHandle inGuide) +{ + return new SGuideInspectableImpl(inCore, inGuide); +} + +SGuideInspectableImpl::SGuideInspectableImpl(CCore &inCore, UICDM::CUICDMGuideHandle inGuide) + : CInspectableBase(&inCore) + , m_Guide(inGuide) + , m_Editor(*inCore.GetDoc()) +{ +} + +Q3DStudio::IDocumentReader &SGuideInspectableImpl::Reader() const +{ + return m_Core->GetDoc()->GetDocumentReader(); +} + +EStudioObjectType SGuideInspectableImpl::GetObjectType() +{ + return OBJTYPE_GUIDE; +} + +Q3DStudio::CString SGuideInspectableImpl::GetName() +{ + return L"Guide"; +} + +long SGuideInspectableImpl::GetGroupCount() +{ + return 1; +} + +CInspectorGroup *SGuideInspectableImpl::GetGroup(long) +{ + CDoc *theDoc = m_Core->GetDoc(); + TCommitFunc theCommiter = std::bind(&SGuideInspectableImpl::Commit, this); + TCancelFunc theCanceler = std::bind(&SGuideInspectableImpl::Rollback, this); + m_Properties.push_back(std::make_shared<SFloatIntItem>( + SInspectableDataInfo("Position", "Position", "Position of the guide", + std::bind(&SGuideInspectableImpl::GetPosition, this), + std::bind(&SGuideInspectableImpl::SetPosition, this, + std::placeholders::_1), + theCommiter, theCanceler), + UICDM::DataModelDataType::Float)); + UICDM::TMetaDataStringList theComboItems; + theComboItems.push_back(L"Horizontal"); + theComboItems.push_back(L"Vertical"); + + m_Properties.push_back(std::make_shared<SComboAttItem>( + SInspectableDataInfo("Direction", "Direction", "Direction of the guide", + std::bind(&SGuideInspectableImpl::GetDirection, this), + std::bind(&SGuideInspectableImpl::SetDirection, this, + std::placeholders::_1), + theCommiter, theCanceler), + theComboItems)); + + m_Properties.push_back(std::make_shared<SFloatIntItem>( + SInspectableDataInfo("Width", "Width", "Width of the guide", + std::bind(&SGuideInspectableImpl::GetWidth, this), + std::bind(&SGuideInspectableImpl::SetWidth, this, std::placeholders::_1), + theCommiter, theCanceler), + UICDM::DataModelDataType::Long, 1.0f, 50.0f)); + + CEasyInspectorGroup *theNewGroup = new CEasyInspectorGroup(QObject::tr("Basic")); + return theNewGroup; +} + +bool SGuideInspectableImpl::IsValid() const +{ + return Reader().IsGuideValid(m_Guide); +} + +bool SGuideInspectableImpl::IsMaster() +{ + return true; +} + +void SGuideInspectableImpl::SetDirection(const UICDM::SValue &inValue) +{ + UICDM::TDataStrPtr theData = inValue.getData<UICDM::TDataStrPtr>(); + UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide)); + if (theData) { + if (UICDM::AreEqual(theData->GetData(), L"Horizontal")) + theSetter.m_Direction = UICDM::GuideDirections::Horizontal; + else if (UICDM::AreEqual(theData->GetData(), L"Vertical")) + theSetter.m_Direction = UICDM::GuideDirections::Vertical; + } + Editor().UpdateGuide(m_Guide, theSetter); + FireRefresh(); +} + +UICDM::SValue SGuideInspectableImpl::GetDirection() +{ + switch (Reader().GetGuideInfo(m_Guide).m_Direction) { + case UICDM::GuideDirections::Horizontal: + return std::make_shared<UICDM::CDataStr>(L"Horizontal"); + case UICDM::GuideDirections::Vertical: + return std::make_shared<UICDM::CDataStr>(L"Vertical"); + default: + return std::make_shared<UICDM::CDataStr>(L""); + } +} + +void SGuideInspectableImpl::SetPosition(const UICDM::SValue &inValue) +{ + float thePos = inValue.getData<float>(); + UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide)); + theSetter.m_Position = thePos; + Editor().UpdateGuide(m_Guide, theSetter); + FireRefresh(); +} + +UICDM::SValue SGuideInspectableImpl::GetPosition() +{ + UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide)); + return theSetter.m_Position; +} + +void SGuideInspectableImpl::SetWidth(const UICDM::SValue &inValue) +{ + auto theData = inValue.getData<qt3ds::QT3DSI32>(); + + UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide)); + theSetter.m_Width = theData; + Editor().UpdateGuide(m_Guide, theSetter); + FireRefresh(); + +} + +UICDM::SValue SGuideInspectableImpl::GetWidth() +{ + UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide)); + return theSetter.m_Width; +} + +Q3DStudio::IDocumentEditor &SGuideInspectableImpl::Editor() +{ + return m_Editor.EnsureEditor(L"Set Property", __FILE__, __LINE__); +} + +void SGuideInspectableImpl::Commit() +{ + m_Editor.CommitEditor(); +} + +void SGuideInspectableImpl::Rollback() +{ + m_Editor.RollbackEditor(); +} + +void SGuideInspectableImpl::FireRefresh() +{ + m_Editor.FireImmediateRefresh(UICDM::CUICDMInstanceHandle()); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h new file mode 100644 index 00000000..77ff7a62 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ +#pragma once +#ifndef __GUIDEINSPECTABLE_H__ +#define __GUIDEINSPECTABLE_H__ +#include "UICDMHandles.h" +#include "Core.h" +#include "InspectableBase.h" +#include "Doc.h" +#include "IDocumentEditor.h" +#include "IInspectableItem.h" + +class CInspectableBase; + +class CGuideInspectable +{ +public: + static CInspectableBase *CreateInspectable(CCore &inCore, UICDM::CUICDMGuideHandle inGuide); +}; + +class SGuideInspectableImpl : public CInspectableBase +{ +public: + SGuideInspectableImpl(CCore &inCore, UICDM::CUICDMGuideHandle inGuide); + + Q3DStudio::IDocumentReader &Reader() const; + // Interface + EStudioObjectType GetObjectType() override; + Q3DStudio::CString GetName() override; + long GetGroupCount() override; + CInspectorGroup *GetGroup(long) override; + bool IsValid() const override; + bool IsMaster() override; + + // Implementation to get/set properties + + void SetDirection(const UICDM::SValue &inValue); + + UICDM::SValue GetDirection(); + + void SetPosition(const UICDM::SValue &inValue); + + UICDM::SValue GetPosition(); + + void SetWidth(const UICDM::SValue &inValue); + + UICDM::SValue GetWidth(); + + Q3DStudio::IDocumentEditor &Editor(); + void Commit(); + void Rollback(); + void FireRefresh(); +private: + UICDM::CUICDMGuideHandle m_Guide; + Q3DStudio::CUpdateableDocumentEditor m_Editor; + std::vector<std::shared_ptr<IInspectableAttributeItem>> m_Properties; +}; + + +#endif diff --git a/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml b/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml new file mode 100644 index 00000000..65e0d6be --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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.Layouts 1.1 +import QtQuick.Controls 2.1 +import "../controls" + +RowLayout { + id: root + + signal showBrowser + property string value: "" + property alias activeBrowser: browser.activeBrowser + + BrowserCombo { + id: browser + Layout.preferredWidth: _valueWidth + Layout.fillWidth: true + value: root.value === "" ? qsTr("Select...") : root.value + onShowBrowser: root.showBrowser() + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml b/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml new file mode 100644 index 00000000..9a8f1688 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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.Layouts 1.1 +import QtQuick.Controls 2.1 +import "../controls" + +RowLayout { + id: root + + signal showBrowser + property alias value: browser.value + property alias activeBrowser: browser.activeBrowser + + BrowserCombo { + id: browser + Layout.preferredWidth: _valueWidth + Layout.fillWidth: true + onShowBrowser: root.showBrowser() + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h b/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h new file mode 100644 index 00000000..ced2099b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ +#pragma once +#include "ToggleButton.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Interface for getting callbacks from the EasyInspectorRow + */ +class IEasyInspectorRowListener +{ +public: // IEasyInspectorRowListener + virtual void OnAnimateToggle(CToggleButton::EButtonState inState) = 0; + virtual void OnLinkToggle() = 0; +}; + +} // namespace Q3DStudio diff --git a/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h b/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h new file mode 100644 index 00000000..341e46f0 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef __IINSPECTABLEITEM_H__ +#define __IINSPECTABLEITEM_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMDataTypes.h" +#include "UICDMHandles.h" +#include "UICDMActionInfo.h" +#include "UICDMMetaData.h" +#include "UICString.h" + +//============================================================================== +// Forwards +//============================================================================== +class CStudioApp; +class IInspectableItem; + +//============================================================================== +// Abstract Base Classes +//============================================================================== + +enum EInspectableItemTypes { + INSPECTABLEITEMTYPE_VANILLA = 1, + INSPECTABLEITEMTYPE_PROPERTY, + INSPECTABLEITEMTYPE_DEPENDENT, + INSPECTABLEITEMTYPE_SLIDE, + INSPECTABLEITEMTYPE_OBJECTREFERENCE, + INSPECTABLEITEMTYPE_EVENTSOURCE, + INSPECTABLEITEMTYPE_ACTION, + INSPECTABLEITEMTYPE_CONDITIONS, +}; + +//============================================================================== +/** + * @class IInspectableItemChangeListener + * @brief Listener class for inspectable item changes. + */ +class IInspectableItemChangeListener +{ +public: + virtual void OnInspectablePropertyChanged(IInspectableItem *inProperty) = 0; +}; + +class IInspectableObject +{ +public: + virtual UICDM::CUICDMInstanceHandle GetInspectableBaseInstance() = 0; + virtual void SetInspectableObject(const UICDM::SObjectRefType &) = 0; + virtual UICDM::SObjectRefType GetInspectableObject() = 0; +}; + +class IInspectableEvent +{ +public: + virtual UICDM::CUICDMInstanceHandle GetInspectableInstance() = 0; + virtual UICDM::CUICDMEventHandle GetInspectableEvent() = 0; + virtual void SetInspectableEvent(const UICDM::CUICDMEventHandle &inEventHandle) = 0; +}; + +class IInspectableTargetSection : public IInspectableObject +{ +public: + virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0; +}; + +class IInspectableEventSection : public IInspectableObject, public IInspectableEvent +{ +public: + virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0; +}; + +class IInspectableHandlerSection +{ +public: + virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0; + virtual UICDM::CUICDMHandlerHandle GetInspectableHandler() = 0; + virtual void SetInspectableHandler(const UICDM::CUICDMHandlerHandle &inHandlerHandle) = 0; + + virtual UICDM::THandlerHandleList GetInspectableHandlerList() = 0; + virtual long GetArgumentCount() = 0; + virtual IInspectableItem *GetArgument(long inIndex) = 0; + virtual Q3DStudio::CString GetInspectableDescription() = 0; +}; + +//============================================================================== +/** + * @class IInspectableItem + * @brief Abstract base class for inspectable items. + */ +class IInspectableItem +{ +public: + virtual ~IInspectableItem() {} + virtual EInspectableItemTypes GetInspectableKind() { return INSPECTABLEITEMTYPE_VANILLA; } + + virtual UICDM::HandlerArgumentType::Value + GetInspectableSubType() const = 0; // TODO : Make this method name correct + virtual Q3DStudio::CString GetInspectableName() const = 0; + virtual Q3DStudio::CString GetInspectableFormalName() const = 0; + virtual Q3DStudio::CString GetInspectableDescription() const = 0; + + virtual UICDM::SValue GetInspectableData() const = 0; + virtual void SetInspectableData(const UICDM::SValue &) = 0; + + // TODO: Remove from here onwards after cleaning up the rest of the UI classes + // This is the non-commital version of SetInspectableData, which must be called + // after ChangeInspectableData to commit the action. + virtual bool GetInspectableReadOnly() const { return false; } + + virtual void ChangeInspectableData(const UICDM::SValue & /*inAttr*/){}; + virtual void CancelInspectableData(){} + + virtual void AddInspectableChangeListener(IInspectableItemChangeListener * /*inListener*/){}; + virtual void RemoveInspectableChangeListener(IInspectableItemChangeListener * /*inListener*/){}; +}; + +//============================================================================== +/** + * Property specialization + */ +class IInspectablePropertyItem : public IInspectableItem +{ +public: + EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_PROPERTY; } + virtual void GetInspectablePropertyList(UICDM::TPropertyHandleList &outList) = 0; + virtual UICDM::CUICDMInstanceHandle GetInspectableInstance() = 0; +}; + +//============================================================================== +/** + * Attribute specialization + */ +class IInspectableAttributeItem : public IInspectableItem +{ +public: + EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_DEPENDENT; } + virtual float GetInspectableMin() const = 0; + virtual float GetInspectableMax() const = 0; + virtual UICDM::TMetaDataStringList GetInspectableList() const = 0; + virtual UICDM::DataModelDataType::Value GetInspectableType() const = 0; + virtual UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const = 0; +}; + +//============================================================================== +/** + * Slide specialization + */ +class IInspectableSlideItem : public IInspectableItem +{ +public: + EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_SLIDE; } + virtual void GetSlideNames(std::list<Q3DStudio::CString> &outSlideNames) = 0; +}; + +//============================================================================== +/** + * ObjectReference specialiaztion + */ +class IInspectableObjectRefItem : public IInspectableObject, public IInspectableItem +{ +public: + EInspectableItemTypes GetInspectableKind() override + { + return INSPECTABLEITEMTYPE_OBJECTREFERENCE; + } +}; + +//============================================================================== +/** + * Event specialization + */ +class IInspectableEventItem : public IInspectableEvent, public IInspectableItem +{ +public: + EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_EVENTSOURCE; } +}; + +#endif // #ifndef __IINSPECTABLEITEM_H__ diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml b/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml new file mode 100644 index 00000000..7621c5ef --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + spacing: 10 + ListView { + id: listView + + anchors { + fill: parent + leftMargin: 8 + } + + boundsBehavior: Flickable.StopAtBounds + spacing: 4 + clip: true + + ScrollBar.vertical: ScrollBar {} + + model: _imageChooserModel + + delegate: ChooserDelegate { + onClicked: _imageChooserView.imageSelected(_imageChooserView.handle, _imageChooserView.instance, filePath); + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp new file mode 100644 index 00000000..98732f74 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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 "ImageChooserModel.h" + +ImageChooserModel::ImageChooserModel(QObject *parent) + : ChooserModelBase(parent) +{ +} + +ImageChooserModel::~ImageChooserModel() +{ +} + +bool ImageChooserModel::isVisible(const QString &path) const +{ + return getIconType(path) == OBJTYPE_IMAGE; +} + +const QVector<ChooserModelBase::FixedItem> ImageChooserModel::getFixedItems() const +{ + static const QVector<FixedItem> items = { { OBJTYPE_IMAGE, tr("[None]") } }; + return items; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h new file mode 100644 index 00000000..288846fd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 IMAGECHOOSERMODEL_H +#define IMAGECHOOSERMODEL_H + +#include "ChooserModelBase.h" + +class ImageChooserModel : public ChooserModelBase +{ + Q_OBJECT + +public: + explicit ImageChooserModel(QObject *parent = nullptr); + virtual ~ImageChooserModel(); + +private: + bool isVisible(const QString &path) const override; + const QVector<FixedItem> getFixedItems() const override; +}; + +#endif // IMAGECHOOSERMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp new file mode 100644 index 00000000..a3a35217 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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 "ImageChooserView.h" +#include "ImageChooserModel.h" +#include "StudioPreferences.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "IDocumentEditor.h" +#include "UICDMStudioSystem.h" +#include "UICDMValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "StudioPreferences.h" + +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +ImageChooserView::ImageChooserView(QWidget *parent) + : QQuickWidget(parent) + , m_model(new ImageChooserModel(this)) +{ + setWindowTitle(tr("Images")); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &ImageChooserView::initialize); +} + +void ImageChooserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_resDir"_L1, + resourceImageUrl()); + rootContext()->setContextProperty("_imageChooserView"_L1, this); + rootContext()->setContextProperty("_imageChooserModel"_L1, m_model); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/ImageChooser.qml"_L1)); +} + +QSize ImageChooserView::sizeHint() const +{ + return {500, 500}; +} + +void ImageChooserView::setHandle(int handle) +{ + m_handle = handle; +} + +int ImageChooserView::handle() const +{ + return m_handle; +} + +void ImageChooserView::setInstance(int instance) +{ + m_instance = instance; +} + +int ImageChooserView::instance() const +{ + return m_instance; +} + +void ImageChooserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &ImageChooserView::close); +} + +void ImageChooserView::showEvent(QShowEvent *event) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + + UICDM::SValue value; + propertySystem->GetInstancePropertyValue(m_instance, m_handle, value); + + const auto guid = UICDM::get<UICDM::SLong4>(value); + + const auto imageInstance = doc->GetDocumentReader().GetInstanceForGuid(guid); + if (imageInstance.Valid()) { + const QString path = doc->GetDocumentReader().GetSourcePath(imageInstance).toQString(); + m_model->setCurrentFile(path); + } else { + m_model->setCurrentFile(tr("[None]")); + } + + QQuickWidget::showEvent(event); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h new file mode 100644 index 00000000..f1738aa9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h @@ -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$ +** +****************************************************************************/ + +#ifndef IMAGECHOOSERVIEW_H +#define IMAGECHOOSERVIEW_H + +#include <QQuickWidget> + +class ImageChooserModel; + +class ImageChooserView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(int instance READ instance) + Q_PROPERTY(int handle READ handle) + +public: + explicit ImageChooserView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + + void setHandle(int handle); + int handle() const; + + void setInstance(int instance); + int instance() const; + +Q_SIGNALS: + void imageSelected(int handle, int instance, const QString &name); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void showEvent(QShowEvent *event) override; + void initialize(); + int m_handle = -1; + int m_instance = -1; + ImageChooserModel *m_model = nullptr; +}; + +#endif // IMAGECHOOSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp new file mode 100644 index 00000000..1c33eb23 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "InspectableBase.h" diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h new file mode 100644 index 00000000..34973393 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ +#pragma once +#ifndef __INSPECTABLEBASE_H__ +#define __INSPECTABLEBASE_H__ + +//============================================================================== +// Forwards +//============================================================================== +class CInspectorGroup; + +#include "Core.h" +#include "StudioObjectTypes.h" + +//============================================================================== +/** + * Parent class of Inspectable types that will appear in the Inspector Palette. + */ +class CInspectableBase +{ +protected: + CCore *m_Core; ///< + +public: + CInspectableBase(CCore *inCore) + : m_Core(inCore) + { + } + virtual ~CInspectableBase() {} + + // Interface + virtual EStudioObjectType GetObjectType() = 0; + // virtual std::wstring GetTypeString() const { return L""; } + virtual Q3DStudio::CString GetName() = 0; + virtual long GetGroupCount() = 0; + virtual CInspectorGroup *GetGroup(long inIndex) = 0; + virtual bool IsValid() const = 0; + virtual bool IsMaster() = 0; +}; + +#endif // #ifndef __INSPECTABLEBASE_H__ diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp new file mode 100644 index 00000000..474fc3e4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp @@ -0,0 +1,862 @@ +/**************************************************************************** +** +** 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 <QFileInfo> + +#include <functional> + +#include "InspectorControlModel.h" +#include "Core.h" +#include "Doc.h" +#include "ControlGraphIterators.h" +#include "InspectorGroup.h" +#include "UICDMInspectorGroup.h" +#include "UICDMInspectorRow.h" +#include "UICDMStudioSystem.h" +#include "UICDMInspectable.h" +#include "UICDMDataCore.h" +#include "StudioApp.h" +#include "IDocumentEditor.h" +#include "Control.h" +#include "ControlData.h" +#include "UICDMMetaData.h" +#include "UICDMSignals.h" +#include "CmdDataModelDeanimate.h" +#include "GuideInspectable.h" +#include "UICDMDataTypes.h" +#include "IObjectReferenceHelper.h" +#include "UICDMXML.h" +#include "UICDMStringTable.h" +#include "UICFileTools.h" +#include "UICDMSlideCore.h" +#include "SlideSystem.h" +#include "UICDMMaterialInspectable.h" +#include "ClientDataModelBridge.h" +#include "IDocumentReader.h" +#include "IStudioRenderer.h" + +static QStringList renderableItems() +{ + QStringList renderables; + renderables.push_back(QObject::tr("No renderable item")); + const CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + Q3DStudio::CString docDir = doc->GetDocumentDirectory(); + Q3DStudio::CFilePath fullDocPath = doc->GetDocumentPath().GetAbsolutePath(); + Q3DStudio::CString docFilename = fullDocPath.GetFileName(); + // First step, find uia file, parse and pull out renderable asset id's but ignoring the + // current presentation. + std::vector<Q3DStudio::CFilePath> dirFiles; + Q3DStudio::CFilePath thePath(docDir); + thePath.ListFilesAndDirectories(dirFiles); + for (size_t idx = 0, end = dirFiles.size(); idx < end; ++idx) { + if (!dirFiles[idx].IsFile()) + continue; + + Q3DStudio::CString ext = dirFiles[idx].GetExtension(); + if (!ext.CompareNoCase("uia")) + continue; + + UICDM::TStringTablePtr theStringTable + = UICDM::IStringTable::CreateStringTable(); + std::shared_ptr<UICDM::IDOMFactory> theDomFact = + UICDM::IDOMFactory::CreateDOMFactory(theStringTable); + Q3DStudio::CString fullFile = dirFiles[idx]; + qt3ds::foundation::CFileSeekableIOStream theStream( + fullFile, qt3ds::foundation::FileReadFlags()); + + UICDM::SDOMElement *theElem + = UICDM::CDOMSerializer::Read(*theDomFact, theStream); + if (theElem) { + std::shared_ptr<UICDM::IDOMReader> theReader = + UICDM::IDOMReader::CreateDOMReader(*theElem, theStringTable, + theDomFact); + if (theReader->MoveToFirstChild("assets")) { + for (bool success = theReader->MoveToFirstChild(); success; + success = theReader->MoveToNextSibling()) { + if (UICDM::AreEqual(theReader->GetElementName(), L"presentation") || + UICDM::AreEqual(theReader->GetElementName(), L"presentation-qml")) { + UICDM::TXMLStr src = nullptr; + UICDM::TXMLStr id = nullptr; + theReader->Att("src", src); + theReader->Att("id", id); + if (docFilename != src.c_str()) + renderables.push_back(QString::fromLatin1(id.c_str())); + } else if (UICDM::AreEqual(theReader->GetElementName(), + L"renderplugin")) { + const wchar_t *id = nullptr; + theReader->UnregisteredAtt(L"id", id); + renderables.push_back(QString::fromWCharArray(id)); + } + } + } + } + } + // second step, find the renderable plugins. + { + Q3DStudio::CFilePath pluginDir + = Q3DStudio::CFilePath::CombineBaseAndRelative(docDir, "plugins"); + if (pluginDir.Exists() && pluginDir.IsDirectory()) { + std::vector<Q3DStudio::CFilePath> dirFiles; + pluginDir.ListFilesAndDirectories(dirFiles); + for (size_t idx = 0, end = dirFiles.size(); idx < end; ++idx) { + if (dirFiles[idx].IsFile()) { + Q3DStudio::CFilePath relPath = + Q3DStudio::CFilePath::GetRelativePathFromBase(docDir, dirFiles[idx]); + renderables.push_back(relPath.toQString()); + } + } + } + } + std::sort(renderables.begin() + 1, renderables.end()); + return renderables; +} + +static std::pair<bool, bool> getSlideCharacteristics(UICDM::CUICDMInstanceHandle instance, + const UICDM::ISlideCore &slideCore, + const UICDM::ISlideSystem &slideSystem) +{ + // Get the slide from the instance. + UICDM::CUICDMSlideHandle slide = slideCore.GetSlideByInstance(instance); + UICDM::CUICDMSlideHandle master = slideSystem.GetMasterSlide(slide); + int index = (int)slideSystem.GetSlideIndex(slide); + int count = (int)slideSystem.GetSlideCount(master); + bool hasNextSlide = index > 0 && index < count - 1; + bool hasPreviousSlide = index > 1; + return std::make_pair(hasNextSlide, hasPreviousSlide); +} + +InspectorControlModel::InspectorControlModel(QObject *parent) + : QAbstractListModel(parent) + , m_UpdatableEditor(*g_StudioApp.GetCore()->GetDoc()) +{ +} + +void InspectorControlModel::setInspectable(CInspectableBase *inInspectable) +{ + const auto signalProvider + = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider(); + + if (m_notifier.get() == nullptr) { + m_notifier = signalProvider->ConnectInstancePropertyValue( + std::bind(&InspectorControlModel::notifyInstancePropertyValue, + this, std::placeholders::_1, std::placeholders::_2)); + } + if (m_slideNotifier.get() == nullptr) { + m_slideNotifier = signalProvider->ConnectSlideRearranged( + std::bind(&InspectorControlModel::onSlideRearranged, this, + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)); + } + + if (m_inspectableBase != inInspectable) { + m_inspectableBase = inInspectable; + rebuildTree(); + } +} + +void InspectorControlModel::notifyInstancePropertyValue(UICDM::CUICDMInstanceHandle inHandle, + UICDM::CUICDMPropertyHandle inProperty) +{ + auto doc = g_StudioApp.GetCore()->GetDoc(); + bool changed = false; + for (int row = 0; row < m_groupElements.count(); ++row) { + auto group = m_groupElements[row]; + for (int p = 0; p < group.controlElements.count(); ++p) { + QVariant& element = group.controlElements[p]; + InspectorControlBase *property = element.value<InspectorControlBase *>(); + UICDM::CUICDMInstanceHandle imageInstance; + if (property->m_dataType == UICDM::DataModelDataType::Long4 + && property->m_property.Valid()) { + imageInstance = doc->GetDocumentReader().GetImageInstanceForProperty( + property->m_instance, property->m_property); + } + if (property->m_property == inProperty || imageInstance == inHandle) { + updatePropertyValue(property); + changed = true; + } + } + } + if (changed) + Q_EMIT dataChanged(index(0), index(rowCount() - 1)); +} + +QVariant InspectorControlModel::getPropertyValue(long instance, int handle) +{ + for (int row = 0; row < m_groupElements.count(); ++row) { + auto group = m_groupElements[row]; + for (int p = 0; p < group.controlElements.count(); ++p) { + QVariant& element = group.controlElements[p]; + InspectorControlBase *property = element.value<InspectorControlBase *>(); + if (property->m_property == UICDM::CDataModelHandle(handle)) + return property->m_value; + } + } + return {}; +} + +void InspectorControlModel::setMaterials(std::vector<Q3DStudio::CFilePath> &materials) +{ + m_materials.clear(); + const Q3DStudio::CString base = g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory(); + + for (Q3DStudio::CFilePath path : materials) { + + const QString relativePath = path.toQString(); + const Q3DStudio::CFilePath absolutePath + = Q3DStudio::CFilePath::CombineBaseAndRelative(base, path); + + const QString name = g_StudioApp.GetCore()->GetDoc()->GetDocumentReader() + .GetCustomMaterialName(absolutePath).toQString(); + + m_materials.push_back({name, relativePath}); + } +} + +InspectorControlBase* InspectorControlModel::createMaterialItem(CUICDMInspectable *inspectable, + int groupIndex) +{ + const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); + InspectorControlBase *item = new InspectorControlBase; + item->m_instance = inspectable->GetGroupInstance(groupIndex); + + item->m_title = tr("Material Type"); + + CClientDataModelBridge *theBridge = studio->GetClientDataModelBridge(); + EStudioObjectType theType = theBridge->GetObjectType(item->m_instance); + item->m_dataType = UICDM::DataModelDataType::StringRef; + item->m_propertyType = UICDM::AdditionalMetaDataType::None; + item->m_tooltip = tr("Type of material being used or custom material"); + + item->m_animatable = false; + + QStringList values; + values.push_back(tr("Standard Material")); + values.push_back(tr("Referenced Material")); + + const QString sourcePath = theBridge->GetSourcePath(item->m_instance).toQString(); + + switch (theType) { + + case OBJTYPE_MATERIAL: + item->m_value = tr("Standard Material"); + break; + + case OBJTYPE_REFERENCEDMATERIAL: + item->m_value = tr("Referenced Material"); + break; + } + + for (size_t matIdx = 0, end = m_materials.size(); matIdx < end; ++matIdx) { + values.push_back(m_materials[matIdx].m_name); + if (m_materials[matIdx].m_relativePath == sourcePath) + item->m_value = values.last(); + } + + item->m_values = values; + + return item; +} + +InspectorControlBase* InspectorControlModel::createItem(CUICDMInspectable *inspectable, + Q3DStudio::CUICDMInspectorRow *row, + int groupIndex) +{ + return createItem(inspectable, row->GetMetaDataPropertyInfo(), groupIndex); +} + +InspectorControlBase* InspectorControlModel::createItem(CUICDMInspectable *inspectable, + const UICDM::SMetaDataPropertyInfo &metaProperty, + int groupIndex) +{ + const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); + if (metaProperty.m_IsHidden) + return nullptr; + + InspectorControlBase *item = new InspectorControlBase; + item->m_property = metaProperty.m_Property; + item->m_instance = inspectable->GetGroupInstance(groupIndex); + + Q3DStudio::CString title; + title.Assign(metaProperty.m_FormalName.c_str()); + if (title.IsEmpty()) + title.Assign(metaProperty.m_Name.c_str()); + item->m_title = title.toQString(); + + const auto propertySystem = studio->GetPropertySystem(); + item->m_dataType = propertySystem->GetDataType(metaProperty.m_Property); + item->m_propertyType = static_cast<UICDM::AdditionalMetaDataType::Value> + (propertySystem->GetAdditionalMetaDataType(item->m_instance, metaProperty.m_Property)); + item->m_tooltip = Q3DStudio::CString(metaProperty.m_Description.c_str()).toQString(); + + item->m_animatable = metaProperty.m_Animatable && + studio->GetAnimationSystem()->IsPropertyAnimatable(item->m_instance, + metaProperty.m_Property); + if (item->m_animatable) { + item->m_animated = studio->GetAnimationSystem()->IsPropertyAnimated(item->m_instance, + metaProperty.m_Property); + + // Update the Animate Toggle on undo/redo + auto signalProvider = studio->GetFullSystemSignalProvider(); + item->m_connections.push_back(signalProvider->ConnectAnimationCreated( + std::bind(&InspectorControlModel::updateAnimateToggleState, + this, item))); + + item->m_connections.push_back(signalProvider->ConnectAnimationDeleted( + std::bind(&InspectorControlModel::updateAnimateToggleState, + this, item))); + } + + // synchronize the value itself + updatePropertyValue(item); + return item; +} + +UICDM::SValue InspectorControlModel::currentPropertyValue(long instance, int handle) +{ + UICDM::SValue value; + const auto doc = g_StudioApp.GetCore()->GetDoc(); + auto studioSystem = doc->GetStudioSystem(); + const auto propertySystem = studioSystem->GetPropertySystem(); + propertySystem->GetInstancePropertyValue(instance, handle, value); + + return value; +} + +void InspectorControlModel::updateAnimateToggleState(InspectorControlBase* inItem) +{ + const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); + bool animated = studio->GetAnimationSystem()->IsPropertyAnimated(inItem->m_instance, + inItem->m_property); + if (animated != inItem->m_animated) { + inItem->m_animated = animated; + Q_EMIT inItem->animatedChanged(); + } +} + +bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase) const +{ + if (inspectBase != m_inspectableBase) + return true; + + long theCount = m_inspectableBase->GetGroupCount(); + if (m_groupElements.size() != theCount) + return true; + + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + const CInspectorGroup *theInspectorGroup = m_inspectableBase->GetGroup(theIndex); + if (m_groupElements.at(theIndex).groupTitle != theInspectorGroup->GetName()) + return true; + } + + return false; +} + +bool InspectorControlModel::isGroupRebuildRequired(CInspectableBase* inspectable, int theIndex) const +{ + Q_ASSERT(theIndex < m_groupElements.size()); + const CInspectorGroup *theInspectorGroup = inspectable->GetGroup(theIndex); + const auto existingGroup = m_groupElements.at(theIndex); + if (existingGroup.groupTitle != theInspectorGroup->GetName()) + return true; + + if (const auto cdmInspectable = dynamic_cast<CUICDMInspectable *>(inspectable)) { + int existingIndex = 0; + if (const auto group = dynamic_cast<const CUICDMInspectorGroup *>(theInspectorGroup)) { + const auto materialGroup + = dynamic_cast<const UICDMMaterialInspectorGroup *>(group); + if (materialGroup && materialGroup->isMaterialGroup()) { + auto i = existingGroup.controlElements.at(existingIndex++).value<InspectorControlBase*>(); + if (i->m_instance != cdmInspectable->GetGroupInstance(theIndex)) + return true; + } + + if ((existingGroup.controlElements.size() - existingIndex) != group->GetRows().size()) + return true; + + for (const auto row : group->GetRows()) { + auto i = existingGroup.controlElements.at(existingIndex++).value<InspectorControlBase*>(); + if (i->m_instance != cdmInspectable->GetGroupInstance(theIndex)) + return true; + + if (i->m_property != row->GetMetaDataPropertyInfo().m_Property) + return true; + } + } + } + + return false; +} + +auto InspectorControlModel::computeTree(CInspectableBase* inspectBase) + -> QVector<GroupInspectorControl> +{ + QVector<GroupInspectorControl> result; + + if (inspectBase) { + long theCount = inspectBase->GetGroupCount(); + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + result.append(computeGroup(inspectBase, theIndex)); + } + } + + return result; +} + +auto InspectorControlModel::computeGroup(CInspectableBase* inspectable, + int theIndex) + -> GroupInspectorControl +{ + CInspectorGroup* theInspectorGroup = inspectable->GetGroup(theIndex); + GroupInspectorControl result; + result.groupTitle = theInspectorGroup->GetName(); + + if (const auto cdmInspectable = dynamic_cast<CUICDMInspectable *>(inspectable)) { + if (const auto group = dynamic_cast<CUICDMInspectorGroup *>(theInspectorGroup)) { + const auto materialGroup + = dynamic_cast<UICDMMaterialInspectorGroup *>(group); + if (materialGroup && materialGroup->isMaterialGroup()) { + InspectorControlBase *item = createMaterialItem(cdmInspectable, theIndex); + if (item) { + result.controlElements.push_back(QVariant::fromValue(item)); + } + } + for (const auto row : group->GetRows()) { + InspectorControlBase *item = createItem(cdmInspectable, row, theIndex); + if (!item) + continue; + + result.controlElements.push_back(QVariant::fromValue(item)); + } + } + } else if (dynamic_cast<SGuideInspectableImpl *>(inspectable)) { + //KDAB_FIXME: load row element (How ?) + } + + return result; +} + +void InspectorControlModel::rebuildTree() +{ + beginResetModel(); + m_groupElements = computeTree(m_inspectableBase); + endResetModel(); +} + +int InspectorControlModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_groupElements.count(); +} + +void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) const +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + auto studioSystem = doc->GetStudioSystem(); + const auto propertySystem = studioSystem->GetPropertySystem(); + UICDM::SValue value; + const auto instance = element->m_instance; + propertySystem->GetInstancePropertyValue(instance, element->m_property, value); + + const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData(); + const auto info = metaDataProvider->GetMetaDataPropertyInfo( + metaDataProvider->GetMetaDataProperty(instance, element->m_property)); + switch (element->m_dataType) { + case UICDM::DataModelDataType::String: + element->m_value = UICDM::get<QString>(value); + //intentional fall-through + case UICDM::DataModelDataType::StringOrInt: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::StringList) { + QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData); + auto slideSystem = studioSystem->GetSlideSystem(); + + if (element->m_title == QStringLiteral("Play Mode")) { + std::pair<bool, bool> slideData( + getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(), + *slideSystem)); + bool hasNextSlide(slideData.first); + bool hasPreviousSlide(slideData.second); + if (!hasNextSlide && !hasPreviousSlide) + stringlist.removeAll("Play Through To..."); + } else if (element->m_title == QStringLiteral("Play Through To")) { + // the code duplication is intentional as we may ask for slide characteristics + // only if the property refers to slides + std::pair<bool, bool> slideData( + getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(), + *slideSystem)); + bool hasNextSlide(slideData.first); + bool hasPreviousSlide(slideData.second); + if (!hasNextSlide) + stringlist.removeAll("Next"); + if (!hasPreviousSlide) + stringlist.removeAll("Previous"); + + auto itemCount = stringlist.count(); + QString listOpt; + int selectedSlideHandle = 0; + int selectedIndex = -1; + UICDM::SStringOrInt stringOrInt = UICDM::get<UICDM::SStringOrInt>(value); + if (stringOrInt.GetType() == UICDM::SStringOrIntTypes::String) + listOpt = QString::fromWCharArray(UICDM::get<UICDM::TDataStrPtr> + (stringOrInt.m_Value)->GetData()); + else + selectedSlideHandle = UICDM::get<long>(stringOrInt.m_Value); + + selectedIndex = stringlist.indexOf(listOpt); + // Add the slide names (exclude the master slide) + auto bridge = studioSystem->GetClientDataModelBridge(); + auto slideHandle = slideSystem->GetSlideByInstance(instance); + auto masterSlide = slideSystem->GetMasterSlide(slideHandle); + long slideCount = (long)slideSystem->GetSlideCount(masterSlide); + for (long slideIndex = 1; slideIndex < slideCount; ++slideIndex) { + auto currentSlide = slideSystem->GetSlideByIndex(masterSlide, slideIndex); + auto currentInstance = slideSystem->GetSlideInstance(currentSlide); + + QString slideName = bridge->GetName(currentInstance).toQString(); + //hack to add a separator before the item + if (slideIndex == 1 && itemCount > 0) + slideName += "|separator"; + stringlist.append(slideName); + + if (currentSlide.GetHandleValue() == selectedSlideHandle) + selectedIndex = slideIndex + itemCount - 1; + } + + element->m_value = QString(selectedIndex > 0 ? stringlist[selectedIndex] + : stringlist.first()).replace("|separator", ""); + } + element->m_values = stringlist; + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Import) { + QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData); + element->m_values = stringlist; + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Renderable) { + element->m_values = renderableItems(); + if (element->m_value.toString().isEmpty()) + element->m_value = element->m_values.toStringList().at(0); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::MultiLine) { + element->m_value = UICDM::get<QString>(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Font) { + std::vector<Q3DStudio::CString> fontNames; + g_StudioApp.GetCore()->GetDoc()->GetProjectFonts(fontNames); + QStringList possibleValues; + for (const auto &fontName: fontNames) + possibleValues.append(fontName.toQString()); + element->m_values = possibleValues; + element->m_value = UICDM::get<QString>(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Mesh) { + QString meshValue = UICDM::get<QString>(value); + Q3DStudio::CFilePath theSelectionItem(Q3DStudio::CString::fromQString(meshValue)); + Q3DStudio::CFilePath theSelectionWithoutId(theSelectionItem.GetPathWithoutIdentifier()); + if (theSelectionWithoutId.size()) + element->m_value = theSelectionWithoutId.GetFileName().toQString(); + else + element->m_value = theSelectionItem.GetIdentifier().toQString(); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Texture) { + QFileInfo fileInfo(UICDM::get<QString>(value)); + element->m_value = fileInfo.fileName(); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::PathBuffer) { + element->m_value = UICDM::get<QString>(value); + } else { + qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:" + << element->m_dataType << " element->m_propertyType : " + << element->m_propertyType; + } + break; + case UICDM::DataModelDataType::StringRef: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) { + element->m_value = UICDM::get<QString>(value); + } + break; + case UICDM::DataModelDataType::Bool: + element->m_value = UICDM::get<bool>(value); + break; + case UICDM::DataModelDataType::Long4: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::Image) { + UICDM::Option<UICDM::SLong4> guid = UICDM::get<UICDM::SLong4>(value); + UICDM::CUICDMInstanceHandle imageInstance = doc->GetDocumentReader() + .GetInstanceForGuid(guid); + if (imageInstance.Valid()) { + Q3DStudio::CString path = doc->GetDocumentReader().GetSourcePath(imageInstance); + Q3DStudio::CFilePath relPath(path); + element->m_value = QVariant(relPath.GetFileName().toQString()); + } else { + element->m_value = QVariant(QString("")); + } + } else { + qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:" + << element->m_dataType << " " << element->m_title; + } + break; + case UICDM::DataModelDataType::Long: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::Range) { + element->m_value = UICDM::get<int>(value); + const UICDM::SMetaDataRange ranges = UICDM::get<UICDM::SMetaDataRange>(info->m_MetaDataData); + const QList<double> rangesValues{ranges.m_Min, ranges.m_Max}; + element->m_values = QVariant::fromValue<QList<double> >(rangesValues); + } + else if (element->m_propertyType == UICDM::AdditionalMetaDataType::ShadowMapResolution) { + element->m_value = UICDM::get<int>(value); + } else { + qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:" + << element->m_dataType; + } + break; + case UICDM::DataModelDataType::Float3: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::Color) { + element->m_value = UICDM::get<QColor>(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Rotation) { + const QVector3D theFloat3 = UICDM::get<QVector3D>(value); + const QList<double> float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()}; + element->m_values = QVariant::fromValue<QList<double> >(float3Values); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) { + const QVector3D theFloat3 = UICDM::get<QVector3D>(value); + const QList<double> float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()}; + element->m_values = QVariant::fromValue<QList<double> >(float3Values); + } + break; + case UICDM::DataModelDataType::Float: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) { + element->m_value = UICDM::get<float>(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Range) { + element->m_value = UICDM::get<float>(value); + const UICDM::SMetaDataRange ranges = UICDM::get<UICDM::SMetaDataRange>(info->m_MetaDataData); + const QList<double> rangesValues{ranges.m_Min, ranges.m_Max}; + element->m_values = QVariant::fromValue<QList<double> >(rangesValues); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::FontSize) { + element->m_value = UICDM::get<float>(value); + } + break; + case UICDM::DataModelDataType::ObjectRef: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::ObjectRef) { + IObjectReferenceHelper *objRefHelper = doc->GetDataModelObjectReferenceHelper(); + if (objRefHelper) { + UICDM::CUICDMInstanceHandle refInstance = objRefHelper->Resolve(value, instance); + element->m_value = objRefHelper->LookupObjectFormalName(refInstance).toQString(); + } + } + break; + default: + qWarning() << "TODO: InspectorControlModel::updatePropertyValue: I've no idea how to handle this datatype" + << element->m_dataType; + break; + } + Q_EMIT element->valueChanged(); + Q_EMIT element->valuesChanged(); +} + +void InspectorControlModel::refreshRenderables() +{ + for (int row = 0; row < m_groupElements.count(); ++row) { + auto group = m_groupElements[row]; + for (int p = 0; p < group.controlElements.count(); ++p) { + QVariant& element = group.controlElements[p]; + InspectorControlBase *property = element.value<InspectorControlBase *>(); + if (property->m_propertyType == UICDM::AdditionalMetaDataType::Renderable) + updatePropertyValue(property); + } + } +} + +void InspectorControlModel::refresh() +{ + for (int row = 0; row < m_groupElements.count(); ++row) { + auto group = m_groupElements[row]; + for (int p = 0; p < group.controlElements.count(); ++p) { + QVariant& element = group.controlElements[p]; + InspectorControlBase *property = element.value<InspectorControlBase *>(); + if (property->m_property.Valid()) + updatePropertyValue(property); + } + } + Q_EMIT dataChanged(index(0), index(rowCount() - 1)); +} + +void InspectorControlModel::setMaterialTypeValue(long instance, int handle, const QVariant &value) +{ + Q_UNUSED(handle); + const QString typeValue = value.toString(); + Q3DStudio::CString v; + + if (typeValue == tr("Standard Material")) { + v = Q3DStudio::CString("Standard Material"); + } else if (typeValue == tr("Referenced Material")) { + v = Q3DStudio::CString("Referenced Material"); + } else { + for (size_t matIdx = 0, end = m_materials.size(); matIdx < end; ++matIdx) { + if (m_materials[matIdx].m_name == typeValue) { + v = Q3DStudio::CString::fromQString(m_materials[matIdx].m_relativePath); + break; + } + } + } + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), + QObject::tr("Set Property"))->SetMaterialType(instance, v); +} + +void InspectorControlModel::setRenderableValue(long instance, int handle, const QVariant &value) +{ + UICDM::SValue oldValue = currentPropertyValue(instance, handle); + + QString v = value.toString(); + if (v == QObject::tr("No renderable item")) + v = QString(); + + if (v == UICDM::get<QString>(oldValue)) + return; + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property")) + ->SetInstancePropertyValueAsRenderable(instance, handle, + Q3DStudio::CString::fromQString(v)); +} + +void InspectorControlModel::setPropertyValue(long instance, int handle, const QVariant &value, bool commit) +{ + UICDM::SValue oldValue = currentPropertyValue(instance, handle); + UICDM::SValue v = value; + + if (v == oldValue) + return; + + // some properties may initialize OpenGL resources (e.g. loading meshes will + // initialize vertex buffers), so the renderer's OpenGL context must be current + Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.GetRenderer()); + theRenderer.MakeContextCurrent(); + + m_UpdatableEditor.EnsureEditor(L"Set Property", __FILE__, __LINE__) + .SetInstancePropertyValue(instance, handle, v); + + theRenderer.ReleaseContext(); + + m_UpdatableEditor.FireImmediateRefresh(instance); + + if (commit) { + m_UpdatableEditor.CommitEditor(); + + if (isTreeRebuildRequired(m_inspectableBase)) { + rebuildTree(); + } else { + // group strucutre is intact, let's walk to see which rows changed + long theCount = m_inspectableBase->GetGroupCount(); + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + if (isGroupRebuildRequired(m_inspectableBase, theIndex)) { + m_groupElements[theIndex] = computeGroup(m_inspectableBase, theIndex); + Q_EMIT dataChanged(index(theIndex), index(theIndex)); + } + } + } + + } // of commit +} + +void InspectorControlModel::setSlideSelection(long instance, int handle, int index, + const QStringList &list) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + auto studioSystem = doc->GetStudioSystem(); + const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData(); + const auto info = metaDataProvider->GetMetaDataPropertyInfo( + metaDataProvider->GetMetaDataProperty(instance, handle)); + QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData); + + auto slideSystem = studioSystem->GetSlideSystem(); + std::pair<bool, bool> slideData( + getSlideCharacteristics(instance, *studioSystem->GetSlideCore(), + *slideSystem)); + bool hasNextSlide(slideData.first); + bool hasPreviousSlide(slideData.second); + UICDM::SStringOrInt newSelectedData; + if (!hasNextSlide) + stringlist.removeAll("Next"); + if (!hasPreviousSlide) + stringlist.removeAll("Previous"); + + auto itemCount = stringlist.count(); + if (index < itemCount) { + newSelectedData = UICDM::SStringOrInt(std::make_shared<UICDM::CDataStr> + (Q3DStudio::CString::fromQString(list[index]).c_str())); + } else { + auto slideHandle = slideSystem->GetSlideByInstance(instance); + auto masterSlide = slideSystem->GetMasterSlide(slideHandle); + long slideIndex = index - itemCount + 1; + auto newSelectedSlide = slideSystem->GetSlideByIndex(masterSlide, slideIndex); + newSelectedData = UICDM::SStringOrInt((long)newSelectedSlide); + } + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property")) + ->SetInstancePropertyValue(instance, handle, newSelectedData); +} + +void InspectorControlModel::setPropertyAnimated(long instance, int handle, bool animated) +{ + CCmd* cmd = nullptr; + auto doc = g_StudioApp.GetCore()->GetDoc(); + if (animated) + cmd = new CCmdDataModelAnimate(doc, instance, handle); + else + cmd = new CCmdDataModelDeanimate(doc, instance, handle); + + g_StudioApp.GetCore()->ExecuteCommand(cmd); +} + +void InspectorControlModel::onSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, + int inOldIndex, int inNewIndex) +{ + Q_UNUSED(inMaster); + Q_UNUSED(inOldIndex); + Q_UNUSED(inNewIndex); + rebuildTree(); +} + +QVariant InspectorControlModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return {}; + + const auto row = index.row(); + + switch (role) { + case GroupValuesRole: + return m_groupElements.at(row).controlElements; + case GroupTitleRole: + return m_groupElements.at(row).groupTitle; + } + return {}; +} + +QHash<int, QByteArray> InspectorControlModel::roleNames() const +{ + auto names = QAbstractListModel::roleNames(); + names.insert(GroupValuesRole, "values"); + names.insert(GroupTitleRole, "title"); + return names; +} + +InspectorControlBase::~InspectorControlBase() +{ +} diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h new file mode 100644 index 00000000..20718039 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** 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 INSPECTORCONTROLMODEL_H +#define INSPECTORCONTROLMODEL_H + +#include <QtCore/qabstractitemmodel.h> +#include <QtCore/qvector.h> + +#include "UICDMValue.h" +#include "UICDMMetaDataValue.h" +#include "UICDMMetaDataTypes.h" +#include "UICFileTools.h" + +#include "IDocumentEditor.h" + +class CInspectableBase; +class CUICDMInspectable; +class SGuideInspectableImpl; + +namespace UICDM { +class ISignalConnection; +typedef std::shared_ptr<ISignalConnection> TSignalConnectionPtr; +} + +namespace Q3DStudio +{ +class CUICDMInspectorRow; +} + +class InspectorControlBase : public QObject +{ + Q_OBJECT + Q_PROPERTY(UICDM::DataModelDataType::Value dataType MEMBER m_dataType CONSTANT) + Q_PROPERTY(UICDM::AdditionalMetaDataType::Value propertyType MEMBER m_propertyType CONSTANT) + Q_PROPERTY(QVariant value MEMBER m_value NOTIFY valueChanged) + Q_PROPERTY(QVariant values MEMBER m_values NOTIFY valuesChanged) + Q_PROPERTY(QString title MEMBER m_title CONSTANT) + Q_PROPERTY(QString toolTip MEMBER m_tooltip CONSTANT) + Q_PROPERTY(int instance MEMBER m_instance CONSTANT) + Q_PROPERTY(int handle MEMBER m_property CONSTANT) + + Q_PROPERTY(bool animatable MEMBER m_animatable CONSTANT) + Q_PROPERTY(bool animated MEMBER m_animated NOTIFY animatedChanged) + +public: + virtual ~InspectorControlBase(); + +Q_SIGNALS: + void valueChanged(); + void valuesChanged(); + void animatedChanged(); + +public: + UICDM::DataModelDataType::Value m_dataType; + UICDM::AdditionalMetaDataType::Value m_propertyType; + QVariant m_value; + QVariant m_values; + QString m_title; + QString m_tooltip; + + UICDM::CUICDMInstanceHandle m_instance; + UICDM::CUICDMPropertyHandle m_property; + + bool m_animatable = false; + bool m_animated = false; + + std::vector<UICDM::TSignalConnectionPtr> m_connections; +}; + +class InspectorControlModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit InspectorControlModel(QObject *parent); + ~InspectorControlModel() = default; + + enum Roles { + GroupValuesRole = Qt::UserRole + 1, + GroupTitleRole + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + + QHash<int, QByteArray> roleNames() const override; + + void setInspectable(CInspectableBase *inInspectable); + void setMaterials(std::vector<Q3DStudio::CFilePath> &materials); + void refreshRenderables(); + void refresh(); + + QVariant getPropertyValue(long instance, int handle); + + Q_INVOKABLE void setMaterialTypeValue(long instance, int handle, const QVariant &value); + Q_INVOKABLE void setRenderableValue(long instance, int handle, const QVariant &value); + Q_INVOKABLE void setPropertyValue(long instance, int handle, const QVariant &value, bool commit = true); + Q_INVOKABLE void setSlideSelection(long instance, int handle, int index, + const QStringList &list); + Q_INVOKABLE void setPropertyAnimated(long instance, int handle, bool animated); + +private: + void onSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex, + int inNewIndex); + + + struct GroupInspectorControl { + QString groupTitle; + QVariantList controlElements; + + ~GroupInspectorControl() { + //for (auto element : controlElements) + // element.value<QObject *>()->deleteLater(); + } + }; + + mutable QVector<GroupInspectorControl> m_groupElements; + CInspectableBase *m_inspectableBase = nullptr; + + struct MaterialEntry + { + QString m_name; + QString m_relativePath; + }; + + std::vector<MaterialEntry> m_materials; + + Q3DStudio::CUpdateableDocumentEditor m_UpdatableEditor; + + void updatePropertyValue(InspectorControlBase *element) const; + void rebuildTree(); + void notifyInstancePropertyValue(UICDM::CUICDMInstanceHandle, UICDM::CUICDMPropertyHandle inProperty); + void updateAnimateToggleState(InspectorControlBase* inItem); + + std::shared_ptr<UICDM::ISignalConnection> m_notifier; + std::shared_ptr<UICDM::ISignalConnection> m_slideNotifier; + + InspectorControlBase *createMaterialItem(CUICDMInspectable *inspectable, int groupIndex); + InspectorControlBase *createItem(CUICDMInspectable *inspectable, + Q3DStudio::CUICDMInspectorRow *row, int groupIndex); + InspectorControlBase *createItem(CUICDMInspectable *inspectable, + const UICDM::SMetaDataPropertyInfo &metaProperty, + int groupIndex); + + UICDM::SValue currentPropertyValue(long instance, int handle); + + QVector<GroupInspectorControl> computeTree(CInspectableBase *inspectBase); + bool isTreeRebuildRequired(CInspectableBase *inspectBase) const; + + GroupInspectorControl computeGroup(CInspectableBase* inspectBase, int theIndex); + bool isGroupRebuildRequired(CInspectableBase *inspectable, int theIndex) const; + +}; + +#endif // INSPECTORCONTROLMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp new file mode 100644 index 00000000..3079c02a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** 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 "InspectorControlView.h" +#include "Literals.h" +#include "CColor.h" +#include "UICDMValue.h" +#include "StudioUtils.h" +#include "InspectorControlModel.h" +#include "StudioPreferences.h" +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> +#include <QtWidgets/qmenu.h> +#include "Core.h" +#include "Doc.h" +#include "IDocumentEditor.h" +#include "ImageChooserModel.h" +#include "ImageChooserView.h" +#include "MeshChooserView.h" +#include "TextureChooserView.h" +#include "InspectableBase.h" +#include "StudioApp.h" +#include "ObjectListModel.h" +#include "ObjectBrowserView.h" +#include "IDirectoryWatchingSystem.h" +#include "StandardExtensions.h" +#include "FileChooserView.h" +#include "IObjectReferenceHelper.h" +#include "UICDMStudioSystem.h" +#include "StudioFullSystem.h" + +InspectorControlView::InspectorControlView(QWidget *parent) + : QQuickWidget(parent), + TabNavigable(), + m_inspectorControlModel(new InspectorControlModel(this)), + m_instance(0), + m_handle(0) +{ + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &InspectorControlView::initialize); + auto dispatch = g_StudioApp.GetCore()->GetDispatch(); + dispatch->AddPresentationChangeListener(this); + dispatch->AddDataModelListener(this); + + m_selectionChangedConnection = g_StudioApp.GetCore()->GetDispatch()->ConnectSelectionChange( + std::bind(&InspectorControlView::OnSelectionSet, this, std::placeholders::_1)); +} + +const wchar_t **AllSupportedExtensionsList() +{ + static const wchar_t *extensions[] = { + L"png", L"jpg", L"jpeg", L"dds", L"hdr", + L"mesh", L"import", L"path", + L"material", + nullptr + }; + return extensions; +} + +static bool isInList(const wchar_t **list, const Q3DStudio::CString &inStr) +{ + for (const wchar_t **item = list; item && *item; ++item) { + if (inStr.Compare(*item, Q3DStudio::CString::ENDOFSTRING, false)) + return true; + } + return false; +} + +void InspectorControlView::filterMaterials(std::vector<Q3DStudio::CFilePath> &materials) +{ + static const wchar_t *extensions[] = { + L"material", + nullptr + }; + for (size_t i = 0; i < m_fileList.size(); ++i) { + if (isInList(extensions, m_fileList[i].GetExtension())) + materials.push_back(m_fileList[i]); + } +} + +void InspectorControlView::OnNewPresentation() +{ + m_DirectoryConnection = g_StudioApp.GetDirectoryWatchingSystem().AddDirectory( + g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory().toQString(), + std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1)); +} + +void InspectorControlView::OnClosingPresentation() +{ + m_fileList.clear(); +} + +void InspectorControlView::OnLoadedSubPresentation() +{ + m_DirectoryConnection = g_StudioApp.GetDirectoryWatchingSystem().AddDirectory( + g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory().toQString(), + std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1)); +} + +void InspectorControlView::onFilesChanged( + const Q3DStudio::TFileModificationList &inFileModificationList) +{ + const wchar_t **extensions = AllSupportedExtensionsList(); + for (size_t idx = 0, end = inFileModificationList.size(); idx < end; ++idx) { + const Q3DStudio::SFileModificationRecord &record(inFileModificationList[idx]); + if (record.m_FileInfo.IsFile() + && isInList(extensions, record.m_File.GetExtension())) { + Q3DStudio::CFilePath relativePath( + Q3DStudio::CFilePath::GetRelativePathFromBase( + g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory(), + record.m_File)); + + if (record.m_ModificationType == Q3DStudio::FileModificationType::Created) + UICDM::binary_sort_insert_unique(m_fileList, relativePath); + else if (record.m_ModificationType == Q3DStudio::FileModificationType::Destroyed) + UICDM::binary_sort_erase(m_fileList, relativePath); + } + if (record.m_FileInfo.IsFile() + && record.m_ModificationType == Q3DStudio::FileModificationType::Modified) { + if (record.m_File.toQString() == g_StudioApp.GetCore()->GetDoc() + ->GetDocumentUIAFile()) { + m_inspectorControlModel->refreshRenderables(); + } + } + } + std::vector<Q3DStudio::CFilePath> materials; + filterMaterials(materials); + m_inspectorControlModel->setMaterials(materials); +} + +InspectorControlView::~InspectorControlView() +{ + g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this); +} + +QSize InspectorControlView::sizeHint() const +{ + return {120, 600}; +} + +void InspectorControlView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_inspectorView"_L1, this); + rootContext()->setContextProperty("_inspectorModel"_L1, m_inspectorControlModel); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + rootContext()->setContextProperty("_tabOrderHandler"_L1, tabOrderHandler()); + qmlRegisterUncreatableType<UICDM::DataModelDataType>("Qt3DStudio", 1, 0, "DataModelDataType", + "DataModelDataType is an enum container"); + qmlRegisterUncreatableType<UICDM::AdditionalMetaDataType>( + "Qt3DStudio", 1, 0, "AdditionalMetaDataType", + "AdditionalMetaDataType is an enum container"); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/InspectorControlView.qml"_L1)); +} + +QAbstractItemModel *InspectorControlView::inspectorControlModel() const +{ + return m_inspectorControlModel; +} + +QString InspectorControlView::titleText() const +{ + if (m_inspectableBase) { + Q3DStudio::CString theName = m_inspectableBase->GetName(); + if (theName == L"PathAnchorPoint") + return tr("Anchor Point"); + else + return theName.toQString(); + } + return tr("No Object Selected"); +} + +QColor InspectorControlView::titleColor(int instance, int handle) const +{ + if (instance != 0 && handle != 0) { + if (g_StudioApp.GetCore()->GetDoc()->GetDocumentReader().IsPropertyLinked(instance, handle)) + return CStudioPreferences::masterColor(); + else + return CStudioPreferences::textColor(); + } else { + return CStudioPreferences::textColor(); + } +} + +QString InspectorControlView::titleIcon() const +{ + if (m_inspectableBase) + return CStudioObjectTypes::GetNormalIconName(m_inspectableBase->GetObjectType()); + return {}; +} + +void InspectorControlView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable) +{ + updateInspectable(g_StudioApp.GetInspectableFromSelectable(inSelectable)); +} + +void InspectorControlView::updateInspectable(CInspectableBase *inInspectable) +{ + if (inInspectable != nullptr) { + if (inInspectable->IsValid() == false) + inInspectable = nullptr; + } + setInspectable(inInspectable); +} + +void InspectorControlView::setInspectable(CInspectableBase *inInspectable) +{ + if (m_inspectableBase != inInspectable) { + m_inspectableBase = inInspectable; + m_inspectorControlModel->setInspectable(inInspectable); + Q_EMIT titleChanged(); + auto sp = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystem()->GetSignalProvider(); + m_PropertyChangeConnection = sp->ConnectInstancePropertyValue( + std::bind(&InspectorControlView::titleChanged, this)); + } +} + +void InspectorControlView::showContextMenu(int x, int y, int handle, int instance) +{ + m_instance = instance; + m_handle = handle; + + QMenu theContextMenu; + + auto doc = g_StudioApp.GetCore()->GetDoc(); + bool isLinkedFlag = doc->GetDocumentReader().IsPropertyLinked(instance, handle); + bool canBeLinkedFlag = doc->GetDocumentReader().CanPropertyBeLinked(instance, handle); + if (isLinkedFlag) { + auto action = theContextMenu.addAction(QObject::tr("Unlink Property from Master Slide")); + action->setEnabled(canBeLinkedFlag); + connect(action, &QAction::triggered, this, &InspectorControlView::toggleMasterLink); + } else { + auto action = theContextMenu.addAction(QObject::tr("Link Property from Master Slide")); + action->setEnabled(canBeLinkedFlag); + connect(action, &QAction::triggered, this, &InspectorControlView::toggleMasterLink); + } + theContextMenu.exec(mapToGlobal({x, y})); + + m_instance = 0; + m_handle = 0; +} + +void InspectorControlView::toggleMasterLink() +{ + Q3DStudio::ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(), + L"Link Property", __FILE__, __LINE__); + bool wasLinked = editor->IsPropertyLinked(m_instance, m_handle); + + if (wasLinked) + editor->UnlinkProperty(m_instance, m_handle); + else + editor->LinkProperty(m_instance, m_handle); +} + +void InspectorControlView::setPropertyValueFromFilename(long instance, int handle, + const QString &name) +{ + if (m_inspectorControlModel) { + QString value; + if (name != tr("[None]")) + value = name; + m_inspectorControlModel->setPropertyValue(instance, handle, value); + } +} + +QObject *InspectorControlView::showImageChooser(int handle, int instance, const QPoint &point) +{ + if (!m_imageChooserView) { + m_imageChooserView = new ImageChooserView(this); + connect(m_imageChooserView, &ImageChooserView::imageSelected, this, + [this] (int handle, int instance, const QString &imageName){ + setPropertyValueFromFilename(instance, handle, imageName); + m_imageChooserView->hide(); + }); + } + + m_imageChooserView->setHandle(handle); + m_imageChooserView->setInstance(instance); + + showBrowser(m_imageChooserView, point); + + return m_imageChooserView; +} + +QObject *InspectorControlView::showFilesChooser(int handle, int instance, const QPoint &point) +{ + if (!m_fileChooserView) { + m_fileChooserView = new FileChooserView(this); + connect(m_fileChooserView, &FileChooserView::fileSelected, this, + [this] (int handle, int instance, const QString &fileName){ + setPropertyValueFromFilename(instance, handle, fileName); + m_fileChooserView->hide(); + }); + } + + m_fileChooserView->setHandle(handle); + m_fileChooserView->setInstance(instance); + + showBrowser(m_fileChooserView, point); + + return m_fileChooserView; +} + +QObject *InspectorControlView::showMeshChooser(int handle, int instance, const QPoint &point) +{ + if (!m_meshChooserView) { + m_meshChooserView = new MeshChooserView(this); + connect(m_meshChooserView, &MeshChooserView::meshSelected, this, + [this] (int handle, int instance, const QString &name){ + if (m_inspectorControlModel) + m_inspectorControlModel->setPropertyValue(instance, handle, name); + }); + } + + m_meshChooserView->setHandle(handle); + m_meshChooserView->setInstance(instance); + + showBrowser(m_meshChooserView, point); + + return m_meshChooserView; +} + +QObject *InspectorControlView::showTextureChooser(int handle, int instance, const QPoint &point) +{ + if (!m_textureChooserView) { + m_textureChooserView = new TextureChooserView(this); + connect(m_textureChooserView, &TextureChooserView::textureSelected, this, + [this] (int handle, int instance, const QString &fileName){ + setPropertyValueFromFilename(instance, handle, fileName); + m_textureChooserView->hide(); + }); + } + + m_textureChooserView->setHandle(handle); + m_textureChooserView->setInstance(instance); + + showBrowser(m_textureChooserView, point); + + return m_textureChooserView; +} + +QObject *InspectorControlView::showObjectReference(int handle, int instance, const QPoint &point) +{ + CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + if (!m_objectReferenceModel) { + m_objectReferenceModel + = new ObjectListModel(g_StudioApp.GetCore(), doc->GetActiveRootInstance(), this); + } + if (!m_objectReferenceView) + m_objectReferenceView = new ObjectBrowserView(this); + m_objectReferenceView->setModel(m_objectReferenceModel); + + disconnect(m_objectReferenceView); + + showBrowser(m_objectReferenceView, point); + + connect(m_objectReferenceView, &ObjectBrowserView::selectionChanged, + this, [this, doc, handle, instance] { + auto selectedItem = m_objectReferenceView->selectedHandle(); + UICDM::SObjectRefType objRef = doc->GetDataModelObjectReferenceHelper()->GetAssetRefValue( + selectedItem, handle, + (CRelativePathTools::EPathType)(m_objectReferenceView->pathType())); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property")) + ->SetInstancePropertyValue(instance, handle, objRef); + }); + + return m_objectReferenceView; +} + +void InspectorControlView::showBrowser(QQuickWidget *browser, const QPoint &point) +{ + QSize popupSize = CStudioPreferences::browserPopupSize(); + browser->resize(popupSize); + browser->move(point - QPoint(popupSize.width(), popupSize.height())); + + // Show asynchronously to avoid flashing blank window on first show + QTimer::singleShot(0, this, [browser] { + browser->show(); + browser->activateWindow(); + browser->setFocus(); + }); +} + +void InspectorControlView::OnBeginDataModelNotifications() +{ + +} + +void InspectorControlView::OnEndDataModelNotifications() +{ + m_inspectorControlModel->refresh(); +} + +void InspectorControlView::OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) +{ + m_inspectorControlModel->refresh(); +} + +void InspectorControlView::OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount) +{ + m_inspectorControlModel->refresh(); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h new file mode 100644 index 00000000..e5815e6c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 INSPECTORCONTROLVIEW_H +#define INSPECTORCONTROLVIEW_H + +#include <QtQuickWidgets/qquickwidget.h> +#include <QtCore/qpointer.h> +#include "DispatchListeners.h" +#include "Dispatch.h" +#include "UICFileTools.h" +#include "TabOrderHandler.h" + +class InspectorControlModel; +class QAbstractItemModel; +class CInspectableBase; +class ImageChooserView; +class ImageChooserModel; +class MeshChooserView; +class ObjectBrowserView; +class ObjectListModel; +class FileChooserView; +class TextureChooserView; + +class InspectorControlView : public QQuickWidget, + public CPresentationChangeListener, + public IDataModelListener, + public TabNavigable +{ + Q_OBJECT + Q_PROPERTY(QString titleText READ titleText NOTIFY titleChanged FINAL) + Q_PROPERTY(QString titleIcon READ titleIcon NOTIFY titleChanged FINAL) +public: + explicit InspectorControlView(QWidget *parent = nullptr); + ~InspectorControlView(); + + void OnSelectionSet(Q3DStudio::SSelectedValue inValue); + QAbstractItemModel *inspectorControlModel() const; + + QString titleText() const; + Q_INVOKABLE QColor titleColor(int instance = 0, int handle = 0) const; + QString titleIcon() const; + + Q_INVOKABLE void showContextMenu(int x, int y, int handle, int instance); + Q_INVOKABLE QObject *showImageChooser(int handle, int instance, const QPoint &point); + Q_INVOKABLE QObject *showFilesChooser(int handle, int instance, const QPoint &point); + Q_INVOKABLE QObject *showMeshChooser(int handle, int instance, const QPoint &point); + Q_INVOKABLE QObject *showObjectReference(int handle, int instance, const QPoint &point); + Q_INVOKABLE QObject *showTextureChooser(int handle, int instance, const QPoint &point); + + // IDataModelListener + void OnBeginDataModelNotifications() override; + void OnEndDataModelNotifications() override; + void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override; + void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, + long inInstanceCount) override; + + +Q_SIGNALS: + void titleChanged(); + void controlsChanged(); + void imageSelected(const QString &name); + +public Q_SLOTS: + void toggleMasterLink(); + +protected: + QSize sizeHint() const override; + +private: + void setInspectable(CInspectableBase *inInspectable); + void updateInspectable(CInspectableBase *inInspectable); + void initialize(); + void onFilesChanged(const Q3DStudio::TFileModificationList &inFileModificationList); + void OnNewPresentation() override; + void OnClosingPresentation() override; + void OnLoadedSubPresentation() override; + void filterMaterials(std::vector<Q3DStudio::CFilePath> &materials); + void setPropertyValueFromFilename(long instance, int handle, const QString &name); + void showBrowser(QQuickWidget *browser, const QPoint &point); + + std::shared_ptr<UICDM::ISignalConnection> m_selectionChangedConnection; + std::shared_ptr<UICDM::ISignalConnection> m_DirectoryConnection; + std::shared_ptr<UICDM::ISignalConnection> m_PropertyChangeConnection; + QColor m_backgroundColor; + InspectorControlModel *m_inspectorControlModel = nullptr; + CInspectableBase *m_inspectableBase = nullptr; + QPointer<ImageChooserView> m_imageChooserView; + QPointer<MeshChooserView> m_meshChooserView; + QPointer<FileChooserView> m_fileChooserView; + QPointer<TextureChooserView> m_textureChooserView; + QPointer<ObjectBrowserView> m_objectReferenceView; + QPointer<ObjectListModel> m_objectReferenceModel; + std::vector<Q3DStudio::CFilePath> m_fileList; + + int m_instance; + int m_handle; +}; + +#endif // INSPECTORCONTROLVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml new file mode 100644 index 00000000..9e838d4c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml @@ -0,0 +1,771 @@ +/**************************************************************************** +** +** 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.Layouts 1.1 +import QtQuick.Controls 2.2 + +import Qt3DStudio 1.0 +import "../controls" +import "../Action" + +Rectangle { + id: root + color: _backgroundColor + + Connections { + target: _inspectorModel + onModelAboutToBeReset: { + _tabOrderHandler.clear(); + } + } + + ColumnLayout { + anchors.fill: parent + anchors.topMargin: 4 + spacing: 8 + + RowLayout { + height: _controlBaseHeight + anchors.margins * 2 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 4 + + Image { + id: headerImage + source: _inspectorView.titleIcon !== "" ? _resDir + _inspectorView.titleIcon : "" + } + + StyledLabel { + text: _inspectorView.titleText + color: _inspectorView.titleColor() + } + } + + ListView { + id: groupElements + + Layout.fillWidth: true + Layout.fillHeight: true + + spacing: 4 + + clip: true + + ScrollBar.vertical: ScrollBar { + visible: size < 1.0 + } + + model: _inspectorModel + delegate: Rectangle { + id: delegateItem + + property int indexOfThisDelegate: index + + width: parent.width + height: items.height + color: "transparent"; + + readonly property var values: model.values + + Column { + id: items + + x: 10 + width: parent.width - x + spacing: 4 + + StyledLabel { + text: model.title + } + + Column { + spacing: 4 + + Repeater { + model: delegateItem.values + + onItemAdded: { + if (index === 0) + _tabOrderHandler.clearGroup(indexOfThisDelegate); + if (item.loadedItem.tabItem1 !== undefined) { + _tabOrderHandler.addItem(indexOfThisDelegate, + item.loadedItem.tabItem1) + if (item.loadedItem.tabItem2 !== undefined) { + _tabOrderHandler.addItem( + indexOfThisDelegate, + item.loadedItem.tabItem2) + if (item.loadedItem.tabItem3 !== undefined) { + _tabOrderHandler.addItem( + indexOfThisDelegate, + item.loadedItem.tabItem3) + } + } + } + } + + RowLayout { + id: groupDelegateItem + spacing: 0 + + property alias loadedItem: loader.item + + function showContextMenu(coords) { + _inspectorView.showContextMenu( + coords.x, coords.y, + model.modelData.handle, + model.modelData.instance); + // Refresh text; title color is wrong after this + propertyRow.color = _inspectorView.titleColor( + modelData.instance, modelData.handle); + } + + Item { + Layout.alignment: Qt.AlignTop + width: animatedPropertyButton.sourceSize.width + height: _controlBaseHeight + visible: model.modelData.animatable + Image { + id: animatedPropertyButton + + property bool animated: model.modelData.animated + + anchors.fill: parent + fillMode: Image.Pad + + source: { + _resDir + (animated + ? "Inspector-AnimateToggle-Active.png" + : "Inspector-AnimateToggle-Normal.png") + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton | Qt.LeftButton + onClicked: { + if (mouse.button === Qt.LeftButton) { + _inspectorModel.setPropertyAnimated( + model.modelData.instance, + model.modelData.handle, + !model.modelData.animated) + } else { + const coords = mapToItem(root, mouse.x, mouse.y); + groupDelegateItem.showContextMenu(coords); + } + } + } + } + } + + + Item { + // Spacer item + width: model.modelData.animatable + ? 4 : animatedPropertyButton.width + 4 + height: loadedItem.height + 4 // Add little space between items + } + + StyledLabel { + id: propertyRow + + readonly property var modelData: model.modelData + text: model.modelData.title + color: _inspectorView.titleColor(modelData.instance, + modelData.handle) + + Layout.alignment: Qt.AlignTop + + MouseArea { + id: mouse + anchors.fill: parent + acceptedButtons: Qt.RightButton + hoverEnabled: true + onClicked: { + const coords = mapToItem(root, mouse.x, mouse.y); + groupDelegateItem.showContextMenu(coords); + } + } + + StyledTooltip { + text: modelData.toolTip + visible: mouse.containsMouse + } + } + + Loader { + id: loader + readonly property var modelData: propertyRow.modelData + sourceComponent: { + const dataType = modelData.dataType; + console.warn("KDAB_TODO: DEBUG for type", dataType, + "property", modelData.propertyType, + "text ", model.modelData.title); + switch (dataType) { + case DataModelDataType.Long: + if (modelData.propertyType === + AdditionalMetaDataType.ShadowMapResolution) { + return shadowResolutionComponent; + } + if (modelData.propertyType === AdditionalMetaDataType.Range) { + return intSliderComponent; + } + console.warn("KDAB_TODO: implement handler for type \"Long\", property:", + modelData.propertyType); + return null; + case DataModelDataType.Long4: + if (modelData.propertyType === AdditionalMetaDataType.Image) { + return imageChooser; + } + console.warn("KDAB_TODO: implement handler for type \"long4\" property:", + modelData.propertyType); + return null; + case DataModelDataType.ObjectRef: + if (modelData.propertyType === AdditionalMetaDataType.ObjectRef) + return objectReference; + console.warn("KDAB_TODO: implement handler for type: \"objectref\" property:", + modelData.propertyType); + return null; + case DataModelDataType.StringOrInt: + //TODO: Maybe do some further check if the right combo is used + if (modelData.propertyType === AdditionalMetaDataType.StringList) + return slideSelectionDropDown; + console.warn("KDAB_TODO: (String) implement handler for type \"stringOrInt\" property:", + modelData.propertyType); + return null; + case DataModelDataType.String: + if (modelData.propertyType === AdditionalMetaDataType.Import) + return fileChooser; + if (modelData.propertyType === AdditionalMetaDataType.StringList) + return comboDropDown; + if (modelData.propertyType === AdditionalMetaDataType.Renderable) + return renderableDropDown; + if (modelData.propertyType === AdditionalMetaDataType.Mesh) + return meshChooser; + if (modelData.propertyType === AdditionalMetaDataType.MultiLine) + return multiLine; + if (modelData.propertyType === AdditionalMetaDataType.Font) + return comboDropDown; + if (modelData.propertyType === AdditionalMetaDataType.Texture) + return textureChooser; + console.warn("KDAB_TODO: (String) implement handler for type \"string\" property:", + modelData.propertyType); + return null; + case DataModelDataType.Bool: + return checkBox; + case DataModelDataType.Float: + if (modelData.propertyType === AdditionalMetaDataType.None) + return valueComponent; + if (modelData.propertyType === AdditionalMetaDataType.Range) + return sliderComponent; + if (modelData.propertyType === AdditionalMetaDataType.FontSize) + return fontSizeComponent; + console.warn("KDAB_TODO: implement handler for type\"float\" property:", + modelData.propertyType); + return null; + case DataModelDataType.Float3: + if (modelData.propertyType === AdditionalMetaDataType.Color) + return colorBox; + if (modelData.propertyType === AdditionalMetaDataType.Rotation) + return xyzPropertyComponent; + if (modelData.propertyType === AdditionalMetaDataType.None) + return xyzPropertyComponent; + console.warn("KDAB_TODO: implement handler for type:\"float3\" property:", + modelData.propertyType, "text ", + model.modelData.title); + return null; + case DataModelDataType.StringRef: + if (modelData.propertyType === AdditionalMetaDataType.None) + return materialDropDown; + console.warn("KDAB_TODO: implement handler for type:\"StringRef\" text ", + model.modelData.title); + return null; + default: + console.warn("KDAB_TODO: implement handler for type", + dataType, "property", + modelData.propertyType, "text ", + model.modelData.title); + } + return null; + } + } + } + } + } + } + } + } + } + + Component { + id: multiLine + + ScrollView { + id: scrollView + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant value: parent.modelData.value + property Item tabItem1: textArea + + width: _valueWidth + height: _controlBaseHeight * 3 + clip: true + + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: ScrollBar.AsNeeded + + TextArea { + id: textArea + + text: scrollView.value + horizontalAlignment: TextInput.AlignLeft + verticalAlignment: TextInput.AlignTop + font.pixelSize: _fontSize + color: _textColor + wrapMode: TextEdit.WordWrap + selectionColor: _selectionColor + selectedTextColor: _textColor + + topPadding: 6 + bottomPadding: 6 + rightPadding: 6 + + background: Rectangle { + color: textArea.enabled ? _studioColor2 : "transparent" + border.width: textArea.activeFocus ? 1 : 0 + border.color: textArea.activeFocus ? _selectionColor : _disabledColor + } + + MouseArea { + id: mouseAreaX + anchors.fill: parent + property int clickedPos + 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: { + _inspectorModel.setPropertyValue(scrollView.instance, scrollView.handle, + text, false) + } + + onEditingFinished: { + _inspectorModel.setPropertyValue(scrollView.instance, scrollView.handle, + text, true) + } + } + } + } + + Component { + id: meshChooser + HandlerFilesChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showMeshChooser(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { + id: imageChooser + HandlerFilesChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showImageChooser(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { + id: fileChooser + HandlerFilesChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value === "" ? qsTr("[None]") : parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showFilesChooser(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { + id: textureChooser + HandlerFilesChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showTextureChooser(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { + id: xyzPropertyComponent + + RowLayout { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + property alias tabItem1: xyzHandler.tabItem1 + property alias tabItem2: xyzHandler.tabItem2 + property alias tabItem3: xyzHandler.tabItem3 + spacing: 0 + Item { + width: _valueWidth - xyzHandler.width + } + HandlerPropertyBaseXYZ { + id: xyzHandler + valueX: Number(values[0]).toFixed(3) + valueY: Number(values[1]).toFixed(3) + valueZ: Number(values[2]).toFixed(3) + onEditingFinished: { + _inspectorModel.setPropertyValue(parent.instance, parent.handle, + Qt.vector3d(valueX, valueY, valueZ)) + } + } + } + } + + Component { + id: valueComponent + + RowLayout { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property real value: Number(parent.modelData.value).toFixed(3) + property Item tabItem1: floatField + spacing: 0 + Item { + width: _valueWidth - floatField.width + } + FloatTextField { + id: floatField + text: parent.value + implicitHeight: _controlBaseHeight + implicitWidth: _valueWidth / 2 + + onWheelEventFinished: { + _inspectorModel.setPropertyValue(parent.instance, parent.handle, Number(text)); + } + + onEditingFinished: { + _inspectorModel.setPropertyValue(parent.instance, parent.handle, Number(text)); + } + } + } + } + + Component { + id: sliderComponent + + HandlerPropertyBaseSlider { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + property real oldValue: 0.0 + + value: parent.modelData.value + sliderMin: values[0] + sliderMax: values[1] + + onEditingStarted: { + oldValue = value + } + onEditingFinished: { + // make sure the undo step is created, therefore resetting it to the old value + var val = value + _inspectorModel.setPropertyValue(instance, handle, oldValue, false) + _inspectorModel.setPropertyValue(instance, handle, val, true) + } + onSliderMoved: { + _inspectorModel.setPropertyValue(instance, handle, value, false) + } + } + } + + Component { + id: comboDropDown + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property var values: parent.modelData.values + property var value: parent.modelData.value + + model: values + + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + currentIndex = find(value) + } + onCurrentIndexChanged: { + var newValue = textAt(currentIndex) + if (value !== newValue && currentIndex !== -1) + _inspectorModel.setPropertyValue(instance, handle, newValue) + } + onValueChanged: { + currentIndex = find(value) + } + } + } + + Component { + id: slideSelectionDropDown + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property var values: parent.modelData.values + property var value: parent.modelData.value + + model: values + + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + var newIndex = find(value) + if (newIndex === -1) + newIndex = find(value + "|separator") + currentIndex = newIndex + } + onCurrentIndexChanged: { + var newValue = textAt(currentIndex).replace("|separator", "") + if (value !== newValue && currentIndex !== -1) { + _inspectorModel.setSlideSelection(instance, handle, + currentIndex, values) + } + } + onValueChanged: { + var newIndex = find(value) + if (newIndex === -1) + newIndex = find(value + "|separator") + currentIndex = newIndex + } + } + } + + Component { + id: materialDropDown + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property var values: parent.modelData.values + property var value: parent.modelData.value + + model: values + + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + currentIndex = find(value) + } + onCurrentIndexChanged: { + var newValue = textAt(currentIndex) + if (value !== newValue && currentIndex !== -1) + _inspectorModel.setMaterialTypeValue(instance, handle, newValue) + } + onValueChanged: { + currentIndex = find(value) + } + } + } + + Component { + id: renderableDropDown + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property var values: parent.modelData.values + property var value: parent.modelData.value + model: values + + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + currentIndex = find(value) + } + + onCurrentIndexChanged: { + var newValue = textAt(currentIndex) + if (value !== newValue && currentIndex !== -1) + _inspectorModel.setRenderableValue(instance, handle, newValue) + } + onValueChanged: { + currentIndex = find(value) + } + } + } + + Component { + id: checkBox + + Image { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property bool checked: parent.modelData.value + + source: (_resDir + (checked ? "checkbox-checked.png" : "checkbox-unchecked.png")) + + MouseArea { + anchors.fill: parent + onClicked: _inspectorModel.setPropertyValue(instance, handle, !checked) + } + } + } + + Component { + id: colorBox + + HandlerGenericBaseColor { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + + color: parent.modelData.value + onColorSelected: _inspectorModel.setPropertyValue(instance, handle, selectedColor) + } + } + + Component { + id: objectReference + + HandlerGenericChooser { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + value: parent.modelData.value + onShowBrowser: { + activeBrowser = _inspectorView.showObjectReference(handle, instance, + mapToGlobal(width, 0)) + } + } + } + + Component { + id: intSliderComponent + + HandlerPropertyBaseSlider { + intSlider: true; + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property variant values: parent.modelData.values + intValue: parent.modelData.value + sliderMin: values[0] + sliderMax: values[1] + + onEditingFinished: { + _inspectorModel.setPropertyValue(instance, handle, intValue) + } + } + } + + Component { + id: fontSizeComponent + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property real value: parent.modelData.value + + model: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72", "96", "120"] + + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + currentIndex = find(value) + } + + onCurrentIndexChanged: { + var newvalue = parseInt(textAt(currentIndex)) + _inspectorModel.setPropertyValue(instance, handle, newvalue) + } + + onValueChanged: { + currentIndex = find(value) + } + } + } + + Component { + id: shadowResolutionComponent + + StyledComboBox { + property int instance: parent.modelData.instance + property int handle: parent.modelData.handle + property var value: parent.modelData.value + property int newValue + + model: ["8", "9", "10", "11"] + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + + Component.onCompleted: { + currentIndex = find(value) + } + + onCurrentIndexChanged: { + newValue = parseInt(textAt(currentIndex)) + if (value !== newValue && currentIndex !== -1) + _inspectorModel.setPropertyValue(instance, handle, newValue) + } + + onValueChanged: { + currentIndex = find(value) + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp new file mode 100644 index 00000000..c3ea86cb --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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 "InspectorGroup.h" + +//============================================================================== +/** + * Constructor + */ +CInspectorGroup::CInspectorGroup() +{ +} + +//============================================================================== +/** + * Destructor + */ +CInspectorGroup::~CInspectorGroup() +{ +} + +//============================================================================== +/** + * Set the name to show up in the title bar + */ +void CInspectorGroup::SetName(const QString &inName) +{ + m_name = inName; +} + +QString CInspectorGroup::GetName() const +{ + return m_name; +} + diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h new file mode 100644 index 00000000..98ac824d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_INSPECTOR_GROUP_H +#define INCLUDED_INSPECTOR_GROUP_H 1 + +#pragma once + +#include <QString> + +//============================================================================== +/** + * @class CInspectorGroup + * @brief This is the base class for inspector groups. + * + * Derive from this class in order to create a new group for the inspector + * palette. + */ +class CInspectorGroup +{ +public: + enum EGroupCommand { + EGroupCommandNone = 0, + EGroupCommandToggle, + }; + +public: + CInspectorGroup(); + virtual ~CInspectorGroup(); + + void SetName(const QString &inName); + QString GetName() const; + +protected: + QString m_name; +}; + +#endif // INCLUDED_INSPECTOR_GROUP_H diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml new file mode 100644 index 00000000..229c4c8c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + ListView { + id: listView + + anchors { + fill: parent + leftMargin: 8 + } + + boundsBehavior: Flickable.StopAtBounds + spacing: 4 + clip: true + + ScrollBar.vertical: ScrollBar {} + + model: _meshChooserModel + + delegate: ChooserDelegate { + onClicked: _meshChooserView.setSelectedMeshName(filePath) + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp new file mode 100644 index 00000000..e1b61bbf --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp @@ -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$ +** +****************************************************************************/ + +#include "MeshChooserModel.h" +#include "Core.h" +#include "Doc.h" +#include "IDocumentBufferCache.h" +#include "StudioApp.h" + +MeshChooserModel::MeshChooserModel(QObject *parent) + : ChooserModelBase(parent) +{ +} + +MeshChooserModel::~MeshChooserModel() +{ + +} + +bool MeshChooserModel::isVisible(const QString &path) const +{ + return getIconType(path) == OBJTYPE_MODEL; +} + +const QVector<ChooserModelBase::FixedItem> MeshChooserModel::getFixedItems() const +{ + static QVector<FixedItem> items; + + if (items.isEmpty()) { + auto primitiveNames = g_StudioApp.GetCore()->GetDoc()->GetBufferCache().GetPrimitiveNames(); + for (auto item = primitiveNames; *item; ++item) { + auto itemName = *item; + if (itemName[0] == L'#') + items.append({ OBJTYPE_MODEL, QString::fromWCharArray(itemName + 1) }); + } + } + + return items; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h new file mode 100644 index 00000000..5aea88a8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 MESHCHOOSERMODEL_H +#define MESHCHOOSERMODEL_H + +#include "ChooserModelBase.h" + +class MeshChooserModel : public ChooserModelBase +{ + Q_OBJECT + +public: + explicit MeshChooserModel(QObject *parent = nullptr); + virtual ~MeshChooserModel(); + +private: + bool isVisible(const QString &path) const override; + const QVector<FixedItem> getFixedItems() const override; +}; + +#endif // MESHCHOOSERMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp new file mode 100644 index 00000000..86f7c75b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 "MeshChooserView.h" +#include "MeshChooserModel.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "StudioPreferences.h" +#include "IDocumentEditor.h" +#include "UICDMStudioSystem.h" +#include "UICDMValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "IDocumentBufferCache.h" + +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +MeshChooserView::MeshChooserView(QWidget *parent) + : QQuickWidget(parent) + , m_model(new MeshChooserModel(this)) +{ + setWindowTitle(tr("Meshes")); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &MeshChooserView::initialize); +} + +void MeshChooserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_resDir"_L1, + resourceImageUrl()); + rootContext()->setContextProperty("_meshChooserView"_L1, this); + rootContext()->setContextProperty("_meshChooserModel"_L1, m_model); + + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/MeshChooser.qml"_L1)); +} + +QSize MeshChooserView::sizeHint() const +{ + return {500, 500}; +} + +void MeshChooserView::setSelectedMeshName(const QString &name) +{ + hide(); + bool resourceName = false; + QString meshName = QLatin1Char('#') + name; + const wchar_t **files = g_StudioApp.GetCore()->GetDoc()->GetBufferCache().GetPrimitiveNames(); + for (const wchar_t **item = files; item && *item; ++item) { + QString primitive = QString::fromWCharArray(*item); + if (primitive == meshName) { + resourceName = true; + break; + } + } + if (!resourceName) + meshName = name; + + Q_EMIT meshSelected(m_handle, m_instance, meshName); +} + +void MeshChooserView::setHandle(int handle) +{ + m_handle = handle; +} + +void MeshChooserView::setInstance(int instance) +{ + m_instance = instance; +} + +void MeshChooserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &MeshChooserView::close); +} + +void MeshChooserView::showEvent(QShowEvent *event) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + + UICDM::SValue value; + propertySystem->GetInstancePropertyValue(m_instance, m_handle, value); + + const QString meshValue = UICDM::get<QString>(value); + const Q3DStudio::CFilePath selectionItem = Q3DStudio::CFilePath::fromQString(meshValue); + const Q3DStudio::CFilePath selectionWithoutId = selectionItem.GetPathWithoutIdentifier(); + + QString currentFile; + + if (selectionWithoutId.size()) { + currentFile = selectionWithoutId.toQString(); + } else { + currentFile = selectionItem.GetIdentifier().toQString(); + } + + m_model->setCurrentFile(currentFile); + + QQuickWidget::showEvent(event); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h new file mode 100644 index 00000000..b47770d9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 MESHCHOOSERVIEW_H +#define MESHCHOOSERVIEW_H + +#include <QQuickWidget> + +namespace Q3DStudio { +class CFilePath; +class CString; +} + +class QAbstractItemModel; +class MeshChooserModel; +class MeshChooserView : public QQuickWidget +{ + Q_OBJECT +public: + explicit MeshChooserView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + + Q_INVOKABLE void setSelectedMeshName(const QString &name); + + void setHandle(int handle); + void setInstance(int instance); + +Q_SIGNALS: + void meshSelected(int handle, int instance, const QString &name); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void showEvent(QShowEvent *event) override; + void initialize(); + int m_handle = -1; + int m_instance = -1; + MeshChooserModel *m_model = nullptr; +}; + +#endif // MESHCHOOSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml new file mode 100644 index 00000000..d0ece17a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import Qt3DStudio 1.0 +import "../controls" + +Rectangle { + id: root + + property alias selectedText: selectionText.text + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + spacing: 10 + + ListView { + id: browserList + + Layout.margins: 10 + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 80 + Layout.preferredHeight: count * 20 + Layout.preferredWidth: root.width + + ScrollBar.vertical: ScrollBar {} + + model: _objectBrowserView.model + boundsBehavior: Flickable.StopAtBounds + clip: true + + delegate: Item { + id: delegateItem + + x: model.depth * 20 + width: parent.width + height: model.parentExpanded ? typeIcon.height + 10 : 0 + + visible: height > 0 + + Behavior on height { + NumberAnimation { + duration: 100 + easing.type: Easing.OutQuad + } + } + + Row { + id: row + + height: typeIcon.height + spacing: 5 + + Image { + source: { + if (!model.hasChildren) + return ""; + model.expanded ? _resDir + "arrow_down.png" + : _resDir + "arrow.png"; + } + + MouseArea { + anchors.fill: parent + onClicked: model.expanded = !model.expanded + } + } + + Rectangle { + height: typeIcon.height + width: typeIcon.width + name.width + 10 + + color: model.index === browserList.currentIndex ? _selectionColor + : "transparent" + + Row { + spacing: 10 + Image { + id: typeIcon + + source: model.icon + } + + StyledLabel { + id: name + anchors.verticalCenter: typeIcon.verticalCenter + color: model.textColor + text: model.name + } + } + + MouseArea { + id: delegateArea + + anchors.fill: parent + onClicked: browserList.currentIndex = model.index + onDoubleClicked: { + browserList.currentIndex = model.index; + _objectBrowserView.close(); + } + } + } + } + } + + onCurrentIndexChanged: _objectBrowserView.selection = currentIndex + } + + StyledMenuSeparator {} + + GridLayout { + columns: 2 + Layout.margins: 10 + + StyledLabel { + text: qsTr("Type") + } + + StyledComboBox { + id: pathCombo + model: [qsTr("Absolute Reference"), qsTr("Path Reference")] + + onActivated: { + if (index === 0) + _objectBrowserView.pathType = ObjectBrowserView.Name; + else if (index === 1) + _objectBrowserView.pathType = ObjectBrowserView.Relative; + } + } + + StyledLabel { + text: qsTr("Path") + } + + StyledLabel { + id: selectionText + Layout.preferredWidth: _valueWidth + text: pathCombo.currentIndex === 0 ? _objectBrowserView.name(browserList.currentIndex) + : _objectBrowserView.path(browserList.currentIndex) + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp new file mode 100644 index 00000000..86067722 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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 "ObjectBrowserView.h" + +#include "CColor.h" +#include "Literals.h" +#include "ObjectListModel.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +ObjectBrowserView::ObjectBrowserView(QWidget *parent) + : QQuickWidget(parent) +{ + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &ObjectBrowserView::initialize); +} + +QAbstractItemModel *ObjectBrowserView::model() const +{ + return m_model; +} + +void ObjectBrowserView::setModel(ObjectListModel *model) +{ + if (!m_model) { + m_model = new FlatObjectListModel(model, this); + } + m_model->setSourceModel(model); + + Q_EMIT modelChanged(); +} + + +QSize ObjectBrowserView::sizeHint() const +{ + return {500, 500}; +} + +QString ObjectBrowserView::name(int index) const +{ + return m_model->index(index, 0).data(ObjectListModel::NameRole).toString(); +} + +QString ObjectBrowserView::path(int index) const +{ + return m_model->index(index, 0).data(ObjectListModel::PathReferenceRole).toString(); +} + +void ObjectBrowserView::setSelection(int index) +{ + if (m_selection != index) { + m_selection = index; + Q_EMIT selectionChanged(); + } +} + +void ObjectBrowserView::setPathType(ObjectBrowserView::PathType type) +{ + if (type != m_pathType) { + m_pathType = type; + Q_EMIT pathTypeChanged(); + } +} + +UICDM::CUICDMInstanceHandle ObjectBrowserView::selectedHandle() const +{ + auto handleId = m_model->index(m_selection, 0).data(ObjectListModel::HandleRole).toInt(); + return UICDM::CUICDMInstanceHandle(handleId); +} + +void ObjectBrowserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &ObjectBrowserView::close); +} + +void ObjectBrowserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_objectBrowserView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + qmlRegisterUncreatableType<ObjectBrowserView>("Qt3DStudio", 1, 0, "ObjectBrowserView" + , tr("Creation of ObjectBrowserView not allowed from QML")); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/ObjectBrowser.qml"_L1)); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h new file mode 100644 index 00000000..8a4ed1eb --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 OBJECTBROWSERVIEW_H +#define OBJECTBROWSERVIEW_H + +#include <QQuickWidget> + +#include "RelativePathTools.h" +#include "UICDMHandles.h" + +#include <QColor> + +class ObjectListModel; +class FlatObjectListModel; + +class QAbstractItemModel; + +class ObjectBrowserView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL) + Q_PROPERTY(int selection READ selection WRITE setSelection NOTIFY selectionChanged FINAL) + Q_PROPERTY(PathType pathType READ pathType WRITE setPathType NOTIFY pathTypeChanged FINAL) + +public: + ObjectBrowserView(QWidget *parent = nullptr); + + + enum PathType { + Name = CRelativePathTools::EPATHTYPE_GUID, + Relative = CRelativePathTools::EPATHTYPE_RELATIVE, + }; + Q_ENUM(PathType) + + QAbstractItemModel *model() const; + void setModel(ObjectListModel *model); + QSize sizeHint() const override; + + Q_INVOKABLE QString name(int index) const; + Q_INVOKABLE QString path(int index) const; + + int selection() const { return m_selection; } + void setSelection(int index); + + PathType pathType() const {return m_pathType;} + void setPathType(PathType type); + + UICDM::CUICDMInstanceHandle selectedHandle() const; + +Q_SIGNALS: + void modelChanged(); + void pathTypeChanged(); + void selectionChanged(); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void initialize(); + + FlatObjectListModel *m_model = nullptr; + QHash<int, ObjectListModel *> m_subModels; + QColor m_baseColor = QColor::fromRgb(75, 75, 75); + QColor m_selectColor; + int m_selection = -1; + PathType m_pathType = Name; +}; + +#endif // OBJECTBROWSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp new file mode 100644 index 00000000..ad1d752f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp @@ -0,0 +1,336 @@ +/**************************************************************************** +** +** 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 "ObjectListModel.h" + +#include "Core.h" +#include "Doc.h" +#include "GraphUtils.h" +#include "IObjectReferenceHelper.h" +#include "StudioUtils.h" +#include "SlideSystem.h" +#include "StudioObjectTypes.h" +#include "StudioPreferences.h" +#include "UICDMStudioSystem.h" + +#include <QCoreApplication> +#include <QColor> + +ObjectListModel::ObjectListModel(CCore *core, + const UICDM::CUICDMInstanceHandle &baseHandle, QObject *parent) + : QAbstractItemModel(parent) + , m_core(core) + , m_baseHandle(baseHandle) +{ + auto doc = m_core->GetDoc(); + m_objRefHelper = doc->GetDataModelObjectReferenceHelper(); + m_slideHandle = m_objRefHelper->GetSlideList(m_baseHandle)[0]; +} + +QHash<int, QByteArray> ObjectListModel::roleNames() const +{ + auto names = QAbstractItemModel::roleNames(); + names.insert(NameRole, "name"); + names.insert(HandleRole, "handle"); + names.insert(IconRole, "icon"); + names.insert(TextColorRole, "textColor"); + names.insert(AbsolutePathRole, "absolutePath"); + names.insert(PathReferenceRole, "referencePath"); + + return names; +} + +int ObjectListModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return 1; + + const auto handle = handleForIndex(parent); + const auto children = childrenList(m_slideHandle, handle); + return children.size(); +} + +int ObjectListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return 1; +} + +QVariant ObjectListModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(), index.parent())) + return {}; + + switch (role) { + case NameRole: { + return nameForHandle(handleForIndex(index)); + } + case PathReferenceRole: { + Q3DStudio::CString data(m_objRefHelper->GetObjectReferenceString( + m_baseHandle, CRelativePathTools::EPATHTYPE_RELATIVE, handleForIndex(index))); + return data.toQString(); + } + case AbsolutePathRole: { + Q3DStudio::CString data(m_objRefHelper->GetObjectReferenceString( + m_baseHandle, CRelativePathTools::EPATHTYPE_GUID, handleForIndex(index))); + return data.toQString(); + } + case HandleRole: { + return (int)handleForIndex(index); + } + case IconRole: { + auto info = m_objRefHelper->GetInfo(handleForIndex(index)); + return resourceImageUrl() + CStudioObjectTypes::GetNormalIconName(info.m_Type); + } + case TextColorRole: { + auto info = m_objRefHelper->GetInfo(handleForIndex(index)); + if (info.m_Master) + return QVariant::fromValue(CStudioPreferences::masterColor()); + else + return QVariant::fromValue(CStudioPreferences::textColor()); + } + default: + return {}; + } + + return {}; +} + +QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid()) + return createIndex(row, column, (quintptr)(m_baseHandle)); + + const auto handle = handleForIndex(parent); + const auto children = childrenList(m_slideHandle, handle); + if (row >= children.size()) + return {}; + + auto childHandle = children[row]; + return createIndex(row, column, (quintptr)(childHandle)); +} + +QModelIndex ObjectListModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return {}; + + const auto handle = handleForIndex(index); + UICDM::CUICDMInstanceHandle parentHandle = m_core->GetDoc()->GetAssetGraph()->GetParent(handle); + if (!parentHandle.Valid()) + return {}; + + int row = 0; + UICDM::CUICDMInstanceHandle grandParentHandle = m_core->GetDoc()->GetAssetGraph() + ->GetParent(handle); + const auto children = childrenList(m_slideHandle, grandParentHandle); + const auto it = std::find(children.begin(), children.end(), parentHandle); + if (it != children.end()) + row = it - children.begin(); + + return createIndex(row, 0, (quintptr)(parentHandle)); +} + +UICDM::CUICDMInstanceHandle ObjectListModel::handleForIndex(const QModelIndex &index) const +{ + return static_cast<UICDM::CUICDMInstanceHandle>(index.internalId()); +} + +UICDM::TInstanceHandleList ObjectListModel::childrenList(const UICDM::CUICDMSlideHandle &slideHandle, const UICDM::CUICDMInstanceHandle &handle) const +{ + auto slideSystem = m_core->GetDoc()->GetStudioSystem()->GetSlideSystem(); + auto currentMaster = slideSystem->GetMasterSlide(slideHandle); + + UICDM::TInstanceHandleList children; + m_objRefHelper->GetChildInstanceList(handle, children, slideHandle, m_baseHandle); + children.erase( + std::remove_if(children.begin(), children.end(), + [&slideHandle, slideSystem, ¤tMaster](const UICDM::CUICDMInstanceHandle &h) { + const auto childSlide = slideSystem->GetAssociatedSlide(h); + if (!childSlide.Valid()) + return true; + const auto childMaster = slideSystem->GetMasterSlide(childSlide); + if (childMaster == currentMaster) { + return childSlide != childMaster && childSlide != slideHandle; + } else { + return childSlide != childMaster; + } + }), children.end()); + return children; +} + +QString ObjectListModel::nameForHandle(const UICDM::CUICDMInstanceHandle &handle) const +{ + const auto data = m_objRefHelper->GetInfo(handle); + return data.m_Name.toQString(); +} + +QModelIndex ObjectListModel::indexForHandle(const UICDM::CUICDMInstanceHandle &handle, + const QModelIndex &startIndex) const +{ + if (handle == m_baseHandle) + return index(0, 0, {}); + + for (int i = 0; i < rowCount(startIndex); i++) { + auto idx = index(i, 0, startIndex); + if (static_cast<UICDM::CUICDMInstanceHandle>(idx.internalId()) == handle) + return idx; + if (rowCount(idx) > 0) + return indexForHandle(handle, idx); + } + return {}; +} + + +FlatObjectListModel::FlatObjectListModel(ObjectListModel *sourceModel, QObject *parent) + : QAbstractListModel(parent) + , m_sourceModel(sourceModel) + +{ + Q_ASSERT(sourceModel); + m_sourceInfo = collectSourceIndexes({}, 0); +} + +QVector<FlatObjectListModel::SourceInfo> FlatObjectListModel::collectSourceIndexes( + const QModelIndex &sourceIndex, int depth) const +{ + QVector<SourceInfo> sourceInfo; + + for (int i = 0; i < m_sourceModel->rowCount(sourceIndex); i++) { + auto idx = m_sourceModel->index(i, 0, sourceIndex); + SourceInfo info; + info.depth = depth; + info.index = idx; + sourceInfo.append(info); + if (m_sourceModel->rowCount(idx) > 0) { + sourceInfo += collectSourceIndexes(idx, depth + 1); + } + } + + return sourceInfo; +} + +QHash<int, QByteArray> FlatObjectListModel::roleNames() const +{ + auto roles = m_sourceModel->roleNames(); + roles.insert(DepthRole, "depth"); + roles.insert(ExpandedRole, "expanded"); + roles.insert(ParentExpandedRole, "parentExpanded"); + roles.insert(HasChildrenRole, "hasChildren"); + return roles; +} + +QModelIndex FlatObjectListModel::mapToSource(const QModelIndex &proxyIndex) const +{ + int row = proxyIndex.row(); + if (row < 0 || row >= m_sourceInfo.count()) + return {}; + return m_sourceInfo[row].index; +} + +QVariant FlatObjectListModel::data(const QModelIndex &index, int role) const +{ + const auto row = index.row(); + if (row < 0 || row >= m_sourceInfo.count()) + return {}; + + switch (role) { + case DepthRole: { + auto info = m_sourceInfo[row]; + return info.depth; + } + case ExpandedRole: { + auto info = m_sourceInfo[row]; + return info.expanded; + } + case ParentExpandedRole: { + auto info = m_sourceInfo[row]; + if (info.depth == 0) + return true; + + int depth = info.depth; + for (int i = row - 1; i >= 0; i--) { + const auto prevInfo = m_sourceInfo[i]; + if (prevInfo.depth < depth) { + if (!prevInfo.expanded) { + return false; + } else { + depth = prevInfo.depth; + } + } + } + return true; + } + case HasChildrenRole: { + if (row == m_sourceInfo.count() - 1) + return false; + auto info = m_sourceInfo[row]; + auto nextInfo = m_sourceInfo[row + 1]; + return (nextInfo.depth > info.depth); + } + } + + QModelIndex sourceIndex = mapToSource(index); + return m_sourceModel->data(sourceIndex, role); +} + +bool FlatObjectListModel::setData(const QModelIndex &index, const QVariant &data, int role) +{ + const auto row = index.row(); + if (row < 0 || row >= m_sourceInfo.count()) + return {}; + + switch (role) { + case ExpandedRole: { + auto info = &m_sourceInfo[index.row()]; + info->expanded = data.toBool(); + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {}); + return true; + } + } + + QModelIndex sourceIndex = mapToSource(index); + return m_sourceModel->setData(sourceIndex, data, role); +} + +int FlatObjectListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_sourceInfo.count(); +} + +void FlatObjectListModel::setSourceModel(ObjectListModel *sourceModel) +{ + beginResetModel(); + m_sourceModel = sourceModel; + m_sourceInfo = collectSourceIndexes({}, 0); + endResetModel(); +} + diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h new file mode 100644 index 00000000..fbff3537 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 OBJECTLISTMODEL_H +#define OBJECTLISTMODEL_H + +#include <QAbstractItemModel> +#include <QAbstractListModel> + +#include "UICDMHandles.h" + +class IObjectReferenceHelper; +class CCore; + +class ObjectListModel : public QAbstractItemModel +{ + Q_OBJECT +public: + ObjectListModel(CCore *core, const UICDM::CUICDMInstanceHandle &baseHandle, QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &index) const override; + + enum Roles { + NameRole = Qt::DisplayRole, + AbsolutePathRole = Qt::UserRole + 1, + PathReferenceRole, + IconRole, + TextColorRole, + HandleRole, + LastRole = HandleRole + }; + + QHash<int, QByteArray> roleNames() const override; + + UICDM::CUICDMInstanceHandle baseHandle() const {return m_baseHandle;} + +private: + UICDM::CUICDMInstanceHandle handleForIndex(const QModelIndex &index) const; + + UICDM::TInstanceHandleList childrenList(const UICDM::CUICDMSlideHandle &slideHandle, + const UICDM::CUICDMInstanceHandle &handle) const; + + QString nameForHandle(const UICDM::CUICDMInstanceHandle &handle) const; + + QModelIndex indexForHandle(const UICDM::CUICDMInstanceHandle &handle, const QModelIndex &startIndex = {}) const; + + CCore *m_core; + UICDM::CUICDMSlideHandle m_slideHandle; + UICDM::CUICDMInstanceHandle m_baseHandle; + IObjectReferenceHelper *m_objRefHelper; +}; + +class FlatObjectListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + FlatObjectListModel(ObjectListModel *sourceModel, QObject *parent = nullptr); + + enum Roles { + DepthRole = ObjectListModel::LastRole + 1, + ExpandedRole, + ParentExpandedRole, + HasChildrenRole + }; + + QHash<int, QByteArray> roleNames() 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; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + void setSourceModel(ObjectListModel *sourceModel); + ObjectListModel *sourceModel() const {return m_sourceModel;} + +private: + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + + struct SourceInfo { + bool expanded = false; + int depth = 0; + QPersistentModelIndex index; + }; + + QVector<SourceInfo> collectSourceIndexes(const QModelIndex &sourceIndex, int depth) const; + + QVector<SourceInfo> m_sourceInfo; + ObjectListModel *m_sourceModel; +}; + + +#endif // OBJECTLISTMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml b/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml new file mode 100644 index 00000000..3e456067 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 + +Rectangle { + id: root + + color: _backgroundColor + ColumnLayout { + anchors.fill: parent + //KDAB_FIXME implement object chooser + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp new file mode 100644 index 00000000..40dc91e1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 "ObjectReferenceModel.h" + +ObjectReferenceModel::ObjectReferenceModel(QObject *parent) + : QAbstractListModel(parent) +{ + //KDAB_FIXME: Understand how it must be filled +} + +ObjectReferenceModel::~ObjectReferenceModel() +{ + +} + + +int ObjectReferenceModel::rowCount(const QModelIndex &parent) const +{ + //KDAB_FIXME + return 0; +} + +QVariant ObjectReferenceModel::data(const QModelIndex &index, int role) const +{ + //KDAB_FIXME + return {}; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h new file mode 100644 index 00000000..29932442 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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 OBJECTREFERENCEMODEL_H +#define OBJECTREFERENCEMODEL_H + +#include <QAbstractListModel> + +class ObjectReferenceModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit ObjectReferenceModel(QObject *parent = nullptr); + ~ObjectReferenceModel(); + + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; +}; + +#endif // OBJECTREFERENCEMODEL_H diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp new file mode 100644 index 00000000..eab0b0aa --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 "ObjectReferenceView.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "StudioPreferences.h" +#include "IDocumentEditor.h" +#include "UICDMValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" + +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +ObjectReferenceView::ObjectReferenceView(QWidget *parent) : QQuickWidget(parent) +{ + setWindowTitle(tr("Object Reference")); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &ObjectReferenceView::initialize); +} + +void ObjectReferenceView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_resDir"_L1, + resourceImageUrl()); + rootContext()->setContextProperty("_objectReferenceView"_L1, this); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/ObjectReference.qml"_L1)); +} + +QSize ObjectReferenceView::sizeHint() const +{ + return {500, 500}; +} + +QAbstractItemModel *ObjectReferenceView::model() const +{ + return m_model; +} + +void ObjectReferenceView::setModel(QAbstractItemModel *model) +{ + if (m_model != model) { + m_model = model; + Q_EMIT modelChanged(); + } +} + +void ObjectReferenceView::setHandle(int handle) +{ + m_handle = handle; +} + +void ObjectReferenceView::setInstance(int instance) +{ + m_instance = instance; +} + +void ObjectReferenceView::setSelectedReference(const QString &name) +{ + UICDM::SValue v = QVariant(name); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property")) + ->SetInstancePropertyValue(m_instance, m_handle, v); +} + +void ObjectReferenceView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + close(); +} + diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h new file mode 100644 index 00000000..5634fd97 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 OBJECTREFERENCEVIEW_H +#define OBJECTREFERENCEVIEW_H + +#include <QQuickWidget> +class QAbstractItemModel; + +class ObjectReferenceView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL) +public: + explicit ObjectReferenceView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); + + void setHandle(int handle); + void setInstance(int instance); + + Q_INVOKABLE void setSelectedReference(const QString &name); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +Q_SIGNALS: + void modelChanged(); + +private: + void initialize(); + int m_handle = -1; + int m_instance = -1; + QColor m_baseColor = QColor::fromRgb(75, 75, 75); + QAbstractItemModel *m_model = nullptr; +}; + +#endif // OBJECTREFERENCEVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp new file mode 100644 index 00000000..415b1877 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 "TabOrderHandler.h" + +TabOrderHandler::TabOrderHandler(QObject *parent) + : QObject(parent) +{ + +} + +TabOrderHandler::~TabOrderHandler() +{ + +} + +void TabOrderHandler::addItem(int group, QQuickItem *item) +{ + m_itemMap[group].append(item); +} + +void TabOrderHandler::clear() +{ + m_itemMap.clear(); +} + +void TabOrderHandler::clearGroup(int group) +{ + m_itemMap[group].clear(); +} + +void TabOrderHandler::tabNavigate(bool tabForward) +{ + // Find the currently focused control + for (int i = 0; i < m_itemMap.size(); i++) { + const QList<QQuickItem *> items = m_itemMap[i]; + for (int j = 0; j < items.size(); j++) { + if (items[j]->hasActiveFocus()) { + if (tabForward) + nextItem(i, j)->forceActiveFocus(); + else + previousItem(i, j)->forceActiveFocus(); + return; + } + } + } + // Activate the first item if could not find currently focused item + for (int i = 0; i < m_itemMap.size(); i++) { + if (m_itemMap[i].size() > 0) + m_itemMap[i][0]->forceActiveFocus(); + } +} + +QQuickItem *TabOrderHandler::nextItem(int group, int index) +{ + if (m_itemMap[group].size() > index + 1) { + // Try next item in group + index++; + } else { + // Get item in next available group + int nextGroup = group + 1; + while (nextGroup != group) { + if (m_itemMap.size() >= nextGroup) + nextGroup = 0; + if (m_itemMap[nextGroup].size() == 0) + nextGroup++; + else + group = nextGroup; + } + index = 0; + } + return m_itemMap[group][index]; +} + +QQuickItem *TabOrderHandler::previousItem(int group, int index) +{ + if (index - 1 >= 0) { + // Try previous item in group + index--; + } else { + // Get last item in previous available group + int nextGroup = group - 1; + while (nextGroup != group) { + if (nextGroup < 0) + nextGroup = m_itemMap.size() - 1; + if (m_itemMap[nextGroup].size() == 0) + nextGroup--; + else + group = nextGroup; + } + index = m_itemMap[group].size() - 1; + } + return m_itemMap[group][index]; +} + diff --git a/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h new file mode 100644 index 00000000..10c1d400 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 TABORDERHANDLER_H +#define TABORDERHANDLER_H + +#include <QtCore/qobject.h> +#include <QtQuick/qquickitem.h> + +class TabOrderHandler : public QObject +{ + Q_OBJECT + +public: + explicit TabOrderHandler(QObject *parent = nullptr); + ~TabOrderHandler(); + + Q_INVOKABLE void addItem(int group, QQuickItem *item); + Q_INVOKABLE void clear(); + Q_INVOKABLE void clearGroup(int group); + + void tabNavigate(bool tabForward); + +private: + QQuickItem *nextItem(int group, int index); + QQuickItem *previousItem(int group, int index); + + QHash<int, QList<QQuickItem *> > m_itemMap; +}; + +class TabNavigable { +public: + TabNavigable() : m_tabOrderHandler(new TabOrderHandler) {} + virtual ~TabNavigable() { delete m_tabOrderHandler; } + TabOrderHandler *tabOrderHandler() const { return m_tabOrderHandler; } + +private: + TabOrderHandler *m_tabOrderHandler; +}; + +#endif // TABORDERHANDLER_H diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml b/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml new file mode 100644 index 00000000..4f90640e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + border.color: _studioColor3 + + ColumnLayout { + anchors.fill: parent + + spacing: 10 + ListView { + id: listView + + anchors { + fill: parent + leftMargin: 8 + } + + boundsBehavior: Flickable.StopAtBounds + spacing: 4 + clip: true + + ScrollBar.vertical: ScrollBar {} + + model: _textureChooserModel + + delegate: ChooserDelegate { + onClicked: { + _textureChooserView.textureSelected( + _textureChooserView.handle, + _textureChooserView.instance, + filePath); + } + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp new file mode 100644 index 00000000..78084b06 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 "TextureChooserView.h" +#include "ImageChooserModel.h" +#include "StudioPreferences.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "IDocumentEditor.h" +#include "UICDMStudioSystem.h" +#include "UICDMValue.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "StudioPreferences.h" + +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +TextureChooserView::TextureChooserView(QWidget *parent) + : QQuickWidget(parent) + , m_model(new ImageChooserModel(this)) +{ + setWindowTitle(tr("Texture")); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &TextureChooserView::initialize); +} + +void TextureChooserView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_textureChooserView"_L1, this); + rootContext()->setContextProperty("_textureChooserModel"_L1, m_model); + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Inspector/TextureChooser.qml"_L1)); +} + +QSize TextureChooserView::sizeHint() const +{ + return {500, 500}; +} + +void TextureChooserView::setHandle(int handle) +{ + m_handle = handle; +} + +int TextureChooserView::handle() const +{ + return m_handle; +} + +void TextureChooserView::setInstance(int instance) +{ + m_instance = instance; +} + +int TextureChooserView::instance() const +{ + return m_instance; +} + +void TextureChooserView::focusOutEvent(QFocusEvent *event) +{ + QQuickWidget::focusOutEvent(event); + QTimer::singleShot(0, this, &TextureChooserView::close); +} + +void TextureChooserView::showEvent(QShowEvent *event) +{ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem(); + + UICDM::SValue value; + propertySystem->GetInstancePropertyValue(m_instance, m_handle, value); + + m_model->setCurrentFile(UICDM::get<QString>(value)); + + QQuickWidget::showEvent(event); +} diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h new file mode 100644 index 00000000..5bd51367 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h @@ -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$ +** +****************************************************************************/ + +#ifndef TEXTURECHOOSERVIEW_H +#define TEXTURECHOOSERVIEW_H + +#include <QQuickWidget> + +class ImageChooserModel; + +class TextureChooserView : public QQuickWidget +{ + Q_OBJECT + Q_PROPERTY(int instance READ instance) + Q_PROPERTY(int handle READ handle) + +public: + explicit TextureChooserView(QWidget *parent = nullptr); + + QSize sizeHint() const override; + + void setHandle(int handle); + int handle() const; + + void setInstance(int instance); + int instance() const; + +Q_SIGNALS: + void textureSelected(int handle, int instance, const QString &name); + +protected: + void focusOutEvent(QFocusEvent *event) override; + +private: + void showEvent(QShowEvent *event) override; + void initialize(); + int m_handle = -1; + int m_instance = -1; + ImageChooserModel *m_model = nullptr; +}; + +#endif // TEXTURECHOOSERVIEW_H diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp new file mode 100644 index 00000000..1d009b4c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMInspectable.h" +#include "UICDMInspectorGroup.h" +#include "UICDMInspectorRow.h" +#include "StudioApp.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMDataCore.h" +#include "UICDMPropertyDefinition.h" +#include "Core.h" +#include "StudioFullSystem.h" +#include "StudioCoreSystem.h" +#include "UICDMMetaData.h" +#include "UICDMSlides.h" +#include "IDocumentReader.h" +#include "Strings.h" +#include "StringLoader.h" + +using namespace UICDM; + +//============================================================================== +/** + * Constructor + */ +CUICDMInspectable::CUICDMInspectable(CStudioApp &inApp, CCore *inCore, + UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inDualPersonalityInstance /*= 0*/) + : CInspectableBase(inCore) + , m_Instance(inInstance) + , m_DualPersonalityInstance((inDualPersonalityInstance != 0) ? inDualPersonalityInstance + : inInstance) + , m_App(inApp) +{ + QT3DS_ASSERT(inCore->GetDoc()->GetDocumentReader().IsInstance(m_Instance)); +} + +//============================================================================== +/** + * Query the name of the inspectable item + */ +Q3DStudio::CString CUICDMInspectable::GetName() +{ + CClientDataModelBridge *theBridge = + m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); + + if (m_Instance == m_DualPersonalityInstance) + return theBridge->GetName(m_Instance); + + Q3DStudio::CString theName = theBridge->GetName(m_Instance); + theName += " ("; + theName += theBridge->GetName(m_DualPersonalityInstance); + theName += ")"; + + return theName; +} + +//============================================================================== +/** + * Query the number of groups to display + */ +long CUICDMInspectable::GetGroupCount() +{ + // If you have a dual personality inspectable then you may overwrite + QT3DS_ASSERT( + m_Instance == m_DualPersonalityInstance + || m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()->IsComponentInstance( + m_Instance)); + IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData(); + long count = (long)theMetaData.GetGroupCountForInstance(m_Instance); + return count; +} + +//============================================================================== +/** + * Return the property group for display + */ +CInspectorGroup *CUICDMInspectable::GetGroup(long inIndex) +{ + CUICDMInspectorGroup *theGroup = + new CUICDMInspectorGroup(m_App, GetGroupName(inIndex).toQString(), *this, inIndex); + + TMetaDataPropertyHandleList theProperties = GetGroupProperties(inIndex); + + size_t thePropertyCount = theProperties.size(); + for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) + theGroup->CreateRow(m_Core->GetDoc(), theProperties[thePropertyIndex]); + + return theGroup; +} + +//============================================================================== +/** + * Return the property handles for display, given the group index + */ +TMetaDataPropertyHandleList CUICDMInspectable::GetGroupProperties(long inIndex) +{ + TMetaDataPropertyHandleList retval; + IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData(); + theMetaData.GetMetaDataProperties(GetGroupInstance(inIndex), retval); + UICDM::IPropertySystem &thePropertySystem( + *m_Core->GetDoc()->GetStudioSystem()->GetPropertySystem()); + // get name of the current group fofr filtering + Option<UICDM::TCharStr> theGroupFilterName = + theMetaData.GetGroupFilterNameForInstance(GetGroupInstance(inIndex), inIndex); + long theGroupCount = GetGroupCount(); + + // end is explicitly required + for (size_t idx = 0; idx < retval.size(); ++idx) { + if (theMetaData.GetMetaDataPropertyInfo(retval[idx])->m_IsHidden) { + retval.erase(retval.begin() + idx); + --idx; + } else if (theGroupCount > 1 && theGroupFilterName.hasValue() + && theMetaData.GetMetaDataPropertyInfo(retval[idx])->m_GroupName + != theGroupFilterName) { + retval.erase(retval.begin() + idx); + --idx; + } else { + qt3ds::foundation::NVConstDataRef<SPropertyFilterInfo> theFilters( + theMetaData.GetMetaDataPropertyFilters(retval[idx])); + if (theFilters.size()) { + Option<bool> keepProperty; + // The tests are done in an ambiguous way. Really, show if equal should take + // multiple conditions + // as should hide if equal. They do not, so we need to rigorously define exactly + // how those two interact. + for (QT3DSU32 propIdx = 0, propEnd = theFilters.size(); propIdx < propEnd; ++propIdx) { + const SPropertyFilterInfo &theFilter(theFilters[propIdx]); + + QT3DS_ASSERT(theFilter.m_FilterType == PropertyFilterTypes::ShowIfEqual + || theFilter.m_FilterType == PropertyFilterTypes::HideIfEqual); + + SValue theValue; + thePropertySystem.GetInstancePropertyValue( + GetGroupInstance(inIndex), theFilter.m_FilterProperty, theValue); + bool resultIfTrue = + theFilter.m_FilterType == PropertyFilterTypes::ShowIfEqual ? true : false; + if (Equals(theValue.toOldSkool(), theFilter.m_Value.toOldSkool())) { + keepProperty = resultIfTrue; + break; + } else { + keepProperty = !resultIfTrue; + } + } + if (keepProperty.hasValue() && *keepProperty == false) { + retval.erase(retval.begin() + idx); + --idx; + } + } + } + } + return retval; +} + +//============================================================================== +/** + * Return the Resource String ID for the Group Name, given the group index + */ +Q3DStudio::CString CUICDMInspectable::GetGroupName(long inGroupIndex) +{ + std::vector<TCharStr> theGroupNames; + IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData(); + theMetaData.GetGroupNamesForInstance(GetGroupInstance(inGroupIndex), theGroupNames); + + size_t theIndex = inGroupIndex; + + if (theGroupNames.size() > theIndex) { + Q3DStudio::CString theName = theGroupNames[inGroupIndex].wide_str(); + return theName; + } else + return ::LoadResourceString(IDS_PROPERTIES_BASIC); +} + +//============================================================================== +/** + * Return the Inspectable Instance Handle for the Group, given the group index + */ +CUICDMInstanceHandle CUICDMInspectable::GetGroupInstance(long inGroupIndex) +{ + Q_UNUSED(inGroupIndex); + return m_DualPersonalityInstance; +} + +EStudioObjectType CUICDMInspectable::GetObjectType() +{ + IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData(); + Option<UICDM::TCharStr> theObjTypeName = theMetaData.GetTypeForInstance(m_Instance); + if (theObjTypeName.hasValue()) { + ComposerObjectTypes::Enum theType = + ComposerObjectTypes::Convert(theObjTypeName->wide_str()); + switch (theType) { + case ComposerObjectTypes::Slide: { + CDoc *theDoc = m_Core->GetDoc(); + CClientDataModelBridge *theBridge = + theDoc->GetStudioSystem()->GetClientDataModelBridge(); + UICDM::CUICDMInstanceHandle theInstance = + theBridge->GetOwningComponentInstance(theDoc->GetActiveSlide()); + Option<TCharStr> theObjTypeName = theMetaData.GetTypeForInstance(theInstance); + if (theObjTypeName.hasValue()) { + ComposerObjectTypes::Enum theType = + ComposerObjectTypes::Convert(theObjTypeName->wide_str()); + if (theType == ComposerObjectTypes::Scene) + return OBJTYPE_SCENE; + else + return OBJTYPE_COMPONENT; + } + return OBJTYPE_UNKNOWN; + } + case ComposerObjectTypes::Scene: + return OBJTYPE_SCENE; + case ComposerObjectTypes::Layer: + return OBJTYPE_LAYER; + case ComposerObjectTypes::Behavior: + return OBJTYPE_BEHAVIOR; + case ComposerObjectTypes::Material: + return OBJTYPE_MATERIAL; + case ComposerObjectTypes::Camera: + return OBJTYPE_CAMERA; + case ComposerObjectTypes::Light: + return OBJTYPE_LIGHT; + case ComposerObjectTypes::Model: + return OBJTYPE_MODEL; + case ComposerObjectTypes::Group: + return OBJTYPE_GROUP; + case ComposerObjectTypes::Image: + return OBJTYPE_IMAGE; + case ComposerObjectTypes::Text: + return OBJTYPE_TEXT; + case ComposerObjectTypes::Component: + return OBJTYPE_COMPONENT; + case ComposerObjectTypes::Effect: + return OBJTYPE_EFFECT; + case ComposerObjectTypes::CustomMaterial: + return OBJTYPE_CUSTOMMATERIAL; + case ComposerObjectTypes::ReferencedMaterial: + return OBJTYPE_REFERENCEDMATERIAL; + case ComposerObjectTypes::Path: + return OBJTYPE_PATH; + case ComposerObjectTypes::SubPath: + return OBJTYPE_SUBPATH; + case ComposerObjectTypes::PathAnchorPoint: + return OBJTYPE_PATHANCHORPOINT; + case ComposerObjectTypes::Lightmaps: + return OBJTYPE_LIGHTMAPS; + } + } + return OBJTYPE_UNKNOWN; +} + +bool CUICDMInspectable::IsValid() const +{ + return m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_Instance) + && m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_DualPersonalityInstance); +} + +bool CUICDMInspectable::IsMaster() +{ + ISlideSystem *theSlideSystem = m_Core->GetDoc()->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theSlideHandle = theSlideSystem->GetAssociatedSlide(m_Instance); + if (theSlideHandle.Valid()) + return theSlideSystem->IsMasterSlide(theSlideHandle); + // Slide handle may not be valid if we are selecting the Scene or if we are inside Component and + // we select the Component root. + return false; +} + +// std::wstring CUICDMInspectable::GetTypeString( ) const +//{ +// std::wstring theReturn(L""); +// try +// { +// IPropertySystem* thePropertySystem = m_Core->GetDoc( )->GetStudioSystem( +//)->GetPropertySystem( ); +// CUICDMPropertyHandle theProperty = +//thePropertySystem->GetAggregateInstancePropertyByName( m_Instance, L"type" ); +// SValue theTypeValue; +// if ( theProperty && thePropertySystem->GetInstancePropertyValue( m_Instance, +//theProperty, theTypeValue ) ) +// { +// theReturn.assign( UICDM::get<TDataStrPtr>( theTypeValue )->GetData() ); +// } +// } +// catch( ... ) +// { +// theReturn.assign(L""); +// } +// +// return theReturn; +//} diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h new file mode 100644 index 00000000..f497d4f9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_UICDM_INSPECTABLE_H +#define INCLUDED_UICDM_INSPECTABLE_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "InspectableBase.h" +#include "UICDMHandles.h" +#include "StudioApp.h" + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** +* For inspecting data model instances +*/ +class CUICDMInspectable : public CInspectableBase +{ +protected: // Fields + UICDM::CUICDMInstanceHandle m_Instance; + UICDM::CUICDMInstanceHandle m_DualPersonalityInstance; + CStudioApp &m_App; + +public: // Constructor + CUICDMInspectable(CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inDualPersonalityInstance = 0); + +public: // CInspectableBase + Q3DStudio::CString GetName() override; + long GetGroupCount() override; + CInspectorGroup *GetGroup(long) override; + EStudioObjectType GetObjectType() override; + // virtual std::wstring GetTypeString( ) const; + bool IsValid() const override; + bool IsMaster() override; + virtual UICDM::TMetaDataPropertyHandleList GetGroupProperties(long inGroupIndex); + virtual UICDM::CUICDMInstanceHandle GetGroupInstance(long inGroupIndex); + +protected: + virtual Q3DStudio::CString GetGroupName(long inGroupIndex); +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp new file mode 100644 index 00000000..86f62847 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMInspectorGroup.h" +#include "UICDMInspectorRow.h" +#include "UICDMInspectable.h" +#include "StudioApp.h" +#include "Core.h" +#include "UICDMMetaData.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" + +//============================================================================== +/** + * Constructor + */ +CUICDMInspectorGroup::CUICDMInspectorGroup(CStudioApp &inApp, const QString &inName, + CUICDMInspectable &inInspectable, long inIndex) + : CEasyInspectorGroup(inName) + , m_App(inApp) + , m_Inspectable(inInspectable) + , m_Index(inIndex) +{ +} + +//============================================================================== +/** + * clean up + */ +CUICDMInspectorGroup::~CUICDMInspectorGroup() +{ + std::vector<Q3DStudio::CUICDMInspectorRow *>::iterator theIterator = + m_UICDMInspectorRows.begin(); + for (; theIterator != m_UICDMInspectorRows.end(); ++theIterator) + delete (*theIterator); +} + +//============================================================================== +/** + * Method to create a new InspectorRowBase. + */ +void CUICDMInspectorGroup::CreateRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty) +{ + Q3DStudio::CUICDMInspectorRow *theUICDMRow = + new Q3DStudio::CUICDMInspectorRow(inDoc, inProperty); + m_UICDMInspectorRows.push_back( + theUICDMRow); // this CUICDMInspectorRow is now owned by this class + +} diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h new file mode 100644 index 00000000..3d811364 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_UICDM_INSPECTORGROUP_H +#define INCLUDED_UICDM_INSPECTORGROUP_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "EasyInspectorGroup.h" +#include "UICDMHandles.h" +#include "StudioApp.h" + +class CDoc; +namespace Q3DStudio { +class CUICDMInspectorRow; +}; + +class CUICDMInspectable; + +//============================================================================== +/** + * + */ +class CUICDMInspectorGroup: public CEasyInspectorGroup +{ +protected: // Members + CStudioApp &m_App; + std::vector<Q3DStudio::CUICDMInspectorRow *> m_UICDMInspectorRows; + CUICDMInspectable &m_Inspectable; + long m_Index; + +public: // Construction + CUICDMInspectorGroup(CStudioApp &inApp, const QString &inName, + CUICDMInspectable &inInspectable, long inIndex); + ~CUICDMInspectorGroup(); + + const std::vector<Q3DStudio::CUICDMInspectorRow *> &GetRows() const + { + return m_UICDMInspectorRows; + } + +public: // Use + void CreateRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty); +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp new file mode 100644 index 00000000..d92ef10a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMInspectorRow.h" +#include "UICDMMetaData.h" +#include "Doc.h" +#include "StudioApp.h" +#include "UICDMSlides.h" +#include "UICDMStudioSystem.h" +#include "UICDMAnimation.h" +#include "UICDMSignals.h" +#include "CmdDataModelDeanimate.h" +#include "UICDMDataCore.h" +#include "Core.h" +#include "ClientDataModelBridge.h" +#include "IDocumentEditor.h" + +//============================================================================== +// Namespace +//============================================================================== +using namespace UICDM; +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + */ +CUICDMInspectorRow::CUICDMInspectorRow(CDoc *inDoc, + CUICDMMetaDataPropertyHandle inProperty) + : m_MetaProperty(inProperty) +{ + IMetaData *theMetaData = inDoc->GetStudioSystem()->GetActionMetaData(); + SMetaDataPropertyInfo theInfo(theMetaData->GetMetaDataPropertyInfo(inProperty)); + m_MetaDataPropertyInfo = theInfo; +} + +//============================================================================== +/** + * Destructor + */ +CUICDMInspectorRow::~CUICDMInspectorRow() +{ +} + +} // namespace Q3DStudio diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h new file mode 100644 index 00000000..ff2155bc --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMHandles.h" +#include "IEasyInspectorRowListener.h" +#include "IDataDrivenChangeListener.h" +#include "DispatchListeners.h" +#include "UICDMMetaDataTypes.h" +#include "CmdBatch.h" + +//============================================================================== +// Forwards +//============================================================================== +class CDoc; +class CEasyInspectorRow; + +// UICDM +namespace UICDM { +class ISignalConnection; +} + +class CGenericEdit; +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * This is a binding between a DataModelInspectable and an EasyInspectorRow + */ +class CUICDMInspectorRow +{ + //============================================================================== + // Members + //============================================================================== +protected: + UICDM::CUICDMMetaDataPropertyHandle m_MetaProperty; + UICDM::SMetaDataPropertyInfo m_MetaDataPropertyInfo; + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CUICDMInspectorRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty); + virtual ~CUICDMInspectorRow(); + +private: // Disabled parameterless construction + CUICDMInspectorRow(); + +public: // Use + UICDM::CUICDMMetaDataPropertyHandle GetMetaDataProperty() const + { + return m_MetaProperty; + } + const UICDM::SMetaDataPropertyInfo &GetMetaDataPropertyInfo() const + { + return m_MetaDataPropertyInfo; + } +}; + +} // namespace Q3DStudio diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp new file mode 100644 index 00000000..70b204e5 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "UICDMMaterialInspectable.h" +#include "UICDMInspectorGroup.h" +#include "UICDMInspectorRow.h" +#include "Core.h" +#include "IDocumentEditor.h" +#include "GenericComboDropDown.h" +#include "UICDMHandles.h" +#include "Doc.h" +#include "GenericFunctor.h" +#include "StudioApp.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "IDocumentReader.h" +#include "Dispatch.h" +#include "IDirectoryWatchingSystem.h" +#include "UICDMSignals.h" +#include "UICString.h" + +using namespace UICDM; + +struct SMaterialTypeDropDown : public CGenericComboDropDown +{ + struct SMaterialEntry + { + Q3DStudio::CString m_Name; + Q3DStudio::CString m_RelativePath; + bool operator<(const SMaterialEntry &inOther) const { return m_Name < inOther.m_Name; } + }; + CUICDMInstanceHandle m_Instance; + Q3DStudio::CAutoMemPtr<CGenericEditCommitListener> m_CommitListener; + vector<SMaterialEntry> m_Materials; + CDoc &m_Doc; + TSignalConnectionPtr m_FileListPtr; + + SMaterialTypeDropDown(CDoc &inDoc, CUICDMInstanceHandle inInstance) + : m_Instance(inInstance) + , m_Doc(inDoc) + { + using Q3DStudio::CString; + using Q3DStudio::CFilePath; + m_CommitListener = + CREATE_LISTENER(CGenericEditCommitListener, SMaterialTypeDropDown, OnDataCommit); + AddCommitListener(m_CommitListener); + m_FileListPtr = m_Doc.GetDirectoryWatchingSystem()->AddDirectory( + m_Doc.GetDocumentDirectory().toQString(), + std::bind(&SMaterialTypeDropDown::OnFilesChanged, this, std::placeholders::_1)); + } + + vector<SMaterialEntry>::iterator GetMaterialEntry(const Q3DStudio::CString &inRelativePath) + { + for (size_t idx = 0, end = m_Materials.size(); idx < end; ++idx) + if (m_Materials[idx].m_RelativePath == inRelativePath) + return m_Materials.begin() + idx; + return m_Materials.end(); + } + + vector<SMaterialEntry>::iterator + GetOrCreateMaterialEntry(const Q3DStudio::CString &inRelativePath) + { + vector<SMaterialEntry>::iterator retval = GetMaterialEntry(inRelativePath); + if (retval == m_Materials.end()) { + m_Materials.push_back(SMaterialEntry()); + m_Materials.back().m_RelativePath = inRelativePath; + return m_Materials.begin() + m_Materials.size() - 1; + } else + return retval; + } + + void OnFilesChanged(const Q3DStudio::TFileModificationList &inFileModificationList) + { + for (size_t idx = 0, end = inFileModificationList.size(); idx < end; ++idx) { + const Q3DStudio::SFileModificationRecord &theRecord = inFileModificationList[idx]; + Q3DStudio::CFilePath relativePath(Q3DStudio::CFilePath::GetRelativePathFromBase( + m_Doc.GetDocumentDirectory(), theRecord.m_File)); + Q3DStudio::CString extension = relativePath.GetExtension(); + if (extension.CompareNoCase("material")) { + switch (theRecord.m_ModificationType) { + case Q3DStudio::FileModificationType::Created: + case Q3DStudio::FileModificationType::Modified: { + SMaterialEntry &theEntry = + *GetOrCreateMaterialEntry(Q3DStudio::CString(relativePath)); + theEntry.m_Name = + m_Doc.GetDocumentReader().GetCustomMaterialName(theRecord.m_File); + } break; + case Q3DStudio::FileModificationType::Destroyed: { + vector<SMaterialEntry>::iterator theEntry = GetMaterialEntry(relativePath); + if (theEntry != m_Materials.end()) + m_Materials.erase(theEntry); + } break; + + default: // don't care. + break; + } + } + } + + std::sort(m_Materials.begin(), m_Materials.end()); + + RefreshAllItems(); + } + + void RefreshAllItems() + { + RemoveAllItems(); + AddItem("Standard Material"); + AddItem("Referenced Material"); + CClientDataModelBridge *theBridge = m_Doc.GetStudioSystem()->GetClientDataModelBridge(); + long selectIdx = 0; + EStudioObjectType theType = theBridge->GetObjectType(m_Instance); + + if (theType == OBJTYPE_REFERENCEDMATERIAL) + selectIdx = 1; + + Q3DStudio::CString sourcePath = theBridge->GetSourcePath(m_Instance); + + for (size_t matIdx = 0, end = m_Materials.size(); matIdx < end; ++matIdx) { + AddItem(m_Materials[matIdx].m_Name); + if (m_Materials[matIdx].m_RelativePath.Compare(sourcePath)) + selectIdx = (long)matIdx + 2; + } + + SelectItem(selectIdx, false); + } + + // Note that the this object is probably deleted when this happens or will be during its + // execution. + static void DoChangeObjectType(CDoc *inDoc, const Q3DStudio::CString &inNewType, + CUICDMInstanceHandle instance) + { + using namespace Q3DStudio; + SCOPED_DOCUMENT_EDITOR(*inDoc, QObject::tr("Set Property"))->SetMaterialType(instance, inNewType); + } + + void OnDataCommit() + { + using Q3DStudio::CString; + size_t item = this->GetSelectedItem(); + if (item >= 0) { + CString selectedType = this->GetItemText(this->GetSelectedItem()); + if (item > 1) { + size_t matIdx = item - 2; + if (matIdx < m_Materials.size()) + selectedType = m_Materials[matIdx].m_RelativePath; + } + // Fire a command to do this later because we will get screwed if we don't as we will be + // deleted + // during this process. + g_StudioApp.GetCore()->GetDispatch()->FireOnAsynchronousCommand( + std::bind(&DoChangeObjectType, &m_Doc, selectedType, m_Instance)); + } + } +}; + +UICDMMaterialInspectorGroup::UICDMMaterialInspectorGroup( + CStudioApp &inApp, + const Q3DStudio::CString &inName, + CUICDMInspectable &inInspectable, + long inIndex) + : CUICDMInspectorGroup(inApp, inName.toQString(), inInspectable, inIndex) +{ +} + +struct SUICDMMaterialInspectorGroup : public UICDMMaterialInspectorGroup +{ + SUICDMMaterialInspectorGroup(CStudioApp &inApp, const Q3DStudio::CString &inName, + CUICDMInspectable &inInspectable, long inIndex) + : UICDMMaterialInspectorGroup(inApp, inName, inInspectable, inIndex) + { + Q3DStudio::CString theMaterialGroupName = L"Material"; + m_isMaterialGroup = (inName == theMaterialGroupName); + } + + bool isMaterialGroup() const override + { + return m_isMaterialGroup; + } + +private: + bool m_isMaterialGroup; +}; + +CInspectorGroup *CUICDMMaterialInspectable::GetGroup(long inIndex) +{ + Q3DStudio::CString theGroupName = GetGroupName(inIndex); + Q3DStudio::CString theMaterialGroupName = L"Material"; + + CUICDMInspectorGroup *theGroup = + new SUICDMMaterialInspectorGroup(m_App, theGroupName, *this, inIndex); + + TMetaDataPropertyHandleList theProperties = GetGroupProperties(inIndex); + size_t thePropertyCount = theProperties.size(); + + for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) + theGroup->CreateRow(m_Core->GetDoc(), theProperties[thePropertyIndex]); + + return theGroup; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h new file mode 100644 index 00000000..20bb4365 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_UICDM_MATERIAL_INSPECTABLE_H +#define INCLUDED_UICDM_MATERIAL_INSPECTABLE_H 1 + +#include "UICDMInspectable.h" +#include "UICDMInspectorGroup.h" + +class UICDMMaterialInspectorGroup : public CUICDMInspectorGroup +{ +public: + UICDMMaterialInspectorGroup(CStudioApp &inApp, const Q3DStudio::CString &inName, + CUICDMInspectable &inInspectable, long inIndex); + + virtual bool isMaterialGroup() const = 0; +}; + +class CUICDMMaterialInspectable : public CUICDMInspectable +{ +public: + CUICDMMaterialInspectable(CStudioApp &inApp, CCore *inCore, + UICDM::CUICDMInstanceHandle inInstance) + : CUICDMInspectable(inApp, inCore, inInstance) + { + } + + CInspectorGroup *GetGroup(long) override; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp new file mode 100644 index 00000000..85f9b60c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMSceneInspectable.h" +#include "Core.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" + +CUICDMSceneInspectable::CUICDMSceneInspectable( + CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inCurrentActiveSlideInstance) + : CUICDMInspectable(inApp, inCore, inInstance) + , m_CurrentActiveSlideInstance(inCurrentActiveSlideInstance) +{ +} + +bool CUICDMSceneInspectable::IsValid() const +{ + return CUICDMInspectable::IsValid() + && m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_CurrentActiveSlideInstance); +} + +long CUICDMSceneInspectable::GetGroupCount() +{ + return 2; // hard-coded to basic and shared +} + +//============================================================================== +/** + * Return the Resource String ID for the Group Name, given the group index + */ +Q3DStudio::CString CUICDMSceneInspectable::GetGroupName(long inGroupIndex) +{ + return (inGroupIndex == 0) ? ::LoadResourceString(IDS_PROPERTIES_BASIC) + : ::LoadResourceString(IDS_PROPERTIES_SHARED); +} + +UICDM::CUICDMInstanceHandle CUICDMSceneInspectable::GetGroupInstance(long inGroupIndex) +{ + return (inGroupIndex == 0) ? m_CurrentActiveSlideInstance : m_Instance; +} diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h new file mode 100644 index 00000000..f30693b9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_UICDM_SCENE_INSPECTABLE_H +#define INCLUDED_UICDM_SCENE_INSPECTABLE_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMInspectable.h" + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** +* For inspecting scene data model instances +*/ +class CUICDMSceneInspectable : public CUICDMInspectable +{ +public: + CUICDMSceneInspectable(CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inCurrentActiveSlideInstance); + + bool IsValid() const override; + // CUICDMInspectable + long GetGroupCount() override; + +protected: + inline Q3DStudio::CString GetGroupName(long inGroupIndex) override; + inline UICDM::CUICDMInstanceHandle GetGroupInstance(long inGroupIndex) override; + + UICDM::CUICDMInstanceHandle m_CurrentActiveSlideInstance; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Master/MasterControl.cpp b/src/Authoring/Studio/Palettes/Master/MasterControl.cpp new file mode 100644 index 00000000..922b6d02 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Master/MasterControl.cpp @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "MasterControl.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "StudioApp.h" +#include "Doc.h" +#include "InspectorControl.h" +#include "ActionControl.h" +#include "GenericTabControl.h" + +//=============================================================================== +/** + * Constructor + * @param inStudioApp + */ +CMasterControl::CMasterControl(IMasterControlProvider *inProvider) + : m_Provider(inProvider) + , m_TabMenu(nullptr) + , m_RenderDevice(nullptr) +{ + // Create the tab control + m_TabControl = new CGenericTabControl(); + AddChild(m_TabControl); + m_TabControl->SigTabSelected.connect(std::bind(&CMasterControl::OnTabSelected, this, + std::placeholders::_1, std::placeholders::_2)); + + // Add the drop-down menu + m_MenuButton = new CProceduralButton<CButtonControl>(); + m_MenuButton->SetUpImage("Storage-Dropdown-Normal.png"); + m_MenuButton->SetDisabledImage("Tab-Menu-Disabled.png"); + m_MenuButton->SetAbsoluteSize(m_MenuButton->GetImageSize()); + m_MenuButton->SetFillColorUp(CStudioPreferences::GetDarkBaseColor()); + m_MenuButton->SetFillColorDown(CStudioPreferences::GetDarkBaseColor()); + m_MenuButton->SetFillColorOver(CStudioPreferences::GetDarkBaseColor()); + m_MenuButton->SetFillColorDisabled(CStudioPreferences::GetDarkBaseColor()); + m_MenuButton->SetFillStyleAll(CProceduralButton<CButtonControl>::EFILLSTYLE_FLOOD); + CProceduralButton<CButtonControl>::SBorderOptions theBorders(false, false, false, false); + m_MenuButton->SetBorderVisibilityAll(theBorders); + m_MenuButton->SigButtonDown.connect(std::bind(&CMasterControl::OnMenuButtonDown, this, + std::placeholders::_1)); + m_TabControl->SetTabBarSibling(m_MenuButton); +} + +//=============================================================================== +/** + * Destructor + */ +CMasterControl::~CMasterControl() +{ + RemoveChild(m_TabControl); +} + +//=============================================================================== +/** + * Display the context menu for this control + */ +void CMasterControl::DisplayContextMenu(CPt inPosition) +{ + ASSERT(m_Provider != nullptr); + m_Provider->OnContextMenu(this, inPosition, m_TabMenu); +} + +//============================================================================= +/** + * Callback when the menu button is selected + */ +void CMasterControl::AddControl(const Q3DStudio::CString &inName, long inType, CControl *inControl) +{ + inControl->SetName(inName); + m_ControlList.insert(std::make_pair(inControl, inType)); + m_TabControl->AddTab(inName, inControl); +} + +//============================================================================= +/** + * Callback when the menu button is selected + */ +void CMasterControl::RemoveControl(CControl *inControl) +{ + TControlMap::iterator theIterator = m_ControlList.begin(); + TControlMap::iterator theEndIterator = m_ControlList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (inControl == theIterator->first) { + m_ControlList.erase(theIterator); + break; + } + } + + if (m_ControlList.size()) + m_TabControl->SelectTab((long)0); + + m_TabControl->RemoveTab(inControl); +} + +//============================================================================= +/** + * Callback when the menu button is selected + */ +void CMasterControl::SelectControl(long inIndex) +{ + m_TabControl->SelectTab(inIndex); +} + +//============================================================================= +/** + * Callback when the menu button is selected + */ +void CMasterControl::SelectControl(CControl *inControl) +{ + m_TabControl->SelectTab(inControl); +} + +//============================================================================= +/** + * Return the number of controls + */ +long CMasterControl::GetControlCount() +{ + return m_TabControl->GetTabCount(); +} + +//============================================================================= +/** + * Return the control for the specified type + */ +CControl *CMasterControl::FindControl(long inType) +{ + CControl *theControl = nullptr; + TControlMap::iterator theIterator = m_ControlList.begin(); + TControlMap::iterator theEndIterator = m_ControlList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (inType == theIterator->second) { + theControl = theIterator->first; + break; + } + } + return theControl; +} + +//============================================================================= +/** + * Return the active control + */ +CControl *CMasterControl::GetActiveControl() +{ + return m_TabControl->GetSelectedTab(); +} + +//============================================================================= +/** + * Return the index of the active tab + */ +long CMasterControl::GetActiveIndex() +{ + return m_TabControl->GetSelectedTabIndex(); +} + +//============================================================================= +/** + * Return the active type + */ +long CMasterControl::GetActiveType() +{ + return m_ControlList[GetActiveControl()]; +} + +//============================================================================= +/** + * Callback when the menu button is selected + */ +void CMasterControl::OnMenuButtonDown(CControl *) +{ + CPt thePosition(GetSize().x, GetPosition().y + m_MenuButton->GetSize().y); + DisplayContextMenu(thePosition); +} + +//============================================================================= +/** + * Callback when a tab changes + */ +void CMasterControl::OnTabSelected(CControl *, CControl *inNewControl) +{ + // Notify the provider that the selection changed + m_Provider->OnControlSelected(this, inNewControl, m_ControlList[inNewControl]); + + // Set the enabled state of the menu item + m_MenuButton->SetEnabled((m_TabControl->GetTabCount() != 0)); +} + +//============================================================================== +// CControl +//============================================================================== + +Q3DStudio::CString CMasterControl::GetName() +{ + CControl *theActiveControl = GetActiveControl(); + if (theActiveControl) + return theActiveControl->GetName(); + return L"< Empty >"; +} + +//============================================================================= +/** + * Fills the whole control with the base (gray) color, then other controls will + * draw on top of that. + * @param inRenderer renderer to draw to + */ +void CMasterControl::Draw(CRenderer *inRenderer) +{ + inRenderer->FillSolidRect(GetSize(), CStudioPreferences::GetDarkBaseColor()); +} + +//============================================================================= +/** + * Set the size of the tree control + */ +void CMasterControl::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + m_TabControl->SetSize(inSize); +} + +//============================================================================= +/** + * Check to see if the right mouse down occurred on the tab control + */ +bool CMasterControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_TabControl->IsInTabBar(inPoint)) { + DisplayContextMenu(inPoint); + return true; + } + + return CControl::OnMouseRDown(inPoint, inFlags); // not handled +} + +//============================================================================= +/** + * Return the window handle to the master view + */ +UICRenderDevice CMasterControl::GetPlatformDevice() +{ + return m_RenderDevice; +} + +//============================================================================= +/** + * Overriden from CControl. Since this control's parent is the CWnd, ensure + * that it gets the keyboard focus if this function is called. + * @see CControl::SetFocus + */ +void CMasterControl::GrabFocus(CControl *inControl) +{ + if (m_RenderDevice) { + ::SetFocus(m_RenderDevice); + } + + CControl::GrabFocus(inControl); +} diff --git a/src/Authoring/Studio/Palettes/Master/MasterControl.h b/src/Authoring/Studio/Palettes/Master/MasterControl.h new file mode 100644 index 00000000..40a347a4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Master/MasterControl.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_MASTER_CONTROL_H +#define INCLUDED_MASTER_CONTROL_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "ProceduralButton.h" + +//============================================================================== +// Forwards +//============================================================================== +class CStudioApp; +class CRenderer; +class CAssetControl; +class CGenericTabControl; +class CMasterControl; + +//============================================================================== +/** + * @class IMasterControlProvider + */ +class IMasterControlProvider +{ +public: + virtual void OnControlRemoved(CMasterControl *inControl) = 0; + virtual void OnContextMenu(CMasterControl *inControl, const CPt &inPosition, + CContextMenu *inMyMenu) = 0; + virtual void OnControlSelected(CMasterControl *inMaster, CControl *inControl, long inType) = 0; +}; + +//============================================================================== +/** + * @class CMasterControl + * @brief Class wrapping up all controls that appear in the Inspector Palette. + */ +class CMasterControl : public CControl +{ +protected: + typedef std::map<CControl *, long> TControlMap; + +public: + CMasterControl(IMasterControlProvider *inProvider); + ~CMasterControl(); + + void SetRenderDevice(UICRenderDevice inDevice) { m_RenderDevice = inDevice; } + + void AddControl(const Q3DStudio::CString &inName, long inType, CControl *inControl); + void RemoveControl(CControl *inControl); + void SelectControl(long inIndex); + void SelectControl(CControl *inControl); + long GetControlCount(); + CControl *FindControl(long inType); + + long GetActiveType(); + long GetActiveIndex(); + CControl *GetActiveControl(); + + // CControl + virtual Q3DStudio::CString GetName(); + void Draw(CRenderer *inRenderer) override; + void SetSize(CPt inSize) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + UICRenderDevice GetPlatformDevice() override; + void GrabFocus(CControl *inControl) override; + +protected: + void DisplayContextMenu(CPt inPosition); + void OnTabSelected(CControl *inOldControl, CControl *inNewControl); + void OnMenuButtonDown(CControl *); + +protected: + IMasterControlProvider *m_Provider; ///< + CContextMenu *m_TabMenu; ///< + Q3DStudio::CAutoMemPtr<CGenericTabControl> m_TabControl; ///< + Q3DStudio::CAutoMemPtr<CProceduralButton<CButtonControl>> + m_MenuButton; ///< menu button for the storage palette + TControlMap m_ControlList; ///< the list of controls to display + UICRenderDevice m_RenderDevice; ///< +}; + +#endif //#ifndef INCLUDED_MASTER_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Master/MasterView.cpp b/src/Authoring/Studio/Palettes/Master/MasterView.cpp new file mode 100644 index 00000000..8a4a9bd5 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Master/MasterView.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "MasterView.h" +#include "WndControl.h" +#include "StudioApp.h" +#include "MasterControl.h" +#include "IDragable.h" + +//============================================================================== +// Message Maps, etc. +//============================================================================== +IMPLEMENT_DYNCREATE(CMasterView, CView) + +BEGIN_MESSAGE_MAP(CMasterView, CView) +//{{AFX_MSG_MAP(CMasterView) +ON_WM_SIZE() +ON_WM_ERASEBKGND() +ON_WM_MOUSEACTIVATE() +//}}AFX_MSG_MAP +ON_MESSAGE(WM_STUDIO_INITIALIZE_PALETTES, OnInitializePalettes) +END_MESSAGE_MAP() + +int CMasterView::OnMouseActivate(CWnd *, UINT, UINT) +{ + return MA_NOACTIVATE; +} + +//============================================================================= +/** + * Constructor: Protected because the view is always created dynamically. + * You must call Initialize() before trying to use this class. + */ +CMasterView::CMasterView() + : m_WndControl(nullptr) + , m_Provider(nullptr) +{ +} + +//============================================================================= +/** + * Destructor + */ +CMasterView::~CMasterView() +{ + m_WndControl->DestroyWindow(); + m_WndControl = nullptr; + + m_MasterControl = nullptr; +} + +//============================================================================== +/** + * Handles the WM_INITIALUPDATE message. Responsible for preparing the view + * before it is displayed for the first time. + */ +LRESULT CMasterView::OnInitializePalettes(WPARAM inwParam, LPARAM) +{ + if (!m_WndControl) { + CStudioApp *theStudioApp = reinterpret_cast<CStudioApp *>(inwParam); + + m_MasterControl = new CMasterControl(m_Provider); + m_WndControl = new CWndControl(m_MasterControl); + + m_WndControl->RegiserForDnd(this); + + m_WndControl->AddMainFlavor(EUIC_FLAVOR_LISTBOX); + m_WndControl->AddMainFlavor(EUIC_FLAVOR_FILE); + m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_UICFILE); + m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_LIB); + m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_TL); + m_WndControl->AddMainFlavor(EUIC_FLAVOR_BASIC_OBJECTS); + + CRect theClientRect; + GetClientRect(&theClientRect); + + m_WndControl->CreateEx( + WS_EX_NOPARENTNOTIFY, AfxRegisterWndClass(CS_DBLCLKS, LoadCursor(nullptr, IDC_ARROW), + (HBRUSH)GetStockObject(BLACK_BRUSH)), + L"MasterViewWndCtrl", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + theClientRect, this, 100); + m_MasterControl->SetRenderDevice(m_WndControl->GetSafeHwnd()); + } + + return 0; +} + +//============================================================================= +/** + * Required by base class but does nothing since all drawing is handled by the + * child control. + */ +void CMasterView::OnDraw(CDC *inDC) +{ + Q_UNUSED(inDC); +} + +//============================================================================= +/** + * Resizes the wnd control to fill the whole view. + */ +void CMasterView::OnSize(UINT inType, int inX, int inY) +{ + CView::OnSize(inType, inX, inY); + if (::IsWindow(m_WndControl->GetSafeHwnd())) + m_WndControl->MoveWindow(0, 0, inX, inY); +} + +//============================================================================== +/** + * Tells the Inspector to erase before redrawing. Overridden because we erasing + * before each draw produces a flashing effect. + * @param inDC the DC to erase on. + * @return FALSE. + */ +BOOL CMasterView::OnEraseBkgnd(CDC *inDC) +{ + Q_UNUSED(inDC); + return FALSE; +} diff --git a/src/Authoring/Studio/Palettes/Master/MasterView.h b/src/Authoring/Studio/Palettes/Master/MasterView.h new file mode 100644 index 00000000..008d748f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Master/MasterView.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_MASTER_VIEW_H +#define INCLUDED_MASTER_VIEW_H 1 + +#pragma once +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +// Forwards +//============================================================================== +class CStudioApp; +class CWndControl; +class CMasterControl; +class IMasterControlProvider; + +//============================================================================= +/** + * Windows view encapsulating the inspector palette. + */ +class CMasterView : public CView +{ +protected: + CMasterView(); + DECLARE_DYNCREATE(CMasterView) + virtual ~CMasterView(); + + afx_msg void OnSize(UINT inType, int inX, int inY); + afx_msg BOOL OnEraseBkgnd(CDC *inDC); + afx_msg int OnMouseActivate(CWnd *pDesktopWnd, UINT nHitTest, UINT message); + DECLARE_MESSAGE_MAP() + +public: + virtual void OnDraw(CDC *inDC); + virtual LRESULT OnInitializePalettes(WPARAM inwParam, LPARAM inlParam); + + void SetProvider(IMasterControlProvider *inProvider) { m_Provider = inProvider; } + CMasterControl *GetMasterControl() const { return m_MasterControl; } + +protected: + IMasterControlProvider *m_Provider; ///< + CWndControl *m_WndControl; ///< + Q3DStudio::CAutoMemPtr<CMasterControl> m_MasterControl; ///< +}; + +#endif // INCLUDED_MASTER_VIEW_H diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h b/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h new file mode 100644 index 00000000..eeff02b8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_PROGRESS_CALLBACK_H +#define INCLUDED_PROGRESS_CALLBACK_H 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** + * Callback interface to progress update window + */ +class IProgressCallback +{ +public: + virtual void SetProgress(long inPercent) = 0; + + virtual void SetActionText(const Q3DStudio::CString &inText) = 0; +}; + +#endif // INCLUDED_PROGRESS_CALLBACK_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp b/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp new file mode 100644 index 00000000..2a69bf44 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ProgressControl.h" +#include "Renderer.h" +#include "ResourceCache.h" +#include "ResImage.h" + +//============================================================================== +/** + * Constructor + */ +CProgressControl::CProgressControl() + : m_Percent(0) +{ + // Load the image + m_Image = CResourceCache::GetInstance()->GetBitmap("progress-screen.png"); + + // Load the default string for the window for now + m_ActionText = ::LoadResourceString(IDS_WAIT_LOADING); +} + +//============================================================================== +/** + * Destructor + */ +CProgressControl::~CProgressControl() +{ +} + +//============================================================================== +/** + * The size of this control is equal to the size of the image that we display. + * @return the size (in pixels) of this control. + */ +CPt CProgressControl::GetSize() const +{ + return m_Image->GetSize(); +} + +//============================================================================== +/** + * Draws this control. + * @param inRenderer renderer to draw to. + */ +void CProgressControl::Draw(CRenderer *inRenderer) +{ + // Draw the image over the whole window + inRenderer->DrawBitmap(CPt(0, 0), m_Image); + + // Show "Loading..." + inRenderer->DrawText(105, 20, m_ActionText, GetSize(), CColor(255, 255, 255)); + + // Show the file name + if (!m_FileName.IsEmpty()) + inRenderer->DrawText(105, 35, m_FileName, GetSize(), CColor(255, 255, 255)); + + // Show the percentage + inRenderer->DrawText(105, 50, m_PercentString, GetSize(), CColor(255, 255, 255)); +} + +//============================================================================== +/** + * Sets the text displayed above the file name. For instance: "Loading..." + * @param inText text to be shown above the file name + */ +void CProgressControl::SetActionText(const Q3DStudio::CString &inText) +{ + m_ActionText = inText; + Invalidate(); +} + +//============================================================================== +/** + * Changes the percentage complete displayed by this control. + * @param inPercent new percentage complete. + */ +void CProgressControl::SetProgress(long inPercent) +{ + m_Percent = inPercent; + char theBuffer[256] = { 0 }; + _ltoa(m_Percent, theBuffer, 10); + m_PercentString = theBuffer; + m_PercentString += " %"; + Invalidate(); +} + +//============================================================================== +/** + * Sets the name of the file that is being opened. This is displayed on the + * control. + * @param inFileName File name to display in the middle of this control + */ +void CProgressControl::SetFileName(const Q3DStudio::CString &inFileName) +{ + m_FileName = inFileName; + Invalidate(); +} diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressControl.h b/src/Authoring/Studio/Palettes/Progress/ProgressControl.h new file mode 100644 index 00000000..1d596c0c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Progress/ProgressControl.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_PROGRESS_CONTROL_H +#define INCLUDED_PROGRESS_CONTROL_H 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CResImage; + +//============================================================================== +/** + * Top-level control of a loading progress window. + */ +class CProgressControl : public CControl +{ +public: + CProgressControl(); + virtual ~CProgressControl(); + + virtual CPt GetSize() const; + virtual void Draw(CRenderer *inRenderer); + virtual void SetActionText(const Q3DStudio::CString &inText); + virtual void SetProgress(long inPercent); + void SetFileName(const Q3DStudio::CString &inFileName); + +protected: + long m_Percent; + Q3DStudio::CString m_ActionText; + Q3DStudio::CString m_PercentString; + Q3DStudio::CString m_FileName; + CResImage *m_Image; +}; + +#endif // INCLUDED_PROGRESS_CONTROL_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp new file mode 100644 index 00000000..edcafbf1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 "ProjectContextMenu.h" +#include "ProjectView.h" + +ProjectContextMenu::ProjectContextMenu(ProjectView *parent, int index) + : QMenu(parent) + , m_view(parent) + , m_index(index) +{ + QAction *action = new QAction(tr("Show in Explorer")); + connect(action, &QAction::triggered, this, &ProjectContextMenu::handleShowInExplorer); + addAction(action); + + addSeparator(); + + action = new QAction(tr("Copy Path")); + connect(action, &QAction::triggered, this, &ProjectContextMenu::handleCopyPath); + addAction(action); + + action = new QAction(tr("Copy Full Path")); + connect(action, &QAction::triggered, this, &ProjectContextMenu::handleCopyFullPath); + addAction(action); + + if (m_view->isGroup(m_index)) { + addSeparator(); + action = new QAction(tr("Refresh Import...")); + connect(action, &QAction::triggered, this, &ProjectContextMenu::handleRefreshImport); + addAction(action); + } +} + +ProjectContextMenu::~ProjectContextMenu() +{ +} + +void ProjectContextMenu::handleShowInExplorer() +{ + m_view->showInExplorer(m_index); +} + +void ProjectContextMenu::handleCopyPath() +{ + m_view->copyPath(m_index); +} + +void ProjectContextMenu::handleCopyFullPath() +{ + m_view->copyFullPath(m_index); +} + +void ProjectContextMenu::handleRefreshImport() +{ + m_view->refreshImport(m_index); +} diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h new file mode 100644 index 00000000..51dc8c5d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 PROJECT_CONTEXT_MENU_H +#define PROJECT_CONTEXT_MENU_H + +#include <QtWidgets/qmenu.h> + +class ProjectView; + +class ProjectContextMenu : public QMenu +{ + Q_OBJECT +public: + explicit ProjectContextMenu(ProjectView *parent, int index); + virtual ~ProjectContextMenu(); + +private Q_SLOTS: + void handleShowInExplorer(); + void handleCopyPath(); + void handleCopyFullPath(); + void handleRefreshImport(); + +private: + ProjectView *m_view; + int m_index; +}; +#endif // PROJECT_CONTEXT_MENU_H diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp new file mode 100644 index 00000000..07ddd3d4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** +** +** 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 "qtAuthoring-config.h" +#include <QtCore/qset.h> + +#include "stdafx.h" +#include "ProjectFileSystemModel.h" +#include "StudioUtils.h" +#include "StudioApp.h" +#include "ClientDataModelBridge.h" +#include "Core.h" +#include "Doc.h" +#include "UICFileTools.h" +#include "ImportUtils.h" +#include "Dialogs.h" +#include "UICDMStudioSystem.h" +#include "UICImportTranslation.h" +#include "IDocumentEditor.h" +#include "PathImportTranslator.h" +#include "IDragable.h" + +ProjectFileSystemModel::ProjectFileSystemModel(QObject *parent) : QAbstractListModel(parent) + , m_model(new QFileSystemModel(this)) +{ + connect(m_model, &QAbstractItemModel::rowsInserted, this, &ProjectFileSystemModel::modelRowsInserted); + connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ProjectFileSystemModel::modelRowsRemoved); + connect(m_model, &QAbstractItemModel::layoutChanged, this, &ProjectFileSystemModel::modelLayoutChanged); +} + +QHash<int, QByteArray> ProjectFileSystemModel::roleNames() const +{ + auto modelRoleNames = m_model->roleNames(); + modelRoleNames.insert(IsExpandableRole, "_isExpandable"); + modelRoleNames.insert(IsDraggableRole, "_isDraggable"); + modelRoleNames.insert(IsReferencedRole, "_isReferenced"); + modelRoleNames.insert(DepthRole, "_depth"); + modelRoleNames.insert(ExpandedRole, "_expanded"); + return modelRoleNames; +} + +int ProjectFileSystemModel::rowCount(const QModelIndex &) const +{ + return m_items.count(); +} + +QVariant ProjectFileSystemModel::data(const QModelIndex &index, int role) const +{ + const auto &item = m_items.at(index.row()); + + switch (role) { + case Qt::DecorationRole: { + QString path = item.index.data(QFileSystemModel::FilePathRole).toString(); + return resourceImageUrl() + getIconName(path); + } + + case IsExpandableRole: { + if (item.index == m_rootIndex) { + return false; + } else { + return hasVisibleChildren(item.index); + } + } + + case IsDraggableRole: + return QFileInfo(item.index.data(QFileSystemModel::FilePathRole).toString()).isFile(); + + case IsReferencedRole: { + const QString path = item.index.data(QFileSystemModel::FilePathRole).toString(); + return m_references.contains(path); + } + + case DepthRole: + return item.depth; + + case ExpandedRole: + return item.expanded; + + default: + return m_model->data(item.index, role); + } +} + +QMimeData *ProjectFileSystemModel::mimeData(const QModelIndexList &indexes) const +{ + const auto path = filePath(indexes.first().row()); // can only drag one item + CUICFile dragFile(Q3DStudio::CString::fromQString(path)); + return CDropSourceFactory::Create(EUIC_FLAVOR_ASSET_UICFILE, + reinterpret_cast<void *>(&dragFile), + sizeof(dragFile)); +} + +QString ProjectFileSystemModel::filePath(int row) const +{ + if (row < 0 || row >= m_items.size()) + return QString(); + const auto &item = m_items.at(row); + return item.index.data(QFileSystemModel::FilePathRole).toString(); +} + +void ProjectFileSystemModel::updateReferences(bool emitDataChanged) +{ + m_references.clear(); + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge(); + const auto sourcePathList = bridge->GetSourcePathList(); + const auto fontFileList = bridge->GetFontFileList(); + const auto effectTextureList = bridge->GetDynamicObjectTextureList(); + + auto addFileReferences = [this, doc](const Q3DStudio::CString &str) { + auto path = doc->GetResolvedPathToDoc(str).toQString(); + path = QDir::cleanPath(path); + m_references.append(path); + QString rootPath = QDir::cleanPath(doc->GetDocumentDirectory().toQString()); + QString parentPath = QFileInfo(path).path(); + do { + if (!m_references.contains(parentPath)) + m_references.append(parentPath); + path = parentPath; + parentPath = QFileInfo(path).path(); + } while (rootPath != path && parentPath != path); + }; + + std::for_each(sourcePathList.begin(), sourcePathList.end(), addFileReferences); + std::for_each(fontFileList.begin(), fontFileList.end(), addFileReferences); + std::for_each(effectTextureList.begin(), effectTextureList.end(), addFileReferences); + + if (emitDataChanged) + Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {IsReferencedRole}); +} + +void ProjectFileSystemModel::setRootPath(const QString &path) +{ + setRootIndex(m_model->setRootPath(path)); +} + +void ProjectFileSystemModel::setRootIndex(const QModelIndex &rootIndex) +{ + if (rootIndex == m_rootIndex) + return; + + clearModelData(); + updateReferences(false); + + m_rootIndex = rootIndex; + + beginInsertRows({}, 0, 0); + m_items.append({ m_rootIndex, 0, true, nullptr, 0 }); + endInsertRows(); + + showModelTopLevelItems(); +} + +void ProjectFileSystemModel::clearModelData() +{ + beginResetModel(); + m_items.clear(); + endResetModel(); +} + +void ProjectFileSystemModel::showModelTopLevelItems() +{ + int rowCount = m_model->rowCount(m_rootIndex); + + if (rowCount == 0) { + if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex)) + m_model->fetchMore(m_rootIndex); + } else { + showModelChildItems(m_rootIndex, 0, rowCount - 1); + } +} + +void ProjectFileSystemModel::showModelChildItems(const QModelIndex &parentIndex, int start, int end) +{ + const int parentRow = modelIndexRow(parentIndex); + if (parentRow == -1) + return; + + Q_ASSERT(isVisible(parentIndex)); + + QVector<QModelIndex> rowsToInsert; + for (int i = start; i <= end; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (isVisible(childIndex)) + rowsToInsert.append(childIndex); + } + + const int insertCount = rowsToInsert.count(); + if (insertCount == 0) + return; + + auto parent = &m_items[parentRow]; + + const int depth = parent->depth + 1; + const int startRow = parentRow + parent->childCount + 1; + + beginInsertRows({}, startRow, startRow + insertCount - 1); + + for (auto it = rowsToInsert.rbegin(); it != rowsToInsert.rend(); ++it) + m_items.insert(startRow, { *it, depth, false, parent, 0 }); + + for (; parent != nullptr; parent = parent->parent) + parent->childCount += insertCount; + + endInsertRows(); + + // also fetch children so we're notified when files are added or removed in immediate subdirs + for (const auto &childIndex : rowsToInsert) { + if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex)) + m_model->fetchMore(childIndex); + } +} + +void ProjectFileSystemModel::expand(int row) +{ + Q_ASSERT(row >= 0 && row < m_items.size()); + + auto &item = m_items[row]; + Q_ASSERT(item.expanded == false); + + const auto &modelIndex = item.index; + + const int rowCount = m_model->rowCount(modelIndex); + if (rowCount == 0) { + if (m_model->hasChildren(modelIndex) && m_model->canFetchMore(modelIndex)) + m_model->fetchMore(modelIndex); + } else { + showModelChildItems(modelIndex, 0, rowCount - 1); + } + + item.expanded = true; + Q_EMIT dataChanged(index(row), index(row)); +} + +bool ProjectFileSystemModel::hasValidUrlsForDropping(const QList<QUrl> &urls) const +{ + for (const auto &url : urls) { + if (url.isLocalFile()) { + const QString path = url.toLocalFile(); + const QFileInfo fileInfo(path); + if (fileInfo.isFile()) { + const QString extension = fileInfo.suffix(); + return extension.compare(QLatin1String(CDialogs::GetDAEFileExtension()), + Qt::CaseInsensitive) == 0 +#ifdef QT_3DSTUDIO_FBX + || extension.compare(QLatin1String(CDialogs::GetFbxFileExtension()), + Qt::CaseInsensitive) == 0 +#endif + || getIconType(path) != OBJTYPE_UNKNOWN; + } + } + } + + return false; +} + +void ProjectFileSystemModel::dropUrls(const QList<QUrl> &urls, int row) +{ + Q_ASSERT(row >= 0 && row < m_items.size()); + + const auto &item = m_items.at(row); + const QString targetPath = item.index.data(QFileSystemModel::FilePathRole).toString(); + const QDir targetDir(targetPath); + + if (targetDir.exists()) { + for (const auto& url : urls) + dropUrl(targetPath, url); + + if (!item.expanded) + expand(row); + } +} + +void ProjectFileSystemModel::dropUrl(const QDir &targetDir, const QUrl &url) const +{ + using namespace Q3DStudio; + using namespace UICIMP; + // Drag and Drop - From Explorer window to Project Palette + // For all valid Project File Types: + // - This performs a file copy from the source Explorer location to the selected Project Palette + // Folder + // - The destination copy must NOT be read-only even if the source is read-only + // For DAE, it will import the file. + + if (!url.isLocalFile()) + return; + + const QString sourceFile = url.toLocalFile(); + + const QFileInfo fileInfo(sourceFile); + if (!fileInfo.isFile()) + return; + + const auto doc = g_StudioApp.GetCore()->GetDoc(); + + const QString extension = fileInfo.suffix(); + const QString fileStem = fileInfo.baseName(); + const QString outputFileName = QStringLiteral("%1.%2").arg(fileStem).arg(CDialogs::GetImportFileExtension()); + + if (extension.compare(QLatin1String(CDialogs::GetDAEFileExtension()), Qt::CaseInsensitive) == 0) { + SColladaTranslator translator(sourceFile); + const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem); + const QString fullOutputFile = outputDir.filePath(outputFileName); + const SImportResult importResult = + CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile)); + bool forceError = QFileInfo(fullOutputFile).isFile() == false; + IDocumentEditor::DisplayImportErrors( + sourceFile, importResult.m_Error, doc->GetImportFailedHandler(), + translator.m_TranslationLog, forceError); +#ifdef QT_3DSTUDIO_FBX + } else if (extension.compare(QLatin1String(CDialogs::GetFbxFileExtension()), Qt::CaseInsensitive) == 0) { + SFbxTranslator translator(sourceFile); + const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem); + const QString fullOutputFile = outputDir.filePath(outputFileName); + const SImportResult importResult = + CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile)); + bool forceError = QFileInfo(fullOutputFile).isFile() == false; + IDocumentEditor::DisplayImportErrors( + sourceFile, importResult.m_Error, doc->GetImportFailedHandler(), + translator.m_TranslationLog, forceError); +#endif + } else if (extension.compare(QLatin1String("svg"), Qt::CaseInsensitive) == 0) { + IDocumentReader &reader(doc->GetDocumentReader()); + SPathImportTranslator translator(sourceFile, *reader.GetLuaContext(), reader.GetFoundation()); + const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem); + const QString fullOutputFile = outputDir.filePath(outputFileName); + const SImportResult importResult = + CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile)); + bool forceError = QFileInfo(fullOutputFile).isFile() == false; + IDocumentEditor::DisplayImportErrors( + sourceFile, importResult.m_Error, + doc->GetImportFailedHandler(), + translator.m_TranslationLog, forceError); + } else { + // Copy the file to target directory + // FindAndCopyDestFile will make sure the file name is unique and make sure it is + // not read only. + bool copyResult = SFileTools::FindAndCopyDestFile(targetDir, sourceFile); + ASSERT(copyResult); + + // For effect and custom material files, automatically copy related resources + if (CDialogs::IsEffectFileExtension(extension.toLatin1().data()) + || CDialogs::IsMaterialFileExtension(extension.toLatin1().data())) { + std::vector<Q3DStudio::CString> effectFileSourcePaths; + doc->GetDocumentReader().ParseSourcePathsOutOfEffectFile( + Q3DStudio::CFilePath::GetAbsolutePath(CFilePath::fromQString(sourceFile)), + effectFileSourcePaths); + + const QDir fileDir = QFileInfo(sourceFile).dir(); + const QDir documentDir(doc->GetDocumentDirectory().toQString()); + + for (const auto &effectFile : effectFileSourcePaths) { + const QString sourcePath = fileDir.filePath(effectFile.toQString()); + const QString resultPath = documentDir.filePath(effectFile.toQString()); + + const QFileInfo resultFileInfo(resultPath); + if (!resultFileInfo.exists()) { + resultFileInfo.dir().mkpath("."); + QFile::copy(sourcePath, resultPath); + } + } + } + } +} + +void ProjectFileSystemModel::collapse(int row) +{ + Q_ASSERT(row >= 0 && row < m_items.size()); + + auto &item = m_items[row]; + Q_ASSERT(item.expanded == true); + + const int childCount = item.childCount; + + if (childCount > 0) { + beginRemoveRows({}, row + 1, row + childCount); + + m_items.erase(std::begin(m_items) + row + 1, std::begin(m_items) + row + 1 + childCount); + + for (auto parent = &item; parent != nullptr; parent = parent->parent) + parent->childCount -= childCount; + + endRemoveRows(); + } + + item.expanded = false; + Q_EMIT dataChanged(index(row), index(row)); +} + +int ProjectFileSystemModel::modelIndexRow(const QModelIndex &modelIndex) const +{ + auto it = std::find_if( + std::begin(m_items), + std::end(m_items), + [&modelIndex](const TreeItem &item) + { + return item.index == modelIndex; + }); + + return it != std::end(m_items) ? std::distance(std::begin(m_items), it) : -1; +} + +bool ProjectFileSystemModel::isExpanded(const QModelIndex &modelIndex) const +{ + if (modelIndex == m_rootIndex) + return true; + const int row = modelIndexRow(modelIndex); + return row != -1 && m_items.at(row).expanded; +} + +EStudioObjectType ProjectFileSystemModel::getIconType(const QString &path) const +{ + Q3DStudio::CFilePath filePath(Q3DStudio::CString::fromQString(path)); + return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(filePath).m_IconType; +} + +QString ProjectFileSystemModel::getIconName(const QString &path) const +{ + QString iconName; + + QFileInfo fileInfo(path); + if (fileInfo.isFile()) { + EStudioObjectType type = getIconType(path); + if (type != OBJTYPE_UNKNOWN) + iconName = CStudioObjectTypes::GetNormalIconName(type); + else + iconName = QStringLiteral("Objects-Layer-Normal.png"); + } else { + iconName = QStringLiteral("Objects-Folder-Normal.png"); + } + + return iconName; +} + +bool ProjectFileSystemModel::hasVisibleChildren(const QModelIndex &modelIndex) const +{ + const QDir dir(modelIndex.data(QFileSystemModel::FilePathRole).toString()); + if (!dir.exists() || dir.isEmpty()) + return false; + + const auto fileInfoList = dir.entryInfoList(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot); + for (const auto &fileInfo : fileInfoList) { + if (fileInfo.isDir() || getIconType(fileInfo.filePath()) != OBJTYPE_UNKNOWN) + return true; + } + + return false; +} + +bool ProjectFileSystemModel::isVisible(const QModelIndex &modelIndex) const +{ + bool result = false; + + if (modelIndex == m_rootIndex) { + result = true; + } else { + QString path = modelIndex.data(QFileSystemModel::FilePathRole).toString(); + QFileInfo fileInfo(path); + if (fileInfo.isFile()) { + result = getIconType(path) != OBJTYPE_UNKNOWN; + } else { + result = true; + } + } + + return result; +} + +void ProjectFileSystemModel::modelRowsInserted(const QModelIndex &parent, int start, int end) +{ + if (!m_rootIndex.isValid()) + return; + + if (isExpanded(parent)) { + showModelChildItems(parent, start, end); + } else { + if (hasVisibleChildren(parent)) { + // show expand arrow + const int row = modelIndexRow(parent); + Q_EMIT dataChanged(index(row), index(row)); + } + } +} + +void ProjectFileSystemModel::modelRowsRemoved(const QModelIndex &parent, int start, int end) +{ + if (!m_rootIndex.isValid()) + return; + + if (isExpanded(parent)) { + for (int i = start; i <= end; ++i) { + const int row = modelIndexRow(m_model->index(i, 0, parent)); + + if (row != -1) { + const auto &item = m_items.at(row); + + beginRemoveRows({}, row, row + item.childCount); + + for (auto parent = item.parent; parent != nullptr; parent = parent->parent) + parent->childCount -= 1 + item.childCount; + + m_items.erase(std::begin(m_items) + row, std::begin(m_items) + row + item.childCount + 1); + + endRemoveRows(); + } + } + } + + if (!hasVisibleChildren(parent)) { + // hide expand arrow + const int row = modelIndexRow(parent); + m_items[row].expanded = false; + Q_EMIT dataChanged(index(row), index(row)); + } +} + +void ProjectFileSystemModel::modelLayoutChanged() +{ + if (!m_rootIndex.isValid()) + return; + + QSet<QPersistentModelIndex> expandedItems; + for (const auto &item : m_items) { + if (item.expanded) + expandedItems.insert(item.index); + } + + const std::function<int(const QModelIndex &, TreeItem *)> insertChildren = [this, &expandedItems, &insertChildren](const QModelIndex &parentIndex, TreeItem *parent) + { + Q_ASSERT(isVisible(parentIndex)); + + const int rowCount = m_model->rowCount(parentIndex); + const int depth = parent->depth + 1; + + int childCount = 0; + + for (int i = 0; i < rowCount; ++i) { + const auto &childIndex = m_model->index(i, 0, parentIndex); + if (isVisible(childIndex)) { + const bool expanded = expandedItems.contains(childIndex); + m_items.append({ childIndex, depth, expanded, parent, 0 }); + auto &item = m_items.last(); + if (expanded) { + item.childCount = insertChildren(childIndex, &item); + childCount += item.childCount; + } + ++childCount; + } + } + + return childCount; + }; + + const int itemCount = m_items.count(); + + m_items.erase(std::begin(m_items) + 1, std::end(m_items)); + m_items.reserve(itemCount); + insertChildren(m_rootIndex, &m_items.first()); + + Q_ASSERT(m_items.count() == itemCount); + + Q_EMIT dataChanged(index(0), index(itemCount - 1)); +} diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h new file mode 100644 index 00000000..c9ef1b27 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 TREEVIEWADAPTOR_H +#define TREEVIEWADAPTOR_H + +#include "StudioObjectTypes.h" + +#include <QFileSystemModel> +#include <QAbstractListModel> +#include <QList> +#include <QUrl> + +class QFileSystemModel; + +class ProjectFileSystemModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit ProjectFileSystemModel(QObject *parent = nullptr); + + enum { + IsExpandableRole = QFileSystemModel::FilePermissions + 1, + IsDraggableRole, + IsReferencedRole, + DepthRole, + ExpandedRole, + }; + + void setRootPath(const QString &path); + + QHash<int, QByteArray> roleNames() const override; + int rowCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role) const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + + QString filePath(int row) const; + + void updateReferences(bool emitDataChanged); + + Q_INVOKABLE void expand(int row); + Q_INVOKABLE void collapse(int row); + + Q_INVOKABLE void dropUrls(const QList<QUrl> &urls, int row); + Q_INVOKABLE bool hasValidUrlsForDropping(const QList<QUrl> &urls) const; + +Q_SIGNALS: + void modelChanged(QAbstractItemModel *model); + +private: + void setRootIndex(const QModelIndex &rootIndex); + void clearModelData(); + void showModelTopLevelItems(); + void showModelChildItems(const QModelIndex &parentItem, int start, int end); + int modelIndexRow(const QModelIndex &modelIndex) const; + bool isExpanded(const QModelIndex &modelIndex) const; + QString getIconName(const QString &path) const; + EStudioObjectType getIconType(const QString &path) const; + bool isVisible(const QModelIndex& modelIndex) const; + bool hasVisibleChildren(const QModelIndex &modelIndex) const; + void dropUrl(const QDir &targetDir, const QUrl &url) const; + + void modelRowsInserted(const QModelIndex &parent, int start, int end); + void modelRowsRemoved(const QModelIndex &parent, int start, int end); + void modelRowsMoved(const QModelIndex &parent, int start, int end); + void modelLayoutChanged(); + + struct TreeItem { + QPersistentModelIndex index; + int depth; + bool expanded; + TreeItem *parent; + int childCount; + }; + + QFileSystemModel *m_model = nullptr; + QPersistentModelIndex m_rootIndex; + QList<TreeItem> m_items; + QStringList m_references; +}; + +#endif // TREEVIEWADAPTOR_H diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.cpp b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp new file mode 100644 index 00000000..0bdc69a6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** 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 "ProjectView.h" +#include "ProjectFileSystemModel.h" +#include "Core.h" +#include "Dispatch.h" +#include "Doc.h" +#include "Literals.h" +#include "StudioUtils.h" +#include "ImportUtils.h" +#include "StudioApp.h" +#include "StudioClipboard.h" +#include "StudioPreferences.h" +#include "UICImport.h" +#include "Dialogs.h" +#include "IDocumentEditor.h" +#include "ProjectContextMenu.h" + +#include <QtCore/qprocess.h> +#include <QtCore/qtimer.h> +#include <QtGui/qdrag.h> +#include <QtGui/qdesktopservices.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +ProjectView::ProjectView(QWidget *parent) : QQuickWidget(parent) + , m_ProjectModel(new ProjectFileSystemModel(this)) +{ + const QString theApplicationPath = + CUICFile::GetApplicationDirectory().GetAbsolutePath().toQString(); + + m_BehaviorDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Behavior Library"))); + m_EffectDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Effect Library"))); + m_FontDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Font Library"))); + m_ImageDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Maps Library"))); + m_MaterialDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Material Library"))); + m_ModelDir = CUICFile( + Q3DStudio::CString::fromQString(theApplicationPath + + QLatin1String("/Content/Models Library"))); + + setResizeMode(QQuickWidget::SizeRootObjectToView); + QTimer::singleShot(0, this, &ProjectView::initialize); + + auto dispatch = g_StudioApp.GetCore()->GetDispatch(); + dispatch->AddPresentationChangeListener(this); + dispatch->AddDataModelListener(this); +} + +ProjectView::~ProjectView() +{ +} + +QAbstractItemModel *ProjectView::projectModel() const +{ + return m_ProjectModel; +} + +QSize ProjectView::sizeHint() const +{ + return {500,500}; +} + +void ProjectView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + rootContext()->setContextProperty("_projectView"_L1, this); + + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Project/ProjectView.qml"_L1)); +} + +void ProjectView::effectAction() +{ + m_EffectDir.Execute(); +} + +void ProjectView::fontAction() +{ + m_FontDir.Execute(); +} + +void ProjectView::imageAction() +{ + m_ImageDir.Execute(); +} + +void ProjectView::materialAction() +{ + m_MaterialDir.Execute(); +} + +void ProjectView::modelAction() +{ + m_ModelDir.Execute(); +} + +void ProjectView::behaviorAction() +{ + m_BehaviorDir.Execute(); +} + +void ProjectView::OnNewPresentation() +{ + rebuild(); +} + +void ProjectView::OnBeginDataModelNotifications() +{ +} + +void ProjectView::OnEndDataModelNotifications() +{ + m_ProjectModel->updateReferences(true); +} + +void ProjectView::OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) +{ + Q_UNUSED(inInstance); +} + +void ProjectView::OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount) +{ + Q_UNUSED(inInstance); + Q_UNUSED(inInstanceCount); +} + +void ProjectView::startDrag(int row) +{ + const auto index = m_ProjectModel->index(row); + + QDrag drag(this); + drag.setMimeData(m_ProjectModel->mimeData({index})); + drag.exec(Qt::CopyAction); +} + +void ProjectView::showInExplorer(int row) const +{ + if (row == -1) + return; + const auto path = m_ProjectModel->filePath(row); +#if defined(Q_OS_WIN) + QProcess::startDetached("explorer", {"/select", path}); +#elif defined(Q_OS_MACOS) + QProcess::startDetached("/usr/bin/osascript", {"-e", + QStringLiteral("tell application \"Finder\" to reveal POSIX file \"%1\"").arg(path)}); + QProcess::startDetached("/usr/bin/osascript", {"-e", + QStringLiteral("tell application \"Finder\" to activate")}); +#else + // we cannot select a file here, because no file browser really supports it... + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath())); +#endif +} + +void ProjectView::copyPath(int row) const +{ + if (row == -1) + return; + const auto path = m_ProjectModel->filePath(row); + const auto doc = g_StudioApp.GetCore()->GetDoc(); + const auto relativePath = doc->GetRelativePathToDoc( + Q3DStudio::CFilePath(Q3DStudio::CString::fromQString(path))); + CStudioClipboard::CopyTextToClipboard(relativePath.toQString()); +} + +void ProjectView::copyFullPath(int row) const +{ + if (row == -1) + return; + const auto path = m_ProjectModel->filePath(row); + CStudioClipboard::CopyTextToClipboard(path); +} + +bool ProjectView::isGroup(int row) const +{ + if (row == -1) + return false; + Q3DStudio::CFilePath path(Q3DStudio::CString::fromQString(m_ProjectModel->filePath(row))); + return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(path).m_ObjectType == OBJTYPE_GROUP; +} + +void ProjectView::showContextMenu(int x, int y, int index) +{ + ProjectContextMenu contextMenu(this, index); + contextMenu.exec(mapToGlobal({x, y})); +} + +void ProjectView::refreshImport(int row) const +{ + if (row == -1) + return; + using namespace Q3DStudio; + const auto path = m_ProjectModel->filePath(row); + UICIMP::ImportPtrOrError importPtr = UICIMP::Import::Load(path.toStdWString().c_str()); + if (importPtr.m_Value) { + const auto destDir = QString::fromWCharArray(importPtr.m_Value->GetDestDir()); + const auto srcFile = QString::fromWCharArray(importPtr.m_Value->GetSrcFile()); + const QString fullSrcPath(QDir(destDir).filePath(srcFile)); + const QFileInfo newFile(g_StudioApp.GetDialogs()->ConfirmRefreshModelFile(fullSrcPath)); + if (newFile.exists() && newFile.isFile()){ + const auto doc = g_StudioApp.GetCore()->GetDoc(); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, tr("Refresh Import...")) + ->RefreshImport(fullSrcPath, CString::fromQString(newFile.filePath())); + } + } +} + +void ProjectView::rebuild() +{ + const auto theDoc = g_StudioApp.GetCore()->GetDoc(); + const Q3DStudio::CFilePath thePath(theDoc->GetDocumentPath().GetAbsolutePath()); + const Q3DStudio::CFilePath theRootDirPath = thePath.GetDirectory(); + + m_ProjectModel->setRootPath(theRootDirPath.toQString()); +} diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.h b/src/Authoring/Studio/Palettes/Project/ProjectView.h new file mode 100644 index 00000000..f46aa976 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectView.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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 PROJECTVIEW_H +#define PROJECTVIEW_H + +#include "DispatchListeners.h" +#include "UICFile.h" + +#include <QQuickWidget> +#include <QModelIndex> + +class ProjectFileSystemModel; + +class ProjectView : public QQuickWidget, + public CPresentationChangeListener, + public IDataModelListener + +{ + Q_OBJECT + + Q_PROPERTY(QAbstractItemModel *projectModel READ projectModel NOTIFY projectChanged FINAL) + +public: + explicit ProjectView(QWidget *parent = nullptr); + ~ProjectView(); + + QSize sizeHint() const override; + + QAbstractItemModel *projectModel() const; + + Q_INVOKABLE void effectAction(); + Q_INVOKABLE void fontAction(); + Q_INVOKABLE void imageAction(); + Q_INVOKABLE void materialAction(); + Q_INVOKABLE void modelAction(); + Q_INVOKABLE void behaviorAction(); + + Q_INVOKABLE void startDrag(int row); + + Q_INVOKABLE void showInExplorer(int row) const; + Q_INVOKABLE void copyPath(int row) const; + Q_INVOKABLE void copyFullPath(int row) const; + Q_INVOKABLE void refreshImport(int row) const; + + Q_INVOKABLE bool isGroup(int row) const; + Q_INVOKABLE void showContextMenu(int x, int y, int index); + + // CPresentationChangeListener + void OnNewPresentation() override; + // IDataModelListener + void OnBeginDataModelNotifications() override; + void OnEndDataModelNotifications() override; + // These are used during drag operations or during operations which + // require immediate user feedback. So they are unimplemented, effectively, + // we ignore them. + void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override; + void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, + long inInstanceCount) override; + +Q_SIGNALS: + void projectChanged(); + +private: + void initialize(); + void rebuild(); + + ProjectFileSystemModel *m_ProjectModel = nullptr; + QColor m_BaseColor = QColor::fromRgb(75, 75, 75); + CUICFile m_BehaviorDir{""}; + CUICFile m_EffectDir{""}; + CUICFile m_FontDir{""}; + CUICFile m_ImageDir{""}; + CUICFile m_MaterialDir{""}; + CUICFile m_ModelDir{""}; +}; + +#endif // PROJECTVIEW_H diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.qml b/src/Authoring/Studio/Palettes/Project/ProjectView.qml new file mode 100644 index 00000000..88ff608f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Project/ProjectView.qml @@ -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$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 +import "../controls" + +Rectangle { + id: root + + color: _backgroundColor + + ColumnLayout { + anchors.fill: parent + spacing: 4 + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + _projectView.showContextMenu(mouse.x, mouse.y, projectTree.currentIndex); + } + } + + ListView { + id: projectTree + + anchors.fill: parent + + ScrollBar.vertical: ScrollBar {} + + model: _projectView.projectModel + + delegate: Rectangle { + id: delegateItem + + width: parent.width + height: 20 + color: index == projectTree.currentIndex ? _selectionColor : "transparent" + + Row { + x: _depth*28 + anchors.verticalCenter: delegateItem.verticalCenter + + Image { + source: _resDir + (_expanded ? "arrow_down.png" : "arrow.png") + opacity: _isExpandable ? 1 : 0 + + MouseArea { + visible: _isExpandable + anchors.fill: parent + onClicked: { + if (_expanded) + projectTree.model.collapse(index) + else + projectTree.model.expand(index) + delegateMouseArea.clickPending = false + } + } + } + + Image { + source: fileIcon + } + + StyledLabel { + text: fileName + color: _isReferenced ? _textColor : _disabledColor + leftPadding: 2 + + Item { + id: dragItem + + visible: _isDraggable + anchors.fill: parent + + Drag.active: dragArea.drag.active + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + + MouseArea { + id: dragArea + anchors.fill: parent + drag.target: dragItem + } + + Drag.onDragStarted: _projectView.startDrag(index) + } + } + } + + DropArea { + id: dropArea + + anchors.fill: parent + + onEntered: { + if (drag.hasUrls && projectTree.model.hasValidUrlsForDropping(drag.urls)) { + drag.accept(Qt.CopyAction) + } else { + drag.accepted = false; + } + } + + onDropped: { + if (drop.hasUrls) { + projectTree.model.dropUrls(drop.urls, index) + } + } + } + + MouseArea { + id: delegateMouseArea + property bool clickPending: false + anchors.fill: parent + acceptedButtons: Qt.RightButton|Qt.LeftButton + propagateComposedEvents: true + onPressed: { + projectTree.currentIndex = model.index; + + // Presses must be ignored by this handler in order for dragging to work + mouse.accepted = false; + + // Since ignoring presses means we don't get doubleClicked events, + // detect doubleclick using custom timer. + if (clickPending) { + if (_isExpandable) { + if (_expanded) + projectTree.model.collapse(index); + else + projectTree.model.expand(index); + } + clickPending = false; + } else { + clickPending = true; + doubleClickTimer.restart(); + } + } + Timer { + id: doubleClickTimer + repeat: false + triggeredOnStart: false + interval: 500 + onTriggered: parent.clickPending = false; + } + } + } + } + } + + StyledMenuSeparator {} + + RowLayout { + width: parent.width + Layout.margins: 4 + Layout.rightMargin: 12 + + Item { + Layout.fillWidth: true + } + + StyledToolButton { + enabledImage: "Objects-Effect-Normal.png"; + onClicked: _projectView.effectAction() + toolTipText: qsTr("Open Effect Library directory") + } + + StyledToolButton { + enabledImage: "Objects-Text-Normal.png"; + onClicked: _projectView.fontAction() + toolTipText: qsTr("Open Font Library directory") + } + + StyledToolButton { + enabledImage: "Objects-Image-Normal.png"; + onClicked: _projectView.imageAction() + toolTipText: qsTr("Open Maps Library directory") + } + + StyledToolButton { + enabledImage: "Objects-Material-Normal.png"; + onClicked: _projectView.materialAction() + toolTipText: qsTr("Open Material Library directory") + } + + StyledToolButton { + enabledImage: "Objects-Model-Normal.png"; + onClicked: _projectView.modelAction() + toolTipText: qsTr("Open Models Library directory") + } + + StyledToolButton { + enabledImage: "Objects-Behavior-Normal.png"; + onClicked: _projectView.behaviorAction() + toolTipText: qsTr("Open Behavior Library directory") + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp new file mode 100644 index 00000000..9af46cb1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 "SlideContextMenu.h" +#include "SlideView.h" + +SlideContextMenu::SlideContextMenu(SlideView *parent, int row, int rowCount, bool master) + : QMenu(parent) + , m_view(parent) + , m_row(row) + , m_rowCount(rowCount) +{ + QAction *action = new QAction(tr("New Slide")); + action->setEnabled(!master); + connect(action, &QAction::triggered, this, &SlideContextMenu::handleAddNewSlide); + addAction(action); + + action = new QAction(tr("Delete Slide")); + action->setEnabled(!master && m_row != -1); + connect(action, &QAction::triggered, this, &SlideContextMenu::handleRemoveSlide); + addAction(action); + + action = new QAction(tr("Duplicate Slide")); + action->setEnabled(!master && m_row != -1); + connect(action, &QAction::triggered, this, &SlideContextMenu::handleDuplicateSlide); + addAction(action); +} + +SlideContextMenu::~SlideContextMenu() +{ +} + +void SlideContextMenu::handleAddNewSlide() +{ + m_view->addNewSlide(m_row == -1 ? m_rowCount : m_row + 1); +} + +void SlideContextMenu::handleRemoveSlide() +{ + m_view->removeSlide(m_row); +} + +void SlideContextMenu::handleDuplicateSlide() +{ + m_view->duplicateSlide(m_row); +} diff --git a/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h new file mode 100644 index 00000000..bb4bb864 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 SLIDE_CONTEXT_MENU_H +#define SLIDE_CONTEXT_MENU_H + +#include <QtWidgets/qmenu.h> + +class SlideView; + +class SlideContextMenu : public QMenu +{ + Q_OBJECT +public: + explicit SlideContextMenu(SlideView *parent, int row, int rowCount, bool master); + virtual ~SlideContextMenu(); + +private Q_SLOTS: + void handleAddNewSlide(); + void handleRemoveSlide(); + void handleDuplicateSlide(); + +private: + SlideView *m_view; + int m_row; + int m_rowCount; +}; +#endif // SLIDE_CONTEXT_MENU_H diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp new file mode 100644 index 00000000..d2ef842c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** 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 "SlideModel.h" + +#include "CmdActivateSlide.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" + +#include "IDocumentEditor.h" + +#include "ClientDataModelBridge.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" + +SlideModel::SlideModel(int slideCount, QObject *parent) : QAbstractListModel(parent) + , m_slides(slideCount) +{ + +} + +QVariant SlideModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return {}; + + const auto row = index.row(); + + switch (role) { + case NameRole: + return slideName(m_slides[row]); + case SelectedRole: + return row == m_selectedRow; + } + + return {}; +} + +bool SlideModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return false; + + auto &slideHandle = m_slides[index.row()]; + + switch (role) { + case NameRole: { + setSlideName(slideHandle, value.toString()); + Q_EMIT dataChanged(index, index, {role}); + break; + } + case HandleRole: { + slideHandle = value.value<UICDM::CUICDMSlideHandle>(); + Q_EMIT dataChanged(index, index, {HandleRole, NameRole}); + break; + } + case SelectedRole: { + m_selectedRow = value.toBool() ? index.row() : -1; + + if (m_selectedRow != -1) { + CCmdActivateSlide *theCmd = new CCmdActivateSlide(GetDoc(), m_slides[m_selectedRow]); + g_StudioApp.GetCore()->ExecuteCommand(theCmd); + } + + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {role}); + return true; + } + default: + return false; + } + + return true; +} + +int SlideModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_slides.count(); +} + +QHash<int, QByteArray> SlideModel::roleNames() const +{ + auto names = QAbstractListModel::roleNames(); + names.insert(NameRole, "name"); + names.insert(SelectedRole, "selected"); + + return names; +} + +bool SlideModel::insertRows(int row, int count, const QModelIndex &parent) +{ + if (row > m_slides.count()) + return false; + + beginInsertRows(parent, row, row + count - 1); + for (int i = 0; i < count; i++) + m_slides.insert(row, {}); + endInsertRows(); + + setData(index(row + count - 1), true, SelectedRole); + return true; +} + +bool SlideModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row + count > m_slides.count()) + return false; + + bool selectionRemoved = false; + beginRemoveRows(parent, row, row + count - 1); + for (int i = 0; i < count; i++) { + if (m_selectedRow == row) + selectionRemoved = true; + m_slides.removeAt(row); + } + endRemoveRows(); + + auto newSelectedRow = -1; + if (selectionRemoved) { + if (row > 0) + newSelectedRow = row - 1; + else + newSelectedRow = row + count - 1; + } else if (m_selectedRow >= m_slides.count()) { + newSelectedRow = m_slides.count() - 1; + } + if (newSelectedRow != -1) + setData(index(newSelectedRow), true, SelectedRole); + + return true; +} + +void SlideModel::duplicateRow(int row) +{ + const auto handle = m_slides[row]; + + beginInsertRows({}, row, row); + m_slides.insert(row + 1, Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), + QObject::tr("Duplicate Slide")) + ->DuplicateSlide(handle)); + endInsertRows(); + setData(index(row + 1), true, SelectedRole); + + Q_EMIT dataChanged(index(row, 0), index(row + 1, 0), {}); +} + +void SlideModel::move(int fromRow, int toRow) +{ + if (fromRow == toRow) + return; + + auto handle = m_slides[fromRow]; + // toRow + 1 as DocumentEditor uses 1 based indexes for slides + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Rearrange Slide")) + ->RearrangeSlide(handle, toRow + 1); + + if (fromRow > toRow) + beginMoveRows({}, fromRow, fromRow, {}, toRow); + else + beginMoveRows({}, fromRow, fromRow, {}, toRow + 1); + m_slides.move(fromRow, toRow); + endMoveRows(); +} + +void SlideModel::clear() +{ + beginResetModel(); + m_slides.clear(); + endResetModel(); +} + +void SlideModel::addNewSlide(int row) +{ + const auto handle = (row < m_slides.size()) ? m_slides[row] : m_slides.last(); + + const auto instanceHandle = GetBridge()->GetOwningComponentInstance(handle); + UICDM::CUICDMSlideHandle theMasterSlide = GetBridge()->GetComponentSlide(instanceHandle, 0); + + beginInsertRows({}, row, row); + m_slides.insert(row, Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), + QObject::tr("Create Slide")) + ->AddSlide(theMasterSlide, row + 1)); + endInsertRows(); + + setData(index(row), true, SelectedRole); +} + +void SlideModel::removeSlide(int row) +{ + const auto handle = m_slides[row]; + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Delete Slide"))->DeleteSlide(handle); + removeRows(row, 1); +} + +bool SlideModel::hasSlideWithName(const QString &name) const +{ + for (const auto &slide: m_slides) { + if (slideName(slide) == name) + return true; + } + return false; +} + +QString SlideModel::slideName(const UICDM::CUICDMSlideHandle &handle) const +{ + auto doc = GetDoc(); + if (!doc->IsValid()) + return {}; + const auto instanceHandle = doc->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(handle); + return GetBridge()->GetName(instanceHandle).toQString(); +} + +void SlideModel::setSlideName(const UICDM::CUICDMSlideHandle &handle, const QString &name) +{ + const auto oldName = slideName(handle); + if (oldName != name && !name.trimmed().isEmpty()) { + using namespace UICDM; + CDoc *theDoc = GetDoc(); + CClientDataModelBridge *theBridge = GetBridge(); + if (!theBridge) + return; + const auto instanceHandle = GetDoc()->GetStudioSystem()-> + GetSlideSystem()->GetSlideInstance(handle); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Set Slide Name")) + ->SetSlideName(instanceHandle, theBridge->GetNameProperty(), + Q3DStudio::CString::fromQString(oldName), + Q3DStudio::CString::fromQString(name)); + } +} + +CDoc *SlideModel::GetDoc() const +{ + return g_StudioApp.GetCore()->GetDoc(); +} + +CClientDataModelBridge *SlideModel::GetBridge() const +{ + auto doc = GetDoc(); + if (!doc->IsValid()) + return nullptr; + return doc->GetStudioSystem()->GetClientDataModelBridge(); +} + + diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.h b/src/Authoring/Studio/Palettes/Slide/SlideModel.h new file mode 100644 index 00000000..659fc548 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 SLIDEMODEL_H +#define SLIDEMODEL_H + +#include <QAbstractListModel> + +#include "UICDMHandles.h" + +class CClientDataModelBridge; +class CDoc; + +class SlideModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum Roles { + NameRole = Qt::DisplayRole, + HandleRole = Qt::UserRole + 1, + SelectedRole + }; + + SlideModel(int slideCount, QObject *parent = nullptr); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::DisplayRole) override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QHash<int, QByteArray> roleNames() const override; + + bool insertRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + void duplicateRow(int row); + void move(int fromRow, int toRow); + + void clear(); + void addNewSlide(int row); + void removeSlide(int row); + +private: + bool hasSlideWithName(const QString &name) const; + QString slideName(const UICDM::CUICDMSlideHandle &handle) const; + void setSlideName(const UICDM::CUICDMSlideHandle &handle, const QString &name); + inline CDoc *GetDoc() const; + inline CClientDataModelBridge *GetBridge() const; + + QVector<UICDM::CUICDMSlideHandle> m_slides; + int m_selectedRow = -1; +}; + + +#endif // SLIDEMODEL_H diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp new file mode 100644 index 00000000..08b38a2c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** 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 "SlideView.h" +#include "CColor.h" +#include "Core.h" +#include "Dispatch.h" +#include "Doc.h" +#include "Literals.h" +#include "StudioPreferences.h" +#include "SlideModel.h" +#include "StudioApp.h" +#include "StudioUtils.h" +#include "SlideContextMenu.h" + +#include "ClientDataModelBridge.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +SlideView::SlideView(QWidget *parent) : QQuickWidget(parent) + , m_MasterSlideModel(new SlideModel(1, this)) + , m_SlidesModel(new SlideModel(0, this)) + , m_ActiveRoot(0) +{ + g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this); + setResizeMode(QQuickWidget::SizeRootObjectToView); + m_CurrentModel = m_SlidesModel; + QTimer::singleShot(0, this, &SlideView::initialize); +} + +SlideView::~SlideView() +{ + clearSlideList(); + g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this); +} + +bool SlideView::showMasterSlide() const +{ + return m_CurrentModel == m_MasterSlideModel; +} + +void SlideView::setShowMasterSlide(bool show) +{ + const bool currentIsMaster = m_CurrentModel == m_MasterSlideModel; + if (show == currentIsMaster) + return; + + if (show) + m_CurrentModel = m_MasterSlideModel; + else + m_CurrentModel = m_SlidesModel; + + // We need to get the first slide in the correct master mode + CDoc *theDoc = GetDoc(); + UICDM::CUICDMInstanceHandle theRoot = theDoc->GetActiveRootInstance(); + CClientDataModelBridge *theBridge = GetBridge(); + UICDM::CUICDMSlideHandle theNewActiveSlide = + theBridge->GetOrCreateGraphRoot(theRoot); // this will return the master slide + UICDM::ISlideSystem *theSlideSystem = theDoc->GetStudioSystem()->GetSlideSystem(); + if (m_CurrentModel != m_MasterSlideModel) { + const auto theFind = m_MasterSlideReturnPointers.find(theNewActiveSlide); + size_t theSlideIndex = 1; + size_t theNumSlides = theSlideSystem->GetSlideCount(theNewActiveSlide); + if (theFind != m_MasterSlideReturnPointers.end() && theFind->second < theNumSlides) + theSlideIndex = theFind->second; + + theNewActiveSlide = theSlideSystem->GetSlideByIndex( + theNewActiveSlide, theSlideIndex); // activate the first slide + } else { + int theIndex = theSlideSystem->GetActiveSlideIndex(theNewActiveSlide); + m_MasterSlideReturnPointers[theNewActiveSlide] = theIndex; + } + + // We have forced a mode change, and so we need to set the current active TC + // to be in the correct mode so our slide palette will show the correct information + if (theNewActiveSlide.Valid()) { + theDoc->NotifyActiveSlideChanged(theNewActiveSlide); + } + + Q_EMIT showMasterSlideChanged(); + Q_EMIT currentModelChanged(); +} + +QSize SlideView::sizeHint() const +{ + return {150, 200}; +} + +void SlideView::deselectAll() +{ + g_StudioApp.GetCore()->GetDoc()->DeselectAllItems(); +} + +void SlideView::addNewSlide(int row) +{ + m_SlidesModel->addNewSlide(row); +} + +void SlideView::removeSlide(int row) +{ + m_SlidesModel->removeSlide(row); +} + +void SlideView::duplicateSlide(int row) +{ + m_SlidesModel->duplicateRow(row); +} + +void SlideView::moveSlide(int from, int to) +{ + m_SlidesModel->move(from, to); +} + +void SlideView::showContextMenu(int x, int y, int row) +{ + SlideContextMenu contextMenu(this, row, m_SlidesModel->rowCount(), + m_CurrentModel == m_MasterSlideModel); + contextMenu.exec(mapToGlobal({x, y})); +} + +void SlideView::OnNewPresentation() +{ + // Register callbacks + UICDM::IStudioFullSystemSignalProvider *theSignalProvider = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider(); + m_MasterSlideReturnPointers.clear(); + + m_Connections.push_back(theSignalProvider->ConnectActiveSlide( + std::bind(&SlideView::OnActiveSlide, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3))); + + // KDAB_TODO We most probably don't need to listen to the below signals, + // as the functionality is done in the model already. Remove after it is confirmed + // it works as desired when the rendering works. + m_Connections.push_back(theSignalProvider->ConnectSlideCreated( + std::bind(&SlideView::OnNewSlide, this, std::placeholders::_1))); + m_Connections.push_back(theSignalProvider->ConnectSlideDeleted( + std::bind(&SlideView::OnDeleteSlide, this, std::placeholders::_1))); + m_Connections.push_back(theSignalProvider->ConnectSlideRearranged( + std::bind(&SlideView::OnSlideRearranged, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3))); +} + +void SlideView::OnClosingPresentation() +{ + m_Connections.clear(); + clearSlideList(); +} + +void SlideView::OnActiveSlide(const UICDM::CUICDMSlideHandle &inMaster, int inIndex, + const UICDM::CUICDMSlideHandle &inSlide) +{ + // When the active slide changes, we need to update our button and mode + if (inMaster.Valid()) { + // if inIndex is 0, it means that we are activating master slide + setShowMasterSlide(inIndex == 0); + setActiveSlide(inSlide); + } +} + +void SlideView::OnNewSlide(const UICDM::CUICDMSlideHandle &inSlide) +{ + +} + +void SlideView::OnDeleteSlide(const UICDM::CUICDMSlideHandle &inSlide) +{ + +} + +void SlideView::OnSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex, int inNewIndex) +{ +} + +void SlideView::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty("_slideView"_L1, this); + rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl()); + + engine()->addImportPath(qmlImportPath()); + setSource(QUrl("qrc:/Studio/Palettes/Slide/SlideView.qml"_L1)); +} + +void SlideView::clearSlideList() +{ + m_ActiveRoot = 0; + m_SlidesModel->clear(); +} + +void SlideView::setActiveSlide(const UICDM::CUICDMSlideHandle &inActiveSlideHandle) +{ + // Make sure we are in the correct master mode based on the inActiveSlideHandle + // If we changed mode, then we need to force a rebuild + bool theRebuildFlag = isMaster(inActiveSlideHandle) && (m_CurrentModel != m_MasterSlideModel); + + // Check to see if the incoming slide is a sibling of the current active slide + // If it is, then we may be able to update without rebuilding everything + if (!theRebuildFlag + && m_ActiveRoot == GetBridge()->GetOwningComponentInstance(inActiveSlideHandle)) { + // If this is a new active slide, but the same root parent + if (m_ActiveSlideHandle != inActiveSlideHandle) { + m_ActiveSlideHandle = inActiveSlideHandle; + } + } else { + // We have a new parent or a new slide that makes us rebuild the entire list + rebuildSlideList(inActiveSlideHandle); + } +} + +void SlideView::rebuildSlideList(const UICDM::CUICDMSlideHandle &inActiveSlideHandle) +{ + // Clear out the existing slides + clearSlideList(); + + // Add new slide controls as required + if (inActiveSlideHandle.Valid()) { + m_ActiveSlideHandle = inActiveSlideHandle; + m_ActiveRoot = GetBridge()->GetOwningComponentInstance(inActiveSlideHandle); + + // Get the Master Slide handle and the slide count + UICDM::ISlideSystem *theSlideSystem = GetSlideSystem(); + UICDM::CUICDMSlideHandle theMasterSlide = + theSlideSystem->GetMasterSlide(inActiveSlideHandle); + + // update handle for master slide + UICDM::CUICDMSlideHandle theMasterSlideHandle = + theSlideSystem->GetSlideByIndex(theMasterSlide, 0); + m_MasterSlideModel->setData(m_MasterSlideModel->index(0, 0), + QVariant::fromValue(theMasterSlideHandle), + SlideModel::HandleRole); + + long theSlideCount = (long)theSlideSystem->GetSlideCount(theMasterSlide); + + // Iterate through, creating the new slide controls + m_SlidesModel->clear(); + m_SlidesModel->insertRows(0, theSlideCount - 1, {}); + int row = 0; + for (long theSlideIndex = 1; theSlideIndex < theSlideCount; ++theSlideIndex) { + UICDM::CUICDMSlideHandle theSlideHandle = + theSlideSystem->GetSlideByIndex(theMasterSlide, theSlideIndex); + auto index = m_SlidesModel->index(row, 0); + m_SlidesModel->setData(index, + QVariant::fromValue(theSlideHandle), + SlideModel::HandleRole); + const auto instanceHandle = + GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(theSlideHandle); + m_SlidesModel->setData(index, + GetBridge()->GetName(instanceHandle).toQString(), + SlideModel::NameRole); + // This slide is the active slide + if (theSlideHandle == m_ActiveSlideHandle) { + m_SlidesModel->setData(index, true, SlideModel::SelectedRole); + } + row++; + } + } +} + +CDoc *SlideView::GetDoc() +{ + return g_StudioApp.GetCore()->GetDoc(); +} + +CClientDataModelBridge *SlideView::GetBridge() +{ + return GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); +} + +UICDM::ISlideSystem *SlideView::GetSlideSystem() +{ + return GetDoc()->GetStudioSystem()->GetSlideSystem(); +} + +long SlideView::GetSlideIndex(const UICDM::CUICDMSlideHandle &inSlideHandle) +{ + return GetSlideSystem()->GetSlideIndex(inSlideHandle); +} + +bool SlideView::isMaster(const UICDM::CUICDMSlideHandle &inSlideHandle) +{ + return (0 == GetSlideIndex(inSlideHandle)); +} + + diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.h b/src/Authoring/Studio/Palettes/Slide/SlideView.h new file mode 100644 index 00000000..a4347ddd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideView.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 SLIDEVIEW_H +#define SLIDEVIEW_H + +#include <QQuickWidget> + +#include "DispatchListeners.h" +#include "SlideModel.h" + +#include "UICDMHandles.h" +#include "UICDMSignals.h" +#include <unordered_map> +class CClientDataModelBridge; +class CDoc; + +namespace UICDM { +class ISlideSystem; +} + +class SlideView : public QQuickWidget, public CPresentationChangeListener +{ + Q_OBJECT + Q_PROPERTY(QAbstractItemModel *currentModel READ currentModel NOTIFY currentModelChanged FINAL) + Q_PROPERTY(bool showMasterSlide READ showMasterSlide WRITE setShowMasterSlide NOTIFY showMasterSlideChanged FINAL) +public: + SlideView(QWidget *parent = nullptr); + ~SlideView(); + + bool showMasterSlide() const; + void setShowMasterSlide(bool show); + QAbstractItemModel *currentModel() { return m_CurrentModel; } + QSize sizeHint() const override; + + Q_INVOKABLE void deselectAll(); + Q_INVOKABLE void addNewSlide(int row); + Q_INVOKABLE void removeSlide(int row); + Q_INVOKABLE void duplicateSlide(int row); + Q_INVOKABLE void moveSlide(int from, int to); + Q_INVOKABLE void showContextMenu(int x, int y, int row); + + // Presentation Change Listener + void OnNewPresentation() override; + void OnClosingPresentation() override; + +Q_SIGNALS: + void currentModelChanged(); + void showMasterSlideChanged(); + + +protected: + // UICDM callbacks + virtual void OnActiveSlide(const UICDM::CUICDMSlideHandle &inMaster, int inIndex, + const UICDM::CUICDMSlideHandle &inSlide); + virtual void OnNewSlide(const UICDM::CUICDMSlideHandle &inSlide); + virtual void OnDeleteSlide(const UICDM::CUICDMSlideHandle &inSlide); + virtual void OnSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex, + int inNewIndex); + +private: + void initialize(); + void clearSlideList(); + void setActiveSlide(const UICDM::CUICDMSlideHandle &inActiveSlideHandle); + inline CDoc *GetDoc(); + inline CClientDataModelBridge *GetBridge(); + inline UICDM::ISlideSystem *GetSlideSystem(); + long GetSlideIndex(const UICDM::CUICDMSlideHandle &inSlideHandle); + bool isMaster(const UICDM::CUICDMSlideHandle &inSlideHandle); + void rebuildSlideList(const UICDM::CUICDMSlideHandle &inActiveSlideHandle); + + SlideModel *m_CurrentModel = nullptr; + SlideModel *m_MasterSlideModel = nullptr; + SlideModel *m_SlidesModel = nullptr; + QColor m_BaseColor = QColor::fromRgb(75, 75, 75); + std::vector<std::shared_ptr<UICDM::ISignalConnection>> + m_Connections; /// connections to the UICDM + typedef std::unordered_map<int, int> TIntIntMap; + // We need to remember which slide we were on when we entered the master slide. + // Then, when the users leave the master slide we can go back to roughly the same + // state. + TIntIntMap m_MasterSlideReturnPointers; + + UICDM::CUICDMInstanceHandle m_ActiveRoot; ///< the object containing the slides to be inspected. + UICDM::CUICDMSlideHandle m_ActiveSlideHandle; ///< the active slide handle +}; + +#endif // SLIDEVIEW_H diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.qml b/src/Authoring/Studio/Palettes/Slide/SlideView.qml new file mode 100644 index 00000000..7bffcad3 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Slide/SlideView.qml @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** 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.1 +import "../controls" + +Rectangle { + + id: root + + readonly property bool masterSlide: _slideView.showMasterSlide + + color: _backgroundColor + + MouseArea { + id: mainMouseArea + + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onClicked: { + if (mouse.button === Qt.RightButton) { + _slideView.showContextMenu(mouse.x, mouse.y, -1); + } else { + root.focus = true; + //Unselect All element when we click outside slider item in listView. + //It worked as it in old version. + _slideView.deselectAll(); + mouse.accepted = false + } + } + } + + Column { + anchors { + top: parent.top + topMargin: 5 + horizontalCenter: parent.horizontalCenter + } + + spacing: 5 + + Column { + id: masterButtonColumn + spacing: -4 + anchors.horizontalCenter: parent.horizontalCenter + Button { + id: masterEditButton + anchors.horizontalCenter: parent.horizontalCenter + + onClicked: _slideView.showMasterSlide = !_slideView.showMasterSlide + + background: Rectangle { + color: "transparent" + } + contentItem: Image { + source: _resDir + "Slide-Master-Active.png" + } + } + StyledLabel { + id: masterEditLabel + text: _slideView.showMasterSlide ? qsTr("Leave Master") : qsTr("Edit Master") + font.pixelSize: _fontSize + color: _masterColor + verticalAlignment: Text.AlignVCenter + anchors.horizontalCenter: parent.horizontalCenter + } + } + + StyledMenuSeparator { + id: separator + leftPadding: 12 + rightPadding: 12 + } + + ListView { + id: slideList + + ScrollBar.vertical: ScrollBar {} + + width: root.width + height: root.height - masterButtonColumn.height + - separator.height - parent.spacing * 2 - 10 + anchors.horizontalCenter: parent.horizontalCenter + boundsBehavior: Flickable.StopAtBounds + clip: true + + model: _slideView.currentModel + spacing: 10 + + + delegate: MouseArea { + id: delegateArea + + property int dragIndex + property bool held : false + + anchors.horizontalCenter: parent.horizontalCenter + height: delegateItem.height + width: parent.width + + acceptedButtons: Qt.RightButton | Qt.LeftButton + drag.target: held ? delegateItem : null + drag.axis: Drag.YAxis + + + onPressed: { + dragIndex = model.index; + if (mouse.x > delegateItem.x && mouse.x < delegateItem.x + delegateItem.width) + held = true; + } + onReleased: held = false + + + onClicked: { + _slideView.deselectAll(); + if (mouse.button === Qt.LeftButton) { + root.focus = true; + model.selected = true; + } + if (mouse.button === Qt.RightButton) { + const coords = mapToItem(root, mouse.x, mouse.y); + _slideView.showContextMenu(coords.x, coords.y, model.index); + } + } + + Item { + id: delegateItem + + anchors.centerIn: parent + height: column.implicitHeight + width: 100 + + Drag.keys: "application/x-slide" + Drag.active: delegateArea.held + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + Drag.source: delegateArea + + Column { + id: column + spacing: 2 + anchors.fill: parent + Image { + id: slideImage + + source: { + if (masterSlide) + return _resDir + "Slide-Master-Active.png" + return model.selected ? _resDir + "Slide-Active.png" + : _resDir + "Slide-Normal.png"; + } + } + + Item { + anchors.horizontalCenter: slideImage.horizontalCenter + + height: childrenRect.height + width: childrenRect.width + Row { + StyledLabel { + visible: !masterSlide + text: model.index + 1 + ": " + } + + TextInput { + id: slideName + + readOnly: masterSlide + selectByMouse: !readOnly + color: _textColor + text: model.name + font.pixelSize: _fontSize + + onFocusChanged: { + if (focus && !readOnly) + selectAll(); + } + + onEditingFinished: { + model.name = text; + slideName.focus = false; + } + + Keys.onEscapePressed: { + slideName.undo(); + slideName.focus = false; + } + } + } + } + } + } + + DropArea { + anchors.fill: parent + keys: "application/x-slide" + onEntered: { + var oldIndex = drag.source.dragIndex + var newIndex = model.index + _slideView.moveSlide(oldIndex, newIndex) + drag.source.dragIndex = newIndex + } + } + + states: State { + when: held + + ParentChange { + target: delegateItem + parent: slideList + } + + PropertyChanges { + target: delegateItem + anchors.centerIn: null + } + } + } + } + } + +} diff --git a/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp new file mode 100644 index 00000000..48fe8993 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "AreaBoundingRect.h" +#include "Renderer.h" +#include "CColor.h" + +//============================================================================= +/** + * Draws the rectangle. + */ +void CAreaBoundingRect::Draw(CRenderer *inRenderer) +{ + CPt theSize = GetSize(); + inRenderer->PushPen(CColor(89, 120, 223)); + + // Removed because alpha doesn't work on Mac + // CColor theOverlayColor( 184, 198, 246 ); + // inRenderer->FillSolidRect( CPt( theSize.x - 1, theSize.y - 1 ) ), theOverlayColor ); + + // Draw the rectangle outline + if (theSize.y > 1 && theSize.x > 1) { + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theSize.y - 1)); + inRenderer->LineTo(CPt(theSize.x - 1, theSize.y - 1)); + inRenderer->LineTo(CPt(theSize.x - 1, 0)); + inRenderer->LineTo(CPt(0, 0)); + } + inRenderer->PopPen(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h new file mode 100644 index 00000000..1ec98c55 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_AREA_BOUNDING_RECT +#define INCLUDED_AREA_BOUNDING_RECT 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "OverlayControl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +class CAreaBoundingRect : public COverlayControl +{ +public: + virtual ~CAreaBoundingRect(){} + void Draw(CRenderer *inRenderer) override; + +protected: +}; +#endif // INCLUDED_AREA_BOUNDING_RECT diff --git a/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp new file mode 100644 index 00000000..c0541fac --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "AssetTimelineKeyframe.h" +#include "StateTimebarlessRow.h" +#include "Renderer.h" +#include "MasterP.h" +#include "StateRow.h" +#include "KeyframeContextMenu.h" +#include "HotKeys.h" +#include "ResourceCache.h" +#include "ITimelineControl.h" +#include "Bindings/ITimelineItemBinding.h" +#include "StudioUtils.h" +#include "TimeEditDlg.h" + +CAssetTimelineKeyframe::CAssetTimelineKeyframe(CStateTimebarlessRow *inParentRow, + double inTimeRatio) + : m_Selected(false) + , m_ParentRow(inParentRow) + , m_IsMouseDown(false) + , m_IsDragging(false) + , m_TimeRatio(inTimeRatio) +{ + CResourceCache *theCache = CResourceCache::GetInstance(); + m_Icon = theCache->GetBitmap("Keyframe-Master-Normal.png"); + m_DisabledIcon = theCache->GetBitmap("Keyframe-Master-Disabled.png"); + m_SelectedIcon = theCache->GetBitmap("Keyframe-Master-Selected.png"); + m_DynamicIcon = theCache->GetBitmap("Keyframe-MasterDynamic-Normal.png"); + m_DynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterDynamic-Selected.png"); + + m_RightIcon = theCache->GetBitmap("Keyframe-MasterRight-Normal.png"); + m_RightDisabledIcon = theCache->GetBitmap("Keyframe-MasterRight-disabled.png"); + m_RightSelectedIcon = theCache->GetBitmap("Keyframe-MasterRight-Selected.png"); + m_RightDynamicIcon = theCache->GetBitmap("Keyframe-MasterRightDynamic-Normal.png"); + m_RightDynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterRightDynamic-Selected.png"); + + m_LeftIcon = theCache->GetBitmap("Keyframe-MasterLeft-Normal.png"); + m_LeftDisabledIcon = theCache->GetBitmap("Keyframe-MasterLeft-disabled.png"); + m_LeftSelectedIcon = theCache->GetBitmap("Keyframe-MasterLeft-Selected.png"); + m_LeftDynamicIcon = theCache->GetBitmap("Keyframe-MasterLeftDynamic-Normal.png"); + m_LeftDynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterLeftDynamic-Selected.png"); + + m_RectOverHandled = false; + m_PreviousSelectState = false; +} + +CAssetTimelineKeyframe::~CAssetTimelineKeyframe() +{ +} + +//============================================================================= +/** + * SetRectOverHandled: Sets if mouse rectangle has been handled + * param@ inState indicates if the rectangle over has been handled. + * return@ NONE + */ + +void CAssetTimelineKeyframe::SetRectOverHandled(bool inState) +{ + m_RectOverHandled = inState; +} + +//============================================================================= +/** + * GetRectOverHandled: GetRectOverHandled + * param@ NONE + * return@ m_RectOverHandled, which indicates if the rectangle over has been handled + */ +bool CAssetTimelineKeyframe::GetRectOverHandled() +{ + return m_RectOverHandled; +} + +//============================================================================= +/** + * SetPreviousSelectState: Sets if the current keyframe was previously selected + * param@ inState is used to set m_PreviousSelectState. + * return@ NONE + */ +void CAssetTimelineKeyframe::SetPreviousSelectState(bool inState) +{ + m_PreviousSelectState = inState; +} + +//============================================================================= +/** + * GetPreviousSelectState: Returns the keyframe's previous select state + * param@ NONE + * return@ m_PreviousSelectState that stores the select state for the keyframe + */ +bool CAssetTimelineKeyframe::GetPreviousSelectState() +{ + return m_PreviousSelectState; +} + +//============================================================================= +/** +* Updates the ToolTip and moves it to the correct place on screen. +* @param inPoint the point that the tooltip is supposed to be placed. +*/ +void CAssetTimelineKeyframe::RefreshToolTip(CPt inPoint) +{ + Q3DStudio::CString theCommentText; + CStateRow *theStateRow = m_ParentRow->GetStateRow(); + CRct theTimelineBounds(theStateRow->GetTopControl()->GetBounds()); + + // format label + theCommentText = " " + ::FormatTimeString(GetTime()); + + inPoint.y = GetPosition().y - GetSize().y; + inPoint.x = GetSize().x / 2; + ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds); +} + +//============================================================================= +/** + * Gets the correct image and draws + */ +void CAssetTimelineKeyframe::Draw(CRenderer *inRenderer) +{ + inRenderer->DrawBitmap(CPt(0, 0), GetImage()); +} + +//============================================================================= +/** + * Gets the name of the current bitmap depending on the state of the button, + * postion of the mouse, etc. Returns name of the image for the up state by + * default. + * @return name of the image representing current state of the button + */ +QPixmap CAssetTimelineKeyframe::GetImage() const +{ + QPixmap theImage = m_Icon; + long theStartTime = m_ParentRow->GetStateRow()->GetStartTime(); + long theEndTime = m_ParentRow->GetStateRow()->GetEndTime(); + + if (theStartTime == m_Time) { + theImage = m_LeftIcon; + if (!IsEnabled()) + theImage = m_LeftDisabledIcon; + else if (m_IsDynamic) { + if (m_Selected) + return m_LeftDynamicSelectedIcon; + else + return m_LeftDynamicIcon; + } else if (m_Selected) + theImage = m_LeftSelectedIcon; + } else if (theEndTime == m_Time) { + theImage = m_RightIcon; + if (!IsEnabled()) + theImage = m_RightDisabledIcon; + else if (m_IsDynamic) { + if (m_Selected) + return m_RightDynamicSelectedIcon; + else + return m_RightDynamicIcon; + } else if (m_Selected) + theImage = m_RightSelectedIcon; + } else { + if (!IsEnabled()) + theImage = m_DisabledIcon; + else if (m_IsDynamic) { + if (m_Selected) + return m_DynamicSelectedIcon; + else + return m_DynamicIcon; + } else if (m_Selected) + theImage = m_SelectedIcon; + } + return theImage; +} + +//============================================================================= +/** + * @return true if the mouse is over the keyframe + * @param inPoint the point where the mouse is + */ +bool CAssetTimelineKeyframe::HitTest(const CPt &inPoint) const +{ + bool theRetVal = false; + // If not over the control then don't bother with specific checks + if (CControl::HitTest(inPoint)) { + // If the key is at the beginning or end of the timebar then calculate the test differently + long theStartTime = m_ParentRow->GetStateRow()->GetStartTime(); + long theEndTime = m_ParentRow->GetStateRow()->GetEndTime(); + CPt thePoint = inPoint - GetPosition(); + if (theStartTime == m_Time) + theRetVal = (thePoint.x > 7); + else if (theEndTime == m_Time) + theRetVal = (thePoint.x < 9); + else { + if (m_Selected) + theRetVal = (thePoint.x > 1 && thePoint.x < 15); + else + theRetVal = (thePoint.x > 3 && thePoint.x < 13); + } + } + return theRetVal; +} + +//============================================================================= +/** + * Handler for left mouse down events. + * @param inPoint the point where the mouse is + * @param inFlags indicates modifier keys that were down at time of the event + */ +bool CAssetTimelineKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Store the mouse down location in screen coordinates so that we can check the dragging buffer + // in OnMouseMove + m_MouseDownLoc = inPoint; + + if (!CControl::OnMouseDown(inPoint, inFlags)) { + bool theClearPreviouslySelectedKeys = false; + bool theSelectedFlag = false; + // If the control key is down then we change state, otherwise + if (!((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL)) { + theClearPreviouslySelectedKeys = !m_Selected; // clear if not multi-selecting + theSelectedFlag = true; + } else { + theSelectedFlag = !m_Selected; + } + m_ParentRow->OnKeySelected(m_Time, theSelectedFlag, theClearPreviouslySelectedKeys); + m_Selected = theSelectedFlag; // set this after OnKeySelected, because the function may + // clear out all previously selected keys including this + // TODO : sk - 1-1 mapping of seemingly useless calls in + // CPropertyTimelineKeyframe::OnMouseDown, see my comments there. + // m_StudioDoc->UpdateClientScene( true ); + // m_ParentRow->GetStateRow( )->GetState( )->FireAnimatedPropertiesChanged( ); + + m_IsMouseDown = true; + CStateRow *theStateRow = m_ParentRow->GetStateRow(); + long theStartTime = theStateRow->GetStartTime(); + long theEndTime = theStateRow->GetEndTime(); + m_Snapper.SetStartEndTime(theStartTime, theEndTime); + m_Snapper.SetSource(this); + m_Snapper.SetKeyFrameClicked(true); + m_Snapper.SetSnappingSelectedKeyframes(false); + + theStateRow->GetTimebar()->GetSnappingListProvider().PopulateSnappingList(&m_Snapper); + m_Snapper.BeginDrag(inPoint.x); + + // display the time range tooltip + RefreshToolTip(inPoint); + } + return true; +} + +//============================================================================= +/** + * Handler for right mouse down events. + * @param inPoint the point where the mouse is + * @param inFlags indicates modifier keys that were down at time of the event + */ +bool CAssetTimelineKeyframe::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseRDown(inPoint, inFlags)) { + if (!m_Selected) { + m_Selected = true; + m_ParentRow->OnKeySelected(m_Time, m_Selected, true); + } + ITimelineItemProperty *iProperty = nullptr; + if (GetTimelineItemBinding()->GetPropertyCount() > 0) { + iProperty = GetTimelineItemBinding()->GetProperty(0); + } + CKeyframeContextMenu theMenu(GetTimelineItemBinding()->GetKeyframesManager(), iProperty); + theMenu.SetTime(GetTime()); + DoPopup(&theMenu, inPoint); + } + + return true; +} + +//============================================================================= +/** + * called when this key is selected + * + * @param inState the state this key is selected to + */ +void CAssetTimelineKeyframe::Select(bool inState) +{ + if (m_Selected != inState) { + m_Selected = inState; + Invalidate(); + } +} + +//============================================================================= +/** + * handler for the mouse up event + * @param inFlags the state of things when the mouse button was released + * @param inPoint the point where the mouse is + */ +void CAssetTimelineKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + m_IsMouseDown = false; + m_IsDragging = false; + + GetTimelineItemBinding()->CommitChangedKeyframes(); + + HideMoveableWindow(); + Invalidate(); +} + +//============================================================================= +/** + * handler for the onMouse Move event. Offsets selected keys. + * Displays the StudioToolTip for the keyframe, showing the time it is at. + * + * @param inFlags the state of things when the mouse was moved + * @param inPoint the point where the mouse is + */ +void CAssetTimelineKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + UICPROFILE(OnMouseMove); + // If the mouse is down and this is slected, then offst the keys + if (m_IsMouseDown && m_Selected) { + // If we are not yet dragging the keyframe + if (!m_IsDragging) { + long theDiff = ::abs(inPoint.x) - m_MouseDownLoc.x; + // Figure out if the mouse has moved far enough to start the drag, and readjust the drag + // postion on the snapper + m_IsDragging = (::abs(theDiff) > DRAGBUFFER); + if (m_IsDragging && (::abs(theDiff) - DRAGBUFFER) > 2) { + m_Snapper.BeginDrag(m_MouseDownLoc.x); + } else + m_Snapper.BeginDrag(inPoint.x); + } + + // If we are now dragging, procceed as normal + if (m_IsDragging) { + long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags); + long theDiffTime = theNewTime - m_Time; + + if (theDiffTime != 0) { + // theDiffTime can get updated if its invalid. + theDiffTime = GetTimelineItemBinding()->OffsetSelectedKeyframes(theDiffTime); + // Set this key's time so it won't be recalced in Refresh keyframes in the row + SetTime(m_Time + theDiffTime); + + Invalidate(); + } + } + + // display the time range tooltip + RefreshToolTip(inPoint); + } +} + +//============================================================================= +/** + * Sets the time ratio + * + * @param inTimeRatio the new ratio + */ +void CAssetTimelineKeyframe::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + CPt theSize = GetSize(); + SetPosition(::TimeToPos(GetTime(), m_TimeRatio) - (theSize.x / 2), 0); +} + +//============================================================================= +/** + * Pass the double click notification on to the row and have it process it. + * The row will do object-specific actions on doubleclicks. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + * @return true stating that the event was processed. + */ +bool CAssetTimelineKeyframe::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + GetTimelineItemBinding()->OnEditKeyframeTime(m_Time, ASSETKEYFRAME); + m_IsMouseDown = false; + m_IsDragging = false; + return true; +} + +//============================================================================= +/** + * @return true if selected + */ +bool CAssetTimelineKeyframe::IsSelected() +{ + return m_Selected; +} + +void CAssetTimelineKeyframe::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); +} + +//============================================================================= +/** + * + */ +ITimelineItemBinding *CAssetTimelineKeyframe::GetTimelineItemBinding() const +{ + return m_ParentRow->GetStateRow()->GetTimelineItemBinding(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h new file mode 100644 index 00000000..54a8b501 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_ASSET_TIMELINE_KEYFRAME +#define INCLUDED_ASSET_TIMELINE_KEYFRAME 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "TimelineKeyframe.h" +#include "Snapper.h" + +#include <QPixmap> + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CStateTimebarlessRow; +class ITimelineItemBinding; + +class CAssetTimelineKeyframe : public CControl, public CTimelineKeyframe +{ + +public: + CAssetTimelineKeyframe(CStateTimebarlessRow *inParentRow, double inTimeRatio); + ~CAssetTimelineKeyframe(); + + void Draw(CRenderer *inRenderer) override; + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void Select(bool inState); + void SetTimeRatio(double inTimeRatio); + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool IsSelected(); + void SetSize(CPt inSize) override; + bool HitTest(const CPt &inPoint) const override; + void SetRectOverHandled(bool inState); + bool GetRectOverHandled(); + void SetPreviousSelectState(bool inState); + bool GetPreviousSelectState(); + +protected: + void RefreshToolTip(CPt inPoint); + QPixmap GetImage() const; + ITimelineItemBinding *GetTimelineItemBinding() const; + +protected: + bool m_RectOverHandled; ///< Indicates if the mouse rect over has been handled. + bool m_PreviousSelectState; ///< Stores the previous select state for the keyframe. + bool m_Selected; + CStateTimebarlessRow *m_ParentRow; + bool m_IsMouseDown; + CPt m_MouseDownLoc; ///< Location of the mouse after an OnMouseDownEvent, in client coordinates + bool m_IsDragging; ///< Indicates whether or not the keyframe is currently being dragged, + ///determined by the pixel buffer + double m_TimeRatio; + + CSnapper m_Snapper; + QPixmap m_Icon; + QPixmap m_DisabledIcon; + QPixmap m_SelectedIcon; + QPixmap m_DynamicIcon; + QPixmap m_DynamicSelectedIcon; + QPixmap m_LeftIcon; + QPixmap m_LeftDisabledIcon; + QPixmap m_LeftSelectedIcon; + QPixmap m_LeftDynamicIcon; + QPixmap m_LeftDynamicSelectedIcon; + QPixmap m_RightIcon; + QPixmap m_RightDisabledIcon; + QPixmap m_RightSelectedIcon; + QPixmap m_RightDynamicIcon; + QPixmap m_RightDynamicSelectedIcon; +}; + +#endif // INCLUDED_ASSET_TIMELINE_KEYFRAME diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp new file mode 100644 index 00000000..7960ed96 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp @@ -0,0 +1,1139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "BaseStateRow.h" +#include "PropertyRow.h" +#include "BaseTimelineTreeControl.h" +#include "ToggleControl.h" +#include "BaseTimebarlessRow.h" +#include "ColorControl.h" +#include "StateRowFactory.h" +#include "TimelineTimelineLayout.h" +#include "ComponentContextMenu.h" +#include "ITimelineControl.h" +#include "ResourceCache.h" +#include "StudioUtils.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/ITimelineTimebar.h" + +const long CBaseStateRow::DEFAULT_TOGGLE_LENGTH = 57; + +CBaseStateRow::CBaseStateRow() + : m_TimeRatio(0.0f) + , m_TreeList(true)// true to align the children in the timeline. + , m_TreeControl(nullptr) + , m_ColorControl(nullptr) + , m_ToggleControl(nullptr) + , m_TimebarControl(nullptr) + , m_Loaded(false) + , m_IsExpanded(false) + , m_Highlighted(false) + , m_Dirty(false) + , m_Selected(false) + , m_TimelineItemBinding(nullptr) + , m_ActiveStart(0) + , m_ActiveEnd(0) +{ +} + +CBaseStateRow::~CBaseStateRow() +{ + delete m_TreeControl; + delete m_ColorControl; + delete m_ToggleControl; + delete m_TimebarControl; + + // Go through all the state rows and delete them, this control owns all child controls. + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + (*thePos)->Dispose(); + + // Go through all the properties and delete them, this control owns all child controls. + TPropertyRowList::iterator thePropertyPos = m_PropertyRows.begin(); + for (; thePropertyPos != m_PropertyRows.end(); ++thePropertyPos) { + CPropertyRow *theRow = (*thePropertyPos); + delete theRow; + } +} + +void CBaseStateRow::Initialize(ITimelineItemBinding *inTimelineItemBinding) +{ + m_Dirty = true; + ASSERT(inTimelineItemBinding); + m_TimelineItemBinding = inTimelineItemBinding; + + m_TreeControl = new CBaseTimelineTreeControl(this, GetTimelineItem()->IsMaster()); + m_ColorControl = new CColorControl(this); + m_ToggleControl = CreateToggleControl(); + m_TimebarControl = CreateTimebarRow(); + + long theTimebarHeight = CStudioPreferences::GetRowSize(); + m_TreeControl->SetSize(CPt(500, theTimebarHeight)); + m_ColorControl->SetAbsoluteSize(CPt(theTimebarHeight, theTimebarHeight)); + m_ToggleControl->SetAbsoluteSize(CPt(DEFAULT_TOGGLE_LENGTH, theTimebarHeight)); + m_TimebarControl->SetSize(CPt(800, theTimebarHeight)); + + ::CColor theColor = GetTimebarBackgroundColor(GetObjectType()); + m_TreeControl->SetBackgroundColor(theColor); + m_ToggleControl->SetBackgroundColor(theColor); + m_TimebarControl->SetBackgroundColor(theColor); + + m_ColorList.AddChild(m_ColorControl); + m_TreeList.AddChild(m_TreeControl); + m_ToggleList.AddChild(m_ToggleControl); + m_TimebarList.AddChild(m_TimebarControl); + + // sk - I think setting controls' names is only useful for debugging. + /*Q3DStudio::CString theAssetName( m_Asset->GetName( ) ); + m_TreeControl->SetName( theAssetName + "TreeControl" ); + m_TreeList.SetName( theAssetName + "TreeList" ); + m_ColorControl->SetName( theAssetName + "ColorControl" ); + m_ColorList.SetName( theAssetName + "ColorList" ); + m_ToggleControl->SetName( theAssetName + "ToggleControl" ); + m_ToggleList.SetName( theAssetName + "ToggleList" ); + m_TimebarControl->SetName( theAssetName + "TimebarControl" ); + m_TimebarList.SetName( theAssetName + "TimebarList" );*/ + + // Bind after all the UI is setup. + m_TimelineItemBinding->Bind(this); // see Dispose where it properly unbinds. + + ClearDirty(); +} + +//============================================================================= +/** + * Expand this node of the tree control. + * This will display all children the fit the filter. + */ +void CBaseStateRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp) +{ + if (!m_IsExpanded) { + m_Filter.SetExpanded(true); + + // Expand/Collapse is done by adding and removing the children, add all the + // properties first so they are at the top of the list. + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->Filter(m_Filter, false); + } + // Add all the State rows after the properties. + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + CStateRow *theRow = (*thePos); + theRow->Filter(m_Filter, false); + } + + m_TreeControl->SetExpanded(true); + m_IsExpanded = true; + m_ColorControl->UpdateIconStatus(); + } + + if (inExpandAll) { + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + (*thePos)->Expand(inExpandAll); + } + + if (inExpandUp && m_ParentRow) + m_ParentRow->Expand(false, inExpandUp); +} + +//============================================================================= +/** + * Collapse this node of the tree control. + * This will hide all children of this control. + */ +void CBaseStateRow::Collapse(bool inCollapseAll /* = false */) +{ + if (m_IsExpanded) { + CFilter theFilter = m_Filter; + theFilter.SetExpanded(false); + + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->Filter(theFilter); + } + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + CStateRow *theRow = (*thePos); + theRow->Filter(theFilter); + } + + m_TimelineItemBinding->OnCollapsed(); + + m_TreeControl->SetExpanded(false); + m_IsExpanded = false; + m_ColorControl->UpdateIconStatus(); + } + + if (inCollapseAll) { + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + (*thePos)->Collapse(inCollapseAll); + } + } +} + +//============================================================================= +/** + * Toggle the expansion state of this control. + * This will expand the control if it is closed, or collapse it if it is + * open. + */ +void CBaseStateRow::ToggleExpansion(CToggleButton *, CButtonControl::EButtonState inButtonState) +{ + if (inButtonState == CButtonControl::EBUTTONSTATE_UP) + Collapse(); + else + Expand(); +} + +//============================================================================= +/** + * Shows or hides rows for all children, based on the filter. + * @param inFilter Object specifying the filters currently applied to the timeline. + * @param inFilterChildren true if the filter should go recursively to children. + */ +void CBaseStateRow::Filter(const CFilter &inFilter, bool inFilterChildren /*= true*/) +{ + m_Filter = inFilter; + + // For each child object + if (inFilterChildren) { + CFilter theChildFilter = inFilter; + theChildFilter.SetExpanded(m_IsExpanded); + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + // Apply the filter + CStateRow *theRow = (*thePos); + theRow->Filter(theChildFilter); + } + } + + // This flag determines whether or not the controls on this row should be shown, based on the + // filter + bool theVisibleFlag = PerformFilter(m_Filter); + + m_IsViewable = theVisibleFlag; + + theVisibleFlag &= inFilter.IsExpanded(); + + // Show or hide the controls on this row before we iterate through the properties + m_ColorList.SetVisible(theVisibleFlag); + m_TreeList.SetVisible(theVisibleFlag); + m_ToggleList.SetVisible(theVisibleFlag); + m_TimebarList.SetVisible(theVisibleFlag); + + if (inFilterChildren) { + CFilter theChildFilter = inFilter; + theChildFilter.SetExpanded(m_IsExpanded); + + // For each property on this object + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + // Apply the filter + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->Filter(theChildFilter); + } + } + + m_TreeControl->SetToggleVisible(this->HasVisibleChildren()); +} + +//============================================================================= +/** + * Get the color control for this row. + * @return the color control for this row. + */ +CControl *CBaseStateRow::GetColorControl() +{ + return &m_ColorList; +} + +//============================================================================= +/** + * Get the tree control for this row. + * @return the tree control for this row. + */ +CControl *CBaseStateRow::GetTreeControl() +{ + return &m_TreeList; +} + +//============================================================================= +/** + * Get the toggle control for this row. + * @return the toggle control for this row. + */ +CControl *CBaseStateRow::GetToggleControl() +{ + return &m_ToggleList; +} + +//============================================================================= +/** + * Get the timebar control for this row. + * @return the timebar control for this row. + */ +CControl *CBaseStateRow::GetTimebarControl() +{ + return &m_TimebarList; +} + +//============================================================================= +/** + * Remove a row from this control. + * @param inState the state of the row to be removed. + */ +void CBaseStateRow::RemoveRow(CStateRow *inRow) +{ + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + CStateRow *theRow = (*thePos); + if (theRow == inRow) { + DeleteRow(theRow); + m_StateRows.erase(thePos); + break; + } + } + m_TreeControl->SetToggleVisible(this->HasVisibleChildren()); +} + +//============================================================================= +/** + * Helper function to remove all controls of this property row and dispose of it. + */ +void CBaseStateRow::DeletePropertyRow(CPropertyRow *inPropertyRow) +{ + if (!inPropertyRow) + return; + + m_ColorList.RemoveChild(inPropertyRow->GetColorControl()); + m_TreeList.RemoveChild(inPropertyRow->GetTreeControl()); + m_ToggleList.RemoveChild(inPropertyRow->GetToggleControl()); + m_TimebarList.RemoveChild(inPropertyRow->GetTimebarControl()); + delete inPropertyRow; +} + +//============================================================================= +/** + * By default, we don't show shy/eye/lock toggles + */ +CBlankToggleControl *CBaseStateRow::CreateToggleControl() +{ + return new CBlankToggleControl(this); +} + +//============================================================================= +/** + * Get the StateRow that is representing this child timeline item. + * @param inTimelineItem child timeline item + * @return the StateRow for inState. + */ +CStateRow *CBaseStateRow::GetRow(ITimelineItem *inTimelineItem) +{ + if (inTimelineItem) { + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + if ((*thePos)->GetTimelineItem() == inTimelineItem) + return (*thePos); + } + } + return nullptr; +} + +//============================================================================= +/** + * Called when a row is to be completely removed from the UI + */ +void CBaseStateRow::DeleteRow(CStateRow *inRow) +{ + m_ColorList.RemoveChild(inRow->GetColorControl()); + m_TreeList.RemoveChild(inRow->GetTreeControl()); + m_ToggleList.RemoveChild(inRow->GetToggleControl()); + m_TimebarList.RemoveChild(inRow->GetTimebarControl()); + + inRow->Dispose(); +} + +//============================================================================= +/** + * Call from the child controls that the mouse is over one of the children. + * This is used to highlight the entire row on mouse over. + */ +void CBaseStateRow::OnMouseOver() +{ + if (!m_Highlighted) { + try { + // TODO: Added the try/catch block to prevent crashing when the instance handle is not + // found + // this will happen sometimes when delete the object from the timeline + // need to really fix this at the root. + ::CColor theColor = GetTimebarHighlightBackgroundColor(GetObjectType()); + m_TreeControl->SetBackgroundColor(theColor); + m_ToggleControl->SetBackgroundColor(theColor); + m_TimebarControl->SetBackgroundColor(theColor); + + m_Highlighted = true; + } catch (...) { + } + } +} + +//============================================================================= +/** + * Call from the child controls that the mouse is no longer over one of the children. + * This is used to highlight the entire row on mouse over. + */ +void CBaseStateRow::OnMouseOut() +{ + if (m_Highlighted) { + try { + // TODO: Added the try/catch block to prevent crashing when the instance handle is not + // found + // this will happen sometimes when delete the object from the timeline + // need to really fix this at the root. + ::CColor theColor = GetTimebarBackgroundColor(GetObjectType()); + m_TreeControl->SetBackgroundColor(theColor); + m_ToggleControl->SetBackgroundColor(theColor); + m_TimebarControl->SetBackgroundColor(theColor); + + m_Highlighted = false; + } catch (...) { + } + } +} + +//============================================================================= +/** + * Tells this that the Asset data has changed and it needs to be updated. + * Someone should call ClearDirty afterwards. + */ +void CBaseStateRow::OnDirty() +{ + m_Dirty = true; +} + +void CBaseStateRow::ClearDirty() +{ + if (m_Dirty) { + m_TreeControl->Refresh(m_TimelineItemBinding->GetTimelineItem()); + m_ToggleControl->Refresh(); + m_ColorControl->Invalidate(); + m_TimebarControl->RefreshRowMetaData(); + m_Dirty = false; + } +} + +//============================================================================= +/** + * Recursively load the children of this control, used by derived classes + * This will load all the properties and states, and create controls for them. + */ +void CBaseStateRow::LoadChildren() +{ + if (!m_Loaded) { + m_Loaded = true; + + LoadProperties(); + + CTimelineItemOrderedIterator theChildIter(m_TimelineItemBinding); + // Go through all the children and load them too. + for (; !theChildIter.IsDone(); ++theChildIter) + CreateChildRow(*theChildIter, nullptr); + + GetTopControl()->OnLayoutChanged(); + } +} + +//============================================================================= +/** + * Add a row that represents this child timeline item + * @param inNextItem indicates row to follow behind the row for inTimeLineItem, nullptr to append inRow + * to the end of the current list. + */ +void CBaseStateRow::AddChildRow(ITimelineItemBinding *inTimeLineItem, + ITimelineItemBinding *inNextItem) +{ + if (!inTimeLineItem) + return; + + // only add if loaded, else it will get added twice. + if (m_Loaded) { + CStateRow *theStateRow = CreateChildRow( + inTimeLineItem, inNextItem ? GetRow(inNextItem->GetTimelineItem()) : nullptr); + if (theStateRow) + theStateRow->LoadChildren(); + } + Expand(false, true); + + CBaseStateRow *theRow = GetRow(inTimeLineItem->GetTimelineItem()); + if (theRow) { + CControl *theTreeControl = theRow->GetTreeControl(); + if (theTreeControl) + theTreeControl->EnsureVisible(); + } +} + +void CBaseStateRow::RemoveChildRow(ITimelineItemBinding *inTimelineItem) +{ + CStateRow *theChildRow = GetRow(inTimelineItem->GetTimelineItem()); + inTimelineItem->SetParent(nullptr); + if (theChildRow) { + RemoveRow(theChildRow); + // preserving legacy behavior. + GetTopControl()->HideTimelineMoveableTooltip(); + } +} + +//============================================================================= +/** + * Removes all child rows from this row. Called prior to a load. The load call is responsible for + * updating the UI. + */ +void CBaseStateRow::RemoveAllChildren() +{ + RemoveAllProperties(); + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + DeleteRow(*thePos); + + m_StateRows.clear(); +} + +//============================================================================= +/** + * Remove all the properties from this object. Called prior to a load. The load call is responsible + * for updating the UI. + */ +void CBaseStateRow::RemoveAllProperties() +{ + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) + DeletePropertyRow(*thePropPos); + + m_PropertyRows.clear(); +} + +//============================================================================= +/** + * Set this row to selected + */ +void CBaseStateRow::Select(SBaseStateRowSelectionKeyState inState, + bool inCheckKeySelection /*= true */) +{ + bool alreadySelected = m_Selected; + m_TimelineItemBinding->SetSelected(inState.IsControlDown()); + if (inCheckKeySelection) { + if (inState.IsShiftDown()) + m_TimebarControl->SelectAllKeys(); + else if (!alreadySelected) + m_TimelineItemBinding->ClearKeySelection(); + } +} + +//============================================================================= +/** + * Change the selection state of the row. + */ +void CBaseStateRow::OnSelected(bool inSelection) +{ + if (inSelection == m_Selected) + return; + + m_Selected = inSelection; + if (inSelection) { + if (m_ParentRow) + m_ParentRow->Expand(false, true); + + m_TreeControl->EnsureVisible(); + + m_TreeControl->OnSelect(); + m_ToggleControl->OnSelect(); + m_ColorControl->OnSelect(); + m_TimebarControl->OnSelect(); + } else { + m_TreeControl->OnDeselect(); + m_ToggleControl->OnDeselect(); + m_ColorControl->OnDeselect(); + m_TimebarControl->OnDeselect(); + } +} + +//============================================================================= +/** + * Call to add a property row as a child of this control. + * @param inRow the row to be added. + */ +void CBaseStateRow::AddPropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow /*= nullptr */) +{ + m_PropertyRows.push_back(inRow); + InitializePropertyRow(inRow, inNextRow); + // For snapping timebars/keyframes + inRow->SetSnappingListProvider(GetSnappingListProvider()); + + m_TimebarControl->SetDirty(true); +} + +//============================================================================= +/** + * Remove the property row. + */ +void CBaseStateRow::RemovePropertyRow(const CPropertyRow *inRow) +{ + if (!inRow) + return; + + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *theRow = *thePropPos; + if (theRow == inRow) { + DeletePropertyRow(theRow); + m_PropertyRows.erase(thePropPos); + + // Update flippy + OnChildVisibilityChanged(); + break; + } + } +} + +//============================================================================= +/** + * Helper function to initialize a new property row + * @param inRow the row to be added. + * @param inNextRow if specified, row that should be after inRow after + * insertion. + */ +void CBaseStateRow::InitializePropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow /*= nullptr */) +{ + CFilter theFilter = m_Filter; + theFilter.SetExpanded(m_IsExpanded); + + if (!inNextRow) { // not provided, this property row would be inserted before the first + // non-property row. + CTimelineItemOrderedIterator theIterator(m_TimelineItemBinding); + if (!theIterator.IsDone()) + inNextRow = GetRow(theIterator.GetCurrent()->GetTimelineItem()); + } + AddRowToUILists(inRow, inNextRow, theFilter); +} + +void CBaseStateRow::AddRowToUILists(CTimelineRow *inRow, CTimelineRow *inNextRow, CFilter &inFilter) +{ + // Default the insert locations to the end of the list. + CControl *theNextColorControl = nullptr; + CControl *theNextTreeControl = nullptr; + CControl *theNextToggleControl = nullptr; + CControl *theNextTimebarControl = nullptr; + if (inNextRow) { + theNextColorControl = inNextRow->GetColorControl(); + theNextTreeControl = inNextRow->GetTreeControl(); + theNextToggleControl = inNextRow->GetToggleControl(); + theNextTimebarControl = inNextRow->GetTimebarControl(); + } + inRow->SetIndent(m_Indent + CTimelineRow::TREE_INDENT); + inRow->SetParent(this); + inRow->Filter(inFilter); + inRow->SetTimeRatio(m_TimeRatio); + + CControl *theColorControl = inRow->GetColorControl(); + CControl *theTreeControl = inRow->GetTreeControl(); + CControl *theToggleControl = inRow->GetToggleControl(); + CControl *theTimebarControl = inRow->GetTimebarControl(); + + // If not expanded then hide the controls. + if (!m_IsExpanded) { + theColorControl->SetVisible(false); + theTreeControl->SetVisible(false); + theToggleControl->SetVisible(false); + theTimebarControl->SetVisible(false); + } + + // Add the controls to the lists in the prioritized order + m_ColorList.AddChild(theColorControl, theNextColorControl); + m_TreeList.AddChild(theTreeControl, theNextTreeControl); + m_ToggleList.AddChild(theToggleControl, theNextToggleControl); + m_TimebarList.AddChild(theTimebarControl, theNextTimebarControl); + + m_TreeControl->SetToggleVisible(this->HasVisibleChildren()); +} + +CStateRow *CBaseStateRow::CreateChildRow(ITimelineItemBinding *inChildBinding, CStateRow *inNextRow) +{ + CStateRow *theRow = + CStateRowFactory::CreateStateRow(inChildBinding, this, GetSnappingListProvider()); + if (theRow) { // add by appending to the list + AddStateRow(theRow, inNextRow); + } + inChildBinding->SetParent(m_TimelineItemBinding); + return theRow; +} + +long CBaseStateRow::GetNumNonPropertyRows() const +{ + return static_cast<long>(m_StateRows.size()); +} + +CBaseStateRow *CBaseStateRow::GetNonPropertyRow(long inIndex) const +{ + return m_StateRows.at(inIndex); +} + +long CBaseStateRow::GetNumPropertyRows() const +{ + return static_cast<long>(m_PropertyRows.size()); +} +CPropertyRow *CBaseStateRow::GetPropertyRow(long inIndex) const +{ + return m_PropertyRows.at(inIndex); +} + +//============================================================================= +/** + * Call to add a state row as a child of this control. + * @param inRow the row to be added. + * @param inNextRow row to follow behind the row that would be added, nullptr to append inRow to the + * end of the current list. + */ +void CBaseStateRow::AddStateRow(CStateRow *inRow, CStateRow *inNextRow) +{ + if (inNextRow != nullptr) { + TStateRowList::iterator thePos = m_StateRows.begin(); + while (thePos != m_StateRows.end()) { + if ((*thePos) == inNextRow) { + m_StateRows.insert(thePos, inRow); + thePos = m_StateRows.end(); + } else + ++thePos; + } + } else { + m_StateRows.push_back(inRow); + } + + AddRowToUILists(inRow, inNextRow, m_Filter); +} + +//============================================================================= +/** + * Checks to see if there are any visible children of this row. + * This is used for figuring out whether the expand button should be displayed + * or not. + */ +bool CBaseStateRow::HasVisibleChildren() +{ + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + // Apply the filter + if ((*thePos)->IsViewable()) + return true; + } + + // For each property on this object + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + // Apply the filter + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow && thePropRow->IsViewable()) + return true; + } + return false; +} + +//============================================================================= +/** + * Set the amount of time that is represented by a pixel. + * This modifies the length of this control. + * @param inTimePerPixel the time per pixel. + */ +void CBaseStateRow::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + m_TimebarControl->SetTimeRatio(inTimeRatio); + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + (*thePos)->SetTimeRatio(inTimeRatio); + } + + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->SetTimeRatio(inTimeRatio); + } +} + +//============================================================================= +/** + * Called when a child becomes visible/invisible. + */ +void CBaseStateRow::OnChildVisibilityChanged() +{ + m_TreeControl->SetToggleVisible(this->HasVisibleChildren()); +} + +//============================================================================= +/** + * Called when the mouse is double clicked. + * @param inPoint location of the mouse at time of event + * @param inFlags modifier key states at time of event + */ +void CBaseStateRow::OnMouseDoubleClick(CPt, Qt::KeyboardModifiers inFlags) +{ + // Do nothing by default. Let subclasses define what to do. + Q_UNUSED(inFlags); +} + +//============================================================================= +/** + * Show context menu for this row + */ +void CBaseStateRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inFlags); + + Select(SBaseStateRowSelectionKeyState()); // ensure this is selected, but doesn't affect any key + // selections, because this can be triggered from a + // key being selected + CComponentContextMenu theMenu(m_TreeControl, m_TimelineItemBinding); + m_TreeControl->DoPopup(&theMenu, inPoint); +} + +//============================================================================= +/** + * Selects keys in a given rect + * @param inRect the rect to use for selection + */ +void CBaseStateRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown, + bool inGlobalCommitSelectionFlag) +{ + CRct theOffsetRect = inRect; + theOffsetRect.Offset(-m_TimebarList.GetPosition()); + + // Commits the keyframe selection by setting the keyframes' previous state to its current state, + // when the user releases the mouse button. + // This will help the keyframes to retain their original states even though they are + // not in the mouse select region. + if (inGlobalCommitSelectionFlag) { + m_TimebarControl->CommitSelections(); + + // iterates through every property row and commits the selection states of properties + // keyframes + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow && thePropRow->IsViewable()) + thePropRow->CommitSelections(); + } + } + + if (m_IsExpanded) { + // Iterates each property row and select the keys that are in the rectangle + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow && thePropRow->IsViewable()) + thePropRow->SelectKeysInRect(theOffsetRect, inModifierKeyDown); + } + + // Recurse the each state row (or master row) and selects the property keyframes in them + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + (*thePos)->SelectKeysInRect(theOffsetRect, inModifierKeyDown, + inGlobalCommitSelectionFlag); + + } else { + // Selects all the master key frames in the rect + m_TimebarControl->SelectKeysInRect(theOffsetRect, inModifierKeyDown); + } +} + +//============================================================================= +/** + * Deletes all the keys for the asset that was chosen by the user + * @param inBatch the batch used to batch all the deletes together + */ +void CBaseStateRow::DeleteAllKeys() +{ + // Iterate through all the property rows and delete all their keys + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->DeleteAllKeys(); + } +} + +//============================================================================= +/** + * Add snapping points to inSnappingList. + * This will add the snapping points for any visible objects to inSnappingList. + * @param inSnappingList the list to add the snapping points to. + */ +void CBaseStateRow::PopulateSnappingList(CSnapper *inSnappingList) +{ + inSnappingList->PushOffset(-m_TimebarList.GetPosition().y); + m_TimebarControl->PopulateSnappingList(inSnappingList); + + if (IsExpanded()) { + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + (*thePos)->PopulateSnappingList(inSnappingList); + } + } +} + +//============================================================================= +/** + * Sets all the child control enable states + * @param inEnabled the state to set the controls to + */ +void CBaseStateRow::SetEnabled(bool inEnabled) +{ + m_TreeControl->SetEnabled(inEnabled); + m_ToggleControl->SetEnabled(inEnabled); + m_ColorControl->SetEnabled(inEnabled); + m_TimebarControl->SetEnabled(inEnabled); +} + +//============================================================================= +/** + * Begin dragging. + * sk - potential spot for refactoring the Drag&Drop implementation. + * Right now, each IDragable is implicitly assumed to be a asset implementation. See + * *DropSource.cpp: each IDragable is dynamically cast to its implementation. + */ +void CBaseStateRow::DoStartDrag(CControlWindowListener *inWndListener) +{ + m_TimelineItemBinding->DoStartDrag(inWndListener); +} + +void CBaseStateRow::AcceptDropAfter(bool inAccept) +{ + m_TreeControl->AcceptDropAfter(inAccept); +} + +void CBaseStateRow::AcceptDropBefore(bool inAccept) +{ + m_TreeControl->AcceptDropBefore(inAccept); +} + +//============================================================================= +/** + * Pass through to the binding to set up the target aset for a drag&drop action on this + *control. + */ +void CBaseStateRow::SetDropTarget(CDropTarget *inDropTarget) +{ + m_TimelineItemBinding->SetDropTarget(inDropTarget); +} + +void CBaseStateRow::SetTimelineLatestTime(long inTime) +{ + long theLength = ::TimeToPos(inTime, m_TimeRatio) + CTimelineTimelineLayout::END_BUFFER_SIZE; + m_TimebarControl->SetAbsoluteSize(CPt(theLength, m_TimebarControl->GetSize().y)); + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + (*thePos)->SetTimelineLatestTime(inTime); +} + +//============================================================================= +/** + * Determines whether or not a row is expanded. A row can be expanded even if + * it is not visible. + * @return true if the row is currently expanded, otherwise false + */ +bool CBaseStateRow::IsExpanded() +{ + return m_IsExpanded; +} + +//============================================================================= +/** + * Determines whether or not a row is loaded. The rows are delayed loaded, i.e. + * it will be loaded when it's visible for the first time. Before it's loaded, any + * updates to the structure, say, adding dynamic properties does not need to update the + * timeline. + * @return true if the row is currently loaded, otherwise false + */ +bool CBaseStateRow::IsLoaded() +{ + return m_Loaded; +} + +long CBaseStateRow::GetStartTime() +{ + ITimelineTimebar *theTimebar = m_TimelineItemBinding->GetTimelineItem()->GetTimebar(); + if (theTimebar) + return theTimebar->GetStartTime(); + return 0; +} + +long CBaseStateRow::GetEndTime() +{ + ITimelineTimebar *theTimebar = m_TimelineItemBinding->GetTimelineItem()->GetTimebar(); + if (theTimebar) + return theTimebar->GetEndTime(); + return 0; +} + +long CBaseStateRow::GetActiveStart() +{ + return m_ActiveStart; +} +long CBaseStateRow::GetActiveEnd() +{ + return m_ActiveEnd; +} + +//============================================================================= +/** + * Get the start time of this row, which is accumulative of all its descendants. + */ +long CBaseStateRow::GetEarliestStartTime() +{ + long theEarliestStartTime = 0; + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + CStateRow *theRow = (*thePos); + long theStartTime = theRow->GetEarliestStartTime(); + if (theStartTime < theEarliestStartTime) + theEarliestStartTime = theStartTime; + } + return theEarliestStartTime; +} + +//============================================================================= +/** + * Get the end time of this row, which is accumulative of all its descendants. + */ +long CBaseStateRow::GetLatestEndTime() +{ + long theLatestTime = 0; + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) { + CStateRow *theRow = (*thePos); + long theEndTime = theRow->GetLatestEndTime(); + if (theEndTime > theLatestTime) + theLatestTime = theEndTime; + } + return theLatestTime; +} + +//============================================================================= +/** + * Lame switch to get the normal state object specific icon. + * @return the icon to be used in the 'normal' state. + */ +QPixmap CBaseStateRow::GetIcon() +{ + return CResourceCache::GetInstance()->GetBitmap( + CStudioObjectTypes::GetNormalIconName(GetObjectType())); +} + +//============================================================================= +/** + * Lame switch to get the disabled state object specific icon. + * @return the icon to be used in the disabled state. + */ +QPixmap CBaseStateRow::GetDisabledIcon() +{ + return CResourceCache::GetInstance()->GetBitmap( + CStudioObjectTypes::GetDisabledIconName(GetObjectType())); +} + +//============================================================================= +/** + * @return the studio type of the object represented by this row + */ +EStudioObjectType CBaseStateRow::GetObjectType() const +{ + return GetTimelineItem()->GetObjectType(); +} + +ITimelineItemBinding *CBaseStateRow::GetTimelineItemBinding() const +{ + return m_TimelineItemBinding; +} + +ITimelineItem *CBaseStateRow::GetTimelineItem() const +{ + return m_TimelineItemBinding->GetTimelineItem(); +} + +//============================================================================= +/** + * When this row is no longer useful, clean up. + */ +void CBaseStateRow::Dispose() +{ + // Disconnection point + if (m_TimelineItemBinding) + m_TimelineItemBinding->Release(); + + CTimelineRow::Dispose(); +} + +void CBaseStateRow::UpdateActionStatus() +{ + m_ColorControl->UpdateIconStatus(); +} + +//============================================================================= +/** + * Restores the focus state of this row. + */ +void CBaseStateRow::SetFocus() +{ + CControl *theParent = m_TreeControl->GetParent(); + if (theParent) + theParent->GrabFocus(m_TreeControl); +} + +CBaseTimebarlessRow *CBaseStateRow::GetTimebar() const +{ + return m_TimebarControl; +} + +void CBaseStateRow::SetNameReadOnly(bool inReadOnly) +{ + m_TreeControl->SetNameReadOnly(inReadOnly); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h new file mode 100644 index 00000000..5a62dfc0 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_BASE_STATE_ROW_H +#define INCLUDED_BASE_STATE_ROW_H 1 + +#pragma once + +#include "TimelineRow.h" +#include "ListLayout.h" +#include "ToggleButton.h" +#include "DispatchListeners.h" + +class CPropertyRow; +class CBaseTimelineTreeControl; +class CColorControl; +class CBlankToggleControl; +class CBaseTimebarlessRow; +class CStateRow; +class CCmdBatch; +class ITimelineItem; +class ITimelineItemBinding; + +struct SBaseStateRowSelectionKeyState +{ + enum Enum { + NoKeyDown = 0, + ShiftKey = 1 << 0, + ControlKey = 1 << 1, + }; + qt3ds::QT3DSU32 m_KeyState; + SBaseStateRowSelectionKeyState() + : m_KeyState(0) + { + } + void SetShiftDown() { m_KeyState = m_KeyState | ShiftKey; } + void SetControlDown() { m_KeyState = m_KeyState | ControlKey; } + bool IsShiftDown() const { return (m_KeyState & ShiftKey) != 0; } + bool IsControlDown() const { return (m_KeyState & ControlKey) != 0; } +}; + +class CBaseStateRow : public CTimelineRow +{ +public: + typedef std::vector<CPropertyRow *> TPropertyRowList; + typedef std::vector<CStateRow *> TStateRowList; + static const long DEFAULT_TOGGLE_LENGTH; + +public: + CBaseStateRow(); + virtual ~CBaseStateRow(); + + virtual void Initialize(ITimelineItemBinding *inTimelineItemBinding); + + bool IsExpanded(); + bool IsLoaded(); + virtual void Expand(bool inExpandAll = false, bool inExpandUp = false); + virtual void Collapse(bool inCollapseAll = false); + void ToggleExpansion(CToggleButton *, CButtonControl::EButtonState); + + void SetTimeRatio(double inTimePerPixel) override; + + CControl *GetColorControl() override; + CControl *GetTreeControl() override; + CControl *GetToggleControl() override; + CControl *GetTimebarControl() override; + + void Select(SBaseStateRowSelectionKeyState inKeyState, bool inCheckKeySelection = true); + void SelectKeysInRect(CRct inRect, bool inModifierKeyDown, bool inGlobalCommitSelectionFlag); + void DeleteAllKeys(); + + virtual void OnMouseOver(); + virtual void OnMouseOut(); + virtual void OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnDirty(); + virtual void OnSelected(bool inSelected); + + void LoadChildren(); + void AddChildRow(ITimelineItemBinding *inTimeLineItem, ITimelineItemBinding *inNextItem); + void RemoveChildRow(ITimelineItemBinding *inTimeLineItem); + + void RemoveRow(CStateRow *inRow); + void AddStateRow(CStateRow *inRow, CStateRow *inNextRow); + void AddPropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow = nullptr); + void RemovePropertyRow(const CPropertyRow *inRow); + void RemoveAllChildren(); + void RemoveAllProperties(); + + long GetNumNonPropertyRows() const; + CBaseStateRow *GetNonPropertyRow(long inIndex) const; + long GetNumPropertyRows() const; + CPropertyRow *GetPropertyRow(long inIndex) const; + + void Filter(const CFilter &inFilter, bool inFilterChildren = true) override; + CFilter *GetFilter() { return &m_Filter; } + void OnChildVisibilityChanged() override; + + virtual bool HasVisibleChildren(); + + void PopulateSnappingList(CSnapper *inSnappingList) override; + + virtual void SetEnabled(bool inEnabled); + + void DoStartDrag(CControlWindowListener *inWndListener); + void AcceptDropAfter(bool inAccept); + void AcceptDropBefore(bool inAccept); + void SetDropTarget(CDropTarget *inDropTarget); + + // CTimelineRow + virtual long GetEarliestStartTime(); + long GetLatestEndTime() override; + + long GetStartTime(); + long GetEndTime(); + long GetActiveStart(); + long GetActiveEnd(); + virtual bool CalculateActiveStartTime() = 0; + virtual bool CalculateActiveEndTime() = 0; + void Dispose() override; + + virtual QPixmap GetIcon(); + virtual QPixmap GetDisabledIcon(); + + EStudioObjectType GetObjectType() const; + ITimelineItemBinding *GetTimelineItemBinding() const; + ITimelineItem *GetTimelineItem() const; + + void UpdateActionStatus(); + void SetFocus(); + + CBaseTimebarlessRow *GetTimebar() const; + + void SetNameReadOnly(bool inReadOnly); + + void ClearDirty(); + +protected: + void DeletePropertyRow(CPropertyRow *inPropertyRow); + virtual CBlankToggleControl *CreateToggleControl(); + virtual CBaseTimebarlessRow *CreateTimebarRow() = 0; + virtual bool PerformFilter(const CFilter &inFilter) = 0; + CStateRow *GetRow(ITimelineItem *inTimelineItem); + void DeleteRow(CStateRow *inRow); + void SetTimelineLatestTime(long inLength); + + virtual void LoadProperties() {} + void InitializePropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow = nullptr); + + void AddRowToUILists(CTimelineRow *inRow, CTimelineRow *inNextRow, CFilter &inFilter); + CStateRow *CreateChildRow(ITimelineItemBinding *inChildBinding, CStateRow *inNextRow); + + double m_TimeRatio; + CFilter m_Filter; + CListLayout m_ColorList; + CListLayout m_TreeList; + CListLayout m_ToggleList; + CListLayout m_TimebarList; + + CBaseTimelineTreeControl *m_TreeControl; + CColorControl *m_ColorControl; + CBlankToggleControl *m_ToggleControl; + CBaseTimebarlessRow *m_TimebarControl; + + TStateRowList m_StateRows; + TPropertyRowList m_PropertyRows; + + bool m_Loaded; + bool m_IsExpanded; + bool m_Highlighted; + bool m_Dirty; + bool m_Selected; + + ITimelineItemBinding *m_TimelineItemBinding; + + long m_ActiveStart; + long m_ActiveEnd; +}; +#endif // INCLUDED_BASE_STATE_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp new file mode 100644 index 00000000..4ded07dd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "BaseTimebarlessRow.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "BaseStateRow.h" + +CBaseTimebarlessRow::CBaseTimebarlessRow() + : m_Selected(false) + , m_DirtyFlag(true) + , m_TimeRatio(0.0f) +{ +} + +CBaseTimebarlessRow::~CBaseTimebarlessRow() +{ +} + +void CBaseTimebarlessRow::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + // Fill in the background + if (!m_Selected) + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + else + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor()); + + // Draw the line at the bottom of this control and the one on the side + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Set this control to being highlighted or not. + * @param inIsHighlighted true if this is to be highlighted. + */ +void CBaseTimebarlessRow::SetBackgroundColor(::CColor inBackgroundColor) +{ + if (m_BackgroundColor != inBackgroundColor) { + m_BackgroundColor = inBackgroundColor; + Invalidate(); + } +} + +void CBaseTimebarlessRow::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been selected. + */ +void CBaseTimebarlessRow::OnSelect() +{ + m_Selected = true; + + Invalidate(); +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been deselected. + */ +void CBaseTimebarlessRow::OnDeselect() +{ + m_Selected = false; + + Invalidate(); +} + +//============================================================================= +/** + * called when meta data for this row is changed... should be overridden by the + * timebar row + */ +void CBaseTimebarlessRow::RefreshRowMetaData() +{ +} + +//============================================================================= +/** + * called when a child changes and the keyframes need to be refreshed + * @param inDirtyFlag true if this object is now dirty + */ +void CBaseTimebarlessRow::SetDirty(bool inDirtyFlag) +{ + if (m_DirtyFlag == inDirtyFlag) + return; + + m_DirtyFlag = inDirtyFlag; + Invalidate(); +} + +void CBaseTimebarlessRow::UpdateTime(long inStartTime, long inEndTime) +{ + Q_UNUSED(inStartTime); + Q_UNUSED(inEndTime); +} + +//============================================================================= +/** + * OnMouseOver event, handles the highlighting of the row. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +void CBaseTimebarlessRow::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + GetBaseStateRow()->OnMouseOver(); +} + +//============================================================================= +/** + * OnMouseOut event, handles the de-highlighting of this row. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +void CBaseTimebarlessRow::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + GetBaseStateRow()->OnMouseOut(); +} + +//============================================================================= +/** + * OnMouseDown event, handles the selecting of this object. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +bool CBaseTimebarlessRow::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + return CControl::OnMouseDown(inPoint, inFlags); +#if 0 + // this addition is causing 4085: Cannot do rubber band selection from sections of timeline that don't contain timebars anymore + bool theReturn = CControl::OnMouseDown( inPoint, inFlags ); + if ( !theReturn ) + { + // Tests if the user has pressed the modifier key, where the intention is to multi-select keyframes. + if ( !(inFlags & CHotKeys::MODIFIER_CONTROL ) ) + { + // SK - I changed this to select the row when this is clicked, because I think its a nice feature. ie don't always have to click on the timebar (esp for those e.g. scene without one) + // when the modifier key is pressed. + GetBaseStateRow( )->Select( false ); + + theReturn = true; + } + } + return theReturn; +#endif +} diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h new file mode 100644 index 00000000..9c2fbea4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_BASE_TIMEBARLESS_ROW_H +#define INCLUDED_BASE_TIMEBARLESS_ROW_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" + +class CSnapper; +class CBaseStateRow; +class ISnappingListProvider; + +class CBaseTimebarlessRow : public CControl +{ +public: + CBaseTimebarlessRow(); + virtual ~CBaseTimebarlessRow(); + + void Draw(CRenderer *inRenderer) override; + + virtual void SetBackgroundColor(::CColor inColor); + virtual void SetTimeRatio(double inTimeRatio); + + virtual void RefreshRowMetaData(); + + virtual void OnSelect(); + virtual void OnDeselect(); + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + virtual void SetDirty(bool inIsDirty); + virtual void UpdateTime(long inStartTime, long inEndTime); + + virtual void CommitSelections() = 0; + virtual void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) = 0; + virtual void SelectAllKeys() = 0; + virtual void SelectKeysByTime(long inTime, bool inSelected) = 0; + virtual void PopulateSnappingList(CSnapper *inSnappingList) = 0; + virtual ISnappingListProvider &GetSnappingListProvider() const = 0; + +protected: + virtual CBaseStateRow *GetBaseStateRow() const = 0; + + ::CColor m_BackgroundColor; + bool m_Selected; + bool m_DirtyFlag; + double m_TimeRatio; +}; +#endif // INCLUDED_BASE_TIMEBARLESS_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp new file mode 100644 index 00000000..3221f6a1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "Renderer.h" +#include "ToggleButton.h" +#include "BaseStateRow.h" +#include "StudioPreferences.h" +#include "TimelineDropTarget.h" +#include "BaseTimelineTreeControl.h" +#include "NameEdit.h" +#include "Bindings/ITimelineItem.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Create a new tree control for the specified state row. + * This control contains the toggle button and item name controls. + * @param inStateRow the state row of which this belongs to. + */ +CBaseTimelineTreeControl::CBaseTimelineTreeControl(CBaseStateRow *inStateRow, bool inMaster) + : m_Selected(false) + , m_MouseDown(false) +{ + m_StateRow = inStateRow; + + m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(m_StateRow->GetObjectType()); + + // Create the expand/collapse button. + m_ExpandButton = new CToggleButton(); + m_ExpandButton->SetUpImage("arrow.png"); + m_ExpandButton->SetDownImage("arrow_down.png"); + + // Add the button and initialize all the listeners for the events on it. + AddChild(m_ExpandButton); + m_ExpandButton->SigToggle.connect(std::bind(&CBaseStateRow::ToggleExpansion, m_StateRow, + std::placeholders::_1, std::placeholders::_2)); + m_ExpandButton->SetVisible(false); + + m_Icon = new CSIcon(m_StateRow->GetIcon(), m_StateRow->GetDisabledIcon()); + AddChild(m_Icon); + + // Create and add the name label. + m_Text = nullptr; // withdrawn from constructor to delay creation of text object + + // Initialize all the component's positions to 0. + SetIndent(CStudioPreferences::GetRowSize()); + + SetMinimumSize(CPt(CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Icon->GetPosition().x + + m_Icon->GetSize().x + 5, + CStudioPreferences::GetRowSize())); + + m_TrackingPoint.x = 0; + m_TrackingPoint.y = 0; + m_DrawAcceptBefore = false; + m_DrawAcceptAfter = false; + + // Set up default text colors + m_NormalTextColor = CStudioPreferences::GetNormalColor(); + m_SelectedTextColor = CStudioPreferences::GetNormalColor(); + if (inMaster) { + m_NormalTextColor = CStudioPreferences::GetMasterColor(); + m_SelectedTextColor = CStudioPreferences::GetMasterColor(); + } + m_LockedTextColor = CStudioPreferences::GetLockedTextColor(); +} + +CBaseTimelineTreeControl::~CBaseTimelineTreeControl() +{ + delete m_Icon; + delete m_ExpandButton; + delete m_Text; +} + +//============================================================================= +/** + * Create a new text object. For performance reasons we delay + * creating this object until it is needed, i.e. until the row is exposed + * by the user and the Draw method is called + */ +void CBaseTimelineTreeControl::CreateText() +{ + if (!m_Text) { + ITimelineItem *theTimelineItem = m_StateRow->GetTimelineItem(); + + m_Text = new CNameEdit(theTimelineItem); + + m_Text->SetSize( + CPt(CStudioPreferences::GetTimelineNameSize(), + CStudioPreferences::GetRowSize() - 3)); /* m_ExpandButton->GetSize( ).y - 3*/ + // m_Text->SetBGColorNoFocus( CStudioPreferences::GetNormalColor( ) ); + // if ( theTimelineItem->IsMaster( ) ) + // m_Text->SetBGColorNoFocus( CStudioPreferences::GetMasterColor( ) ); + // m_Text->SetFillBackground( false ); + m_Text->SetBoldText(false); + + // If the object is the scene, you can't edit it's name + m_Text->SetEditable(m_StateRow->GetObjectType() != OBJTYPE_SCENE); + AddChild(m_Text); + m_Text->SetPosition(CPt(m_Icon->GetPosition().x + m_Icon->GetSize().x + 5, 1)); + + // This was disabled before Text was created. + if (!IsEnabled()) { + m_Text->SetEnabled(false); + m_Text->SetParentEnabled(false); + m_Text->SetTextColor(m_LockedTextColor); + } else // since we do delay-creation, "sync" with the parent's selection state + UpdateTextSelection(); + + // This is so that make the timeline scrollbar scrolls correctly + // ( i.e. to the end of the asset name ) + CPt theSize(GetSize()); + theSize.x = + CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Text->GetPosition().x + m_Text->GetSize().x; + SetAbsoluteSize(theSize); + } +} + +void CBaseTimelineTreeControl::UpdateTextSelection() +{ + // since we do delay-creation for the Text only when we have to draw it.. this checks if it is + // created first + if (m_Text) { + if (!IsEnabled()) + m_Text->SetTextColor(m_LockedTextColor); + else + m_Text->SetTextColor(m_Selected ? m_SelectedTextColor : m_NormalTextColor); + // m_Text->SetFillBackground( m_Selected ); + // m_Text->SetBoldText( m_Selected ); + } +} + +//============================================================================= +/** + * Perform the drawing of this control. + * @param inRenderer the renderer to draw to. + */ +void CBaseTimelineTreeControl::Draw(CRenderer *inRenderer) +{ + CreateText(); // the row is now exposed and we can't delay creating the text object any longer + + CRct theRect(GetSize()); + // Fill in the background + if (!m_Selected) + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + else + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor()); + + // if ( m_Text ) + // m_Text->SetBoldText( m_Selected ); + // m_Text->SetFillBackground( m_Selected ); + + // Draw the line at the bottom of this control + inRenderer->PushPen(CStudioPreferences::GetTreeFloorColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Override for the set parent enabled function which tells children the state of the parent + */ +void CBaseTimelineTreeControl::SetEnabled(bool inIsEnabled) +{ + CControl::SetEnabled(inIsEnabled); + if (m_Text) { + m_Text->SetEnabled(inIsEnabled); + if (!inIsEnabled) + m_Text->SetTextColor(m_LockedTextColor); + else + m_Text->SetTextColor(m_Selected ? m_SelectedTextColor : m_NormalTextColor); + Invalidate(); + } +} + +//============================================================================= +/** + * Notification that something has changed on the asset that this + * represents, update it. + */ +void CBaseTimelineTreeControl::Refresh(ITimelineItem *inTimelineItem) +{ + bool theEnabled = !inTimelineItem->IsLocked(); + if (m_Text) { + // Make sure the color is correct depending on if its is a master object + if (m_NormalTextColor != CStudioPreferences::GetMasterColor() + && inTimelineItem->IsMaster()) { + m_NormalTextColor = CStudioPreferences::GetMasterColor(); + m_Text->SetBGColorNoFocus(CStudioPreferences::GetMasterColor()); + if (!m_Selected) + m_Text->SetTextColor(m_NormalTextColor); + } + + m_Text->SetData(inTimelineItem->GetName()); + } + m_Icon->SetImage((theEnabled) ? m_StateRow->GetIcon() : m_StateRow->GetDisabledIcon()); + SetEnabled(theEnabled); +} + +//============================================================================= +/** + * Set the indent of this control. + * The indent gives the semblance of a tree control, and causes the toggle + * name and icon to be pushed in some. + * @param inIndent the indent for this control. + */ +void CBaseTimelineTreeControl::SetIndent(long inIndent) +{ + m_Indent = inIndent; + + // Set the new position for all the children. + m_ExpandButton->SetPosition(CPt(inIndent, 0)); + + m_Icon->SetPosition(CPt(m_ExpandButton->GetPosition().x + m_ExpandButton->GetSize().x, 0)); + if (m_Text) + m_Text->SetPosition(CPt(m_Icon->GetPosition().x + m_Icon->GetSize().x + 5, 1)); +} + +//============================================================================= +/** + * Get the current indent of this control. + */ +long CBaseTimelineTreeControl::GetIndent() +{ + return m_Indent; +} + +//============================================================================= +/** + * Set whether or not to have the toggle control visible. + * The toggle is turned off by the state row when there are no visible children. + * @param inIsToggleVisible false if the toggle is not to be visible. + */ +void CBaseTimelineTreeControl::SetToggleVisible(bool inIsToggleVisible) +{ + m_ExpandButton->SetVisible(inIsToggleVisible); +} + +//============================================================================= +/** + * Set whether or not this control is expanded. + * This is used to set the state of the expand button. + */ +void CBaseTimelineTreeControl::SetExpanded(bool inIsExpanded) +{ + m_ExpandButton->SetToggleState(inIsExpanded); +} + +//============================================================================= +/** + * Set the current background color for this control. + * The background color changes when the control gets a mouse over/mouse out. + */ +void CBaseTimelineTreeControl::SetBackgroundColor(CColor inColor) +{ + if (m_BackgroundColor == inColor) + return; + + m_BackgroundColor = inColor; + + Invalidate(); +} + +//============================================================================= +/** + * Notify the row that a mouse out occurred. + * The row will in turn turn off the highlighting. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CBaseTimelineTreeControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_DrawAcceptAfter = false; + m_DrawAcceptBefore = false; + + CControl::OnMouseOut(inPoint, inFlags); + + m_StateRow->OnMouseOut(); + + if (m_TimerHandler) { + + // nullptr out our handle so we can create a new one. + m_TimerHandler = std::shared_ptr<UICDM::ISignalConnection>(); + } + + AcceptDropAfter(false); + AcceptDropBefore(false); +} + +//============================================================================= +/** + * Notify the row that a mouse over occurred. + * The row will in turn turn on the highlighting. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CBaseTimelineTreeControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + m_StateRow->OnMouseOver(); +} + +//============================================================================= +/** + * Pass the double click notification on to the row and have it process it. + * The row will do object-specific actions on doubleclicks. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + * @return true stating that the event was processed. + */ +bool CBaseTimelineTreeControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDoubleClick(inPoint, inFlags)) { + m_StateRow->OnMouseDoubleClick(inPoint, inFlags); + GrabFocus(nullptr); + } + return true; +} + +//============================================================================= +/** + * Handles mouse down on the this control. Flags the button as down which results + * in some possible drawing changes. + * @param inPoint location of the mouse when event occurred + * @param inFlags state of modifier keys when event occurred + * @return true + */ +bool CBaseTimelineTreeControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + SBaseStateRowSelectionKeyState theKeyState; + if ((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT) + theKeyState.SetShiftDown(); + if ((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL) + theKeyState.SetControlDown(); + m_StateRow->Select(theKeyState); + + // Always track where the mouse is. + m_MouseDown = true; + + Invalidate(); + } + + return true; +} + +bool CBaseTimelineTreeControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseRDown(inPoint, inFlags)) + m_StateRow->OnMouseRDown(inPoint, inFlags); + + return true; +} + +void CBaseTimelineTreeControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_MouseDown = false; + + CControl::OnMouseUp(inPoint, inFlags); + + AcceptDropAfter(false); + AcceptDropBefore(false); +} + +//============================================================================= +/** + * This method handles the keydown event for a StateTreeControl. It calls + * CControl::OnKeyDown method to make sure that the keydown event is handled + * by its children. If the keydown event is not handled and F2 is down, it + * enables text edit mode. + * @param inChar is the char pressed + * @param inFlags state of modifier keys when event occurred + * @return if the key was handled + */ +bool CBaseTimelineTreeControl::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool theKeyWasHandled = CControl::OnKeyDown(inChar, inFlags); + + if (!theKeyWasHandled && (inChar == Qt::Key_F2)) { + DoRename(); + theKeyWasHandled = true; + } + + return theKeyWasHandled; +} + +//============================================================================= +/** + * This is so the Gesture can this object to get something ready to Drag. + */ +void CBaseTimelineTreeControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + if (m_MouseDown /*&& inFlags & MOUSE_LBUTTON*/) { + long theDeltaX = inPoint.x - m_TrackingPoint.x; + long theDeltaY = inPoint.y - m_TrackingPoint.y; + + if (::abs(theDeltaX) > 3 || ::abs(theDeltaY) > 3) { + m_TrackingPoint = inPoint; + + m_StateRow->DoStartDrag(GetWindowListener()); + } + } +} + +//============================================================================= +/** + * Notification that the state that this is displaying has been selected. + */ +void CBaseTimelineTreeControl::OnSelect() +{ + m_Selected = true; + + UpdateTextSelection(); + + Invalidate(); +} + +//============================================================================= +/** + * Notification that the state that this is displaying has been deselected. + */ +void CBaseTimelineTreeControl::OnDeselect() +{ + m_Selected = false; + + UpdateTextSelection(); + Invalidate(); +} + +void CBaseTimelineTreeControl::GrabTextFocus() +{ + GrabFocus(m_Text); +} + +//============================================================================= +/** + * To enable F2 editing. + */ +void CBaseTimelineTreeControl::OnGainFocus() +{ + CControl::OnGainFocus(); + GrabFocus(m_Text); +} + +//============================================================================= +/** + * Called when this control loses focus. Overridden because we need to set the + * text color depending on whether or not the asset for this row is still + * selected. + */ +void CBaseTimelineTreeControl::OnLoseFocus() +{ + CControl::OnLoseFocus(); + + if (m_Text) { + if (m_Selected) { + m_Text->SetTextColor(m_SelectedTextColor); + } else // If this asset is no longer selected + { + // If the row is enabled, use the normal text color + if (m_Text->IsEnabled()) { + m_Text->SetTextColor(m_NormalTextColor); + } + // Otherwise use the locked text color + else { + m_Text->SetTextColor(m_LockedTextColor); + } + } + } + + AcceptDropAfter(false); + AcceptDropBefore(false); +} + +//============================================================================= +/** + * If the name is changed, the size has to be adjusted accordingly. + */ +void CBaseTimelineTreeControl::OnChildSizeChanged(CControl *inChild) +{ + CControl::OnChildSizeChanged(inChild); + + if (inChild == m_Text) { // This is so that make the timeline scrollbar scrolls correctly + // ( i.e. to the end of the asset name ) + CPt theSize(GetSize()); + theSize.x = + CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Text->GetPosition().x + m_Text->GetSize().x; + SetAbsoluteSize(theSize); + } +} + +//============================================================================= +/** + * This will do a vertical hit test on this control. + * This need to figure out if the point is toward teh top or toward the bottom, or on this + *control. + * @param inMousePoint the point where the dropp wants to occure. + * @return An enumeration representing the location of the potential drop. + */ +CBaseTimelineTreeControl::ECONTROLREGION CBaseTimelineTreeControl::FindHitRegion(CPt &inMousePoint) +{ + // Default Region is "on" + CBaseTimelineTreeControl::ECONTROLREGION theDropRegion = + CBaseTimelineTreeControl::ECONTROLREGION_ON; + + CPt theSize = GetSize(); + long theTop = 0; + long theBottom = theSize.y - 1; + long thePointY = inMousePoint.y; + + // check if we are in the upper part of the control + if ((thePointY >= theTop) && (thePointY <= (theTop + 3))) { + theDropRegion = CBaseTimelineTreeControl::ECONTROLREGION_ABOVE; + } + // check if we are in the lower part of the control + else if ((thePointY <= (theBottom)) && (thePointY >= (theBottom - 3))) { + theDropRegion = CBaseTimelineTreeControl::ECONTROLREGION_BELOW; + } + + return theDropRegion; +} + +//============================================================================= +/** + * Find an object under the point. + * If tht point is close to the top or the bottom of the control, + * then the Asset to use would be the parent of the current asset. + * @param inMousePoint the point where the Drop wants to occure. + */ +CDropTarget *CBaseTimelineTreeControl::BuildDropTarget(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inFlags); + + // This will do the hit testing to see where we are with the point. + ECONTROLREGION theRegion = FindHitRegion(inMousePoint); + + // Make a new DropTarget to return. + CTimeLineDropTarget *theTarget = new CTimeLineDropTarget(); + + EDROPDESTINATION theDropDest = EDROPDESTINATION_ON; + + switch (theRegion) { + case ECONTROLREGION_BELOW: + theDropDest = EDROPDESTINATION_BELOW; + + AcceptDropAfter(true); + AcceptDropBefore(false); + break; + + case ECONTROLREGION_ABOVE: + theDropDest = EDROPDESTINATION_ABOVE; + + AcceptDropAfter(false); + AcceptDropBefore(true); + break; + + case ECONTROLREGION_ON: + + AcceptDropAfter(false); + AcceptDropBefore(false); + break; + } + theTarget->SetDestination(theDropDest); + // For insertion markers + theTarget->SetInsertionMarkerRow(this); + theTarget->SetInsertionMarkerIndent(m_Icon->GetPosition().x); + + // connect the data portion of the drag&drop action + m_StateRow->SetDropTarget(theTarget); + + return theTarget; +} + +//============================================================================= +/** + * This function is overriden from the CControl class. + * It will find an Asset that can be dropped upon. Also it will + * figureout if the DropTarget should contain this Asset or the parent + * of this Asset. + * @param inMousePoint the coords [in local space] of the drop action. + * @param inFlags the Modifier flags for the keyboard state. + * @return the found DropTarget or null if not found. + */ +CDropTarget *CBaseTimelineTreeControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + // Make sure the Mouse Highlighting happens. + m_StateRow->OnMouseOver(); + + // This will do all of the work. + CDropTarget *theReturnTarget = BuildDropTarget(inMousePoint, inFlags); + + // Expand the object [ once again ask CE for an explaination of this ] + if (!m_TimerHandler && m_ExpandButton->IsVisible() && m_ExpandButton->IsEnabled()) { + if (!m_DrawAcceptBefore && !m_DrawAcceptAfter) + m_TimerHandler = Q3DStudio::ITickTock::GetInstance().AddTimer( + 1000, false, std::bind(&CBaseTimelineTreeControl::OnTimer, this), + "CStateTreeControl::FindDropCandidate::" + GetName()); + } + + // we always return true, since we should be the only one to handle it. + return theReturnTarget; +} + +//============================================================================= +/** + * Notification that the Hover Time has expired, + */ +void CBaseTimelineTreeControl::OnTimer() +{ + // Expand the Row to show the children. + m_StateRow->Expand(); +} + +//============================================================================= +/** + * This will set the Flag so we can Draw the Bottom Line. + * @param inAccept true to draw the line false otherwise. + */ +void CBaseTimelineTreeControl::AcceptDropAfter(bool inAccept) +{ + if (inAccept != m_DrawAcceptAfter) { + m_DrawAcceptAfter = inAccept; + } +} + +//============================================================================= +/** + * This will set the Flag so we can Draw the Top Line. + * @param inAccept true to draw the line false otherwise. + */ +void CBaseTimelineTreeControl::AcceptDropBefore(bool inAccept) +{ + if (inAccept != m_DrawAcceptBefore) { + m_DrawAcceptBefore = inAccept; + } +} + +//============================================================================= +/** + * Called by the state context menu to do the renaming portion of the menu + */ +void CBaseTimelineTreeControl::DoRename() +{ + CreateText(); + m_Text->SetEditMode(true); + GrabFocus(m_Text); + m_Text->SelectAllText(); +} + +void CBaseTimelineTreeControl::SetNameReadOnly(bool inReadOnly) +{ + CreateText(); // Create the text if it's not ready. + m_Text->SetEditable(!inReadOnly); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h new file mode 100644 index 00000000..e348cccf --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_BASE_TIMELINE_TREE_CONTROL_H +#define INCLUDED_BASE_TIMELINE_TREE_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "SIcon.h" +#include "ToggleButton.h" +#include "ITickTock.h" + +class CButtonControl; +class CBaseStateRow; +class CDropTarget; +class CNameEdit; +class CTickTockProc; +struct STickTockHandle; +class CPt; +class CToggleButton; +class ITimelineItem; + +class CBaseTimelineTreeControl : public CControl +{ + +public: + enum ECONTROLREGION { ECONTROLREGION_ON, ECONTROLREGION_ABOVE, ECONTROLREGION_BELOW }; + + CBaseTimelineTreeControl(CBaseStateRow *inStateRow, bool inMaster); + virtual ~CBaseTimelineTreeControl(); + + void Draw(CRenderer *inRenderer) override; + void OnChildSizeChanged(CControl *inChild) override; + + void SetIndent(long inIndent); + long GetIndent(); + + void SetExpanded(bool inIsExpanded); + + void SetToggleVisible(bool inIsToggleVisible); + void OnSelect(); + void OnDeselect(); + void GrabTextFocus(); + void OnGainFocus() override; + void OnLoseFocus() override; + void SetBackgroundColor(::CColor inBackgroundColor); + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) override; + + void OnTimer(); + + void Refresh(ITimelineItem *inTimelineItem); + + void SetEnabled(bool inIsEnabled) override; + + CDropTarget *BuildDropTarget(CPt &inMousePoint, Qt::KeyboardModifiers inFlags); + CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override; + void AcceptDropAfter(bool inAccept); + void AcceptDropBefore(bool inAccept); + void DoRename(); + + void SetNameReadOnly(bool inReadOnly); + +protected: + ECONTROLREGION FindHitRegion(CPt &inMousePoint); + void CreateText(); // delay text creation until row is exposed + void UpdateTextSelection(); + + long m_Indent; + + CBaseStateRow *m_StateRow; + + CToggleButton *m_ExpandButton; + CNameEdit *m_Text; + + CSIcon *m_Icon; + bool m_Selected; + + ::CColor m_BackgroundColor; + + CPt m_TrackingPoint; + CPt m_MouseMovePoint; + bool m_MouseDown; + bool m_DrawAcceptBefore; + bool m_DrawAcceptAfter; + std::shared_ptr<UICDM::ISignalConnection> m_TimerHandler; + ::CColor m_NormalTextColor; + ::CColor m_SelectedTextColor; + ::CColor m_LockedTextColor; +}; +#endif // INCLUDED_BASE_TIMELINE_TREE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp new file mode 100644 index 00000000..196d345d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "BehaviorTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "StudioApp.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "Doc.h" + +using namespace UICDM; + +CBehaviorTimelineItemBinding::CBehaviorTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ +} + +EStudioObjectType CBehaviorTimelineItemBinding::GetObjectType() const +{ + return OBJTYPE_BEHAVIOR; +} + +//============================================================================= +/** + * Open the associated item as though it was double-clicked in explorer + */ +bool CBehaviorTimelineItemBinding::OpenAssociatedEditor() +{ + return OpenSourcePathFile(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h new file mode 100644 index 00000000..b75d100c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H +#define INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; + +//============================================================================= +/** + * Binding to a UICDM object of Behavior type + */ +class CBehaviorTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: + CBehaviorTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + ~CBehaviorTimelineItemBinding() {} + + // CUICDMTimelineItemBinding + EStudioObjectType GetObjectType() const override; + bool OpenAssociatedEditor() override; +}; + +#endif // INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp new file mode 100644 index 00000000..7534fa73 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "EmptyTimelineTimebar.h" +#include "StudioPreferences.h" + +CEmptyTimelineTimebar::CEmptyTimelineTimebar() +{ +} + +CEmptyTimelineTimebar::~CEmptyTimelineTimebar() +{ +} + +long CEmptyTimelineTimebar::GetStartTime() const +{ + return 0; +} + +long CEmptyTimelineTimebar::GetEndTime() const +{ + return 0; +} + +long CEmptyTimelineTimebar::GetDuration() const +{ + return 0; +} + +bool CEmptyTimelineTimebar::ShowHandleBars() const +{ // makes no sense to show handle bars, when this does not have start/end times. + return false; +} + +void CEmptyTimelineTimebar::OnBeginDrag() +{ +} + +void CEmptyTimelineTimebar::OffsetTime(long inDiff) +{ + Q_UNUSED(inDiff); +} + +void CEmptyTimelineTimebar::ChangeTime(long inTime, bool inSetStart) +{ + Q_UNUSED(inTime); + Q_UNUSED(inSetStart); +} + +void CEmptyTimelineTimebar::CommitTimeChange() +{ +} + +void CEmptyTimelineTimebar::RollbackTimeChange() +{ +} + +::CColor CEmptyTimelineTimebar::GetTimebarColor() +{ + return CStudioPreferences::GetObjectTimebarColor(); +} + +void CEmptyTimelineTimebar::SetTimebarColor(const ::CColor &inColor) +{ + Q_UNUSED(inColor); +} + +Q3DStudio::CString CEmptyTimelineTimebar::GetTimebarComment() +{ + return ""; +} + +void CEmptyTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComment) +{ + Q_UNUSED(inComment); +} + +void CEmptyTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/) +{ + Q_UNUSED(inCallback); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h new file mode 100644 index 00000000..9aacb524 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#pragma once + +#include "ITimelineTimebar.h" + +//============================================================================= +/** + * The current timeline UI design is such that even when no timebar shows up ( with the exception of + * the top row, ie the time context ) + * there is a timebar control to store the keyframes for the animated properties. + * Hence, instead of return nullptr for GetTimebar for ITimelineItem, this class will ensure the UI + * classes still work. + */ +class CEmptyTimelineTimebar : public ITimelineTimebar +{ +public: + CEmptyTimelineTimebar(); + virtual ~CEmptyTimelineTimebar(); + + // ITimelineTimebar + long GetStartTime() const override; + long GetEndTime() const override; + long GetDuration() const override; + bool ShowHandleBars() const override; + void OnBeginDrag() override; + void OffsetTime(long inDiff) override; + void ChangeTime(long inTime, bool inSetStart) override; + void CommitTimeChange() override; + void RollbackTimeChange() override; + ::CColor GetTimebarColor() override; + void SetTimebarColor(const ::CColor &inColor) override; + Q3DStudio::CString GetTimebarComment() override; + void SetTimebarComment(const Q3DStudio::CString &inComment) override; + void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) override; +}; diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp new file mode 100644 index 00000000..322cbd33 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "GroupTimelineItemBinding.h" +#include "BaseStateRow.h" +#include "TimelineTranslationManager.h" +#include "StudioApp.h" +#include "Core.h" +#include "Dialogs.h" + +// Data model specific +#include "Doc.h" +#include "CmdGeneric.h" + +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMSlides.h" +#include "UICDMDataCore.h" +#include "UICFileTools.h" + +using namespace UICDM; + +CGroupTimelineItemBinding::CGroupTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ +} + +//============================================================================= +/** + * Ideally we like to be able to edit the component in a different editor ( we've been hoping for + * that feature ) BUT we don't have that, + * and it has always been we 'dive' into the component within Studio. + */ +bool CGroupTimelineItemBinding::OpenAssociatedEditor() +{ + if (GetObjectType() == OBJTYPE_COMPONENT) { + ISlideSystem *theSlideSystem = m_StudioSystem->GetSlideSystem(); + + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + Q3DStudio::CId theId = m_StudioSystem->GetClientDataModelBridge()->GetGUID(theInstance); + UICDM::CUICDMSlideHandle theMasterSlide = + theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId)); + + if (theMasterSlide.Valid()) { + CUICDMSlideHandle theActiveSlide = theSlideSystem->GetActiveSlide(theMasterSlide); + + CCmd *theCmd = new CCmdGeneric<CDoc, CUICDMSlideHandle>( + m_TransMgr->GetDoc(), &CDoc::NotifyActiveSlideChanged, + &CDoc::NotifyActiveSlideChanged, theActiveSlide, NULL, ""); + theCmd->SetUndoable(false); + theCmd->SetModifiedFlag(false); + m_TransMgr->GetDoc()->GetCore()->ExecuteCommand(theCmd, false); + } + return true; + } + return false; +} + +bool CGroupTimelineItemBinding::IsImported() const +{ + + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetDoc()->GetStudioSystem()->GetPropertySystem(); + UICDM::SValue theValue; + if (thePropertySystem->GetInstancePropertyValue(theInstance, m_TransMgr->GetDoc() + ->GetStudioSystem() + ->GetClientDataModelBridge() + ->GetSourcePathProperty(), + theValue)) { + UICDM::TDataStrPtr theSrcPath(UICDM::get<UICDM::TDataStrPtr>(theValue)); + Q3DStudio::CFilePath theFilePath(theSrcPath->GetData()); + if (theFilePath.GetExtension() == CDialogs::GetWideImportFileExtension()) + return true; + } + // If it is, check to be sure that + // we can get to the import file. + // If we can, then we are imported. + return false; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h new file mode 100644 index 00000000..a9462c1c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_GROUP_TIMELINEITEM_BINDING_H +#define INCLUDED_GROUP_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" + +//============================================================================== +// Classes +//============================================================================== +class ITimelineItem; +class CTimelineTranslationManager; +class CBaseStateRow; + +//============================================================================= +/** + * Binding to a UICDM object of Group type + */ +class CGroupTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: + CGroupTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + ~CGroupTimelineItemBinding() {} + + // CUICDMTimelineItemBinding + bool OpenAssociatedEditor() override; + bool IsImported() const override; +}; + +#endif // INCLUDED_GROUP_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h new file mode 100644 index 00000000..db8b551f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_IKEYFRAME_SELECTOR_H +#define INCLUDED_IKEYFRAME_SELECTOR_H 1 + +#pragma once + +//============================================================================= +/** + * Interface that performs keyframe selection. + */ +//============================================================================= +class IKeyframeSelector +{ +public: + virtual ~IKeyframeSelector() {} + + //============================================================================= + /** + * @param inTime -1 to selected (or deselect) ALL keyframes, otherwise only by time. + */ + virtual void SelectKeyframes(bool inSelected, long inTime = -1) = 0; +}; + +#endif // INCLUDED_IKEYFRAME_SELECTOR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h new file mode 100644 index 00000000..e5af8671 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_ITIMELINE_ITEM_H +#define INCLUDED_ITIMELINE_ITEM_H 1 + +#pragma once + +#include "INamable.h" +#include "StudioObjectTypes.h" + +class ITimelineTimebar; + +//============================================================================= +/** + * Abstraction of a data model item in the Scene. This might end up deriving from a more generic + * interface, so that common + * functions can be generalized for items in the different palettes. + */ +//============================================================================= +class ITimelineItem : public INamable +{ +public: + virtual ~ITimelineItem() {} + + virtual EStudioObjectType GetObjectType() const = 0; + virtual bool IsMaster() const = 0; + + virtual bool IsShy() const = 0; + virtual void SetShy(bool) = 0; + virtual bool IsLocked() const = 0; + virtual void SetLocked(bool) = 0; + virtual bool IsVisible() const = 0; + virtual void SetVisible(bool) = 0; + virtual bool IsExpanded() const = 0; + virtual void SetExpanded(bool) = 0; + virtual bool IsImported() const { return false; } + + // Actions + virtual bool HasAction(bool inMaster) = 0; + virtual bool ChildrenHasAction(bool inMaster) = 0; + virtual bool ComponentHasAction(bool inMaster) = 0; + + virtual ITimelineTimebar *GetTimebar() = 0; +}; + +#endif // INCLUDED_ITIMELINE_ITEM_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h new file mode 100644 index 00000000..d251f530 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_ITIMELINE_ITEM_BINDINGS_H +#define INCLUDED_ITIMELINE_ITEM_BINDINGS_H 1 + +#pragma once + +#include "ITimelineItem.h" +#include "ITimelineItemProperty.h" +#include "IKeyframeSelector.h" +#include "SIterator.h" + +class CBaseStateRow; +class CControlWindowListener; +class ITimelineKeyframesManager; + +// Data model specific ?? +class CDropTarget; + +class ITimelineItemKeyframesHolder +{ +public: + virtual ~ITimelineItemKeyframesHolder() {} + + virtual void InsertKeyframe() = 0; + virtual void DeleteAllChannelKeyframes() = 0; + virtual long GetKeyframeCount() const = 0; + virtual IKeyframe *GetKeyframeByTime(long inTime) const = 0; + virtual IKeyframe *GetKeyframeByIndex(long inIndex) const = 0; + virtual long OffsetSelectedKeyframes(long inOffset) = 0; + virtual void CommitChangedKeyframes() = 0; + virtual void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) = 0; +}; + +//============================================================================= +/** + * Interface to encapsulate data model specific functions, that Timeline UI objects can talk to. + */ +//============================================================================= +class ITimelineItemBinding : public ITimelineItemKeyframesHolder, public IKeyframeSelector +{ +public: + // List of possible transactions that requires querying the data model if they are valid + enum EUserTransaction { + EUserTransaction_None, + EUserTransaction_Rename, + EUserTransaction_Duplicate, + EUserTransaction_Cut, + EUserTransaction_Copy, + EUserTransaction_Paste, + EUserTransaction_Delete, + EUserTransaction_MakeComponent, + EUserTransaction_EditComponent, + }; + +public: + virtual ~ITimelineItemBinding() {} + + virtual ITimelineItem *GetTimelineItem() = 0; + virtual CBaseStateRow *GetRow() = 0; + + // Events + virtual void SetSelected(bool multiSelect) = 0; + virtual void OnCollapsed() = 0; + virtual void ClearKeySelection() = 0; + virtual bool OpenAssociatedEditor() = 0; + virtual void DoStartDrag(CControlWindowListener *inWndListener) = 0; + virtual void SetDropTarget(CDropTarget *inTarget) = 0; + + // Hierarchy + virtual long GetChildrenCount() = 0; + virtual ITimelineItemBinding *GetChild(long inIndex) = 0; + virtual ITimelineItemBinding *GetParent() = 0; + virtual void SetParent(ITimelineItemBinding *parent) = 0; + // Properties + virtual long GetPropertyCount() = 0; + virtual ITimelineItemProperty *GetProperty(long inIndex) = 0; + + // Eye/Lock toggles + virtual bool ShowToggleControls() const = 0; + virtual bool IsLockedEnabled() const = 0; + virtual bool IsVisibleEnabled() const = 0; + + // Init/Cleanup + virtual void Bind(CBaseStateRow *inRow) = 0; + virtual void Release() = 0; + + // ContextMenu + virtual bool IsValidTransaction(EUserTransaction inTransaction) = 0; + virtual void PerformTransaction(EUserTransaction inTransaction) = 0; + virtual Q3DStudio::CString GetObjectPath() = 0; + + virtual bool IsExternalizeable() { return false; } + virtual void Externalize() {} + virtual bool IsInternalizeable() { return false; } + virtual void Internalize() {} + + // Selected keyframes + virtual ITimelineKeyframesManager *GetKeyframesManager() const = 0; + + // Properties + virtual void RemoveProperty(ITimelineItemProperty *inProperty) = 0; + virtual void LoadProperties() = 0; +}; + +//============================================================================= +/** + * Helper iterator class that iterates over a ITimeline's children in a ordered (priority) list. + */ +//============================================================================= +class CTimelineItemOrderedIterator : public CSIterator<ITimelineItemBinding *> +{ +public: + CTimelineItemOrderedIterator(ITimelineItemBinding *inRootTimelineItem) + { + m_RootTimelineItem = inRootTimelineItem; + Reset(); + } + bool IsDone() override { return (m_Index >= m_Total); } + void operator++() override { m_Index++; } + void operator+=(const long inNumToInc) override { m_Index += inNumToInc; } + ITimelineItemBinding *GetCurrent() override { return m_RootTimelineItem->GetChild(m_Index); } + virtual void Reset() + { + m_Index = 0; + m_Total = m_RootTimelineItem->GetChildrenCount(); + } + +protected: + ITimelineItemBinding *m_RootTimelineItem; + long m_Index; + long m_Total; +}; + +//============================================================================= +/** + * Helper iterator class that iterates over a ITimeline's properties + */ +//============================================================================= +class CTimelineItemPropertyIterator : public CSIterator<ITimelineItemProperty *> +{ +public: + CTimelineItemPropertyIterator(ITimelineItemBinding *inTimelineItem) + { + m_TimelineItem = inTimelineItem; + Reset(); + } + bool IsDone() override { return (m_Index >= m_Total); } + void operator++() override { m_Index++; } + void operator+=(const long inNumToInc) override { m_Index += inNumToInc; } + ITimelineItemProperty *GetCurrent() override { return m_TimelineItem->GetProperty(m_Index); } + virtual void Reset() + { + m_Index = 0; + m_Total = m_TimelineItem->GetPropertyCount(); + } + +protected: + ITimelineItemBinding *m_TimelineItem; + long m_Index; + long m_Total; +}; + +#endif // INCLUDED_ITIMELINE_ITEM_BINDINGS_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h new file mode 100644 index 00000000..c241ebfa --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_ITIMELINE_ITEM_PROPERTY_H +#define INCLUDED_ITIMELINE_ITEM_PROPERTY_H 1 + +#pragma once + +#include "IKeyframeSelector.h" +#include "UICDMMetaData.h" +#include "UICString.h" + +class CPropertyRow; +class IKeyframe; +class ITimelineKeyframesManager; + +//============================================================================= +/** + * Abstraction of a data model item's property that is displayed in the Timeline. + */ +//============================================================================= +class ITimelineItemProperty : public IKeyframeSelector +{ +public: + virtual ~ITimelineItemProperty() {} + + virtual Q3DStudio::CString GetName() const = 0; + virtual bool IsMaster() const = 0; + virtual UICDM::TDataTypePair GetType() const = 0; + virtual float GetMaximumValue() const = 0; + virtual float GetMinimumValue() const = 0; + + virtual void SetSelected() = 0; + virtual void ClearKeySelection() = 0; + virtual void DeleteAllKeys() = 0; + + virtual void Bind(CPropertyRow *inRow) = 0; + virtual void Release() = 0; + virtual CPropertyRow *GetRow() = 0; + + // Keyframes + virtual ITimelineKeyframesManager *GetKeyframesManager() const = 0; + virtual IKeyframe *GetKeyframeByTime(long inTime) const = 0; + virtual IKeyframe *GetKeyframeByIndex(long inIndex) const = 0; + virtual long GetKeyframeCount() const = 0; + virtual long GetChannelCount() const = 0; + virtual float GetChannelValueAtTime(long inChannelIndex, long inTime) = 0; + virtual void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) = 0; + virtual long OffsetSelectedKeyframes(long inOffset) = 0; + virtual void CommitChangedKeyframes() = 0; + virtual void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) = 0; + virtual bool IsDynamicAnimation() = 0; +}; + +#endif // INCLUDED_ITIMELINE_ITEM_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h new file mode 100644 index 00000000..e1a6914f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_ITIMELINE_KEYFRAMES_MANAGER_H +#define INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H 1 + +#pragma once + +#include "IKeyframesManager.h" + +//============================================================================= +/** + * Interface to manage keyframes related actions in the Timeline + */ +//============================================================================= +class ITimelineKeyframesManager : public IKeyframesManager +{ +public: + virtual ~ITimelineKeyframesManager() {} + + virtual void SetKeyframeTime(long inTime) = 0; + virtual void SetKeyframesDynamic(bool inDynamic) = 0; + virtual long OffsetSelectedKeyframes(long inOffset) = 0; + virtual bool CanMakeSelectedKeyframesDynamic() = 0; + virtual void CommitChangedKeyframes() = 0; + virtual void RollbackChangedKeyframes() = 0; +}; + +#endif // INCLUDED_IKEYFRAMES_MANAGER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h new file mode 100644 index 00000000..dbeefb85 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_ITIMELINE_TIMEBAR_H +#define INCLUDED_ITIMELINE_TIMEBAR_H 1 + +#pragma once + +#include "UICString.h" + +class ITimeChangeCallback; + +class CColor; + +//============================================================================= +/** + * Interface for a Timebar + */ +//============================================================================= +class ITimelineTimebar +{ +public: + virtual ~ITimelineTimebar() {} + + virtual long GetStartTime() const = 0; + virtual long GetEndTime() const = 0; + virtual long GetDuration() const = 0; + virtual bool ShowHandleBars() const = 0; + //============================================================================= + /** + * TODO: consider refactor. drag&drop specfics should not be in the Data Model. + */ + virtual void OnBeginDrag() = 0; + // + virtual void OffsetTime(long inDiff) = 0; + // Change the start time or the end time of the timebar. inTime: time to change to, inSetStart: + // true to set start time, false to set end time. + virtual void ChangeTime(long inTime, bool inSetStart) = 0; + virtual void CommitTimeChange() = 0; + virtual void RollbackTimeChange() = 0; + // + virtual CColor GetTimebarColor() = 0; + virtual void SetTimebarColor(const CColor &inColor) = 0; + virtual Q3DStudio::CString GetTimebarComment() = 0; + virtual void SetTimebarComment(const Q3DStudio::CString &inComment) = 0; + virtual void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) = 0; +}; + +#endif // INCLUDED_ITIMELINE_TIMEBAR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp new file mode 100644 index 00000000..bf41f00d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ImageTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "UICDMHandles.h" +#include "BaseStateRow.h" +#include "Doc.h" +#include "IObjectReferenceHelper.h" +#include "EmptyTimelineTimebar.h" + +using namespace UICDM; + +CImageTimelineItemBinding::CImageTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ +} + +CImageTimelineItemBinding::~CImageTimelineItemBinding() +{ +} + +ITimelineTimebar *CImageTimelineItemBinding::GetTimebar() +{ // No timebars on images + return new CEmptyTimelineTimebar(); +} + +Q3DStudio::CString CImageTimelineItemBinding::GetName() const +{ + return m_Name; +} + +void CImageTimelineItemBinding::SetName(const Q3DStudio::CString &inName) +{ + m_Name = inName; +} + +EStudioObjectType CImageTimelineItemBinding::GetObjectType() const +{ + return OBJTYPE_IMAGE; +} + +bool CImageTimelineItemBinding::ShowToggleControls() const +{ + // no toggle controls, by design + return false; +} + +void CImageTimelineItemBinding::Bind(CBaseStateRow *inRow) +{ + CUICDMTimelineItemBinding::Bind(inRow); + GetRow()->SetNameReadOnly(true); +} + +//============================================================================= +/** + * Open the associated item as though it was double-clicked in explorer + */ +bool CImageTimelineItemBinding::OpenAssociatedEditor() +{ + return OpenSourcePathFile(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h new file mode 100644 index 00000000..2c27dd2d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_IMAGE_TIMELINEITEM_BINDING_H +#define INCLUDED_IMAGE_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; +class CBaseStateRow; +class ITimelineTimebar; + +//============================================================================= +/** + * Binding to a UICDM object of Image type + */ +class CImageTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: + CImageTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + virtual ~CImageTimelineItemBinding(); + + // CUICDMTimelineItemBinding + ITimelineTimebar *GetTimebar() override; + Q3DStudio::CString GetName() const override; + void SetName(const Q3DStudio::CString &inName) override; + EStudioObjectType GetObjectType() const override; + bool ShowToggleControls() const override; + void Bind(CBaseStateRow *inRow) override; + bool OpenAssociatedEditor() override; + + void SetPropertyHandle(UICDM::CUICDMPropertyHandle inProperty) + { + m_PropertyHandle = inProperty; + } + UICDM::CUICDMPropertyHandle GetPropertyHandle() const { return m_PropertyHandle; } + +protected: + Q3DStudio::CString m_Name; + UICDM::CUICDMPropertyHandle m_PropertyHandle; +}; + +#endif // INCLUDED_IMAGE_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp new file mode 100644 index 00000000..a4adefbc --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp @@ -0,0 +1,506 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +#include "KeyframesManager.h" +#include "IDoc.h" +#include "TimeEditDlg.h" +#include "TimelineTranslationManager.h" +#include "UICDMTimelineKeyframe.h" +#include "UICDMTimelineItemBinding.h" +#include "CmdDataModelRemoveKeyframe.h" +#include "CmdDataModelInsertKeyframe.h" +#include "CmdDataModelChangeKeyframe.h" +#include "UICDMAnimation.h" +#include "ClientDataModelBridge.h" +#include "PasteKeyframesCommandHelper.h" +#include "IDocumentEditor.h" +#include "IKeyframe.h" +#include "Dispatch.h" +#include "StudioPreferences.h" + +#include "StudioApp.h" //for CommitCurrentCommand +#include "Core.h" +#include "Dialogs.h" + +using namespace UICDM; + +bool SortKeyframeInstancePairByTime(const CKeyframesManager::SKeyframeInstancePair &inLHS, + const CKeyframesManager::SKeyframeInstancePair &inRHS) +{ + return inLHS.m_Keyframe->GetTime() < inRHS.m_Keyframe->GetTime(); +} + +//============================================================================== +// Keyframe specific. +// UICDM selection is handled by CTimelineTranslationManager. +//============================================================================== +CKeyframesManager::CKeyframesManager(CTimelineTranslationManager *inTransMgr) + : m_TransMgr(inTransMgr) + , m_OffsetKeyframeCommandHelper(*(g_StudioApp.GetCore()->GetDoc())) + , m_PasteKeyframeCommandHelper(nullptr) +{ + g_StudioApp.GetCore()->GetDoc()->SetKeyframesManager(this); +} + +CKeyframesManager::~CKeyframesManager() +{ + delete m_PasteKeyframeCommandHelper; +} + +bool CKeyframesManager::HasSelectedKeyframes(bool inOnlyDynamic /*= false */) +{ + // specifically only to know if there are any selected keyframes that are dynamic + if (inOnlyDynamic) { + for (size_t theIndex = 0; theIndex < m_SelectedKeyframes.size(); ++theIndex) + if (m_SelectedKeyframes[theIndex].m_Keyframe->IsDynamic()) + return true; + + return false; + } + + bool theRetVal = !m_SelectedKeyframes.empty(); + + return theRetVal; +} + +bool CKeyframesManager::CanPerformKeyframeCopy() +{ + bool theCanCopyNewData = false; + // Legacy system actually prevents copy/pasting between different instances, so let's preserve + // that + if (!m_SelectedKeyframes.empty()) { + theCanCopyNewData = true; + if (m_SelectedKeyframes.size() > 1) { + CUICDMTimelineItemBinding *theInstance = m_SelectedKeyframes[0].m_Instance; + TSelectedKeyframeList::iterator theIter = m_SelectedKeyframes.begin(); + ++theIter; + for (; theIter != m_SelectedKeyframes.end() && theCanCopyNewData; ++theIter) { + if (theIter->m_Instance != theInstance) // fail! + theCanCopyNewData = false; + } + } + } + return theCanCopyNewData; +} + +bool CKeyframesManager::CanPerformKeyframePaste() +{ + if (m_PasteKeyframeCommandHelper && m_PasteKeyframeCommandHelper->HasCopiedKeyframes()) { + UICDM::CUICDMInstanceHandle theSelectedInstance = + g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance(); + if (theSelectedInstance.Valid()) { + return true; + } + } + return false; +} + +void CKeyframesManager::CopyKeyframes() +{ + CopySelectedKeyframes(); +} + +// legacy stuff that we have to support for animation tracks in the old data model to work +inline void PostExecuteCommand(IDoc *inDoc) +{ + CDoc *theDoc = dynamic_cast<CDoc *>(inDoc); + theDoc->GetCore()->CommitCurrentCommand(); + // fire render event. + // theDoc->UpdateClientScene( true ); +} + +//@param inPerformCopy true if that is a copy/cut command. false if this is a delete. +// Note: Keyframes are never explicitly copied to the clipboard (only as part of a asset copy), +// hence that means that the keyframes (only) are never copied across different instances of studio. +bool CKeyframesManager::RemoveKeyframes(bool inPerformCopy) +{ + bool theRetVal = HasSelectedKeyframes(); + + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + + if (inPerformCopy) // copy prior to removing the keyframes + CopySelectedKeyframes(); + + CCmdDataModelRemoveKeyframe *theCmd = nullptr; + if (!m_SelectedKeyframes.empty()) { + TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin(); + for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) { + CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; + theKeyIter->m_Keyframe->GetKeyframeHandles(theKeyframeHandles); + ASSERT(!theKeyframeHandles.empty()); + CUICDMTimelineKeyframe::TKeyframeHandleList::iterator theIter = + theKeyframeHandles.begin(); + if (!theCmd) { + theCmd = new CCmdDataModelRemoveKeyframe(theDoc, *theIter); + ++theIter; + } + for (; theIter != theKeyframeHandles.end(); ++theIter) + theCmd->AddKeyframeHandle(*theIter); + } + } + + if (theCmd) { + g_StudioApp.GetCore()->ExecuteCommand(theCmd); + PostExecuteCommand(theDoc); + } + return theRetVal; +} + +// note: we can't paste data from old data model system to the new one, and vice versa. so either +// the old Or the new system succeeds in pasting, never both. +void CKeyframesManager::PasteKeyframes() +{ + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + + if (m_PasteKeyframeCommandHelper && m_PasteKeyframeCommandHelper->HasCopiedKeyframes()) { + UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance(); + if (theSelectedInstance.Valid()) { + long theCurrentViewTimeInMilliseconds = theDoc->GetCurrentViewTime(); + CCmdDataModelInsertKeyframe *theInsertKeyframesCommand = + m_PasteKeyframeCommandHelper->GetCommand(theDoc, theCurrentViewTimeInMilliseconds, + theSelectedInstance); + if (theInsertKeyframesCommand) + g_StudioApp.GetCore()->ExecuteCommand(theInsertKeyframesCommand); + } + } +} + +//============================================================================= +/** + * Sets interpolation values of all selected keyframes to the values specified + * by the user. Pops up a dialog prompting the user to choose new ease in and + * ease out values. Values in the dialog are initialized to the left-most + * selected keyframe's interpolation values. + */ +void CKeyframesManager::SetKeyframeInterpolation() +{ + if (!HasSelectedKeyframes()) + return; + + float theEaseIn = 0; + float theEaseOut = 0; + if (CStudioPreferences::GetInterpolation()) + theEaseIn = theEaseOut = 100; + + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + + if (!m_SelectedKeyframes.empty()) // this is a sorted list, so we only need to grab tge ease + // in/out values from the first item in this list. + { + CUICDMTimelineKeyframe *theTimelineKeyframe = m_SelectedKeyframes.front().m_Keyframe; + CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; + theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles); + TKeyframe theKeyframeData = theAnimationCore->GetKeyframeData(theKeyframeHandles[0]); + GetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut); + } + + if (g_StudioApp.GetDialogs()->PromptForKeyframeInterpolation(theEaseIn, theEaseOut)) { + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Set Keyframe Interpolation", __FILE__, + __LINE__); + TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin(); + for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) { + CUICDMTimelineKeyframe *theTimelineKeyframe = theKeyIter->m_Keyframe; + CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; + theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles); + for (size_t i = 0; i < theKeyframeHandles.size(); ++i) { + TKeyframe theKeyframeData = + theAnimationCore->GetKeyframeData(theKeyframeHandles[i]); + SetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut); + theAnimationCore->SetKeyframeData(theKeyframeHandles[i], theKeyframeData); + } + } + } +} + +bool CKeyframesManager::HasDynamicKeyframes() +{ + CUICDMTimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding(); + if (theBinding) { + return theBinding->HasDynamicKeyframes(-1); + } + return false; +} + +void CKeyframesManager::SelectAllKeyframes() +{ + ITimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding(); + if (theBinding) + theBinding->SelectKeyframes(true); +} + +void CKeyframesManager::DeselectAllKeyframes() +{ + m_TransMgr->ClearBindingsKeyframeSelection(); + m_SelectedKeyframes.clear(); +} + +//============================================================================== +/** + * Sets keyframes on all the changed properties of the selected object. + * Also known as autoset keyframes, but it only applies to one object, and is + * the result of an F6 key press. Tells the TimelineCtrl to autoset keyframes. + */ +void CKeyframesManager::SetChangedKeyframes() +{ + + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance(); + if (theSelectedInstance.Valid()) { + using namespace Q3DStudio; + Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Set Changed Keyframes", __FILE__, + __LINE__); + CStudioSystem *theStudioSystem = theDoc->GetStudioSystem(); + // Get all animated properties. + TPropertyHandleList theProperties; + theStudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(theSelectedInstance, + theProperties); + for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); + ++thePropertyIndex) { + if (theStudioSystem->GetAnimationSystem()->IsPropertyAnimated( + theSelectedInstance, theProperties[thePropertyIndex])) + editor->KeyframeProperty(theSelectedInstance, theProperties[thePropertyIndex], + true); + } + } +} + +void CKeyframesManager::SetKeyframeTime(long inTime) +{ + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.SetKeyframesManager(this); + theTimeEditDlg.ShowDialog(inTime, 0, g_StudioApp.GetCore()->GetDoc(), ASSETKEYFRAME); +} + +void CKeyframesManager::SetKeyframeDynamic(CUICDMTimelineKeyframe *inKeyframe, bool inDynamic) +{ + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::TKeyframeHandleList theKeyframeHandle; + CCmdDataModelChangeDynamicKeyframe *theCmd = nullptr; + + if (inKeyframe != nullptr) + inKeyframe->GetKeyframeHandles(theKeyframeHandle); + + UICDM::IAnimationCore *theAnimationCore = theDoc->GetStudioSystem()->GetAnimationCore(); + for (size_t theKeyframe = 0; theKeyframe < theKeyframeHandle.size(); ++theKeyframe) { + UICDM::CUICDMAnimationHandle theAnimation( + theAnimationCore->GetAnimationForKeyframe(theKeyframeHandle.at(theKeyframe))); + if (!theCmd) + theCmd = new CCmdDataModelChangeDynamicKeyframe(theDoc, theAnimation, inDynamic); + else + theCmd->AddHandle(theAnimation); + } + + if (theCmd) + g_StudioApp.GetCore()->ExecuteCommand(theCmd); +} + +void CKeyframesManager::SetKeyframesDynamic(bool inDynamic) +{ + + CUICDMTimelineKeyframe *theKeyframe; + + if (m_SelectedKeyframes.size() == 0) { + CUICDMTimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding(); + IKeyframe *key = theBinding->GetKeyframeByIndex(0); + theKeyframe = dynamic_cast<CUICDMTimelineKeyframe *>(key); + SetKeyframeDynamic(theKeyframe, inDynamic); + } else { + for (int i = 0; i < (int)m_SelectedKeyframes.size(); ++i) { + theKeyframe = m_SelectedKeyframes[i].m_Keyframe; + SetKeyframeDynamic(theKeyframe, inDynamic); + } + } +} + +long CKeyframesManager::OffsetSelectedKeyframes(long inOffset) +{ + m_InstanceSet.clear(); + m_InstanceList.clear(); + std::set<CUICDMTimelineItemBinding *> &theInstances(m_InstanceSet); + + TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin(); + for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) { + // since this list is sorted by time and we are iterating from the first in the list + long theKeyframeTime = theKeyIter->m_Keyframe->GetTime(); + if (inOffset < 0 && theKeyframeTime + inOffset < 0) + inOffset = -theKeyframeTime; + + theKeyIter->m_Keyframe->UpdateKeyframesTime(&m_OffsetKeyframeCommandHelper, + theKeyframeTime + inOffset); + + // this contains unique instancs, i.e. mulitple keyframe can map to the same instances + if (theInstances.insert(theKeyIter->m_Instance).second) + m_InstanceList.push_back(theKeyIter->m_Instance->GetInstance()); + } + + // UI update, explicitly because this doesn't generate any events till action is committed + std::set<CUICDMTimelineItemBinding *>::iterator theInstanceIter = theInstances.begin(); + for (; theInstanceIter != theInstances.end(); ++theInstanceIter) + (*theInstanceIter)->UIRefreshPropertyKeyframe(inOffset); + + if (m_InstanceList.size()) + m_TransMgr->GetDoc()->GetCore()->GetDispatch()->FireImmediateRefreshInstance( + &m_InstanceList[0], (long)m_InstanceList.size()); + + // by contract, this functions returns the "legal" offset, ie time cannot be offset to negative. + return inOffset; +} + +void CKeyframesManager::CommitChangedKeyframes() +{ + m_OffsetKeyframeCommandHelper.Finalize(); +} + +void CKeyframesManager::RollbackChangedKeyframes() +{ + m_OffsetKeyframeCommandHelper.Rollback(); +} + +bool CKeyframesManager::CanMakeSelectedKeyframesDynamic() +{ + using namespace UICDM; + TKeyframeHandleList theKeyframes; + TKeyframeHandleList allTheKeyframes; + IAnimationCore &theAnimationCore( + *g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetAnimationCore()); + // Ensure that all keyframes selected are the first keyframes from the animation track. + for (size_t idx = 0, end = m_SelectedKeyframes.size(); idx < end; ++idx) { + theKeyframes.clear(); + m_SelectedKeyframes.at(idx).m_Keyframe->GetKeyframeHandles(theKeyframes); + for (size_t specificKeyframeIdx = 0, specificKeyframeEnd = theKeyframes.size(); + specificKeyframeIdx < specificKeyframeEnd; ++specificKeyframeIdx) { + CUICDMKeyframeHandle theKeyframe = theKeyframes[specificKeyframeIdx]; + CUICDMAnimationHandle theAnimation = + theAnimationCore.GetAnimationForKeyframe(theKeyframe); + allTheKeyframes.clear(); + theAnimationCore.GetKeyframes(theAnimation, allTheKeyframes); + if (allTheKeyframes[0] != theKeyframe) + return false; + } + } + return true; +} + +// keeps track of selected keyframes so that we don't have to iterate through the entire hierarchy +// to find them +void CKeyframesManager::SetKeyframeSelected(CUICDMTimelineKeyframe *inKeyframe, bool inSelected, + CUICDMTimelineItemBinding *inOwningInstance /*= nullptr */) +{ + TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin(); + for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) { + if (theKeyIter->m_Keyframe == inKeyframe) + break; + } + if (inSelected) { + ASSERT(inOwningInstance); + if (theKeyIter == m_SelectedKeyframes.end()) { // only this is not already selected + m_SelectedKeyframes.push_back(SKeyframeInstancePair(inKeyframe, inOwningInstance)); + std::sort(m_SelectedKeyframes.begin(), m_SelectedKeyframes.end(), + SortKeyframeInstancePairByTime); + } + } else if (theKeyIter != m_SelectedKeyframes.end()) { + m_SelectedKeyframes.erase(theKeyIter); + } +} + +UICDM::SGetOrSetKeyframeInfo SetupKeyframeInfo(UICDM::CUICDMKeyframeHandle inKeyframe, + UICDM::IAnimationCore &inCore) +{ + TKeyframe theKeyframeData = inCore.GetKeyframeData(inKeyframe); + SEaseInEaseOutKeyframe theKeyframe = UICDM::get<SEaseInEaseOutKeyframe>(theKeyframeData); + // Is this the first keyframe? + bool isDynamic = false; + if (inCore.IsFirstKeyframe(inKeyframe)) + isDynamic = inCore.GetAnimationInfo(inCore.GetAnimationForKeyframe(inKeyframe)) + .m_DynamicFirstKeyframe; + + return SGetOrSetKeyframeInfo(theKeyframe.m_KeyframeValue, theKeyframe.m_EaseIn, + theKeyframe.m_EaseOut, isDynamic); +} + +// only deal with this manager's selected keyframes +void CKeyframesManager::CopySelectedKeyframes() +{ + if (!m_SelectedKeyframes.empty()) { + if (m_PasteKeyframeCommandHelper) + m_PasteKeyframeCommandHelper->Clear(); // clear out previously copied data + else + m_PasteKeyframeCommandHelper = new CPasteKeyframeCommandHelper(); + + // note: m_SelectedKeyframes is already sorted by time + float theEarliestKeyframeTimeInSecs = + CUICDMTimelineKeyframe::GetTimeInSecs(m_SelectedKeyframes[0].m_Keyframe->GetTime()); + + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + TSelectedKeyframeList::iterator theIter = m_SelectedKeyframes.begin(); + for (; theIter != m_SelectedKeyframes.end(); ++theIter) { + CUICDMTimelineKeyframe *theKeyframe = (*theIter).m_Keyframe; + CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; + theKeyframe->GetKeyframeHandles(theKeyframeHandles); + UICDM::SGetOrSetKeyframeInfo theInfos[3]; + size_t theValidInfos = 0; + if (!theKeyframeHandles.empty()) { + // TODO: need to figure out a good way to convert from individual keyframes back to + // SValue + SValue theValue; + switch (theKeyframeHandles.size()) { + case 1: { + theInfos[0] = SetupKeyframeInfo(theKeyframeHandles[0], *theAnimationCore); + theValidInfos = 1; + + } break; + case 3: { + theInfos[0] = SetupKeyframeInfo(theKeyframeHandles[0], *theAnimationCore); + theInfos[1] = SetupKeyframeInfo(theKeyframeHandles[1], *theAnimationCore); + theInfos[2] = SetupKeyframeInfo(theKeyframeHandles[2], *theAnimationCore); + theValidInfos = 3; + } break; + default: // not handled + break; + } + // time is relative to the earliest keyframe time. + float theRelativeTimeInSecs = + CUICDMTimelineKeyframe::GetTimeInSecs(theKeyframe->GetTime()) + - theEarliestKeyframeTimeInSecs; + + CUICDMAnimationHandle theAnimation = + theAnimationCore->GetAnimationForKeyframe(theKeyframeHandles[0]); + m_PasteKeyframeCommandHelper->AddKeyframeData( + theAnimationCore->GetAnimationInfo(theAnimation).m_Property, + theRelativeTimeInSecs, theInfos, theValidInfos); + } + } + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h new file mode 100644 index 00000000..61ac2740 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_KEYFRAMES_MANAGER_H +#define INCLUDED_KEYFRAMES_MANAGER_H 1 + +#pragma once + +#include "ITimelineKeyframesManager.h" +#include "OffsetKeyframesCommandHelper.h" + +class CTimelineTranslationManager; +class CUICDMTimelineKeyframe; +class CUICDMTimelineItemBinding; +class CPasteKeyframeCommandHelper; + +//============================================================================= +/** + * Abstraction layer to the class that manages both selected keyframes. + */ +//============================================================================= +class CKeyframesManager : public ITimelineKeyframesManager +{ +public: + CKeyframesManager(CTimelineTranslationManager *inTransMgr); + virtual ~CKeyframesManager(); + + // IKeyframesManager + bool HasSelectedKeyframes(bool inOnlyDynamic = false) override; + bool HasDynamicKeyframes() override; + bool CanPerformKeyframeCopy() override; + bool CanPerformKeyframePaste() override; + void CopyKeyframes() override; + bool RemoveKeyframes(bool inPerformCopy) override; + void PasteKeyframes() override; + void SetKeyframeInterpolation() override; + void DeselectAllKeyframes() override; + void SelectAllKeyframes() override; + void SetChangedKeyframes() override; + // ITimelineKeyframesManager + void SetKeyframeTime(long inTime) override; + void SetKeyframesDynamic(bool inDynamic) override; + bool CanMakeSelectedKeyframesDynamic() override; + long OffsetSelectedKeyframes(long inOffset) override; + void CommitChangedKeyframes() override; + void RollbackChangedKeyframes() override; + + void SetKeyframeSelected(CUICDMTimelineKeyframe *inKeyframe, bool inSelected, + CUICDMTimelineItemBinding *inOwningInstance = nullptr); + +protected: + void SetKeyframeDynamic(CUICDMTimelineKeyframe *inKeyframe, bool inDynamic); + void CopySelectedKeyframes(); + +public: + struct SKeyframeInstancePair + { + CUICDMTimelineKeyframe *m_Keyframe; + CUICDMTimelineItemBinding *m_Instance; + + SKeyframeInstancePair(CUICDMTimelineKeyframe *inKeyframe, + CUICDMTimelineItemBinding *inInstance) + { + m_Keyframe = inKeyframe; + m_Instance = inInstance; + } + }; + +protected: + typedef std::vector<SKeyframeInstancePair> TSelectedKeyframeList; ///< handle multiple keyframes + ///manipulation, e.g. + ///offsetting by dragging + + CTimelineTranslationManager *m_TransMgr; + TSelectedKeyframeList m_SelectedKeyframes; + COffsetKeyframesCommandHelper m_OffsetKeyframeCommandHelper; // so that we can commit on mouseup + CPasteKeyframeCommandHelper *m_PasteKeyframeCommandHelper; + std::set<CUICDMTimelineItemBinding *> m_InstanceSet; + std::vector<UICDM::CUICDMInstanceHandle> m_InstanceList; +}; + +#endif // INCLUDED_IKEYFRAMES_MANAGER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp new file mode 100644 index 00000000..73d5d5d2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "LayerTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "BaseStateRow.h" +#include "ImageTimelineItemBinding.h" +#include "EmptyTimelineTimebar.h" + +// Data model specific +#include "IDoc.h" +#include "ClientDataModelBridge.h" +#include "DropSource.h" +#include "Doc.h" + +#include "UICDMHandles.h" +#include "UICDMStudioSystem.h" + +#include "UICDMMetaData.h" +#include "UICDMDataCore.h" +#include "StudioFullSystem.h" +#include "StudioCoreSystem.h" +#include "UICDMSlides.h" + +using namespace UICDM; + +namespace { + +bool ImageSlotIsFilled(UICDM::IPropertySystem *inPropertySystem, CUICDMInstanceHandle inInstance, + const TCharStr &inStr) +{ + CUICDMPropertyHandle theProperty = + inPropertySystem->GetAggregateInstancePropertyByName(inInstance, inStr); + SValue theValue; + inPropertySystem->GetInstancePropertyValue(inInstance, theProperty, theValue); + + SLong4 theLong4 = UICDM::get<SLong4>(theValue); + bool theReturn = theLong4.m_Longs[0] != 0 || theLong4.m_Longs[1] != 0 + || theLong4.m_Longs[2] != 0 || theLong4.m_Longs[3] != 0; + + return theReturn; +} + +// helper function to find the image binding class that 'represents' this property +inline CImageTimelineItemBinding *FindImageBindingByProperty(CBaseStateRow *inRow, + CUICDMPropertyHandle inProperty) +{ + if (!inRow || !inProperty.Valid()) + return nullptr; + + CImageTimelineItemBinding *theInvalidImageBinding = nullptr; + for (long theIndex = 0; theIndex < inRow->GetNumNonPropertyRows(); ++theIndex) { + CImageTimelineItemBinding *theImageBinding = dynamic_cast<CImageTimelineItemBinding *>( + inRow->GetNonPropertyRow(theIndex)->GetTimelineItemBinding()); + if (theImageBinding && theImageBinding->GetPropertyHandle() == inProperty) { + theInvalidImageBinding = theImageBinding; + break; + } + } + return theInvalidImageBinding; +} +} + +CLayerTimelineItemBinding::CLayerTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + TPropertyHandleList theProperties; + thePropertySystem->GetAggregateInstanceProperties(inDataHandle, theProperties); + + size_t thePropertyCount = theProperties.size(); + for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) { + CUICDMPropertyHandle theProperty = theProperties[thePropertyIndex]; + + AdditionalMetaDataType::Value theAdditionalMetaDataType = + thePropertySystem->GetAdditionalMetaDataType(inDataHandle, theProperty); + + if (theAdditionalMetaDataType == AdditionalMetaDataType::Image) { + TCharStr theName(thePropertySystem->GetName(theProperty)); + TCharStr theFormalName(thePropertySystem->GetFormalName(inDataHandle, theProperty)); + TNameFormalNamePair thePair = + std::make_tuple(theName, theFormalName, theProperty); + m_ImageNameFormalNamePairs.push_back(thePair); + } + } +} + +CLayerTimelineItemBinding::~CLayerTimelineItemBinding() +{ +} + +EStudioObjectType CLayerTimelineItemBinding::GetObjectType() const +{ + return OBJTYPE_LAYER; +} + +ITimelineItemBinding *CLayerTimelineItemBinding::GetChild(long inIndex) +{ + static const TCharStr theLayerPrefix(L"Layer_"); + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + if (theInstance.Valid()) { + Q3DStudio::CGraphIterator theChildren; + CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide(); + GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(), + theChildren, theActiveSlide); + theChildren += inIndex; + + UICDM::CUICDMInstanceHandle theChildInstance = theChildren.GetCurrent(); + if (theChildInstance.Valid()) { + std::shared_ptr<IDataCore> theDataCore = + m_TransMgr->GetStudioSystem()->GetFullSystem()->GetCoreSystem()->GetDataCore(); + ISlideSystem *theSlideSystem = m_TransMgr->GetStudioSystem()->GetSlideSystem(); + ISlideCore *theSlideCore = m_TransMgr->GetStudioSystem()->GetSlideCore(); + + size_t theSlotCursor = (size_t)-1; + { + + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + UICDM::SLong4 theGuid; + { + CUICDMPropertyHandle theTypeProperty = + thePropertySystem->GetAggregateInstancePropertyByName(theChildInstance, + L"id"); + SValue theIdValue; + thePropertySystem->GetInstancePropertyValue(theChildInstance, theTypeProperty, + theIdValue); + theGuid = UICDM::get<UICDM::SLong4>(theIdValue); + } + for (size_t theSlotIndex = 0, theSlotCount = m_ImageNameFormalNamePairs.size(); + theSlotIndex < theSlotCount; ++theSlotIndex) { + bool theIsMatch = false; + UICDM::CUICDMPropertyHandle theProperty = + std::get<2>(m_ImageNameFormalNamePairs[theSlotIndex]); + SValue theValue; + const SUICDMPropertyDefinition &theDefinition( + theDataCore->GetProperty(theProperty)); + if (theDefinition.m_Type == DataModelDataType::Long4) { + SValue theDCValue; + if (theDataCore->GetInstancePropertyValue(theInstance, theProperty, + theDCValue)) { + SLong4 thePropGuid = get<SLong4>(theDCValue); + if (thePropGuid == theGuid) + theIsMatch = true; + } + CUICDMSlideHandle theSlide = + theSlideSystem->GetAssociatedSlide(theChildInstance); + CUICDMSlideHandle theMasterSlide = theSlideSystem->GetMasterSlide(theSlide); + if (theIsMatch == false && theSlide.Valid() + && theSlideCore->GetSpecificInstancePropertyValue( + theSlide, theInstance, theProperty, theValue)) { + SLong4 thePropGuid = get<SLong4>(theValue); + if (thePropGuid == theGuid) + theIsMatch = true; + } + } + if (theIsMatch) { + theSlotCursor = theSlotIndex; + break; + } + } + } + if (theSlotCursor != (size_t)-1) { + CUICDMPropertyHandle theImageProperty = + thePropertySystem->GetAggregateInstancePropertyByName( + m_DataHandle, std::get<0>(m_ImageNameFormalNamePairs[theSlotCursor])); + return GetOrCreateImageBinding( + theImageProperty, + std::get<1>(m_ImageNameFormalNamePairs[theSlotCursor]).wide_str()); + } else + return m_TransMgr->GetOrCreate(theChildInstance); + } + } + return nullptr; +} + +void CLayerTimelineItemBinding::OnAddChild(UICDM::CUICDMInstanceHandle inInstance) +{ + using namespace UICDM; + CClientDataModelBridge *theBridge = m_TransMgr->GetStudioSystem()->GetClientDataModelBridge(); + // This is handled via the OnPropertyChanged call below + if (theBridge->IsImageInstance(inInstance)) + return; + else + CUICDMTimelineItemBinding::OnAddChild(inInstance); +} + +void CLayerTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle) +{ + bool theHandled = false; + if (m_Row) { + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + CClientDataModelBridge *theBridge = + m_TransMgr->GetStudioSystem()->GetClientDataModelBridge(); + UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle); + size_t theSlotCount = m_ImageNameFormalNamePairs.size(); + for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) { + UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]); + if (thePropertyName == thePropName) { + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) { + // already created, bail! + if (m_TransMgr->GetBinding(GetImage(inPropertyHandle))) + return; + + // Image property was changed from one non-zero guid value to another, delete + // the old and and create a new one + CImageTimelineItemBinding *theReplacedImageBinding = + FindImageBindingByProperty(m_Row, inPropertyHandle); + if (theReplacedImageBinding) + m_Row->RemoveChildRow(theReplacedImageBinding); + + ITimelineItemBinding *theNextImageBinding = nullptr; + // Determine if this is inserted somewhere in the existing list. + for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount; + ++theNextImage) { + UICDM::TCharStr theTempName = + std::get<0>(m_ImageNameFormalNamePairs[theNextImage]); + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) { + CUICDMPropertyHandle theNextImageProperty = + theBridge->GetAggregateInstancePropertyByName(m_DataHandle, + theTempName); + theNextImageBinding = + m_TransMgr->GetBinding(GetImage(theNextImageProperty)); + break; + } + } + m_Row->AddChildRow( + GetOrCreateImageBinding( + inPropertyHandle, + std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()), + theNextImageBinding); + } else // check for delete + { + // GetImage will not return anything valid since the value is nuked. + // From the UI end, there is no way we can tell which image is associated with + // this property, since that is "encapsulated" in the property value. + CImageTimelineItemBinding *theInvalidImageBinding = + FindImageBindingByProperty(m_Row, inPropertyHandle); + if (theInvalidImageBinding) + m_Row->RemoveChildRow(theInvalidImageBinding); + } + theHandled = true; + break; + } + } + } + if (!theHandled) + CUICDMTimelineItemBinding::OnPropertyChanged(inPropertyHandle); +} + +UICDM::CUICDMInstanceHandle +CLayerTimelineItemBinding::GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle) +{ + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + SValue theImageValue; + thePropertySystem->GetInstancePropertyValue(m_DataHandle, inPropertyHandle, theImageValue); + SLong4 theImageLong4 = UICDM::get<SLong4>(theImageValue); + return m_TransMgr->GetStudioSystem()->GetClientDataModelBridge()->GetImageInstanceByGUID( + theImageLong4); +} + +ITimelineItemBinding * +CLayerTimelineItemBinding::GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle, + const wchar_t *inName) +{ + UICDM::CUICDMInstanceHandle theImageInstance = GetImage(inPropertyHandle); + ITimelineItemBinding *theImageTimelineRow = m_TransMgr->GetBinding(theImageInstance); + if (!theImageTimelineRow) // create + { + theImageTimelineRow = m_TransMgr->GetOrCreate(theImageInstance); + // Set the name, by spec: the nice name. + theImageTimelineRow->GetTimelineItem()->SetName(inName); + CImageTimelineItemBinding *theImageBinding = + dynamic_cast<CImageTimelineItemBinding *>(theImageTimelineRow); + if (theImageBinding) + theImageBinding->SetPropertyHandle(inPropertyHandle); + } + return theImageTimelineRow; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h new file mode 100644 index 00000000..d4826f2f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_LAYER_TIMELINEITEM_BINDING_H +#define INCLUDED_LAYER_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" + +namespace UICDM { +class CStudioSystem; +} + +//============================================================================= +/** + * Binding to generic UICDM object + */ +class CLayerTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: // Types + typedef std::tuple<UICDM::TCharStr, UICDM::TCharStr, UICDM::CUICDMPropertyHandle> + TNameFormalNamePair; + typedef std::vector<TNameFormalNamePair> TNameFormalNamePairList; + +protected: // Members + TNameFormalNamePairList m_ImageNameFormalNamePairs; + +public: // Construction + CLayerTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + virtual ~CLayerTimelineItemBinding(); + +public: // CUICDMTimelineItemBinding + EStudioObjectType GetObjectType() const override; + // Hierarchy + ITimelineItemBinding *GetChild(long inIndex) override; + void OnAddChild(UICDM::CUICDMInstanceHandle inInstance) override; + // Event callback + void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle) override; + +protected: + UICDM::CUICDMInstanceHandle GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle); + ITimelineItemBinding *GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle, + const wchar_t *inName); +}; + +#endif // INCLUDED_LAYER_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp new file mode 100644 index 00000000..eb91714e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp @@ -0,0 +1,336 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "MaterialTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "BaseStateRow.h" +#include "ImageTimelineItemBinding.h" +#include "EmptyTimelineTimebar.h" + +// Data model specific +#include "IDoc.h" +#include "ClientDataModelBridge.h" +#include "DropSource.h" + +#include "UICDMHandles.h" +#include "UICDMStudioSystem.h" + +#include "UICDMMetaData.h" +#include "UICDMDataCore.h" +#include "StudioFullSystem.h" +#include "StudioCoreSystem.h" + +using namespace UICDM; + +CMaterialTimelineItemBinding::CMaterialTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + TPropertyHandleList theProperties; + thePropertySystem->GetAggregateInstanceProperties(inDataHandle, theProperties); + + size_t thePropertyCount = theProperties.size(); + for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) { + CUICDMPropertyHandle theProperty = theProperties[thePropertyIndex]; + + AdditionalMetaDataType::Value theAdditionalMetaDataType = + thePropertySystem->GetAdditionalMetaDataType(inDataHandle, theProperty); + + if (theAdditionalMetaDataType == AdditionalMetaDataType::Image) { + TCharStr theName(thePropertySystem->GetName(theProperty)); + TCharStr theFormalName(thePropertySystem->GetFormalName(inDataHandle, theProperty)); + TNameFormalNamePair thePair = std::make_tuple(theName, theFormalName); + m_ImageNameFormalNamePairs.push_back(thePair); + } + } +} + +CMaterialTimelineItemBinding::~CMaterialTimelineItemBinding() +{ +} + +ITimelineTimebar *CMaterialTimelineItemBinding::GetTimebar() +{ // No timebars on materials + return new CEmptyTimelineTimebar(); +} + +EStudioObjectType CMaterialTimelineItemBinding::GetObjectType() const +{ + return OBJTYPE_MATERIAL; +} + +bool CMaterialTimelineItemBinding::ShowToggleControls() const +{ + // Materials have no toggle controls, by design + return false; +} + +bool ImageSlotIsFilled(UICDM::IPropertySystem *inPropertySystem, CUICDMInstanceHandle inInstance, + const TCharStr &inStr) +{ + CUICDMPropertyHandle theProperty = + inPropertySystem->GetAggregateInstancePropertyByName(inInstance, inStr); + SValue theValue; + inPropertySystem->GetInstancePropertyValue(inInstance, theProperty, theValue); + + // Prevent assertion down the path when changing from edited standard material to reference material + if (UICDM::GetValueType(theValue) == DataModelDataType::None) + return false; + + SLong4 theLong4 = UICDM::get<SLong4>(theValue); + bool theReturn = theLong4.m_Longs[0] != 0 || theLong4.m_Longs[1] != 0 + || theLong4.m_Longs[2] != 0 || theLong4.m_Longs[3] != 0; + + return theReturn; +} + +long CMaterialTimelineItemBinding::GetChildrenCount() +{ + long theReturnCount = 0; + if (m_TransMgr->GetStudioSystem()->IsInstance(m_DataHandle)) { + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + size_t theSlotCount = m_ImageNameFormalNamePairs.size(); + for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) { + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, + std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]))) { + ++theReturnCount; + } + } + } + + return theReturnCount; +} + +ITimelineItemBinding *CMaterialTimelineItemBinding::GetChild(long inIndex) +{ + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + + size_t theSlotCursor = 0; + size_t theSlotCount = m_ImageNameFormalNamePairs.size(); + for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) { + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, + std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]))) { + inIndex--; + + if (inIndex < 0) { + theSlotCursor = theSlotIndex; + break; + } + } + } + CUICDMPropertyHandle theImageProperty = thePropertySystem->GetAggregateInstancePropertyByName( + m_DataHandle, std::get<0>(m_ImageNameFormalNamePairs[theSlotCursor])); + return GetOrCreateImageBinding( + theImageProperty, std::get<1>(m_ImageNameFormalNamePairs[theSlotCursor]).wide_str()); +} + +void CMaterialTimelineItemBinding::OnAddChild(UICDM::CUICDMInstanceHandle inInstance) +{ + using namespace UICDM; + CClientDataModelBridge *theBridge = m_TransMgr->GetStudioSystem()->GetClientDataModelBridge(); + // This is handled via the OnPropertyChanged call below + if (theBridge->IsImageInstance(inInstance)) + return; + else + CUICDMTimelineItemBinding::OnAddChild(inInstance); +} + +// helper function to find the image binding class that 'represents' this property +inline CImageTimelineItemBinding *FindImageBindingByProperty(CBaseStateRow *inRow, + CUICDMPropertyHandle inProperty) +{ + if (!inRow || !inProperty.Valid()) + return nullptr; + + CImageTimelineItemBinding *theInvalidImageBinding = nullptr; + for (long theIndex = 0; theIndex < inRow->GetNumNonPropertyRows(); ++theIndex) { + CImageTimelineItemBinding *theImageBinding = dynamic_cast<CImageTimelineItemBinding *>( + inRow->GetNonPropertyRow(theIndex)->GetTimelineItemBinding()); + if (theImageBinding && theImageBinding->GetPropertyHandle() == inProperty) { + theInvalidImageBinding = theImageBinding; + break; + } + } + return theInvalidImageBinding; +} + +void CMaterialTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle) +{ + bool theHandled = false; + if (m_Row) { + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + CClientDataModelBridge *theBridge = + m_TransMgr->GetStudioSystem()->GetClientDataModelBridge(); + UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle); + size_t theSlotCount = m_ImageNameFormalNamePairs.size(); + for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) { + UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]); + if (thePropertyName == thePropName) { + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) { + // already created, bail! + if (m_TransMgr->GetBinding(GetImage(inPropertyHandle))) + return; + + // Image property was changed from one non-zero guid value to another, delete + // the old and and create a new one + CImageTimelineItemBinding *theReplacedImageBinding = + FindImageBindingByProperty(m_Row, inPropertyHandle); + if (theReplacedImageBinding) + m_Row->RemoveChildRow(theReplacedImageBinding); + + ITimelineItemBinding *theNextImageBinding = nullptr; + // Determine if this is inserted somewhere in the existing list. + for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount; + ++theNextImage) { + UICDM::TCharStr theTempName = + std::get<0>(m_ImageNameFormalNamePairs[theNextImage]); + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) { + CUICDMPropertyHandle theNextImageProperty = + theBridge->GetAggregateInstancePropertyByName(m_DataHandle, + theTempName); + theNextImageBinding = + m_TransMgr->GetBinding(GetImage(theNextImageProperty)); + break; + } + } + m_Row->AddChildRow( + GetOrCreateImageBinding( + inPropertyHandle, + std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()), + theNextImageBinding); + } else // check for delete + { + // GetImage will not return anything valid since the value is nuked. + // From the UI end, there is no way we can tell which image is associated with + // this property, since that is "encapsulated" in the property value. + CImageTimelineItemBinding *theInvalidImageBinding = + FindImageBindingByProperty(m_Row, inPropertyHandle); + if (theInvalidImageBinding) + m_Row->RemoveChildRow(theInvalidImageBinding); + } + theHandled = true; + break; + } + } + } + if (!theHandled) + CUICDMTimelineItemBinding::OnPropertyChanged(inPropertyHandle); +} + +void CMaterialTimelineItemBinding::OnPropertyLinked(CUICDMPropertyHandle inPropertyHandle) +{ + bool theHandled = false; + if (m_Row) { + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + CClientDataModelBridge *theBridge = + m_TransMgr->GetStudioSystem()->GetClientDataModelBridge(); + UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle); + size_t theSlotCount = m_ImageNameFormalNamePairs.size(); + for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) { + UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]); + if (thePropertyName == thePropName) { + // Refresh image child row by delete and recreate + CImageTimelineItemBinding *theInvalidImageBinding = + FindImageBindingByProperty(m_Row, inPropertyHandle); + if (theInvalidImageBinding) + m_Row->RemoveChildRow(theInvalidImageBinding); + + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) { + ITimelineItemBinding *theNextImageBinding = nullptr; + // Determine if this is inserted somewhere in the existing list. + for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount; + ++theNextImage) { + UICDM::TCharStr theTempName = + std::get<0>(m_ImageNameFormalNamePairs[theNextImage]); + if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) { + CUICDMPropertyHandle theNextImageProperty = + theBridge->GetAggregateInstancePropertyByName(m_DataHandle, + theTempName); + theNextImageBinding = + m_TransMgr->GetBinding(GetImage(theNextImageProperty)); + break; + } + } + m_Row->AddChildRow( + GetOrCreateImageBinding( + inPropertyHandle, + std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()), + theNextImageBinding); + } + + theHandled = true; + break; + } + } + } + if (!theHandled) + CUICDMTimelineItemBinding::OnPropertyLinked(inPropertyHandle); +} + +UICDM::CUICDMInstanceHandle +CMaterialTimelineItemBinding::GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle) +{ + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + SValue theImageValue; + thePropertySystem->GetInstancePropertyValue(m_DataHandle, inPropertyHandle, theImageValue); + SLong4 theImageLong4 = UICDM::get<SLong4>(theImageValue); + return m_TransMgr->GetStudioSystem()->GetClientDataModelBridge()->GetImageInstanceByGUID( + theImageLong4); +} + +ITimelineItemBinding * +CMaterialTimelineItemBinding::GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle, + const wchar_t *inName) +{ + UICDM::CUICDMInstanceHandle theImageInstance = GetImage(inPropertyHandle); + ITimelineItemBinding *theImageTimelineRow = m_TransMgr->GetBinding(theImageInstance); + if (!theImageTimelineRow) // create + { + theImageTimelineRow = m_TransMgr->GetOrCreate(theImageInstance); + // Set the name, by spec: the nice name. + theImageTimelineRow->GetTimelineItem()->SetName(inName); + CImageTimelineItemBinding *theImageBinding = + dynamic_cast<CImageTimelineItemBinding *>(theImageTimelineRow); + if (theImageBinding) + theImageBinding->SetPropertyHandle(inPropertyHandle); + } + return theImageTimelineRow; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h new file mode 100644 index 00000000..e1c2188d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H +#define INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" +#include "UICDMDataTypes.h" + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; +class CBaseStateRow; + +//============================================================================= +/** + * Binding to a UICDM object of Material type + */ +class CMaterialTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: // Types + typedef std::tuple<UICDM::TCharStr, UICDM::TCharStr> TNameFormalNamePair; + typedef std::vector<TNameFormalNamePair> TNameFormalNamePairList; + +protected: // Members + TNameFormalNamePairList m_ImageNameFormalNamePairs; + +public: // Construction + CMaterialTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + virtual ~CMaterialTimelineItemBinding(); + +public: // CUICDMTimelineItemBinding + ITimelineTimebar *GetTimebar() override; + EStudioObjectType GetObjectType() const override; + bool ShowToggleControls() const override; + // Hierarchy + long GetChildrenCount() override; + ITimelineItemBinding *GetChild(long inIndex) override; + void OnAddChild(UICDM::CUICDMInstanceHandle inInstance) override; + // Event callback + void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle) override; + void OnPropertyLinked(UICDM::CUICDMPropertyHandle inPropertyHandle) override; + +protected: + UICDM::CUICDMInstanceHandle GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle); + ITimelineItemBinding *GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle, + const wchar_t *inName); +}; + +#endif // INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp new file mode 100644 index 00000000..374c123b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "OffsetKeyframesCommandHelper.h" +#include "Core.h" + +// Data model specific +#include "IDoc.h" +#include "CmdDataModelChangeKeyframe.h" +#include "IDocumentEditor.h" + +#include "UICDMTimelineKeyframe.h" //TODO: remove once we resolve the precision issue + +using namespace UICDM; + +COffsetKeyframesCommandHelper::COffsetKeyframesCommandHelper(CDoc &inDoc) + : Q3DStudio::CUpdateableDocumentEditor(inDoc) + , m_Doc(inDoc) +{ +} + +COffsetKeyframesCommandHelper::~COffsetKeyframesCommandHelper() +{ + Finalize(); +} + +//@param inTime time in millisecs +void COffsetKeyframesCommandHelper::SetCommandTime(UICDM::CUICDMKeyframeHandle inKeyframe, + long inTime) +{ + // The UICDM system will take care of merging these under the hood. + ENSURE_EDITOR(L"Set Keyframe Time").SetKeyframeTime(inKeyframe, inTime); +} + +// equivalent to commit (onmouseup) +void COffsetKeyframesCommandHelper::Finalize() +{ + CommitEditor(); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h new file mode 100644 index 00000000..3a58e672 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_OFFSET_KEYFRAMES_COMMAND_HELPER_H +#define INCLUDED_OFFSET_KEYFRAMES_COMMAND_HELPER_H 1 + +#pragma once + +// Data model +#include "UICDMHandles.h" +#include "IDocumentEditor.h" + +namespace Q3DStudio { +class IDocumentEditor; +} + +//============================================================================== +// Classes +//============================================================================== +class CCmdDataModelSetKeyframeTime; + +class COffsetKeyframesCommandHelper : public Q3DStudio::CUpdateableDocumentEditor +{ +protected: + CDoc &m_Doc; + +public: + COffsetKeyframesCommandHelper(CDoc &inDoc); + ~COffsetKeyframesCommandHelper(); + + void SetCommandTime(UICDM::CUICDMKeyframeHandle inKeyframe, long inTime); + void Finalize(); + void Rollback() { RollbackEditor(); } +}; + +#endif
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h new file mode 100644 index 00000000..130f6d20 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PASTE_KEYFRAME_COMMAND_HELPER_H +#define INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H 1 + +#pragma once + +//============================================================================== +// Include +//============================================================================== +#include "CmdDataModelInsertKeyframe.h" +#include "UICDMPropertyDefinition.h" +#include "UICDMDataCore.h" + +// This caches all copied keyframes' time and data, for a paste action. +// This has to deal with the actual data and not keyframe handles, because a prior Cut can +// invalidate those handles. +class CPasteKeyframeCommandHelper +{ +protected: + typedef std::vector<CCmdDataModelInsertKeyframe::STimeKeyframeData> TCopiedKeyframeList; + TCopiedKeyframeList m_CopiedKeyframeList; + +public: // Construction + CPasteKeyframeCommandHelper() {} + ~CPasteKeyframeCommandHelper() {} + + // inTime should be relative to the earliest keyframe time in this list + void AddKeyframeData(UICDM::CUICDMPropertyHandle inProperty, float inKeyframeTime, + UICDM::SGetOrSetKeyframeInfo *inInfos, size_t inInfoCount) + { + m_CopiedKeyframeList.push_back(CCmdDataModelInsertKeyframe::STimeKeyframeData( + inProperty, inKeyframeTime, inInfos, inInfoCount)); + } + + bool HasCopiedKeyframes() const { return !m_CopiedKeyframeList.empty(); } + + // Triggered by a "Paste Keyframe" action + // Note: The logic is based on what the Animation Manager in the old system used to do. + // 1. The condition for paste to occur is that the property name matches. + // The old data model has a limitation that if the destination property is a linked property, + // the source has to come from the same instance, most likely a easy way out than to deal with + // with having to 'sync' all linked animation tracks. + // but that is not an issue in the new data model. + // + // 2. The first pasted keyframe is at current view time and the rest are offset accordingly. + CCmdDataModelInsertKeyframe *GetCommand(CDoc *inDoc, long inTimeOffsetInMilliseconds, + UICDM::CUICDMInstanceHandle inTargetInstance) + { + using namespace UICDM; + + CCmdDataModelInsertKeyframe *theInsertKeyframesCommand = nullptr; + TCopiedKeyframeList::iterator theIter = m_CopiedKeyframeList.begin(); + UICDM::IPropertySystem *thePropertySystem = inDoc->GetStudioSystem()->GetPropertySystem(); + CClientDataModelBridge *theBridge = inDoc->GetStudioSystem()->GetClientDataModelBridge(); + + for (; theIter != m_CopiedKeyframeList.end(); ++theIter) { + TCharStr thePropertyName = thePropertySystem->GetName(theIter->m_Property); + DataModelDataType::Value thePropertyType = + thePropertySystem->GetDataType(theIter->m_Property); + CUICDMPropertyHandle theTargetPropertyHandle = + theBridge->GetAggregateInstancePropertyByName(inTargetInstance, thePropertyName); + if (theTargetPropertyHandle.Valid()) // property exists on target + { + // sanity check for type match + DataModelDataType::Value theTargetPropertyType = + thePropertySystem->GetDataType(theTargetPropertyHandle); + if (theTargetPropertyType == thePropertyType) { + // 2. Offset keyframe time by current view time + double milliseconds = theIter->m_KeyframeTime * 1000.0; + double theTimeInMilliseconds = milliseconds + inTimeOffsetInMilliseconds; + float theTimeInSeconds = static_cast<float>(theTimeInMilliseconds / 1000.0); + + if (!theInsertKeyframesCommand) + theInsertKeyframesCommand = new CCmdDataModelInsertKeyframe( + inDoc, inTargetInstance, theTargetPropertyHandle, theTimeInSeconds, + theIter->m_Infos, theIter->m_ValidInfoCount); + else + theInsertKeyframesCommand->AddKeyframeData( + theTargetPropertyHandle, theTimeInSeconds, theIter->m_Infos, + theIter->m_ValidInfoCount); + } + } + } + return theInsertKeyframesCommand; + } + + void Clear() { m_CopiedKeyframeList.clear(); } +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp new file mode 100644 index 00000000..286a899f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "PathAnchorPointTimelineItemBinding.h" +#include "EmptyTimelineTimebar.h" + +using namespace UICDM; + +CPathAnchorPointTimelineItemBinding::CPathAnchorPointTimelineItemBinding( + CTimelineTranslationManager *inMgr, CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) +{ +} + +ITimelineTimebar *CPathAnchorPointTimelineItemBinding::GetTimebar() +{ + return new CEmptyTimelineTimebar(); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h new file mode 100644 index 00000000..2bc3f8d6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef PATH_ANCHOR_POINT_TIMELINE_ITEM_BINDING +#define PATH_ANCHOR_POINT_TIMELINE_ITEM_BINDING +#pragma once + +#include "UICDMTimelineItemBinding.h" +#include "UICDMDataTypes.h" +#include <boost/tuple/tuple.hpp> + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; +class CBaseStateRow; + +//============================================================================= +/** + * Binding to a UICDM object of Material type + */ +class CPathAnchorPointTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: // Construction + CPathAnchorPointTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + + bool ShowToggleControls() const override { return false; } + bool IsVisible() const override { return true; } + void SetVisible(bool) override {} + ITimelineTimebar *GetTimebar() override; + bool IsLocked() const override { return false; } + void SetLocked(bool) override {} + bool IsShy() const override { return false; } + void SetShy(bool) override {} + Q3DStudio::CString GetName() const override { return L"Anchor Point"; } + void SetName(const Q3DStudio::CString &) override {} +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp new file mode 100644 index 00000000..3fbed168 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "PathTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "Doc.h" + +bool CPathTimelineItemBinding::IsExternalizeable() +{ + // If this path has subpath children, then it is externalizeable. + return m_TransMgr->GetDoc()->GetDocumentReader().IsPathExternalizeable(GetInstance()); +} + +void CPathTimelineItemBinding::Externalize() +{ + Q3DStudio::ScopedDocumentEditor(*m_TransMgr->GetDoc(), L"Externalize Path Buffer", __FILE__, + __LINE__) + ->ExternalizePath(GetInstance()); +} + +bool CPathTimelineItemBinding::IsInternalizeable() +{ + // If this path has a sourcepath, then it might be internalizeable + return m_TransMgr->GetDoc()->GetDocumentReader().IsPathInternalizeable(GetInstance()); +} + +void CPathTimelineItemBinding::Internalize() +{ + Q3DStudio::ScopedDocumentEditor(*m_TransMgr->GetDoc(), L"Internalize Path Buffer", __FILE__, + __LINE__) + ->InternalizePath(GetInstance()); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h new file mode 100644 index 00000000..1be4b2e1 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef PATH_TIMELINE_ITEM_BINDING +#define PATH_TIMELINE_ITEM_BINDING +#pragma once +#include "UICDMTimelineItemBinding.h" +#include "UICDMDataTypes.h" +#include <boost/tuple/tuple.hpp> + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; +class CBaseStateRow; + +//============================================================================= +/** + * Binding to a UICDM object of Material type + */ +class CPathTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: // Construction + CPathTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr, inDataHandle) + { + } + + bool IsExternalizeable() override; + void Externalize() override; + bool IsInternalizeable() override; + void Internalize() override; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp new file mode 100644 index 00000000..ce381f44 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "SlideTimelineItemBinding.h" +#include "BaseStateRow.h" + +// Data model specific +#include "Doc.h" +#include "CmdGeneric.h" +#include "EmptyTimelineTimebar.h" + +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" +#include "ClientDataModelBridge.h" + +using namespace UICDM; + +CSlideTimelineItemBinding::CSlideTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : CUICDMTimelineItemBinding(inMgr) +{ + UICDM::CUICDMSlideHandle theSlideHandle = + m_StudioSystem->GetSlideSystem()->GetSlideByInstance(inDataHandle); + + // Get the owning component of m_SlideHandle. + // This should return CAsset OBJTYPE_SCENE or OBJTYPE_COMPONENT. + UICDM::CUICDMInstanceHandle theInstance = + m_StudioSystem->GetClientDataModelBridge()->GetOwningComponentInstance(theSlideHandle); + SetInstanceHandle(theInstance); + + // Listen to change on Asset name + IStudioFullSystemSignalProvider *theEngine = m_StudioSystem->GetFullSystemSignalProvider(); + std::function<void(CUICDMInstanceHandle, CUICDMPropertyHandle)> theSetter( + std::bind(&CSlideTimelineItemBinding::OnPropertyChanged, this, std::placeholders::_2)); + m_Connection = theEngine->ConnectInstancePropertyValue( + std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void( + CUICDMInstanceHandle, CUICDMPropertyHandle)>>, + std::placeholders::_1, std::placeholders::_2, theInstance, + m_StudioSystem->GetClientDataModelBridge()->GetNameProperty(), theSetter)); +} + +ITimelineTimebar *CSlideTimelineItemBinding::GetTimebar() +{ // No timebars on slides + return new CEmptyTimelineTimebar(); +} + +void CSlideTimelineItemBinding::SetName(const Q3DStudio::CString & /*inName*/) +{ + // Do nothing because name is read only +} + +void CSlideTimelineItemBinding::Bind(CBaseStateRow *inRow) +{ + CUICDMTimelineItemBinding::Bind(inRow); + GetRow()->SetNameReadOnly(true); +} + +bool CSlideTimelineItemBinding::IsValidTransaction(EUserTransaction inTransaction) +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + switch (inTransaction) { + // Disable the following context menus + case EUserTransaction_Rename: + case EUserTransaction_MakeComponent: + case EUserTransaction_EditComponent: + return false; + } + + return CUICDMTimelineItemBinding::IsValidTransaction(inTransaction); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h new file mode 100644 index 00000000..759fdfb9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_SLIDE_TIMELINEITEM_BINDING_H +#define INCLUDED_SLIDE_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "UICDMTimelineItemBinding.h" + +//============================================================================== +// Classes +//============================================================================== +class ITimelineItem; +class CTimelineTranslationManager; +class CBaseStateRow; + +//============================================================================= +/** + * Binding to a UICDM object of Slide type + */ +class CSlideTimelineItemBinding : public CUICDMTimelineItemBinding +{ +public: + CSlideTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + ~CSlideTimelineItemBinding() {} + + // CUICDMTimelineItemBinding + ITimelineTimebar *GetTimebar() override; + void SetName(const Q3DStudio::CString &inName) override; + void Bind(CBaseStateRow *inRow) override; + bool IsValidTransaction(EUserTransaction inTransaction) override; + + // No properties + long GetPropertyCount() override { return 0; } + ITimelineItemProperty *GetProperty(long) override { return nullptr; } + void LoadProperties() override {} + + // Eye/Lock toggles are not applicable + bool ShowToggleControls() const override { return false; } + bool IsLockedEnabled() const override { return false; } + bool IsVisibleEnabled() const override { return false; } + + // Shy, Locked, Visible are not applicable + bool IsShy() const override { return false; } + void SetShy(bool) override {} + bool IsLocked() const override { return false; } + void SetLocked(bool) override {} + bool IsVisible() const override { return true; } + void SetVisible(bool) override {} + + // Keyframes, not applicable to a Slide + void InsertKeyframe() override {} + void DeleteAllChannelKeyframes() override {} + long GetKeyframeCount() const override { return 0; } + IKeyframe *GetKeyframeByTime(long) const override { return nullptr; } + IKeyframe *GetKeyframeByIndex(long) const override { return nullptr; } + long OffsetSelectedKeyframes(long) override { return 0; } + void CommitChangedKeyframes() override {} + void OnEditKeyframeTime(long, long) override {} + // IKeyframeSelector + void SelectKeyframes(bool, long inTime = -1) override { Q_UNUSED(inTime); } + + // Keyframe manipulation, not applicable + void UIRefreshPropertyKeyframe(long inOffset) override { Q_UNUSED(inOffset); } + bool HasDynamicKeyframes(long inTime) override + { + Q_UNUSED(inTime); + return false; + } + void SetDynamicKeyframes(long inTime, bool inDynamic) override + { + Q_UNUSED(inTime); + Q_UNUSED(inDynamic); + } + void DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI) override + { + Q_UNUSED(inSelected); + Q_UNUSED(inTime); + Q_UNUSED(inUpdateUI); + } + void OnPropertySelection(long inTime) override { Q_UNUSED(inTime); } + +protected: + std::shared_ptr<UICDM::ISignalConnection> + m_Connection; // Callback when the Asset name changes + + bool AmITimeParent() const override { return true; } +}; + +#endif // INCLUDED_SLIDE_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp new file mode 100644 index 00000000..4bd1fc01 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "TimelineBreadCrumbProvider.h" +#include "Core.h" + +// Link to data model +#include "Doc.h" +#include "StudioApp.h" +#include "Cmd.h" +#include "ResourceCache.h" +#include "Strings.h" +#include "StringLoader.h" +#include "CColor.h" + +#include "ClientDataModelBridge.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" +#include "CmdActivateSlide.h" + +using namespace UICDM; + +//============================================================================= +/** + * Constructor + */ +CTimelineBreadCrumbProvider::CTimelineBreadCrumbProvider(CDoc *inDoc) + : m_Doc(inDoc) +{ +} + +//============================================================================= +/** + */ +CTimelineBreadCrumbProvider::~CTimelineBreadCrumbProvider() +{ +} + +//============================================================================= +/** + * determine the color and text string for this breadcrumb + */ +static inline void FillBreadCrumb(SBreadCrumb &outBreadCrumb, + UICDM::CUICDMInstanceHandle inInstance, CDoc *inDoc) +{ + // Get the MasterSlide Handle associated with inAsset + CClientDataModelBridge *theBridge = inDoc->GetStudioSystem()->GetClientDataModelBridge(); + ISlideSystem *theSlideSystem = inDoc->GetStudioSystem()->GetSlideSystem(); + Q3DStudio::CId theId = theBridge->GetGUID(inInstance); + UICDM::CUICDMSlideHandle theMasterSlide = + theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId)); + ASSERT(theMasterSlide.Valid()); // it should be valid because inAsset should be OBJTYPE_SCENE or + // non-library OBJTYPE_COMPONENT + + // Get the active slide index of the master slide. Master Slide always has index 0 + long theActiveIndex = theSlideSystem->GetActiveSlideIndex(theMasterSlide); + bool theIsMaster = (theActiveIndex == 0); + + // Determine the color + outBreadCrumb.m_Color = + theIsMaster ? CColor(0, 0, 255) : CColor(0, 0, 0); // blue for master, black otherwise + + // Determine the text string + outBreadCrumb.m_String = theBridge->GetName(inInstance).toQString(); + outBreadCrumb.m_String += " ("; + if (theIsMaster) + outBreadCrumb.m_String += ::LoadResourceString(IDS_OBJTYPE_MASTER).toQString(); + else { + CUICDMSlideHandle theActiveSlide = + theSlideSystem->GetSlideByIndex(theMasterSlide, theActiveIndex); + CUICDMInstanceHandle theInstanceHandle = theSlideSystem->GetSlideInstance(theActiveSlide); + ASSERT(theInstanceHandle.Valid()); + outBreadCrumb.m_String += theBridge->GetName(theInstanceHandle).toQString(); + } + outBreadCrumb.m_String += ")"; +} + +//============================================================================= +/** + * return the trail of breadcrumb. + * This constructs a list of the "time context tree" from Scene down to the current active time + * context. + * @param inRefresh true to refresh the list, false to get existing. + */ +CTimelineBreadCrumbProvider::TTrailList +CTimelineBreadCrumbProvider::GetTrail(bool inRefresh /*= true */) +{ + if (inRefresh) + RefreshSlideList(); + + TTrailList theList; + for (size_t theIndex = 0; theIndex < m_BreadCrumbList.size(); ++theIndex) { + SBreadCrumb theBreadCrumb; + FillBreadCrumb(theBreadCrumb, m_BreadCrumbList[theIndex], m_Doc); + theList.push_back(theBreadCrumb); + } + return theList; +} + +//============================================================================= +/** + * switch current time context to the one 'represented' by the breadcrumbs. + * @param inTrailIndex index into the trail list + */ +void CTimelineBreadCrumbProvider::OnBreadCrumbClicked(long inTrailIndex) +{ + if (inTrailIndex >= 0 && inTrailIndex < (long)m_BreadCrumbList.size()) { + CCmdActivateSlide *theCmd = new CCmdActivateSlide(m_Doc, m_BreadCrumbList[inTrailIndex]); + theCmd->SetForceRefresh(false); + m_Doc->GetCore()->ExecuteCommand(theCmd, false); + } +} + +QPixmap CTimelineBreadCrumbProvider::GetRootImage() const +{ + return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_scene.png"); +} + +QPixmap CTimelineBreadCrumbProvider::GetBreadCrumbImage() const +{ + return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_button.png"); +} + +QPixmap CTimelineBreadCrumbProvider::GetSeparatorImage() const +{ + return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_colon_button.png"); +} + +QPixmap CTimelineBreadCrumbProvider::GetActiveBreadCrumbImage() const +{ + return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_grey_button.png"); +} + +//============================================================================= +/** + * Called when active time context is changed. + */ +void CTimelineBreadCrumbProvider::RefreshSlideList() +{ + ClearSlideList(); + + UICDM::CUICDMInstanceHandle theActiveRoot = m_Doc->GetActiveRootInstance(); + if (!theActiveRoot.Valid()) + return; + FillSlideList(theActiveRoot); +} + +//============================================================================= +/** + * Callback that inAsset has its name changed, fire off a signal to the UI control. + * All the assets' signals are connected to this object and we'll let the UI control check iterate + * through the list for changes and refresh. + * Alternative we can set up additional classes that listens to specific assets and only the asset + * affected refreshed. the former is easier for now. + */ +void CTimelineBreadCrumbProvider::OnNameDirty() +{ + SigBreadCrumbUpdate(); +} + +void CTimelineBreadCrumbProvider::ClearSlideList() +{ + m_Connections.clear(); + m_BreadCrumbList.clear(); +} + +//============================================================================= +/** + * This will recurse up the time context tree, so that we can fill the list in a top-down (i.e + * Scene) first manner + */ +void CTimelineBreadCrumbProvider::FillSlideList(UICDM::CUICDMInstanceHandle inInstance) +{ + if (!inInstance.Valid()) + return; + + CClientDataModelBridge *theBridge = m_Doc->GetStudioSystem()->GetClientDataModelBridge(); + ISlideSystem *theSlideSystem = m_Doc->GetStudioSystem()->GetSlideSystem(); + Q3DStudio::CId theId = theBridge->GetGUID(inInstance); + + // Recurse + FillSlideList(theBridge->GetParentComponent(inInstance)); + + m_BreadCrumbList.push_back(inInstance); + + CUICDMPropertyHandle theNameProp = + m_Doc->GetStudioSystem()->GetClientDataModelBridge()->GetNameProperty(); + IStudioFullSystemSignalProvider *theEngine = + m_Doc->GetStudioSystem()->GetFullSystemSignalProvider(); + std::function<void(CUICDMInstanceHandle, CUICDMPropertyHandle)> theSetter( + std::bind(&CTimelineBreadCrumbProvider::OnNameDirty, this)); + + // Listen to name changes on the Asset + m_Connections.push_back(theEngine->ConnectInstancePropertyValue( + std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void( + CUICDMInstanceHandle, CUICDMPropertyHandle)>>, + std::placeholders::_1, std::placeholders::_2, inInstance, theNameProp, theSetter))); + + // Listen to name changes on the non-master Slides + UICDM::CUICDMSlideHandle theMasterSlide = + theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId)); + long theSlideCount = (long)theSlideSystem->GetSlideCount(theMasterSlide); + + for (long theIndex = 1; theIndex < theSlideCount; ++theIndex) { + CUICDMSlideHandle theSlide = theSlideSystem->GetSlideByIndex(theMasterSlide, theIndex); + CUICDMInstanceHandle theSlideInstance = theSlideSystem->GetSlideInstance(theSlide); + m_Connections.push_back(theEngine->ConnectInstancePropertyValue( + std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void( + CUICDMInstanceHandle, CUICDMPropertyHandle)>>, + std::placeholders::_1, std::placeholders::_2, theSlideInstance, theNameProp, theSetter))); + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h new file mode 100644 index 00000000..d71b57b9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_BREADCRUMBPROVIDER_H +#define INCLUDED_BREADCRUMBPROVIDER_H 1 + +#pragma once + +#include "IBreadCrumbProvider.h" +#include "UICDMSignals.h" + +// Link to data model +class CDoc; +class CTimelineBreadCrumbProvider; + +//============================================================================= +/** + * Bread crumb provider for displaying a trail of time contexts + */ +class CTimelineBreadCrumbProvider : public IBreadCrumbProvider +{ +public: + CTimelineBreadCrumbProvider(CDoc *inDoc); + virtual ~CTimelineBreadCrumbProvider(); + + TTrailList GetTrail(bool inRefresh = true) override; + void OnBreadCrumbClicked(long inTrailIndex) override; + + QPixmap GetRootImage() const override; + QPixmap GetBreadCrumbImage() const override; + QPixmap GetSeparatorImage() const override; + QPixmap GetActiveBreadCrumbImage() const override; + + void RefreshSlideList(); + void OnNameDirty(); + +protected: + void ClearSlideList(); + void FillSlideList(UICDM::CUICDMInstanceHandle inInstance); + +protected: + std::vector<UICDM::CUICDMInstanceHandle> m_BreadCrumbList; + CDoc *m_Doc; + std::vector<std::shared_ptr<UICDM::ISignalConnection>> + m_Connections; /// connections to the UICDM +}; + +#endif // INCLUDED_BREADCRUMBPROVIDER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp new file mode 100644 index 00000000..cc28b0cc --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp @@ -0,0 +1,599 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TimelineTranslationManager.h" +#include "SlideTimelineItemBinding.h" +#include "GroupTimelineItemBinding.h" +#include "BehaviorTimelineItemBinding.h" +#include "MaterialTimelineItemBinding.h" +#include "ImageTimelineItemBinding.h" +#include "PathAnchorPointTimelineItemBinding.h" +#include "PathTimelineItemBinding.h" +#include "LayerTimelineItemBinding.h" +#include "KeyframesManager.h" +#include "TimelineBreadCrumbProvider.h" +#include "BaseStateRow.h" +#include "PropertyRow.h" +#include "IDoc.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" +#include "UICDMSignals.h" + +// Link to Data model +#include "ClientDataModelBridge.h" +#include "UICDMDataCore.h" +#include "Doc.h" //Because we need to access Client Data Model Bridge +#include "StudioApp.h" +#include "Core.h" + +using namespace UICDM; + +CTimelineTranslationManager::CTimelineTranslationManager() +{ + m_KeyframesManager = new CKeyframesManager(this); + m_BreadCrumbProvider = new CTimelineBreadCrumbProvider(g_StudioApp.GetCore()->GetDoc()); +} + +CTimelineTranslationManager::~CTimelineTranslationManager() +{ + // clean up all bindings + Clear(); + m_Connections.clear(); + delete m_KeyframesManager; + delete m_BreadCrumbProvider; +} + +ITimelineItemBinding *CTimelineTranslationManager::GetOrCreate(CUICDMInstanceHandle inInstance) +{ + ITimelineItemBinding *theBinding = GetBinding(inInstance); + if (!theBinding) { + CUICDMTimelineItemBinding *theReturn = nullptr; + UICDM::IPropertySystem *thePropertySystem = GetStudioSystem()->GetPropertySystem(); + CUICDMPropertyHandle theTypeProperty = + thePropertySystem->GetAggregateInstancePropertyByName(inInstance, L"type"); + + SValue theTypeValue; + thePropertySystem->GetInstancePropertyValue(inInstance, theTypeProperty, theTypeValue); + + std::wstring theWideTypeString(UICDM::get<TDataStrPtr>(theTypeValue)->GetData()); + + if (theWideTypeString == L"Material" || theWideTypeString == L"CustomMaterial" + || theWideTypeString == L"ReferencedMaterial") + theReturn = new CMaterialTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Image") + theReturn = new CImageTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Group" || theWideTypeString == L"Component") + theReturn = new CGroupTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Behavior") + theReturn = new CBehaviorTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Slide") + theReturn = new CSlideTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"PathAnchorPoint") + theReturn = new CPathAnchorPointTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Path") + theReturn = new CPathTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Layer") + theReturn = new CLayerTimelineItemBinding(this, inInstance); + else if (theWideTypeString == L"Model" || theWideTypeString == L"Text" + || theWideTypeString == L"Camera" || theWideTypeString == L"Effect" + || theWideTypeString == L"Light" || theWideTypeString == L"RenderPlugin" + || theWideTypeString == L"Alias" || theWideTypeString == L"SubPath") + theReturn = new CUICDMTimelineItemBinding(this, inInstance); + else { + // Add support for additional UICDM types here. + ASSERT(0); + } + + m_InstanceHandleBindingMap.insert( + std::make_pair(theReturn->GetInstanceHandle(), theReturn)); + m_InstanceHandleExpandedMap.insert(std::make_pair(theReturn->GetInstanceHandle(), false)); + theBinding = theReturn; + } + + return theBinding; +} + +//============================================================================== +/** + * Create a new CPropertyRow that maps to this ITimelineItemProperty. + * The caller is assumed to have ensured that this is only called once per property binding. + */ +void CTimelineTranslationManager::CreateNewPropertyRow( + ITimelineItemProperty *inTimelineItemPropertyBinding, CBaseStateRow *inParentRow, + CPropertyRow *inNextRow) +{ + if (!inParentRow || !inTimelineItemPropertyBinding) + return; + + CPropertyRow *theNewRow = new CPropertyRow(inTimelineItemPropertyBinding); + inParentRow->AddPropertyRow(theNewRow, inNextRow); + inTimelineItemPropertyBinding->Bind(theNewRow); +} + +//============================================================================== +/** + * Does the reverse of CreateNewPropertyRow, when a property has been de-animated. + */ +void CTimelineTranslationManager::RemovePropertyRow( + ITimelineItemProperty *inTimelineItemPropertyBinding) +{ + CPropertyRow *theRow = nullptr; + if (!inTimelineItemPropertyBinding + || (theRow = inTimelineItemPropertyBinding->GetRow()) == nullptr) + return; + + CBaseStateRow *theParentRow = theRow->GetParentRow(); + if (theParentRow) { + inTimelineItemPropertyBinding->Release(); + theParentRow->RemovePropertyRow(theRow); // this implicitly delete the row + } +} + +//============================================================================== +/** + * Clear all bindings, typically when a presentation is closed. + */ +void CTimelineTranslationManager::Clear() +{ + // clean up all bindings + m_InstanceHandleBindingMap.clear(); +} + +//============================================================================== +/** + * Called when the associated UI is no longer valid. + */ +void CTimelineTranslationManager::Unregister(ITimelineItemBinding *inTimelineItem) +{ + // UICDM + bool theDeselectItem = false; + TInstanceHandleBindingMap::iterator theInstanceIter = m_InstanceHandleBindingMap.begin(); + for (; theInstanceIter != m_InstanceHandleBindingMap.end(); ++theInstanceIter) { + if (theInstanceIter->second == inTimelineItem) { + // If this is the currently selected object and make sure that is cleared. + UICDM::CUICDMInstanceHandle theSelectedInstance = + g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance(); + if (theSelectedInstance.Valid() && theSelectedInstance == theInstanceIter->first) + theDeselectItem = true; + + m_InstanceHandleBindingMap.erase(theInstanceIter); + break; + } + } + + delete inTimelineItem; +} + +CKeyframesManager *CTimelineTranslationManager::GetKeyframesManager() const +{ + return m_KeyframesManager; +} + +IBreadCrumbProvider *CTimelineTranslationManager::GetBreadCrumbProvider() const +{ + return m_BreadCrumbProvider; +} + +CBaseStateRow *CTimelineTranslationManager::GetSelectedRow() const +{ + ITimelineItemBinding *theBinding = GetSelectedBinding(); + if (theBinding) + return theBinding->GetRow(); + return nullptr; +} + +long CTimelineTranslationManager::GetCurrentViewTime() const +{ + return g_StudioApp.GetCore()->GetDoc()->GetCurrentViewTime(); +} + +//============================================================================== +/** + * @return the Binding object that corresponds to this instance. + */ +CUICDMTimelineItemBinding * +CTimelineTranslationManager::GetBinding(CUICDMInstanceHandle inHandle) const +{ + TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.find(inHandle); + if (theIter != m_InstanceHandleBindingMap.end()) + return theIter->second; + return nullptr; +} + +CUICDMTimelineItemBinding *CTimelineTranslationManager::GetSelectedBinding() const +{ + UICDM::CUICDMInstanceHandle theSelectedInstance = + g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance(); + if (theSelectedInstance.Valid()) { + CUICDMTimelineItemBinding *theBinding = GetBinding(theSelectedInstance); + return theBinding; + } + return nullptr; +} + +//============================================================================== +/** + * Triggered from individual binding classes, to clear all keyframe selection + */ +void CTimelineTranslationManager::ClearKeyframeSelection() +{ + m_KeyframesManager->DeselectAllKeyframes(); +} + +//============================================================================== +/** + * Set up callbacks for animation changes + */ +void CTimelineTranslationManager::OnNewPresentation() +{ + m_Connections.clear(); + m_InstanceHandleExpandedMap.clear(); + + IStudioFullSystemSignalProvider *theSignalProvider = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider(); + m_Connections.push_back(theSignalProvider->ConnectAnimationCreated( + std::bind(&CTimelineTranslationManager::OnAnimationCreated, this, + std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectAnimationDeleted( + std::bind(&CTimelineTranslationManager::OnAnimationDeleted, this, + std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectPropertyLinked( + std::bind(&CTimelineTranslationManager::OnPropertyLinked, this, + std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectPropertyUnlinked( + std::bind(&CTimelineTranslationManager::OnPropertyUnlinked, this, + std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectKeyframeInserted( + std::bind(&CTimelineTranslationManager::OnKeyframeInserted, this, + std::placeholders::_1, std::placeholders::_2))); + m_Connections.push_back(theSignalProvider->ConnectKeyframeErased( + std::bind(&CTimelineTranslationManager::OnKeyframeDeleted, this, + std::placeholders::_1, std::placeholders::_2))); + m_Connections.push_back(theSignalProvider->ConnectKeyframeUpdated( + std::bind(&CTimelineTranslationManager::OnKeyframeUpdated, this, std::placeholders::_1))); + m_Connections.push_back(theSignalProvider->ConnectInstancePropertyValue( + std::bind(&CTimelineTranslationManager::OnPropertyChanged, this, + std::placeholders::_1, std::placeholders::_2))); + m_Connections.push_back(theSignalProvider->ConnectFirstKeyframeDynamicSet( + std::bind(&CTimelineTranslationManager::OnDynamicKeyframeChanged, this, + std::placeholders::_1, std::placeholders::_2))); + + m_Connections.push_back(theSignalProvider->ConnectInstanceCreated( + std::bind(&CTimelineTranslationManager::OnAssetCreated, this, std::placeholders::_1))); + m_Connections.push_back(theSignalProvider->ConnectInstanceDeleted( + std::bind(&CTimelineTranslationManager::OnAssetDeleted, this, std::placeholders::_1))); + + m_Connections.push_back(theSignalProvider->ConnectActionCreated( + std::bind(&CTimelineTranslationManager::OnActionEvent, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectActionDeleted( + std::bind(&CTimelineTranslationManager::OnActionEvent, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + + Q3DStudio::CGraph &theGraph(*g_StudioApp.GetCore()->GetDoc()->GetAssetGraph()); + m_Connections.push_back(theGraph.ConnectChildAdded( + std::bind(&CTimelineTranslationManager::OnChildAdded, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theGraph.ConnectChildRemoved( + std::bind(&CTimelineTranslationManager::OnChildRemoved, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_Connections.push_back(theGraph.ConnectChildMoved( + std::bind(&CTimelineTranslationManager::OnChildMoved, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, std::placeholders::_4))); +} + +//============================================================================== +/** + * Selection events on the old data model was triggered via signals on the actual objects. + * For the new data model, it would be via this OnSelectionChange event. + */ +void CTimelineTranslationManager::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable) +{ + // Deselect all items + TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.begin(); + for (; theIter != m_InstanceHandleBindingMap.end(); ++theIter) { + ITimelineItemBinding *theBinding = theIter->second; + CBaseStateRow *theRow = theBinding->GetRow(); + if (theRow) + theRow->OnSelected(false); + } + + // Select new + if (inNewSelectable) + SetSelected(inNewSelectable, true); +} + +CDoc *CTimelineTranslationManager::GetDoc() const +{ + return dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc()); +} + +CStudioSystem *CTimelineTranslationManager::GetStudioSystem() const +{ + // TODO: figure if we can just deal with IDoc instead of CDoc + return g_StudioApp.GetCore()->GetDoc()->GetStudioSystem(); +} + +void CTimelineTranslationManager::OnAnimationCreated(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->AddPropertyRow(inProperty); +} + +void CTimelineTranslationManager::OnAnimationDeleted(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->RemovePropertyRow(inProperty); +} + +void CTimelineTranslationManager::OnPropertyLinked(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->OnPropertyLinked(inProperty); +} + +void CTimelineTranslationManager::OnPropertyUnlinked(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + OnPropertyLinked(inInstance, inProperty); +} + +void CTimelineTranslationManager::RefreshKeyframe(CUICDMAnimationHandle inAnimation, + CUICDMKeyframeHandle inKeyframe, + ETimelineKeyframeTransaction inTransaction) +{ + CUICDMTimelineItemBinding *theTimelineBinding = nullptr; + if (GetStudioSystem()->GetAnimationCore()->AnimationValid(inAnimation)) { + SAnimationInfo theAnimationInfo = + GetStudioSystem()->GetAnimationCore()->GetAnimationInfo(inAnimation); + theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(theAnimationInfo.m_Instance)); + + if (theTimelineBinding) + theTimelineBinding->RefreshPropertyKeyframe(theAnimationInfo.m_Property, inKeyframe, + inTransaction); + } + // else, animation has been nuked, ignore this event, we'll get a AnimationDelete +} + +void CTimelineTranslationManager::OnKeyframeInserted(CUICDMAnimationHandle inAnimation, + CUICDMKeyframeHandle inKeyframe) +{ + RefreshKeyframe(inAnimation, inKeyframe, ETimelineKeyframeTransaction_Add); +} + +void CTimelineTranslationManager::OnKeyframeDeleted(CUICDMAnimationHandle inAnimation, + CUICDMKeyframeHandle inKeyframe) +{ + RefreshKeyframe(inAnimation, inKeyframe, ETimelineKeyframeTransaction_Delete); +} + +void CTimelineTranslationManager::OnKeyframeUpdated(CUICDMKeyframeHandle inKeyframe) +{ + IAnimationCore *theAnimationCore = GetStudioSystem()->GetAnimationCore(); + if (theAnimationCore->KeyframeValid(inKeyframe)) { + CUICDMAnimationHandle theAnimationHandle = + theAnimationCore->GetAnimationForKeyframe(inKeyframe); + RefreshKeyframe(theAnimationHandle, inKeyframe, ETimelineKeyframeTransaction_Update); + } + // else, keyframe has been nuked, ignore this event, we'll get a KeyframeDeleted +} + +void CTimelineTranslationManager::OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->OnPropertyChanged(inProperty); +} + +void CTimelineTranslationManager::OnDynamicKeyframeChanged(UICDM::CUICDMAnimationHandle inAnimation, + bool inDynamic) +{ + Q_UNUSED(inDynamic); + + CUICDMTimelineItemBinding *theTimelineBinding = nullptr; + if (GetStudioSystem()->GetAnimationCore()->AnimationValid(inAnimation)) { + SAnimationInfo theAnimationInfo = + GetStudioSystem()->GetAnimationCore()->GetAnimationInfo(inAnimation); + theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(theAnimationInfo.m_Instance)); + if (theTimelineBinding) + theTimelineBinding->RefreshPropertyKeyframe( + theAnimationInfo.m_Property, 0, ETimelineKeyframeTransaction_DynamicChanged); + } +} + +void CTimelineTranslationManager::OnAssetCreated(UICDM::CUICDMInstanceHandle inInstance) +{ + CClientDataModelBridge *theDataModelBridge = GetStudioSystem()->GetClientDataModelBridge(); + + if (theDataModelBridge->IsSceneGraphInstance(inInstance)) + EnsureLoaded(inInstance); +} + +void CTimelineTranslationManager::OnAssetDeleted(UICDM::CUICDMInstanceHandle inInstance) +{ + // You can't assume the instance is valid. Someone may have deleted a large number of items + // from the model and then decided to send notifications after the fact. + // if the created asset is library asset, do nothing + // start to add the scene asset to the timeline + CUICDMTimelineItemBinding *theItemBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance)); + if (theItemBinding) { + CUICDMTimelineItemBinding *theParentBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(theItemBinding->GetParent()); + if (theParentBinding) + theParentBinding->OnDeleteChild(inInstance); + } +} + +void CTimelineTranslationManager::OnChildAdded(int /*inParent*/, int inChild, long /*inIndex*/) +{ + OnAssetCreated(inChild); +} +void CTimelineTranslationManager::OnChildRemoved(int /*inParent*/, int inChild, long /*inIndex*/) +{ + OnAssetDeleted(inChild); +} +void CTimelineTranslationManager::OnChildMoved(int /*inParent*/, int inChild, long /*inOldIndex*/, + long /*inNewIndex*/) +{ + OnAssetDeleted(inChild); + OnAssetCreated(inChild); +} + +//============================================================================== +/** + * Callback method whenever an action is either created or removed. + * Basically, it tells the owner of the action to update its timeline control to + * update the icon that shows action association status + */ +void CTimelineTranslationManager::OnActionEvent(UICDM::CUICDMActionHandle inAction, + UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inOwner) +{ + Q_UNUSED(inAction); + + // the slide that action is added to is the current slide or + // is added to the master slide of the current slide + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inOwner)); + if (theTimelineBinding) + theTimelineBinding->UpdateActionStatus(); +} + +//============================================================================== +/** + * Helper functions to go through ALL binding and clear any keyframes selection. + */ +void CTimelineTranslationManager::ClearBindingsKeyframeSelection() +{ + // UICDM bindings handle their own selections + TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.begin(); + for (; theIter != m_InstanceHandleBindingMap.end(); ++theIter) + theIter->second->DoSelectKeyframes(false, -1, true); +} + +//============================================================================== +/** + * Helper function to find the binding that corresponds to inSelectable and set its selection state + */ +void CTimelineTranslationManager::SetSelected(Q3DStudio::SSelectedValue inSelectable, + bool inSelected) +{ + UICDM::TInstanceHandleList theInstances = inSelectable.GetSelectedInstances(); + for (size_t idx = 0, end = theInstances.size(); idx < end; ++idx) { + CUICDMInstanceHandle theInstance(theInstances[idx]); + if (GetStudioSystem()->IsInstance(theInstance)) { + ITimelineItemBinding *theBinding = EnsureLoaded(theInstance); + if (theBinding) { + CBaseStateRow *theRow = theBinding->GetRow(); + if (theRow) + theRow->OnSelected(inSelected); + } + } + } +} + +ITimelineItemBinding *CTimelineTranslationManager::EnsureLoaded(CUICDMInstanceHandle inHandle) +{ + ITimelineItemBinding *theBinding = GetBinding(inHandle); + bool rowLoaded = theBinding != nullptr && theBinding->GetRow() != nullptr; + if (rowLoaded == false) { + // tell my parent to load me + CClientDataModelBridge *theDataModelBridge = GetStudioSystem()->GetClientDataModelBridge(); + CUICDMInstanceHandle theParent = theDataModelBridge->GetParentInstance(inHandle); + if (theParent.Valid()) { + ITimelineItemBinding *theParentBinding = EnsureLoaded(theParent); + if (theParentBinding) + theParentBinding->GetRow()->LoadChildren(); + + // The LoadChildren has an optimzation such that if it's already loaded, it won't + // recreate again + // So, if we still can't get the binding after LoadChildren, it very likely means that + // this is newly added + // so call OnAddChild to let it just add this. + theBinding = GetBinding(inHandle); + bool rowLoaded = theBinding != nullptr && theBinding->GetRow() != nullptr; + if (theParentBinding && rowLoaded == false) { + // start to add the scene asset to the timeline + CUICDMTimelineItemBinding *theUICDMBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(theParentBinding); + theUICDMBinding->OnAddChild(inHandle); + theBinding = GetBinding(inHandle); + } + } + } + return theBinding; +} + +//============================================================================== +/** + * remember the expanded state for the current presentation + */ +bool CTimelineTranslationManager::IsExpanded(CUICDMInstanceHandle inInstance) const +{ + TInstanceHandleExpandedMap::const_iterator theIter = + m_InstanceHandleExpandedMap.find(inInstance); + if (theIter != m_InstanceHandleExpandedMap.end()) { + return theIter->second; + } + return false; +} + +//============================================================================== +/** + * remember the expanded state for the current presentation + */ +void CTimelineTranslationManager::SetExpanded(CUICDMInstanceHandle inInstance, bool inExpanded) +{ + TInstanceHandleExpandedMap::iterator theIter = m_InstanceHandleExpandedMap.find(inInstance); + if (theIter != m_InstanceHandleExpandedMap.end()) { + theIter->second = inExpanded; + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h new file mode 100644 index 00000000..48f7bebe --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_TIMELINE_TRANSLATIONMANAGER_H +#define INCLUDED_TIMELINE_TRANSLATIONMANAGER_H 1 + +#pragma once + +#include "UICDMHandles.h" +#include "UICDMTimeline.h" + +#include "Doc.h" + +//============================================================================== +// Classes +//============================================================================== +class ITimelineItemBinding; +class ITimelineItemProperty; +class CUICDMTimelineItemBinding; +class CBaseStateRow; +class CPropertyRow; +class CKeyframesManager; +class IBreadCrumbProvider; + +// Link to data model +class CAsset; +class IUICDMSelectable; +class CClientDataModelBridge; + +// UICDM +namespace UICDM { +class CStudioSystem; +class ISignalConnection; +} + +class CDoc; + +//============================================================================= +/** + * There is a TranslationManager per presentation (project) + */ +class CTimelineTranslationManager +{ +protected: // Typedefs + // UICDM support + typedef std::map<UICDM::CUICDMInstanceHandle, CUICDMTimelineItemBinding *> + TInstanceHandleBindingMap; + + // Store expanded state + typedef std::map<UICDM::CUICDMInstanceHandle, bool> TInstanceHandleExpandedMap; // UICDM support + +protected: // Properties + // UICDM support + TInstanceHandleBindingMap m_InstanceHandleBindingMap; + + CKeyframesManager *m_KeyframesManager; + IBreadCrumbProvider *m_BreadCrumbProvider; + std::vector<std::shared_ptr<UICDM::ISignalConnection>> + m_Connections; /// connections to the UICDM + + TInstanceHandleExpandedMap m_InstanceHandleExpandedMap; + +public: + CTimelineTranslationManager(); + ~CTimelineTranslationManager(); + +public: + ITimelineItemBinding *GetOrCreate(UICDM::CUICDMInstanceHandle inInstance); + void CreateNewPropertyRow(ITimelineItemProperty *inTimelineItemPropertyBinding, + CBaseStateRow *inParentRow, CPropertyRow *inNextRow); + void RemovePropertyRow(ITimelineItemProperty *inTimelineItemPropertyBinding); + + void Clear(); + void Unregister(ITimelineItemBinding *inTimelineItem); + + CKeyframesManager *GetKeyframesManager() const; + IBreadCrumbProvider *GetBreadCrumbProvider() const; + CBaseStateRow *GetSelectedRow() const; + long GetCurrentViewTime() const; + CUICDMTimelineItemBinding *GetBinding(UICDM::CUICDMInstanceHandle inHandle) const; + CUICDMTimelineItemBinding *GetSelectedBinding() const; + + void ClearKeyframeSelection(); + void OnNewPresentation(); + void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable); + + UICDM::CStudioSystem *GetStudioSystem() const; + + // UICDM callback + void OnAnimationCreated(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void OnAnimationDeleted(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void OnPropertyLinked(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void OnPropertyUnlinked(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void RefreshKeyframe(UICDM::CUICDMAnimationHandle inAnimation, + UICDM::CUICDMKeyframeHandle inKeyframe, + ETimelineKeyframeTransaction inTransaction); + void OnKeyframeInserted(UICDM::CUICDMAnimationHandle inAnimation, + UICDM::CUICDMKeyframeHandle inKeyframe); + void OnKeyframeDeleted(UICDM::CUICDMAnimationHandle inAnimation, + UICDM::CUICDMKeyframeHandle inKeyframe); + void OnKeyframeUpdated(UICDM::CUICDMKeyframeHandle inKeyframe); + void OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void OnDynamicKeyframeChanged(UICDM::CUICDMAnimationHandle inAnimation, bool inDynamic); + + void OnAssetCreated(UICDM::CUICDMInstanceHandle inInstance); + void OnAssetDeleted(UICDM::CUICDMInstanceHandle inInstance); + void OnChildAdded(int inParent, int inChild, long inIndex); + void OnChildRemoved(int inParent, int inChild, long inIndex); + void OnChildMoved(int inParent, int inChild, long inOldIndex, long inNewIndex); + + void OnActionEvent(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inOwner); + + // Helper function to iterate over all bindings + void ClearBindingsKeyframeSelection(); + CDoc *GetDoc() const; + + // Store expanded state + bool IsExpanded(UICDM::CUICDMInstanceHandle inInstance) const; + void SetExpanded(UICDM::CUICDMInstanceHandle inInstance, bool inExpanded); + +protected: + void SetSelected(Q3DStudio::SSelectedValue inSelectable, bool inSelected); + ITimelineItemBinding *EnsureLoaded(UICDM::CUICDMInstanceHandle inHandle); +}; + +#endif // INCLUDED_TIMELINE_TRANSLATIONMANAGER_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp new file mode 100644 index 00000000..4eb0f906 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "UICDMAssetTimelineKeyframe.h" +#include "UICDMTimelineItemBinding.h" + +using namespace UICDM; + +CUICDMAssetTimelineKeyframe::CUICDMAssetTimelineKeyframe(CUICDMTimelineItemBinding *inOwningBinding, + long inTime) + : m_OwningBinding(inOwningBinding) + , m_Time(inTime) + , m_Selected(false) +{ +} + +CUICDMAssetTimelineKeyframe::~CUICDMAssetTimelineKeyframe() +{ +} + +bool CUICDMAssetTimelineKeyframe::IsSelected() const +{ + return m_Selected; +} + +long CUICDMAssetTimelineKeyframe::GetTime() const +{ + return m_Time; +} + +void CUICDMAssetTimelineKeyframe::SetTime(const long inNewTime) +{ + Q_UNUSED(inNewTime); + // note: this is not used. because setting time is currently only done through offsetting by + // moving keyframes OR using the edit time dialog. + ASSERT(0); +} + +void CUICDMAssetTimelineKeyframe::SetDynamic(bool inIsDynamic) +{ + m_OwningBinding->SetDynamicKeyframes(m_Time, inIsDynamic); +} + +bool CUICDMAssetTimelineKeyframe::IsDynamic() const +{ + // return true if any of its property keyframes is dynamic + return m_OwningBinding->HasDynamicKeyframes(m_Time); +} + +void CUICDMAssetTimelineKeyframe::SetSelected(bool inSelected) +{ + m_Selected = inSelected; +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h new file mode 100644 index 00000000..e8cf6870 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_UICDMASSETKEYFRAME_H +#define INCLUDED_UICDMASSETKEYFRAME_H 1 + +#pragma once + +#include "IKeyframe.h" + +// Data model specific +#include "UICDMHandles.h" + +class CUICDMTimelineItemBinding; + +//============================================================================== +/** + * Represents a keyframe displayed for a Asset( e.g. material ), for all keyframes (of the + *animated properties) at time t. + */ +//============================================================================== +class CUICDMAssetTimelineKeyframe : public IKeyframe +{ +protected: + CUICDMTimelineItemBinding *m_OwningBinding; + long m_Time; + bool m_Selected; + +public: + CUICDMAssetTimelineKeyframe(CUICDMTimelineItemBinding *inOwningBinding, long inTime); + virtual ~CUICDMAssetTimelineKeyframe(); + + // IKeyframe + bool IsSelected() const override; + long GetTime() const override; + void SetTime(const long inNewTime) override; + void SetDynamic(bool inIsDynamic) override; + bool IsDynamic() const override; + + void SetSelected(bool inSelected); + void UpdateTime(const long inTime) { m_Time = inTime; } +}; + +#endif // INCLUDED_UICDMKEYFRAME_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h new file mode 100644 index 00000000..7989956f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_UICDMTIMELINE_H +#define INCLUDED_UICDMTIMELINE_H 1 + +#pragma once + +enum ETimelineKeyframeTransaction { + ETimelineKeyframeTransaction_Add, + ETimelineKeyframeTransaction_Delete, + ETimelineKeyframeTransaction_Update, + ETimelineKeyframeTransaction_DynamicChanged, +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp new file mode 100644 index 00000000..b6dd94d9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp @@ -0,0 +1,1260 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMTimelineItemBinding.h" +#include "TimelineTranslationManager.h" +#include "TimeEditDlg.h" +#include "EmptyTimelineTimebar.h" +#include "UICDMTimelineTimebar.h" +#include "BaseStateRow.h" +#include "BaseTimebarlessRow.h" +#include "PropertyTimebarRow.h" +#include "PropertyRow.h" +#include "KeyframesManager.h" +#include "StudioApp.h" +#include "Core.h" +#include "Dialogs.h" +#include "GraphUtils.h" +#include "UICDMDataCore.h" +#include "Strings.h" +#include "StringLoader.h" + +// Data model specific +#include "IDoc.h" +#include "ClientDataModelBridge.h" +#include "Dispatch.h" +#include "DropSource.h" +#include "UICDMTimelineItemProperty.h" +#include "UICDMSlides.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlideGraphCore.h" +#include "UICDMActionCore.h" +#include "UICDMAnimation.h" +#include "CmdDataModelChangeKeyframe.h" +#include "RelativePathTools.h" +#include "IDocumentEditor.h" +#include "UICFileTools.h" +#include "ImportUtils.h" + +#include <QMessageBox> + +using namespace UICDM; + +CUICDMTimelineItemBinding::CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr, + CUICDMInstanceHandle inDataHandle) + : m_Row(nullptr) + , m_TransMgr(inMgr) + , m_DataHandle(inDataHandle) + , m_Parent(nullptr) + , m_TimelineTimebar(nullptr) + +{ + m_StudioSystem = m_TransMgr->GetStudioSystem(); + m_TransMgr->GetDoc()->GetCore()->GetDispatch()->AddDataModelListener(this); +} + +CUICDMTimelineItemBinding::CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr) + : m_Row(nullptr) + , m_TransMgr(inMgr) + , m_DataHandle(0) + , m_Parent(nullptr) + , m_TimelineTimebar(nullptr) +{ + m_StudioSystem = m_TransMgr->GetStudioSystem(); + m_TransMgr->GetDoc()->GetCore()->GetDispatch()->AddDataModelListener(this); +} + +CUICDMTimelineItemBinding::~CUICDMTimelineItemBinding() +{ + RemoveAllPropertyBindings(); + delete m_TimelineTimebar; + m_TransMgr->GetDoc()->GetCore()->GetDispatch()->RemoveDataModelListener(this); +} + +// helpers +bool CUICDMTimelineItemBinding::UICDMGetBoolean(UICDM::CUICDMPropertyHandle inProperty) const +{ + UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem(); + SValue theValue; + thePropertySystem->GetInstancePropertyValue(m_DataHandle, inProperty, theValue); + return UICDM::get<bool>(theValue); +} + +void CUICDMTimelineItemBinding::UICDMSetBoolean(UICDM::CUICDMPropertyHandle inProperty, + bool inValue, const QString &inNiceText) const +{ + CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc()); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*theDoc, inNiceText) + ->SetInstancePropertyValue(m_DataHandle, inProperty, inValue); +} + +void CUICDMTimelineItemBinding::SetInstanceHandle(UICDM::CUICDMInstanceHandle inDataHandle) +{ + m_DataHandle = inDataHandle; +} + +EStudioObjectType CUICDMTimelineItemBinding::GetObjectType() const +{ + return m_StudioSystem->GetClientDataModelBridge()->GetObjectType(m_DataHandle); +} + +bool CUICDMTimelineItemBinding::IsMaster() const +{ + CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc()); + Q3DStudio::IDocumentReader &theReader(theDoc->GetDocumentReader()); + if (GetObjectType() == OBJTYPE_IMAGE) { + CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge(); + CUICDMInstanceHandle theParent; + CUICDMPropertyHandle theProperty; + bool isPropertyLinked; + + theBridge->GetMaterialFromImageInstance(GetInstance(), theParent, theProperty); + isPropertyLinked = theReader.IsPropertyLinked(theParent, theProperty); + + // Also check light probe + if (!isPropertyLinked) { + theBridge->GetLayerFromImageProbeInstance(GetInstance(), theParent, theProperty); + isPropertyLinked = theReader.IsPropertyLinked(theParent, theProperty); + } + + return isPropertyLinked; + } + CUICDMInstanceHandle theQueryHandle(m_DataHandle); + if (GetObjectType() == OBJTYPE_PATHANCHORPOINT) + theQueryHandle = theReader.GetParent(m_DataHandle); + + // logic: you can't unlink name, so if name is linked then, this is master. + CUICDMPropertyHandle theNamePropHandle = + m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(theQueryHandle, + L"name"); + return theReader.IsPropertyLinked(theQueryHandle, theNamePropHandle); +} + +bool CUICDMTimelineItemBinding::IsShy() const +{ + return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Shy); +} +void CUICDMTimelineItemBinding::SetShy(bool inShy) +{ + UICDMSetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Shy, inShy, + QObject::tr("Shy Toggle")); +} +bool CUICDMTimelineItemBinding::IsLocked() const +{ + return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Locked); +} + +void ToggleChildrenLock(Q3DStudio::ScopedDocumentEditor &scopedDocEditor, + CUICDMTimelineItemBinding *inTimelineItemBinding, + SDataModelSceneAsset inSceneAsset, bool inLocked) +{ + scopedDocEditor->SetInstancePropertyValue(inTimelineItemBinding->GetInstanceHandle(), + inSceneAsset.m_Locked, inLocked); + long childrenCount = inTimelineItemBinding->GetChildrenCount(); + if (childrenCount == 0) + return; + for (long i = 0; i < childrenCount; ++i) { + CUICDMTimelineItemBinding *child = + static_cast<CUICDMTimelineItemBinding *>(inTimelineItemBinding->GetChild(i)); + ToggleChildrenLock(scopedDocEditor, child, inSceneAsset, inLocked); + } +} + +void CUICDMTimelineItemBinding::SetLocked(bool inLocked) +{ + CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc()); + Q3DStudio::ScopedDocumentEditor scopedDocEditor(*theDoc, L"SetLock", __FILE__, __LINE__); + + SDataModelSceneAsset sceneAsset = m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset(); + ToggleChildrenLock(scopedDocEditor, this, sceneAsset, inLocked); + + if (inLocked) + g_StudioApp.GetCore()->GetDoc()->NotifySelectionChanged(); +} + +bool CUICDMTimelineItemBinding::IsVisible() const +{ + return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Eyeball); +} + +void CUICDMTimelineItemBinding::SetVisible(bool inVisible) +{ + UICDMSetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Eyeball, + inVisible, QObject::tr("Visibility Toggle")); +} + +// remember the expanded state for the current presentation +bool CUICDMTimelineItemBinding::IsExpanded() const +{ + return m_TransMgr->IsExpanded(m_DataHandle); +} +// remember the expanded state for the current presentation +void CUICDMTimelineItemBinding::SetExpanded(bool inExpanded) +{ + m_TransMgr->SetExpanded(m_DataHandle, inExpanded); +} + +bool CUICDMTimelineItemBinding::HasAction(bool inMaster) +{ + TActionHandleList theActions; + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + + CUICDMSlideHandle theSlide = theDoc->GetActiveSlide(); + UICDM::ISlideCore &theSlideCore(*m_StudioSystem->GetSlideCore()); + if (theSlideCore.IsSlide(theSlide)) { + if (inMaster) + theSlide = + m_StudioSystem->GetSlideSystem()->GetMasterSlide(theSlide); // use the master slide + + m_StudioSystem->GetActionCore()->GetActions(theSlide, m_DataHandle, theActions); + } + return theActions.size() > 0; +} + +bool CUICDMTimelineItemBinding::ChildrenHasAction(bool inMaster) +{ + // Get all the instances in this slidegraph + // check whehter it's an action instance and is in the slide of interst + // check also it's owner is a descendent of the viewed instances + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + IActionCore *theActionCore(m_StudioSystem->GetActionCore()); + CClientDataModelBridge *theBridge(m_StudioSystem->GetClientDataModelBridge()); + + CUICDMSlideHandle theSlide = theDoc->GetActiveSlide(); + UICDM::ISlideCore &theSlideCore(*m_StudioSystem->GetSlideCore()); + if (theSlideCore.IsSlide(theSlide)) { + if (inMaster) + theSlide = + m_StudioSystem->GetSlideSystem()->GetMasterSlide(theSlide); // use the master slide + + TSlideInstancePairList theGraphInstances; + m_StudioSystem->GetSlideSystem()->GetAssociatedInstances(theSlide, theGraphInstances); + + UICDM::CUICDMInstanceHandle theObservedInstance = GetInstance(); + if (theObservedInstance.Valid()) { + for (TSlideInstancePairList::const_iterator theIter = theGraphInstances.begin(); + theIter != theGraphInstances.end(); ++theIter) { + if (theIter->first == theSlide && theBridge->IsActionInstance(theIter->second)) { + CUICDMActionHandle theAction = + theActionCore->GetActionByInstance(theIter->second); + SActionInfo theActionInfo = theActionCore->GetActionInfo(theAction); + CUICDMInstanceHandle theAcionOwner = theActionInfo.m_Owner; + if (theAcionOwner.Valid() + && IsAscendant(theAcionOwner, theObservedInstance, theDoc->GetAssetGraph())) + return true; + } + } + } + } + + return false; +} + +bool CUICDMTimelineItemBinding::ComponentHasAction(bool inMaster) +{ + // Get all the instances in this component slidegraph + // check whether the instance is an action instance + // if inMaster is true, we only interest with those that are in the master slide, else we want + // those that are not in the master slide + CClientDataModelBridge *theBridge(m_StudioSystem->GetClientDataModelBridge()); + if (!theBridge->IsComponentInstance(m_DataHandle)) + return false; + + Q3DStudio::CId theAssetId = theBridge->GetGUID(m_DataHandle); + CUICDMSlideHandle theMasterSlide = + m_StudioSystem->GetSlideSystem()->GetMasterSlideByComponentGuid(GuidtoSLong4(theAssetId)); + + TSlideInstancePairList theGraphInstances; + m_StudioSystem->GetSlideSystem()->GetAssociatedInstances(theMasterSlide, theGraphInstances); + + for (TSlideInstancePairList::const_iterator theIter = theGraphInstances.begin(); + theIter != theGraphInstances.end(); ++theIter) { + if (((inMaster && theIter->first == theMasterSlide) + || (!inMaster && theIter->first != theMasterSlide)) + && theBridge->IsActionInstance(theIter->second)) + return true; + } + return false; +} + +ITimelineTimebar *CUICDMTimelineItemBinding::GetTimebar() +{ + if (!m_TimelineTimebar) + m_TimelineTimebar = CreateTimelineTimebar(); + return m_TimelineTimebar; +} + +Q3DStudio::CString CUICDMTimelineItemBinding::GetName() const +{ + if (m_StudioSystem->IsInstance(m_DataHandle) == false) + return L""; + CUICDMPropertyHandle theNamePropHandle = + m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(m_DataHandle, + L"name"); + SValue theNameValue; + m_StudioSystem->GetPropertySystem()->GetInstancePropertyValue(m_DataHandle, theNamePropHandle, + theNameValue); + TDataStrPtr theName = UICDM::get<TDataStrPtr>(theNameValue); + + return (theName) ? Q3DStudio::CString(theName->GetData()) : ""; +} + +void CUICDMTimelineItemBinding::SetName(const Q3DStudio::CString &inName) +{ + // Display warning dialog if user tried to enter an empty string + if (inName.IsEmpty()) { + Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_TITLE)); + Q3DStudio::CString theString(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_EMPTY_STRING)); + g_StudioApp.GetDialogs()->DisplayMessageBox(theTitle, theString, CUICMessageBox::ICON_ERROR, + false); + + return; + } + + CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge(); + if (!theBridge->CheckNameUnique(m_DataHandle, inName)) { + Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_TITLE)); + Q3DStudio::CString theString( + ::LoadResourceString(IDS_ERROR_OBJECT_RENAME_DUPLICATED_STRING)); + int theUserChoice = g_StudioApp.GetDialogs()->DisplayChoiceBox( + theTitle, theString, CUICMessageBox::ICON_WARNING); + if (theUserChoice == QMessageBox::Yes) { + // Set with the unique name + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*m_TransMgr->GetDoc(), QObject::tr("Set Name")) + ->SetName(m_DataHandle, inName, true); + return; + } + } + // Set the name no matter it's unique or not + CUICDMPropertyHandle theNamePropHandle = + m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(m_DataHandle, + L"name"); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*m_TransMgr->GetDoc(), QObject::tr("Set Name")) + ->SetInstancePropertyValue(m_DataHandle, theNamePropHandle, + std::make_shared<CDataStr>(inName)); +} + +ITimelineItem *CUICDMTimelineItemBinding::GetTimelineItem() +{ + return this; +} + +CBaseStateRow *CUICDMTimelineItemBinding::GetRow() +{ + return m_Row; +} + +void CUICDMTimelineItemBinding::SetSelected(bool inMultiSelect) +{ + if (!inMultiSelect) + g_StudioApp.GetCore()->GetDoc()->SelectUICDMObject(m_DataHandle); + else + g_StudioApp.GetCore()->GetDoc()->ToggleUICDMObjectToSelection(m_DataHandle); +} + +void CUICDMTimelineItemBinding::OnCollapsed() +{ + // Preserves legacy behavior where collapsing a tree will select that root, if any of its + // descendant was selected + // TODO: This won't work for Image (because Image is Material's property, not child) + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + if (theInstance.Valid()) { + CDoc *theDoc = m_TransMgr->GetDoc(); + UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance(); + if (theSelectedInstance.Valid() + && IsAscendant(theSelectedInstance, theInstance, theDoc->GetAssetGraph())) + SetSelected(false); + } +} + +void CUICDMTimelineItemBinding::ClearKeySelection() +{ + m_TransMgr->ClearKeyframeSelection(); +} + +bool CUICDMTimelineItemBinding::OpenAssociatedEditor() +{ + return false; // nothing to do by default +} + +void CUICDMTimelineItemBinding::DoStartDrag(CControlWindowListener *inWndListener) +{ + inWndListener->DoStartDrag(this); +} + +inline UICDM::CUICDMInstanceHandle CUICDMTimelineItemBinding::GetInstance() const +{ + return m_DataHandle; +} + +void CUICDMTimelineItemBinding::SetDropTarget(CDropTarget *inTarget) +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + inTarget->SetInstance(theInstance); +} + +long CUICDMTimelineItemBinding::GetChildrenCount() +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + if (theInstance.Valid()) { + Q3DStudio::CGraphIterator theChildren; + CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide(); + GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(), + theChildren, theActiveSlide); + return (long)theChildren.GetCount(); + } + return 0; +} + +ITimelineItemBinding *CUICDMTimelineItemBinding::GetChild(long inIndex) +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + if (theInstance.Valid()) { + Q3DStudio::CGraphIterator theChildren; + CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide(); + GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(), + theChildren, theActiveSlide); + theChildren += inIndex; + + UICDM::CUICDMInstanceHandle theChildInstance = theChildren.GetCurrent(); + if (theChildInstance.Valid()) + return m_TransMgr->GetOrCreate(theChildInstance); + } + return nullptr; +} + +ITimelineItemBinding *CUICDMTimelineItemBinding::GetParent() +{ + return m_Parent; +} +void CUICDMTimelineItemBinding::SetParent(ITimelineItemBinding *parent) +{ + if (parent != m_Parent) { + ASSERT(parent == nullptr || m_Parent == nullptr); + m_Parent = parent; + } +} + +long CUICDMTimelineItemBinding::GetPropertyCount() +{ + long theCount = 0; + if (m_StudioSystem->IsInstance(m_DataHandle)) { + TPropertyHandleList theProperties; + m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle, + theProperties); + for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); + ++thePropertyIndex) { + if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated( + m_DataHandle, theProperties[thePropertyIndex])) + ++theCount; + } + } + return theCount; +} + +ITimelineItemProperty *CUICDMTimelineItemBinding::GetProperty(long inIndex) +{ + TPropertyHandleList theProperties; + m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle, + theProperties); + long theIndex = -1; + size_t thePropertyIndex = 0; + for (; thePropertyIndex < theProperties.size(); ++thePropertyIndex) { + if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated( + m_DataHandle, theProperties[thePropertyIndex])) { + ++theIndex; + if (theIndex == inIndex) + break; + } + } + ASSERT(thePropertyIndex < theProperties.size()); // no reason why this would be out of range!! + return GetOrCreatePropertyBinding(theProperties[thePropertyIndex]); +} + +bool CUICDMTimelineItemBinding::ShowToggleControls() const +{ + return true; +} +bool CUICDMTimelineItemBinding::IsLockedEnabled() const +{ + return IsLocked(); +} +bool CUICDMTimelineItemBinding::IsVisibleEnabled() const +{ + // You can only toggle visible if you aren't on the master slide. + return m_StudioSystem->GetSlideSystem()->GetSlideIndex(m_TransMgr->GetDoc()->GetActiveSlide()) + != 0; +} + +void CUICDMTimelineItemBinding::Bind(CBaseStateRow *inRow) +{ + ASSERT(!m_Row); + m_Row = inRow; + + // Because children(properties included) may only be loaded later, check if there are any + // keyframes without having to have the UI created. + TPropertyHandleList theProperties; + m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle, + theProperties); + for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); ++thePropertyIndex) { + if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated( + m_DataHandle, theProperties[thePropertyIndex])) + AddKeyframes(GetOrCreatePropertyBinding(theProperties[thePropertyIndex])); + } + + // Set selection status + CUICDMInstanceHandle theSelectedInstance = m_TransMgr->GetDoc()->GetSelectedInstance(); + m_Row->OnSelected(m_DataHandle == theSelectedInstance); +} + +void CUICDMTimelineItemBinding::Release() +{ + m_Row = nullptr; + RemoveAllPropertyBindings(); + m_TransMgr->Unregister(this); +} + +bool CUICDMTimelineItemBinding::IsValidTransaction(EUserTransaction inTransaction) +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + switch (inTransaction) { + case EUserTransaction_Rename: + return (GetObjectType() != OBJTYPE_SCENE && GetObjectType() != OBJTYPE_IMAGE); + + case EUserTransaction_Duplicate: + if (theInstance.Valid()) + return m_StudioSystem->GetClientDataModelBridge()->IsDuplicateable(theInstance); + break; + + case EUserTransaction_Cut: + return g_StudioApp.CanCut(); + + case EUserTransaction_Copy: + return g_StudioApp.CanCopy(); + + case EUserTransaction_Paste: + return m_TransMgr->GetDoc()->CanPasteObject(); + + case EUserTransaction_Delete: + if (theInstance.Valid()) + return m_StudioSystem->GetClientDataModelBridge()->CanDelete(theInstance); + break; + + case EUserTransaction_MakeComponent: { + bool theCanMakeFlag = false; + if (theInstance.Valid()) { + CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge(); + EStudioObjectType theObjectType = theBridge->GetObjectType(theInstance); + + if (!IsLocked()) { + // Any assets that are attached to the Scene directly must not be wrapped in a + // component. + // This may include behavior assets which may be directly attached to the Scene. + // This is because by principal, components cannot exist on the Scene directly. + UICDM::CUICDMInstanceHandle theParentInstance = + theBridge->GetParentInstance(theInstance); + if (theObjectType != OBJTYPE_LAYER && theObjectType != OBJTYPE_SCENE + && theObjectType != OBJTYPE_MATERIAL && theObjectType != OBJTYPE_IMAGE + && theObjectType != OBJTYPE_EFFECT + && (theParentInstance.Valid() + && theBridge->GetObjectType(theParentInstance) + != OBJTYPE_SCENE)) // This checks if the object is + // AttachedToSceneDirectly + { + theCanMakeFlag = true; + } + } + } + return theCanMakeFlag; + } + + case EUserTransaction_EditComponent: + return (GetObjectType() == OBJTYPE_COMPONENT); + + default: // not handled + break; + } + + return false; +} + +using namespace Q3DStudio; + +inline void DoCut(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances) +{ + inDoc.DeselectAllKeyframes(); + inDoc.CutObject(inInstances); +} + +inline void DoDelete(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances) +{ + inDoc.DeselectAllKeyframes(); + inDoc.DeleteObject(inInstances); +} + +inline void DoMakeComponent(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances) +{ + SCOPED_DOCUMENT_EDITOR(inDoc, QObject::tr("Make Component"))->MakeComponent(inInstances); +} + +void CUICDMTimelineItemBinding::PerformTransaction(EUserTransaction inTransaction) +{ + CDoc *theDoc = m_TransMgr->GetDoc(); + UICDM::TInstanceHandleList theInstances = theDoc->GetSelectedValue().GetSelectedInstances(); + if (theInstances.empty()) + return; + CDispatch &theDispatch(*theDoc->GetCore()->GetDispatch()); + + // Transactions that could result in *this* object being deleted need to be executed + // via postmessage, not in this context because it could result in the currently + // active timeline row being deleted while in its own mouse handler. + switch (inTransaction) { + case EUserTransaction_Duplicate: { + theDoc->DeselectAllKeyframes(); + SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Duplicate Object"))->DuplicateInstances(theInstances); + } break; + case EUserTransaction_Cut: { + theDispatch.FireOnAsynchronousCommand( + std::bind(DoCut, std::ref(*theDoc), theInstances)); + } break; + case EUserTransaction_Copy: { + theDoc->DeselectAllKeyframes(); + theDoc->CopyObject(theInstances); + } break; + case EUserTransaction_Paste: { + theDoc->DeselectAllKeyframes(); + theDoc->PasteObject(GetInstance()); + } break; + case EUserTransaction_Delete: { + theDispatch.FireOnAsynchronousCommand( + std::bind(DoDelete, std::ref(*theDoc), theInstances)); + } break; + case EUserTransaction_MakeComponent: { + theDispatch.FireOnAsynchronousCommand( + std::bind(DoMakeComponent, std::ref(*theDoc), theInstances)); + } + default: // not handled + break; + } +} + +Q3DStudio::CString CUICDMTimelineItemBinding::GetObjectPath() +{ + CDoc *theDoc = m_TransMgr->GetDoc(); + // Because we are getting absolute path, the base id doesn't matter. + return CRelativePathTools::BuildAbsoluteReferenceString(m_DataHandle, theDoc); +} + +ITimelineKeyframesManager *CUICDMTimelineItemBinding::GetKeyframesManager() const +{ + return m_TransMgr->GetKeyframesManager(); +} + +void CUICDMTimelineItemBinding::RemoveProperty(ITimelineItemProperty *inProperty) +{ + Q_UNUSED(inProperty); + // TODO: This function has no use in UICDM world. This is replaced by RemovePropertyRow( + // CUICDMPropertyHandle inPropertyHandle ). + // Decide if this function should be removed from ITimelineItemBinding. +} + +void CUICDMTimelineItemBinding::LoadProperties() +{ + TPropertyHandleList theProperties; + m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle, + theProperties); + for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); ++thePropertyIndex) { + if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated( + m_DataHandle, theProperties[thePropertyIndex])) + AddPropertyRow(theProperties[thePropertyIndex], true); + } +} + +void CUICDMTimelineItemBinding::InsertKeyframe() +{ + if (m_PropertyBindingMap.empty()) + return; + + TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin(); + ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(), L"Insert Keyframe", __FILE__, + __LINE__); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) + editor->KeyframeProperty(m_DataHandle, theIter->first, false); +} + +void CUICDMTimelineItemBinding::DeleteAllChannelKeyframes() +{ + if (m_PropertyBindingMap.empty()) + return; + + CDoc *theDoc = m_TransMgr->GetDoc(); + Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Delete Channel Keyframes", __FILE__, + __LINE__); + for (TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(), + theEnd = m_PropertyBindingMap.end(); + theIter != theEnd; ++theIter) + theIter->second->DeleteAllKeys(); +} + +long CUICDMTimelineItemBinding::GetKeyframeCount() const +{ + // This list is updated when properties are loaded and when keyframes are added & deleted. + return (long)m_Keyframes.size(); +} + +IKeyframe *CUICDMTimelineItemBinding::GetKeyframeByTime(long inTime) const +{ + TAssetKeyframeList::const_iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + if ((*theIter).GetTime() == inTime) + return const_cast<CUICDMAssetTimelineKeyframe *>(&(*theIter)); + } + return nullptr; +} + +IKeyframe *CUICDMTimelineItemBinding::GetKeyframeByIndex(long inIndex) const +{ + if (inIndex >= 0 && inIndex < (long)m_Keyframes.size()) + return const_cast<CUICDMAssetTimelineKeyframe *>(&m_Keyframes[inIndex]); + + ASSERT(0); // should not happen + return nullptr; +} + +long CUICDMTimelineItemBinding::OffsetSelectedKeyframes(long inOffset) +{ + return m_TransMgr->GetKeyframesManager()->OffsetSelectedKeyframes(inOffset); +} + +void CUICDMTimelineItemBinding::CommitChangedKeyframes() +{ + m_TransMgr->GetKeyframesManager()->CommitChangedKeyframes(); +} + +void CUICDMTimelineItemBinding::OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) +{ + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.SetKeyframesManager(m_TransMgr->GetKeyframesManager()); + theTimeEditDlg.ShowDialog(inCurrentTime, 0, g_StudioApp.GetCore()->GetDoc(), + inObjectAssociation); +} + +void CUICDMTimelineItemBinding::SelectKeyframes(bool inSelected, long inTime /*= -1 */) +{ + // Callback from UI, hence skip the UI update + DoSelectKeyframes(inSelected, inTime, false); +} + +CUICDMInstanceHandle CUICDMTimelineItemBinding::GetInstanceHandle() const +{ + return m_DataHandle; +} + +long CUICDMTimelineItemBinding::GetFlavor() const +{ + return EUIC_FLAVOR_ASSET_TL; +} + +void CUICDMTimelineItemBinding::OnBeginDataModelNotifications() +{ +} +void CUICDMTimelineItemBinding::OnEndDataModelNotifications() +{ + RefreshStateRow(); +} +void CUICDMTimelineItemBinding::OnImmediateRefreshInstanceSingle( + UICDM::CUICDMInstanceHandle inInstance) +{ + if (inInstance == m_DataHandle) + RefreshStateRow(true); +} +void CUICDMTimelineItemBinding::OnImmediateRefreshInstanceMultiple( + UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount) +{ + for (long idx = 0; idx < inInstanceCount; ++idx) + if (inInstance[idx] == m_DataHandle) { + RefreshStateRow(); + break; + } +} + +void CUICDMTimelineItemBinding::RefreshStateRow(bool inRefreshChildren) +{ + CStateRow *theRow = dynamic_cast<CStateRow *>(m_Row); + if (theRow) { + theRow->OnTimeChange(); + theRow->ClearDirty(); + if (inRefreshChildren) { + long theChildrenCount = GetChildrenCount(); + for (long theIndex = 0; theIndex < theChildrenCount; ++theIndex) { + ITimelineItemBinding *theChild = GetChild(theIndex); + CUICDMTimelineItemBinding *theBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(theChild); + if (theBinding) + theBinding->RefreshStateRow(inRefreshChildren); + } + } + } +} + +ITimelineTimebar *CUICDMTimelineItemBinding::CreateTimelineTimebar() +{ + return new CUICDMTimelineTimebar(m_TransMgr, m_DataHandle); +} + +ITimelineItemProperty * +CUICDMTimelineItemBinding::GetPropertyBinding(CUICDMPropertyHandle inPropertyHandle) +{ + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle); + // check if it already exists + if (theIter != m_PropertyBindingMap.end()) + return theIter->second; + return nullptr; +} + +ITimelineItemProperty * +CUICDMTimelineItemBinding::GetOrCreatePropertyBinding(CUICDMPropertyHandle inPropertyHandle) +{ + ITimelineItemProperty *theProperty = GetPropertyBinding(inPropertyHandle); + // check if it already exists + if (theProperty) + return theProperty; + + // Create + CUICDMTimelineItemProperty *theTimelineProperty = + new CUICDMTimelineItemProperty(m_TransMgr, inPropertyHandle, m_DataHandle); + m_PropertyBindingMap.insert(std::make_pair(inPropertyHandle, theTimelineProperty)); + + return theTimelineProperty; +} + +//============================================================================= +/** + * Add a new property row for this property. + * @param inAppend true to skip the check to find where to insert. ( true if this is a + * loading/initializing step, where the call is already done in order ) + */ +void CUICDMTimelineItemBinding::AddPropertyRow(CUICDMPropertyHandle inPropertyHandle, + bool inAppend /*= false */) +{ + ITimelineItemProperty *theTimelineProperty = GetPropertyBinding(inPropertyHandle); + if (theTimelineProperty && theTimelineProperty->GetRow()) // if created, bail + return; + + if (!theTimelineProperty) + theTimelineProperty = GetOrCreatePropertyBinding(inPropertyHandle); + + // Find the row to insert this new property, if any, this preserves the order the property rows + // is displayed in the timeline. + ITimelineItemProperty *theNextProperty = nullptr; + if (!inAppend) { + TPropertyHandleList theProperties; + m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle, + theProperties); + size_t thePropertyIndex = 0; + size_t thePropertyCount = theProperties.size(); + for (; thePropertyIndex < thePropertyCount; ++thePropertyIndex) { + if (theProperties[thePropertyIndex] == inPropertyHandle) { + ++thePropertyIndex; + break; + } + } + // Not all properties are displayed, so another loop to search for the first one that maps + // to a existing propertyrow + for (; thePropertyIndex < thePropertyCount; ++thePropertyIndex) { + TPropertyBindingMap::iterator theNextPropIter = + m_PropertyBindingMap.find(theProperties[thePropertyIndex]); + if (theNextPropIter != m_PropertyBindingMap.end()) { + theNextProperty = theNextPropIter->second; + break; + } + } + } + // Create a new property row + m_TransMgr->CreateNewPropertyRow(theTimelineProperty, m_Row, + theNextProperty ? theNextProperty->GetRow() : nullptr); + + // Update keyframes + AddKeyframes(theTimelineProperty); +} + +void CUICDMTimelineItemBinding::RemovePropertyRow(CUICDMPropertyHandle inPropertyHandle) +{ + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle); + if (theIter != m_PropertyBindingMap.end()) { + ITimelineItemProperty *thePropertyBinding = theIter->second; + + bool theUpdateUI = DeleteAssetKeyframesWhereApplicable(thePropertyBinding); + + m_TransMgr->RemovePropertyRow(thePropertyBinding); + m_PropertyBindingMap.erase(theIter); + + // UI must update + if (m_Row && theUpdateUI) { + m_Row->OnChildVisibilityChanged(); + m_Row->GetTimebar()->SetDirty(true); + } + } +} + +// called when a keyframe is inserted, deleted or updated in the data model +void CUICDMTimelineItemBinding::RefreshPropertyKeyframe( + UICDM::CUICDMPropertyHandle inPropertyHandle, UICDM::CUICDMKeyframeHandle inKeyframe, + ETimelineKeyframeTransaction inTransaction) +{ + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle); + if (theIter != m_PropertyBindingMap.end()) { + CUICDMTimelineItemProperty *theProperty = theIter->second; + if (theProperty) { + if (theProperty->RefreshKeyframe(inKeyframe, inTransaction)) { + // Update asset keyframes + UpdateKeyframe(theProperty->GetKeyframeByHandle(inKeyframe), inTransaction); + if (m_Row) // UI update + m_Row->GetTimebar()->SetDirty(true); + } + } + } +} + +// called when the keyframes are updated in the UI and data model hasn't committed the change, ie no +// event callback from UICDM +void CUICDMTimelineItemBinding::UIRefreshPropertyKeyframe(long inOffset) +{ + if (!m_Row) + return; + + // TODO: figure out a better way to sync m_Keyframes + TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin(); + for (; theKeyIter != m_Keyframes.end(); ++theKeyIter) { + if (theKeyIter->IsSelected()) + theKeyIter->UpdateTime(theKeyIter->GetTime() + inOffset); + } + // If a asset keyframe was "shared" by several properties' keyframes + // we need to 'break' this sharing and create for the remaining unmoved keyframes. + TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) { + (*theIter).second->RefreshKeyFrames(); + + for (long i = 0; i < theIter->second->GetKeyframeCount(); ++i) { + IKeyframe *theKeyframe = theIter->second->GetKeyframeByIndex(i); + UpdateKeyframe(theKeyframe, ETimelineKeyframeTransaction_Add); + + // Unfortunately, this is the way we can propagate UI updates to ALL selected keyframes + if (theKeyframe->IsSelected()) { + CPropertyRow *thePropertyRow = theIter->second->GetRow(); + if (thePropertyRow) + thePropertyRow->GetTimebar()->SetDirty(true); + } + } + } + m_Row->GetTimebar()->SetDirty(true); +} + +void CUICDMTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle) +{ // Refresh UI + CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge(); + if (m_Row && (inPropertyHandle == theBridge->GetNameProperty() + || inPropertyHandle == theBridge->GetSceneAsset().m_Eyeball + || inPropertyHandle == theBridge->GetSceneAsset().m_Locked + || inPropertyHandle == theBridge->GetSceneAsset().m_Shy + || inPropertyHandle == theBridge->GetSceneAsset().m_StartTime + || inPropertyHandle == theBridge->GetSceneAsset().m_EndTime)) + m_Row->OnDirty(); +} + +void CUICDMTimelineItemBinding::OnPropertyLinked(CUICDMPropertyHandle inPropertyHandle) +{ + if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(m_DataHandle, inPropertyHandle)) { + // Refresh property row by delete and recreate + RemovePropertyRow(inPropertyHandle); + AddPropertyRow(inPropertyHandle); + } +} + +bool CUICDMTimelineItemBinding::HasDynamicKeyframes(long inTime) +{ + if (inTime == -1) { + if (GetPropertyCount() == 0) + return false; + + for (long i = 0; i < GetPropertyCount(); ++i) { + ITimelineItemProperty *theTimelineItemProperty = GetProperty(i); + if (!theTimelineItemProperty->IsDynamicAnimation()) + return false; + } + return true; + } else { + TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) { + IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime); + if (theKeyframe && theKeyframe->IsDynamic()) + return true; + } + } + return false; +} + +void CUICDMTimelineItemBinding::SetDynamicKeyframes(long inTime, bool inDynamic) +{ + TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) { + IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime); + if (theKeyframe) + theKeyframe->SetDynamic(inDynamic); // TODO: we want this in 1 batch command + } +} + +// Update UI on the selection state of all keyframes on this row and all its properties' keyframes. +void CUICDMTimelineItemBinding::DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI) +{ + if (inTime == -1) // all keyframes + { + TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin(); + for (; theKeyIter != m_Keyframes.end(); ++theKeyIter) + theKeyIter->SetSelected(inSelected); + } else { + CUICDMAssetTimelineKeyframe *theKeyframe = + dynamic_cast<CUICDMAssetTimelineKeyframe *>(GetKeyframeByTime(inTime)); + if (theKeyframe) + theKeyframe->SetSelected(inSelected); + } + if (inUpdateUI && m_Row) + m_Row->GetTimebar()->SelectKeysByTime(-1, inSelected); + + // legacy feature: all properties with keyframes at inTime or all if inTime is -1 are selected + // as well. + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) + theIter->second->DoSelectKeyframes(inSelected, inTime, true, this); +} + +// When selecting by mouse-drag, if all properties are selected, select the asset keyframe. And if +// one gets de-selected, de-select. Legacy feature. +// Note that if only 1 property has a keyframe at time t, the asset keyframe gets selected +// automatically when that keyframe is selected. Its odd to me but +// that's how it has always behaved. +void CUICDMTimelineItemBinding::OnPropertySelection(long inTime) +{ + IKeyframe *theAssetKeyframe = GetKeyframeByTime(inTime); + if (theAssetKeyframe) { + bool theAllSelectedFlag = true; + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) { + IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime); + if (theKeyframe && !theKeyframe->IsSelected()) // done, i.e selection remain unchanged. + { + theAllSelectedFlag = false; + break; + } + } + if (theAssetKeyframe->IsSelected() != theAllSelectedFlag) { + dynamic_cast<CUICDMAssetTimelineKeyframe *>(theAssetKeyframe) + ->SetSelected(theAllSelectedFlag); + // Update UI + if (m_Row) + m_Row->GetTimebar()->SelectKeysByTime(inTime, theAllSelectedFlag); + } + } +} + +Q3DStudio::CId CUICDMTimelineItemBinding::GetGuid() const +{ + CClientDataModelBridge *theClientBridge = m_StudioSystem->GetClientDataModelBridge(); + UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem(); + SValue theValue; + if (thePropertySystem->GetInstancePropertyValue(m_DataHandle, theClientBridge->GetIdProperty(), + theValue)) { + SLong4 theLong4 = UICDM::get<SLong4>(theValue); + return Q3DStudio::CId(theLong4.m_Longs[0], theLong4.m_Longs[1], theLong4.m_Longs[2], + theLong4.m_Longs[3]); + } + return Q3DStudio::CId(); +} + +// Delete asset keyframes at time t if no property keyframes exist at time t +//@param inSkipPropertyBinding property that to skip, e.g. in cases where property is deleted +//@return true if there are asset keyframes deleted. +bool CUICDMTimelineItemBinding::DeleteAssetKeyframesWhereApplicable( + ITimelineItemProperty *inSkipPropertyBinding /*= nullptr */) +{ + // iterate through m_Keyframes because we cannot obtain time information from the Animation + // keyframes anymore, since they are deleted. + std::vector<long> theDeleteIndicesList; + for (size_t theIndex = 0; theIndex < m_Keyframes.size(); ++theIndex) { + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) { + if ((!inSkipPropertyBinding || theIter->second != inSkipPropertyBinding) + && theIter->second->GetKeyframeByTime(m_Keyframes[theIndex].GetTime())) // done! + break; + } + if (theIter == m_PropertyBindingMap.end()) + theDeleteIndicesList.push_back((long)theIndex); + } + // start with the last item, so that the indices remain valid. + for (long i = (long)theDeleteIndicesList.size() - 1; i >= 0; --i) { + TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin(); + std::advance(theKeyIter, theDeleteIndicesList[i]); + m_Keyframes.erase(theKeyIter); + } + + return !theDeleteIndicesList.empty(); +} + +void CUICDMTimelineItemBinding::RemoveAllPropertyBindings() +{ + TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(); + for (; theIter != m_PropertyBindingMap.end(); ++theIter) + delete theIter->second; + m_PropertyBindingMap.clear(); +} + +void CUICDMTimelineItemBinding::AddKeyframes(ITimelineItemProperty *inPropertyBinding) +{ + for (long i = 0; i < inPropertyBinding->GetKeyframeCount(); ++i) + UpdateKeyframe(inPropertyBinding->GetKeyframeByIndex(i), ETimelineKeyframeTransaction_Add); +} + +// Update the asset keyframes based on the properties' keyframes. +void CUICDMTimelineItemBinding::UpdateKeyframe(IKeyframe *inKeyframe, + ETimelineKeyframeTransaction inTransaction) +{ + bool theDoAddFlag = (inTransaction == ETimelineKeyframeTransaction_Add); + bool theDoDeleteFlag = (inTransaction == ETimelineKeyframeTransaction_Delete); + + // For update, if there isn't already a asset keyframe at the associated time, create one + if (inTransaction == ETimelineKeyframeTransaction_Update) { + theDoAddFlag = inKeyframe && !GetKeyframeByTime(inKeyframe->GetTime()); + theDoDeleteFlag = true; // plus, since we don't keep track of indiviual property keyframes + // here, iterate and make sure list is correct. + } + + if (theDoDeleteFlag) + DeleteAssetKeyframesWhereApplicable(); + + // Add when a new keyframe is added or MAYBE when a keyframe is moved + if (theDoAddFlag && inKeyframe) { + long theKeyframeTime = inKeyframe->GetTime(); + if (theKeyframeTime >= 0) { + bool theAppend = true; + // insert this in the order that it should be. and we trust the + TAssetKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + long theTime = (*theIter).GetTime(); + if (theTime == theKeyframeTime) { + theAppend = false; + break; // already exists, we are done. Because we only need 1 to represent ALL + // properties + } + } + if (theAppend) + m_Keyframes.push_back(CUICDMAssetTimelineKeyframe(this, theKeyframeTime)); + } + } + if (m_Row && (theDoAddFlag + || inTransaction == ETimelineKeyframeTransaction_DynamicChanged)) // dynamic => + // only UI needs + // to refresh + m_Row->GetTimebar()->SetDirty(true); +} + +void CUICDMTimelineItemBinding::OnAddChild(CUICDMInstanceHandle inInstance) +{ + CDoc *theDoc = m_TransMgr->GetDoc(); + CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge(); + ISlideSystem *theSlideSystem = m_StudioSystem->GetSlideSystem(); + + UICDM::CUICDMSlideHandle theSlide = theSlideSystem->GetAssociatedSlide(inInstance); + if (theBridge->IsInActiveComponent(inInstance) + && (theSlideSystem->IsMasterSlide(theSlide) || theSlide == theDoc->GetActiveSlide())) { + // Only add if the asset is in the current active component, and it's a master asset or in + // the current slide + ITimelineItemBinding *theNextItem = nullptr; + UICDM::CUICDMInstanceHandle theParentInstance = GetInstance(); + // Figure out where to insert this row, if applicable. + // CAsset has a list of children, and not necessarily all are active in this slide (e.g. + // non-master children) + Q3DStudio::TIdentifier theNextChild = 0; + if (theParentInstance.Valid()) { + // Get the next prioritized child in the same slide + Q3DStudio::CGraphIterator theChildren; + GetAssetChildrenInSlide(theDoc, theParentInstance, theDoc->GetActiveSlide(), + theChildren); + theNextChild = GetSibling(inInstance, true, theChildren); + } + + if (theNextChild != 0) + theNextItem = m_TransMgr->GetOrCreate(theNextChild); + + m_Row->AddChildRow(m_TransMgr->GetOrCreate(inInstance), theNextItem); + } +} + +void CUICDMTimelineItemBinding::OnDeleteChild(CUICDMInstanceHandle inInstance) +{ + ITimelineItemBinding *theChild = m_TransMgr->GetOrCreate(inInstance); + if (theChild) { + m_Row->RemoveChildRow(theChild); + } +} + +void CUICDMTimelineItemBinding::UpdateActionStatus() +{ + if (m_Row) + m_Row->UpdateActionStatus(); +} + +//============================================================================= +/** + * Open the associated item as though it was double-clicked in explorer + * Respective subclasses (for example Image and Behavior) can call this function + */ +bool CUICDMTimelineItemBinding::OpenSourcePathFile() +{ + // Get source path property value + CClientDataModelBridge *theClientBridge = m_StudioSystem->GetClientDataModelBridge(); + UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem(); + SValue theValue; + if (thePropertySystem->GetInstancePropertyValue( + m_DataHandle, theClientBridge->GetSourcePathProperty(), theValue)) { + // Open the respective file + Q3DStudio::CFilePath theSourcePath(UICDM::get<UICDM::TDataStrPtr>(theValue)->GetData()); + CUICFile theFile(m_TransMgr->GetDoc()->GetResolvedPathToDoc(theSourcePath)); + theFile.Execute(); + return true; + } + return false; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h new file mode 100644 index 00000000..2866d698 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_UICDM_TIMELINEITEM_BINDING_H +#define INCLUDED_UICDM_TIMELINEITEM_BINDING_H 1 + +#pragma once + +#include "ITimelineItemBinding.h" +#include "ITimelineItem.h" + +// Data model +#include "UICDMHandles.h" +#include "IDragable.h" +#include "UICDMAssetTimelineKeyframe.h" +#include "OffsetKeyframesCommandHelper.h" +#include "UICDMTimeline.h" +#include "UICDMSignals.h" +#include "DispatchListeners.h" + +//============================================================================== +// Classes +//============================================================================== +class CTimelineTranslationManager; +class CBaseStateRow; +class CUICDMTimelineItemProperty; +class CCmdDataModelSetKeyframeTime; + +namespace UICDM { +class CStudioSystem; +} + +//============================================================================= +/** + * Binding to generic UICDM object + */ +class CUICDMTimelineItemBinding : public ITimelineItemBinding, + public ITimelineItem, + public IDragable, + public IDataModelListener + +{ +protected: // Typedef + typedef std::map<UICDM::CUICDMPropertyHandle, CUICDMTimelineItemProperty *> TPropertyBindingMap; + typedef std::vector<CUICDMAssetTimelineKeyframe> TAssetKeyframeList; + +protected: + CBaseStateRow *m_Row; + CTimelineTranslationManager *m_TransMgr; + UICDM::CUICDMInstanceHandle m_DataHandle; + ITimelineItemBinding *m_Parent; + ITimelineTimebar *m_TimelineTimebar; + TPropertyBindingMap m_PropertyBindingMap; + TAssetKeyframeList m_Keyframes; /// Sorted (by time) list of keyframes + UICDM::CStudioSystem *m_StudioSystem; + + UICDM::TSignalConnectionPtr m_StartTimeConnection; + UICDM::TSignalConnectionPtr m_EndTimeConnection; + +public: + CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr, + UICDM::CUICDMInstanceHandle inDataHandle); + CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr); + virtual ~CUICDMTimelineItemBinding(); + +protected: + bool UICDMGetBoolean(UICDM::CUICDMPropertyHandle inProperty) const; + void UICDMSetBoolean(UICDM::CUICDMPropertyHandle inProperty, bool inValue, + const QString &inNiceText) const; + void SetInstanceHandle(UICDM::CUICDMInstanceHandle inDataHandle); + +public: + // ITimelineItem + EStudioObjectType GetObjectType() const override; + bool IsMaster() const override; + bool IsShy() const override; + void SetShy(bool) override; + bool IsLocked() const override; + void SetLocked(bool) override; + bool IsVisible() const override; + void SetVisible(bool) override; + bool IsExpanded() const override; + void SetExpanded(bool inExpanded) override; + bool HasAction(bool inMaster) override; + bool ChildrenHasAction(bool inMaster) override; + bool ComponentHasAction(bool inMaster) override; + ITimelineTimebar *GetTimebar() override; + + // INamable + Q3DStudio::CString GetName() const override; + void SetName(const Q3DStudio::CString &inName) override; + + // ITimelineItemBinding + ITimelineItem *GetTimelineItem() override; + CBaseStateRow *GetRow() override; + void SetSelected(bool inMultiSelect) override; + void OnCollapsed() override; + void ClearKeySelection() override; + bool OpenAssociatedEditor() override; + void DoStartDrag(CControlWindowListener *inWndListener) override; + void SetDropTarget(CDropTarget *inTarget) override; + // Hierarchy + long GetChildrenCount() override; + ITimelineItemBinding *GetChild(long inIndex) override; + ITimelineItemBinding *GetParent() override; + void SetParent(ITimelineItemBinding *parent) override; + // Properties + long GetPropertyCount() override; + ITimelineItemProperty *GetProperty(long inIndex) override; + // Eye/Lock toggles + bool ShowToggleControls() const override; + bool IsLockedEnabled() const override; + bool IsVisibleEnabled() const override; + // Init/Cleanup + void Bind(CBaseStateRow *inRow) override; + void Release() override; + // ContextMenu + bool IsValidTransaction(EUserTransaction inTransaction) override; + void PerformTransaction(EUserTransaction inTransaction) override; + Q3DStudio::CString GetObjectPath() override; + // Selected keyframes + ITimelineKeyframesManager *GetKeyframesManager() const override; + // Properties + void RemoveProperty(ITimelineItemProperty *inProperty) override; + void LoadProperties() override; + + // ITimelineItemKeyframesHolder + void InsertKeyframe() override; + void DeleteAllChannelKeyframes() override; + long GetKeyframeCount() const override; + IKeyframe *GetKeyframeByTime(long inTime) const override; + IKeyframe *GetKeyframeByIndex(long inIndex) const override; + long OffsetSelectedKeyframes(long inOffset) override; + void CommitChangedKeyframes() override; + void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) override; + + // IKeyframeSelector + void SelectKeyframes(bool inSelected, long inTime = -1) override; + + // IUICDMSelectable + virtual UICDM::CUICDMInstanceHandle GetInstanceHandle() const; + + // IDragable + long GetFlavor() const override; + + void OnBeginDataModelNotifications() override; + void OnEndDataModelNotifications() override; + void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override; + void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, + long inInstanceCount) override; + void RefreshStateRow(bool inRefreshChildren = false); + + virtual void AddPropertyRow(UICDM::CUICDMPropertyHandle inPropertyHandle, + bool inAppend = false); + virtual void RemovePropertyRow(UICDM::CUICDMPropertyHandle inPropertyHandle); + virtual void RefreshPropertyKeyframe(UICDM::CUICDMPropertyHandle inPropertyHandle, + UICDM::CUICDMKeyframeHandle, + ETimelineKeyframeTransaction inTransaction); + virtual void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle); + virtual void OnPropertyLinked(UICDM::CUICDMPropertyHandle inPropertyHandle); + + virtual void UIRefreshPropertyKeyframe(long inOffset); + // Keyframe manipulation + virtual bool HasDynamicKeyframes(long inTime); + virtual void SetDynamicKeyframes(long inTime, bool inDynamic); + virtual void DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI); + virtual void OnPropertySelection(long inTime); + + virtual void OnAddChild(UICDM::CUICDMInstanceHandle inInstance); + virtual void OnDeleteChild(UICDM::CUICDMInstanceHandle inInstance); + + void UpdateActionStatus(); + + Q3DStudio::CId GetGuid() const; + + // Bridge between asset & UICDM. Ideally we should be fully UICDM + virtual UICDM::CUICDMInstanceHandle GetInstance() const; + +protected: + virtual ITimelineTimebar *CreateTimelineTimebar(); + ITimelineItemProperty *GetPropertyBinding(UICDM::CUICDMPropertyHandle inPropertyHandle); + ITimelineItemProperty *GetOrCreatePropertyBinding(UICDM::CUICDMPropertyHandle inPropertyHandle); + void RemoveAllPropertyBindings(); + void AddKeyframes(ITimelineItemProperty *inPropertyBinding); + bool + DeleteAssetKeyframesWhereApplicable(ITimelineItemProperty *inTriggerPropertyBinding = nullptr); + void UpdateKeyframe(IKeyframe *inKeyframe, ETimelineKeyframeTransaction inTransaction); + + // For iterating through children + virtual bool AmITimeParent() const { return false; } + + // subclasses can call this method to open referenced files + virtual bool OpenSourcePathFile(); +}; + +#endif // INCLUDED_UICDM_TIMELINEITEM_BINDING_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp new file mode 100644 index 00000000..c09fca25 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp @@ -0,0 +1,579 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMTimelineItemProperty.h" +#include "PropertyRow.h" +#include "TimelineTranslationManager.h" +#include "ITimelineItemBinding.h" +#include "PropertyTimebarRow.h" +#include "UICDMTimelineItemBinding.h" +#include "UICDMTimelineKeyframe.h" +#include "KeyframesManager.h" +#include "CmdDataModelChangeKeyframe.h" +#include "CmdDataModelRemoveKeyframe.h" +#include "StudioApp.h" +#include "Core.h" + +// Link to data model +#include "TimeEditDlg.h" +#include "ClientDataModelBridge.h" +#include "UICDMSlides.h" +#include "UICDMStudioSystem.h" +#include "UICDMAnimation.h" +#include "UICDMMetaData.h" +#include "UICDMPropertyDefinition.h" +#include "UICDMDataCore.h" +#include "StudioFullSystem.h" +#include <boost/bind.hpp> +using namespace UICDM; + +bool SortKeyframeByTime(const CUICDMTimelineKeyframe *inLHS, const CUICDMTimelineKeyframe *inRHS) +{ + return inLHS->GetTime() < inRHS->GetTime(); +} + +// UICDM stores it from 0..1, UI expects 0..255 +inline float UICDMToColor(float inValue) +{ + return inValue * 255; +} + +CUICDMTimelineItemProperty::CUICDMTimelineItemProperty(CTimelineTranslationManager *inTransMgr, + CUICDMPropertyHandle inPropertyHandle, + CUICDMInstanceHandle inInstance) + : m_Row(nullptr) + , m_InstanceHandle(inInstance) + , m_PropertyHandle(inPropertyHandle) + , m_TransMgr(inTransMgr) + , m_SetKeyframeValueCommand(nullptr) +{ + // Cache all the animation handles because we need them for any keyframes manipulation. + // the assumption is that all associated handles are created all at once (i.e. we do not need to + // add or delete from this list ) + CreateKeyframes(); + InitializeCachedVariables(inInstance); + m_Signals.push_back( + m_TransMgr->GetStudioSystem()->GetFullSystem()->GetSignalProvider()->ConnectPropertyLinked( + boost::bind(&CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged, this, _1, _2, + _3))); + + m_Signals.push_back( + m_TransMgr->GetStudioSystem() + ->GetFullSystem() + ->GetSignalProvider() + ->ConnectPropertyUnlinked(boost::bind( + &CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged, this, _1, _2, _3))); +} + +CUICDMTimelineItemProperty::~CUICDMTimelineItemProperty() +{ + ReleaseKeyframes(); + Release(); +} + +void CUICDMTimelineItemProperty::CreateKeyframes() +{ + // Cache all the animation handles because we need them for any keyframes manipulation. + // the assumption is that all associated handles are created all at once (i.e. we do not need to + // add or delete from this list ) + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + DataModelDataType::Value theDataType = thePropertySystem->GetDataType(m_PropertyHandle); + IStudioAnimationSystem *theAnimationSystem = + m_TransMgr->GetStudioSystem()->GetAnimationSystem(); + std::tuple<bool, size_t> theArity = GetDatatypeAnimatableAndArity(theDataType); + for (size_t i = 0; i < std::get<1>(theArity); ++i) { + CUICDMAnimationHandle theAnimationHandle = + theAnimationSystem->GetControllingAnimation(m_InstanceHandle, m_PropertyHandle, i); + if (theAnimationHandle.Valid()) + m_AnimationHandles.push_back(theAnimationHandle); + } + if (!m_AnimationHandles.empty()) { // update wrappers for keyframes + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + TKeyframeHandleList theKeyframes; + // all channels have keyframes at the same time + theAnimationCore->GetKeyframes(m_AnimationHandles[0], theKeyframes); + for (size_t i = 0; i < theKeyframes.size(); ++i) + CreateKeyframeIfNonExistent(theKeyframes[i], m_AnimationHandles[0]); + } +} + +void CUICDMTimelineItemProperty::ReleaseKeyframes() +{ + // clear any selection from m_TransMgr + TKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(*theIter, false); + + SAFE_DELETE(*theIter); + } + m_Keyframes.clear(); + m_AnimationHandles.clear(); +} + +// Type doesn't change and due to the logic required to figure this out, cache it. +void CUICDMTimelineItemProperty::InitializeCachedVariables(UICDM::CUICDMInstanceHandle inInstance) +{ + using namespace Q3DStudio; + UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem(); + + m_Type.first = thePropertySystem->GetDataType(m_PropertyHandle); + m_Type.second = thePropertySystem->GetAdditionalMetaDataType(inInstance, m_PropertyHandle); + + // Name doesn't change either. + TCharStr theFormalName = thePropertySystem->GetFormalName(inInstance, m_PropertyHandle); + + if (theFormalName.empty()) // fallback on property name + theFormalName = thePropertySystem->GetName(m_PropertyHandle); + m_Name = theFormalName.c_str(); +} + +Q3DStudio::CString CUICDMTimelineItemProperty::GetName() const +{ + return m_Name; +} + +// Helper function to retrieve the parent binding class. +inline ITimelineItemBinding *GetParentBinding(CPropertyRow *inRow) +{ + ITimelineItemBinding *theParentBinding = nullptr; + if (inRow) { + CBaseStateRow *theParentRow = inRow->GetParentRow(); + if (theParentRow) { + theParentBinding = theParentRow->GetTimelineItemBinding(); + ASSERT(theParentBinding); // TimelineItemBinding should be set properly during + // CBaseStateRow::Initialize + } + } + return theParentBinding; +} + +bool CUICDMTimelineItemProperty::IsMaster() const +{ + if (m_Row) { + if (CUICDMTimelineItemBinding *theParentBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row))) + return m_TransMgr->GetDoc()->GetDocumentReader().IsPropertyLinked( + theParentBinding->GetInstanceHandle(), m_PropertyHandle); + } + return false; +} + +UICDM::TDataTypePair CUICDMTimelineItemProperty::GetType() const +{ + return m_Type; +} + +void CompareAndSet(const CUICDMTimelineKeyframe *inKeyframe, float &outRetValue, bool inGreaterThan) +{ + float theValue = (inGreaterThan) ? inKeyframe->GetMaxValue() : inKeyframe->GetMinValue(); + if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue)) + outRetValue = theValue; +} + +// return the max value of the current set of keyframes +float CUICDMTimelineItemProperty::GetMaximumValue() const +{ + float theRetVal = FLT_MIN; + do_all(m_Keyframes, boost::bind(CompareAndSet, _1, boost::ref(theRetVal), true)); + if (m_Type.first == DataModelDataType::Float3 && m_Type.second == AdditionalMetaDataType::Color) + theRetVal = UICDMToColor(theRetVal); + return theRetVal; +} + +// return the min value of the current set of keyframes +float CUICDMTimelineItemProperty::GetMinimumValue() const +{ + float theRetVal = FLT_MAX; + do_all(m_Keyframes, boost::bind(CompareAndSet, _1, boost::ref(theRetVal), false)); + if (m_Type.first == DataModelDataType::Float3 && m_Type.second == AdditionalMetaDataType::Color) + theRetVal = UICDMToColor(theRetVal); + return theRetVal; +} + +void CUICDMTimelineItemProperty::Bind(CPropertyRow *inRow) +{ + ASSERT(!m_Row); + + m_Row = inRow; +} + +void CUICDMTimelineItemProperty::Release() +{ + m_Row = nullptr; +} + +// Ensures the object that owns this property is selected. +void CUICDMTimelineItemProperty::SetSelected() +{ + if (m_Row) { + ITimelineItemBinding *theParentBinding = GetParentBinding(m_Row); + if (theParentBinding) + theParentBinding->SetSelected(false); + } +} + +void CUICDMTimelineItemProperty::ClearKeySelection() +{ + m_TransMgr->ClearKeyframeSelection(); +} + +void CUICDMTimelineItemProperty::DeleteAllKeys() +{ + if (m_Keyframes.empty()) + return; + + using namespace Q3DStudio; + + ScopedDocumentEditor editor(*m_TransMgr->GetDoc(), L"Delete All Keyframes", __FILE__, __LINE__); + for (size_t idx = 0, end = m_AnimationHandles.size(); idx < end; ++idx) + editor->DeleteAllKeyframes(m_AnimationHandles[idx]); +} + +ITimelineKeyframesManager *CUICDMTimelineItemProperty::GetKeyframesManager() const +{ + return m_TransMgr->GetKeyframesManager(); +} + +IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByTime(long inTime) const +{ + std::vector<long> theTest; + TKeyframeList::const_iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + if ((*theIter)->GetTime() == inTime) + return (*theIter); + + theTest.push_back((*theIter)->GetTime()); + } + // if key had been deleted, this returns nullptr + return nullptr; +} + +IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByIndex(long inIndex) const +{ + if (inIndex >= 0 && inIndex < (long)m_Keyframes.size()) + return m_Keyframes[inIndex]; + + ASSERT(0); // should not happen + return nullptr; +} + +long CUICDMTimelineItemProperty::GetKeyframeCount() const +{ + // this list is updated in constructor and when keyframes are added or deleted. + return (long)m_Keyframes.size(); +} + +long CUICDMTimelineItemProperty::GetChannelCount() const +{ + return (long)m_AnimationHandles.size(); +} + +float CUICDMTimelineItemProperty::GetChannelValueAtTime(long inChannelIndex, long inTime) +{ + // if no keyframes, get current property value. + if (m_Keyframes.empty()) { + CUICDMTimelineItemBinding *theParentBinding = + dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row)); + if (theParentBinding) { + + SValue theValue; + UICDM::IPropertySystem *thePropertySystem = + m_TransMgr->GetStudioSystem()->GetPropertySystem(); + thePropertySystem->GetInstancePropertyValue(theParentBinding->GetInstanceHandle(), + m_PropertyHandle, theValue); + switch (m_Type.first) { + case DataModelDataType::Float3: { + if (m_Type.second == AdditionalMetaDataType::Color) { + SFloat3 theFloat3 = UICDM::get<SFloat3>(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 3) + return UICDMToColor(theFloat3[inChannelIndex]); + } else { + SFloat3 theFloat3 = UICDM::get<SFloat3>(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 3) + return theFloat3[inChannelIndex]; + } + break; + } + case DataModelDataType::Float2: { + SFloat2 theFloat2 = UICDM::get<SFloat2>(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 2) + return theFloat2[inChannelIndex]; + break; + } + case DataModelDataType::Float: + return UICDM::get<float>(theValue); + break; + default: // TODO: handle other types + break; + } + } + } + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + if (!m_AnimationHandles.empty() && inChannelIndex >= 0 + && inChannelIndex < (long)m_AnimationHandles.size()) { + float theValue = theAnimationCore->EvaluateAnimation( + m_AnimationHandles[inChannelIndex], CUICDMTimelineKeyframe::GetTimeInSecs(inTime)); + if (m_Type.first == DataModelDataType::Float3 + && m_Type.second == AdditionalMetaDataType::Color) + theValue = UICDMToColor(theValue); + + return theValue; + } + return 0.f; +} + +void CUICDMTimelineItemProperty::SetChannelValueAtTime(long inChannelIndex, long inTime, + float inValue) +{ + using namespace boost; + CUICDMTimelineKeyframe *theKeyframeWrapper = + dynamic_cast<CUICDMTimelineKeyframe *>(GetKeyframeByTime(inTime)); + if (theKeyframeWrapper) { + CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframes; + theKeyframeWrapper->GetKeyframeHandles(theKeyframes); + if (!theKeyframes.empty() && inChannelIndex < (long)theKeyframes.size()) { + inValue /= 255; + if (!m_SetKeyframeValueCommand) + m_SetKeyframeValueCommand = new CCmdDataModelSetKeyframeValue( + g_StudioApp.GetCore()->GetDoc(), theKeyframes[inChannelIndex], inValue); + m_SetKeyframeValueCommand->Update(inValue); + } + } +} + +long CUICDMTimelineItemProperty::OffsetSelectedKeyframes(long inOffset) +{ + long theRetVal = m_TransMgr->GetKeyframesManager()->OffsetSelectedKeyframes(inOffset); + if (m_Row) // UI update, since the data model sends no event while the change isn't commited. + { + m_Row->Refresh(); + } + return theRetVal; +} + +void CUICDMTimelineItemProperty::CommitChangedKeyframes() +{ + if (m_SetKeyframeValueCommand) { // if this is moving a keyframe value + g_StudioApp.GetCore()->ExecuteCommand(m_SetKeyframeValueCommand, false); + m_SetKeyframeValueCommand = nullptr; + } else // otherwise its changing keyframe times + m_TransMgr->GetKeyframesManager()->CommitChangedKeyframes(); +} + +void CUICDMTimelineItemProperty::OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) +{ + (void)inObjectAssociation; + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.SetKeyframesManager(m_TransMgr->GetKeyframesManager()); + theTimeEditDlg.ShowDialog(inCurrentTime, 0, g_StudioApp.GetCore()->GetDoc(), ASSETKEYFRAME); +} + +void CUICDMTimelineItemProperty::SelectKeyframes(bool inSelected, long inTime /*= -1 */) +{ + CUICDMTimelineItemBinding *theParent = + dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row)); + DoSelectKeyframes(inSelected, inTime, false, theParent); +} + +CPropertyRow *CUICDMTimelineItemProperty::GetRow() +{ + return m_Row; +} + +bool CUICDMTimelineItemProperty::IsDynamicAnimation() +{ + return m_Keyframes.size() > 0 && m_Keyframes[0]->IsDynamic(); +} + +//============================================================================= +/** + * For updating the UI when keyframes are added/updated/deleted. + */ +bool CUICDMTimelineItemProperty::RefreshKeyframe(UICDM::CUICDMKeyframeHandle inKeyframe, + ETimelineKeyframeTransaction inTransaction) +{ + bool theHandled = false; + switch (inTransaction) { + case ETimelineKeyframeTransaction_Delete: { + TKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + CUICDMTimelineKeyframe *theKeyframe = *theIter; + if (theKeyframe->HasKeyframeHandle(inKeyframe)) { // clear selection + m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(theKeyframe, false); + m_Keyframes.erase(theIter); + + theHandled = true; + break; + } + } + } break; + case ETimelineKeyframeTransaction_Add: { + ASSERT(!m_AnimationHandles.empty()); + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + CUICDMAnimationHandle theAnimationHandle = + theAnimationCore->GetAnimationForKeyframe(inKeyframe); + // only create for the first animation handle. + if (theAnimationHandle == m_AnimationHandles[0]) { // for undo/redo, the keyframes can be + // added in reverse, hence the need to + // sort + if (CreateKeyframeIfNonExistent(inKeyframe, theAnimationHandle)) + std::stable_sort(m_Keyframes.begin(), m_Keyframes.end(), SortKeyframeByTime); + theHandled = true; + } + } break; + case ETimelineKeyframeTransaction_Update: + case ETimelineKeyframeTransaction_DynamicChanged: + theHandled = true; + break; + default: + return false; + } + if (theHandled && m_Row) + m_Row->Refresh(); + + return theHandled; +} + +IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByHandle(UICDM::CUICDMKeyframeHandle inKeyframe) +{ + TKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + CUICDMTimelineKeyframe *theKeyframe = *theIter; + if (theKeyframe->HasKeyframeHandle(inKeyframe)) + return *theIter; + } + return nullptr; +} + +// This is either triggered from this property's keyframe selection OR from a parent's keyframe +// selection. +void CUICDMTimelineItemProperty::DoSelectKeyframes(bool inSelected, long inTime, + bool inParentTriggered, + CUICDMTimelineItemBinding *inParent) +{ + // this is what it used to do before the refactor. selecting a keyframe always selects the + // asset. + if (inSelected) + SetSelected(); + + if (!inParent) + return; + + if (inTime == -1) // all keyframes + { + TKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + (*theIter)->SetSelected(inSelected); + m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(*theIter, inSelected, inParent); + } + } else { + CUICDMTimelineKeyframe *theKeyframe = + dynamic_cast<CUICDMTimelineKeyframe *>(GetKeyframeByTime(inTime)); + if (theKeyframe) { + theKeyframe->SetSelected(inSelected); + m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(theKeyframe, inSelected, + inParent); + } + } + // Requires UI to be updated explicitly + if (inParentTriggered && m_Row) + m_Row->GetTimebar()->SelectKeysByTime(inTime, inSelected); + + // Support existing feature, selection by mouse-drag a rect, when all property keyframes are + // selected, the asset keyframe is automatically selected as well. + // and the mouse drags 'outside' a keyframe and de-selecting it, the asset keyframe has to be + // deselected as well. + if (!inParentTriggered && inTime != -1) + inParent->OnPropertySelection(inTime); +} + +//============================================================================= +/** + * Create a wrapper for this keyframe if doesn't exists. + * @return true if created, false if already exists. + */ +bool CUICDMTimelineItemProperty::CreateKeyframeIfNonExistent( + UICDM::CUICDMKeyframeHandle inKeyframeHandle, CUICDMAnimationHandle inOwningAnimation) +{ + TKeyframeList::iterator theIter = m_Keyframes.begin(); + for (; theIter != m_Keyframes.end(); ++theIter) { + CUICDMTimelineKeyframe *theKeyframe = *theIter; + if (theKeyframe->HasKeyframeHandle(inKeyframeHandle)) + return false; + } + // check for multiple channels => only create 1 CUICDMTimelineKeyframe + CUICDMTimelineKeyframe *theNewKeyframe = + new CUICDMTimelineKeyframe(g_StudioApp.GetCore()->GetDoc()); + theNewKeyframe->AddKeyframeHandle(inKeyframeHandle); + if (m_AnimationHandles.size() + > 1) { // assert assumption that is only called for the first handle + ASSERT(m_AnimationHandles[0] == inOwningAnimation); + IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + float theKeyframeTime = KeyframeTime(theAnimationCore->GetKeyframeData(inKeyframeHandle)); + for (size_t i = 1; i < m_AnimationHandles.size(); ++i) { + TKeyframeHandleList theKeyframes; + theAnimationCore->GetKeyframes(m_AnimationHandles[i], theKeyframes); + // the data model ensures that there is only 1 keyframe created for a given time + for (size_t theKeyIndex = 0; theKeyIndex < theKeyframes.size(); ++theKeyIndex) { + float theValue = + KeyframeTime(theAnimationCore->GetKeyframeData(theKeyframes[theKeyIndex])); + if (theValue == theKeyframeTime) { + theNewKeyframe->AddKeyframeHandle(theKeyframes[theKeyIndex]); + break; + } + } + } + } + m_Keyframes.push_back(theNewKeyframe); + return true; +} + +void CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged(UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty) +{ + if (inInstance == m_InstanceHandle && inProperty == m_PropertyHandle) { + // Re-bind to keyframes because the ones we should be pointing to will have changed. + ReleaseKeyframes(); + CreateKeyframes(); + } +} + +void CUICDMTimelineItemProperty::RefreshKeyFrames(void) +{ + std::stable_sort(m_Keyframes.begin(), m_Keyframes.end(), SortKeyframeByTime); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h new file mode 100644 index 00000000..ddd4b647 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_UICDMTIMELINE_ITEM_PROPERTY_H +#define INCLUDED_UICDMTIMELINE_ITEM_PROPERTY_H 1 + +#pragma once + +#include "ITimelineItemProperty.h" +#include "UICDMTimelineKeyframe.h" +#include "UICDMTimeline.h" +#include "UICDMPropertyDefinition.h" + +class CTimelineTranslationManager; +class CCmdDataModelSetKeyframeValue; +class CUICDMTimelineItemBinding; + +//============================================================================= +/** + * A data model item's property. + * Typically only animated properties show up in the Timeline. + */ +//============================================================================= +class CUICDMTimelineItemProperty : public ITimelineItemProperty +{ +public: + CUICDMTimelineItemProperty(CTimelineTranslationManager *inTransMgr, + UICDM::CUICDMPropertyHandle inPropertyHandle, + UICDM::CUICDMInstanceHandle inInstance); + virtual ~CUICDMTimelineItemProperty(); + + // ITimelineProperty + Q3DStudio::CString GetName() const override; + bool IsMaster() const override; + UICDM::TDataTypePair GetType() const override; + float GetMaximumValue() const override; + float GetMinimumValue() const override; + void SetSelected() override; + void ClearKeySelection() override; + void DeleteAllKeys() override; + ITimelineKeyframesManager *GetKeyframesManager() const override; + IKeyframe *GetKeyframeByTime(long inTime) const override; + IKeyframe *GetKeyframeByIndex(long inIndex) const override; + long GetKeyframeCount() const override; + long GetChannelCount() const override; + float GetChannelValueAtTime(long inChannelIndex, long inTime) override; + void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) override; + long OffsetSelectedKeyframes(long inOffset) override; + void CommitChangedKeyframes() override; + void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) override; + bool IsDynamicAnimation() override; + // IKeyframeSelector + void SelectKeyframes(bool inSelected, long inTime = -1) override; + + void Bind(CPropertyRow *inRow) override; + void Release() override; + CPropertyRow *GetRow() override; + + bool RefreshKeyframe(UICDM::CUICDMKeyframeHandle inKeyframe, + ETimelineKeyframeTransaction inTransaction); + IKeyframe *GetKeyframeByHandle(UICDM::CUICDMKeyframeHandle inKeyframe); + void DoSelectKeyframes(bool inSelected, long inTime, bool inParentTriggered, + CUICDMTimelineItemBinding *inParent); + + void RefreshKeyFrames(void); + +protected: + void InitializeCachedVariables(UICDM::CUICDMInstanceHandle inInstance); + bool CreateKeyframeIfNonExistent(UICDM::CUICDMKeyframeHandle inKeyframe, + UICDM::CUICDMAnimationHandle inOwningAnimation); + void OnPropertyLinkStatusChanged(UICDM::CUICDMSlideHandle inSlide, + UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + void CreateKeyframes(); + void ReleaseKeyframes(); + +protected: + typedef std::vector<CUICDMTimelineKeyframe *> TKeyframeList; + + CPropertyRow *m_Row; + UICDM::CUICDMInstanceHandle m_InstanceHandle; + UICDM::CUICDMPropertyHandle m_PropertyHandle; + CTimelineTranslationManager *m_TransMgr; + std::vector<UICDM::CUICDMAnimationHandle> m_AnimationHandles; + TKeyframeList m_Keyframes; + CCmdDataModelSetKeyframeValue + *m_SetKeyframeValueCommand; // for merging modifying keyframe values via graph + UICDM::TDataTypePair m_Type; + Q3DStudio::CString m_Name; + std::vector<std::shared_ptr<UICDM::ISignalConnection>> m_Signals; +}; + +#endif // INCLUDED_UICDMTIMELINE_ITEM_PROPERTY_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp new file mode 100644 index 00000000..c29062a2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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 "stdafx.h" +#include "UICDMTimelineKeyframe.h" +#include "UICDMAnimation.h" +#include "CmdDataModelChangeKeyframe.h" +#include "CmdBatch.h" +#include "UICDMStudioSystem.h" +#include "OffsetKeyframesCommandHelper.h" + +#include "Doc.h" +#include "StudioApp.h" +#include "Core.h" + +using namespace UICDM; + +// TODO: figure out if we can just use IDoc instead of CDoc +CUICDMTimelineKeyframe::CUICDMTimelineKeyframe(IDoc *inDoc) + : m_Doc(dynamic_cast<CDoc *>(inDoc)) + , m_Selected(false) +{ +} + +CUICDMTimelineKeyframe::~CUICDMTimelineKeyframe() +{ +} + +bool CUICDMTimelineKeyframe::IsSelected() const +{ + return m_Selected; +} + +float my_roundf(float r) +{ + return (r > 0.0f) ? floorf(r + 0.5f) : ceilf(r - 0.5f); +} + +long CUICDMTimelineKeyframe::GetTime() const +{ + if (!m_KeyframeHandles.empty()) { + IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + CUICDMKeyframeHandle theKeyframeHandle = *m_KeyframeHandles.begin(); + if (theAnimationCore->KeyframeValid(theKeyframeHandle)) { + float theTimeinSecs = + KeyframeTime(theAnimationCore->GetKeyframeData(theKeyframeHandle)); + // We always convert back and forth between between long and float. + // This causes especially issues when we do comparisons + return (long)my_roundf(theTimeinSecs * 1000); + } + } + return -1; // keyframe was deleted, and data cannot be retrieved. +} + +float CUICDMTimelineKeyframe::GetTimeInSecs(long inTime) +{ + float theTimeinSecs = static_cast<float>(inTime) / 1000.f; + // round off to 4 decimal place to workaround precision issues + // TODO: fix this, either all talk float OR long. choose one. + theTimeinSecs = (float)(((theTimeinSecs + 0.00005) * 10000.0) / 10000.0f); + return theTimeinSecs; +} + +void CUICDMTimelineKeyframe::SetTime(const long inNewTime) +{ + float theTimeinSecs = GetTimeInSecs(inNewTime); + CCmd *theCmd = nullptr; + if (m_KeyframeHandles.size() == 1) { + theCmd = new CCmdDataModelSetKeyframeTime(m_Doc, m_KeyframeHandles.front(), theTimeinSecs); + } else { // more than 1 channel + CCmdBatch *theBatch = new CCmdBatch(m_Doc); + TKeyframeHandleList::iterator theIter = m_KeyframeHandles.begin(); + for (; theIter != m_KeyframeHandles.end(); ++theIter) + theBatch->AddCommand(new CCmdDataModelSetKeyframeTime(m_Doc, *theIter, theTimeinSecs)); + theCmd = theBatch; + } + if (theCmd) + m_Doc->GetCore()->ExecuteCommand(theCmd); + +#ifdef _DEBUG + // we have a precision issue from converting from long to float.. + IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + long theTest = static_cast<long>( + KeyframeTime(theAnimationCore->GetKeyframeData(*m_KeyframeHandles.begin())) * 1000); + ASSERT(inNewTime == theTest); +#endif +} + +inline CUICDMAnimationHandle GetAnimationHandle(UICDM::IAnimationCore *inAnimationCore, + const TKeyframeHandleList &inKeyframes) +{ + if (!inKeyframes.empty()) + return inAnimationCore->GetAnimationForKeyframe(inKeyframes[0]); + return 0; +} + +void CUICDMTimelineKeyframe::SetDynamic(bool inIsDynamic) +{ + if (!m_KeyframeHandles.empty()) { + CUICDMAnimationHandle theAnimation = + GetAnimationHandle(m_Doc->GetStudioSystem()->GetAnimationCore(), m_KeyframeHandles); + if (theAnimation.Valid()) + m_Doc->GetCore()->ExecuteCommand( + new CCmdDataModelChangeDynamicKeyframe(m_Doc, theAnimation, inIsDynamic)); + } +} + +// Only the first key of a track can be dynamic. +bool CUICDMTimelineKeyframe::IsDynamic() const +{ + UICDM::IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + CUICDMAnimationHandle theAnimation = GetAnimationHandle(theAnimationCore, m_KeyframeHandles); + if (theAnimation.Valid()) { + SAnimationInfo theInfo = theAnimationCore->GetAnimationInfo(theAnimation); + if (theInfo.m_DynamicFirstKeyframe) { + TKeyframeHandleList theKeyframes; + theAnimationCore->GetKeyframes(theAnimation, theKeyframes); + if (!theKeyframes.empty()) // only true if track is dynamic and this is the first + // keyframe. Might have to optimize because this is so + // clunky. + return (theKeyframes[0] == m_KeyframeHandles[0]); + } + } + return false; +} + +void CUICDMTimelineKeyframe::AddKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle) +{ + m_KeyframeHandles.push_back(inHandle); +} + +bool CUICDMTimelineKeyframe::HasKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle) const +{ + TKeyframeHandleList::const_iterator theIter = m_KeyframeHandles.begin(); + for (; theIter != m_KeyframeHandles.end(); ++theIter) { + if (*theIter == inHandle) + return true; + } + return false; +} + +void CUICDMTimelineKeyframe::SetSelected(bool inSelected) +{ + m_Selected = inSelected; +} + +// For colors, there would be 3 keyframe handles +void CUICDMTimelineKeyframe::UpdateKeyframesTime(COffsetKeyframesCommandHelper *inCommandHelper, + long inTime) +{ + for (size_t i = 0; i < m_KeyframeHandles.size(); ++i) + inCommandHelper->SetCommandTime(m_KeyframeHandles[i], inTime); +} + +void CUICDMTimelineKeyframe::GetKeyframeHandles(TKeyframeHandleList &outList) const +{ + outList = m_KeyframeHandles; +} + +void CompareAndSet(CUICDMKeyframeHandle inKeyframe, IAnimationCore *inAnimationCore, + float &outRetValue, bool inGreaterThan) +{ + TKeyframe theKeyframeData = inAnimationCore->GetKeyframeData(inKeyframe); + float theValue = KeyframeValueValue(theKeyframeData); + if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue)) + outRetValue = theValue; +} + +float CUICDMTimelineKeyframe::GetMaxValue() const +{ + IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + float theRetVal = FLT_MIN; + do_all(m_KeyframeHandles, + std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore, + std::ref(theRetVal), true)); + return theRetVal; +} + +float CUICDMTimelineKeyframe::GetMinValue() const +{ + IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + float theRetVal = FLT_MAX; + do_all(m_KeyframeHandles, + std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore, + std::ref(theRetVal), false)); + return theRetVal; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h new file mode 100644 index 00000000..bb615202 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_UICDMKEYFRAME_H +#define INCLUDED_UICDMKEYFRAME_H 1 + +#pragma once + +#include "IKeyframe.h" + +// Data model specific +#include "UICDMHandles.h" + +class IDoc; +class CDoc; +class CCmdBatch; +class COffsetKeyframesCommandHelper; + +//============================================================================== +/** + * Wrapper for a keyframe in UICDM. + */ +//============================================================================== +class CUICDMTimelineKeyframe : public IKeyframe +{ +public: + typedef std::vector<UICDM::CUICDMKeyframeHandle> TKeyframeHandleList; + +protected: + TKeyframeHandleList + m_KeyframeHandles; ///< no. corresponds to the channels the animated property has. + CDoc *m_Doc; + bool m_Selected; + +public: + CUICDMTimelineKeyframe(IDoc *inDoc); + virtual ~CUICDMTimelineKeyframe(); + + // IKeyframe + bool IsSelected() const override; + long GetTime() const override; + void SetTime(const long inNewTime) override; + void SetDynamic(bool inIsDynamic) override; + bool IsDynamic() const override; + + void AddKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle); + bool HasKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle) const; + void SetSelected(bool inSelected); + void UpdateKeyframesTime(COffsetKeyframesCommandHelper *inCommandHelper, long inTime); + void GetKeyframeHandles(TKeyframeHandleList &outList) const; + + // support drawing graphs + float GetMaxValue() const; + float GetMinValue() const; + + static float GetTimeInSecs(long inTime); +}; + +#endif // INCLUDED_UICDMKEYFRAME_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp new file mode 100644 index 00000000..2c44e438 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICDMTimelineTimebar.h" +#include "UICDMStudioSystem.h" +#include "UICDMDataCore.h" +#include "UICDMDataTypes.h" +#include "ClientDataModelBridge.h" +#include "TimelineTranslationManager.h" +#include "Doc.h" +#include "Dispatch.h" +#include "Core.h" +#include "TimeEditDlg.h" +#include "IDocumentEditor.h" +#include "BaseStateRow.h" +#include "BaseTimebarlessRow.h" +#include "StudioFullSystem.h" +#include "StudioPreferences.h" +#include "ITimelineItemBinding.h" + +CUICDMTimelineTimebar::CUICDMTimelineTimebar( + CTimelineTranslationManager *inTimelineTranslationManager, + UICDM::CUICDMInstanceHandle inDataHandle) + : Q3DStudio::CUpdateableDocumentEditor(*inTimelineTranslationManager->GetDoc()) + , m_TimelineTranslationManager(inTimelineTranslationManager) + , m_PropertySystem(inTimelineTranslationManager->GetStudioSystem()->GetPropertySystem()) + , m_DataHandle(inDataHandle) +{ + CClientDataModelBridge *theClientDataModelBridge = + inTimelineTranslationManager->GetStudioSystem()->GetClientDataModelBridge(); + m_StartTime = theClientDataModelBridge->GetSceneAsset().m_StartTime; + m_EndTime = theClientDataModelBridge->GetSceneAsset().m_EndTime; + UICDM::SValue theValue; + if (m_PropertySystem->GetInstancePropertyValue( + m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor, theValue)) { + UICDM::SFloat3 theTimebarColor = UICDM::get<UICDM::SFloat3>(theValue); + + m_Color.SetRGB(static_cast<int>(theTimebarColor.m_Floats[0] * 255.0f), + static_cast<int>(theTimebarColor.m_Floats[1] * 255.0f), + static_cast<int>(theTimebarColor.m_Floats[2] * 255.0f)); + } + UICDM::IStudioFullSystemSignalProvider *theProvider = + inTimelineTranslationManager->GetStudioSystem()->GetFullSystem()->GetSignalProvider(); + m_PropertyChangedSignal = theProvider->ConnectInstancePropertyValue( + std::bind(&CUICDMTimelineTimebar::OnPropertyChanged, this, + std::placeholders::_1, std::placeholders::_2)); + + OnPropertyChanged(m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor); + OnPropertyChanged(m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarText); +} + +void CUICDMTimelineTimebar::OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty) +{ + if (m_DataHandle == inInstance) { + bool needsInvalidate = false; + UICDM::SValue theValue; + CClientDataModelBridge *theClientDataModelBridge = + m_TimelineTranslationManager->GetStudioSystem()->GetClientDataModelBridge(); + if (inProperty == theClientDataModelBridge->GetSceneAsset().m_TimebarColor) { + + if (m_PropertySystem->GetInstancePropertyValue( + m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor, + theValue)) { + UICDM::SFloat3 theTimebarColor = UICDM::get<UICDM::SFloat3>(theValue); + + m_Color.SetRGB(static_cast<int>(theTimebarColor.m_Floats[0] * 255.0f), + static_cast<int>(theTimebarColor.m_Floats[1] * 255.0f), + static_cast<int>(theTimebarColor.m_Floats[2] * 255.0f)); + } else { + switch (theClientDataModelBridge->GetObjectType(inInstance)) { + case OBJTYPE_LAYER: + m_Color = CStudioPreferences::GetLayerTimebarColor(); + break; + case OBJTYPE_BEHAVIOR: + m_Color = CStudioPreferences::GetBehaviorTimebarColor(); + break; + case OBJTYPE_CAMERA: + m_Color = CStudioPreferences::GetCameraTimebarColor(); + break; + case OBJTYPE_LIGHT: + m_Color = CStudioPreferences::GetLightTimebarColor(); + break; + case OBJTYPE_MODEL: + m_Color = CStudioPreferences::GetModelTimebarColor(); + break; + case OBJTYPE_GROUP: + m_Color = CStudioPreferences::GetGroupTimebarColor(); + break; + case OBJTYPE_COMPONENT: + m_Color = CStudioPreferences::GetComponentTimebarColor(); + break; + case OBJTYPE_EFFECT: + m_Color = CStudioPreferences::GetEffectTimebarColor(); + break; + default: + m_Color = CStudioPreferences::GetObjectTimebarColor(); + break; + } + } + needsInvalidate = true; + } else if (inProperty == theClientDataModelBridge->GetSceneAsset().m_TimebarText) { + if (m_PropertySystem->GetInstancePropertyValue( + m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarText, + theValue)) { + UICDM::SStringRef theTimebarComment = UICDM::get<UICDM::SStringRef>(theValue); + m_Comment.Assign(static_cast<const wchar_t *>(theTimebarComment)); + } else { + m_Comment.Assign(L""); + } + needsInvalidate = true; + } + if (needsInvalidate) { + ITimelineItemBinding *theBinding = + m_TimelineTranslationManager->GetOrCreate(inInstance); + if (theBinding) { + CBaseStateRow *theRow = theBinding->GetRow(); + if (theRow) { + CBaseTimebarlessRow *theTimebar = theRow->GetTimebar(); + theTimebar->RefreshRowMetaData(); + } + } + } + } +} + +CUICDMTimelineTimebar::~CUICDMTimelineTimebar() +{ +} + +// TODO: Can we put this on IInstancePropertyCore? +template <typename T> +T GetInstancePropertyValue(UICDM::IPropertySystem *inPropertySystem, + UICDM::CUICDMInstanceHandle inInstanceHandle, + UICDM::CUICDMPropertyHandle inProperty) +{ + UICDM::SValue theValue; + inPropertySystem->GetInstancePropertyValue(inInstanceHandle, inProperty, theValue); + return UICDM::get<T>(theValue); +} + +long CUICDMTimelineTimebar::GetStartTime() const +{ + return GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_StartTime); +} + +long CUICDMTimelineTimebar::GetEndTime() const +{ + return GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_EndTime); +} + +long CUICDMTimelineTimebar::GetDuration() const +{ + auto theStartTime = GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_StartTime); + auto theEndTime = GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_EndTime); + + return theEndTime - theStartTime; +} + +bool CUICDMTimelineTimebar::ShowHandleBars() const +{ + return true; +} + +void CUICDMTimelineTimebar::OnBeginDrag() +{ // Really? TODO: Figure out why this is here. + // ASSERT(0); +} + +void CUICDMTimelineTimebar::OffsetTime(long inDiff) +{ + if (m_DataHandle.Valid()) { + ENSURE_EDITOR(L"Time Bar Move").OffsetTimeRange(m_DataHandle, inDiff); + m_TimelineTranslationManager->GetDoc() + ->GetCore() + ->GetDispatch() + ->FireImmediateRefreshInstance(m_DataHandle); + } +} + +void CUICDMTimelineTimebar::ChangeTime(long inTime, bool inSetStart) +{ + if (m_DataHandle.Valid()) { + ENSURE_EDITOR(L"Time Bar Resize").ResizeTimeRange(m_DataHandle, inTime, inSetStart); + m_TimelineTranslationManager->GetDoc() + ->GetCore() + ->GetDispatch() + ->FireImmediateRefreshInstance(m_DataHandle); + } +} + +void CUICDMTimelineTimebar::CommitTimeChange() +{ + CommitEditor(); +} + +void CUICDMTimelineTimebar::RollbackTimeChange() +{ + RollbackEditor(); +} + +void CUICDMTimelineTimebar::SetTimebarColor(const ::CColor &inColor) +{ + using namespace Q3DStudio; + if (inColor != m_Color) { + UICDM::CUICDMInstanceHandle theHandle = m_DataHandle; + SCOPED_DOCUMENT_EDITOR(*m_TimelineTranslationManager->GetDoc(), QObject::tr("Set Timebar Color")) + ->SetTimebarColor(theHandle, inColor); + } +} + +void CUICDMTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComment) +{ + using namespace Q3DStudio; + if (inComment != m_Comment) { + UICDM::CUICDMInstanceHandle theHandle = m_DataHandle; + SCOPED_DOCUMENT_EDITOR(*m_TimelineTranslationManager->GetDoc(), QObject::tr("Set Timebar Text")) + ->SetTimebarText(theHandle, inComment); + } +} + +void CUICDMTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/) +{ + long theStartTime = GetStartTime(); + long theEndTime = GetEndTime(); + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.ShowDialog(theStartTime, theEndTime, m_TimelineTranslationManager->GetDoc(), + TIMEBAR, inCallback); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h new file mode 100644 index 00000000..d1441039 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// Includes +#include "ITimelineTimebar.h" +#include "UICDMHandles.h" +#include "IDocumentEditor.h" + +/////////////////////////////////////////////////////////////////////////////// +// Forwards +class CTimelineTranslationManager; + +namespace Q3DStudio { +class IDocumentEditor; +} + +namespace UICDM { +class IPropertySystem; +class ISignalConnection; +} + +//============================================================================= +/** + * General timebar implementation for UICDM objects + */ +class CUICDMTimelineTimebar : public ITimelineTimebar, public Q3DStudio::CUpdateableDocumentEditor +{ +public: + CUICDMTimelineTimebar(CTimelineTranslationManager *inTimelineTranslationManager, + UICDM::CUICDMInstanceHandle inDataHandle); + virtual ~CUICDMTimelineTimebar(); + +protected: + CTimelineTranslationManager *m_TimelineTranslationManager; + UICDM::IPropertySystem *m_PropertySystem; + UICDM::CUICDMInstanceHandle m_DataHandle; // The Instance Handle for this Timeline Timeber. + UICDM::CUICDMPropertyHandle m_StartTime; + UICDM::CUICDMPropertyHandle m_EndTime; + ::CColor m_Color; // Timebar color + Q3DStudio::CString m_Comment; // Timebar comment text + std::shared_ptr<UICDM::ISignalConnection> m_PropertyChangedSignal; + void OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMPropertyHandle inProperty); + +public: + // ITimelineTimebar + long GetStartTime() const override; + long GetEndTime() const override; + long GetDuration() const override; + bool ShowHandleBars() const override; + void OnBeginDrag() override; + void OffsetTime(long inDiff) override; + void ChangeTime(long inTime, bool inSetStart) override; + void CommitTimeChange() override; + void RollbackTimeChange() override; + ::CColor GetTimebarColor() override { return m_Color; } + void SetTimebarColor(const ::CColor &inColor) override; + Q3DStudio::CString GetTimebarComment() override { return m_Comment; } + void SetTimebarComment(const Q3DStudio::CString &inComment) override; + void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) override; +}; diff --git a/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp new file mode 100644 index 00000000..fb25559a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "BlankToggleControl.h" +#include "Renderer.h" +#include "BaseStateRow.h" +#include "StudioPreferences.h" +#include "HotKeys.h" + +CBlankToggleControl::CBlankToggleControl(CBaseStateRow *inBaseStateRow) + : m_StateRow(inBaseStateRow) + , m_Selected(false) +{ + m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(inBaseStateRow->GetObjectType()); +} + +CBlankToggleControl::~CBlankToggleControl() +{ +} + +//============================================================================== +/** + * Handles the drawing fo rthe toggle control + */ +void CBlankToggleControl::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + // Fill in the background + if (!m_Selected) + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + else + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor()); + + // Draw the line at the bottom of this control + inRenderer->PushPen(CStudioPreferences::GetTreeFloorColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); + + // Draw the line on the left side of this control + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theRect.size.y - 1)); + inRenderer->PopPen(); + + // Draw the highlight + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(1, 0)); + inRenderer->LineTo(CPt(1, theRect.size.y - 1)); + inRenderer->PopPen(); + + // Draw the line on the right side of this control + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(CPt(theRect.size.x - 1, 0)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been selected. + */ +void CBlankToggleControl::OnSelect() +{ + m_Selected = true; + + Invalidate(); +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been deselected. + */ +void CBlankToggleControl::OnDeselect() +{ + m_Selected = false; + + Invalidate(); +} + +//============================================================================== +/** + * Handler for the OnMouseDown event + * + * @param inPoint the point where this event takes place + * @param inFlags the state when this event takes place. + */ +bool CBlankToggleControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_StateRow->Select(SBaseStateRowSelectionKeyState()); + } + return true; +} + +//============================================================================== +/** + * Sets the background color of this toggle control + */ +void CBlankToggleControl::SetBackgroundColor(::CColor inBackgroundColor) +{ + if (m_BackgroundColor == inBackgroundColor) + return; + + m_BackgroundColor = inBackgroundColor; + + Invalidate(); +} + +//============================================================================== +/** + * Handler for the OnMouseOver event + * + * @param inPoint the point where this event takes place + * @param inFlags the state when this event takes place. + */ +void CBlankToggleControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + m_StateRow->OnMouseOver(); +} + +//============================================================================== +/** + * Handler for the OnMouseOut event + * + * @param inPoint the point where this event takes place + * @param inFlags the state when this event takes place. + */ +void CBlankToggleControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + m_StateRow->OnMouseOut(); +} + +void CBlankToggleControl::Refresh() +{ +} diff --git a/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h new file mode 100644 index 00000000..2fe4ce28 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_BLANK_TOGGLE_CONTROL_H +#define INCLUDED_BLANK_TOGGLE_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" + +class CBaseStateRow; + +class CBlankToggleControl : public CControl +{ +public: + CBlankToggleControl(CBaseStateRow *inStateRow); + virtual ~CBlankToggleControl(); + + void Draw(CRenderer *inRenderer) override; + + void OnSelect(); + void OnDeselect(); + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void SetBackgroundColor(::CColor inBackgroundColor); + + virtual void Refresh(); + +protected: + CBaseStateRow *m_StateRow; + bool m_Selected; + + ::CColor m_BackgroundColor; +}; +#endif // INCLUDED_BLANK_TOGGLE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp new file mode 100644 index 00000000..2564d087 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ColorBlankControl.h" +#include "Renderer.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Constructor + */ +CColorBlankControl::CColorBlankControl(CColor inColor) + : CBlankControl(inColor) +{ +} + +//============================================================================= +/** + * Destructor + */ +CColorBlankControl::~CColorBlankControl() +{ +} + +//============================================================================= +/** + * Handles custom drawing of the blank control underneath the tree control + * on the timeline palette. + */ +void CColorBlankControl::Draw(CRenderer *inRenderer) +{ + CBlankControl::Draw(inRenderer); + + // Draw the line on the right side of this control + CPt theSize = GetSize(); + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(theSize.x - 1, 0); + inRenderer->LineTo(theSize.x - 1, theSize.y - 1); + inRenderer->PopPen(); + + // Draw the line on the left side of this control + inRenderer->PushPen(CStudioPreferences::GetRowTopColor()); + inRenderer->MoveTo(0, 0); + inRenderer->LineTo(0, theSize.y - 1); + inRenderer->PopPen(); + + // Draw the highlight on the left side of this control + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(1, 0)); + inRenderer->LineTo(CPt(1, theSize.y - 1)); + inRenderer->PopPen(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h new file mode 100644 index 00000000..bb85b2aa --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_COLOR_BLANK_CONTROL_H +#define INCLUDED_COLOR_BLANK_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BlankControl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================= +/** + * Extends the blank control to draw items specific to the tree view side of the + * timeline palette. + */ +class CColorBlankControl : public CBlankControl +{ +public: + CColorBlankControl(CColor inColor = CStudioPreferences::GetBaseColor()); + virtual ~CColorBlankControl(); + void Draw(CRenderer *inRenderer) override; + +protected: +}; + +#endif // INCLUDED_COLOR_BLANK_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp new file mode 100644 index 00000000..71d1c392 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "CColor.h" +#include "ColorControl.h" +#include "CoreUtils.h" +#include "BaseStateRow.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include "Dispatch.h" +#include "ResourceCache.h" +#include "Bindings/ITimelineItem.h" + +//============================================================================== +/** + * The control (of each row) to the left of the tree view, where it indicates if there are + *actions associated with this row. + */ +CColorControl::CColorControl(CBaseStateRow *inRow) + : m_Shaded(true) + , m_Selected(false) + , m_HasAction(false) + , m_HasMasterAction(false) + , m_ChildHasAction(false) + , m_ChildHasMasterAction(false) + , m_ComponentHasAction(false) + , m_ComponentHasMasterAction(false) +{ + m_ParentRow = inRow; + m_BackgroundColor = m_ParentRow->GetTimebarBackgroundColor(m_ParentRow->GetObjectType()); + + UpdateIconStatus(); +} + +CColorControl::~CColorControl() +{ +} + +void CColorControl::SetShaded(bool inIsShaded) +{ + m_Shaded = inIsShaded; +} + +//============================================================================== +/** + * Draw + * + * draws this object + * + * @param inRenderer a renderer object + */ +void CColorControl::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + // + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + // bottom + inRenderer->MoveTo(CPt(1, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + // left + inRenderer->MoveTo(CPt(0, 1)); + inRenderer->LineTo(CPt(0, theRect.size.y - 1)); + // right + inRenderer->MoveTo(CPt(theRect.size.x - 1, 1)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + // + inRenderer->PopPen(); + + CPt thePos(0, 0); + if (m_HasMasterAction) { + if (m_ActionImages[IMAGETYPE_MASTERACTION].isNull()) + m_ActionImages[IMAGETYPE_MASTERACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-MasterAction.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_MASTERACTION]); + } else if (m_HasAction) { + if (m_ActionImages[IMAGETYPE_ACTION].isNull()) + m_ActionImages[IMAGETYPE_ACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-Action.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_ACTION]); + } + if (m_ChildHasMasterAction) { + if (m_ActionImages[IMAGETYPE_CHILDMASTERACTION].isNull()) + m_ActionImages[IMAGETYPE_CHILDMASTERACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-ChildMasterAction.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_CHILDMASTERACTION]); + } else if (m_ChildHasAction) { + if (m_ActionImages[IMAGETYPE_CHILDACTION].isNull()) + m_ActionImages[IMAGETYPE_CHILDACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-ChildAction.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_CHILDACTION]); + } + if (m_ComponentHasMasterAction) { + if (m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION].isNull()) + m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-ComponentMasterAction.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION]); + } else if (m_ComponentHasAction) { + if (m_ActionImages[IMAGETYPE_COMPONENTACTION].isNull()) + m_ActionImages[IMAGETYPE_COMPONENTACTION] = + CResourceCache::GetInstance()->GetBitmap("Action-ComponentAction.png"); + + inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_COMPONENTACTION]); + } + + // the old code with selection + + // inRenderer->DrawGradientBitmap( theRect, m_ParentRow->GetAsset( )->GetTimebarColor( ), false + // ); + // if ( m_Selected ) + //{ + // long theXSize = theRect.size.x / 2; + // long theYSize = theRect.size.y / 2; + // inRenderer->FillSolidRect( CRct( CPt( theXSize / 2, theYSize / 2 ), CPt( theXSize, theYSize) + //), CalculateSelectedColor( m_ParentRow->GetAsset( )->GetTimebarColor( ) ) ); + //} + + // if this is selected then do something special + // if ( m_Shaded ) + //{ + // // This is used for the left line of the color control + // CColor theNonGradiantHighlight = m_ParentRow->GetAsset( )->GetTimebarColor( ); + // float theLuminance = theNonGradiantHighlight.GetLuminance( ); + // theLuminance = theLuminance * (float)1.15; + // if ( theLuminance > 1.0 ) + // { + // theLuminance = (float)1.0; + // } + // + // // Highlight on left edge + // theNonGradiantHighlight.SetLuminance( theLuminance ); + // inRenderer->PushPen( theNonGradiantHighlight ); + // inRenderer->MoveTo( CPt( 1, 0 ) ); + // inRenderer->LineTo( CPt( 1, theRect.size.y - 1 ) ); + // inRenderer->PopPen( ); + + // // Dark line on far left edge + // inRenderer->PushPen( CStudioPreferences::GetRowTopColor( ) ); + // inRenderer->MoveTo( CPt( 0, 0 ) ); + // inRenderer->LineTo( CPt( 0, theRect.size.y - 1 ) ); + // inRenderer->PopPen( ); + // + // inRenderer->PushPen( CStudioPreferences::GetRowTopColor( ) ); + // inRenderer->MoveTo( CPt( 0,theRect.size.y - 1 ) ); + // inRenderer->LineTo( CPt( theRect.size.x, theRect.size.y - 1 ) ); + // inRenderer->MoveTo( CPt( theRect.size.x - 1, 0 ) ); + // inRenderer->LineTo( CPt( theRect.size.x - 1, theRect.size.y - 1 ) ); + // inRenderer->PopPen( ); + //} + + // inRenderer->Draw3dRect( CRct( theRect.position, CPt( theRect.size.x, theRect.size.y + 1 ) ), + // CColor( 0, 255, 0 ), CColor( 0, 255, 0 ) ); +} + +//============================================================================== +/** + * CalculateNonGradiantHighlight + * + * calculates the highlight for this color + * + * @param inColor color to multiply + */ +CColor CColorControl::CalculateNonGradiantHighlight(CColor inColor) +{ + double theNonGradiantHighlightR = inColor.GetRed() * 1.15; + double theNonGradiantHighlightG = inColor.GetGreen() * 1.15; + double theNonGradiantHighlightB = inColor.GetBlue() * 1.15; + if (theNonGradiantHighlightR > 255) { + theNonGradiantHighlightR = 255; + } + if (theNonGradiantHighlightG > 255) { + theNonGradiantHighlightG = 255; + } + if (theNonGradiantHighlightB > 255) { + theNonGradiantHighlightB = 255; + } + return CColor(::dtol(theNonGradiantHighlightR), ::dtol(theNonGradiantHighlightG), + ::dtol(theNonGradiantHighlightB)); +} + +//============================================================================== +/** + * CalculateNonGradiantHighlight + * + * calculates the highlight for this color + * + * @param inColor color to multiply + */ +CColor CColorControl::CalculateSelectedColor(CColor inColor) +{ + double theNonGradiantHighlightR = inColor.GetRed() * 0.65; + double theNonGradiantHighlightG = inColor.GetGreen() * 0.65; + double theNonGradiantHighlightB = inColor.GetBlue() * 0.65; + if (theNonGradiantHighlightR > 255) { + theNonGradiantHighlightR = 255; + } + if (theNonGradiantHighlightG > 255) { + theNonGradiantHighlightG = 255; + } + if (theNonGradiantHighlightB > 255) { + theNonGradiantHighlightB = 255; + } + return CColor(::dtol(theNonGradiantHighlightR), ::dtol(theNonGradiantHighlightG), + ::dtol(theNonGradiantHighlightB)); +} + +//============================================================================== +/** + * Handles the OnMouseDownEvent + */ +bool CColorControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + return true; +} + +//============================================================================== +/** + * Called when this row becomes selected + */ +void CColorControl::OnSelect() +{ + m_Selected = true; + this->Invalidate(); +} + +//============================================================================== +/** + * Called when this row becomes deselected + */ +void CColorControl::OnDeselect() +{ + m_Selected = false; + this->Invalidate(); +} + +//============================================================================== +/** + * Updates the icon used for display based on the following logic: + * 1. Self has actions + * 2. Descendents have actions + * Results in 4 states. + */ +void CColorControl::UpdateIconStatus() +{ + ITimelineItem *theTimelineItem = m_ParentRow->GetTimelineItem(); + + if (!theTimelineItem) + return; + + // Master 'supersede' non-master + m_HasMasterAction = theTimelineItem->HasAction(true); + if (!m_HasMasterAction) + m_HasAction = theTimelineItem->HasAction(false); + + // no descendent info if current row is expanded + if (!m_ParentRow->IsExpanded()) { + m_ChildHasMasterAction = theTimelineItem->ChildrenHasAction(true); + if (!m_ChildHasMasterAction) + m_ChildHasAction = theTimelineItem->ChildrenHasAction(false); + } else { + m_ChildHasMasterAction = false; + m_ChildHasAction = false; + } + + m_ComponentHasMasterAction = theTimelineItem->ComponentHasAction(true); + if (!m_ComponentHasMasterAction) + m_ComponentHasAction = theTimelineItem->ComponentHasAction(false); + + this->Invalidate(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorControl.h b/src/Authoring/Studio/Palettes/Timeline/ColorControl.h new file mode 100644 index 00000000..ec5b156d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ColorControl.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_COLOR_CONTROL_H +#define INCLUDED_COLOR_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" +#include "CmdStack.h" + +#include <QPixmap> + +class CBaseStateRow; + +//============================================================================== +/** + * The control at the left side of the TimeContextRow. + * It is currently being used to indicate if the Asset or its descendents have any Action. + */ +class CColorControl : public CControl +{ +protected: + enum EImageType { + IMAGETYPE_ACTION = 0, ///< Types of action image + IMAGETYPE_MASTERACTION, + IMAGETYPE_CHILDACTION, + IMAGETYPE_CHILDMASTERACTION, + IMAGETYPE_COMPONENTACTION, + IMAGETYPE_COMPONENTMASTERACTION, + IMAGETYPE_MAXCOUNT + }; + +public: + CColorControl(CBaseStateRow *inRow); + virtual ~CColorControl(); + + void SetColor(::CColor inColor); + + void SetShaded(bool inIsShaded); + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void Draw(CRenderer *inRenderer) override; + ::CColor CalculateNonGradiantHighlight(::CColor inColor); + + void OnSelect(); + void OnDeselect(); + + static ::CColor CalculateSelectedColor(::CColor inCOLOR); + + void UpdateIconStatus(); + +protected: + ::CColor m_BackgroundColor; + bool m_Shaded; + bool m_Selected; + CBaseStateRow *m_ParentRow; + + /////////////////////////////////////////////////// + // Action icons + // Action status + bool m_HasAction; + bool m_HasMasterAction; + bool m_ChildHasAction; + bool m_ChildHasMasterAction; + bool m_ComponentHasAction; + bool m_ComponentHasMasterAction; + // Action images + QPixmap m_ActionImages[IMAGETYPE_MAXCOUNT]; +}; +#endif // INCLUDED_COLOR_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp new file mode 100644 index 00000000..d0d5325f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "CommentEdit.h" +#include "Renderer.h" +#include "ColorControl.h" +#include "Bindings/ITimelineTimebar.h" +#include "CoreUtils.h" +//============================================================================= +/** + * Constructor + */ +CCommentEdit::CCommentEdit(ITimelineTimebar *inTimelineItemTimebar) + : m_TimelineItemTimebar(inTimelineItemTimebar) + , m_IsSelected(false) +{ + AddCommitListener(this); +} + +//============================================================================= +/** + * Destructor + */ +CCommentEdit::~CCommentEdit() +{ + RemoveCommitListener(this); +} + +//============================================================================= +/** + * Called when a property changes. + * @param inProperty the property that was changed + * @param inIsVisibleChange true if this is a change that effects the property's visibility in the + * Timeline + */ +void CCommentEdit::OnSetData(CControl *inControl) +{ + if (inControl == this && m_TimelineItemTimebar) { + m_TimelineItemTimebar->SetTimebarComment(GetString()); + } +} + +//============================================================================= +/** + * Called when this control receives a double click, edit the comment. + * + * @param inPoint the point where the double click occured + * @param inFlags the flags at the time of the click + */ +bool CCommentEdit::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + if (GetDisplayString().Length() > 0) { + DoChangeComment(); + return true; + } + return false; +} + +//============================================================================= +/** + * Edit the Comment + * + */ +void CCommentEdit::DoChangeComment() +{ + SetEditMode(true); + SelectAllText(); +} + +//============================================================================= +/** + * Called when this control receives a mouse down, don't do anything unless we're in edit mode + * + * @param inPoint the point where the click occured + * @param inFlags the flags at the time of the click + */ +bool CCommentEdit::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + if (GetEditMode()) { + theRetVal = CTextEditInPlace::OnMouseDown(inPoint, inFlags); + } + return theRetVal; +} + +//============================================================================= +/** + * Called when this control loses focus + */ +void CCommentEdit::OnLoseFocus() +{ + CStringEdit::OnLoseFocus(); + SetEditMode(false); +} + +//============================================================================= +/** + * Called when this control gains focus, don't do anytihng + */ +void CCommentEdit::OnGainFocus() +{ +} + +//============================================================================= +/** + * Override for the draw, don't set the size of this control here since we are in + * a comment and wouldn't want the size changing + */ +void CCommentEdit::Draw(CRenderer *inRenderer) +{ + CPt theRectPoint = CPt(::dtol(CalculateCharWidths(inRenderer) + GetRightBuffer()), GetSize().y); + CPt theSize = GetSize(); + if (theSize.x < theRectPoint.x) + theRectPoint.x = theSize.x; + CRct theRect = CRct(theRectPoint); + ::CColor theOutlineColor = ::CColor(0, 0, 0); + bool theFillFlag = m_FillBackground; + + if (theFillFlag && !GetEditMode()) + SetFillBackground(false); + + if (GetEditMode()) + SetTextColor(::CColor(0, 0, 0)); + + inRenderer->PushClippingRect(theRect); + CStringEdit::Draw(inRenderer); + inRenderer->PopClippingRect(); + + if (!GetEditMode()) + SetFillBackground(theFillFlag); + + if (GetEditMode()) + inRenderer->DrawRectOutline(theRect, theOutlineColor, theOutlineColor, theOutlineColor, + theOutlineColor); +} + +//============================================================================= +/** + * Called when the timebar comment or the time bar color changes on an asset + */ +void CCommentEdit::RefreshMetaData() +{ + m_Color = ::CColor(m_TimelineItemTimebar->GetTimebarColor()); + CalculateTextColor(); + SetData(m_TimelineItemTimebar->GetTimebarComment()); + + Invalidate(); +} + +//============================================================================= +/** + * Calculates the text color based on whether the object is selected or not + */ +void CCommentEdit::CalculateTextColor() +{ + ::CColor theColor = m_Color; + float theLuminance = theColor.GetLuminance(); + if (m_IsSelected) { + theLuminance = theLuminance * 0.8f; + } + // Duplicated Code to check luminance when the timebar changes color + + if (theLuminance < 0.5) { + SetTextColor(::CColor(255, 255, 255)); + } else { + SetTextColor(::CColor(0, 0, 0)); + } +} + +//============================================================================= +/** + * Sets this object as selected + * @param inPoint the point to check + */ +void CCommentEdit::SetSelected(bool inState) +{ + m_IsSelected = inState; + CalculateTextColor(); +} + +//============================================================================= +/** + * Overrides the hit test for the case when the click occurs in the object, but outside the text + * @param inPoint the point to check + */ +bool CCommentEdit::HitTest(const CPt &inPoint) const +{ + // rp this seems wrong but apparently it magically works + bool theRetVal = false; + if (inPoint.x + < m_TotalCharWidth + GetRightBuffer() + 2 * CStudioPreferences::GetTimebarTipSize()) + theRetVal = CTextEditInPlace::HitTest(inPoint); + return theRetVal; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h new file mode 100644 index 00000000..8ae37ad9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_COMMENT_EDIT +#define INCLUDED_COMMENT_EDIT 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "TextEditInPlace.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class ITimelineTimebar; + +//============================================================================= +/** + * @class CCommentEdit this class handles changing the comments for a timebar in + * the timeline. This class seems necessary only to change the color of the text + * depending on the timebar color + */ +class CCommentEdit : public CTextEditInPlace, public CCommitDataListener +{ +public: + CCommentEdit(ITimelineTimebar *inTimelineItemTimebar); + virtual ~CCommentEdit(); + void OnSetData(CControl *inControl) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void Draw(CRenderer *inRenderer) override; + void RefreshMetaData(); + void CalculateTextColor(); + bool HitTest(const CPt &inPoint) const override; + void SetSelected(bool inState); + + void OnLoseFocus() override; + void OnGainFocus() override; + + void DoChangeComment(); + +protected: + ITimelineTimebar *m_TimelineItemTimebar; + ::CColor m_Color; + bool m_IsSelected; +}; + +#endif // INCLUDED_COMMENT_EDIT diff --git a/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp new file mode 100644 index 00000000..8909ab7e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ComponentContextMenu.h" +#include "TimelineControl.h" +#include "StudioUtils.h" +#include "StudioClipboard.h" +#include "Dialogs.h" +#include "BaseTimelineTreeControl.h" +#include "Bindings/ITimelineItemBinding.h" +#include "RelativePathTools.h" + +CComponentContextMenu::CComponentContextMenu(CBaseTimelineTreeControl *inTreeControl, + ITimelineItemBinding *inTimelineItemBinding, + QWidget *parent) + : QMenu(parent) + , m_TreeControl(inTreeControl) + , m_TimelineItemBinding(inTimelineItemBinding) +{ + Initialize(); +} + +void CComponentContextMenu::Initialize() +{ + m_renameAction = new QAction(tr("Rename Object"), this); + connect(m_renameAction, &QAction::triggered, this, &CComponentContextMenu::RenameObject); + addAction(m_renameAction); + + m_duplicateAction = new QAction(tr("Duplicate Object"), this); + connect(m_duplicateAction, &QAction::triggered, this, &CComponentContextMenu::DuplicateObject); + addAction(m_duplicateAction); + + m_deleteAction = new QAction(tr("Delete Object"), this); + connect(m_deleteAction, &QAction::triggered, this, &CComponentContextMenu::DeleteObject); + addAction(m_deleteAction); + + addSeparator(); + + m_copyAction = new QAction(tr("Copy"), this); + connect(m_copyAction, &QAction::triggered, this, &CComponentContextMenu::CopyObject); + addAction(m_copyAction); + + m_pasteAction = new QAction(tr("Paste"), this); + connect(m_pasteAction, &QAction::triggered, this, &CComponentContextMenu::PasteObject); + addAction(m_pasteAction); + + m_cutAction = new QAction(tr("Cut"), this); + connect(m_cutAction, &QAction::triggered, this, &CComponentContextMenu::CutObject); + addAction(m_cutAction); + addSeparator(); + + m_makeAction = new QAction(tr("Make Component"), this); + connect(m_makeAction, &QAction::triggered, this, &CComponentContextMenu::MakeComponent); + addAction(m_makeAction); + + if (CanInspectComponent()) { + m_inspectAction = new QAction(tr("Edit Component"), this); + connect(m_inspectAction, &QAction::triggered, this, &CComponentContextMenu::InspectComponent); + addAction(m_inspectAction); + } + + if (m_TimelineItemBinding->IsExternalizeable()) { + addSeparator(); + m_externalizeAction = new QAction(tr("Externalize Buffer"), this); + connect(m_externalizeAction, &QAction::triggered, this, &CComponentContextMenu::Externalize); + addAction(m_externalizeAction); + } else if (m_TimelineItemBinding->IsInternalizeable()) { + addSeparator(); + m_internalizeAction = new QAction(tr("Internalize Buffer"), this); + connect(m_internalizeAction, &QAction::triggered, this, &CComponentContextMenu::Internalize); + addAction(m_internalizeAction); + } + + addSeparator(); + + m_copyPathAction = new QAction(tr("Copy Object Path"), this); + connect(m_copyPathAction, &QAction::triggered, this, &CComponentContextMenu::CopyObjectPath); + addAction(m_copyPathAction); +} + +void CComponentContextMenu::showEvent(QShowEvent *event) +{ + m_renameAction->setEnabled(CanRenameObject()); + m_duplicateAction->setEnabled(CanDuplicateObject()); + m_deleteAction->setEnabled(CanDeleteObject()); + + m_cutAction->setEnabled(CanCutObject()); + m_copyAction->setEnabled(CanCopyObject()); + m_pasteAction->setEnabled(CanPasteObject()); + + m_makeAction->setEnabled(CanMakeComponent()); + + QMenu::showEvent(event); +} + + +CComponentContextMenu::~CComponentContextMenu() +{ + // This will result in a double deletion. + // DeletePerformers( ); +} + +//============================================================================= +/** + * Checks to see if the object can be renamed. + * @return true if the object can be renamed. + */ +bool CComponentContextMenu::CanRenameObject() +{ + return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Rename); +} + +//============================================================================= +/** + * Rename the object. + */ +void CComponentContextMenu::RenameObject() +{ + m_TreeControl->DoRename(); +} + +//============================================================================= +/** + * Checks to see if the object can be duplicated. + * @return true if the object can be duplicated. + */ +bool CComponentContextMenu::CanDuplicateObject() +{ + return m_TimelineItemBinding->IsValidTransaction( + ITimelineItemBinding::EUserTransaction_Duplicate); +} + +//============================================================================= +/** + * Duplicate the object. + */ +void CComponentContextMenu::DuplicateObject() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Duplicate); +} + +//============================================================================= +/** + * Checks to see if the object can be deleted. + * @return true if the object can be deleted. + */ +bool CComponentContextMenu::CanDeleteObject() +{ + return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Delete); +} + +//============================================================================= +/** + * Deletes the object from the scene graph. + */ +void CComponentContextMenu::DeleteObject() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Delete); +} + +//============================================================================= +/** + * Checks to see if the State is a component and can be inspected. + * @return true is the state is a component and can be inspected. + */ +bool CComponentContextMenu::CanInspectComponent() +{ + return m_TimelineItemBinding->IsValidTransaction( + ITimelineItemBinding::EUserTransaction_EditComponent); +} + +//============================================================================= +/** + * Inspect the State (Component). + * This will make the component the top level item of the timelineview. + */ +void CComponentContextMenu::InspectComponent() +{ + m_TimelineItemBinding->OpenAssociatedEditor(); +} + +//============================================================================= +/** + * Checks to see if the object can be wrapped in a component. + * @return true if the object is allowed to be wrapped in a component. + */ +bool CComponentContextMenu::CanMakeComponent() +{ + return m_TimelineItemBinding->IsValidTransaction( + ITimelineItemBinding::EUserTransaction_MakeComponent); +} + +//============================================================================= +/** + * Wraps the specified asset hierarchy under a component. + */ +void CComponentContextMenu::MakeComponent() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_MakeComponent); +} + +//============================================================================= +/** + * Get the full Scripting path of the object and copy it to the clipboard. + * This will figure out the proper way to address the object via scripting + * and put that path into the clipboard. + */ +void CComponentContextMenu::CopyObjectPath() +{ + CStudioClipboard::CopyTextToClipboard(m_TimelineItemBinding->GetObjectPath().toQString()); +} + +//============================================================================= +/** + * Checks to see if the object can be copied + * @return true if the object can be copied + */ +bool CComponentContextMenu::CanCopyObject() +{ + return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Copy); +} + +//============================================================================= +/** + * Copy the object. + */ +void CComponentContextMenu::CopyObject() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Copy); +} + +bool CComponentContextMenu::CanCutObject() +{ + return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Cut); +} + +void CComponentContextMenu::CutObject() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Cut); +} + +//============================================================================= +/** + * Checks to see if the object can be pasted + * @return true if the object can be pasted + */ +bool CComponentContextMenu::CanPasteObject() +{ + return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Paste); +} + +//============================================================================= +/** + * Paste the object. + */ +void CComponentContextMenu::PasteObject() +{ + m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Paste); +} + +ITimelineItem *CComponentContextMenu::GetTimelineItem() const +{ + return m_TimelineItemBinding->GetTimelineItem(); +} + +void CComponentContextMenu::Externalize() +{ + m_TimelineItemBinding->Externalize(); +} + +void CComponentContextMenu::Internalize() +{ + m_TimelineItemBinding->Internalize(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h new file mode 100644 index 00000000..cf1573e6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_COMPONENT_CONTEXT_MENU_H +#define INCLUDED_COMPONENT_CONTEXT_MENU_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include <QMenu> + +//============================================================================== +// Forwards +//============================================================================== +class CBaseTimelineTreeControl; +class ITimelineItem; +class ITimelineItemBinding; + +class CComponentContextMenu : public QMenu +{ + Q_OBJECT +public: + CComponentContextMenu(CBaseTimelineTreeControl *inTreeControl, + ITimelineItemBinding *inTimelineItemBinding, + QWidget *parent = nullptr); + virtual ~CComponentContextMenu(); + +protected Q_SLOTS: + void RenameObject(); + void DuplicateObject(); + void DeleteObject(); + void InspectComponent(); + void MakeComponent(); + void CopyObjectPath(); + void CopyObject(); + void PasteObject(); + void CutObject(); + void Externalize(); + void Internalize(); + +protected: + void showEvent(QShowEvent *event) override; + + bool CanRenameObject(); + bool CanDuplicateObject(); + bool CanDeleteObject(); + bool CanInspectComponent(); + bool CanMakeComponent(); + bool CanCopyObject(); + bool CanPasteObject(); + bool CanCutObject(); + void Import(); + void RefreshImport(); + bool CanImport(); + bool CanRefreshImport(); + bool CanExportComponent(); + + void Initialize(); + + ITimelineItem *GetTimelineItem() const; + + CBaseTimelineTreeControl *m_TreeControl; + ITimelineItemBinding *m_TimelineItemBinding; + QAction *m_renameAction; + QAction *m_duplicateAction; + QAction *m_deleteAction; + QAction *m_inspectAction; + QAction *m_makeAction; + QAction *m_copyPathAction; + QAction *m_cutAction; + QAction *m_copyAction; + QAction *m_pasteAction; + QAction *m_externalizeAction; + QAction *m_internalizeAction; +}; +#endif // INCLDUED_STATE_CONTEXT_MENU_H diff --git a/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp new file mode 100644 index 00000000..ce2b296c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== +#include "FilterToolbar.h" +#include "ButtonControl.h" +#include "SystemPreferences.h" +#include "Renderer.h" +#include "TimelineTreeLayout.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Constructor + */ +CFilterToolbar::CFilterToolbar(CTimelineTreeLayout *inTreeLayout) + : CFlowLayout(nullptr, false) +{ + m_TreeLayout = inTreeLayout; + + SetFlowDirection(FLOW_HORIZONTAL); + SetAlignment(ALIGN_TOP, ALIGN_LEFT); + SetLeftMargin(1); + + // Create the buttons + m_FltrBehaviorsBtn = new CProceduralButton<CToggleButton>(); + m_FltrPropertiesBtn = new CProceduralButton<CToggleButton>(); + m_FltrMaterialsBtn = new CProceduralButton<CToggleButton>(); + m_FltrShyBtn = new CProceduralButton<CToggleButton>(); + m_FltrVisibleBtn = new CProceduralButton<CToggleButton>(); + + // Load the bitmaps + m_FltrBehaviorsBtn->SetUpImage("obsolete_placeholder.png"); + m_FltrBehaviorsBtn->SetDownImage("obsolete_placeholder.png"); + + m_FltrPropertiesBtn->SetUpImage("obsolete_placeholder.png"); + m_FltrPropertiesBtn->SetDownImage("obsolete_placeholder.png"); + + m_FltrMaterialsBtn->SetUpImage("obsolete_placeholder.png"); + m_FltrMaterialsBtn->SetDownImage("obsolete_placeholder.png"); + + m_FltrShyBtn->SetUpImage("Toggle-Shy.png"); + m_FltrShyBtn->SetDownImage("Toggle-Shy.png"); + + m_FltrVisibleBtn->SetUpImage("Toggle-HideShow.png"); + m_FltrVisibleBtn->SetDownImage("Toggle-HideShow.png"); + + // Turn off the left border of each button since they are all next to each other, otherwise, + // you'll get a double line effect + CProceduralButton<CToggleButton>::SBorderOptions theBorderOptions(false, true, true, true); + m_FltrBehaviorsBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrPropertiesBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrMaterialsBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrShyBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrVisibleBtn->SetBorderVisibilityAll(theBorderOptions); + CProceduralButton<CButtonControl>::SBorderOptions theBorderOptions2(false, true, true, true); + + // Set the max sizes for the buttons + m_FltrBehaviorsBtn->SetAbsoluteSize(m_FltrBehaviorsBtn->GetSize()); + m_FltrPropertiesBtn->SetAbsoluteSize(m_FltrPropertiesBtn->GetSize()); + m_FltrMaterialsBtn->SetAbsoluteSize(m_FltrMaterialsBtn->GetSize()); + m_FltrShyBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize()); + m_FltrVisibleBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize()); + + // Tooltips + m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR2)); + m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES2)); + m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS2)); + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2)); + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2)); + + // Callback for one of the Filter buttons being clicked on + m_FltrBehaviorsBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + m_FltrPropertiesBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + m_FltrMaterialsBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + m_FltrShyBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + m_FltrVisibleBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + + // Add the buttons to this layout + AddChild(m_FltrMaterialsBtn); + AddChild(m_FltrPropertiesBtn); + AddChild(m_FltrBehaviorsBtn); + AddChild(m_FltrShyBtn); + AddChild(m_FltrVisibleBtn); + + m_FltrBehaviorsBtn->SetToggleState(false); + m_FltrPropertiesBtn->SetToggleState(false); + m_FltrMaterialsBtn->SetToggleState(false); + m_FltrShyBtn->SetToggleState(false); + m_FltrVisibleBtn->SetToggleState(false); +} + +//============================================================================= +/** + * Destructor + */ +CFilterToolbar::~CFilterToolbar() +{ + delete m_FltrBehaviorsBtn; + delete m_FltrPropertiesBtn; + delete m_FltrMaterialsBtn; + delete m_FltrShyBtn; + delete m_FltrVisibleBtn; +} + +//============================================================================= +/** + * Overriden to draw some highlighting. + */ +void CFilterToolbar::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + // Draw the highlight at the bottom + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); + + // Draw the line on the left side + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(0, 0); + inRenderer->LineTo(0, theRect.size.y - 1); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Turns filtering on and off for behavior objects in the timeline. + * @param inFilter true to filter behaviors out of the timeline, false to show + * behaviors in the timeline. + */ +void CFilterToolbar::FilterBehaviors(bool inFilter) +{ + if (inFilter) + m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR1)); + else + m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR2)); + + m_TreeLayout->GetFilter()->SetBehaviors(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for properties on objects in the timeline. + * @param inFilter true to filter properties out of the timeline, false to show + * properties in the timeline. + */ +void CFilterToolbar::FilterProperties(bool inFilter) +{ + if (inFilter) + m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES1)); + else + m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES2)); + + m_TreeLayout->GetFilter()->SetProperties(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for material objects. + * @param inFilter true to filter material objects out of the timeline, false to show + * material objects in the timeline. + */ +void CFilterToolbar::FilterMaterials(bool inFilter) +{ + if (inFilter) + m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS1)); + else + m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS2)); + + m_TreeLayout->GetFilter()->SetMaterials(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for shy objects. + * @param inFilter true to filter shy objects out of the timeline, false to show + * shy objects in the timeline. + */ +void CFilterToolbar::FilterShy(bool inFilter) +{ + if (inFilter) + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY1)); + else + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2)); + + m_TreeLayout->GetFilter()->SetShy(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for visible objects. + * @param inFilter true to filter visible objects out of the timeline, false to show + * shy objects in the timeline. + */ +void CFilterToolbar::FilterVisible(bool inFilter) +{ + if (inFilter) + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE1)); + else + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2)); + + m_TreeLayout->GetFilter()->SetVisible(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Handles turning a filter on or off in response to a button being pressed. + * @param inButton button that generated the event + * @param inState new state of the button after being toggled + */ +void CFilterToolbar::OnButtonToggled(CToggleButton *inButton, CButtonControl::EButtonState inState) +{ + bool theFilterNeedsApplied = (inState == CButtonControl::EBUTTONSTATE_UP); + + if (inButton == m_FltrBehaviorsBtn) + FilterBehaviors(theFilterNeedsApplied); + else if (inButton == m_FltrPropertiesBtn) + FilterProperties(theFilterNeedsApplied); + else if (inButton == m_FltrMaterialsBtn) + FilterMaterials(theFilterNeedsApplied); + else if (inButton == m_FltrShyBtn) + FilterShy(theFilterNeedsApplied); + else if (inButton == m_FltrVisibleBtn) + FilterVisible(theFilterNeedsApplied); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h new file mode 100644 index 00000000..8148fff3 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_FILTER_TOOLBAR_H +#define INCLUDED_FILTER_TOOLBAR_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "FlowLayout.h" +#include "ProceduralButton.h" +#include "ToggleButton.h" + +//============================================================================== +// Forwards +//============================================================================== +class CButtonControl; +class CRenderer; +class CTimelineTreeLayout; + +//============================================================================= +/** + * Control at the top of the timeline containing filter buttons. + */ +class CFilterToolbar : public CFlowLayout +{ +public: + CFilterToolbar(CTimelineTreeLayout *inTreeLayout); + virtual ~CFilterToolbar(); + void Draw(CRenderer *inRenderer) override; + + void FilterBehaviors(bool inFilter); + void FilterProperties(bool inFilter); + void FilterMaterials(bool inFilter); + void FilterShy(bool inFilter); + void FilterVisible(bool inFilter); + + void OnButtonToggled(CToggleButton *inButton, CToggleButton::EButtonState inState); + +protected: + CProceduralButton<CToggleButton> *m_FltrBehaviorsBtn; + CProceduralButton<CToggleButton> *m_FltrPropertiesBtn; + CProceduralButton<CToggleButton> *m_FltrMaterialsBtn; + CProceduralButton<CToggleButton> *m_FltrShyBtn; + CProceduralButton<CToggleButton> *m_FltrVisibleBtn; + CTimelineTreeLayout *m_TreeLayout; +}; + +#endif // INCLUDED_FILTER_TOOLBAR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h b/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h new file mode 100644 index 00000000..18aa31ac --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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_IBREADCRUMBPROVIDER_H +#define INCLUDED_IBREADCRUMBPROVIDER_H 1 + +#pragma once + +#include <QColor> +#include <QString> + +#include <boost/signals.hpp> + +class QPixmap; + +struct SBreadCrumb +{ + QColor m_Color; /// Color for text of the bread crumb + QString m_String; /// Text to be displayed for the bread crumb +}; + +//============================================================================= +/** + * A interface class for the breadcrumb control, to walk down the breadcrumb trail, without having + * to know any underlying implementations. + */ +class IBreadCrumbProvider +{ +public: + typedef std::vector<SBreadCrumb> TTrailList; + +public: + virtual ~IBreadCrumbProvider() {} + + virtual TTrailList GetTrail(bool inRefresh = true) = 0; + virtual void OnBreadCrumbClicked(long inTrailIndex) = 0; + + virtual QPixmap GetRootImage() const = 0; + virtual QPixmap GetBreadCrumbImage() const = 0; + virtual QPixmap GetSeparatorImage() const = 0; + virtual QPixmap GetActiveBreadCrumbImage() const = 0; + + boost::signal0<void> SigBreadCrumbUpdate; +}; + +#endif // INCLUDED_IBREADCRUMBPROVIDER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h b/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h new file mode 100644 index 00000000..05af776e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2008 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_ITIMELINE_CONTROL_H +#define INCLUDED_ITIMELINE_CONTROL_H 1 + +#pragma once + +#include "Rct.h" + +class ISnappingListProvider; + +class ITimelineControl +{ +public: + virtual ~ITimelineControl() {} + + virtual void OnLayoutChanged() = 0; + virtual CRct GetBounds() const = 0; + virtual void HideTimelineMoveableTooltip() = 0; + virtual ISnappingListProvider *GetSnappingListProvider() const = 0; +}; + +#endif // INCLUDED_TIMELINE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp new file mode 100644 index 00000000..78a2e4cb --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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 "stdafx.h" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== +#include "KeyframeContextMenu.h" +#include "IDoc.h" +#include "CColor.h" +#include "Preferences.h" +#include "Dialogs.h" +#include "TimebarControl.h" +#include "Bindings/ITimelineTimebar.h" +#include "Bindings/ITimelineKeyframesManager.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/ITimelineItemProperty.h" +#include "IKeyframe.h" + +#include <QColorDialog> + +#define IDC_KEYFRAME_COLOR_BOX 1002 + +//============================================================================= +/** + * Constructor + */ +CBaseKeyframeContextMenu::CBaseKeyframeContextMenu(QWidget *parent) + : QMenu(parent) + , m_HasDynamicSelectedKeyframes(false) + , m_KeyframesManager(nullptr) +{ +} + +//============================================================================= +/** + * Destructor + */ +CBaseKeyframeContextMenu::~CBaseKeyframeContextMenu() +{ +} + +void CBaseKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager) +{ + m_KeyframesManager = inKeyframesManager; + ASSERT(m_KeyframesManager); + + //"Insert Keyframe" + ITimelineItemKeyframesHolder *theKeyframesHolder = GetKeyframesHolder(); + if (theKeyframesHolder) { + m_insertAction = new QAction(tr("Insert Keyframe")); + connect(m_insertAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::InsertKeyframe); + addAction(m_insertAction); + } + + bool theHasKeysSelected = m_KeyframesManager->HasSelectedKeyframes(); + bool theCanCopyKeys = m_KeyframesManager->CanPerformKeyframeCopy(); + bool theCanPasteKeys = m_KeyframesManager->CanPerformKeyframePaste(); + + m_cutAction = new QAction(tr("Cut Selected Keyframes")); + connect(m_cutAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::CutSelectedKeys); + m_cutAction->setEnabled(theCanCopyKeys); + addAction(m_cutAction); + + m_copyAction = new QAction(tr("Copy Selected Keyframes")); + connect(m_copyAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::CopySelectedKeys); + m_copyAction->setEnabled(theCanCopyKeys); + addAction(m_copyAction); + + m_pasteAction = new QAction(tr("Paste Keyframes")); + connect(m_pasteAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::PasteSelectedKeys); + m_pasteAction->setEnabled(theCanPasteKeys); + addAction(m_pasteAction); + + m_deleteSelectedAction = new QAction(tr("Delete Selected Keyframes")); + connect(m_deleteSelectedAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::DeleteSelectedKeys); + m_deleteSelectedAction->setEnabled(theHasKeysSelected); + addAction(m_deleteSelectedAction); + + //"Delete All Channel Keyframes" + if (theKeyframesHolder) { + m_deleteChannelKeysAction = new QAction(tr("Delete All Channel Keyframes")); + connect(m_deleteChannelKeysAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::DeleteChannelKeys); + addAction(m_deleteChannelKeysAction); + } +} + +//============================================================================= +/** + * Called when the cut selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::InsertKeyframe() +{ + GetKeyframesHolder()->InsertKeyframe(); +} + +//============================================================================= +/** + * Called when the cut selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::DeleteChannelKeys() +{ + GetKeyframesHolder()->DeleteAllChannelKeyframes(); +} + +//============================================================================= +/** + * Called when the cut selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::CutSelectedKeys() +{ + m_KeyframesManager->RemoveKeyframes(true); +} + +//============================================================================= +/** + * Called when the copy selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::CopySelectedKeys() +{ + m_KeyframesManager->CopyKeyframes(); +} + +//============================================================================= +/** + * Called when the paste selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::PasteSelectedKeys() +{ + m_KeyframesManager->PasteKeyframes(); +} + +//============================================================================= +/** + * Called when the delete selected keys option is chosen by the user. Makes a call + * to the doc to handle the request + */ +void CBaseKeyframeContextMenu::DeleteSelectedKeys() +{ + m_KeyframesManager->RemoveKeyframes(false); +} + +//============================================================================= +/** + * Toggle if the selected keyframe(s) is dynamic + */ +void CBaseKeyframeContextMenu::MakeDynamic() +{ + m_KeyframesManager->SetKeyframesDynamic(!m_HasDynamicSelectedKeyframes); // toggle +} + +//============================================================================== +// CTimebarKeyframeContextMenu +//============================================================================== +CTimebarKeyframeContextMenu::CTimebarKeyframeContextMenu(ITimebarControl *inTimebarControl, ITimelineKeyframesManager *inKeyframesManager, + bool inShowTimebarPropertiesOptions /*= true */, QWidget *parent) + : CBaseKeyframeContextMenu(parent) + , m_TimebarControl(inTimebarControl) + , m_ShowTimebarPropertiesOptions(inShowTimebarPropertiesOptions) +{ + Initialize(inKeyframesManager); +} + +CTimebarKeyframeContextMenu::~CTimebarKeyframeContextMenu() +{ +} + +void CTimebarKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager) +{ + CBaseKeyframeContextMenu::Initialize(inKeyframesManager); + + // Dynamic keyframes ( the way it was set up before was, this option is still shown, but grayed + // out even if this context menu isn't triggered from right-clicking on a timebar ) + QString theMakeDynamicOption = tr("Make Animations Static"); + + if (m_TimebarControl->GetKeyframesHolder()->GetKeyframeCount() > 0) { + m_HasDynamicSelectedKeyframes = m_KeyframesManager->HasDynamicKeyframes(); + + if (!m_HasDynamicSelectedKeyframes) { + theMakeDynamicOption = tr("Make Animations Dynamic"); + } + + m_makeDynamicAction = new QAction(theMakeDynamicOption); + connect(m_makeDynamicAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::MakeDynamic); + addAction(m_makeDynamicAction); + } + + if (m_ShowTimebarPropertiesOptions) { + // Timebar specific actions + addSeparator(); + m_timeBarColorAction = new QAction(tr("Change Time Bar Color")); + connect(m_timeBarColorAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ChangeTimebarColor); + + m_timeBarTextAction = new QAction(tr("Change Time Bar Text")); + connect(m_timeBarTextAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ChangeTimebarText); + + // Change the text for the timebar option depending on whether they are currently being + // shown or not + QString theTimebarHandleTextID = tr("Show Time Bar Handles"); + if (CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false)) + theTimebarHandleTextID = tr("Hide Time Bar Handles"); + + m_timeBarHandlesAction = new QAction(theTimebarHandleTextID); + connect(m_timeBarHandlesAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ToggleTimebarHandles); + + m_timeBarTimeAction = new QAction(tr("Set Timebar Time")); + connect(m_timeBarTimeAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::SetTimebarTime); + } +} + +void CTimebarKeyframeContextMenu::MakeDynamic() +{ + m_KeyframesManager->SelectAllKeyframes(); + CBaseKeyframeContextMenu::MakeDynamic(); +} + +//============================================================================= +/** + * To show "Insert Keyframe" and "Delete All Channel Keyframes" + */ +ITimelineItemKeyframesHolder *CTimebarKeyframeContextMenu::GetKeyframesHolder() +{ + return m_TimebarControl->GetKeyframesHolder(); +} + +//============================================================================= +/** + * Called when the copy selected keys option is chosen by the user. + */ +void CTimebarKeyframeContextMenu::ChangeTimebarColor() +{ + const auto color = QColorDialog::getColor(m_TimebarControl->GetTimebarColor()); + if (color.isValid()) + m_TimebarControl->SetTimebarColor(color); +} + +//============================================================================= +/** + * Called when the copy selected keys option is chosen by the user. + */ +void CTimebarKeyframeContextMenu::ChangeTimebarText() +{ + m_TimebarControl->OnEditTimeComment(); +} + +//============================================================================= +/** + * Shows or hides timebar handles in the timeline. If timebar handles are + * currently being shown, they are hidden, and the preference is stored. If + * timebar handles are being hidden, they are shown. + */ +void CTimebarKeyframeContextMenu::ToggleTimebarHandles() +{ + // Get the current timebar handle preference + bool theHandlesAreShowing = + CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false); + // Switch the preference. + CPreferences::GetUserPreferences("Timeline") + .SetValue("ShowTimebarHandles", !theHandlesAreShowing); + if (m_TimebarControl) + m_TimebarControl->OnToggleTimebarHandles(); +} + +//============================================================================= +/** + * SetTimebarTime: This is the event handler that will be called when the user + * chooses set timebar time from a pop up menu. This pop up + *menu + * is triggered when the user right click on the selected + *timebar. + * It displays a time edit dialog to allow the user to set the + * start and end time of the timebar time. + * @param NONE + * @return NONE + */ +void CTimebarKeyframeContextMenu::SetTimebarTime() +{ + m_TimebarControl->SetTimebarTime(); +} + +//============================================================================== +// CKeyframeContextMenu +//============================================================================== +CKeyframeContextMenu::CKeyframeContextMenu(ITimelineKeyframesManager *inKeyframesManager, + ITimelineItemProperty *inTimelineItemProperty, QWidget *parent) + : CBaseKeyframeContextMenu(parent) + , m_TimelineItemProperty(inTimelineItemProperty) +{ + Initialize(inKeyframesManager); +} + +CKeyframeContextMenu::~CKeyframeContextMenu() +{ +} + +void CKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager) +{ + CBaseKeyframeContextMenu::Initialize(inKeyframesManager); + + // Dynamic keyframes ( the way it was set up before was, this option is still shown, but grayed + // out even if this context menu isn't triggered from right-clicking on a timebar ) + QString theMakeDynamicOption = tr("Make Animations Static"); + m_HasDynamicSelectedKeyframes = + m_TimelineItemProperty && m_TimelineItemProperty->IsDynamicAnimation(); + + if (!m_HasDynamicSelectedKeyframes) { + theMakeDynamicOption = tr("Make Animations Dynamic"); + } + + m_makeDynamicAction = new QAction(theMakeDynamicOption); + connect(m_makeDynamicAction, &QAction::triggered, this, &CKeyframeContextMenu::MakeDynamic); + addAction(m_makeDynamicAction); + + addSeparator(); + bool theHasKeysSelected = m_KeyframesManager->HasSelectedKeyframes(); + m_setInterpolationAction = new QAction(tr("Set Interpolation")); + connect(m_setInterpolationAction, &QAction::triggered, this, &CKeyframeContextMenu::SetInterpolation); + addAction(m_setInterpolationAction); + + m_setKeyframeTimeAction = new QAction(tr("Set Keyframe Time")); + connect(m_setKeyframeTimeAction, &QAction::triggered, this, &CKeyframeContextMenu::SetKeyframeTime); + m_setKeyframeTimeAction->setEnabled(theHasKeysSelected); + addAction(m_setKeyframeTimeAction); +} + +void CKeyframeContextMenu::MakeDynamic() +{ + if (m_TimelineItemProperty != nullptr && m_TimelineItemProperty->GetKeyframeCount() > 0) { + m_TimelineItemProperty->SelectKeyframes( + true, m_TimelineItemProperty->GetKeyframeByIndex(0)->GetTime()); + } + + CBaseKeyframeContextMenu::MakeDynamic(); +} + +//============================================================================= +/** + * SetTime: Saves the keyframe time + * @param inTime is the keyframe time + */ +void CKeyframeContextMenu::SetTime(long inTime) +{ + m_Time = inTime; +} + +//============================================================================= +/** + * Called when the set interpolation option is taken by the user. Uses the left most + * selected key for the base interpolation in the dialog box. User can then set the interpolation + * and it is propagated to all teh keys + */ +void CKeyframeContextMenu::SetInterpolation() +{ + m_KeyframesManager->SetKeyframeInterpolation(); +} + +//============================================================================= +/** + * SetKeyframeTime: This is the event handler that will be called when the user + * chooses set keyframe time from a pop up menu. This pop up + *menu + * is triggered when the user right click on the selected + *keyframe. + * It displays a time edit dialog to allow the user to set the + * keyframe time. + * @param NONE + * @return NONE + */ +void CKeyframeContextMenu::SetKeyframeTime() +{ + m_KeyframesManager->SetKeyframeTime(m_Time); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h new file mode 100644 index 00000000..b11ccb2f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_KEYFRAME_CONTEXT_MENU +#define INCLUDED_KEYFRAME_CONTEXT_MENU 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include <QMenu> + +class ITimelineKeyframesManager; +class ITimelineItemProperty; +class ITimelineTimebar; +class ITimeChangeCallback; +class ITimelineItemKeyframesHolder; +class ITimebarControl; + +class QAction; + +//============================================================================= +/** + * Abstract class that contain the common items for the keyframes-related context menu. + */ +class CBaseKeyframeContextMenu : public QMenu +{ + Q_OBJECT +public: + CBaseKeyframeContextMenu(QWidget *parent = nullptr); + virtual ~CBaseKeyframeContextMenu(); + +protected: + virtual void Initialize(ITimelineKeyframesManager *inKeyframesManager); + virtual void MakeDynamic(); + virtual ITimelineItemKeyframesHolder *GetKeyframesHolder() { return nullptr; } + +protected Q_SLOTS: + void CutSelectedKeys(); + void CopySelectedKeys(); + void PasteSelectedKeys(); + void DeleteSelectedKeys(); + void InsertKeyframe(); + void DeleteChannelKeys(); + +protected: + bool m_HasDynamicSelectedKeyframes; + ITimelineKeyframesManager *m_KeyframesManager; + QAction *m_insertAction; + QAction *m_cutAction; + QAction *m_copyAction; + QAction *m_pasteAction; + QAction *m_deleteSelectedAction; + QAction *m_deleteChannelKeysAction; +}; + +//============================================================================= +/** + * Context menu right-clicking on a timebar, + */ +class CTimebarKeyframeContextMenu : public CBaseKeyframeContextMenu +{ + Q_OBJECT +public: + CTimebarKeyframeContextMenu(ITimebarControl *inTimebarControl, + ITimelineKeyframesManager *inKeyframesManager, + bool inShowTimebarPropertiesOptions = true, + QWidget *parent = nullptr); + ~CTimebarKeyframeContextMenu(); + +protected: + void Initialize(ITimelineKeyframesManager *inKeyframesManager) override; + ITimelineItemKeyframesHolder *GetKeyframesHolder() override; + void MakeDynamic() override; + + void ChangeTimebarColor(); + void ChangeTimebarText(); + void ToggleTimebarHandles(); + void SetTimebarTime(); + +protected: + ITimebarControl *m_TimebarControl; + bool m_ShowTimebarPropertiesOptions; + + QAction *m_makeDynamicAction; + QAction *m_timeBarColorAction; + QAction *m_timeBarTextAction; + QAction *m_timeBarHandlesAction; + QAction *m_timeBarTimeAction; +}; + +//============================================================================= +/** + * Context menu for right-clicking on selected keyframe(s) + * so even though the assoicated action isn't limited to the keyframe that was right-clicked on, + * this is still a different one from right-clicking on outside the keyframe. + * This is how the old system used to be. + */ +class CKeyframeContextMenu : public CBaseKeyframeContextMenu +{ + Q_OBJECT +public: + CKeyframeContextMenu(ITimelineKeyframesManager *inKeyframesManager, + ITimelineItemProperty *inTimelineItemProperty = nullptr, + QWidget *parent = nullptr); + ~CKeyframeContextMenu(); + + void SetTime(long inTime); + +protected: + void Initialize(ITimelineKeyframesManager *inKeyframesManager) override; + void MakeDynamic() override; + +protected Q_SLOTS: + void SetInterpolation(); + void SetKeyframeTime(); + +protected: + long m_Time; + +private: + ITimelineItemProperty *m_TimelineItemProperty; + QAction *m_makeDynamicAction; + QAction *m_setKeyframeTimeAction; + QAction *m_setInterpolationAction; +}; +#endif // INCLUDED_KEYFRAME_CONTEXT_MENU diff --git a/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp new file mode 100644 index 00000000..676a5d2d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** 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 "stdafx.h" +#include "MultiSelectAspect.h" diff --git a/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h new file mode 100644 index 00000000..0c19b2b2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_MULTISELECT_ASPECT_H +#define INCLUDED_MULTISELECT_ASPECT_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StateRow.h" +#include "TimelineTimelineLayout.h" +#include "Bindings/IKeyframeSelector.h" + +//============================================================================== +/** + * This class handles the multi selection aspect for keyframes in the timeline. + * It toggles each keyframe's select state on or off, depending on whether the + * mouse rectangle is over them and if the modifier key is down. + */ +template <typename TSTLKeyFrameList> +class CMultiSelectAspect +{ + +public: + typedef typename TSTLKeyFrameList::iterator TSTLKeyframesItr; + +protected: + TSTLKeyFrameList &m_STLKeyframes; ///< stores list of keyframes in a vector (STL) + IKeyframeSelector *m_KeyframeSelector; ///< the interface that performs the keyframes selection + +public: + //============================================================================= + /** + * Constructor + * @param inSTLKeyframes stores a list of keyframes in a vector + * @param inDoc stores the studio document + */ + CMultiSelectAspect(TSTLKeyFrameList &inSTLKeyframes, IKeyframeSelector *inKeyframeSelector) + : m_STLKeyframes(inSTLKeyframes) + , m_KeyframeSelector(inKeyframeSelector) + { + } + + //============================================================================= + /** + * Destructor + */ + ~CMultiSelectAspect() {} + + //============================================================================= + /** + * CommitSelections: Overwrites all previous keyframe states with the current keyframe states. + * This will prevent the keyframes in the current selection +*from +* switching states as we select other keyframes. + */ + void CommitSelections() + { + // Iterates each keyframe and set the previous state to the current one. + TSTLKeyframesItr thePos = m_STLKeyframes.begin(); + for (; thePos != m_STLKeyframes.end(); ++thePos) { + (*thePos)->SetPreviousSelectState((*thePos)->IsSelected()); + } + } + + //============================================================================= + /** + * MultiSelect: Handles the selection of keyframes in a given rect. + * @param inRect stores the rectangle that will be used to select the keyframes within it. + * @param inModifierKeyDown indicates if thte modifier key is pressed. + */ + void MultiSelect(CRct inRect, bool inModifierKeyDown) + { + // Iterates through the keyframes and checks if the keys are in the rect and + // perform the necessary selection operations on each keyframe. + TSTLKeyframesItr thePos = m_STLKeyframes.begin(); + for (; thePos != m_STLKeyframes.end(); ++thePos) { + bool isInRect = (*thePos)->IsInRect(inRect); + if ((*thePos)->IsEnabled()) { + if (inModifierKeyDown) { + if (isInRect) { + if (!(*thePos)->GetRectOverHandled()) { + bool theSelectState = (*thePos)->IsSelected(); + + // Update the previous select state + (*thePos)->SetPreviousSelectState(theSelectState); + // Negate the keyframe state when it is in the rectangle + theSelectState = !theSelectState; + (*thePos)->Select(theSelectState); + m_KeyframeSelector->SelectKeyframes(theSelectState, + (*thePos)->GetTime()); + + // Set the RectOverFlag to true, so that we will not repeat the negation + // in indefinitely. + (*thePos)->SetRectOverHandled(true); + } + } else { + // When the rectangle is not over the current keyframe, revert its state to + // the previous one + if ((*thePos)->IsSelected() != (*thePos)->GetPreviousSelectState()) { + (*thePos)->Select((*thePos)->GetPreviousSelectState()); + m_KeyframeSelector->SelectKeyframes((*thePos)->GetPreviousSelectState(), + (*thePos)->GetTime()); + } + (*thePos)->SetRectOverHandled(false); + } + } else { + // When modifier is not pressed we will just select the keyframes if it is over + // in the rectangle and deselect it when it isn't. + if ((*thePos)->IsSelected() != isInRect) { + (*thePos)->SetPreviousSelectState((*thePos)->IsSelected()); + m_KeyframeSelector->SelectKeyframes(isInRect, (*thePos)->GetTime()); + (*thePos)->Select(isInRect); + } + (*thePos)->SetRectOverHandled(false); + } + } + } + } +}; +#endif // INCLUDED_MULTISELECT_ASPECT_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp b/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp new file mode 100644 index 00000000..c010a854 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "Playhead.h" +#include "Renderer.h" +#include "TimelineTimelineLayout.h" +#include "IDoc.h" +#include "HotKeys.h" +#include "ResourceCache.h" +#include "TimeEditDlg.h" +#include "TimeMeasure.h" + +//============================================================================= +/** + * Create a new Playhead. + * The timeline is used for notifying of time changes and for scrolling. + * @param inTimeline the timeline that this is a part of. + */ +CPlayhead::CPlayhead(CTimelineTimelineLayout *inTimeline, IDoc *inDoc) + : m_IsMouseDown(false) + , m_MinimumPosition(0) + , m_MaximumPosition(LONG_MAX) + , m_InitialOffset(0) + , m_Doc(inDoc) +{ + m_Timeline = inTimeline; + + m_PlayheadImage = CResourceCache::GetInstance()->GetBitmap("PlaybackHead.png"); + SetName("Playhead"); + + // Set the line to the middle of this. + m_LinePos = GetSize().x / 2; + SetAlpha(128); +} + +CPlayhead::~CPlayhead() +{ +} + +//============================================================================= +/** + * Call from the OverlayControl to perform the draw. + * Wish this didn't have to be a special function but... + * @param inRenderer the renderer to draw to. + */ +void CPlayhead::Draw(CRenderer *inRenderer) +{ + // If this goes before position then clip it at 0. + if (GetPosition().x < 0) { + CRct theClipRect(GetSize()); + theClipRect.Offset(CPt(-GetPosition().x, 0)); + inRenderer->PushClippingRect(theClipRect); + } + + // Draw the playhead + inRenderer->DrawBitmap(CPt(0, 2), m_PlayheadImage); + + // Draw the line + inRenderer->PushPen(CColor(255, 0, 0)); + inRenderer->MoveTo(m_LinePos, 20); + inRenderer->LineTo(m_LinePos, GetSize().y - 1); + inRenderer->PopPen(); + + // If we added an extra clipping rect then remove it. + if (GetPosition().x < 0) { + inRenderer->PopClippingRect(); + } +} + +//============================================================================= +/** + * Handles mouse down messages. + * @param inPoint where the mouse was clicked. + * @param inFlags the state of the mouse. + */ +bool CPlayhead::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // If no one else processed it then process the command. + if (!COverlayControl::OnMouseDown(inPoint, inFlags)) { + m_Snapper.Clear(); + m_Snapper.SetSource(this); + m_Timeline->PopulateSnappingList(&m_Snapper); + + // m_Snapper.SetTimeOffset( m_Timeline->GetViewTimeOffset( ) ); + m_Snapper.SetSnappingKeyframes(true); + m_Snapper.BeginDrag(inPoint.x, GetSize().x / 2); + + m_InitialOffset = inPoint.x; + m_IsMouseDown = true; + + m_Timeline->RecalcTime((inFlags & CHotKeys::MODIFIER_CONTROL) == 0, 0); + } + + return true; +} + +//============================================================================= +/** + * Handles mouse double click messages. Pops up a time edit dialog box for + * modifying playhead time. + * @param inPoint the location of the mouse in local coordinates. + * @param inFlags the state of the mouse. + */ +bool CPlayhead::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.ShowDialog(GetCurrentTime(), 0, m_Doc, PLAYHEAD); + return true; +} + +//============================================================================= +/** + * Handles mouse move messages. + * @param inPoint the location of the mouse in local coordinates. + * @param inFlags the state of the mouse. + */ +void CPlayhead::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + COverlayControl::OnMouseMove(inPoint, inFlags); + + // If we are down then move the playhead + if (m_IsMouseDown) { + long theTime = m_Snapper.ProcessDrag(GetCurrentTime(), inPoint.x, inFlags); + bool theUpdateClientTimeFlag = (inFlags & CHotKeys::MODIFIER_CONTROL) == 0; + + UpdateTime(theTime, theUpdateClientTimeFlag); + } +} + +//============================================================================= +/** + * Updates the time of the active context + * @param inTime the new time + * @param inUpdateClient true if scene is to be redrawn + */ +void CPlayhead::UpdateTime(long inTime, bool /*inUpdateClient*/) +{ + // true to "check bounds" to ensure playhead is within valid range. + m_Doc->NotifyTimeChanged(inTime); +} + +//============================================================================= +/** + * Notification that the mouse was let go. + * @param inPoint the location of the mouse in local coordinates. + * @param inFlags the state of the mouse. + */ +void CPlayhead::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + COverlayControl::OnMouseUp(inPoint, inFlags); + + m_IsMouseDown = false; +} + +//============================================================================= +/** + * Set the size of this control. + * @param inSize the size to be set. + */ +void CPlayhead::SetSize(CPt inSize) +{ + COverlayControl::SetSize(inSize); + // Update the line position. + m_LinePos = inSize.x / 2; +} + +//============================================================================= +/** + * Set the minimum and maximum allowed positions of the line. + * @param inMinimumPosition the minimum allowed position. + * @param inMaximumPosition the maximum allowed position. + */ +void CPlayhead::SetMinMaxPosition(long inMinimumPosition, long inMaximumPosition) +{ + m_MinimumPosition = inMinimumPosition; + m_MaximumPosition = inMaximumPosition; +} + +long CPlayhead::GetCurrentTime() +{ + return m_Doc->GetCurrentViewTime(); +} + +//============================================================================= +/** + * Check to see if inPoint is over this control or not. + * This overrides COverlayControl::HitTest so that the playhead line can be + * exempt from mouse hits. + * @param inPoint the location of the mouse in local coordinates. + */ +bool CPlayhead::HitTest(const CPt &inPoint) const +{ + if (inPoint.y < m_PlayheadImage.height()) { + return COverlayControl::HitTest(inPoint); + } + return false; +} + +void CPlayhead::StepRightSmall() +{ + long theInterval = m_Timeline->GetTimeMeasure()->GetSmallHashInterval(); + + long theCurrentTime = GetCurrentTime(); + long theTime = theCurrentTime / theInterval * theInterval + theInterval; + UpdateTime(theTime, true); +} + +void CPlayhead::StepRightLarge() +{ + long theInterval = m_Timeline->GetTimeMeasure()->GetLargeHashInterval(); + + long theCurrentTime = GetCurrentTime(); + long theTime = theCurrentTime / theInterval * theInterval + theInterval; + UpdateTime(theTime, true); +} + +void CPlayhead::StepLeftSmall() +{ + long theInterval = m_Timeline->GetTimeMeasure()->GetSmallHashInterval(); + + long theCurrentTime = GetCurrentTime(); + long theTime = theCurrentTime / theInterval * theInterval - theInterval; + + UpdateTime(theTime, true); +} + +void CPlayhead::StepLeftLarge() +{ + long theInterval = m_Timeline->GetTimeMeasure()->GetLargeHashInterval(); + + long theCurrentTime = GetCurrentTime(); + long theTime = theCurrentTime / theInterval * theInterval - theInterval; + + UpdateTime(theTime, true); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Playhead.h b/src/Authoring/Studio/Palettes/Timeline/Playhead.h new file mode 100644 index 00000000..21d21041 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Playhead.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PLAYHEAD_H +#define INCLUDED_PLAYHEAD_H 1 + +#pragma once + +#include "OverlayControl.h" +#include "Snapper.h" + +#include <QPixmap> + +class CTimelineTimelineLayout; +class IDoc; + +class CPlayhead : public COverlayControl +{ +public: + CPlayhead(CTimelineTimelineLayout *inTimeline, IDoc *inDoc); + virtual ~CPlayhead(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void SetSize(CPt inSize) override; + void Draw(CRenderer *inRenderer) override; + void SetMinMaxPosition(long inMinimumPosition, long inMaximumPosition); + long GetCurrentTime(); + bool HitTest(const CPt &inPoint) const override; + void StepRightSmall(); + void StepRightLarge(); + void StepLeftSmall(); + void StepLeftLarge(); + + long GetCenterOffset() const { return m_LinePos; } + bool IsMouseDown() const { return m_IsMouseDown; } + + void UpdateTime(long inTime, bool inUpdateClient); + +protected: + QPixmap m_PlayheadImage; + bool m_IsMouseDown; + long m_InitialOffset; + + long m_MinimumPosition; + long m_MaximumPosition; + long m_LinePos; + + CTimelineTimelineLayout *m_Timeline; + + CSnapper m_Snapper; + IDoc *m_Doc; +}; +#endif // INCLUDED_PLAYHEAD_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp new file mode 100644 index 00000000..3cffd417 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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 "stdafx.h" + +#include "PropertyColorControl.h" +#include "Renderer.h" +#include "PropertyRow.h" +#include "StudioPreferences.h" +#include "HotKeys.h" + +CPropertyColorControl::CPropertyColorControl(CPropertyRow *inPropertyRow) +{ + m_ParentRow = inPropertyRow; +} + +CPropertyColorControl::~CPropertyColorControl() +{ +} + +//============================================================================== +/** + * Draw + * + * draws this object + * + * @param inRenderer a renderer object + */ +void CPropertyColorControl::Draw(CRenderer *inRenderer) +{ + // Fill the control with the solid color + CRct theRect(GetSize()); + CColor theBgColor(CStudioPreferences::GetPropertyBackgroundColor()); + inRenderer->FillSolidRect(theRect, theBgColor); + + // Define the colors for the side and bottom outline + CColor theBorderColor(CStudioPreferences::GetPropertyFloorColor()); + + // Right + inRenderer->PushPen(theBorderColor); + inRenderer->MoveTo(CPt(theRect.size.x - 1, 0)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + + // Left + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theRect.size.y - 1)); + + // Bottom + inRenderer->MoveTo(CPt(1, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x - 2, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================== +/** + * Handles the OnMouseDownEvent + */ +bool CPropertyColorControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + m_ParentRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT); + return true; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h new file mode 100644 index 00000000..cc3263b8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_PROPERTYCOLOR_CONTROL_H +#define INCLUDED_PROPERTYCOLOR_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" + +class CRenderer; +class CPropertyRow; + +class CPropertyColorControl : public CControl +{ +public: + CPropertyColorControl(CPropertyRow *inPropertyRow); + virtual ~CPropertyColorControl(); + + void SetColor(::CColor inColor); + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void Draw(CRenderer *inRenderer) override; + +protected: + CPropertyRow *m_ParentRow; +}; +#endif // INCLUDED_ diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp new file mode 100644 index 00000000..fd7585ac --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "PropertyGraphKeyframe.h" +#include "Renderer.h" +#include "Bindings/ITimelineItemProperty.h" +#include "StudioUtils.h" +#include "CColor.h" + +CPropertyGraphKeyframe::CPropertyGraphKeyframe(ITimelineItemProperty *inProperty, + long inChannelIndex, long inKeyframeTime, + double inTimeRatio, long inMinY, long inMaxY, + float inMinVal, float inMaxVal) + : m_Property(inProperty) + , m_ChannelIndex(inChannelIndex) + , m_KeyframeTime(inKeyframeTime) + , m_TimeRatio(inTimeRatio) + , m_MinVal(inMinVal) + , m_MaxVal(inMaxVal) + , m_MinY(inMinY) + , m_MaxY(inMaxY) + , m_IsMouseDown(false) +{ + SetSize(CPt(4, 4)); + PositionKeyframe(); +} + +CPropertyGraphKeyframe::~CPropertyGraphKeyframe() +{ +} + +long CPropertyGraphKeyframe::GetTime() +{ + return m_KeyframeTime; +} + +long CPropertyGraphKeyframe::GetChannelIndex() const +{ + return m_ChannelIndex; +} + +void CPropertyGraphKeyframe::PositionKeyframe() +{ + long theXPos = ::TimeToPos(m_KeyframeTime, m_TimeRatio); + float theValue = GetKeyframeValue(); + long theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY) + + m_MinY - GetSize().y / 2 + .5); + + if (theYPos < m_MinY) + theYPos = m_MinY; + else if (theYPos > m_MaxY) + theYPos = m_MaxY; + + SetPosition(CPt(theXPos, theYPos)); +} + +void CPropertyGraphKeyframe::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + PositionKeyframe(); +} + +float CPropertyGraphKeyframe::GetKeyframeValue() +{ + return m_Property->GetChannelValueAtTime(m_ChannelIndex, m_KeyframeTime); +} + +void CPropertyGraphKeyframe::SetKeyframeValue(float inValue) +{ + m_Property->SetChannelValueAtTime(m_ChannelIndex, m_KeyframeTime, inValue); +} + +void CPropertyGraphKeyframe::Draw(CRenderer *inRenderer) +{ + CPt mySize = GetSize(); + inRenderer->MoveTo(0, 0); + inRenderer->LineTo(mySize.x, 0); + inRenderer->LineTo(mySize.x, mySize.y); + inRenderer->LineTo(0, mySize.y); + inRenderer->LineTo(0, 0); + + if (m_IsMouseDown) { + inRenderer->FillSolidRect(CRct(GetSize()), CColor::black); + } +} + +bool CPropertyGraphKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_IsMouseDown = true; + m_MouseDownLoc = inPoint; + } + return true; +} + +void CPropertyGraphKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + m_IsMouseDown = false; + m_Property->CommitChangedKeyframes(); + GetParent()->Invalidate(); +} + +void CPropertyGraphKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + if (m_IsMouseDown) { + long theDiff = inPoint.y - m_MouseDownLoc.y; + long theYPos = GetPosition().y + theDiff; + if (theYPos < m_MinY) + theYPos = m_MinY; + if (theYPos > m_MaxY) + theYPos = m_MaxY; + SetPosition(GetPosition().x, theYPos); + + float theValue = (m_MaxVal - m_MinVal) + * (((m_MaxY + m_MinY) - theYPos - GetSize().y / 2) - m_MinY) / (m_MaxY - m_MinY) + + m_MinVal; + SetKeyframeValue(theValue); + + GetParent()->Invalidate(); + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h new file mode 100644 index 00000000..daffc8ab --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PROPERTY_GRAPH_KEYFRAME_H +#define INCLUDED_PROPERTY_GRAPH_KEYFRAME_H 1 + +#pragma once + +#include "Control.h" + +class ITimelineItemProperty; + +class CPropertyGraphKeyframe : public CControl +{ +public: + CPropertyGraphKeyframe(ITimelineItemProperty *inProperty, long inChannelIndex, + long inKeyframeTime, double inTimeRatio, long inHeight, long inOffset, + float inMinVal, float inMaxVal); + virtual ~CPropertyGraphKeyframe(); + + void Draw(CRenderer *inRenderer) override; + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + long GetTime(); + long GetChannelIndex() const; + void SetTimeRatio(double inTimeRatio); + void PositionKeyframe(); + +protected: + float GetKeyframeValue(); + void SetKeyframeValue(float inValue); + + ITimelineItemProperty *m_Property; + long m_ChannelIndex; // index that identifies the channel for a animated property + long m_KeyframeTime; + double m_TimeRatio; + float m_MinVal; + float m_MaxVal; + long m_MinY; + long m_MaxY; + CPt m_MouseDownLoc; + bool m_IsMouseDown; +}; +#endif // INCLUDED_PROPERTY_GRAPH_KEYFRAME_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp new file mode 100644 index 00000000..986d8326 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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 "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "PropertyRow.h" +#include "TimelineControl.h" +#include "PropertyColorControl.h" +#include "PropertyToggleControl.h" +#include "PropertyTreeControl.h" +#include "PropertyTimebarRow.h" +#include "BlankControl.h" +#include "StudioPreferences.h" +#include "StateRow.h" +#include "Bindings/ITimelineItemProperty.h" + +//============================================================================= +/** + * Create a property row for inProperty. + * @param inProperty the property that this is displaying. + */ +CPropertyRow::CPropertyRow(ITimelineItemProperty *inProperty) + : m_Highlighted(false) + , m_DetailedView(false) + , m_TimeRatio(0.0f) + , m_Property(inProperty) +{ + m_IsViewable = true; + + m_TreeControl = new CPropertyTreeControl(this); + m_ToggleControl = new CPropertyToggleControl(this); + m_TimebarRow = new CPropertyTimebarRow(this); + + m_PropertyColorControl = new CPropertyColorControl(this); + long theTimebarHeight = CStudioPreferences::GetRowSize(); + + // do not set absolute size because it messes up the timeline + m_TreeControl->SetSize(CPt(500, theTimebarHeight)); + m_PropertyColorControl->SetAbsoluteSize(CPt(theTimebarHeight, theTimebarHeight)); + m_ToggleControl->SetAbsoluteSize(CPt(57, theTimebarHeight)); + m_TimebarRow->SetSize(CPt(0, theTimebarHeight)); + + // sk: setting controls names' seem to be only useful for debugging. + // Q3DStudio::CString thePropName( inProperty->GetName( ) ); + // m_TreeControl->SetName( thePropName ); + // m_TimebarRow->SetName( thePropName + "TimebarRow" ); +} + +CPropertyRow::~CPropertyRow() +{ + delete m_TreeControl; + delete m_ToggleControl; + delete m_PropertyColorControl; + delete m_TimebarRow; +} + +//============================================================================= +/** + * Get the left hand color control for this row. + * @return the color control for this row. + */ +CControl *CPropertyRow::GetColorControl() +{ + return m_PropertyColorControl; +} + +//============================================================================= +/** + * Get the tree control object for this row. + * @return the tree control object for this row. + */ +CControl *CPropertyRow::GetTreeControl() +{ + return m_TreeControl; +} + +//============================================================================= +/** + * Get the toggle control object for this row. + * @return the toggle control object for this row. + */ +CControl *CPropertyRow::GetToggleControl() +{ + return m_ToggleControl; +} + +//============================================================================= +/** + * Get the timebar control for this row. + * @return the timebar control for this row. + */ +CControl *CPropertyRow::GetTimebarControl() +{ + return m_TimebarRow; +} + +//============================================================================= +/** + * Set the amount that this row is indented. + * This handles the tree indenting. + * @param inIndent the amount of indent for this row. + */ +void CPropertyRow::SetIndent(long inIndent) +{ + m_TreeControl->SetIndent(inIndent); +} + +//============================================================================= +/** + * Notification from one of the child controls that the mouse just entered. + * This is used to handle the highlighting of the entire row. + */ +void CPropertyRow::OnMouseOver() +{ + // Only change if change is needed + if (!m_Highlighted) { + m_TreeControl->SetHighlighted(true); + m_ToggleControl->SetHighlighted(true); + m_TimebarRow->SetHighlighted(true); + + m_Highlighted = true; + } +} + +//============================================================================= +/** + * Notification from one of the child controls that the mouse just left. + * This is used to handle the highlighting of the entire row. + */ +void CPropertyRow::OnMouseOut() +{ + // Only change is change is needed. + if (m_Highlighted) { + m_TreeControl->SetHighlighted(false); + m_ToggleControl->SetHighlighted(false); + m_TimebarRow->SetHighlighted(false); + + m_Highlighted = false; + } +} + +//============================================================================= +/** + * Double click handler for the property row + */ +void CPropertyRow::OnMouseDoubleClick() +{ + SetDetailedView(!m_DetailedView); +} + +//============================================================================= +/** + * Expands the row out so a more detailed view of the animation tracks can be seen + * + * @param inIsInDetailedView true if we are switching to a detailed view + */ +void CPropertyRow::SetDetailedView(bool inIsDetailedView) +{ + m_DetailedView = inIsDetailedView; + + if (m_DetailedView) { + long theHeight = 100; + m_PropertyColorControl->SetAbsoluteSize( + CPt(m_PropertyColorControl->GetSize().x, theHeight)); + m_TreeControl->SetSize(CPt(m_TreeControl->GetSize().x, theHeight)); + m_ToggleControl->SetAbsoluteSize(CPt(m_ToggleControl->GetSize().x, theHeight)); + m_TimebarRow->SetAbsoluteSize(CPt(m_TimebarRow->GetSize().x, theHeight)); + + m_TimebarRow->SetDetailedView(true); + } else { + long theDefaultHeight = CStudioPreferences::GetRowSize(); + + m_PropertyColorControl->SetAbsoluteSize( + CPt(m_PropertyColorControl->GetSize().x, theDefaultHeight)); + m_TreeControl->SetSize(CPt(m_TreeControl->GetSize().x, theDefaultHeight)); + m_ToggleControl->SetAbsoluteSize(CPt(m_ToggleControl->GetSize().x, theDefaultHeight)); + m_TimebarRow->SetAbsoluteSize(CPt(m_TimebarRow->GetSize().x, theDefaultHeight)); + + m_TimebarRow->SetDetailedView(false); + } + + GetTopControl()->OnLayoutChanged(); +} + +//============================================================================= +/** + * Filter this property. + * This controls whether or not this row should be displayed. The filter will + * be stored and used for future operations that may change whether or not + * this should be visible. + * @param inFilter the filter to filter on. + * @param inFilterChildren true if the call is recursive. + */ +void CPropertyRow::Filter(const CFilter &inFilter, bool inFilterChildren /*= true*/) +{ + Q_UNUSED(inFilterChildren); + + m_Filter = inFilter; + + bool theVisibleFlag = inFilter.Filter(m_Property); + m_TreeControl->SetVisible(theVisibleFlag); + m_TimebarRow->SetVisible(theVisibleFlag); + m_ToggleControl->SetVisible(theVisibleFlag); + m_PropertyColorControl->SetVisible(theVisibleFlag); + m_IsViewable = theVisibleFlag; +} + +//============================================================================= +/** + * @return true if this property is animated and is not currently being filtered out + */ +bool CPropertyRow::IsViewable() const +{ + return m_Filter.GetProperties(); +} + +//============================================================================= +/** + * Call from one of the child controls to select this object. + * Currently this just causes the Asset to be selected. + */ +void CPropertyRow::Select(bool inIsShiftKeyPressed /*= false */) +{ + m_Property->SetSelected(); + + if (inIsShiftKeyPressed) + m_TimebarRow->SelectAllKeys(); + else + m_Property->ClearKeySelection(); +} + +ISnappingListProvider *CPropertyRow::GetSnappingListProvider() const +{ + return &m_TimebarRow->GetSnappingListProvider(); +} + +void CPropertyRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + m_TimebarRow->SetSnappingListProvider(inProvider); +} + +//============================================================================= +/** + * Retrieves the background color for the row based upon the type of asset + * passed in. Overridden so that properties can have a different background + * color than their parent asset does. + * @return background color to use for this row + */ +::CColor CPropertyRow::GetTimebarBackgroundColor() +{ + return CStudioPreferences::GetPropertyBackgroundColor(); +} + +//============================================================================= +/** + * Retrieves the background color for the row when the mouse is over the row + * based upon the type of asset passed in. Overridden so that properties can + * have a different highlight background color than their parent asset does. + * @return background color to use for this row when the mouse is over it + */ +::CColor CPropertyRow::GetTimebarHighlightBackgroundColor() +{ + return CStudioPreferences::GetPropertyMouseOverColor(); +} + +//============================================================================= +/** + * Set the amount of time that is represented by a pixel. + * This modifies the length of this control. + * @param inTimePerPixel the time per pixel. + */ +void CPropertyRow::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + m_TimebarRow->SetTimeRatio(inTimeRatio); +} + +//============================================================================= +/** + * Selects all keyframes of this property that are inside inRect + * + * @param inRect theRect to check + */ +void CPropertyRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown) +{ + CRct theOffsetRect = inRect; + CRct myRect(CPt(0, 0), m_TimebarRow->GetSize()); + theOffsetRect.Offset(-m_TimebarRow->GetPosition()); + m_TimebarRow->SelectKeysInRect(theOffsetRect, inModifierKeyDown); +} + +//============================================================================= +/** + * CommitSelections: commits all the property keyframe selections by setting their + * previous selection state to the current selection state. + * This will prevent the keyframes in the current selection + *from + * switching states as we select other keyframes. + * + * @param NONE + * @return NONE + */ +void CPropertyRow::CommitSelections() +{ + m_TimebarRow->CommitSelections(); +} + +//============================================================================= +/** + * Selects all keyframes + */ +void CPropertyRow::SelectAllKeys() +{ + m_TimebarRow->SelectAllKeys(); +} + +//============================================================================= +/** + * Deletes keyframes on this property row + */ +void CPropertyRow::DeleteAllKeys() +{ + m_Property->DeleteAllKeys(); + m_TimebarRow->Invalidate(); +} + +//============================================================================= +/** + * Sets all the child control enable states + * @param inEnabled the state to set the controls to + */ +void CPropertyRow::SetEnabled(bool inEnabled) +{ + m_TreeControl->SetEnabled(inEnabled); + m_ToggleControl->SetEnabled(inEnabled); + m_PropertyColorControl->SetEnabled(inEnabled); + m_TimebarRow->SetEnabled(inEnabled); +} + +//============================================================================= +/** + * Callback from the ITimelineProperty. + */ +void CPropertyRow::Refresh() +{ + if (m_TimebarRow->IsVisible()) + m_TimebarRow->SetDirty(true); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h new file mode 100644 index 00000000..49ca60a7 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_PROPERTY_ROW_H +#define INCLUDED_PROPERTY_ROW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "TimelineRow.h" +#include "StateRow.h" +#include "Rct.h" +#include <vector> + +//============================================================================== +// Forwards +//============================================================================== +class CPropertyColorControl; +class CBlankControl; +class CPropertyTreeControl; +class CPropertyToggleControl; +class CPropertyTimebarRow; +class ITimelineItemProperty; + +class CPropertyRow : public CTimelineRow +{ +public: + CPropertyRow(ITimelineItemProperty *inProperty); + virtual ~CPropertyRow(); + CControl *GetColorControl() override; + CControl *GetTreeControl() override; + CControl *GetToggleControl() override; + CControl *GetTimebarControl() override; + + void SetTimeRatio(double inTimePerPixel) override; + void SetIndent(long inIndent) override; + void Filter(const CFilter &inFilter, bool inFilterChildren = true) override; + void OnMouseOver(); + void OnMouseOut(); + void OnMouseDoubleClick(); + void Select(bool inIsShiftKeyPressed = false); + void SetDetailedView(bool inIsInDetailedView); + void CommitSelections(); + void SelectKeysInRect(CRct inRect, bool inModifierKeyDown); + void SelectAllKeys(); + void DeleteAllKeys(); + bool IsViewable() const override; + void SetEnabled(bool inEnabled); + + ISnappingListProvider *GetSnappingListProvider() const override; + void SetSnappingListProvider(ISnappingListProvider *inProvider) override; + using CTimelineRow::GetTimebarBackgroundColor; + virtual ::CColor GetTimebarBackgroundColor(); + using CTimelineRow::GetTimebarHighlightBackgroundColor; + virtual ::CColor GetTimebarHighlightBackgroundColor(); + + void Refresh(); + ITimelineItemProperty *GetProperty() const { return m_Property; } + + CPropertyTimebarRow *GetTimebar() { return m_TimebarRow; } + +protected: + CPropertyTreeControl *m_TreeControl; + CPropertyToggleControl *m_ToggleControl; + CPropertyColorControl *m_PropertyColorControl; + CPropertyTimebarRow *m_TimebarRow; + bool m_Highlighted; + bool m_DetailedView; + double m_TimeRatio; + CFilter m_Filter; + ITimelineItemProperty *m_Property; +}; +#endif // INCLUDED_PROPERTY_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp new file mode 100644 index 00000000..ecd3b5df --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "PropertyTimebarGraph.h" +#include "IKeyframe.h" +#include "Renderer.h" +#include "PropertyGraphKeyframe.h" +#include "Bindings/ITimelineItemProperty.h" +#include "StudioUtils.h" + +//============================================================================= +/** + * Create a graph for the specified property. + * @param inProperty the property this is graphing. + */ +CPropertyTimebarGraph::CPropertyTimebarGraph(ITimelineItemProperty *inProperty) + : m_Property(inProperty) + , m_TimeRatio(0.0f) + , m_MaxVal(0.0f) + , m_MinVal(0.0f) + , m_MinY(0) + , m_MaxY(0) +{ +} + +CPropertyTimebarGraph::~CPropertyTimebarGraph() +{ + TKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) + delete (*thePos); +} + +//============================================================================= +/** + * Toggle whether this is visible or not. + * Overrides CControl::SetVisible. If this is not visible then it removes + * a bunch of the refresh logic to speed stuff up. + * @param inIsVisible true if this control is to be visible. + */ +void CPropertyTimebarGraph::SetVisible(bool inIsVisible) +{ + CControl::SetVisible(inIsVisible); + + // If this is visible then add the appropriate keyframes and listeners. + if (inIsVisible) { + m_MaxVal = m_Property->GetMaximumValue(); + m_MinVal = m_Property->GetMinimumValue(); + + m_MinY = 10; + m_MaxY = GetSize().y - m_MinY; + + RefreshKeyframes(); + } else + RemoveKeyframes(); +} + +//============================================================================= +/** + * Set the time ratio for this display. + * The time ratio controls how much time is displayed in how much space. + * @param inTimeRatio the time ratio. + */ +void CPropertyTimebarGraph::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; +} + +//============================================================================= +/** + * Draw this to the specified renderer. + * This will perform the graphing of all the channels on the property. + * @param inRenderer the renderer to draw to. + */ +void CPropertyTimebarGraph::Draw(CRenderer *inRenderer) +{ + CRct theRect(CPt(0, 0), GetSize()); + inRenderer->PushClippingRect(theRect); + + // the available line colors, tried to use Rainbow.bvs code to do it dynamically but didn't + // quite work. + ::CColor theColors[6] = { ::CColor(255, 0, 0), ::CColor(0, 255, 0), ::CColor(0, 0, 255), + ::CColor(255, 255, 0), ::CColor(255, 0, 255), ::CColor(0, 255, 255) }; + + long theChannelCount = m_Property->GetChannelCount(); + // Don't want to overflow the color array + if (theChannelCount <= 6) { + // For each channel graph it. + for (long theIndex = 0; theIndex < theChannelCount; ++theIndex) + DrawDetailedChannel(inRenderer, theIndex, theColors[theIndex]); + } + + inRenderer->PopClippingRect(); +} + +void CPropertyTimebarGraph::DrawDetailedChannel(CRenderer *inRenderer, long inChannelIndex, + ::CColor inColor) +{ + inRenderer->PushPen(inColor, 2); + + CRct theClipRect = inRenderer->GetClippingRect(); + float theValue = m_Property->GetChannelValueAtTime(inChannelIndex, 0); + long theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY) + + m_MinY + .5); + + inRenderer->MoveTo(CPt(0, theYPos)); + + long theInterval = 5; + long theSize = theClipRect.position.x + theClipRect.size.x + theInterval; + + for (long thePixel = theClipRect.position.x; thePixel < theSize; thePixel += theInterval) { + long theTime = ::PosToTime(thePixel, m_TimeRatio); //(long)( thePixel / m_TimeRatio + .5 ); + theValue = m_Property->GetChannelValueAtTime(inChannelIndex, theTime); + theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY) + + m_MinY + .5); + + inRenderer->LineTo(CPt(thePixel, theYPos)); + } + + inRenderer->PopPen(); +} + +void CPropertyTimebarGraph::AddKeyframes() +{ + long theChannelCount = m_Property->GetChannelCount(); + long theKeyframeCount = + m_Property->GetKeyframeCount(); // the way it works now (and hence the assumption is), the + // number of keyframes for all the channels is the same. + for (long theIndex = 0; theIndex < theChannelCount; ++theIndex) { + for (long theKeyIndex = 0; theKeyIndex < theKeyframeCount; ++theKeyIndex) { + CPropertyGraphKeyframe *theGraphKeyframe = new CPropertyGraphKeyframe( + m_Property, theIndex, m_Property->GetKeyframeByIndex(theKeyIndex)->GetTime(), + m_TimeRatio, m_MinY, m_MaxY, m_MinVal, m_MaxVal); + AddChild(theGraphKeyframe); + m_Keyframes.push_back(theGraphKeyframe); + } + } +} + +void CPropertyTimebarGraph::Invalidate(bool inIsInvalidated) +{ + CControl::Invalidate(inIsInvalidated); + + if (inIsInvalidated && GetParent() != nullptr) { + GetParent()->Invalidate(inIsInvalidated); + } +} + +void CPropertyTimebarGraph::RemoveKeyframes() +{ + TKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + CPropertyGraphKeyframe *theKeyframe = (*thePos); + RemoveChild(theKeyframe); + delete theKeyframe; + } + m_Keyframes.clear(); +} + +void CPropertyTimebarGraph::RefreshKeyframes() +{ + TKeyframeList::iterator thePos = m_Keyframes.begin(); + while (thePos != m_Keyframes.end()) { + CPropertyGraphKeyframe *theKeyframe = (*thePos); + if (m_Property->GetKeyframeByTime(theKeyframe->GetTime())) { + theKeyframe->PositionKeyframe(); + ++thePos; + } else { + RemoveChild(theKeyframe); + delete theKeyframe; + thePos = m_Keyframes.erase(thePos); + } + } + long theChannelCount = m_Property->GetChannelCount(); + long theKeyframeCount = + m_Property->GetKeyframeCount(); // the way it works now (and hence the assumption is), the + // number of keyframes for all the channels is the same. + for (long theIndex = 0; theIndex < theChannelCount; ++theIndex) { + for (long theKeyIndex = 0; theKeyIndex < theKeyframeCount; ++theKeyIndex) { + IKeyframe *theKeyframe = m_Property->GetKeyframeByIndex(theKeyIndex); + CPropertyGraphKeyframe *theExistingKeyframe = + GetKeyframe(theKeyframe->GetTime(), theIndex); + if (!theExistingKeyframe) { + CPropertyGraphKeyframe *theGraphKeyframe = + new CPropertyGraphKeyframe(m_Property, theIndex, theKeyframe->GetTime(), + m_TimeRatio, m_MinY, m_MaxY, m_MinVal, m_MaxVal); + AddChild(theGraphKeyframe); + + m_Keyframes.push_back(theGraphKeyframe); + } + } + } + + Invalidate(); +} + +CPropertyGraphKeyframe *CPropertyTimebarGraph::GetKeyframe(long inTime, long inChannelIndex) +{ + TKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + CPropertyGraphKeyframe *theKeyframe = (*thePos); + if (theKeyframe->GetChannelIndex() == inChannelIndex && theKeyframe->GetTime() == inTime) { + return theKeyframe; + } + } + return nullptr; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h new file mode 100644 index 00000000..76379bcd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PROPERTY_TIMEBAR_GRAPH_H +#define INCLUDED_PROPERTY_TIMEBAR_GRAPH_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" + +class CPropertyGraphKeyframe; +class ITimelineItemProperty; + +class CPropertyTimebarGraph : public CControl +{ + typedef std::vector<CPropertyGraphKeyframe *> TKeyframeList; + +public: + CPropertyTimebarGraph(ITimelineItemProperty *inProperty); + virtual ~CPropertyTimebarGraph(); + void SetVisible(bool inIsVisible) override; + void Draw(CRenderer *inRenderer) override; + void SetTimeRatio(double inTimeRatio); + void Invalidate(bool inIsInvalidated = true) override; + void RefreshKeyframes(); + +protected: + void DrawDetailedChannel(CRenderer *inRenderer, long inChannelIndex, ::CColor inColor); + void AddKeyframes(); + void RemoveKeyframes(); + + CPropertyGraphKeyframe *GetKeyframe(long inTime, long inChannelIndex); + +protected: + ITimelineItemProperty *m_Property; + double m_TimeRatio; + TKeyframeList m_Keyframes; + float m_MaxVal; + float m_MinVal; + long m_MinY; + long m_MaxY; +}; +#endif // INCLUDED_PROPERTY_TIMEBAR_GRAPH_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp new file mode 100644 index 00000000..428777a8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp @@ -0,0 +1,508 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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 "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "PropertyTimebarRow.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" +#include "PropertyRow.h" +#include "MasterP.h" +#include "KeyframeContextMenu.h" +#include "PropertyTimelineKeyframe.h" +#include "HotKeys.h" +#include "MultiSelectAspect.h" +#include "Bindings/ITimelineItemProperty.h" +#include "IKeyframe.h" +#include "CoreUtils.h" + +//============================================================================= +/** + */ +CPropertyTimebarRow::CPropertyTimebarRow(CPropertyRow *inPropertyRow) + : m_PropertyRow(inPropertyRow) + , m_DetailedView(inPropertyRow->GetProperty()) + , m_DirtyFlag(false) + , m_Refreshing(false) + , m_SnappingListProvider(nullptr) +{ + m_DetailedView.SetVisible(false); + + m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor(); + + AddChild(&m_DetailedView); + m_Refreshing = false; + RefreshKeyframes(); +} + +CPropertyTimebarRow::~CPropertyTimebarRow() +{ + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + CPropertyTimelineKeyframe *theDeletedKey = (*thePos); + RemoveChild(theDeletedKey); + delete theDeletedKey; + } +} + +//============================================================================= +/** + * Draws the this row background. + * @param inRenderer the renderer to draw to. + */ +void CPropertyTimebarRow::Draw(CRenderer *inRenderer) +{ + if (m_DirtyFlag) { + RefreshKeyframes(); + m_DirtyFlag = false; + } + + CRct theRect(GetSize()); + UICDM::TDataTypePair theType = m_PropertyRow->GetProperty()->GetType(); + if (theType.first == UICDM::DataModelDataType::Float3 + && theType.second == UICDM::AdditionalMetaDataType::Color) { + inRenderer->FillSolidRect(CRct(0, 0, theRect.size.x, theRect.size.y - 1), + m_BackgroundColor); + DrawColor(inRenderer); + } else { + inRenderer->FillSolidRect(CRct(0, 0, theRect.size.x, theRect.size.y - 1), + m_BackgroundColor); + } + + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Draw a colorized background for this property row. + * If this is a color object then this will draw the background of this control + * as the color that the property is. This will draw a gradient between the + * colors over time to show somewhat what the colors look like. + * @param inRenderer the renderer to draw to. + */ +void CPropertyTimebarRow::DrawColor(CRenderer *inRenderer) +{ + UICPROFILE(DrawColor); + + ITimelineItemProperty *theProperty = m_PropertyRow->GetProperty(); + ASSERT(theProperty->GetChannelCount() == 3); // sanity check + + CColor thePreviousColor; + thePreviousColor.SetRed(::dtol(theProperty->GetChannelValueAtTime(0, 0))); + thePreviousColor.SetGreen(::dtol(theProperty->GetChannelValueAtTime(1, 0))); + thePreviousColor.SetBlue(::dtol(theProperty->GetChannelValueAtTime(2, 0))); + + long thePreviousTime = 0; + long theLastPosition = 0; + CColor theCurrentColor; + + long theKeyframeCount = theProperty->GetKeyframeCount(); + + // Go through all the keyframes and draw a gradient from the previous key to the current key. + // Only use the first channel for the keyframes, assume they are all at the same time. + for (long theIndex = 0; theIndex < theKeyframeCount; ++theIndex) { + long theCurrentTime = theProperty->GetKeyframeByIndex(theIndex)->GetTime(); + // Get the color at the specified time. + theCurrentColor.SetRed(::dtol(theProperty->GetChannelValueAtTime(0, theCurrentTime))); + theCurrentColor.SetGreen(::dtol(theProperty->GetChannelValueAtTime(1, theCurrentTime))); + theCurrentColor.SetBlue(::dtol(theProperty->GetChannelValueAtTime(2, theCurrentTime))); + + long thePreviousPixel = ::TimeToPos(thePreviousTime, m_TimeRatio); + long theCurrentPixel = ::TimeToPos(theCurrentTime, m_TimeRatio); + + // Draw a gradient from the previous keyframe position to the current one. + inRenderer->DrawGradient( + CRct(thePreviousPixel, 0, theCurrentPixel - thePreviousPixel, GetSize().y), + thePreviousColor, theCurrentColor); + thePreviousTime = theCurrentTime; + thePreviousColor = theCurrentColor; + theLastPosition = theCurrentPixel; + } + // Fill in from the last keyframe to the end of the bar. + inRenderer->DrawGradient(CRct(theLastPosition, 0, GetSize().x - theLastPosition, GetSize().y), + thePreviousColor, thePreviousColor); +} + +//============================================================================= +/** + * OnMouseOver event, handles the highlighting of the row. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +void CPropertyTimebarRow::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + m_PropertyRow->OnMouseOver(); +} + +//============================================================================= +/** + * OnMouseOut event, handles the de-highlighting of this row. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +void CPropertyTimebarRow::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + m_PropertyRow->OnMouseOut(); +} + +//============================================================================= +/** + * OnMouseRDown event, pops up a context menu + * @param inPoint the location of the mouse over this control. + * @param inFlags the modifier key states (shift, alt, and ctrl). + */ +bool CPropertyTimebarRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Only do it if a child has not handled the mouse down. + bool theRetVal = CControl::OnMouseRDown(inPoint, inFlags); + if (!theRetVal) { + m_PropertyRow->Select(); + CKeyframeContextMenu theMenu(m_PropertyRow->GetProperty()->GetKeyframesManager(), + m_PropertyRow->GetProperty()); + DoPopup(&theMenu, inPoint); + theRetVal = true; + } + + return theRetVal; +} + +//============================================================================= +/** + * OnMouseOut event, handles the de-highlighting of this row. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +void CPropertyTimebarRow::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + UICPROFILE(OnMouseMove); + CControl::OnMouseMove(inPoint, inFlags); +} +//============================================================================= +/** + * Set this control to being highlighted or not. + * @param inIsHighlighted true if this is to be highlighted. + */ +void CPropertyTimebarRow::SetHighlighted(bool inIsHighlighted) +{ + if (inIsHighlighted) + m_BackgroundColor = m_PropertyRow->GetTimebarHighlightBackgroundColor(); + else + m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor(); + + Invalidate(); +} + +//============================================================================= +/** + * Get the state row that this belongs to. + */ +CPropertyRow *CPropertyTimebarRow::GetPropertyRow() +{ + return m_PropertyRow; +} + +//============================================================================= +/** + * Sets teh time ratio + * + * @param inTimeRatio the new ratio + */ +void CPropertyTimebarRow::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + (*thePos)->SetTimeRatio(inTimeRatio); + } + m_DetailedView.SetTimeRatio(inTimeRatio); + + Invalidate(); +} + +void CPropertyTimebarRow::SetDetailedView(bool inDetailedView) +{ + m_DetailedView.SetVisible(inDetailedView); +} + +//============================================================================= +/** + * Sets teh size of this control. + * @param inSize size to set the row + */ +void CPropertyTimebarRow::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + + m_DetailedView.SetSize(inSize); +} + +//============================================================================= +/** + * called when keyframes need to be updated, this funciton has two loops: + * the first loops through and deletes any keys no longer in the sskf list. the + * second adds any keys in the sskf list that are not already in the list + * + */ +void CPropertyTimebarRow::RefreshKeyframes() +{ + m_Refreshing = true; + UICPROFILE(RefreshKeyframes); + + // First Loop clears any keys that do not correlate to a supersetkey + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + while (thePos != m_Keyframes.end()) { + CPropertyTimelineKeyframe *theTimelineKey = (*thePos); + CPt theSize = theTimelineKey->GetSize(); + IKeyframe *theTempKey = nullptr; + theTempKey = m_PropertyRow->GetProperty()->GetKeyframeByTime(theTimelineKey->GetTime()); + + // If we find a key at this time, then the timeline key doesn't need to be deleted + if (!theTempKey) { + RemoveChild(theTimelineKey); + delete theTimelineKey; + thePos = m_Keyframes.erase(thePos); + } else if (theTempKey->IsDynamic() != theTimelineKey->IsDynamic()) { + theTimelineKey->SetDynamic(theTempKey->IsDynamic()); + } else { + // Set the position + theTimelineKey->SetPosition( + ::TimeToPos(theTempKey->GetTime(), m_TimeRatio) - (theSize.x / 2), 0); + ++thePos; + } + } + + // Second Loop adds teh remaining keys + long theKeyframeCount = m_PropertyRow->GetProperty()->GetKeyframeCount(); + for (long theKey = 0; theKey < theKeyframeCount; ++theKey) { + bool theFoundFlag = false; + IKeyframe *theTempKey = m_PropertyRow->GetProperty()->GetKeyframeByIndex(theKey); + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + + long theKeyframeTime = theTempKey->GetTime(); + // each key needs to be compared to all the keys in the sskf list to see if it has to be + // added. + for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) { + CPropertyTimelineKeyframe *theCurrentKey = (*thePos); + if (theCurrentKey->GetTime() == theKeyframeTime) { + theFoundFlag = true; + } + } + if (!theFoundFlag) { + // If we don't have a timeline key, then we have to make a new one + CPropertyTimelineKeyframe *thePropertyTimelineKey = + new CPropertyTimelineKeyframe(this, m_TimeRatio); + thePropertyTimelineKey->SetTime(theKeyframeTime); + thePropertyTimelineKey->Select(theTempKey->IsSelected()); + thePropertyTimelineKey->SetDynamic(theTempKey->IsDynamic()); + thePropertyTimelineKey->SetSize(CPt(15, 16)); + CPt theSize = thePropertyTimelineKey->GetSize(); + long theXPosition = ::TimeToPos(theKeyframeTime, m_TimeRatio) - (theSize.x / 2); + thePropertyTimelineKey->SetPosition(theXPosition, 0); + AddChild(thePropertyTimelineKey); + m_Keyframes.push_back(thePropertyTimelineKey); + } + } + + if (m_DetailedView.IsVisible()) + m_DetailedView.RefreshKeyframes(); + + m_Refreshing = false; +} + +void CPropertyTimebarRow::Invalidate(bool inInvalidate) +{ + if (!m_Refreshing) { + CControl::Invalidate(inInvalidate); + } +} + +//============================================================================= +/** + * Handler for when a child key is selected + * + * @param inTime time of the key + */ +void CPropertyTimebarRow::OnKeySelected(long inTime, bool inSelected) +{ + if (inTime >= 0) { + m_PropertyRow->GetProperty()->SelectKeyframes(inSelected, inTime); + Invalidate(); + } +} + +//============================================================================= +/** + * Deselects all keyframes + */ +void CPropertyTimebarRow::DeselectAllKeyframes() +{ + m_PropertyRow->GetProperty()->SelectKeyframes(false); +} + +//============================================================================= +/** + * called when a child changes and the keyframes need to be refreshed + * + * @param inDirtyFlag true if this object is now dirty + * + */ +void CPropertyTimebarRow::SetDirty(bool inDirtyFlag) +{ + if (m_DirtyFlag == inDirtyFlag) + return; + + m_DirtyFlag = inDirtyFlag; + Invalidate(); +} + +//============================================================================= +/** + * SelectKeysInRect: selects any keyframes inside the rect + * + * @param inRect is used to select keyframes + * @param inModifierKeyDown indicates if the control modifier is down + */ +void CPropertyTimebarRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown) +{ + CMultiSelectAspect<TTimelineKeyframeList> theMultiSelectAspect(m_Keyframes, + m_PropertyRow->GetProperty()); + theMultiSelectAspect.MultiSelect(inRect, inModifierKeyDown); +} + +//============================================================================= +/** + * CommitSelections: commits all the master keyframe selections by setting their + * previous selection state to the current selection state. + * This will prevent the keyframes in the current selection + *from + * switching states as we select other keyframes. + * + * @param NONE + * @return NONE + */ + +void CPropertyTimebarRow::CommitSelections() +{ + CMultiSelectAspect<TTimelineKeyframeList> theMultiSelectAspect(m_Keyframes, + m_PropertyRow->GetProperty()); + theMultiSelectAspect.CommitSelections(); +} + +//============================================================================= +/** + * true if there are selected keys on this object + */ +bool CPropertyTimebarRow::HasSelectedKeys() +{ + bool theRetVal = false; + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end() && !theRetVal; ++thePos) { + if ((*thePos)->IsSelected()) { + theRetVal = true; + } + } + return theRetVal; +} + +//============================================================================= +/** + * selects all keys for this timebar row + */ +void CPropertyTimebarRow::SelectAllKeys() +{ + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + m_PropertyRow->GetProperty()->SelectKeyframes(true, (*thePos)->GetTime()); + (*thePos)->Select(true); + Invalidate(); + } +} + +//============================================================================= +/** + * Set this control as being visible or not. + * If the control is not visible then it will not be drawn and will not + * get mouse clicks. + * @param inIsVisible true if this control is to be visible. + */ +void CPropertyTimebarRow::SetVisible(bool inIsVisible) +{ + if (inIsVisible != IsVisible()) { + CControl::SetVisible(inIsVisible); + SetDirty(true); + } +} + +bool CPropertyTimebarRow::HasKeyframe(long inTime) const +{ + return m_PropertyRow->GetProperty()->GetKeyframeByTime(inTime) != nullptr; +} + +//============================================================================= +/** + * @param inTime -1 for all keyframes + */ +void CPropertyTimebarRow::SelectKeysByTime(long inTime, bool inSelected) +{ + TTimelineKeyframeList::iterator thePos = m_Keyframes.begin(); + bool theFoundFlag = false; + for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) { + CPropertyTimelineKeyframe *theKey = (*thePos); + if (inTime == -1 || theKey->GetTime() == inTime) { + theKey->Select(inSelected); + theFoundFlag = (inTime != -1); + } + } + Invalidate(); +} + +void CPropertyTimebarRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + m_SnappingListProvider = inProvider; +} + +ISnappingListProvider &CPropertyTimebarRow::GetSnappingListProvider() const +{ + // sk - If you hit this, it means the setup is incorrect. e.g. the parent row (which is most + // probably a staterow) isn't pass 'down' this info. + ASSERT(m_SnappingListProvider); + return *m_SnappingListProvider; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h new file mode 100644 index 00000000..a07118f9 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_PROPERTY_TIMEBAR_ROW_H +#define INCLUDED_PROPERTY_TIMEBAR_ROW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "PropertyTimebarGraph.h" +#include "StateRow.h" + +//============================================================================== +// forwards +//============================================================================== +class CPropertyRow; +class CPropertyTimelineKeyframe; +class ISnappingListProvider; + +class CPropertyTimebarRow : public CControl +{ + typedef std::vector<CPropertyTimelineKeyframe *> TTimelineKeyframeList; + +public: + CPropertyTimebarRow(CPropertyRow *inPropertyRow); + virtual ~CPropertyTimebarRow(); + + void Draw(CRenderer *inRenderer) override; + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void SetHighlighted(bool inIsHighlighted); + void RefreshKeyframes(); + + void SetSize(CPt inSize) override; + + CPropertyRow *GetPropertyRow(); + + void SetTimeRatio(double inTimeRatio); + + void SetDetailedView(bool inDetailedView); + void OnKeySelected(long inTime, bool inSelected); + void DeselectAllKeyframes(); + void SetDirty(bool inDirtyFlag); + void CommitSelections(); + void SelectKeysInRect(CRct inRect, bool inModifierKeyDown); + void SelectAllKeys(); + bool HasSelectedKeys(); + void Invalidate(bool inInvalidate = true) override; + void SetVisible(bool inIsVisible) override; + + bool HasKeyframe(long inTime) const; + void SelectKeysByTime(long inTime, bool inSelected); + + void SetSnappingListProvider(ISnappingListProvider *inProvider); + ISnappingListProvider &GetSnappingListProvider() const; + +protected: + void DrawColor(CRenderer *inRenderer); + +protected: + TTimelineKeyframeList m_Keyframes; ///< Properties Keyframe List (STL) + CPropertyRow *m_PropertyRow; + CPropertyTimebarGraph m_DetailedView; + ::CColor m_BackgroundColor; + double m_TimeRatio; + + bool m_DirtyFlag; + bool m_Refreshing; + ISnappingListProvider *m_SnappingListProvider; +}; +#endif // INCLUDED_STATE_TIMEBAR_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp new file mode 100644 index 00000000..c3a83e09 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" +#include "Dialogs.h" + +//============================================================================== +// Includes +//============================================================================== +#include "PropertyTimelineKeyframe.h" +#include "PropertyTimebarRow.h" +#include "Renderer.h" +#include "PropertyRow.h" +#include "KeyframeContextMenu.h" +#include "HotKeys.h" +#include "ResourceCache.h" +#include "TimelineControl.h" +#include "Bindings/ITimelineItemProperty.h" +#include "StudioUtils.h" +#include "TimeEditDlg.h" + +CPropertyTimelineKeyframe::CPropertyTimelineKeyframe(CPropertyTimebarRow *inParentRow, + double inTimeRatio) + : m_Selected(false) + , m_IsMouseDown(false) + , m_IsDragging(false) +{ + m_ParentRow = inParentRow; + m_TimeRatio = inTimeRatio; + CResourceCache *theCache = CResourceCache::GetInstance(); + m_Icon = theCache->GetBitmap("Keyframe-Property-Normal.png"); + m_DisabledIcon = theCache->GetBitmap("Keyframe-Property-Disabled.png"); + m_SelectedIcon = theCache->GetBitmap("Keyframe-Property-Selected.png"); + m_DynamicIcon = theCache->GetBitmap("Keyframe-PropertyDynamic-Normal.png"); + m_DynamicSelectedIcon = theCache->GetBitmap("Keyframe-PropertyDynamic-Selected.png"); + m_RectOverHandled = false; + m_PreviousSelectState = false; +} + +CPropertyTimelineKeyframe::~CPropertyTimelineKeyframe() +{ +} + +//============================================================================= +/** + * SetRectOverHandled: Sets if mouse rectangle has been handled + * param@ inState indicates if the rectangle over has been handled. + * return@ NONE + */ +void CPropertyTimelineKeyframe::SetRectOverHandled(bool inState) +{ + m_RectOverHandled = inState; +} + +//============================================================================= +/** + * GetRectOverHandled: GetRectOverHandled + * param@ NONE + * return@ m_RectOverHandled, which indicates if the rectangle over has been handled + */ +bool CPropertyTimelineKeyframe::GetRectOverHandled() +{ + return m_RectOverHandled; +} + +//============================================================================= +/** + * SetPreviousSelectState: Sets if the current keyframe was previously selected + * param@ inState is used to set m_PreviousSelectState. + * return@ NONE + */ +void CPropertyTimelineKeyframe::SetPreviousSelectState(bool inState) +{ + m_PreviousSelectState = inState; +} + +//============================================================================= +/** + * GetPreviousSelectState: Returns the keyframe's previous select state + * param@ NONE + * return@ m_PreviousSelectState that stores the select state for the keyframe + */ +bool CPropertyTimelineKeyframe::GetPreviousSelectState() +{ + return m_PreviousSelectState; +} + +//============================================================================= +/** + * Gets teh correct image and draws + */ +void CPropertyTimelineKeyframe::Draw(CRenderer *inRenderer) +{ + if (m_Selected) { + inRenderer->DrawBitmap(CPt(0, 0), GetImage()); + } else { + inRenderer->DrawBitmap(CPt(2, 0), GetImage()); + } +} + +//============================================================================= +/** + * Gets the current bitmap depending on the state of the button, postion of the + * mouse, etc. Returns the image for the up state by default. + */ +QPixmap CPropertyTimelineKeyframe::GetImage() +{ + if (!IsEnabled()) + return m_DisabledIcon; + else if (m_IsDynamic) { + if (m_Selected) + return m_DynamicSelectedIcon; + else + return m_DynamicIcon; + } else if (m_Selected) + return m_SelectedIcon; + else + return m_Icon; +} + +//============================================================================= +/** + * Handler for left-click events. Allows keyframe dragging. Children are + * allowed to handle this event before the parent does. + * @param inPoint the point where the mouse is + * @param inFlags the state of modifier keys when the event occurred + * @return true + */ +bool CPropertyTimelineKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Store the mouse down location in screen coordinates so that we can check the dragging buffer + // in OnMouseMove + m_MouseDownLoc = inPoint; + + if (!CControl::OnMouseDown(inPoint, inFlags)) { + // If the control key is down then we change state, otherwise + if (!((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL)) { + if (!m_Selected) + GetProperty()->ClearKeySelection(); + + m_Selected = true; + } else { + m_Selected = !m_Selected; + } + m_ParentRow->OnKeySelected(m_Time, m_Selected); + // TODO : sk - Remove this when we are clear on the fact that UpdateClientScene & + // FireChangeEvent do nothing useful here. + // This call makes no sense. However, if you run into some wierd + //behavior related to mouse down events, this might be a clue. + // I am leaving this just in case this speeds up debugging for anyone + //else looking at this. + // CAssetTimelineKeyframe::OnMouseDown does similar things. + // m_Doc->UpdateClientScene( true ); + // m_ParentRow->GetPropertyRow()->GetProperty()->FireChangeEvent( false ); + m_IsMouseDown = true; + + m_Snapper.Clear(); + m_Snapper.SetSource(this); + m_Snapper.SetSnappingSelectedKeyframes(false); + m_ParentRow->GetSnappingListProvider().PopulateSnappingList(&m_Snapper); + m_Snapper.BeginDrag(inPoint.x); + + // display the time range tooltip + RefreshToolTip(inPoint); + } + + return true; +} + +//============================================================================= +/** + * Handler for right-click events. Pops up a context menu. Children are + * allowed to handle this event before the parent does. + * @param inPoint the point where the mouse is + * @param inFlags the state of modifier keys when the event occurred + * @return true + */ +bool CPropertyTimelineKeyframe::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseRDown(inPoint, inFlags)) { + if (!m_Selected) { + GetProperty()->ClearKeySelection(); + m_Selected = true; + m_ParentRow->OnKeySelected(m_Time, m_Selected); + } + + CKeyframeContextMenu theMenu(GetProperty()->GetKeyframesManager(), GetProperty()); + theMenu.SetTime(GetTime()); + DoPopup(&theMenu, inPoint); + } + + return true; +} + +//============================================================================= +/** + * called when this key is selected + * @param inState the state this key is selected to + */ +void CPropertyTimelineKeyframe::Select(bool inState) +{ + if (m_Selected != inState) { + m_Selected = inState; + Invalidate(); + } +} + +//============================================================================= +/** + * handler for the mouse up event + * @param inFlags the state of things when the mouse button was released + * @param inPoint the point where the mouse is + */ +void CPropertyTimelineKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + + // If this key is selected, then we need to make sure that it moved all the way to the + // mouse up location + if (m_Selected && m_IsMouseDown && m_IsDragging) { + long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags); + long theDiffTime = theNewTime - m_Time; + + // theDiffTime can get updated if its invalid. + theDiffTime = GetProperty()->OffsetSelectedKeyframes(theDiffTime); + // Set this key's time so it won't be recalced in Refresh keyframes in the row + SetTime(m_Time + theDiffTime); + } + + m_IsMouseDown = false; + m_IsDragging = false; + + GetProperty()->CommitChangedKeyframes(); + HideMoveableWindow(); + Invalidate(); +} + +//============================================================================= +/** + * handler for the onMouse Move event. Offsets selected keys. + * + * @param inFlags the state of things when the mouse was moved + * @param inPoint the point where the mouse is + */ +void CPropertyTimelineKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + // If the mouse is down and this is slected, then offst the keys + if (m_IsMouseDown && m_Selected) { + // If we are not yet dragging the keyframe + if (!m_IsDragging) { + long theDiff = ::abs(inPoint.x) - m_MouseDownLoc.x; + // Figure out if the mouse has moved far enough to start the drag, and readjust the drag + // postion on the snapper + m_IsDragging = (::abs(theDiff) > DRAGBUFFER); + if (m_IsDragging && (::abs(theDiff) - DRAGBUFFER) > 2) { + m_Snapper.BeginDrag(m_MouseDownLoc.x); + } else + m_Snapper.BeginDrag(inPoint.x); + } + + // If we are already dragging the keyframe, procceed as normal + if (m_IsDragging) { + long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags); + long theDiffTime = theNewTime - m_Time; + + if (theDiffTime != 0) { + // theDiffTime can get updated if its invalid. + theDiffTime = GetProperty()->OffsetSelectedKeyframes(theDiffTime); + // Set this key's time so it won't be recalced in Refresh keyframes in the row + SetTime(m_Time + theDiffTime); + Invalidate(); + } + } + + // display the time range tooltip + RefreshToolTip(inPoint); + } +} + +//============================================================================= +/** + * Sets teh time ratio + * + * @param inTimeRatio the new ratio + */ +void CPropertyTimelineKeyframe::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + CPt theSize = GetSize(); + SetPosition(::TimeToPos(GetTime(), m_TimeRatio) - (theSize.x / 2), 0); +} + +//============================================================================= +/** + * Pass the double click notification on to the row and have it process it. + * The row will do object-specific actions on doubleclicks. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + * @return true stating that the event was processed. + */ +bool CPropertyTimelineKeyframe::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + GetProperty()->OnEditKeyframeTime(m_Time, ASSETKEYFRAME); + return true; +} + +//============================================================================= +/** + * @return true if selected + */ +bool CPropertyTimelineKeyframe::IsSelected() +{ + return m_Selected; +} + +//============================================================================= +/** +* Updates the ToolTip and moves it to the correct place on screen. +* @param inPoint the point that the tooltip is supposed to be placed. +*/ +void CPropertyTimelineKeyframe::RefreshToolTip(CPt inPoint) +{ + CRct theTimelineBounds(m_ParentRow->GetPropertyRow()->GetTopControl()->GetBounds()); + + // format label + Q3DStudio::CString theCommentText = " " + ::FormatTimeString(GetTime()); + + inPoint.y = GetPosition().y - GetSize().y; + inPoint.x = GetSize().x / 2; + ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds); +} + +//============================================================================= +/** +* Helper function to retrieve the ITimelineItemProperty +*/ +ITimelineItemProperty *CPropertyTimelineKeyframe::GetProperty() const +{ + return m_ParentRow->GetPropertyRow()->GetProperty(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h new file mode 100644 index 00000000..40c7f05b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_PROPERTY_TIMELINE_KEYFRAME +#define INCLUDED_PROPERTY_TIMELINE_KEYFRAME 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "TimelineKeyframe.h" +#include "Snapper.h" + +#include <QPixmap> + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CPropertyTimebarRow; +class ITimelineItemProperty; + +class CPropertyTimelineKeyframe : public CControl, public CTimelineKeyframe +{ + +public: + CPropertyTimelineKeyframe(CPropertyTimebarRow *inParentRow, double inTimeRatio); + ~CPropertyTimelineKeyframe(); + void Draw(CRenderer *inRenderer) override; + QPixmap GetImage(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void Select(bool inState); + void SetTimeRatio(double inTimeRatio); + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool IsSelected(); + void SetRectOverHandled(bool inState); + bool GetRectOverHandled(); + void SetPreviousSelectState(bool inState); + bool GetPreviousSelectState(); + +protected: + void RefreshToolTip(CPt inPoint); + ITimelineItemProperty *GetProperty() const; + +protected: + bool m_Selected; + bool m_RectOverHandled; ///< Indicates if the mouse rect over has been handled. + bool m_PreviousSelectState; ///< Stores the previous select state for the keyframe. + CPropertyTimebarRow *m_ParentRow; + bool m_IsMouseDown; + CPt m_MouseDownLoc; ///< Location of the mouse after an OnMouseDownEvent, in client coordinates + bool m_IsDragging; ///< Indicates whether or not the keyframe is currently being dragged, + ///determined by the pixel buffer + double m_TimeRatio; + CSnapper m_Snapper; + QPixmap m_Icon; + QPixmap m_DisabledIcon; + QPixmap m_SelectedIcon; + QPixmap m_DynamicIcon; + QPixmap m_DynamicSelectedIcon; +}; + +#endif // INCLUDED_PROPERTY_TIMELINE_KEYFRAME diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp new file mode 100644 index 00000000..994ba2fe --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "PropertyToggleControl.h" +#include "TimelineRow.h" +#include "PropertyRow.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "HotKeys.h" + +CPropertyToggleControl::CPropertyToggleControl(CPropertyRow *inPropertyRow) + : m_PropertyRow(inPropertyRow) +{ + m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor(); +} + +CPropertyToggleControl::~CPropertyToggleControl() +{ +} + +void CPropertyToggleControl::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + inRenderer->FillSolidRect(QRect(0, 0, theRect.size.x + 1, theRect.size.y), m_BackgroundColor); + + // Draw the line at the bottom of this control + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + + // Draw the line on the left side of this control + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theRect.size.y - 1)); + + // Draw the highlight + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(1, 0)); + inRenderer->LineTo(CPt(1, theRect.size.y - 1)); + inRenderer->PopPen(); + + // Draw the line on the right side of this control + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(CPt(theRect.size.x - 1, 0)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +void CPropertyToggleControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + m_PropertyRow->OnMouseOver(); +} + +void CPropertyToggleControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + m_PropertyRow->OnMouseOut(); +} + +void CPropertyToggleControl::SetHighlighted(bool inIsHighlighted) +{ + if (inIsHighlighted) + m_BackgroundColor = m_PropertyRow->GetTimebarHighlightBackgroundColor(); + else + m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor(); + + Invalidate(); +} + +//============================================================================== +/** + * Handles the OnMouseDownEvent + */ +bool CPropertyToggleControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) + m_PropertyRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT); + + return true; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h new file mode 100644 index 00000000..81435cc6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PROPERTY_TOGGLE_CONTROL_H +#define INCLUDED_PROPERTY_TOGGLE_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" + +class CPropertyRow; + +class CPropertyToggleControl : public CControl +{ +public: + CPropertyToggleControl(CPropertyRow *inPropertyRow); + virtual ~CPropertyToggleControl(); + + void Draw(CRenderer *inRenderer) override; + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void SetHighlighted(bool inIsHightlighted); + +protected: + CPropertyRow *m_PropertyRow; + ::CColor m_BackgroundColor; +}; +#endif // INCLUDED_PROPERTY_TOGGLE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp new file mode 100644 index 00000000..813f04f3 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "PropertyTreeControl.h" +#include "PropertyRow.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" +#include "HotKeys.h" +#include "ResourceCache.h" +#include "BaseTimelineTreeControl.h" +#include "Bindings/ITimelineItemProperty.h" +#include "CoreUtils.h" + +CPropertyTreeControl::CPropertyTreeControl(CPropertyRow *inPropRow) + : m_Icon(CResourceCache::GetInstance()->GetBitmap("Objects-Property-Normal.png"), + CResourceCache::GetInstance()->GetBitmap("Objects-Property-Disabled.png")) +{ + m_PropRow = inPropRow; + + CBaseStateRow *theParentRow = m_PropRow->GetParentRow(); + if (theParentRow) // property row typically should never exists on its own, but to be safe. + m_BackgroundColor = m_PropRow->GetTimebarBackgroundColor(); + else + m_BackgroundColor = CStudioPreferences::GetPropertyBackgroundColor(); + + AddChild(&m_Icon); + + m_Text.SetData(inPropRow->GetProperty()->GetName()); + m_Text.SetAlignment(CTextEdit::LEFT); + m_Text.SetReadOnly(true); + + AddChild(&m_Text); + + SetIndent(0); +} + +CPropertyTreeControl::~CPropertyTreeControl() +{ +} + +void CPropertyTreeControl::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + + // Draw the line at the bottom of this control + CColor theShadowColor = CStudioPreferences::GetPropertyFloorColor(); + inRenderer->PushPen(theShadowColor); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); + + ::CColor theTextColor = CStudioPreferences::GetNormalColor(); + if (m_PropRow->GetProperty()->IsMaster()) + theTextColor = CStudioPreferences::GetMasterColor(); + m_Text.SetTextColor(theTextColor); +} + +void CPropertyTreeControl::SetIndent(long inIndent) +{ + m_Indent = inIndent; + + // place it it's size x2 to the right since we don't have a toggle. + m_Icon.SetPosition(CPt(m_Indent + m_Icon.GetSize().x, 0)); + + m_Text.SetPosition(CPt(m_Icon.GetPosition().x + m_Icon.GetSize().x + 5, 0)); + m_Text.SetSize(CPt(200, m_Icon.GetSize().y - 1)); +} + +long CPropertyTreeControl::GetIndent() +{ + return m_Indent; +} + +void CPropertyTreeControl::SetHighlighted(bool inIsHighlighted) +{ + CBaseStateRow *theParentRow = m_PropRow->GetParentRow(); + if (theParentRow) // property row typically should never exists on its own, but to be safe. + m_BackgroundColor = (inIsHighlighted) ? m_PropRow->GetTimebarHighlightBackgroundColor() + : m_PropRow->GetTimebarBackgroundColor(); + else + m_BackgroundColor = (inIsHighlighted) ? CStudioPreferences::GetPropertyMouseOverColor() + : CStudioPreferences::GetPropertyBackgroundColor(); + + Invalidate(); +} + +//============================================================================== +/** + * HACK: Trying to scroll the timeline during a drag and drop operation. + * + * The Property Tree Control will never have a drop candidate, so this function + * returns nullptr. However, we still need to scroll the timeline in case we are + * at the top or bottom of the window. This is hackish for two reasons. 1) It + * points out that CPropertyTreeControl and CStateTreeControl should have a + * common base class that handles similar code. 2) The TreeControls should not + * have to scroll the timeline automatically. It should be handled through a + * timer on the scroller when the mouse is being dragged and hovering near the + * border of the scroller. But all of that will be saved for another day. + * @param inMousePoint location of the mouse + * @param inFlags not used (modifier key flags) + * @return nullptr (no drop candidate is ever found) + */ +CDropTarget *CPropertyTreeControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inFlags); + + CPt theSize(GetSize()); + + // If the mouse is towards the top of this row, make sure that this row and the + // one above it are visible (scroll upwards) + if (inMousePoint.y <= ::dtol(theSize.y / 2.0f)) + EnsureVisible(CRct(CPt(0, -theSize.y), theSize)); + // Otherwise, the mouse is towards the bottom of this row, so make sure this row + // and the one below it are visible (scroll downwards) + else + EnsureVisible(CRct(CPt(theSize.x, theSize.y * 2))); + + return nullptr; +} + +void CPropertyTreeControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + m_PropRow->OnMouseOver(); +} + +void CPropertyTreeControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + m_PropRow->OnMouseOut(); +} + +//============================================================================== +/** + * Handles the OnMouseDownEvent + */ +bool CPropertyTreeControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) + m_PropRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT); + + return true; +} + +bool CPropertyTreeControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDoubleClick(inPoint, inFlags)) { + m_PropRow->OnMouseDoubleClick(); + } + return true; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h new file mode 100644 index 00000000..5bc61c23 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_PROPERTY_TREE_CONTROL_H +#define INCLUDED_PROPERTY_TREE_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "SIcon.h" +#include "StringEdit.h" + +class CPropertyRow; + +class CPropertyTreeControl : public CControl +{ +public: + CPropertyTreeControl(CPropertyRow *inPropRow); + virtual ~CPropertyTreeControl(); + + void Draw(CRenderer *inRenderer) override; + + void SetIndent(long inIndent); + long GetIndent(); + + void SetHighlighted(bool inIsHighlighted); + + CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override; + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + +protected: + long m_Indent; + CPropertyRow *m_PropRow; + CSIcon m_Icon; + CStringEdit m_Text; + ::CColor m_BackgroundColor; +}; +#endif // INCLUDED_PROPERTY_TREE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp new file mode 100644 index 00000000..b445db83 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "ScalableScroller.h" +#include "ScalableScrollerBar.h" + +CScalableScroller::CScalableScroller() + : CScroller(false) + , m_ScalableBar(nullptr) + , m_ScalingListener(nullptr) +{ + Initialize(); +} + +CScalableScroller::~CScalableScroller() +{ +} + +CScrollerBar *CScalableScroller::CreateHorizontalBar() +{ + if (m_ScalableBar == nullptr) { + m_ScalableBar = new CScalableBar(this); + m_ScalableBar->SetOrientation(CScrollerBar::HORIZONTAL); + m_ScalableBar->SetScalingListener(m_ScalingListener); + } + return m_ScalableBar; +} + +void CScalableScroller::SetScalingListener(CScalingListener *inListener) +{ + m_ScalingListener = inListener; + + if (m_ScalableBar != nullptr) { + m_ScalableBar->SetScalingListener(inListener); + } +} + +//==================================================================== +/** + * Protected function for seting the display size of the scroller. + * Overridden because the scaleable scroller thumb at the bottom of + * the timeline was getting messed up. Yes, it's a hack, but I couldn't + * fix it any other way. + */ +void CScalableScroller::SetVisibleSize(CPt inSize) +{ + m_VisibleSize = inSize; + + // Don't call the base class because it messes things up +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h new file mode 100644 index 00000000..9fd6df3b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_SCALABLE_SCROLLER_H +#define INCLUDED_SCALABLE_SCROLLER_H 1 + +#pragma once + +#include "Scroller.h" + +class CScalingListener; +class CScalableBar; + +class CScalableScroller : public CScroller +{ +public: + CScalableScroller(); + virtual ~CScalableScroller(); + + void SetScalingListener(CScalingListener *inScalingListener); + + void SetVisibleSize(CPt inSize) override; + +protected: + CScrollerBar *CreateHorizontalBar() override; + + CScalableBar *m_ScalableBar; + + CScalingListener *m_ScalingListener; +}; +#endif // INCLUDED_SCALABLE_SCROLLER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp new file mode 100644 index 00000000..77c63292 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "ScrollerBackground.h" +#include "ScalableScrollerBar.h" +#include "ScalableScroller.h" +#include "Renderer.h" +#include "MouseCursor.h" +#include "ResourceCache.h" + +#include <QApplication> + +//============================================================================= +/** + * Creates a new ThumbTab (the scalable ends of the thumb). + * @param inThumb the thumb this belongs to. + * @param inIsRight true if this is the right side, false for left. + * @param inBar the ScalableBar this belongs to. + */ +CScalableThumbTab::CScalableThumbTab(CScalableThumb *inThumb, bool inIsRightTab, + CScalableBar *inBar) + : m_Bar(inBar) + , m_IsMouseDown(false) + , m_IsRightTab(inIsRightTab) +{ + m_Thumb = inThumb; +} + +CScalableThumbTab::~CScalableThumbTab() +{ +} + +//============================================================================= +/** + * MouseOver handler, modifies the cursor. + * @param inPoint the mouse location. + * @param inFlags the mouse state. + */ +void CScalableThumbTab::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); + Invalidate(); +} + +//============================================================================= +/** + * Mouse out handler, invalidates the control to clear the mouse over drawing. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CScalableThumbTab::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + if (!m_IsMouseDown) + resetCursor(); + + Invalidate(); +} + +//============================================================================= +/** + * Mouse move handlers, if this was clicked on then drags the control. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CScalableThumbTab::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + // Only drag if this was clicked on + if (m_IsMouseDown) { + long theDiff = inPoint.x - m_MouseDownLoc.x; + // Fire the scaling event for the delta size. + if (m_IsRightTab) + m_Bar->OnScalingRight(theDiff); + else + m_Bar->OnScalingLeft(theDiff); + } + + CRct theRect(GetSize()); + if (theRect.IsInRect(inPoint)) + setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); +} + +//============================================================================= +/** + * Mouse click handler, starts resizing the control. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +bool CScalableThumbTab::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseDown(inPoint, inFlags); + + setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); + m_IsMouseDown = true; + m_MouseDownLoc = inPoint; + + return true; +} + +//============================================================================= +/** + * Mouse up handler, ends resizing this control. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CScalableThumbTab::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + + resetCursor(); + + m_IsMouseDown = false; +} + +//============================================================================= +/** + * Draw this control. + * @param inRenderer the renderer to draw to. + */ +void CScalableThumbTab::Draw(CRenderer *inRenderer) +{ + CPt theSize = GetSize(); + CRct theRect(theSize); + + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetScrollThumbBGColor()); + + // Draw the light colored highlight + inRenderer->PushPen(CStudioPreferences::GetScrollThumbHighlightColor()); + inRenderer->MoveTo(CPt(1, theSize.y - 1)); + inRenderer->LineTo(CPt(1, 1)); + inRenderer->LineTo(CPt(theSize.x - 1, 1)); + inRenderer->PopPen(); + + // Draw the dark bounding rectangle + CColor theGripBoundColor = CStudioPreferences::GetScrollThumbShadowColor(); + inRenderer->Draw3dRect(theRect, theGripBoundColor, theGripBoundColor); +} + +//============================================================================= +/** + * Create a scalable thumb, this is the dragging component of the bar. + * @param inScrollerBar the bar this belongs to. + */ +CScalableThumb::CScalableThumb(CScalableBar *inScrollerBar) + : CScrollerThumb(inScrollerBar) + , m_LeftTab(this, false, inScrollerBar) + , m_RightTab(this, true, inScrollerBar) +{ + m_ScrollerBar = inScrollerBar; + + m_LeftTab.SetPosition(CPt(0, 0)); + + AddChild(&m_LeftTab); + AddChild(&m_RightTab); +} + +CScalableThumb::~CScalableThumb() +{ +} + +//============================================================================= +/** + * Set the size of this component, overrides to update the location of the tabs. + * @param inSize the new size of this control. + */ +void CScalableThumb::SetSize(CPt inSize) +{ + CScrollerThumb::SetSize(inSize); + m_LeftTab.SetSize(CPt(7, inSize.y)); + m_RightTab.SetSize(CPt(7, inSize.y)); + m_RightTab.SetPosition(CPt(inSize.x - m_RightTab.GetSize().x, 0)); +} + +//============================================================================= +/** + * On double click this sends off a reset scaling notification. + * @param inPoint the mouse location. + * @param inFlags the state of the mouse. + */ +bool CScalableThumb::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDoubleClick(inPoint, inFlags)) + m_ScrollerBar->OnScalingReset(); + + return true; +} + +//============================================================================= +/** + * Creates a new scalable scroller bar. + * This object can only be used for horizontal scrolling. + * @param inScroller the scalable scroller this is operating on. + */ +CScalableBar::CScalableBar(CScalableScroller *inScroller) + : CScrollerBar(inScroller, false) + , m_ScalableScroller(inScroller) + , m_Listener(nullptr) + , m_Thumb(nullptr) +{ + Initialize(); +} + +CScalableBar::~CScalableBar() +{ +} + +//============================================================================= +/** + * Create a new thumb control. + * This method is here so the ScalableBar can override it and return the Scalable + * Thumb instead of a normal thumb. + */ +CControl *CScalableBar::CreateThumb() +{ + if (m_Thumb == nullptr) + m_Thumb = new CScalableThumb(this); + return m_Thumb; +} + +//============================================================================= +/** + * This control is not allowed to become disabled (it should always allow scaling). + * @param inIsEnabled ignored. + */ +void CScalableBar::SetEnabled(bool inIsEnabled) +{ + Q_UNUSED(inIsEnabled); + CControl::SetEnabled(true); +} + +//============================================================================= +/** + * Set the single scaling listener that is to carry out the actual scaling work. + * @param inListener the scaling listener, there is only one. + */ +void CScalableBar::SetScalingListener(CScalingListener *inListener) +{ + m_Listener = inListener; +} + +//============================================================================= +/** + * Event from the left ThumbTab that it is scaling. + * @param inAmount the amount that the left ThumbTab is being scaled by. + */ +void CScalableBar::OnScalingLeft(long inAmount) +{ + CPt theLoc = m_Thumb->GetPosition(); + CPt theSize = m_Thumb->GetSize(); + + // Don't let the loc go before the end of the control. + if (theLoc.x + inAmount < 0) + inAmount = -theLoc.x; + + // Anchors the scroller position when its size reaches the minimum size + // The algorithm does not modify the inAmount as the scale can be further reduced, + // when the scroller reaches the minimum size. + + CPt thePreviousPosition; + bool theAnchor = false; + if (theSize.x - inAmount < m_Thumb->GetMinimumSize().x) { + thePreviousPosition = m_Thumb->GetPosition(); + theAnchor = true; + } + + // Tell the listener of the scaling, it's the listener that will do the actual scaling work. + if (m_Listener != nullptr) + m_Listener->OnScalingLeft(theSize.x - inAmount, m_Background->GetSize().x, + m_Thumb->GetPosition().x + inAmount); + + // When the Anchor flag is true (i.e. when the scroller has reach its minimum size), stop the + // scroller + // from moving by restoring its previous position. + if (theAnchor) { + m_Thumb->SetPosition(thePreviousPosition); + } + + Invalidate(); +} + +//============================================================================= +/** + * Event from the right ThumbTab that it is scaling. + * @param inAmount the amount that the left ThumbTab is being scaled by. + */ +void CScalableBar::OnScalingRight(long inAmount) +{ + CPt theLoc = m_Thumb->GetPosition(); + CPt theSize = m_Thumb->GetSize(); + // Don't let the loc go after the end of the control. + if (theLoc.x + theSize.x + inAmount > m_Background->GetSize().x) + inAmount = m_Background->GetSize().x - (theLoc.x + theSize.x); + + // Anchors the scroller position when its size reaches the minimum size + // The algorithm does not modify the inAmount as the scale can be further reduced, + // when the scroller reaches the minimum size. + + CPt thePreviousPosition; + bool theAnchor = false; + if (theSize.x + inAmount < m_Thumb->GetMinimumSize().x) { + thePreviousPosition = m_Thumb->GetPosition(); + theAnchor = true; + } + + // Tell the listener of the scaling, it's the listener that will do the actual scaling work. + if (m_Listener != nullptr) + m_Listener->OnScalingRight(theSize.x + inAmount, m_Background->GetSize().x, + m_Thumb->GetPosition().x); + + // When the Anchor flag is true (i.e. when the scroller has reach its minimum size), stop the + // scroller + // from moving by restoring its previous position. + if (theAnchor) { + m_Thumb->SetPosition(thePreviousPosition); + } + Invalidate(); +} + +//============================================================================= +/** + * Handles scaling reset messages commands, just routes them to the listener. + */ +void CScalableBar::OnScalingReset() +{ + m_Listener->OnScalingReset(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h new file mode 100644 index 00000000..afc0ef1e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_SCALABLE_SCROLLER_BAR_H +#define INCLUDED_SCALABLE_SCROLLER_BAR_H 1 + +#pragma once + +#include "ScrollerThumb.h" +#include "ScrollerBar.h" + +#include <QCursor> + +class CScalableBar; +class CScalableScroller; +class CScalableThumb; + +class CScalingListener +{ +public: + virtual void OnScalingLeft(long inLength, long inTotalLength, long inOffset) = 0; + virtual void OnScalingRight(long inLength, long inTotalLength, long inOffset) = 0; + virtual void OnScalingReset() = 0; +}; + +class CScalableThumbTab : public CControl +{ +public: + CScalableThumbTab(CScalableThumb *inThumb, bool inIsRightTab, CScalableBar *inBar); + virtual ~CScalableThumbTab(); + + void Draw(CRenderer *inRenderer) override; + + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + +protected: + CScalableThumb *m_Thumb; + CScalableBar *m_Bar; + bool m_IsMouseDown; + bool m_IsRightTab; + CPt m_MouseDownLoc; +}; + +class CScalableThumb : public CScrollerThumb +{ +public: + CScalableThumb(CScalableBar *inScrollerBar); + virtual ~CScalableThumb(); + + void SetSize(CPt inSize) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + +protected: + CScalableBar *m_ScrollerBar; + CScalableThumbTab m_LeftTab; + CScalableThumbTab m_RightTab; +}; + +class CScalableBar : public CScrollerBar +{ +public: + CScalableBar(CScalableScroller *inScroller); + virtual ~CScalableBar(); + + void SetEnabled(bool inIsEnabled) override; + + void SetScalingListener(CScalingListener *inListener); + + void OnScalingRight(long inAmount); + void OnScalingLeft(long inAmount); + void OnScalingReset(); + +protected: + CControl *CreateThumb() override; + + CScalableScroller *m_ScalableScroller; + + CScalingListener *m_Listener; + CScalableThumb *m_Thumb; +}; + +#endif // INCLUDED_SCALABLE_SCROLLER_BAR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp b/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp new file mode 100644 index 00000000..ac14bee2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "SlideRow.h" +#include "BlankToggleControl.h" +#include "ColorControl.h" +#include "SlideTimebarRow.h" +#include "Bindings/ITimelineItemBinding.h" +#include "ITimelineControl.h" + +CSlideRow::CSlideRow(ITimelineItemBinding *inTimelineItem) + : m_TimelineControl(nullptr) +{ + Initialize(inTimelineItem); +} + +CSlideRow::~CSlideRow() +{ +} + +void CSlideRow::SetTimelineControl(ITimelineControl *inTimelineControl) +{ + m_TimelineControl = inTimelineControl; +} + +//============================================================================= +/** + * Expand this node of the tree control. + * This will display all children the fit the filter. + */ +void CSlideRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp) +{ + if (!m_Loaded) { + m_Loaded = true; + LoadChildren(); + } + + CBaseStateRow::Expand(inExpandAll, inExpandUp); +} + +//============================================================================= +/** + * This do not 'contribute' to its child's active start time + */ +bool CSlideRow::CalculateActiveStartTime() +{ + return false; +} +//============================================================================= +/** + * This do not 'contribute' to its child's active end time + */ +bool CSlideRow::CalculateActiveEndTime() +{ + return false; +} + +ISnappingListProvider *CSlideRow::GetSnappingListProvider() const +{ + ASSERT(m_TimelineControl); + return m_TimelineControl->GetSnappingListProvider(); +} + +void CSlideRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + // does nothing + Q_UNUSED(inProvider); +} + +//============================================================================= +/** + * See CBaseStateRow::GetTopControl comments. + * This being to "top" row will have the actual pointer + */ +ITimelineControl *CSlideRow::GetTopControl() const +{ + return m_TimelineControl; +} + +//============================================================================= +/** + * Create a new CStateTimebarRow. + * This is virtual and used for objects to return their type specific + * timebar rows if they want to. + * @return the created timebar row. + */ +CBaseTimebarlessRow *CSlideRow::CreateTimebarRow() +{ + return new CSlideTimebarRow(this); +} + +bool CSlideRow::PerformFilter(const CFilter &inFilter) +{ + Q_UNUSED(inFilter); + return true; +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideRow.h b/src/Authoring/Studio/Palettes/Timeline/SlideRow.h new file mode 100644 index 00000000..d978f11e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/SlideRow.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIME_CONTEXT_ROW_H +#define INCLUDED_TIME_CONTEXT_ROW_H 1 + +#pragma once + +#include "BaseStateRow.h" + +class ISnappingListProvider; +class ITimelineControl; + +class CSlideRow : public CBaseStateRow +{ +public: + CSlideRow(ITimelineItemBinding *inTimelineItem); + virtual ~CSlideRow(); + + void SetTimelineControl(ITimelineControl *inTimelineControl); + + // BaseStateRow + void Expand(bool inExpandAll = false, bool inExpandUp = false) override; + bool CalculateActiveStartTime() override; + bool CalculateActiveEndTime() override; + ISnappingListProvider *GetSnappingListProvider() const override; + void SetSnappingListProvider(ISnappingListProvider *inProvider) override; + ITimelineControl *GetTopControl() const override; + +protected: + // CBaseStateRow + CBaseTimebarlessRow *CreateTimebarRow() override; + bool PerformFilter(const CFilter &inFilter) override; + + ITimelineControl *m_TimelineControl; +}; +#endif // INCLUDED_TIME_CONTEXT_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp new file mode 100644 index 00000000..49ce261f --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "SlideTimebarRow.h" +#include "SlideRow.h" + +CSlideTimebarRow::CSlideTimebarRow(CSlideRow *inSlideRow) + : m_SlideRow(inSlideRow) +{ +} + +CSlideTimebarRow::~CSlideTimebarRow() +{ +} + +void CSlideTimebarRow::CommitSelections() +{ +} + +void CSlideTimebarRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown) +{ + Q_UNUSED(inRect); + Q_UNUSED(inModifierKeyDown); +} + +void CSlideTimebarRow::SelectKeysByTime(long inTime, bool inSelected) +{ + Q_UNUSED(inTime); + Q_UNUSED(inSelected); +} + +void CSlideTimebarRow::SelectAllKeys() +{ +} + +void CSlideTimebarRow::PopulateSnappingList(CSnapper *inSnapper) +{ + Q_UNUSED(inSnapper); +} + +CBaseStateRow *CSlideTimebarRow::GetBaseStateRow() const +{ + return m_SlideRow; +} + +// This is not applicable to a SlideTimebarRow!! +ISnappingListProvider &CSlideTimebarRow::GetSnappingListProvider() const +{ + throw; +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h new file mode 100644 index 00000000..a2f63e33 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIME_CONTEXT_TIMEBAR_ROW_H +#define INCLUDED_TIME_CONTEXT_TIMEBAR_ROW_H 1 + +#pragma once + +#include "BaseTimebarlessRow.h" + +class CSlideRow; + +class CSlideTimebarRow : public CBaseTimebarlessRow +{ +public: + CSlideTimebarRow(CSlideRow *inSlideRow); + virtual ~CSlideTimebarRow(); + + void CommitSelections() override; + + void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) override; + void SelectKeysByTime(long inTime, bool inSelected) override; + void SelectAllKeys() override; + + void PopulateSnappingList(CSnapper *inSnappingList) override; + ISnappingListProvider &GetSnappingListProvider() const override; + +protected: + CBaseStateRow *GetBaseStateRow() const override; + +protected: + CSlideRow *m_SlideRow; +}; +#endif // INCLUDED_TIME_CONTEXT_TIMEBAR_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp b/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp new file mode 100644 index 00000000..2b405e70 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp @@ -0,0 +1,455 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "Snapper.h" +#include "StudioPreferences.h" +#include "Control.h" +#include "CoreUtils.h" +#include "StudioUtils.h" +#include "HotKeys.h" + +//============================================================================= +/** + * Create a new snapper object. + * @param inTimeRatio the default time ratio. + */ +CSnapper::CSnapper(double inTimeRatio) + : m_theStartTime(0) + , m_theEndTime(0) + , m_TimeRatio(inTimeRatio) + , m_IsSnappingKeyframes(false) + , m_IsSnappingSelectedKeyframes(true) + , m_Offset(0) + , m_StartHeight(0) + , m_EndHeight(0) + , m_PeriodicInterval(LONG_MAX) + , m_InitialOffset(0) + , m_ObjectTimeOffset(0) + , m_TimeOffset(0) + , m_KeyFrameClicked(false) + , m_Source(nullptr) +{ + SetSnappingDistance(CStudioPreferences::GetSnapRange()); +} + +CSnapper::~CSnapper() +{ +} +//============================================================================= +/** + * Set if keyframe is clicked + * @param inKeyFrameClicked toggles snapping to end handles at 1 pixel range, + * if true. + */ +void CSnapper::SetKeyFrameClicked(bool inKeyFrameClicked) +{ + m_KeyFrameClicked = inKeyFrameClicked; +} +//============================================================================= +/** + * Clear all the snapping points from this. + * This effectively erases this object. + */ +void CSnapper::Clear() +{ + m_PeriodicInterval = LONG_MAX; + m_Times.clear(); + m_KeyFrameClicked = false; + SetSnappingDistance(CStudioPreferences::GetSnapRange()); +} + +//============================================================================= +/** + * Add a snapping point at the specified time. + * @param inTime the time to add the point at. + */ +void CSnapper::AddTime(long inTime) +{ + m_Times.insert(inTime); +} + +//============================================================================= +/** + * Add a snapping point at the specified pixel location. + * @param inPosition the position of the snapping point to add. + */ +void CSnapper::AddPixelLocation(long inPosition) +{ + AddTime(::PosToTime(inPosition, m_TimeRatio)); +} + +//============================================================================= +/** + * Set whether or not keyframes should be added as snapping points. + * @param true if keyframes should be added as snapping points. + */ +void CSnapper::SetSnappingKeyframes(bool inIsSnappingKeyframes) +{ + m_IsSnappingKeyframes = inIsSnappingKeyframes; +} + +//============================================================================= +/** + * Checks whether or not keyframes are being snapped to. + * @return true if keyframes should be snapped to. + */ +bool CSnapper::IsSnappingKeyframes() +{ + return m_IsSnappingKeyframes; +} + +//============================================================================= +/** + * Sets whether or not selected keyframes are being snapped to. + * This is used to ignore all selected keyframes when keyframes are being + * dragged. + * @param inIsSnappingSelectedKeyframes true if selected keys should be snapped. + */ +void CSnapper::SetSnappingSelectedKeyframes(bool inIsSnappingSelectedKeyframes) +{ + m_IsSnappingSelectedKeyframes = inIsSnappingSelectedKeyframes; +} + +//============================================================================= +/** + * Checks whether or not selected keyframes are being snapped to. + * This is used to ignore all selected keyframes when keyframes are being + * dragged. + * @return true if selected keyframes should be snapping points. + */ +bool CSnapper::IsSnappingSelectedKeyframes() +{ + return m_IsSnappingKeyframes && m_IsSnappingSelectedKeyframes; +} + +//============================================================================= +/** + * Set the current time ratio. + * This will effect all time based positions as well as the intervals. It is + * suggested that this is called on an empty snapper when possible for speed. + * @param inTimeRatio the new time ratio. + */ +void CSnapper::SetTimeRatio(double inTimeRatio) +{ + m_SnapDistance = ::dtol(m_SnapDistance * m_TimeRatio / inTimeRatio); + m_TimeRatio = inTimeRatio; +} + +//============================================================================= +/** + * Set the visible area of this snapper. + * This is used to limit snapping to visible areas only. The visibility limit + * is only on vertical because the user can scroll horizontally and expose + * previously non visible objects. The heights are relative to the initial + * offset and + * @param inStartHeight the minimum height for visibility. + * @param inEndHeight the maximum height for visibility. + */ +void CSnapper::SetVisibleArea(long inStartHeight, long inEndHeight) +{ + m_StartHeight = inStartHeight; + m_EndHeight = inEndHeight; +} + +//============================================================================= +/** + * Push an offset into this for calculating later visibilities. + * This is accumulated with previous offsets. + * @param inHeight the amount to modify the offset by. + */ +void CSnapper::PushOffset(long inHeight) +{ + m_Offsets.push_back(inHeight); + m_Offset += inHeight; +} + +//============================================================================= +/** + * Remove an offset that was pushed on. + * This will update the current offset to be what it was before the push. + */ +void CSnapper::PopOffset() +{ + m_Offset -= m_Offsets.back(); + m_Offsets.pop_back(); +} + +//============================================================================= +/** + * Checks to see if an object at inPosition of height inHeight is visible. + * This uses the current offset with the visible area to check visibility. + * @param inPosition the position of the object to be checked. + * @param inHeight the height of the object to be checked. + */ +bool CSnapper::IsVisible(long inPosition, long inHeight) +{ + return (inPosition + m_Offset < m_EndHeight + && inPosition + m_Offset + inHeight > m_StartHeight); +} + +//============================================================================= +/** + * Add a periodic interval to the snapping points. + * This will make snapping points at every multiple of inInterval. The interval + * starts at time 0. + * @param inInterval time in millis for the periodic points. + */ +void CSnapper::SetPeriodicInterval(long inInterval) +{ + m_PeriodicInterval = inInterval; +} + +//============================================================================= +/** + * Interpret the given position into a snapped/nonsnapped position. + * This will use the inFlags to determine whether or not this should be snapping + * and uses inPosition to figure out the closest snapping position. If the + * closest position is not within the tolerances then inPosition will be + * returned. + * @param inPosition to position to check for snapping. + * @param inFlags the mouse state flags, to determine whether or not snapping. + */ +bool CSnapper::InterpretTimeEx(long &ioTime, long inFlags) +{ + // Only snap if shift key is down. + if (inFlags & CHotKeys::MODIFIER_SHIFT) + return GetSnapTime(ioTime, true); + else + return GetSnapTime(ioTime, false); +} + +//============================================================================= +/** + * Interpret the given position into a snapped/nonsnapped position. + * This will use the inFlags to determine whether or not this should be snapping + * and uses inPosition to figure out the closest snapping position. If the + * closest position is not within the tolerances then inPosition will be + * returned. + * @param inPosition to position to check for snapping. + * @param inFlags the mouse state flags, to determine whether or not snapping. + */ +long CSnapper::InterpretTime(long inTime, long inFlags) +{ + if (inFlags & CHotKeys::MODIFIER_SHIFT) { + GetSnapTime(inTime, true); + return inTime; + } + GetSnapTime(inTime, false); + return inTime; +} + +//============================================================================= +/** + * Set the maximum distance that snapping will occur at. + * This sets the maximum tolerances for a position to be away from a snapping + * point and still get snapped to it. + * @param inSnapDistance the snap distance, in pixels. + */ +void CSnapper::SetSnappingDistance(long inSnapDistance) +{ + m_SnapDistance = ::dtol(inSnapDistance / m_TimeRatio); +} + +//============================================================================= +/** + * Helper method to find the closer of two values to a third. + * If both values are the same distance then the first value will be returned. + * @param inFirst the first value to check the distance to inBase. + * @param inSecond the second value to check the distance to inBase. + * @param inBase the value the others are being compared to. + * @return the value, either first or second, that is closest to inBase. + */ +long GetClosestValue(long inFirst, long inSecond, long inBase) +{ + return (::labs(inFirst - inBase) <= ::labs(inSecond - inBase)) ? inFirst : inSecond; +} + +//============================================================================= +/** + * Given the current time, it is adjusted if necessary to snap. + * @param ioTime the current time on input; on output the adjusted time + * @param inShiftKeyDown true if the shift key was down, otherwise false + * @return true if a snap occurred, otherwise false + */ +bool CSnapper::GetSnapTime(long &ioTime, bool inShiftKeyDown) +{ + bool theReturnValue = false; + + if (inShiftKeyDown) // If user hits the shift key (i.e. snapping is toggled on) + { + long thePreviousTime = 0; + long theNextTime = 0; + + // Go through all the snapping positions finding the positions on either + // side of ioPosition. Bsically just loop through until a snap position + // is larger than in position and use that with the previous value to get + // the closest snapping location. + TTimeList::iterator thePos = m_Times.begin(); + for (; thePos != m_Times.end(); ++thePos) { + thePreviousTime = theNextTime; + theNextTime = (*thePos); + + // Don't need to go any further because we've hit the first point larget than + // ioPosition. + if (theNextTime >= ioTime) { + break; + } + } + + // Use the last snap position less than ioPosition and the first snap position greater than + // ioPosition + // to find the closest of the two. + long theClosestTime = GetClosestValue(thePreviousTime, theNextTime, ioTime); + long theClosestInterval = GetClosestPeriodicInterval(ioTime); + + // Get the closest snapping position between the periodic interval and the position + theClosestTime = GetClosestValue(theClosestTime, theClosestInterval, ioTime); + + // If the closest position is within tolerances then use it, otherwise return the original + // value. + if (::labs(theClosestTime - ioTime) <= m_SnapDistance) { + ioTime = theClosestTime; + theReturnValue = true; + } + } else // If user does not hit the shift key (i.e. snapping is toggled off) + { + // Snap to end handles at 1 pixel range if the current object dragged + // is a keyframe + if (m_KeyFrameClicked) { + // Returns if the startTime or the endTime of a Time Bar is closer to the dragged + // keyframe + long theClosestTime = GetClosestValue(m_theStartTime, m_theEndTime, ioTime); + + // Set snapping range to 1 pixel and converts it to time. + // The snapping range of 1 pixel applies for keyframes that are dragged really + // close to the end handles. + long thePixel = 1; + long theTime = ::dtol(thePixel / m_TimeRatio); + + // Determines if the closest time is within 1 pixel range + // If so returns the closest time, which is the snapping time, and true indicating + // that snapping occurs. + if (::labs(theClosestTime - ioTime) <= theTime) { + ioTime = theClosestTime; + theReturnValue = true; + } + } + } + + return theReturnValue; +} +//============================================================================= +/** + * Get the closest periodic interval to inPosition. + * Since it is too expensive to store every possible periodic interval in the + * snapping list, this just dynamically figures out the closest periodic + * interval. + */ +void CSnapper::SetStartEndTime(long theStartTime, long theEndTime) +{ + m_theStartTime = theStartTime; + m_theEndTime = theEndTime; +} +//============================================================================= +/** + * Get the closest periodic interval to inPosition. + * Since it is too expensive to store every possible periodic interval in the + * snapping list, this just dynamically figures out the closest periodic + * interval. + */ +long CSnapper::GetClosestPeriodicInterval(long inTime) +{ + long theIntervalLow = inTime / m_PeriodicInterval * m_PeriodicInterval; + long theIntervalHigh = (inTime / m_PeriodicInterval + 1) * m_PeriodicInterval; + + return GetClosestValue(theIntervalLow, theIntervalHigh, inTime); +} + +//============================================================================= +/** + * Used to pass off snapping logic to this for objects being dragged. + * This does all the work of an object when the object itself is being dragged + * and it's position is being modified by the drag, but it needs to be snapped + * as well. It is not necessary to call this unless ProcessDrag is being + * used. + * @param inClickPosition the mouse click location, usually just inPoint.x. + * @param inCenterOffset the center of the object where it should be snapped to. + */ +void CSnapper::BeginDrag(long inClickLocation, long inCenterTimeOffset) +{ + m_InitialOffset = inClickLocation; + m_ObjectTimeOffset = inCenterTimeOffset; +} + +//============================================================================= +/** + * Process an object's drag event and figure out where the object should be. + * This does all the work of figuring out where the object should be snapped + * to. It is not necessary to call this, but it may make implementing snapping + * much easier. BeginDrag needs to be called on OnMouseDown to use this. + * @param inPosition the position of the mouse, GetPosition( ).x + inPoint.x. + * @param inFlags the mouse state flags, used to determine snapping state. + */ +long CSnapper::ProcessDrag(long inTime, long inOffset, long inFlags) +{ + long theModPos = inTime + m_TimeOffset + ::dtol((inOffset - m_InitialOffset) / m_TimeRatio); + InterpretTimeEx(theModPos, inFlags); + theModPos -= m_TimeOffset; + + return theModPos; +} + +//============================================================================= +/** + * Set the source for this Snapper object. + * This is so that objects may choose to no add themselves to snapping lists + * that they originated. This is only meant for comparison with the 'this' ptr. + * @param inSource the source object for this snapping list. + */ +void CSnapper::SetSource(void *inSource) +{ + m_Source = inSource; +} + +//============================================================================= +/** + * Get the source for this snapper object. + * @return the source of the snapping. + */ +void *CSnapper::GetSource() +{ + return m_Source; +} + +void CSnapper::SetTimeOffset(long inTimeOffset) +{ + m_TimeOffset = inTimeOffset; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Snapper.h b/src/Authoring/Studio/Palettes/Timeline/Snapper.h new file mode 100644 index 00000000..ea230bc0 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/Snapper.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_SNAPPER_H +#define INCLUDED_SNAPPER_H 1 + +#pragma once + +#include <set> +#include <vector> + +class CSnapper +{ + typedef std::set<long> TTimeList; + typedef std::vector<long> TOffsetList; + +public: + CSnapper(double inTimeRatio = .1); + virtual ~CSnapper(); + + void AddTime(long inTime); + void AddPixelLocation(long inPixelLoc); + + void SetSnappingKeyframes(bool inIsSnappingKeyframes); + bool IsSnappingKeyframes(); + void SetSnappingSelectedKeyframes(bool inIsSnappingSelectedKeyframes); + bool IsSnappingSelectedKeyframes(); + + void Clear(); + + void SetVisibleArea(long inStartHeight, long inEndHeight); + void PushOffset(long inHeight); + void PopOffset(); + bool IsVisible(long inPosition, long inHeight); + + void SetTimeRatio(double inTimeRatio); + + void SetPeriodicInterval(long inInterval); + + bool InterpretTimeEx(long &ioTime, long inFlags); + long InterpretTime(long inTime, long inFlags); + + void SetSnappingDistance(long inSnapDistance); + + void BeginDrag(long inPosition, long inOffset = 0); + long ProcessDrag(long inTime, long inPosition, long inFlags); + + void SetSource(void *inSource); + void *GetSource(); + + void SetTimeOffset(long inTimeOffset); + void SetStartEndTime(long theStartTime, long theEndTime); + void SetKeyFrameClicked(bool inKeyFrameClicked); + +protected: + bool GetSnapTime(long &inTime, bool inShiftKeyDown); + long GetClosestPeriodicInterval(long inTime); + + long m_theStartTime; + long m_theEndTime; + + TTimeList m_Times; + TOffsetList m_Offsets; + + double m_TimeRatio; + + bool m_IsSnappingKeyframes; + bool m_IsSnappingSelectedKeyframes; + long m_Offset; + long m_StartHeight; + long m_EndHeight; + long m_SnapDistance; + + long m_PeriodicInterval; + + long m_InitialOffset; + long m_ObjectTimeOffset; + long m_TimeOffset; + bool m_KeyFrameClicked; + void *m_Source; +}; + +// Interface that will provider the info for snapping logic in the timebars and keyframes +class ISnappingListProvider +{ +public: + virtual ~ISnappingListProvider() {} + + virtual void PopulateSnappingList(CSnapper *inSnappingList) = 0; +}; + +#endif // INCLUDED_SNAPPER_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp new file mode 100644 index 00000000..bdc07a11 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "StateRow.h" +#include "TimelineControl.h" +#include "TimelineTimelineLayout.h" +#include "ColorControl.h" +#include "ToggleControl.h" +#include "PropertyRow.h" +#include "StateTimebarRow.h" +#include "BaseTimebarlessRow.h" +#include "BaseTimelineTreeControl.h" +#include "Bindings/ITimelineItemBinding.h" + +//============================================================================= +/** + * Creates a new CStateRow for the Asset. + * @param inParentRow the parent of this row. + */ +CStateRow::CStateRow(CBaseStateRow *inParentRow) +{ + m_ParentRow = inParentRow; +} + +CStateRow::~CStateRow() +{ +} + +CBlankToggleControl *CStateRow::CreateToggleControl() +{ + return (m_TimelineItemBinding->ShowToggleControls()) + ? new CToggleControl(this, m_TimelineItemBinding) + : CBaseStateRow::CreateToggleControl(); +} + +//============================================================================= +/** + * Create a new CStateTimebarRow. + * This is virtual and used for objects to return their type specific + * timebar rows if they want to. + * @return the created timebar row. + */ +CBaseTimebarlessRow *CStateRow::CreateTimebarRow() +{ + return new CStateTimebarRow(this); +} + +//============================================================================= +/** + * Initialize this object. + * This must be called after construction and may only be called once. + */ +void CStateRow::Initialize(ITimelineItemBinding *inTimelineItemBinding, + ISnappingListProvider *inProvider) +{ + CBaseStateRow::Initialize(inTimelineItemBinding); + + // cache these numbers. I believe caching these numbers is to avoid having to incur expensive + // recursive calculations on ever draw. + CalculateActiveStartTime(); + CalculateActiveEndTime(); + + SetSnappingListProvider(inProvider); + + if (GetTimelineItem()->IsExpanded()) // this is stored for the current opened presentation and + // conveniently help you remember the last view before you + // switch slides. + Expand(); + // sk - Delay loading till this is expanded. I think it makes more sense to not have to incur + // work till the UI needs to be displayed + // Plus it would not work now since the parent always needs to be 'fully' initialized for the + //SnappingListProvider, prior to any child creation. + // else + // LoadChildren( ); +} + +//============================================================================= +/** + * Expand this node of the tree control. + * This will display all children the fit the filter. + */ +void CStateRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp) +{ + // Only RecalcLayout if loaded children or expanded. + bool theDoRecalLayout = !m_Loaded; + + if (!m_Loaded) + LoadChildren(); + + bool theWasExpanded = m_IsExpanded; + CBaseStateRow::Expand(inExpandAll, inExpandUp); + // Check if this is expanded + theDoRecalLayout |= (theWasExpanded != m_IsExpanded); + GetTimelineItem()->SetExpanded( + m_IsExpanded); // remember this setting so that it persist when this row is recreated + + if (theDoRecalLayout) + DoTimelineRecalcLayout(); +} + +//============================================================================= +/** + * Collapse this node of the tree control. + * This will hide all children of this control. + */ +void CStateRow::Collapse(bool inCollapseAll /* = false */) +{ + bool theWasExpanded = m_IsExpanded; + CBaseStateRow::Collapse(inCollapseAll); + + GetTimelineItem()->SetExpanded( + m_IsExpanded); // remember this setting so that it persist when this row is recreated + // only RecalcLayout if this is collapsed + if (theWasExpanded != m_IsExpanded) + DoTimelineRecalcLayout(); +} + +bool CStateRow::PerformFilter(const CFilter &inFilter) +{ + return inFilter.Filter(m_TimelineItemBinding->GetTimelineItem()); +} + +//============================================================================= +/** + * Set the indent of this control. + * This controls how far to the right the toggle and text display on this + * control. The indent should be increased for every level of sub-controls. + * @param inIndent how much this control should be indented. + */ +void CStateRow::SetIndent(long inIndent) +{ + CTimelineRow::SetIndent(inIndent); + + m_TreeControl->SetIndent(inIndent); + + TStateRowList::iterator thePos = m_StateRows.begin(); + for (; thePos != m_StateRows.end(); ++thePos) + (*thePos)->SetIndent(inIndent + CTimelineRow::TREE_INDENT); + + // For each property on this object + TPropertyRowList::iterator thePropPos = m_PropertyRows.begin(); + for (; thePropPos != m_PropertyRows.end(); ++thePropPos) { + CPropertyRow *thePropRow = (*thePropPos); + if (thePropRow) + thePropRow->SetIndent(inIndent + CTimelineRow::TREE_INDENT); + } +} + +bool CStateRow::HasVisibleChildren() +{ + if (!m_Loaded) { + CTimelineItemOrderedIterator theChildren(m_TimelineItemBinding); + // Return true if has children but do not load the children. + if (!theChildren.IsDone()) { + return true; + } + CTimelineItemPropertyIterator theProperties(m_TimelineItemBinding); + if (!theProperties.IsDone()) { + return true; + } + } + return CBaseStateRow::HasVisibleChildren(); +} + +ISnappingListProvider *CStateRow::GetSnappingListProvider() const +{ + CStateTimebarRow *theTimebarControl = dynamic_cast<CStateTimebarRow *>(m_TimebarControl); + return (theTimebarControl) ? &theTimebarControl->GetSnappingListProvider() : nullptr; +} + +void CStateRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + CStateTimebarRow *theTimebarControl = dynamic_cast<CStateTimebarRow *>(m_TimebarControl); + if (theTimebarControl) + theTimebarControl->SetSnappingListProvider(inProvider); +} + +//============================================================================= +/** + * Trigger any external applications where applicable. + */ +void CStateRow::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + if (!m_TimelineItemBinding + ->OpenAssociatedEditor()) // if not handled, fall backon the base class + CBaseStateRow::OnMouseDoubleClick(inPoint, inFlags); +} + +void CStateRow::OnTimeChange() +{ + CalculateActiveStartTime(); + CalculateActiveEndTime(); + + // sk - I don't see the need to DoTimelineRecalcLayout here, because that is usually when height + // of the control change + // this should just change width.. but maybe I am missing something, so I am leaving this + //here for 'easy' debugging + // DoTimelineRecalcLayout( ); + + m_TimebarControl->UpdateTime(GetStartTime(), GetEndTime()); + + GetTopControl()->OnLayoutChanged(); +} + +//============================================================================= +/** + * calculate the active start time... this function set the active start to its + * parent's start time if it comes after the objects start time + */ +bool CStateRow::CalculateActiveStartTime() +{ + long theRetVal = GetStartTime(); + + if (m_ParentRow) { + if (m_ParentRow->CalculateActiveStartTime()) { + long theParentActiveStart = m_ParentRow->GetActiveStart(); + if (theParentActiveStart > theRetVal) + theRetVal = theParentActiveStart; + } + } + m_ActiveStart = theRetVal; + return true; +} + +//============================================================================= +/** + * calculate the active end time... this function set the active end to its + * parent's end time if it comes before the objects end time + */ +bool CStateRow::CalculateActiveEndTime() +{ + long theRetVal = GetEndTime(); + if (m_ParentRow) { + if (m_ParentRow->CalculateActiveEndTime()) { + long theParentActiveEnd = m_ParentRow->GetActiveEnd(); + if (theParentActiveEnd < theRetVal) + theRetVal = theParentActiveEnd; + } + } + m_ActiveEnd = theRetVal; + return true; +} + +//============================================================================== +/** + * + */ +long CStateRow::GetLatestEndTime() +{ + if (m_IsExpanded) // if its children are not visible, they do not have any affect + return CBaseStateRow::GetLatestEndTime(); + + return GetActiveEnd(); +} + +//============================================================================= +/** + * Load all the properties on this object. + */ +void CStateRow::LoadProperties() +{ + m_TimelineItemBinding->LoadProperties(); +} + +//============================================================================== +/** + * Tells the timeline timeline layout to recalc its layout. Should only be called + * from this class, that's why it's protected. + */ +void CStateRow::DoTimelineRecalcLayout() +{ + GetTopControl()->OnLayoutChanged(); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRow.h b/src/Authoring/Studio/Palettes/Timeline/StateRow.h new file mode 100644 index 00000000..f03682e3 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateRow.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_STATE_ROW_H +#define INCLUDED_STATE_ROW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BaseStateRow.h" + +//============================================================================== +// Forwards +//============================================================================== +class CButtonControl; +class CButtonDownListener; +class CColorControl; +class CStateTreeControl; +class CToggleControl; +class CStateTimebarlessRow; +class CPropertyRow; +class CCmdBatch; +class CSnapper; +class CResImage; + +class CStateRow : public CBaseStateRow +{ +public: + CStateRow(CBaseStateRow *inParentRow); + virtual ~CStateRow(); + + using CBaseStateRow::Initialize; + virtual void Initialize(ITimelineItemBinding *inTimelineItemBinding, + ISnappingListProvider *inProvider); + + void Expand(bool inExpandAll = false, bool inExpandUp = false) override; + void Collapse(bool inCollapseAll = false) override; + void SetIndent(long inIndent) override; + virtual void OnTimeChange(); + + long GetLatestEndTime() override; + bool CalculateActiveStartTime() override; + bool CalculateActiveEndTime() override; + bool HasVisibleChildren() override; + ISnappingListProvider *GetSnappingListProvider() const override; + void SetSnappingListProvider(ISnappingListProvider *inProvider) override; + + // CControl + void OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + +protected: + CBlankToggleControl *CreateToggleControl() override; + CBaseTimebarlessRow *CreateTimebarRow() override; + + bool PerformFilter(const CFilter &inFilter) override; + void LoadProperties() override; + void DoTimelineRecalcLayout(); +}; +#endif // INCLUDED_STATE_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp new file mode 100644 index 00000000..921b4b04 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "StateRowFactory.h" +#include "Bindings/ITimelineItemBinding.h" +#include "StateRow.h" + +//============================================================================= +/** + * Create the type specific StateRow for the Asset. + * Different asset use different derivations of StateRow, and this will + * return the proper state row for the asset. + * @param inTimelineItem the timeline item to create the state row for. + * @param inParentRow the parent row of the state row being created. + * @param inSnappingListProvider For keyframe/timebar snapping + * @return CStateRow the row that represents the state, or nullptr if it should not show up. + */ +CStateRow *CStateRowFactory::CreateStateRow(ITimelineItemBinding *inTimelineItem, + CBaseStateRow *inParentRow, + ISnappingListProvider *inSnappingListProvider) +{ + CStateRow *theRow = nullptr; + if (inTimelineItem) { + theRow = new CStateRow(inParentRow); + + if (theRow != nullptr) { + theRow->Initialize(inTimelineItem, inSnappingListProvider); + } + } + + return theRow; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h new file mode 100644 index 00000000..d818f4cd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_STATE_ROW_FACTORY_H +#define INCLUDED_STATE_ROW_FACTORY_H 1 + +#pragma once + +class ITimelineItemBinding; +class CStateRow; +class CBaseStateRow; +class ISnappingListProvider; + +class CStateRowFactory +{ +protected: + CStateRowFactory(); + virtual ~CStateRowFactory(); + +public: + static CStateRow *CreateStateRow(ITimelineItemBinding *inTimelineItem, CBaseStateRow *inParent, + ISnappingListProvider *inSnappingListProvider); +}; +#endif // INCLUDED_STATE_ROW_FACTORY_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp new file mode 100644 index 00000000..0a0ba258 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "StateTimebarRow.h" +#include "Renderer.h" +#include "StateRow.h" +#include "StudioPreferences.h" +#include "TimebarControl.h" +#include "MasterP.h" +#include "Snapper.h" +#include "Bindings/ITimelineItemBinding.h" + +//============================================================================= +/** + * Creates a new CStateTimebarRow for the StateRow. + * @param inStateRow the State Row that this is on. + * @param inCreateTimebar true if the constructor is responsible for creating a timebar, otherwise + * the derived class will take care of the construction. + * + */ +CStateTimebarRow::CStateTimebarRow(CStateRow *inStateRow, bool inCreateTimebar /*=true*/) + : CStateTimebarlessRow(inStateRow) + , m_Timebar(nullptr) +{ + if (inCreateTimebar) { + m_Timebar = new CTimebarControl(this, inStateRow->GetTimelineItemBinding()); + m_Timebar->SetMinimumSize(CPt(0, CStudioPreferences::GetRowSize())); + + AddChild(m_Timebar); + } +} + +CStateTimebarRow::~CStateTimebarRow() +{ + delete m_Timebar; +} + +//============================================================================= +/** + * OnMouseRDown event, handles context menus for this object. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +bool CStateTimebarRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CStateTimebarlessRow::OnMouseRDown(inPoint, inFlags)) { + CPt theTimebarPoint = inPoint - m_Timebar->GetPosition(); + m_Timebar->ShowContextMenu(theTimebarPoint, false); + } + return true; +} + +//============================================================================= +/** + * Set the amount of time that is being represented per pixel. + * @param inTimerPerPixel the amound of time being represented per pixel. + */ +void CStateTimebarRow::SetTimeRatio(double inTimeRatio) +{ + CStateTimebarlessRow::SetTimeRatio(inTimeRatio); + + m_Timebar->SetTimeRatio(inTimeRatio); +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been selected. + */ +void CStateTimebarRow::OnSelect() +{ + CStateTimebarlessRow::OnSelect(); + + m_Timebar->SetSelected(true); +} + +//============================================================================= +/** + * Notification that the object that this row is representing has been deselected. + */ +void CStateTimebarRow::OnDeselect() +{ + CStateTimebarlessRow::OnDeselect(); + + m_Timebar->SetSelected(false); +} + +//============================================================================= +/** + * Notification from the Asset that it's time has changed. + * @param inStartTime the new start time. + * @param inEndTime the new end time. + */ +void CStateTimebarRow::UpdateTime(long inStartTime, long inEndTime) +{ + m_Timebar->Refresh(inStartTime, inEndTime); + Invalidate(); +} + +void CStateTimebarRow::PopulateSnappingList(CSnapper *inSnappingList) +{ + if (inSnappingList->GetSource() != m_Timebar) { + inSnappingList->AddTime(m_Timebar->GetStartTime()); + inSnappingList->AddTime(m_Timebar->GetEndTime()); + } + m_Timebar->PopulateSnappingList(inSnappingList); + CStateTimebarlessRow::PopulateSnappingList(inSnappingList); +} + +//============================================================================= +/** + * called when meta data for this row is changed... should be overridden by the + * timebar row + */ +void CStateTimebarRow::RefreshRowMetaData() +{ + Invalidate(); + m_Timebar->RefreshMetaData(); +} + +void CStateTimebarRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + m_Timebar->SetSnappingListProvider(inProvider); +} + +ISnappingListProvider &CStateTimebarRow::GetSnappingListProvider() const +{ + return m_Timebar->GetSnappingListProvider(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h new file mode 100644 index 00000000..7b62e3fd --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_STATE_TIMEBAR_ROW_H +#define INCLUDED_STATE_TIMEBAR_ROW_H 1 + +#pragma once + +#include "Control.h" +#include "StateTimebarlessRow.h" + +class CStateRow; +class CTimebarControl; +class CSnapper; +class ITimelineItemBinding; + +class CStateTimebarRow : public CStateTimebarlessRow +{ +public: + CStateTimebarRow(CStateRow *inStateRow, bool inCreateTimebar = true); + virtual ~CStateTimebarRow(); + + // CControl + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void SetTimeRatio(double inTimeRatio) override; + + void OnSelect() override; + void OnDeselect() override; + void UpdateTime(long inStartTime, long inEndTime) override; + + void PopulateSnappingList(CSnapper *inSnappingList) override; + void RefreshRowMetaData() override; + + void SetSnappingListProvider(ISnappingListProvider *inProvider); + ISnappingListProvider &GetSnappingListProvider() const override; + +protected: + CTimebarControl *m_Timebar; +}; +#endif // INCLUDED_STATE_TIMEBAR_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp new file mode 100644 index 00000000..6eebd0c4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "StateTimebarlessRow.h" +#include "IKeyframe.h" +#include "Renderer.h" +#include "StateRow.h" +#include "MasterP.h" +#include "KeyframeContextMenu.h" +#include "Snapper.h" +#include "MultiSelectAspect.h" +#include "PropertyTimebarRow.h" +#include "PropertyRow.h" +#include "AssetTimelineKeyframe.h" +#include "Bindings/ITimelineItemBinding.h" +#include "StudioUtils.h" + +//============================================================================= +/** + * Creates a new CStateTimebarRow for the StateRow. + * @param inStateRow the State Row that this is on. + */ +CStateTimebarlessRow::CStateTimebarlessRow(CStateRow *inStateRow) + : m_StateRow(inStateRow) + , m_Selected(false) + , m_Refreshing(false) +{ + m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(m_StateRow->GetObjectType()); +} + +CStateTimebarlessRow::~CStateTimebarlessRow() +{ + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + CAssetTimelineKeyframe *theDeletedKey = (*thePos); + RemoveChild(theDeletedKey); + delete theDeletedKey; + } +} + +void CStateTimebarlessRow::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation); +} + +//============================================================================= +/** + * Draws the this row background. + * @param inRenderer the renderer to draw to. + */ +void CStateTimebarlessRow::Draw(CRenderer *inRenderer) +{ + UICPROFILE(Draw); + + if (m_DirtyFlag) { + RefreshKeyframes(); + m_DirtyFlag = false; + } + + CBaseTimebarlessRow::Draw(inRenderer); +} + +//============================================================================= +/** + * OnMouseRDown event, handles context menus for this object. + * @param inPoint the location of the mouse over this control. + * @param inFlags the mouse state flags. + */ +bool CStateTimebarlessRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_StateRow->Select(SBaseStateRowSelectionKeyState()); // ensure this is selected, but doesn't + // affect any key selections, because this + // can be triggered from a key being + // selected + return CControl::OnMouseRDown(inPoint, inFlags); +} + +//============================================================================= +/** + * Set the amount of time that is being represented per pixel. + * @param inTimerPerPixel the amound of time being represented per pixel. + */ +void CStateTimebarlessRow::SetTimeRatio(double inTimeRatio) +{ + CBaseTimebarlessRow::SetTimeRatio(inTimeRatio); + + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + (*thePos)->SetTimeRatio(inTimeRatio); + } +} + +//============================================================================= +/** + * Get the state row that this belongs to. + */ +CStateRow *CStateTimebarlessRow::GetStateRow() +{ + return m_StateRow; +} + +//============================================================================= +/** + * Handler for when a child key is selected + * + * @param inTime time of the key + */ +void CStateTimebarlessRow::OnKeySelected(long inTime, bool inSelected, + bool inClearPreviouslySelectedKeys) +{ + ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding(); + if (inSelected) + theTimelineItemBinding->SetSelected(false); + + if (inClearPreviouslySelectedKeys) + theTimelineItemBinding->ClearKeySelection(); + + theTimelineItemBinding->SelectKeyframes(inSelected, inTime); + RefreshKeyframes(); + Invalidate(); +} + +CBaseStateRow *CStateTimebarlessRow::GetBaseStateRow() const +{ + return m_StateRow; +} + +//============================================================================= +/** + * Checks the data binding, instead of the property rows since they may not be created + * (delayed-loading) if this is not expanded. + */ +bool CStateTimebarlessRow::PropertiesHaveKeyframe(long inTime) +{ + bool theResult = false; + + ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding(); + long theNumProps = theTimelineItemBinding->GetPropertyCount(); + for (long theIndex = 0; theIndex < theNumProps; ++theIndex) { + ITimelineItemProperty *theProp = theTimelineItemBinding->GetProperty(theIndex); + if (theProp && theProp->GetKeyframeByTime(inTime)) { + theResult = true; + break; + } + } + return theResult; +} + +//============================================================================= +/** + * called when keyframes need to be updated, this funciton has two loops: + * the first loops through and deletes any keys no longer in the sskf list. the + * second adds any keys in the sskf list that are not already in the list + * + */ +void CStateTimebarlessRow::RefreshKeyframes() +{ + UICPROFILE(RefreshKeyframes); + + m_Refreshing = true; + + ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding(); + long theKeyframeCount = theTimelineItemBinding->GetKeyframeCount(); + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + + // First Loop clears any keys that do not correlate to a supersetkey + while (thePos != m_Keyframes.end()) { + CAssetTimelineKeyframe *theTimelineKey = (*thePos); + IKeyframe *theTempKey = nullptr; + theTempKey = theTimelineItemBinding->GetKeyframeByTime(theTimelineKey->GetTime()); + + // If we find a key at this time, then the timeline key doesn't need to be deleted + if (!theTempKey || !PropertiesHaveKeyframe(theTimelineKey->GetTime())) { + RemoveChild(theTimelineKey); + delete theTimelineKey; + thePos = m_Keyframes.erase(thePos); + } else if (theTempKey->IsDynamic() != theTimelineKey->IsDynamic()) { + theTimelineKey->SetDynamic(theTempKey->IsDynamic()); + } else { + // Set the position + theTimelineKey->SetPosition(::TimeToPos(theTempKey->GetTime(), m_TimeRatio) + - (theTimelineKey->GetSize().x / 2), + 0); + ++thePos; + } + } + + // Second Loop adds the remaining keys + for (long theKey = 0; theKey < theKeyframeCount; ++theKey) { + bool theFoundFlag = false; + IKeyframe *theTempKey = theTimelineItemBinding->GetKeyframeByIndex(theKey); + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + + // each key needs to be compared to all the keys in the sskf list to see if it has to be + // added. + for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) { + CAssetTimelineKeyframe *theCurrentKey = (*thePos); + if (theCurrentKey->GetTime() == theTempKey->GetTime()) { + theFoundFlag = true; + } + } + if (!theFoundFlag && PropertiesHaveKeyframe(theTempKey->GetTime())) { + // If we don't have a timeline key, then we have to make a new one + CAssetTimelineKeyframe *theAssetTimelineKey = + new CAssetTimelineKeyframe(this, m_TimeRatio); + theAssetTimelineKey->SetTime(theTempKey->GetTime()); + theAssetTimelineKey->Select(theTempKey->IsSelected()); + theAssetTimelineKey->SetDynamic(theTempKey->IsDynamic()); + theAssetTimelineKey->SetSize(CPt(17, 16)); + theAssetTimelineKey->SetPosition(::TimeToPos(theTempKey->GetTime(), m_TimeRatio) + - (theAssetTimelineKey->GetSize().x / 2), + 0); + AddChild(theAssetTimelineKey); + m_Keyframes.push_back(theAssetTimelineKey); + } + } + m_Refreshing = false; +} + +void CStateTimebarlessRow::Invalidate(bool inInvalidate) +{ + if (!m_Refreshing) { + CControl::Invalidate(inInvalidate); + } +} + +//============================================================================= +/** + * called when a list has a member change selection + * @param inTime -1 to affect all keyframes. + * + */ +void CStateTimebarlessRow::SelectKeysByTime(long inTime, bool inSelected) +{ + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + bool theFoundFlag = false; + for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) { + CAssetTimelineKeyframe *theKey = (*thePos); + if (inTime == -1 || theKey->GetTime() == inTime) { + theKey->Select(inSelected); + theFoundFlag = (inTime != -1); + } + } + Invalidate(); +} + +//============================================================================= +/** + * SelectKeysInRect: selects any keyframes inside the rect + * + * @param inRect the Rect to select the keyframes in + * @return NONE. + */ +void CStateTimebarlessRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown) +{ + CMultiSelectAspect<TTimelineAssetKeyframeList> theMultiSelectAspect( + m_Keyframes, m_StateRow->GetTimelineItemBinding()); + theMultiSelectAspect.MultiSelect(inRect, inModifierKeyDown); +} + +//============================================================================= +/** + * CommitSelections: commits all the master keyframe selections by setting their + * previous selection state to the current selection state. + * This will prevent the current keyframe states from + *changing. + * + * @param NONE + * @return NONE + */ + +void CStateTimebarlessRow::CommitSelections() +{ + CMultiSelectAspect<TTimelineAssetKeyframeList> theMultiSelectAspect( + m_Keyframes, m_StateRow->GetTimelineItemBinding()); + theMultiSelectAspect.CommitSelections(); +} + +//============================================================================= +/** + * true if there are selected keys on this object + */ +bool CStateTimebarlessRow::HasSelectedKeys() +{ + bool theRetVal = false; + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end() && !theRetVal; ++thePos) { + if ((*thePos)->IsSelected()) { + theRetVal = true; + } + } + return theRetVal; +} + +//============================================================================= +/** + * selects all keys for this timebar row + */ +void CStateTimebarlessRow::SelectAllKeys() +{ + m_StateRow->GetTimelineItemBinding()->SelectKeyframes(true, -1); + + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) + (*thePos)->Select(true); + + Invalidate(); +} + +//============================================================================= +/** + * Populates the snapping list with any snapping points that may be on this. + * This will add the timebar ends, master keyframes to the snapping list, and + * time labels to the snapping list. + * @param inSnapper the snapper to add the points to. + */ +void CStateTimebarlessRow::PopulateSnappingList(CSnapper *inSnapper) +{ + // Only add points if this is not the object originating the snapping. + if (inSnapper->GetSource() != this) { + // Add Keyframes + TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin(); + for (; thePos != m_Keyframes.end(); ++thePos) { + if (inSnapper->IsSnappingSelectedKeyframes()) + inSnapper->AddTime((*thePos)->GetTime()); + else if (!(*thePos)->IsSelected()) + inSnapper->AddTime((*thePos)->GetTime()); + } + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h new file mode 100644 index 00000000..1812e365 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_STATE_TIMEBARLESS_ROW_H +#define INCLUDED_STATE_TIMEBARLESS_ROW_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "BaseTimebarlessRow.h" +#include "DispatchListeners.h" + +//============================================================================== +// Forwards +//============================================================================== +class CStateRow; +class CSnapper; +class CAssetTimelineKeyframe; +class ITimelineItemBinding; + +class CStateTimebarlessRow : public CBaseTimebarlessRow +{ + typedef std::vector<CAssetTimelineKeyframe *> TTimelineAssetKeyframeList; + +public: + CStateTimebarlessRow(CStateRow *inStateRow); + virtual ~CStateTimebarlessRow(); + + void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override; + void Draw(CRenderer *inRenderer) override; + + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void OnKeySelected(long inTime, bool inState, bool inClearPreviouslySelectedKeys); + + void SetTimeRatio(double inTimeRatio) override; + + virtual void RefreshKeyframes(); + void Invalidate(bool inInvalidate = true) override; + void CommitSelections() override; + void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) override; + void SelectAllKeys() override; + void SelectKeysByTime(long inTime, bool inSelected) override; + bool HasSelectedKeys(); + CStateRow *GetStateRow(); + void PopulateSnappingList(CSnapper *inSnapper) override; + +protected: + CBaseStateRow *GetBaseStateRow() const override; + bool PropertiesHaveKeyframe(long inTime); + +protected: + CStateRow *m_StateRow; + bool m_Selected; + TTimelineAssetKeyframeList m_Keyframes; ///<Master Keyframe list ( STL ) + bool m_Refreshing; +}; +#endif // INCLUDED_STATE_TIMEBARLESS_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp new file mode 100644 index 00000000..5ef32619 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ +//============================================================================== +// Includes +//============================================================================== +#include "stdafx.h" +#include "TimeEditAspect.h" + +//============================================================================= +/** + * Constructor + */ +CTimeEditAspect::CTimeEditAspect() +{ +} + +//============================================================================= +/** + * Destructor + */ +CTimeEditAspect::~CTimeEditAspect() +{ +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h new file mode 100644 index 00000000..f8cf0599 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_TIME_EDIT_ASPECT_H +#define INCLUDED_TIME_EDIT_ASPECT_H 1 + +#pragma once +//============================================================================== +// Prefix +//============================================================================== + +//============================================================================== +/** + * @class CTimeEditAspect: It contains cross-platform codes that handles the Time Edit + * processing for the the time edit dialog box in Mac and Win + */ +//============================================================================== +class CTimeEditAspect +{ +protected: +public: + CTimeEditAspect(); + ~CTimeEditAspect(); +}; +#endif // INCLUDED_TIME_EDIT_ASPECT_H
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp new file mode 100644 index 00000000..9735499a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "TimeMeasure.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" +#include "TimelineTimelineLayout.h" +#include "Snapper.h" +#include "UICDMSignals.h" + +const long AUTO_TICK_AMNT = 60; +using namespace Q3DStudio; + +//============================================================================= +/** + * Create a new time measure. + * @param inLayout the layout this is representing, used for modifying time. + * @param inTimeRatio the current time ratio. + * @param inIsTransparent true if the background of this control should not be drawn. + */ +CTimeMeasure::CTimeMeasure(CTimelineTimelineLayout *inLayout, double inTimeRatio, + bool inFillBackground /*= true */) + : CBaseMeasure(inTimeRatio, inFillBackground) + , m_ScrollDir(0) + , m_TimePerPixel(0) + , m_IsMouseDown(false) + , m_TimelineLayout(inLayout) +{ + SetTimeRatio(inTimeRatio); + SetName("TimeMeasure"); + + m_EdgeMargin = 2; + // the large tickmark is shorter than the medium to leave room for the text + m_LargeHashOffset = 5; +} + +CTimeMeasure::~CTimeMeasure() +{ +} + +//============================================================================= +/** + * Set the amount of time that is represented for each pixel. + * @param inTimePerPixel the amount of time represented for each pixel. + */ +void CTimeMeasure::SetTimeRatio(double inTimeRatio) +{ + m_Ratio = inTimeRatio; + + double theTimePerPixel = (double)(1 / inTimeRatio); + + // Only go through this if it has actually changed + if (theTimePerPixel != m_TimePerPixel) { + m_TimePerPixel = theTimePerPixel; + + // Go through the possible hash settings and find the one that best suits the + // time per pixel. + double theMillisPerLargeHash = theTimePerPixel * 50; + if (theMillisPerLargeHash <= 100) // 100ms + theMillisPerLargeHash = 100; + else if (theMillisPerLargeHash <= 200) // 200ms + theMillisPerLargeHash = 200; + else if (theMillisPerLargeHash <= 500) // .5s + theMillisPerLargeHash = 500; + else if (theMillisPerLargeHash <= 1000) // 1s + theMillisPerLargeHash = 1000; + else if (theMillisPerLargeHash <= 2000) // 2s + theMillisPerLargeHash = 2000; + else if (theMillisPerLargeHash <= 5000) // 5s + theMillisPerLargeHash = 5000; + else if (theMillisPerLargeHash <= 10000) // 10s + theMillisPerLargeHash = 10000; + else if (theMillisPerLargeHash <= 20000) // 20s + theMillisPerLargeHash = 20000; + else if (theMillisPerLargeHash <= 30000) // 30s + theMillisPerLargeHash = 30000; + else if (theMillisPerLargeHash <= 60000) // 1m + theMillisPerLargeHash = 60000; + else if (theMillisPerLargeHash <= 120000) // 2m + theMillisPerLargeHash = 120000; + else if (theMillisPerLargeHash <= 300000) // 5m + theMillisPerLargeHash = 300000; + else if (theMillisPerLargeHash <= 600000) // 10m + theMillisPerLargeHash = 600000; + else if (theMillisPerLargeHash <= 1200000) // 20m + theMillisPerLargeHash = 1200000; + else if (theMillisPerLargeHash <= 1800000) // 30m + theMillisPerLargeHash = 1800000; + else if (theMillisPerLargeHash <= 3600000) // 1h + theMillisPerLargeHash = 3600000; + else + theMillisPerLargeHash = 7200000; // 2h + + // Set the distances between the hashes + m_LargeHashInterval = theMillisPerLargeHash; + m_MediumHashInterval = theMillisPerLargeHash / 2; + m_SmallHashInterval = theMillisPerLargeHash / 10; + + // update to StudioPreferences so that the ',' '.' and '<' '>' keys would respond + // accordingly + CStudioPreferences::SetTimeAdvanceAmount(static_cast<long>(m_SmallHashInterval)); + CStudioPreferences::SetBigTimeAdvanceAmount(static_cast<long>(m_MediumHashInterval)); + + Invalidate(); + } +} +//============================================================================= +/** + * Get the time formatted as a string. + * This will figure out the best way to display the time and return it as a + * string. + * @param inTime the time to display in milliseconds. + * @return the time formatted in a string. + */ +Q3DStudio::CString CTimeMeasure::FormatTime(long inTime) +{ + long theHours = inTime / 3600000; + long theMinutes = inTime % 3600000 / 60000; + long theSeconds = inTime % 60000 / 1000; + long theMillis = inTime % 1000; + + bool theHoursOnlyFlag = theHours != 0 && theMinutes == 0 && theSeconds == 0 && theMillis == 0; + bool theMinutesOnlyFlag = + !theHoursOnlyFlag && theMinutes != 0 && theSeconds == 0 && theMillis == 0; + bool theSecondsOnlyFlag = !theMinutesOnlyFlag && theMillis == 0; + + Q3DStudio::CString theTime; + // If only hours are being displayed then format it as hours. + if (theHoursOnlyFlag) { + theTime.Format(_UIC("%dh"), theHours); + } + // If only minutes are being displayed then format it as minutes. + else if (theMinutesOnlyFlag) { + theTime.Format(_UIC("%dm"), theMinutes); + } + // If only seconds are being displayed then format as seconds + else if (theSecondsOnlyFlag) { + theTime.Format(_UIC("%ds"), theSeconds); + } + // If the intervals are correct then this should only be tenths of seconds, so do that. + else { + theTime.Format(_UIC("0.%ds"), theMillis / 100); + } + + return theTime; +} + +//============================================================================= +/** + * Set the amount of time that this time measure is offset by. + * @param inTimeOffset the offset time in milliseconds. + */ +void CTimeMeasure::SetTimeOffset(long inTimeOffset) +{ + if (inTimeOffset != m_Offset) { + m_Offset = inTimeOffset; + + Invalidate(); + } +} + +//============================================================================= +/** + * Notification that the left mouse button was clicked. + * This tells the timeline to move the playhead to the current loc. + * @param inPoint the location where the mouse was clicked. + * @param inFlags the state of the mouse. + */ +bool CTimeMeasure::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_IsMouseDown = true; + + m_TimelineLayout->OnTimeMeasureMouseDown(inPoint, inFlags); + } + + return true; +} + +//============================================================================= +/** + * Notification that the mouse is moving over this control. + * If the mouse was clicked on this control this will drag the playhead. + * @param inPoint the location where the mouse was clicked. + * @param inFlags the state of the mouse. + */ +void CTimeMeasure::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>(); + + // subtract out the button width since the playhead is never allowed into that area on the right + // side + // of the timeline and use it for the initial autoscrolling place + if (inPoint.x > 0 && inPoint.x <= GetSize().x - CStudioPreferences::GetDefaultButtonWidth()) { + CControl::OnMouseMove(inPoint, inFlags); + if (m_IsMouseDown) + m_TimelineLayout->OnTimeMeasureMouseDown(inPoint, inFlags); + m_ScrollDir = 0; + } else if (m_IsMouseDown) { + if (inPoint.x < 0) + m_ScrollDir = -1; + else if (inPoint.x > GetSize().x - CStudioPreferences::GetDefaultButtonWidth()) + m_ScrollDir = 1; + m_TimerConnection = ITickTock::GetInstance().AddTimer( + 150, true, std::bind(&CTimeMeasure::OnTimer, this), "CTimeMeasure::OnMouseMove"); + OnTimer(); + } +} + +//============================================================================= +/** + * Call back for the timer that was set in on mouse move + */ +void CTimeMeasure::OnTimer() +{ + CPt theOffset; + if (m_ScrollDir > 0) + theOffset.x = + GetSize().x - 2 * CStudioPreferences::GetDefaultButtonWidth() + AUTO_TICK_AMNT; + else if (m_ScrollDir < 0) + theOffset.x = -AUTO_TICK_AMNT; + m_TimelineLayout->OnTimeMeasureMouseDown(theOffset, 0); + ; +} + +//============================================================================= +/** + * Notification that the mouse was unclicked. + * This stops dragging of the playhead if it was dragging it. + * @param inPoint the location where the mouse was unclicked. + * @param inFlags the state of the mouse. + */ +void CTimeMeasure::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>(); + m_IsMouseDown = false; +} + +//============================================================================= +/** + * Notification that the mouse was unclicked. + * This stops dragging of the playhead if it was dragging it. + * @param inPoint the location where the mouse was unclicked. + * @param inFlags the state of the mouse. + */ +void CTimeMeasure::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>(); + m_IsMouseDown = false; +} + +//============================================================================= +/** + * Add the tick marks to the snapping list. + * This uses the user preference for the tick marks and adds them. + */ +void CTimeMeasure::PopulateSnappingList(CSnapper *inSnapper) +{ + // Only if this is supposed to snap to time markers. + if (CStudioPreferences::IsTimelineSnappingGridActive()) { + // Check the resolution to snap to + ESnapGridResolution theResolution = CStudioPreferences::GetTimelineSnappingGridResolution(); + double thePeriodicInterval; + if (theResolution == SNAPGRID_TICKMARKS) { + thePeriodicInterval = m_SmallHashInterval; + } else if (theResolution == SNAPGRID_HALFSECONDS) { + thePeriodicInterval = m_MediumHashInterval; + } else { + thePeriodicInterval = m_LargeHashInterval; + } + + // Set a periodic interval for snapping + inSnapper->SetPeriodicInterval(::dtol(thePeriodicInterval)); + } +} + +void CTimeMeasure::OnLoseFocus() +{ + m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>(); + m_IsMouseDown = false; +} + +//============================================================================= +/** + * Draw the time at the specified position. + * @param inRenderer the renderer to draw to. + * @param inPosition the position to draw the time to, the time will be centered here. + * @param inTime the time to draw. + */ +void CTimeMeasure::DrawMeasureText(CRenderer *inRenderer, long inPosition, long inMeasure) +{ + Q3DStudio::CString theTimeFormat(FormatTime(inMeasure)); + // Offset the position by half the text size to center it over the hash. + const auto textSize = inRenderer->GetTextSize(theTimeFormat.toQString()); + inPosition -= ::dtol(textSize.width() / 2); + + inRenderer->DrawText((float)inPosition, -3, theTimeFormat.toQString(), + QRect(0, 0, GetSize().x, GetSize().y), + CStudioPreferences::GetRulerTickColor().getQColor()); +} + +//============================================================================= +/** + * Calculate the position of a time value on the time measure + */ +long CTimeMeasure::CalculatePos(double inNewValue) +{ + return ::TimeToPos(inNewValue, m_Ratio); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h new file mode 100644 index 00000000..7e72a52c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIME_MEASURE_H +#define INCLUDED_TIME_MEASURE_H 1 + +#pragma once + +#include "BaseMeasure.h" +#include "ITickTock.h" + +class CTimelineTimelineLayout; +class CSnapper; + +class CTimeMeasure : public CBaseMeasure +{ +public: + CTimeMeasure(CTimelineTimelineLayout *inLayout, double inTimeRatio, + bool inFillBackground = true); + virtual ~CTimeMeasure(); + + void SetTimeRatio(double inTimeRatio); + void SetTimeOffset(long inTimeOffset); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + void PopulateSnappingList(CSnapper *inSnapper); + + virtual void OnTimer(); + void OnLoseFocus() override; + +protected: + // CBaseMeasure + void DrawMeasureText(CRenderer *inRenderer, long inPosition, long inMeasure) override; + long CalculatePos(double inNewValue) override; + + Q3DStudio::CString FormatTime(long inTime); + + long m_ScrollDir; + double m_TimePerPixel; + bool m_IsMouseDown; + CTimelineTimelineLayout *m_TimelineLayout; + std::shared_ptr<UICDM::ISignalConnection> m_TimerConnection; +}; +#endif // INCLUDED_TIME_MEASURE_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp new file mode 100644 index 00000000..639e61d2 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "TimeToolbar.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "BlankControl.h" +#include "IDoc.h" + +//============================================================================= +/** + * Constructor + */ +CTimeToolbar::CTimeToolbar(IDoc *inDoc) +{ + m_Doc = inDoc; + m_TimeEdit = new CTimeEdit(inDoc); + m_Color = CStudioPreferences::GetBaseColor(); + m_TimeEdit->SetBackgroundColor(m_Color); + AddChild(m_TimeEdit); + + m_TimeEdit->AddTimeChangeListener(this); +} + +//============================================================================= +/** + * Destructor + */ +CTimeToolbar::~CTimeToolbar() +{ + delete m_TimeEdit; +} + +//============================================================================= +/** + * Fills in the background color for this layout. + */ +void CTimeToolbar::Draw(CRenderer *inRenderer) +{ + // Fill in the background color and draw the child controls + + // Draw the shadow lines at the top and bottom of the layout + CRct theRect(GetSize()); + inRenderer->FillSolidRect(theRect, m_Color); + + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(theRect.size.x, 0)); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theRect.size.y - 2)); + inRenderer->MoveTo(CPt(0, theRect.size.y - 2)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 2)); + inRenderer->PopPen(); + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y - 1)); + inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Override of Control's set size to reposition the TimeEdit. + * @param inSize the new size. + */ +void CTimeToolbar::SetSize(CPt inSize) +{ + m_TimeEdit->SetSize(CPt(m_TimeEdit->GetWidth(), inSize.y - 4)); + m_TimeEdit->SetPosition(inSize.x - m_TimeEdit->GetWidth(), 2); + + CControl::SetSize(inSize); +} + +//============================================================================= +/** + * Call from the TimelineView (or thereabouts) that the scene time changed. + * @param inTime the new time. + */ +void CTimeToolbar::SetTime(long inTime) +{ + m_TimeEdit->SetTime(inTime); +} +//============================================================================= +/** + * Returns the playhead time + */ +long CTimeToolbar::GetTime() +{ + return m_TimeEdit->GetTime(); +} + +//============================================================================= +/** + * Callback from the TimeEdit that it's time was manually changed. + * @param inNewTime the new time. + */ +void CTimeToolbar::OnTimeChanged(long inNewTime) +{ + m_Doc->NotifyTimeChanged(inNewTime); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h new file mode 100644 index 00000000..c1ed948d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#ifndef INCLUDED_TIME_TOOLBAR_H +#define INCLUDED_TIME_TOOLBAR_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "TimeEdit.h" +#include "Control.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class IDoc; + +//============================================================================= +/** + * Control at the top of the time display and a header for the toggle column. + */ +class CTimeToolbar : public CControl, public CTimeEditChangeListener +{ +public: + CTimeToolbar(IDoc *inDoc); + virtual ~CTimeToolbar(); + void Draw(CRenderer *inRenderer) override; + + void SetSize(CPt inSize) override; + void SetTime(long inTime); + virtual long GetTime(); + + void OnTimeChanged(long inNewTime) override; + +protected: + CTimeEdit *m_TimeEdit; + IDoc *m_Doc; + CColor m_Color; +}; + +#endif // INCLUDED_TIME_TOOLBAR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp new file mode 100644 index 00000000..af0084aa --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp @@ -0,0 +1,690 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "TimebarControl.h" +#include "StateTimebarRow.h" +#include "StateRow.h" +#include "Renderer.h" +#include "ColorControl.h" +#include "StudioPreferences.h" +#include "Views.h" +#include "TimelineControl.h" +#include "TimelineTimelineLayout.h" +#include "ResourceCache.h" +#include "HotKeys.h" +#include "Preferences.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/ITimelineTimebar.h" +#include "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "CoreUtils.h" +#include "StudioUtils.h" +#include "MasterP.h" + +const float SCALING_FACTOR = 0.50; + +//============================================================================= +/** + * Create a timebar control on the specified state timebar row. + * Attaches a new ToolTip to it that displays the time range this timebar control + * encompasses. + * @param inRow the row on which this timebar is attached. + */ +CTimebarControl::CTimebarControl(CStateTimebarRow *inRow, + ITimelineItemBinding *inTimelineItemBinding) + : m_IsSelected(false) + , m_IsMouseDown(false) + , m_MaybeDragStart(false) + , m_LeftLeftTip(this, true) + , m_LeftTip(this, true) + , m_RightTip(this, false) + , m_RightRightTip(this, false) + , m_SnappingListProvider(nullptr) +{ + m_TimebarRow = inRow; + m_TimelineItemBinding = inTimelineItemBinding; + // Start/End times + ITimelineTimebar *theTimelineTimebar = GetTimebar(); + m_StartTime = theTimelineTimebar->GetStartTime(); + m_EndTime = theTimelineTimebar->GetEndTime(); + bool theShowHandleBars = theTimelineTimebar->ShowHandleBars(); + m_LeftLeftTip.ShowHandles(theShowHandleBars); + m_RightRightTip.ShowHandles(theShowHandleBars); + + m_LeftLeftTip.SetSize(CStudioPreferences::GetTimebarTipSize(), + CStudioPreferences::GetRowSize()); + m_LeftTip.SetPosition(CPt(0, 0)); + m_LeftTip.SetSize(CStudioPreferences::GetTimebarInnerTipSize(), + CStudioPreferences::GetRowSize()); + m_LeftTip.SetPosition(CPt(m_LeftLeftTip.GetSize().x, 0)); + + m_RightTip.SetSize(CStudioPreferences::GetTimebarInnerTipSize(), + CStudioPreferences::GetRowSize()); + m_RightRightTip.SetSize(CStudioPreferences::GetTimebarTipSize(), + CStudioPreferences::GetRowSize()); + + m_EditControl = new CCommentEdit(theTimelineTimebar); + m_EditControl->SetPosition(CStudioPreferences::GetTimebarTipSize() * 2, 1); + m_EditControl->SetSize(CPt(100, 15)); + m_EditControl->SetFillBackground(false); + AddChild(m_EditControl); + AddChild(&m_LeftTip); + AddChild(&m_RightTip); + AddChild(&m_RightRightTip); + AddChild(&m_LeftLeftTip); +} + +//============================================================================= +/** + * Destructor + */ +CTimebarControl::~CTimebarControl() +{ + delete m_EditControl; +} + +//============================================================================= +/** + * Draw this timebar control to the renderer. + * @param inRenderer the renderer to draw to. + */ +void CTimebarControl::Draw(CRenderer *inRenderer) +{ + CStateRow *theRow = m_TimebarRow->GetStateRow(); + CRct theRect(GetSize()); + + ::CColor theNormalColor = GetTimebar()->GetTimebarColor(); + ::CColor theSelectedColor = CColorControl::CalculateSelectedColor(theNormalColor); + + ::CColor theBorderColor = CStudioPreferences::GetTimeBarBorderColor(); + ::CColor theDarkExtendedColor = CStudioPreferences::GetExtendedObjectDarkColor(); + ::CColor theLightExtendedColor = CStudioPreferences::GetExtendedObjectLightColor(); + + long theTipOffset = CStudioPreferences::GetTimebarTipSize(); + + if (!IsEnabled()) { + theNormalColor = CStudioPreferences::GetLockedTimebarColor(); + theBorderColor = CStudioPreferences::GetLockedBorderColor(); + theDarkExtendedColor = CStudioPreferences::GetExtendedLockedDarkColor(); + theLightExtendedColor = CStudioPreferences::GetExtendedLockedLightColor(); + } + + // Calculate the start/end/activestart + long theObjectLifeStart = ::TimeToPos(m_StartTime, m_TimeRatio); + long theStartPos = ::TimeToPos(theRow->GetActiveStart(), m_TimeRatio) - theObjectLifeStart; + long theEndPos = ::TimeToPos(theRow->GetActiveEnd(), m_TimeRatio) - theObjectLifeStart; + long theObjectLifeEnd = ::TimeToPos(m_EndTime, m_TimeRatio) - theObjectLifeStart; + + CRct theGradientRct(theStartPos + theTipOffset, 0, theEndPos - theStartPos, theRect.size.y - 1); + + if (theEndPos > theStartPos) { + inRenderer->DrawGradientBitmap(theGradientRct, theNormalColor, 0, SCALING_FACTOR); + // Calculate the gradient rect a bit differently depending on selection + if (m_IsSelected) { + CRct theSelectedRct(CPt(theGradientRct.position.x, theGradientRct.position.y + 3), + CPt(theGradientRct.size.x, theGradientRct.size.y - 7)); + inRenderer->FillSolidRect(theSelectedRct, theSelectedColor); + } + } + + inRenderer->PushPen(theBorderColor); + // Check to see if we need some hashes at the end + if (theObjectLifeEnd > theEndPos) { + long theUpdatedStartTime = theEndPos; + if (theStartPos > theUpdatedStartTime) + theUpdatedStartTime = theStartPos; + else { + inRenderer->MoveTo(theEndPos + theTipOffset, 0); + inRenderer->LineTo(theEndPos + theTipOffset, theRect.size.y - 1); + } + CRct theClippingRect(CPt(theUpdatedStartTime + theTipOffset + 1, 0), + CPt(theObjectLifeEnd - theUpdatedStartTime - 1, theRect.size.y - 1)); + inRenderer->PushClippingRect(theClippingRect); + + // Draw the hashed background + DrawHashedBackgroundX(inRenderer, theDarkExtendedColor, theLightExtendedColor, + theClippingRect); + inRenderer->PopClippingRect(); + } + + // Check to see if we need some hashes at the beginning + if (theStartPos > 0) { + long theUpdatedEndTime = theStartPos; + if (theObjectLifeEnd < theUpdatedEndTime) + theUpdatedEndTime = theObjectLifeEnd; + else { + inRenderer->MoveTo(theStartPos + theTipOffset, 0); + inRenderer->LineTo(theStartPos + theTipOffset, theRect.size.y - 1); + } + CRct theClippingRect(CPt(theTipOffset, 0), CPt(theUpdatedEndTime, theRect.size.y - 1)); + inRenderer->PushClippingRect(theClippingRect); + + // Draw the hashed background + DrawHashedBackgroundX(inRenderer, theDarkExtendedColor, theLightExtendedColor, + theClippingRect); + inRenderer->PopClippingRect(); + } + + // Draw the border stuff + inRenderer->MoveTo(CPt(theTipOffset, 0)); + inRenderer->LineTo(CPt(theTipOffset, theRect.size.y - 1)); + inRenderer->MoveTo(CPt(theObjectLifeEnd + theTipOffset, 0)); + inRenderer->LineTo(CPt(theObjectLifeEnd + theTipOffset, theRect.size.y - 1)); + + inRenderer->PopPen(); + // Setting the position with the active time + m_EditControl->SetPosition(CStudioPreferences::GetTimebarTipSize() * 2, 1); +} + +//============================================================================= +/** + * Draws a hashed background in a given clipping rect + * + * @param inStartX the x position to start from + * @param inSizeY the y size the you want the lines to range from + * @param inEndX one after the last place where lines can be drawn from + * @inRenderer the renderer to draw to + * @param inFirstColor the first hash color + * @param inSecondColor the second hash color + * @para inRect the clipping rect + */ +void CTimebarControl::DrawHashedBackgroundX(CRenderer *inRenderer, ::CColor inFirstColor, + ::CColor inSecondColor, CRct inRect) +{ + inRenderer->FillSolidRect(inRect, inFirstColor); + if (m_IsSelected) { + CRct theSelectedRct(CPt(inRect.position.x, inRect.position.y + 4), + CPt(inRect.size.x, inRect.size.y - 8)); + inRenderer->FillSolidRect( + theSelectedRct, CColorControl::CalculateSelectedColor(GetTimebar()->GetTimebarColor())); + } + + inRenderer->FillHashed(inRect, inSecondColor); +} + +//============================================================================= +/** + * Set the current time ratio. + * The time ratio controls the length of this control and is the ratio of + * pixels to milliseconds. + * @param inTimeRatio the new time ratio. + */ +void CTimebarControl::SetTimeRatio(double inTimeRatio) +{ + m_TimeRatio = inTimeRatio; + + Refresh(); +} + +//============================================================================= +/** + * Set the size of this control. + * @param inSize the new size of this control. + */ +void CTimebarControl::SetSize(CPt inSize) +{ + CControl::SetSize(CPt(inSize.x, inSize.y)); + + CStateRow *theRow = m_TimebarRow->GetStateRow(); + long theTipSize = + CStudioPreferences::GetTimebarTipSize() + CStudioPreferences::GetTimebarInnerTipSize(); + long theCommentSize = CStudioPreferences::GetDefaultCommentSize(); + if (inSize.x < theCommentSize) + theCommentSize = inSize.x; + + // Recalculate the comment size depending on where the timebar is and how large it is + long theDiff = ::dtol((theRow->GetActiveEnd() - theRow->GetActiveStart()) * m_TimeRatio); + if (theDiff < theCommentSize) { + theCommentSize = theDiff - theTipSize; + if (theCommentSize < 0) + theCommentSize = 0; + } + + m_EditControl->SetSize(CPt(theCommentSize, 15)); + + // Set the two right tips depending on where the right side is + m_RightTip.SetPosition(CPt(inSize.x - theTipSize, 0)); + m_RightRightTip.SetPosition(CPt(inSize.x - m_RightRightTip.GetSize().x + 1, 0)); +} + +//============================================================================= +/** + * Set whether this control is selected or not. + * If this is selected then it will modify how this control looks. + * @param inIsSelected true if this control is to be selected. + */ +void CTimebarControl::SetSelected(bool inIsSelected) +{ + if (inIsSelected != m_IsSelected) { + m_IsSelected = inIsSelected; + m_EditControl->SetSelected(m_IsSelected); + Invalidate(); + } +} + +void CTimebarControl::RefreshMetaData() +{ + m_EditControl->RefreshMetaData(); +} + +//============================================================================= +/** + * Request for this control to refresh it's properties. + * This checks the size of the asset and adjusts it's size the the asset's + * length. Called when the time ratio or properties have changed. + * If the time has changed then Refresh( long, long ) must be called with the + * new times. + */ +void CTimebarControl::Refresh() +{ + Refresh(m_StartTime, m_EndTime); +} + +//============================================================================= +/** + * Request for this control to refresh it's properties. + * This updates all the properties of this control and resize it as necessary. + * Called when the time changes on the asset, the time ratio changes or any + * properties that this displays change. + * @param inStartTime the asset's start time. + * @param inEndTime the asset's end time. + */ +void CTimebarControl::Refresh(long inStartTime, long inEndTime) +{ + m_StartTime = inStartTime; + m_EndTime = inEndTime; + + long thePosition = ::TimeToPos(inStartTime, m_TimeRatio); + long theSize = ::dtol((inEndTime - inStartTime) * m_TimeRatio); + + SetPosition(thePosition - CStudioPreferences::GetTimebarTipSize(), GetPosition().y); + + SetSize(CPt(theSize + 2 * CStudioPreferences::GetTimebarTipSize(), GetMinimumSize().y)); + if (IsInvalidated()) + m_TimebarRow->Invalidate(); +} + +//============================================================================= +/** + * Get the interface to the timebar item in the data model + */ +ITimelineTimebar *CTimebarControl::GetTimebar() +{ + return m_TimelineItemBinding->GetTimelineItem()->GetTimebar(); +} + +//============================================================================= +/** +* Updates the ToolTip and moves it to the correct place on screen. +* @param inPoint the point that the tooltip is supposed to be placed. +*/ +void CTimebarControl::RefreshToolTip(CPt inPoint) +{ + Q3DStudio::CString theCommentText; + CStateRow *theRow = m_TimebarRow->GetStateRow(); + + CRct theTimelineBounds(GetTopControlBounds()); + // format label as: startTime - endTime (timeDifference) + theCommentText = " " + FormatTimeString(theRow->GetStartTime()) + " - " + + FormatTimeString(theRow->GetEndTime()) + " (" + + FormatTimeString(theRow->GetEndTime() - theRow->GetStartTime()) + ")"; + inPoint.y = GetPosition().y - GetSize().y; + ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds); +} + +//============================================================================= +/** + * OnMouseDoubleClick: Pop up a dialog box for the editing of the timebar start + * and end time. + */ +bool CTimebarControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDoubleClick(inPoint, inFlags) + && !m_TimelineItemBinding->IsLockedEnabled()) { + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.ShowDialog(m_StartTime, m_EndTime, g_StudioApp.GetCore()->GetDoc(), TIMEBAR, + this); + } + + return true; +} + +//============================================================================= +/** + * Allows this timebar control to add any times it wishes to the snapper list + * @param inSnapper the Snapper that is handling the snapping functions for this timebar + */ +void CTimebarControl::PopulateSnappingList(CSnapper *inSnapper) +{ + Q_UNUSED(inSnapper); +} + +//============================================================================= +/** + * Start drag handler, puts this control into drag mode. + * @param inPoint the point where the mouse was clicked. + * @param inFlags the mouse state. + */ +bool CTimebarControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_IsMouseDown = true; + m_MaybeDragStart = true; + m_MouseDownLoc = inPoint; + + OnBeginDrag(); + + m_TimebarRow->GetStateRow()->Select(SBaseStateRowSelectionKeyState()); + + m_Snapper.Clear(); + m_Snapper.SetSource(this); + + GetSnappingListProvider().PopulateSnappingList(&m_Snapper); + m_Snapper.BeginDrag(inPoint.x); + + if (HasFocus(m_EditControl) && !m_EditControl->HitTest(inPoint)) { + m_EditControl->OnLoseFocus(); + } + + // display the time range tooltip + RefreshToolTip(inPoint); + } + return true; +} + +//============================================================================= +/** + * Puts up the context menu. + * @param inPoint the point where the mouse was clicked. + * @param inFlags the mouse state. + */ +bool CTimebarControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseRDown(inPoint, inFlags)) { + if (m_IsMouseDown) { + m_IsMouseDown = false; + CommitTimeChange(); + HideMoveableWindow(); + } + // only right-clicking ON the timebar will show the timebar (text and color) properties' + // options + ShowContextMenu(inPoint, true); + } + + return true; +} + +//============================================================================= +/** + * Notification that the drag has finished. + * @param inPoint the point where the mouse was let go. + * @param inFlags the state of the mouse. + */ +void CTimebarControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // try to prevent stuck mousetips on exceptions + try { + CControl::OnMouseUp(inPoint, inFlags); + CommitTimeChange(); + } catch (...) { + } + m_IsMouseDown = false; + m_MaybeDragStart = false; + HideMoveableWindow(); +} + +//============================================================================= +/** + * Handler for the mouse move messages. + * If the mouse is down then this will drag the control and offset the timebar. + * @param inPoint the current location of the mouse. + * @param inFlags the state of the mouse. + */ +void CTimebarControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + bool theCommentEditMode = m_EditControl->GetEditMode(); + + // If we are in edit Comment mode or locked, then we do not drag the timebar. + if (!theCommentEditMode && m_IsMouseDown && !m_TimelineItemBinding->IsLockedEnabled()) { + UICPROFILE(OnMouseMove); + + if (m_MaybeDragStart) { + // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental + // moves + CPt theDragDistance = inPoint - m_MouseDownLoc; + if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y <= 25) + return; + + m_MaybeDragStart = false; + } + + long theNewTime = m_Snapper.ProcessDrag(m_StartTime, inPoint.x, inFlags); + if (theNewTime < 0) + theNewTime = 0; + long theDiffTime = theNewTime - m_StartTime; + + if (theDiffTime) { + GetTimebar()->OffsetTime(theDiffTime); + // display the time range tooltip + RefreshToolTip(inPoint); + } + } +} + +//============================================================================= +/** + * Call from the left TimebarTab to resize the control. + * @param inTime the time to set the start time to. + */ +void CTimebarControl::ResizeTimebarLeftTo(long inTime) +{ + // TOOD: sk - Figure out what this does + // if ( inTime != 0 ) + { + // The whole idea is to not do anything additional once times passes 0 (negatively) + // unless it is valid that time is negative on the timebar + if (inTime < 0 && m_StartTime > 0) + inTime = -m_StartTime; // so that it decrements to 0 + + if (m_StartTime > 0 || (m_StartTime == 0 && inTime > 0)) + GetTimebar()->ChangeTime(inTime, true); + } +} + +//============================================================================= +/** + * Call from the right TimebarTab to resize the control. + * @param inTime the time to set the start time to. + */ +void CTimebarControl::ResizeTimebarRightTo(long inTime) +{ + GetTimebar()->ChangeTime(inTime, false); +} + +//============================================================================= +/** + * Sets the Actual string of text + * @param inText the text to set the comment text to + */ +void CTimebarControl::SetText(const Q3DStudio::CString &inText) +{ + m_EditControl->SetData(inText); +} + +//============================================================================= +/** + * Sets the Text Color on the edit control + * @param inColor the color + */ +void CTimebarControl::SetTextColor(::CColor inColor) +{ + m_EditControl->SetTextColor(inColor); +} + +long CTimebarControl::GetStartTime() +{ + return m_StartTime; +} + +long CTimebarControl::GetEndTime() +{ + return m_EndTime; +} + +//============================================================================= +/** + * Sets whether or not this control is enabled. + * If the control is not enabled then it is still drawn and still intercepts + * mouse clicks, but it will not actually process them. + * @param inIsEnabled true if this control is to be enabled. + */ +void CTimebarControl::SetEnabled(bool inIsEnabled) +{ + CControl::SetEnabled(inIsEnabled); +} + +//============================================================================= +/** + * COMMENT!!!!!!!!!!!!!!!!!!!!!! + */ +void CTimebarControl::OnLoseFocus() +{ + if (m_IsMouseDown) { + m_IsMouseDown = false; + CommitTimeChange(); + HideMoveableWindow(); + } + CControl::OnLoseFocus(); +} + +//============================================================================= +/** + * Setup prior to dragging. + */ +void CTimebarControl::OnBeginDrag() +{ + GetTimebar()->OnBeginDrag(); +} + +void CTimebarControl::ChangeStartTime(long inTime) +{ + ResizeTimebarLeftTo(inTime); +} + +void CTimebarControl::ChangeEndTime(long inTime) +{ + ResizeTimebarRightTo(inTime); +} + +void CTimebarControl::Commit() +{ + GetTimebar()->CommitTimeChange(); +} +void CTimebarControl::Rollback() +{ + GetTimebar()->RollbackTimeChange(); +} + +void CTimebarControl::ShowContextMenu(CPt inPoint, bool inShowTimebarPropertiesOptions) +{ + CTimebarKeyframeContextMenu theMenu(this, m_TimelineItemBinding->GetKeyframesManager(), + inShowTimebarPropertiesOptions); + DoPopup(&theMenu, inPoint); +} + +void CTimebarControl::CommitTimeChange() +{ + GetTimebar()->CommitTimeChange(); +} + +//============================================================================= +/** + * The binding is a keyframes holder + */ +ITimelineItemKeyframesHolder *CTimebarControl::GetKeyframesHolder() +{ + return m_TimelineItemBinding; +} + +//============================================================================= +/** + * Start editing the timebar comment + */ +void CTimebarControl::OnEditTimeComment() +{ + GrabFocus(m_EditControl); + m_EditControl->DoChangeComment(); +} + +//============================================================================= +/** + * Need to invalidate all timebars to redraw + */ +void CTimebarControl::OnToggleTimebarHandles() +{ + Invalidate(); +} + +void CTimebarControl::SetTimebarTime() +{ + GetTimebar()->SetTimebarTime(this); +} + +::CColor CTimebarControl::GetTimebarColor() +{ + return GetTimebar()->GetTimebarColor(); +} + +void CTimebarControl::SetTimebarColor(const ::CColor &inColor) +{ + GetTimebar()->SetTimebarColor(inColor); +} + +void CTimebarControl::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + m_SnappingListProvider = inProvider; +} + +ISnappingListProvider &CTimebarControl::GetSnappingListProvider() const +{ + // sk - If you hit this, it means the setup order is incorrect. e.g. loading children is done + // depth first, ie your child's children is loaded before parent, doesn't work that way. + ASSERT(m_SnappingListProvider); + return *m_SnappingListProvider; +} + +CRct CTimebarControl::GetTopControlBounds() const +{ + return m_TimebarRow->GetStateRow()->GetTopControl()->GetBounds(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h new file mode 100644 index 00000000..ec37d134 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIMEBAR_CONTROL_H +#define INCLUDED_TIMEBAR_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "Snapper.h" +#include "CommentEdit.h" +#include "TimebarTip.h" +#include "TimeEditDlg.h" +#include "KeyframeContextMenu.h" + +class CStateTimebarRow; +class ITimelineItemBinding; +class ISnappingListProvider; + +//============================================================================= +/** + * Interface to a timebar control + */ +class ITimebarControl +{ +public: + virtual ~ITimebarControl() {} + + virtual ITimelineItemKeyframesHolder *GetKeyframesHolder() = 0; + virtual void OnEditTimeComment() = 0; + virtual void OnToggleTimebarHandles() = 0; + virtual void SetTimebarTime() = 0; + virtual ::CColor GetTimebarColor() = 0; + virtual void SetTimebarColor(const ::CColor &inColor) = 0; +}; + +class CTimebarControl : public CControl, public ITimeChangeCallback, public ITimebarControl +{ +public: + CTimebarControl(CStateTimebarRow *inRow, ITimelineItemBinding *inTimelineItemBinding); + virtual ~CTimebarControl(); + void Draw(CRenderer *inRenderer) override; + void SetSize(CPt inSize) override; + void SetSelected(bool inIsSelected); + void SetTimeRatio(double inTimeRatio); + void Refresh(); + void Refresh(long inStartTime, long inEndTime); + void RefreshMetaData(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void ResizeTimebarLeftTo(long inTime); + void ResizeTimebarRightTo(long inTime); + void SetText(const Q3DStudio::CString &inText); + void SetTextColor(::CColor inColor = ::CColor(0, 0, 0)); + void SetEnabled(bool inIsEnabled) override; + + long GetStartTime(); + long GetEndTime(); + + virtual void PopulateSnappingList(CSnapper *inSnapper); + void OnLoseFocus() override; + + void OnBeginDrag(); + + // ITimeChangeCallback + void ChangeStartTime(long) override; + void ChangeEndTime(long) override; + void Commit() override; + void Rollback() override; + + void ShowContextMenu(CPt inPoint, bool inShowTimebarPropertiesOptions); + void CommitTimeChange(); + + // ITimebarControl + ITimelineItemKeyframesHolder *GetKeyframesHolder() override; + void OnEditTimeComment() override; + void OnToggleTimebarHandles() override; + void SetTimebarTime() override; + ::CColor GetTimebarColor() override; + void SetTimebarColor(const ::CColor &inColor) override; + + void SetSnappingListProvider(ISnappingListProvider *inProvider); + ISnappingListProvider &GetSnappingListProvider() const; + + CRct GetTopControlBounds() const; + +protected: + ITimelineTimebar *GetTimebar(); + + void RefreshToolTip(CPt inPoint); + void DrawHashedBackgroundX(CRenderer *inRenderer, ::CColor inFirstColor, ::CColor inSecondColor, + CRct inRect); + + CStateTimebarRow *m_TimebarRow; + bool m_IsSelected; + double m_TimeRatio; + bool m_IsMouseDown; + bool m_MaybeDragStart; + CPt m_MouseDownLoc; + long m_StartTime; + long m_EndTime; + + CTimebarTip m_LeftLeftTip; + CTimebarTip m_LeftTip; + + CTimebarTip m_RightTip; + CTimebarTip m_RightRightTip; + CCommentEdit *m_EditControl; + CSnapper m_Snapper; + + ITimelineItemBinding *m_TimelineItemBinding; + ISnappingListProvider *m_SnappingListProvider; +}; +#endif // INCLUDED_TIMEBAR_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp new file mode 100644 index 00000000..9968a838 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TimebarTip.h" +#include "TimebarControl.h" +#include "MouseCursor.h" +#include "TimelineControl.h" +#include "ResourceCache.h" +#include "Renderer.h" +#include "StudioUtils.h" + +#include <QApplication> + +//============================================================================= +/** + * Create a timebar tip for the timebar. + * This handles displaying the resize cursor and processing the mouse commands. + * @param inTimebar the timebar on which this tip is attached. + * @param inIsLeft true if this is the left timebar tip. + */ +CTimebarTip::CTimebarTip(CTimebarControl *inTimebar, bool inIsLeft, bool inHasHandle /*=false*/) + : m_IsMouseDown(false) + , m_MaybeDragStart(false) + , m_HasHandle(false) +{ + m_Timebar = inTimebar; + m_IsLeft = inIsLeft; + + ShowHandles(inHasHandle); +} + +//============================================================================= +/** + * Destructor + */ +CTimebarTip::~CTimebarTip() +{ +} + +//============================================================================= +/** +* Updates the ToolTip and moves it to the correct place on screen. +* @param inPoint the point that the tooltip is supposed to be placed. +*/ +void CTimebarTip::RefreshToolTip(CPt inPoint) +{ + Q3DStudio::CString theCommentText; + + // format label as: startTime - endTime (timeDifference) + theCommentText = " " + FormatTimeString(m_Timebar->GetStartTime()) + " - " + + FormatTimeString(m_Timebar->GetEndTime()) + " (" + + FormatTimeString(m_Timebar->GetEndTime() - m_Timebar->GetStartTime()) + ")"; + + CRct theTimelineBounds(m_Timebar->GetTopControlBounds()); + inPoint.y = GetPosition().y - GetSize().y; + ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds); +} + +//============================================================================= +/** + * Starts the dragging of the timebar tip. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +bool CTimebarTip::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseDown(inPoint, inFlags); + + m_Timebar->OnBeginDrag(); + + m_Snapper.Clear(); + m_Snapper.SetSource(m_Timebar); + m_Timebar->GetSnappingListProvider().PopulateSnappingList(&m_Snapper); + m_Snapper.BeginDrag(inPoint.x); + + m_IsMouseDown = true; + m_MaybeDragStart = true; + m_MouseDownLoc = inPoint; + + setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); + + // display the time range tooltip + RefreshToolTip(inPoint); + + return true; +} + +//============================================================================= +/** + * Ends the dragging of the tip and commits the commands. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CTimebarTip::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // try to prevent stuck mousetips on exceptions + try { + CControl::OnMouseUp(inPoint, inFlags); + + // Commit the current command so it will not be merged with drag commands if this gets + // dragged again. + m_Timebar->CommitTimeChange(); + } catch (...) { + } + + m_IsMouseDown = false; + m_MaybeDragStart = false; + HideMoveableWindow(); + resetCursor(); +} + +//============================================================================= +/** + * If the mouse is down then this handles the resizing of the timebar. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse. + */ +void CTimebarTip::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + // Don't show the cursor if the mouse is down from someone else. + if (!(inFlags & CHotKeys::MOUSE_RBUTTON) && !(inFlags & CHotKeys::MOUSE_LBUTTON)) + setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); + + if (m_IsMouseDown) { + if (m_MaybeDragStart) { + // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental + // moves + CPt theDragDistance = inPoint - m_MouseDownLoc; + if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y <= 25) + return; + + m_MaybeDragStart = false; + } + + // Figure out which method to call based on which tip we are. + if (m_IsLeft) { + long theNewTime = m_Snapper.ProcessDrag(m_Timebar->GetStartTime(), inPoint.x, inFlags); + m_Timebar->ResizeTimebarLeftTo(theNewTime); + } else { + long theNewTime = m_Snapper.ProcessDrag(m_Timebar->GetEndTime(), inPoint.x, inFlags); + m_Timebar->ResizeTimebarRightTo(theNewTime); + } + + // display the time range tooltip + RefreshToolTip(inPoint); + } +} + +//============================================================================= +/** + * Resets the cursor back to normal. + * @param inPoint the location of the mouse. + * @param inFlags the state of the mouse/modifier buttons. + */ +void CTimebarTip::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + + resetCursor(); +} + +//============================================================================= +/** + * Draws timebar handles if necessary. + */ +void CTimebarTip::Draw(CRenderer *inRenderer) +{ + if (m_HasHandle) { // to show or not is based on Studio preferences + bool theShowHandle = + CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false); + if (theShowHandle) { + if (IsEnabled()) + inRenderer->DrawBitmap(CPt(0, 0), m_HandleImage); + else + inRenderer->DrawBitmap(CPt(0, 0), m_HandleDisabledImage); + } + } +} + +void CTimebarTip::ShowHandles(bool inShowHandles) +{ + m_HasHandle = inShowHandles; + + // If this tip can have a handle + if (m_HasHandle) { + if (!m_HandleImage) { + // If this is a tip on the left side, load the images for the left side + const char *theBitMap = + (m_IsLeft) ? "timebarhandle-left.png" : "timebarhandle-right.png"; + m_HandleImage = CResourceCache::GetInstance()->GetBitmap(theBitMap); + } + + if (!m_HandleDisabledImage) { + const char *theBitMap = + (m_IsLeft) ? "timebarhandle-disabled-left.png" : "timebarhandle-disabled-right.png"; + m_HandleDisabledImage = CResourceCache::GetInstance()->GetBitmap(theBitMap); + } + } +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h new file mode 100644 index 00000000..4aca03a7 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_TIMEBAR_TIP +#define INCLUDED_TIMEBAR_TIP 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "Snapper.h" + +#include <QCursor> +#include <QPixmap> +//============================================================================== +// Forwards +//============================================================================== +class CTimebarControl; +class CRenderer; + +//============================================================================== +/** + * Class for the tips of timebar controls. Allows the user to resize timebars + * by grabbing the tips. + */ +class CTimebarTip : public CControl +{ +public: + CTimebarTip(CTimebarControl *inTimebarControl, bool inIsLeft, bool inHasHandle = false); + virtual ~CTimebarTip(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void Draw(CRenderer *inRenderer) override; + + void ShowHandles(bool inShowHandles); + +protected: + void RefreshToolTip(CPt inPoint); + + CTimebarControl *m_Timebar; + bool m_IsMouseDown; + bool m_MaybeDragStart; + CPt m_MouseDownLoc; + bool m_IsLeft; + bool m_HasHandle; + QPixmap m_HandleImage; + QPixmap m_HandleDisabledImage; + CSnapper m_Snapper; +}; + +#endif // INCLUDED_TIMEBAR_TIP diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp new file mode 100644 index 00000000..9e0f4303 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TimelineControl.h" +#include "TimelineSplitter.h" +#include "StudioApp.h" +#include "Dispatch.h" +#include "TimelineTreeLayout.h" +#include "TimelineTimelineLayout.h" +#include "SlideRow.h" +#include "IDoc.h" +#include "InsertionLine.h" +#include "InsertionOverlay.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "BreadCrumbControl.h" +#include "BaseTimelineTreeControl.h" +#include "Bindings/TimelineTranslationManager.h" +#include "Doc.h" +#include "Core.h" +#include "MasterP.h" + +// Data model specific +#include "TimelineDropTarget.h" + +#include "ClientDataModelBridge.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" + +IMPLEMENT_OBJECT_COUNTER(CTimelineControl) + +CTimelineControl::CTimelineControl() + : m_SuspendRecalcLayout(false) + , m_TranslationManager(nullptr) +{ + ADDTO_OBJECT_COUNTER(CTimelineControl) + + m_TranslationManager = new CTimelineTranslationManager(); + + m_Splitter = new CTimelineSplitter(); + AddChild(m_Splitter); + + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + m_TreeLayout = new CTimelineTreeLayout(this, theDoc); + m_Splitter->AddChild(m_TreeLayout); + + m_TimelineLayout = new CTimelineTimelineLayout(this, theDoc); + m_Splitter->AddChild(m_TimelineLayout); + + m_Splitter->SetSplitDirection(CSplitter::SPLIT_VERTICAL); + m_Splitter->SetSplitLocation(CStudioPreferences::GetTimelineSplitterLocation()); + + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + theDispatch->AddPresentationChangeListener(this); + theDispatch->AddClientPlayChangeListener(this); + + // Insertion line + m_InsertionLine = new CInsertionLine(); + m_InsertionLine->SetName("TimelineInsertionLine"); + AddChild(m_InsertionLine); + + // Insertion overlay marker + m_InsertionOverlay = new CInsertionOverlay(); + m_InsertionOverlay->SetName("TimelineInsertionOverlay"); + AddChild(m_InsertionOverlay); + + m_Splitter->SetPosition(CPt(0, CStudioPreferences::GetHeaderHeight())); + + m_BreadCrumbToolbar = new CBreadCrumbControl(); + AddChild(m_BreadCrumbToolbar); + + SetPreferredSize(CPt(400, 200)); +} + +CTimelineControl::~CTimelineControl() +{ + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + theDispatch->RemovePresentationChangeListener(this); + theDispatch->RemoveClientPlayChangeListener(this); + + delete m_InsertionOverlay; + delete m_InsertionLine; + delete m_TimelineLayout; + delete m_TreeLayout; + delete m_Splitter; + delete m_BreadCrumbToolbar; + + REMOVEFROM_OBJECT_COUNTER(CTimelineControl) +} + +//============================================================================= +/** + * Returns the playhead time + */ +long CTimelineControl::GetTime() +{ + return m_TreeLayout->GetTime(); +} + +//============================================================================= +/** + * Clear the contents of this view. + * This will empty out this view and leave it ready for inspecting other objects. + */ +void CTimelineControl::ClearView() +{ + m_TimelineLayout->ClearRows(); + m_TreeLayout->ClearRows(); + m_ActiveSlide = 0; + + // clean out all previous translations, because the bindings are not guaranteed to be valid when + // switching from one slide to another. + m_TranslationManager->Clear(); +} + +//============================================================================= +/** + * Populates this view with the provided state. + * This will set the state as being the root object on this view. ClearView + * should be called before this is called. + * The object will become the root object of this and will become the active + * root of the doc. + * @param inState the state to be viewed as the root asset. + */ +void CTimelineControl::ViewSlide(UICDM::CUICDMSlideHandle inSlide) +{ + m_ActiveSlide = inSlide; + + UICDM::ISlideSystem *theSlideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMInstanceHandle theSlideInstance = theSlideSystem->GetSlideInstance(inSlide); + CSlideRow *theSlideRow = new CSlideRow(m_TranslationManager->GetOrCreate(theSlideInstance)); + theSlideRow->SetTimelineControl(this); + + m_TreeLayout->AddRow(theSlideRow); + m_TimelineLayout->AddRow(theSlideRow); + + // Since this would be loading the entire context's assets, fire the OnTimelineLayoutChange + // event just once. + SuspendLayoutChanges(true); + try { + theSlideRow->LoadChildren(); + theSlideRow->Expand(); + } catch (...) { // restore the 'states' before passing the exception up + SuspendLayoutChanges(false); + throw; + } + // Update breadcrumbs + m_BreadCrumbToolbar->RefreshTrail(m_TranslationManager->GetBreadCrumbProvider()); + + SuspendLayoutChanges(false); + OnLayoutChanged(); +} + +//============================================================================= +/** + * Notification from the StudioFullSystem signal provider that a we have a new active slide. + * This will populate this view with the new context. + */ +void CTimelineControl::OnActiveSlide(UICDM::CUICDMSlideHandle inSlide) +{ + ClearView(); + ViewSlide(inSlide); + + double theStoredRatio = m_TimelineLayout->GetTimelineRatio(inSlide); + if (theStoredRatio != -1) + m_TimelineLayout->SetTimeRatio(theStoredRatio); + else + m_TimelineLayout->OnScalingReset(); + + m_TimelineLayout->RecalcLayout(); +} + +void CTimelineControl::OnNewPresentation() +{ + m_TranslationManager->OnNewPresentation(); + + // Register callback + UICDM::IStudioFullSystemSignalProvider *theSignalProvider = + GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider(); + m_Connections.push_back(theSignalProvider->ConnectActiveSlide( + std::bind(&CTimelineControl::OnActiveSlide, this, std::placeholders::_3))); + m_Connections.push_back(theSignalProvider->ConnectSlideDeleted( + std::bind(&CTimelineControl::OnDeleteSlide, this, std::placeholders::_1))); + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + m_Connections.push_back(theDispatch->ConnectSelectionChange( + std::bind(&CTimelineControl::OnSelectionChange, this, std::placeholders::_1))); +} + +//============================================================================= +/** + * Notification from the dispatch that the presentation is being closed. + * This will clear all the objects from this presentation. + */ +void CTimelineControl::OnClosingPresentation() +{ + ClearView(); + m_TimelineLayout->ClearAllTimeRatios(); + m_BreadCrumbToolbar->RefreshTrail(nullptr); + + m_Connections.clear(); +} + +//============================================================================= +/** + * Accessor for the root object being displayed in this view. + */ +UICDM::CUICDMSlideHandle CTimelineControl::GetActiveSlide() +{ + return m_ActiveSlide; +} + +//============================================================================= +/** + * Gets the timeline layout which is the portion of the timeline to the right + * of the splitter. The timeline layout contains the timebars. + */ +CTimelineTimelineLayout *CTimelineControl::GetTimelineLayout() +{ + return m_TimelineLayout; +} + +//============================================================================= +/** + * Gets the tree layout which is the portion of the timeline to the left + * of the splitter. The tree layout contains the tree controls for expanding + * rows in the timeline. + */ +CTimelineTreeLayout *CTimelineControl::GetTreeLayout() +{ + return m_TreeLayout; +} + +//============================================================================= +/** + * Notification from the dispatch that the presentation is going into play mode. + */ +void CTimelineControl::OnPlayStart() +{ +} + +//============================================================================= +/** + * Notification from the dispatch that the presentation is exiting play state. + */ +void CTimelineControl::OnPlayStop() +{ +} + +//============================================================================= +/** + * Notification from the dispatch that the time has changed. + * This is used to update the playhead location and view time. + * @param inNewTime the new time that this should display. + */ +void CTimelineControl::OnTimeChanged(long inNewTime) +{ + SetTime(inNewTime); +} + +//============================================================================== +// CSelectionChangeListener +//============================================================================== +void CTimelineControl::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable) +{ + // testing for nullptr selection OR if the selected is not displayed in the timeline + bool theLoseFocus = !inNewSelectable.empty(); + if (!theLoseFocus) { + Q3DStudio::SelectedValueTypes::Enum theSelectionType = inNewSelectable.getType(); + // for now, its just UICDM objects + theLoseFocus = theSelectionType != Q3DStudio::SelectedValueTypes::Instance; // UICDM objects + } + if (theLoseFocus) + m_TreeLayout->OnLoseFocus(); + + GetTranslationManager()->OnSelectionChange(inNewSelectable); + + // The drag&drop doesn't have any sort of callback after a drop + // so for now, this acts as a "event-trigger" after a drop ( because new items are always + // selcted after a drop ) + HideInsertionMarkers(); +} + +//============================================================================= +/** + * Callback when individual rows has affected the layout, such that the treelayout needs to be + * synchronized with the timelinelayout or vice versa. + */ +void CTimelineControl::OnLayoutChanged() +{ + if (m_SuspendRecalcLayout) // optimization where this is explicitly shutoff. + return; + + m_TreeLayout->RecalcLayout(); + m_TimelineLayout->OnTimelineLayoutChanged(); +} + +//============================================================================= +/** + * typically for displaying tooltip + */ +CRct CTimelineControl::GetBounds() const +{ + return CRct(GetGlobalPosition(CPt(0, 0)), GetSize()); +} + +void CTimelineControl::HideTimelineMoveableTooltip() +{ + HideMoveableWindow(); +} + +//============================================================================= +/** + * For snapping timebars/keyframes + */ +ISnappingListProvider *CTimelineControl::GetSnappingListProvider() const +{ + return m_TimelineLayout; +} + +//============================================================================= +/** + * Sets the current time as seen in this palette. + * This will update the Playhead time and the time view time. + * @param inNewTime the time to set on this. + */ +void CTimelineControl::SetTime(long inNewTime) +{ + m_TimelineLayout->SetTime(inNewTime); + m_TreeLayout->SetTime(inNewTime); +} + +void CTimelineControl::HideInsertionMarkers() +{ + bool theInvalidate = false; + if (m_InsertionOverlay->IsVisible()) { + m_InsertionOverlay->SetVisible(false); + theInvalidate = true; + } + if (m_InsertionLine->IsVisible()) { + m_InsertionLine->SetVisible(false); + theInvalidate = true; + } + if (theInvalidate) { + m_TreeLayout->Invalidate(); + Invalidate(); + } +} + +void CTimelineControl::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + + m_Splitter->SetSize(CPt(inSize.x, inSize.y)); +} + +//============================================================================= +/** + * Scrolls both sides of the timeline along the y-axis so that they stay synced. + * @param inSource Scroller that generated the scroll messsage + * @param inPositionY New vertical scroll bar position + */ +void CTimelineControl::SetScrollPositionY(CScroller *inSource, long inPositionY) +{ + m_TreeLayout->SetScrollPositionY(inSource, inPositionY); + m_TimelineLayout->SetScrollPositionY(inSource, inPositionY); +} + +//============================================================================= +/** + * Override OnDraw to provide Timeline only draw profiling stats. + */ +void CTimelineControl::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + UICPROFILE(OnDraw); + CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation); +} + +//============================================================================= +/** + * Fills the whole control with the base (gray) color, then other controls will + * draw on top of that. + * @param inRenderer renderer to draw to + */ +void CTimelineControl::Draw(CRenderer *inRenderer) +{ + const auto size = GetSize(); + inRenderer->FillSolidRect(QRect(0, 0, size.x, size.y), CStudioPreferences::GetBaseColor()); +} + +//============================================================================= +/** + * Overriden from CControl. We want to propagate keydown (specifically F2) + * messages to the selected row regardless if the control has focus or not. + */ +void CTimelineControl::OnGainFocus() +{ + CControl::OnGainFocus(); + + CBaseStateRow *theRow = m_TranslationManager->GetSelectedRow(); + if (theRow) + theRow->SetFocus(); +} + +//============================================================================= +/** + * Overridden to draw insertion lines + */ +CDropTarget *CTimelineControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + CDropTarget *theDropTarget = CControl::FindDropCandidate(inMousePoint, inFlags); + + bool theHideInsertionMarkers = true; + CTimeLineDropTarget *theTimelineDropTarget = nullptr; + if (theDropTarget + && (theTimelineDropTarget = dynamic_cast<CTimeLineDropTarget *>(theDropTarget))) { + CControl *theInsertionOverControl = theTimelineDropTarget->GetInsertionMarkerRow(); + if (theInsertionOverControl) { + CRct theTreeRect = GetVisibleTreeLayoutArea(); + EDROPDESTINATION theDropDest = theTimelineDropTarget->GetDestination(); + switch (theDropDest) { + case EDROPDESTINATION_ABOVE: + case EDROPDESTINATION_BELOW: { + // the insertion line starts from the indent to the end of the row + long theIndent = theTimelineDropTarget->GetInsertionMarkerIndent(); + if (theDropDest == EDROPDESTINATION_ABOVE) + m_InsertionLine->SetPosition(theInsertionOverControl->GetGlobalPosition( + CPt(theIndent, -GetPosition().y))); + else + m_InsertionLine->SetPosition(theInsertionOverControl->GetGlobalPosition(CPt( + theIndent, theInsertionOverControl->GetSize().y - 1 - GetPosition().y))); + + long theWidth = + theTreeRect.size.x + theTreeRect.position.x - m_InsertionLine->GetPosition().x; + m_InsertionLine->SetLineWidth(theWidth); + m_InsertionLine->SetVisible(true); + m_InsertionOverlay->SetVisible(false); + } break; + case EDROPDESTINATION_ON: { + // insertion overlay spans the width of the row + m_InsertionOverlay->SetPosition(theInsertionOverControl->GetGlobalPosition( + CPt(theTreeRect.position.x, -GetPosition().y))); + + long theWidth = theTreeRect.size.x + theTreeRect.position.x + - m_InsertionOverlay->GetPosition().x; + m_InsertionOverlay->SetWidth(theWidth); + m_InsertionOverlay->SetVisible(true); + m_InsertionLine->SetVisible(false); + } break; + } + theHideInsertionMarkers = false; + } + } + // not drawn + if (theHideInsertionMarkers) + HideInsertionMarkers(); + + return theDropTarget; +} + +void CTimelineControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + HideInsertionMarkers(); +} + +void CTimelineControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + HideInsertionMarkers(); +} + +//============================================================================= +/** + * Gets the insertion line for the timeline. The insertion line should be used + * to indicate when you can drag-and-drop and item between two other items. + * Call SetVisible on this control to show/hide it. + * @return the insertion line control + */ +CInsertionLine *CTimelineControl::GetInsertionLine() +{ + return m_InsertionLine; +} + +//============================================================================= +/** + * Gets the insertion overlay marker for the timeline. This control should be + * used to indicate that you can drag-and-drop and object onto another item in + * the timeline. Call SetVisible on this control to show/hide it. + * @return the insertion overlay marker for the timeline + */ +CInsertionOverlay *CTimelineControl::GetInsertionOverlay() +{ + return m_InsertionOverlay; +} + +//============================================================================= +/** + * Fetches the bounding rect for the CTimelineTreeLayout section of the + * timeline. This is the section that contains toggles and text names of items + * in the timeline. The actual tree layout might be bigger than this rect + * specifies. This is because portions of the tree layout might be overlapped + * by other controls. + * @return rectangle describing visible area of the tree control + */ +CRct CTimelineControl::GetVisibleTreeLayoutArea() +{ + return m_TreeLayout->GetVisibleArea(); +} + +void CTimelineControl::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler) +{ + m_TimelineLayout->RegisterGlobalKeyboardShortcuts(inShortcutHandler); +} + +//============================================================================= +/** + * event that takes place just before a save or export, on lose focus will commit changes + * in text boxes + */ +void CTimelineControl::OnSavingPresentation(const CUICFile *inNewPresentationFile) +{ + Q_UNUSED(inNewPresentationFile); + OnLoseFocus(); +} + +//============================================================================= +/** + * Notification from the StudioFullSystem signal provider that a slide has been deleted. + */ +void CTimelineControl::OnDeleteSlide(UICDM::CUICDMSlideHandle inSlide) +{ + m_TimelineLayout->DeleteTimelineRatio(inSlide); +} + +//============================================================================== +/** + * When caller knows that there are 'batch' changes to the timeline layout, + * to prevent unnecessary calls to recalclayout + */ +void CTimelineControl::SuspendLayoutChanges(bool inSuspend) +{ + m_SuspendRecalcLayout = inSuspend; +} + +CDoc *CTimelineControl::GetDoc() +{ + return g_StudioApp.GetCore()->GetDoc(); +} + +CClientDataModelBridge *CTimelineControl::GetBridge() +{ + return GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h new file mode 100644 index 00000000..470a10a5 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_TIMELINE_CONTROL_H +#define INCLUDED_TIMELINE_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "DispatchListeners.h" +#include "TimelineRow.h" +#include "ITimelineControl.h" + +#include "UICDMHandles.h" +#include "UICDMSignals.h" +#include "SelectedValueImpl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CDoc; +class CDropTarget; +class CTimelineSplitter; +class CTimelineTreeLayout; +class CTimelineTimelineLayout; +class CScroller; +class CInsertionLine; +class CInsertionOverlay; +class CRenderer; +class CHotKeys; +class CBreadCrumbControl; +class CTimelineTranslationManager; +class CClientDataModelBridge; + +//============================================================================== +// Classes +//============================================================================== + +class CTimelineControl : public CControl, + public CPresentationChangeListener, + public CClientPlayChangeListener, + public ITimelineControl +{ +public: + CTimelineControl(); + ~CTimelineControl(); + + DEFINE_OBJECT_COUNTER(CTimelineControl) + + // CControl + void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override; + void Draw(CRenderer *inRenderer) override; + void OnGainFocus() override; + CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + // Presentation Change Listener + void OnNewPresentation() override; + void OnClosingPresentation() override; + void OnSavingPresentation(const CUICFile *inNewPresentationFile) override; + + // ClientPlayChangeListener + void OnPlayStart() override; + void OnPlayStop() override; + void OnTimeChanged(long inNewTime) override; + + // CSelectionChangeListener, + virtual void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable); + + // ITimelineControl + void OnLayoutChanged() override; + CRct GetBounds() const override; + void HideTimelineMoveableTooltip() override; + ISnappingListProvider *GetSnappingListProvider() const override; + + void ClearView(); + void ViewSlide(UICDM::CUICDMSlideHandle inSlide); + UICDM::CUICDMSlideHandle GetActiveSlide(); + + CTimelineTimelineLayout *GetTimelineLayout(); + CTimelineTreeLayout *GetTreeLayout(); + + void SetSize(CPt inSize) override; + long GetTime(); + void SetScrollPositionY(CScroller *inSource, long inPositionY); + + CInsertionLine *GetInsertionLine(); + CInsertionOverlay *GetInsertionOverlay(); + CRct GetVisibleTreeLayoutArea(); + + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + + CTimelineTranslationManager *GetTranslationManager() const { return m_TranslationManager; } + +protected: + void SuspendLayoutChanges(bool inSuspend); + void SetTime(long inNewTime); + + void HideInsertionMarkers(); + + // UICDM callbacks + void OnActiveSlide(UICDM::CUICDMSlideHandle inSlide); + void OnDeleteSlide(UICDM::CUICDMSlideHandle inSlide); + + // Helper functions + inline CDoc *GetDoc(); + inline CClientDataModelBridge *GetBridge(); + + CTimelineSplitter *m_Splitter; + CTimelineTreeLayout *m_TreeLayout; + CTimelineTimelineLayout *m_TimelineLayout; + UICDM::CUICDMSlideHandle m_ActiveSlide; + CInsertionLine + *m_InsertionLine; ///< Drag-and-drop insertion line for dropping between timeline items + CInsertionOverlay + *m_InsertionOverlay; ///< Drag-and-drop insertion marker for dropping on a timeline item + CBreadCrumbControl *m_BreadCrumbToolbar; + bool m_SuspendRecalcLayout; + + CTimelineTranslationManager *m_TranslationManager; + + std::vector<std::shared_ptr<UICDM::ISignalConnection>> + m_Connections; /// connections to the UICDM +}; +#endif // INCLUDED_TIMELINE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp new file mode 100644 index 00000000..5ef25911 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TimelineFilter.h" +#include "Bindings/ITimelineItemProperty.h" +#include "Bindings/ITimelineItem.h" + +//============================================================================= +/** + * Constructor + */ +CFilter::CFilter() + : m_ShowBehaviors(true) + , m_ShowMaterials(true) + , m_ShowProperties(true) + , m_ShowShy(true) + , m_ShowLocked(true) + , m_ShowVisible(true) + , m_IsExpanded(true) +{ +} + +//============================================================================= +/** + * Destructor + */ +CFilter::~CFilter() +{ +} + +//============================================================================= +/** + * @return true if behaviors should be shown, false if they should be hidden + */ +bool CFilter::GetBehaviors() const +{ + return m_ShowBehaviors; +} + +//============================================================================= +/** + * @return true if materials should be shown, false if they should be hidden + */ +bool CFilter::GetMaterials() const +{ + return m_ShowMaterials; +} + +//============================================================================= +/** + * @return true if properties should be shown, false if they should be hidden + */ +bool CFilter::GetProperties() const +{ + return m_ShowProperties; +} + +//============================================================================= +/** + * @return true if shy objects should still be shown, false if they should be hidden + */ +bool CFilter::GetShy() const +{ + return m_ShowShy; +} + +//============================================================================= +/** + * @return true if locked objects should still be shown, false if they should be hidden + */ +bool CFilter::GetLocked() const +{ + return m_ShowLocked; +} + +//============================================================================= +/** + * Sets whether or not to show behaviors on objects. + * @param inShow true to show behaviors, false to hide behaviors + */ +void CFilter::SetBehaviors(bool inShow /*= true*/) +{ + m_ShowBehaviors = inShow; +} + +//============================================================================= +/** + * Sets whether or not to show materials on objects. + * @param inShow true to show materials, false to hide materials + */ +void CFilter::SetMaterials(bool inShow /*= true*/) +{ + m_ShowMaterials = inShow; +} + +//============================================================================= +/** + * Sets whether or not to show properties on objects. + * @param inShow true to show properties, false to hide properties + */ +void CFilter::SetProperties(bool inShow /*= true*/) +{ + m_ShowProperties = inShow; +} + +//============================================================================= +/** + * Sets whether or not to show objects with the shy flag. + * @param inShow true to show shy objects, false to hide shy objects + */ +void CFilter::SetShy(bool inShow /*= true*/) +{ + m_ShowShy = inShow; +} + +//============================================================================= +/** + * Sets whether or not to show objects with the locked flag. + * @param inShow true to show locked objects, false to hide locked objects + */ +void CFilter::SetLocked(bool inShow /*= true*/) +{ + m_ShowLocked = inShow; +} + +//============================================================================= +/** + * Sets whether or not the parent object is expanded. + * If the parent is not expanded then nothing should be visible. + */ +void CFilter::SetExpanded(bool inIsExpanded /*= true*/) +{ + m_IsExpanded = inIsExpanded; +} + +//============================================================================= +/** + * Sets whether or not to show objects that are not visible. + * @param inIsVisible true to show non-visible objects, false to hide them. + */ +void CFilter::SetVisible(bool inIsVisible /*= true*/) +{ + m_ShowVisible = inIsVisible; +} + +//============================================================================= +/** + * Gets whether or not non-visible objects should be displayed. + * @return true if non-visible objects should be displayed. + */ +bool CFilter::GetVisible() const +{ + return m_ShowVisible; +} + +//============================================================================= +/** + * Gets whether or not the parent object is expanded. + * If the parent is not expanded then nothing should be visible. + */ +bool CFilter::IsExpanded() const +{ + return m_IsExpanded; +} + +//============================================================================= +/** + * Checks to see if the specified property should be displayed or not. + * @return true if the property should be visible. + */ +bool CFilter::Filter(ITimelineItemProperty *inTimelineItemProperty) const +{ + Q_UNUSED(inTimelineItemProperty); + + bool theVisibleFlag = GetProperties(); + theVisibleFlag &= IsExpanded(); + + return theVisibleFlag; +} + +//============================================================================= +/** + * Checks to see if the specified state should be displayed or not. + * @return true if the state should be visible. + */ +bool CFilter::Filter(ITimelineItem *inTimelineItem) const +{ + bool theVisibleFlag = true; + + // If this row is shy, we need to check the filter for shy objects + if (inTimelineItem->IsShy()) + theVisibleFlag &= GetShy(); + + // If this row is locked, we need to check the filter for locked objects + if (inTimelineItem->IsLocked()) + theVisibleFlag &= GetLocked(); + + // This is for hiding visible eye toggle objects + if (!inTimelineItem->IsVisible()) + theVisibleFlag &= GetVisible(); + + // If this row is a behavior, we need to check the filter for behaviors + if (inTimelineItem->GetObjectType() == OBJTYPE_BEHAVIOR) + theVisibleFlag &= GetBehaviors(); + + // If this row is a material, we need to check the filter for materials + if (inTimelineItem->GetObjectType() == OBJTYPE_MATERIAL) + theVisibleFlag &= GetMaterials(); + + return theVisibleFlag; +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h new file mode 100644 index 00000000..e956b4da --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#ifndef INCLUDED_FILTER_H +#define INCLUDED_FILTER_H 1 + +#pragma once + +//============================================================================== +// Forward +//============================================================================== +class ITimelineItem; +class ITimelineItemProperty; + +//============================================================================= +/** + * Filter class for determining what objects to show in the timeline. + */ +class CFilter +{ +public: + CFilter(); + virtual ~CFilter(); + + bool GetBehaviors() const; + bool GetMaterials() const; + bool GetProperties() const; + bool GetShy() const; + bool GetLocked() const; + bool GetVisible() const; + void SetBehaviors(bool inShow = true); + void SetMaterials(bool inShow = true); + void SetProperties(bool inShow = true); + void SetShy(bool inShow = true); + void SetLocked(bool inShow = true); + void SetVisible(bool inShow = true); + + void SetExpanded(bool inExpanded = true); + bool IsExpanded() const; + + bool Filter(ITimelineItemProperty *inTimelineItemProperty) const; + bool Filter(ITimelineItem *inTimelineItem) const; + +protected: + bool m_ShowBehaviors; + bool m_ShowMaterials; + bool m_ShowProperties; + bool m_ShowShy; + bool m_ShowLocked; + bool m_ShowVisible; + bool m_IsExpanded; +}; + +#endif // INCLUDED_FILTER_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp new file mode 100644 index 00000000..36946432 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "TimelineKeyframe.h" +#include "Renderer.h" + +CTimelineKeyframe::CTimelineKeyframe() + : m_Time(0) + , m_IsDynamic(false) +{ +} + +CTimelineKeyframe::~CTimelineKeyframe() +{ +} + +void CTimelineKeyframe::SetTime(long inTime) +{ + m_Time = inTime; +} + +long CTimelineKeyframe::GetTime() +{ + return m_Time; +} + +//============================================================================= +/** + * called when this key is made dynamic + * @param inIsDynamic true if the keyframe is dynamic + */ +void CTimelineKeyframe::SetDynamic(bool inIsDynamic) +{ + if (m_IsDynamic != inIsDynamic) { + m_IsDynamic = inIsDynamic; + // Invalidate( ); + } +} + +//============================================================================= +/** + * @return true if dynamic + */ +bool CTimelineKeyframe::IsDynamic() +{ + return m_IsDynamic; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h new file mode 100644 index 00000000..a08f553c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIMELINE_KEYFRAME +#define INCLUDED_TIMELINE_KEYFRAME 1 + +#pragma once +class CRenderer; + +class CTimelineKeyframe +{ +public: + CTimelineKeyframe(); + ~CTimelineKeyframe(); + virtual void Draw(CRenderer *inRenderer) = 0; + + virtual void SetTime(long inTime); + virtual long GetTime(); + + void SetDynamic(bool inIsDynamic); + bool IsDynamic(); + + static const long DRAGBUFFER = + 3; // Specifies how many pixels a keframe should be dragged before it actually moves + +protected: + long m_Time; + bool m_IsDynamic; +}; + +#endif // INCLUDED_TIMELINE_KEYFRAME
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp new file mode 100644 index 00000000..c465575c --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "TimelineRow.h" +#include "StudioPreferences.h" +#include "StudioObjectTypes.h" +#include "BaseStateRow.h" + +const long CTimelineRow::TREE_INDENT = CStudioPreferences::GetRowSize(); + +CTimelineRow::CTimelineRow() + : m_ParentRow(nullptr) + , m_IsViewable(false) + , m_Indent(0) +{ +} + +CTimelineRow::~CTimelineRow() +{ +} +void CTimelineRow::SetIndent(long inIndent) +{ + m_Indent = inIndent; +} + +long CTimelineRow::GetIndent() +{ + return m_Indent; +} + +void CTimelineRow::SetParent(CBaseStateRow *inParent) +{ + m_ParentRow = inParent; +} + +//============================================================================= +/** + * Gets the Parent Row + */ +CBaseStateRow *CTimelineRow::GetParentRow() const +{ + return m_ParentRow; +} + +void CTimelineRow::SetTimeRatio(double inTimeRatio) +{ + Q_UNUSED(inTimeRatio); +} + +void CTimelineRow::OnChildVisibilityChanged() +{ +} + +bool CTimelineRow::IsViewable() const +{ + return m_IsViewable; +} + +void CTimelineRow::PopulateSnappingList(CSnapper *inSnapper) +{ + Q_UNUSED(inSnapper); +} + +//============================================================================= +/** + * By default, this will recurse up its parent, for an answer. + * If this proves to a performance hit, we can cache a ITimelineControl pointer at EVERY row. + */ +ITimelineControl *CTimelineRow::GetTopControl() const +{ + ITimelineControl *theControl = (m_ParentRow) ? m_ParentRow->GetTopControl() : nullptr; + ASSERT(theControl); + return theControl; +} + +//============================================================================= +/** + * Retrieves the background color for the row based upon the type of asset + * passed in. + * @param inType specifies which asset type you want the color for + * @return background color to use for this row + */ +::CColor CTimelineRow::GetTimebarBackgroundColor(EStudioObjectType inType) +{ + ::CColor theColor; + + switch (inType) { + case OBJTYPE_LAYER: + theColor = CStudioPreferences::GetLayerBackgroundColor(); + break; + + case OBJTYPE_GROUP: + case OBJTYPE_COMPONENT: + theColor = CStudioPreferences::GetGroupBackgroundColor(); + break; + + default: + theColor = CStudioPreferences::GetObjectBackgroundColor(); + break; + } + + return theColor; +} + +//============================================================================= +/** + * Retrieves the background color for the row when the mouse is over the row, + * based upon the type of asset passed in. + * @param inType specifies which asset type you want the color for + * @return background color to use for this row when the mouse is over the row + */ +::CColor CTimelineRow::GetTimebarHighlightBackgroundColor(EStudioObjectType inType) +{ + ::CColor theColor; + + switch (inType) { + case OBJTYPE_LAYER: + theColor = CStudioPreferences::GetMouseOverHighlightColor(); + break; + + case OBJTYPE_GROUP: + case OBJTYPE_COMPONENT: + theColor = CStudioPreferences::GetMouseOverHighlightColor(); + break; + + default: + theColor = CStudioPreferences::GetMouseOverHighlightColor(); + break; + } + + return theColor; +} + +long CTimelineRow::GetLatestEndTime() +{ + return 0; +} + +void CTimelineRow::Dispose() +{ + delete this; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h new file mode 100644 index 00000000..c18d438b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TIMELINE_ROW_H +#define INCLUDED_TIMELINE_ROW_H 1 + +#pragma once + +#include "TimelineFilter.h" +#include "CColor.h" +#include "StudioObjectTypes.h" + +#include <vector> + +class CSnapper; +class CControl; +class CBaseStateRow; +class ISnappingListProvider; +class ITimelineControl; + +class CTimelineRow +{ +public: + static const long TREE_INDENT; + + CTimelineRow(); + virtual ~CTimelineRow(); + + virtual CControl *GetColorControl() = 0; + virtual CControl *GetTreeControl() = 0; + virtual CControl *GetToggleControl() = 0; + virtual CControl *GetTimebarControl() = 0; + + virtual void SetIndent(long inIndent); + long GetIndent(); + + virtual void Filter(const CFilter &inFilter, bool inFilterChildren = true) = 0; + + void SetParent(CBaseStateRow *inParent); + CBaseStateRow *GetParentRow() const; + virtual void SetTimeRatio(double inTimeRatio); + virtual void OnChildVisibilityChanged(); + virtual bool IsViewable() const; + virtual void PopulateSnappingList(CSnapper *inSnappingList); + virtual ISnappingListProvider *GetSnappingListProvider() const = 0; + virtual void SetSnappingListProvider(ISnappingListProvider *inProvider) = 0; + virtual ITimelineControl *GetTopControl() const; + + virtual ::CColor GetTimebarBackgroundColor(EStudioObjectType inType); + virtual ::CColor GetTimebarHighlightBackgroundColor(EStudioObjectType inType); + + virtual long GetLatestEndTime(); + + virtual void Dispose(); + +protected: + CBaseStateRow *m_ParentRow; + bool m_IsViewable; + long m_Indent; +}; +#endif // INCLUDED_TIMELINE_ROW_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp new file mode 100644 index 00000000..fe072db6 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#include "stdafx.h" + +//============================================================================= +// Includes +//============================================================================= +#include "TimelineSplitter.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Constructor + */ +CTimelineSplitter::CTimelineSplitter() +{ +} + +//============================================================================= +/** + * Destructor + */ +CTimelineSplitter::~CTimelineSplitter() +{ +} + +//============================================================================= +/** + * Set the location of the splitter bar. Overridden so that this location can + * be stored in the user's preferences. + * @param inSplitLocation the location of the splitter bar, in pixels from the right/top. + */ +void CTimelineSplitter::SetSplitLocation(long inPixels) +{ + CSplitter::SetSplitLocation(inPixels); + CStudioPreferences::SetTimelineSplitterLocation(inPixels); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h new file mode 100644 index 00000000..f9ba681a --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#ifndef TIMELINE_SPLITTER_INCLUDED +#define TIMELINE_SPLITTER_INCLUDED 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "Splitter.h" + +//============================================================================= +/** + * Overridden splitter, specific to the timeline, which stores the split location + * so that it can be retrieved between program sessions. + */ +class CTimelineSplitter : public CSplitter +{ +public: + CTimelineSplitter(); + virtual ~CTimelineSplitter(); + void SetSplitLocation(long inPixels) override; +}; + +#endif diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp new file mode 100644 index 00000000..ead5251d --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#include "stdafx.h" + +//============================================================================= +// Includes +//============================================================================= +#include "TimelineTimelineLayout.h" +#include "TimeMeasure.h" +#include "ScalableScroller.h" +#include "StudioUtils.h" +#include "TimelineRow.h" +#include "TimelineControl.h" +#include "StateRow.h" +#include "Snapper.h" +#include "Bindings/TimelineTranslationManager.h" +#include "ControlData.h" +#include "HotKeys.h" +#include "foundation/Qt3DSLogging.h" + +//============================================================================= +// Defines +//============================================================================= +// For Win the modifier key for keyframe multi selection is the control key. +#define MODIFIER_KEY CHotKeys::MODIFIER_CONTROL + +//============================================================================= +// Class constants +//============================================================================= +const double DEFAULT_TIME_RATIO = .05; +const double CTimelineTimelineLayout::SCALING_PERCENTAGE_INC = 1.1; +const double CTimelineTimelineLayout::SCALING_PERCENTAGE_DEC = 0.9; +const double CTimelineTimelineLayout::MAX_ZOOM_OUT = 7e-005; + +//============================================================================= +/** + * Constructor + */ +CTimelineTimelineLayout::CTimelineTimelineLayout(CTimelineControl *inTimelineControl, IDoc *inDoc) + : m_Playhead(this, inDoc) + , m_IsLayoutChanged(false) + , m_IsMouseDown(false) +{ + m_ControlData->SetMouseWheelEnabled(true); + m_TimelineControl = inTimelineControl; + + m_TimeRatio = DEFAULT_TIME_RATIO + .01; + m_TimeMeasure = new CTimeMeasure(this, m_TimeRatio); + m_Scroller = new CScalableScroller(); + + m_Scroller->SetVerticalScrollMode(CScroller::ALWAYS); + m_Scroller->SetHorizontalScrollMode(CScroller::ALWAYS); + m_Scroller->AddScrollListener(this); + m_BoundingRect = new CAreaBoundingRect(); + m_BoundingRect->SetName("TimelineAreaBoundingRect"); + m_BoundingRect->SetVisible(false); + m_BoundingRect->SetAlpha(128); + + AddChild(m_TimeMeasure); + AddChild(m_Scroller); + AddChild(&m_Playhead); + AddChild(m_BoundingRect); + + // Blank control filling in the bottom of the timeline, under the rows + CBlankControl *theTimelineBlankControl = new CBlankControl(); + m_TimebarList = new CFlowLayout(theTimelineBlankControl); + + m_Scroller->AddChild(m_TimebarList); + m_Scroller->SetScalingListener(this); + m_TimebarList->SetName("TimelineTimelineLayoutList"); + + // Initializing flags for keyframe multi select to work. + m_CommitKeyframeSelection = false; +} + +//============================================================================= +/** + * Destructor + */ +CTimelineTimelineLayout::~CTimelineTimelineLayout() +{ + delete m_TimeMeasure; + delete m_Scroller; + delete m_TimebarList; + delete m_BoundingRect; +} + +//============================================================================= +/** + * Clear all the StateRows out of the top-level list. + * This is used when the current presentation is being cleared out. + */ +void CTimelineTimelineLayout::ClearRows() +{ + TTimelineRowList::iterator thePos = m_Rows.begin(); + for (; thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = (*thePos); + m_TimebarList->RemoveChild(theRow->GetTimebarControl()); + } + + m_Rows.clear(); +} + +//============================================================================= +/** + * Set the size of this control. + * Overrrides CControl::SetSize so that this can redo the layout of all inner + * controls. + * @param inSize the new size of this control. + */ +void CTimelineTimelineLayout::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + + RecalcLayout(); +} + +//============================================================================= +/** + * Recalculate the positioning of all the child components. + */ +void CTimelineTimelineLayout::RecalcLayout() +{ + CPt mySize = GetSize(); + // Put the time measure on top taking 21 pixels high. + m_TimeMeasure->SetSize(CPt(mySize.x, 21)); + m_TimeMeasure->SetPosition(CPt(0, 0)); + + // Make the scroller take up the rest of the space. + m_Scroller->SetSize(CPt(mySize.x, mySize.y - 42)); + m_Scroller->SetPosition(CPt(0, 21)); + + // Make it the full length of the view, minus the bottom scroll bar. + m_Playhead.SetSize(CPt(13, GetSize().y - m_Scroller->GetHorizontalBar()->GetSize().y - 21)); + + long theMinTime = -(m_Playhead.GetCenterOffset()); + + if (!m_Rows.empty()) { + long theLatestTime = 0; + TTimelineRowList::iterator thePos = m_Rows.begin(); + for (; thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = (*thePos); + long theRowLatestTime = theRow->GetLatestEndTime(); + if (theRowLatestTime > theLatestTime) + theLatestTime = theRowLatestTime; + } + + long theMinWidth = ::TimeToPos(theLatestTime, m_TimeRatio) + END_BUFFER_SIZE; + long theMinHeight = m_TimebarList->GetMinimumSize().y; + + CPt theVisSize = m_Scroller->GetVisibleSize(); + + if (theMinHeight < theVisSize.y) + theMinHeight = theVisSize.y; + if (theMinWidth < theVisSize.x) + theMinWidth = theVisSize.x; + + m_TimebarList->ResetMinMaxPref(); + m_TimebarList->SetAbsoluteSize(CPt(theMinWidth, theMinHeight)); + } + + // Set up the limits. + m_Playhead.SetMinMaxPosition(theMinTime, mySize.x - m_Scroller->GetVerticalBar()->GetSize().x); + + // Set playhead to time 0. + SetTime(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime(), true); + + // Reset! so that this isn't unnecessarily run + m_IsLayoutChanged = false; +} + +//============================================================================= +/** + * Add a timeline row to this object. + * This will add the row as a top level object. + * @param inRow the row to be added. + */ +void CTimelineTimelineLayout::AddRow(CTimelineRow *inRow) +{ + m_Rows.push_back(inRow); + + m_TimebarList->AddChild(inRow->GetTimebarControl()); + + inRow->SetTimeRatio(m_TimeRatio); + // For keyframe/timebar snapping. + inRow->SetSnappingListProvider(this); +} + +//============================================================================= +/** + * Call from the ScalableScroller that it is scaling the right side of the timebar. + * @param inLength the length that the thumb wants to be. + * @param inTotalLength the maximum length that the thumb can be. + * @param inOffset the offset of the thumb position. + */ +void CTimelineTimelineLayout::OnScalingRight(long inLength, long inTotalLength, long inOffset) +{ + double theViewSize = m_Scroller->GetVisibleSize().x; + double theClientSize = m_Scroller->GetContaineeSize().x; + double theLength = inLength; + double theTotalLength = inTotalLength; + + double theTimeRatio = + (theViewSize * theTotalLength) / (theClientSize * theLength) * m_TimeRatio; + + // This means the bar was dragged to the far end, just prevent it for getting wacky. + if (theTimeRatio > 0) { + // This will set the time ratio, but will cap it at 1 or MAX_ZOOM_OUT so if the Time ratio + // less than max, don't need to move the timeline + SetTimeRatio(theTimeRatio); + if (theTimeRatio < 1) { + double theMaxVisPos = m_Scroller->GetMaxVisiblePosition().x; + long theVisiblePosition = ::dtol(theMaxVisPos * inOffset / (inTotalLength - inLength)); + m_Scroller->SetVisiblePosition( + CPt(theVisiblePosition, m_Scroller->GetVisiblePosition().y)); + } + } +} + +//============================================================================= +/** + * Under construction. + */ +void CTimelineTimelineLayout::OnScalingLeft(long inLength, long inTotalLength, long inOffset) +{ + // Hey- look at that, doesn't matter which side you're scaling. + // Hey, nice comment especially the function header + OnScalingRight(inLength, inTotalLength, inOffset); +} + +void CTimelineTimelineLayout::OnScalingReset() +{ + SetTimeRatio(DEFAULT_TIME_RATIO); +} + +//============================================================================= +/** + * Set the TimeRatio to be used. + * This will propagate the time ratio down to all the child items. + * @param inTimeRatio the time ratio to be set. + */ +void CTimelineTimelineLayout::SetTimeRatio(double inTimeRatio) +{ + if (inTimeRatio != m_TimeRatio) { + if (inTimeRatio > 1) + inTimeRatio = 1; + // if ( inTimeRatio < MAX_ZOOM_OUT ) + // inTimeRatio = MAX_ZOOM_OUT; + + m_TimeRatio = inTimeRatio; + m_TimeMeasure->SetTimeRatio(inTimeRatio); + + TTimelineRowList::iterator thePos = m_Rows.begin(); + for (; thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = (*thePos); + theRow->SetTimeRatio(inTimeRatio); + } + + RecalcLayout(); + + // store the timeline ratio + SetTimelineRatio(m_TimelineControl->GetActiveSlide(), m_TimeRatio); + qCInfo(qt3ds::TRACE_INFO) << "Set time ratio: " << inTimeRatio; + } +} + +//============================================================================== +/** + * When timeline layout has changed. RecalcLayout should be called to adjust the scrollbars if + * a asset is expanded/collapsed in the timeline. + */ +void CTimelineTimelineLayout::OnTimelineLayoutChanged() +{ + RecalcLayout(); + + // In addition, this has to be 'marked' for if SetScrollerPositionY is called due to + // new assets being added, RecalcLayout has to be called again. + m_IsLayoutChanged = true; +} + +/** + * Deletes the time zoom ratio for a particular slide. + * @param inContext the time context of that slide to delete + */ +void CTimelineTimelineLayout::DeleteTimelineRatio(UICDM::CUICDMSlideHandle inSlide) +{ + m_TimelineRatio.erase(inSlide); +} + +/** + * Clear all entries + */ +void CTimelineTimelineLayout::ClearAllTimeRatios() +{ + m_TimelineRatio.clear(); +} + +/** + * Retrieves the time zoom ratio for a particular slide + * @param inContext the time context of that slide to retrieve zoom ratio + * @return the zoom ratio, or -1 if it's not found + */ +double CTimelineTimelineLayout::GetTimelineRatio(UICDM::CUICDMSlideHandle inSlide) +{ + TSlideRatioMap::iterator theResult = m_TimelineRatio.find(inSlide); + if (theResult != m_TimelineRatio.end()) + return theResult->second; + else + return -1; +} + +/** + * Sets the time zoom ratio for a particular slide + * @param inContext the time context of that slide + * @param inRatio the zoom factor + */ +void CTimelineTimelineLayout::SetTimelineRatio(UICDM::CUICDMSlideHandle inSlide, double inRatio) +{ + m_TimelineRatio[inSlide] = inRatio; +} + +//============================================================================= +/** + * For testing purposes. + */ +long CTimelineTimelineLayout::GetMaximumTimebarTime() +{ + return 30000; +} + +//============================================================================= +/** + * Call from the TimelineView to notifiy this that some of its objects got filtered. + * This was used for redoing the layout but is no longer necessary. + */ +void CTimelineTimelineLayout::Filter() +{ +} + +//============================================================================= +/** + * Notification from the CScroller that it is scrolling. + * This will update the other views with the verticall scrolling and update + * the TimeMeasure with the horizontal scroll amount. + * @param inScrollAmount the amount that was scrolled by. + */ +void CTimelineTimelineLayout::OnScroll(CScroller *inSource, CPt inScrollAmount) +{ + Q_UNUSED(inSource); + + m_TimelineControl->SetScrollPositionY(m_Scroller, m_Scroller->GetVisiblePosition().y); + + long theTimeOffset = GetViewTimeOffset(); + m_TimeMeasure->SetTimeOffset(theTimeOffset); + + long thePlayheadPos = + ::TimeToPos(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime() + - theTimeOffset, + m_TimeRatio) + - m_Playhead.GetCenterOffset(); + + m_Playhead.SetPosition(CPt(thePlayheadPos, 0)); + + m_DragBeginPoint += inScrollAmount; +} + +void CTimelineTimelineLayout::SetScrollPositionY(CScroller *inSource, long inPositionY, + bool inAbsolute) +{ + Q_UNUSED(inSource); + + CPt theVisPos = m_Scroller->GetVisiblePosition(); + + if (!inAbsolute) { + CPt theMaxSize = m_Scroller->GetMaxVisiblePosition(); + + CRct theVisibleRect(CPt(theVisPos.x, theMaxSize.y - theVisPos.y), + m_Scroller->GetVisibleSize()); + CPt thePoint(theVisPos.x, inPositionY); + if (!theVisibleRect.IsInRect(thePoint)) + m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY)); + } else { + // For new assets added, RecalcLayout needs be called here if there was a layout changed + // because + // m_TimebarList->GetMinimumSize( ).y is only updated at this point, otherwise the tree and + // layout will + // go out of sync. + if (m_IsLayoutChanged) + RecalcLayout(); + + m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY)); + } +} + +//============================================================================= +/** + * Get the scroller control this is using. + * Meant for testing purposes. + * @return the scroller this is using. + */ +CScalableScroller *CTimelineTimelineLayout::GetScroller() +{ + return m_Scroller; +} + +//============================================================================= +/** + * Get the playhead control this is using. + * Meant for testing purposes. + * @return the playhead this is using. + */ +CPlayhead *CTimelineTimelineLayout::GetPlayhead() +{ + return &m_Playhead; +} + +//============================================================================= +/** + * Scroll the contents of the timeline horizontally. + * This is used mainly by the playhead to scroll the view when it gets to the + * edge. + * @param inAmount the amount to scroll the view by. + * @return the amount actually scrolled, limited by min/max values. + */ +long CTimelineTimelineLayout::ScrollLayout(long inAmount) +{ + // Log the current position for returning + CPt thePosition = m_Scroller->GetVisiblePosition(); + + m_Scroller->SetVisiblePosition(CPt(thePosition.x + inAmount, thePosition.y)); + + // Return how much was actually scrolled, let the scroller handle min/max scroll amounts. + return m_Scroller->GetVisiblePosition().x - thePosition.x; +} + +//============================================================================= +/** + * Recalculate what the time is based on the location of the playhead. + * This will call SetTime on the TimelineView with the new time. + * @param inUpdateClient true if the client time should be updated. + */ +void CTimelineTimelineLayout::RecalcTime(bool inUpdateClient, long inFlags) +{ + long theOffset = m_Playhead.GetPosition().x + m_Playhead.GetCenterOffset() + + m_Scroller->GetVisiblePosition().x; + + long theTime = ::PosToTime(theOffset, m_TimeRatio); + m_Snapper.InterpretTimeEx(theTime, inFlags); + + // Update the time + m_Playhead.UpdateTime(theTime, inUpdateClient); +} + +//============================================================================= +/** + * Call from the timeline view that the time is changing. + * @param inNewTime the new time. + * @param inIsSecondary lame flag to prevent infinite recursion. + */ +void CTimelineTimelineLayout::SetTime(long inNewTime, bool inIsSecondary) +{ + long theOffset = ::TimeToPos(inNewTime, m_TimeRatio); + theOffset -= m_Scroller->GetVisiblePosition().x + m_Playhead.GetCenterOffset(); + + long theViewSize = m_Scroller->GetVisibleSize().x; + + if (!inIsSecondary) { + if (theOffset < -m_Playhead.GetCenterOffset()) { + long thePos = ::TimeToPos(inNewTime, m_TimeRatio) - m_Playhead.GetCenterOffset(); + m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y)); + } else if (theOffset > (theViewSize - (m_Playhead.GetCenterOffset() + 20))) { + long thePos = ::TimeToPos(inNewTime, m_TimeRatio) + 20; + thePos -= theViewSize; + m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y)); + } + SetTime(inNewTime, true); + } else { + m_Playhead.SetPosition(CPt(theOffset, m_Playhead.GetPosition().y)); + } +} + +//============================================================================= +/** + * Notification that the TimeMeasure was clicked on. + * This is used to reposition the playhead wherever the mouse was clicked. + * @param inPoint the location of the mouse local to the time measure. + */ +void CTimelineTimelineLayout::OnTimeMeasureMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inFlags); + + m_Snapper.Clear(); + m_Snapper.SetSource(&m_Playhead); + PopulateSnappingList(&m_Snapper); + m_Snapper.SetSnappingKeyframes(true); + + m_Playhead.SetPosition( + CPt(inPoint.x - m_Playhead.GetCenterOffset(), m_Playhead.GetPosition().y)); + RecalcTime(true, inFlags); +} + +//============================================================================= +/** + * Handles left-clicks. Starts a drag operation if a child does not handle the + * message. + * @param inPoint location of the mouse when event occurred + * @param inFlags state of modifier keys when event occurred + */ +bool CTimelineTimelineLayout::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_BoundingRect->SetSize(CPt(0, 0)); + m_BoundingRect->SetVisible(true); + + // Do not deselect all keyframes as the user intends to select more keyframes, + // when the modifier key is pressed. + if (!(inFlags & MODIFIER_KEY)) + m_TimelineControl->GetTranslationManager()->ClearKeyframeSelection(); + + m_IsMouseDown = true; + m_DragBeginPoint = inPoint; + } + return true; +} + +void CTimelineTimelineLayout::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + if (m_IsMouseDown) { + CPt theSize; + CRct theRect; + + // Tests if the user has pressed the modifier key, while moving the mouse. + bool theModifierKeyDown; + if (inFlags & MODIFIER_KEY) + theModifierKeyDown = true; + else + theModifierKeyDown = false; + + // Calculate the rect for the bounding box + theSize = CPt(inPoint.x - m_DragBeginPoint.x, inPoint.y - m_DragBeginPoint.y); + theRect = CRct(m_DragBeginPoint, theSize); + theRect.Normalize(); + m_BoundingRect->SetPosition(theRect.position); + m_BoundingRect->SetSize(theRect.size); + theRect.Offset(-m_Scroller->GetPosition()); + theRect.Offset(m_Scroller->GetVisiblePosition()); + + // Select all keys inside the rect + + TTimelineRowList::iterator thePos = m_Rows.begin(); + + for (; thePos != m_Rows.end(); ++thePos) { + CStateRow *theRow = reinterpret_cast<CStateRow *>(*thePos); + theRow->SelectKeysInRect(theRect, theModifierKeyDown, m_CommitKeyframeSelection); + } + m_CommitKeyframeSelection = false; + } +} + +void CTimelineTimelineLayout::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // try to prevent stuck mousetips on exceptions + try { + CControl::OnMouseUp(inPoint, inFlags); + m_BoundingRect->SetVisible(false); + } catch (...) { + } + + m_IsMouseDown = false; + + // Commits the key frame selection. This finalises the keyframes selection + // in the rect. When the mouse is down again, we would be able to append + // the commited keyframes with the new batch of keyframes. + m_CommitKeyframeSelection = true; +} + +void CTimelineTimelineLayout::PopulateSnappingList(CSnapper *inSnappingList) +{ + CRct theArea(m_Scroller->GetVisibleSize()); + theArea.Offset(-m_Scroller->GetPosition()); + theArea.Offset(m_Scroller->GetVisiblePosition()); + + inSnappingList->SetVisibleArea(theArea.position.y, theArea.size.y); + + inSnappingList->SetTimeRatio(m_TimeRatio); + if (inSnappingList->GetSource() != &m_Playhead) + inSnappingList->AddTime(m_Playhead.GetCurrentTime()); + + m_TimeMeasure->PopulateSnappingList(inSnappingList); + + TTimelineRowList::iterator theRowIter = m_Rows.begin(); + for (; theRowIter != m_Rows.end(); ++theRowIter) { + (*theRowIter)->PopulateSnappingList(inSnappingList); + } +} + +long CTimelineTimelineLayout::GetViewTimeOffset() +{ + return ::dtol(m_Scroller->GetVisiblePosition().x / m_TimeRatio); +} + +CTimeMeasure *CTimelineTimelineLayout::GetTimeMeasure() +{ + return m_TimeMeasure; +} + +//============================================================================= +/** + * Register all the events for hotkeys that are active for the entire application. + * Hotkeys for the entire application are ones that are not view specific in + * scope. + * @param inShortcutHandler the global shortcut handler. + */ +void CTimelineTimelineLayout::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler) +{ + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>( + this, &CTimelineTimelineLayout::OnScalingZoomIn), + 0, Qt::Key_Plus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>( + this, &CTimelineTimelineLayout::OnScalingZoomOut), + 0, Qt::Key_Minus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>( + this, &CTimelineTimelineLayout::OnScalingZoomIn), + Qt::KeypadModifier, Qt::Key_Plus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>( + this, &CTimelineTimelineLayout::OnScalingZoomOut), + Qt::KeypadModifier, Qt::Key_Minus); +} + +//============================================================================= +/** + * Call from the Hotkey that it is zooming in the timebar. + */ + +void CTimelineTimelineLayout::OnScalingZoomIn() +{ + double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_INC; + + SetTimeRatio(theTimeRatio); + CenterToPlayhead(); +} + +//============================================================================= +/** + * Call from the Hotkey that it is zooming out of the timebar. + */ + +void CTimelineTimelineLayout::OnScalingZoomOut() +{ + double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_DEC; + + SetTimeRatio(theTimeRatio); + CenterToPlayhead(); +} + +void CTimelineTimelineLayout::CenterToPlayhead() +{ + long theTime = m_Playhead.GetCurrentTime(); + long thePos = ::TimeToPos(theTime, m_TimeRatio); + long theNewPosX = thePos - (m_Scroller->GetSize().x / 2); + + m_Scroller->SetVisiblePosition(CPt(theNewPosX, m_Scroller->GetVisiblePosition().y)); +} + +//============================================================================== +/** + * Handle mouse wheel messages to allow zooming + */ +bool CTimelineTimelineLayout::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + if (inFlags & CHotKeys::MODIFIER_CONTROL) { + if (inAmount > 0) + OnScalingZoomIn(); + else + OnScalingZoomOut(); + theRetVal = true; + } else + theRetVal = CControl::OnMouseWheel(inPoint, inAmount, inFlags); + return theRetVal; +} diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h new file mode 100644 index 00000000..35524d5b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#ifndef INCLUDED_TIMELINE_TIMELINE_LAYOUT_H +#define INCLUDED_TIMELINE_TIMELINE_LAYOUT_H 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "Control.h" +#include <vector> +#include "ScalableScrollerBar.h" +#include "Scroller.h" +#include "Pt.h" +#include "Snapper.h" +#include "AreaBoundingRect.h" +#include "Playhead.h" +#include "UICDMHandles.h" + +//============================================================================= +// Forwards +//============================================================================= +class CScalableScroller; +class CTimelineRow; +class CFlowLayout; +class CTimelineControl; +class CSnapper; +class IDoc; +class CHotKeys; +class CTimeMeasure; +class CPlayhead; + +//============================================================================= +/** + * Right-hand pane of the Timeline containing timebars, keyframes, etc. + */ +class CTimelineTimelineLayout : public CControl, + public CScalingListener, + public CScrollListener, + public ISnappingListProvider +{ + typedef std::vector<CTimelineRow *> TTimelineRowList; + typedef std::map<UICDM::CUICDMSlideHandle, double> TSlideRatioMap; + +public: + static const long END_BUFFER_SIZE = 20; + static const double SCALING_PERCENTAGE_INC; + static const double SCALING_PERCENTAGE_DEC; + static const double MAX_ZOOM_OUT; + + CTimelineTimelineLayout(CTimelineControl *inView, IDoc *inDoc); + virtual ~CTimelineTimelineLayout(); + + void SetSize(CPt inSize) override; + + void AddRow(CTimelineRow *inRow); + + void OnScalingRight(long inLength, long inTotalLength, long inOffset) override; + void OnScalingLeft(long inLength, long inTotalLength, long inOffset) override; + void OnScalingReset() override; + + long ScrollLayout(long inAmount); + + void Filter(); + + void OnScroll(CScroller *inScroller, CPt inScrollAmount) override; + void SetScrollPositionY(CScroller *inSource, long inPositionY, bool inAbsolute = true); + + void ClearRows(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) override; + + CScalableScroller *GetScroller(); + CPlayhead *GetPlayhead(); + CTimeMeasure *GetTimeMeasure(); + void RecalcTime(bool inUpdateClient, long inFlags); + void SetTime(long inTime, bool inIsSecondary = false); + void OnTimeMeasureMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + long GetViewTimeOffset(); + void RecalcLayout(); + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + void SetTimeRatio(double inTimeRatio); + void OnTimelineLayoutChanged(); + + void DeleteTimelineRatio(UICDM::CUICDMSlideHandle inSlide); + void ClearAllTimeRatios(); + double GetTimelineRatio(UICDM::CUICDMSlideHandle inSlide); + + // ISnappingListProvider + void PopulateSnappingList(CSnapper *inSnappingList) override; + +protected: + void SetTimelineRatio(UICDM::CUICDMSlideHandle inSlide, double inRatio); + + long GetMaximumTimebarTime(); + void OnScalingZoomIn(); + void OnScalingZoomOut(); + void CenterToPlayhead(); + + bool m_CommitKeyframeSelection; ///< flag for saving previous keyframe selection when the mouse + ///is released. + CTimelineControl *m_TimelineControl; + CTimeMeasure *m_TimeMeasure; + CScalableScroller *m_Scroller; + CFlowLayout *m_TimebarList; + double m_TimeRatio; + + TTimelineRowList m_Rows; + CPlayhead m_Playhead; + CSnapper m_Snapper; + bool m_IsLayoutChanged; ///< flag to keep track of a need for a delayed RecalcLayout + + bool m_IsMouseDown; + CPt m_DragBeginPoint; + CAreaBoundingRect *m_BoundingRect; + + TSlideRatioMap m_TimelineRatio; ///< stores the time zooming ratios for each slide +}; +#endif // INCLUDED_TIMELINE_TIMELINE_LAYOUT_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp new file mode 100644 index 00000000..1229b88b --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#include "stdafx.h" + +//============================================================================= +// Includes +//============================================================================= +#include "TimelineTreeLayout.h" +#include "FlowLayout.h" +#include "Scroller.h" +#include "StateRow.h" +#include "FilterToolbar.h" +#include "ToggleToolbar.h" +#include "TimeToolbar.h" +#include "StudioPreferences.h" +#include "TimelineControl.h" +#include "Renderer.h" +#include "ToggleBlankControl.h" +#include "ColorBlankControl.h" +#include "TreeBlankControl.h" + +//============================================================================= +/** + * Constructor + */ +CTimelineTreeLayout::CTimelineTreeLayout(CTimelineControl *inTimelineControl, IDoc *inDoc) + : m_IsScrolling(false) +{ + m_TimelineControl = inTimelineControl; + + m_ColorScroller = new CScroller(); + m_ColorScroller->SetHorizontalScrollMode(CScroller::NEVER); + m_ColorScroller->SetVerticalScrollMode(CScroller::NEVER); + m_ColorScroller->AddScrollListener(this); + + m_ColorBlankControl = new CColorBlankControl(); + m_ColorList = new CFlowLayout(m_ColorBlankControl); + m_ColorScroller->AddChild(m_ColorList); + + m_ToggleScroller = new CScroller(); + m_ToggleScroller->SetHorizontalScrollMode(CScroller::NEVER); + m_ToggleScroller->SetVerticalScrollMode(CScroller::NEVER); + + m_ToggleBlankControl = new CToggleBlankControl(); + m_ToggleList = new CFlowLayout(m_ToggleBlankControl); + m_ToggleScroller->AddChild(m_ToggleList); + m_ToggleScroller->AddScrollListener(this); + + m_TreeScroller = new CScroller(); + m_TreeScroller->SetVerticalScrollMode(CScroller::NEVER); + m_TreeScroller->SetHorizontalScrollMode(CScroller::ALWAYS); + m_TreeScroller->AddScrollListener(this); + + m_TreeBlankControl = new CTreeBlankControl(); + m_TreeList = new CFlowLayout(m_TreeBlankControl); + m_TreeScroller->AddChild(m_TreeList); + + m_FilterToolbar = new CFilterToolbar(this); + m_TimeToolbar = new CTimeToolbar(inDoc); + m_ToggleToolbar = new CToggleToolbar(this); + + AddChild(m_TreeScroller); + AddChild(m_ToggleScroller); + AddChild(m_TimeToolbar); + AddChild(m_ToggleToolbar); + AddChild(m_ColorScroller); +} + +//============================================================================= +/** + * Destructor + */ +CTimelineTreeLayout::~CTimelineTreeLayout() +{ + m_ColorScroller->RemoveChild(m_ColorList); + m_ToggleScroller->RemoveChild(m_ToggleList); + m_TreeScroller->RemoveChild(m_TreeList); + + RemoveChild(m_TreeScroller); + RemoveChild(m_ToggleScroller); + RemoveChild(m_TimeToolbar); + RemoveChild(m_FilterToolbar); + RemoveChild(m_ToggleToolbar); + RemoveChild(m_ColorScroller); + // RemoveChild( m_BreadCrumbToolbar ); + + delete m_FilterToolbar; + delete m_TimeToolbar; + delete m_ToggleToolbar; + delete m_ColorScroller; + delete m_ColorList; + delete m_ToggleScroller; + delete m_ToggleList; + delete m_TreeList; + delete m_TreeScroller; + // delete m_BreadCrumbToolbar; + + // Delete all the rows, this control is responsible for the rows, maybe it should not + // be but currently it is. + TTimelineRowList::iterator thePos = m_Rows.begin(); + for (; thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = (*thePos); + theRow->Dispose(); // Dispose will delete the row as well + } +} + +//============================================================================= +/** + * Clear out all the contents of this tree layout. + * This will also delete all the rows, so make sure it is called after the + * TimelineTimelineLayout::ClearRows is called. + */ +void CTimelineTreeLayout::ClearRows() +{ + TTimelineRowList::iterator thePos = m_Rows.begin(); + for (; thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = (*thePos); + m_ColorList->RemoveChild(theRow->GetColorControl()); + m_TreeList->RemoveChild(theRow->GetTreeControl()); + m_ToggleList->RemoveChild(theRow->GetToggleControl()); + + theRow->Dispose(); + } + + m_Rows.clear(); +} + +//============================================================================= +/** + * Set the filter back to it's default state. + */ +void CTimelineTreeLayout::ResetFilter() +{ + m_FilterToolbar->FilterBehaviors(false); + m_FilterToolbar->FilterProperties(false); + m_FilterToolbar->FilterMaterials(false); + m_FilterToolbar->FilterShy(false); +} + +//============================================================================= +/** + * Set the size of this control. + * Overrides CControl::SetSize so that RecalcLayout can be called. + */ +void CTimelineTreeLayout::SetSize(CPt inSize) +{ + if (inSize != GetSize()) { + CControl::SetSize(inSize); + + RecalcLayout(); + } +} + +//============================================================================= +/** + * Recalculate the layout of all the child components. + * Called when this changes size and all the children need to be repositioned. + */ +void CTimelineTreeLayout::RecalcLayout() +{ + CPt mySize = GetSize(); + long theHeaderHeight = CStudioPreferences::GetHeaderHeight(); + + m_FilterToolbar->SetSize(CPt(120, theHeaderHeight)); + m_FilterToolbar->SetPosition(0, 0); + + m_ToggleToolbar->SetSize(CPt(61, theHeaderHeight)); + m_ToggleToolbar->SetPosition(mySize.x - m_ToggleToolbar->GetSize().x, 0); + + m_TimeToolbar->SetSize(CPt(mySize.x - m_ToggleToolbar->GetSize().x, theHeaderHeight)); + m_TimeToolbar->SetPosition(0, 0); + + m_ColorScroller->SetSize(CPt(CStudioPreferences::GetRowSize(), mySize.y - theHeaderHeight + - m_TreeScroller->GetHorizontalBar()->GetMinimumSize().y + - theHeaderHeight)); + m_ColorScroller->SetPosition(0, theHeaderHeight); + + m_ToggleScroller->SetSize(CPt(m_ToggleToolbar->GetSize().x, mySize.y - theHeaderHeight + - m_TreeScroller->GetHorizontalBar()->GetMinimumSize().y + - theHeaderHeight)); + m_ToggleScroller->SetPosition(mySize.x - m_ToggleScroller->GetSize().x, theHeaderHeight); + + m_TreeScroller->SetSize( + CPt(mySize.x, mySize.y - m_FilterToolbar->GetSize().y - theHeaderHeight)); + m_TreeScroller->SetPosition(0, theHeaderHeight); + + m_TreeScroller->SetAdditionalClippingRect( + CRct(m_ColorScroller->GetSize().x, 0, + m_ToggleScroller->GetPosition().x - m_ColorScroller->GetSize().x, + m_TreeScroller->GetSize().y)); +} + +//============================================================================= +/** + * Add another top level item to the left side of the timeline. + * If there is already a top level item then this one will be appended to the + * list. + * @param inRow the row to be added. + */ +void CTimelineTreeLayout::AddRow(CTimelineRow *inRow) +{ + m_ColorList->AddChild(inRow->GetColorControl()); + m_TreeList->AddChild(inRow->GetTreeControl()); + m_ToggleList->AddChild(inRow->GetToggleControl()); + + m_Rows.push_back(inRow); + + inRow->SetIndent(20); + + inRow->Filter(m_Filter); +} + +//============================================================================= +/** + * Applies the current filter settings to the timeline. Although the filter + * preferences can be set independently, they are not actually applied until + * this function is called. + */ +void CTimelineTreeLayout::Filter() +{ + for (TTimelineRowList::iterator thePos = m_Rows.begin(); thePos != m_Rows.end(); ++thePos) { + CTimelineRow *theRow = *thePos; + theRow->Filter(m_Filter); + } + + // TODO: sk - it is unclear to me what this is trying to do.. I am leavint this here till it + // becomes obvious it is totally redundant OR someone finds a related bug + /* + // Call OnSelect( ) on the selected object (if there is one) to get the timeline to scroll down. + CAsset* theSelectedObject = dynamic_cast<CAsset*>( m_Doc->GetSelectedObject( ) ); + if ( theSelectedObject ) + theSelectedObject->OnSelect( ); + + m_TimelineControl->GetTimelineLayout( )->RecalcLayout( ); + */ +} + +void CTimelineTreeLayout::OnScroll(CScroller *inSource, CPt inScrollAmount) +{ + Q_UNUSED(inScrollAmount); + + // SetScrollPositionY triggers another onScroll event and potentially causes the position + // to be set incorrectly. + if (!m_IsScrolling) { + m_IsScrolling = true; + m_TreeBlankControl->SetVisiblePositionX(inSource->GetVisiblePosition().x); + m_TimelineControl->SetScrollPositionY(inSource, inSource->GetVisiblePosition().y); + m_IsScrolling = false; + } +} + +//============================================================================= +/** + * Set the vertical position of all the scrollers in this view. + * This is used to sync up the positions with the timebar scroller view. + * @param inScrollPositionY the position of the scroller. + */ +void CTimelineTreeLayout::SetScrollPositionY(CScroller *inSource, long inScrollPositionY, + bool inAbsolute) +{ + Q_UNUSED(inSource); + + if (!inAbsolute) { + CRct theVisibleRect(m_ColorScroller->GetVisiblePosition(), + m_ColorScroller->GetVisibleSize()); + CPt thePoint(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY); + if (!theVisibleRect.IsInRect(thePoint)) { + m_ColorScroller->SetVisiblePosition( + CPt(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY)); + m_TreeScroller->SetVisiblePosition( + CPt(m_TreeScroller->GetVisiblePosition().x, inScrollPositionY)); + m_ToggleScroller->SetVisiblePosition( + CPt(m_ToggleScroller->GetVisiblePosition().x, inScrollPositionY)); + } + } else { + m_ColorScroller->SetVisiblePosition( + CPt(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY)); + m_TreeScroller->SetVisiblePosition( + CPt(m_TreeScroller->GetVisiblePosition().x, inScrollPositionY)); + m_ToggleScroller->SetVisiblePosition( + CPt(m_ToggleScroller->GetVisiblePosition().x, inScrollPositionY)); + } +} + +//============================================================================= +/** + * Sets the time on the Time header display time. + * @param inTime the new time. + */ +void CTimelineTreeLayout::SetTime(long inTime) +{ + m_TimeToolbar->SetTime(inTime); +} + +//============================================================================= +/** + * This is overridden so the Gesture can Notify Drop Listeners that its time to Drop. + * If the gesture is dragging something then wee will drop. + */ +void CTimelineTreeLayout::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); +} + +//============================================================================= +/** + * Returns the playhead time + */ +long CTimelineTreeLayout::GetTime() +{ + return m_TimeToolbar->GetTime(); +} + +//============================================================================= +/** + * @return rectangle describing the visible area of the tree control + */ +CRct CTimelineTreeLayout::GetVisibleArea() +{ + CPt theUpperLeftCorner; + CPt theSize; + + theUpperLeftCorner.x = m_ColorScroller->GetSize().x; + theUpperLeftCorner.y = CStudioPreferences::GetHeaderHeight(); + theSize.x = m_ToggleScroller->GetPosition().x - theUpperLeftCorner.x; + theSize.y = ::abs(m_ToggleScroller->GetPosition().y - m_ToggleScroller->GetSize().y) + - theUpperLeftCorner.y; + + return CRct(theUpperLeftCorner, theSize); +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h new file mode 100644 index 00000000..004bf3b7 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================= +// Prefix +//============================================================================= +#ifndef INCLUDED_TIMELINE_TREE_LAYOUT_H +#define INCLUDED_TIMELINE_TREE_LAYOUT_H 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "Control.h" +#include "TimelineFilter.h" +#include "Scroller.h" +#include <vector> + +//============================================================================= +// Forwards +//============================================================================= +class CFlowLayout; +class CScroller; +class CFilterToolbar; +class CTimelineRow; +class CToggleToolbar; +class CTimeToolbar; +class CTimelineControl; +class IDoc; +class CRenderer; +class CToggleBlankControl; +class CColorBlankControl; +class CTreeBlankControl; + +//============================================================================= +/** + * Class for tree control on the timeline palette. + */ +class CTimelineTreeLayout : public CControl, public CScrollListener +{ + typedef std::vector<CTimelineRow *> TTimelineRowList; + +public: + CTimelineTreeLayout(CTimelineControl *inTimelineControl, IDoc *inDoc); + virtual ~CTimelineTreeLayout(); + + // CControl + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void SetSize(CPt inSize) override; + + virtual void AddRow(CTimelineRow *inRow); + + /// Returns a filter object so that filter preferences can be set. You must call Filter() in + /// order to apply the filters once you make your changes. + CFilter *GetFilter() { return &m_Filter; } + void Filter(); + + void OnScroll(CScroller *inScroller, CPt inScrollAmount) override; + void SetScrollPositionY(CScroller *inSource, long inPositionY, bool inAbsolute = true); + + void ClearRows(); + + void SetTime(long inTime); + long GetTime(); + void ResetFilter(); + CRct GetVisibleArea(); + void RecalcLayout(); + +protected: + CFilter m_Filter; + CFilterToolbar + *m_FilterToolbar; ///< Control at the top of the timeline containing filter buttons. + CTimeToolbar *m_TimeToolbar; ///< Control at the top containing the time display + CToggleToolbar + *m_ToggleToolbar; ///< Control at the top containing a header for the toggle column. + + CScroller *m_ColorScroller; + CFlowLayout *m_ColorList; + CColorBlankControl *m_ColorBlankControl; + + CScroller *m_ToggleScroller; + CFlowLayout *m_ToggleList; + CToggleBlankControl *m_ToggleBlankControl; + + CScroller *m_TreeScroller; + CFlowLayout *m_TreeList; + CTreeBlankControl *m_TreeBlankControl; + + TTimelineRowList m_Rows; + CTimelineControl *m_TimelineControl; ///< Parent control of this control + + bool + m_IsScrolling; ///< Flag to not process onScroll that was triggered from a previous onScroll +}; +#endif // INCLUDED_TIMELINE_TREE_LAYOUT_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp new file mode 100644 index 00000000..c9ffff8e --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "ToggleBlankControl.h" +#include "Renderer.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Constructor + */ +CToggleBlankControl::CToggleBlankControl(CColor inColor) + : CBlankControl(inColor) +{ +} + +//============================================================================= +/** + * Destructor + */ +CToggleBlankControl::~CToggleBlankControl() +{ +} + +//============================================================================= +/** + * Handles custom drawing of the blank control underneath the tree control + * on the timeline palette. + */ +void CToggleBlankControl::Draw(CRenderer *inRenderer) +{ + CBlankControl::Draw(inRenderer); + + // Draw the line on the right side of this control + CPt theSize = GetSize(); + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(theSize.x - 1, 0); + inRenderer->LineTo(theSize.x - 1, theSize.y - 1); + inRenderer->PopPen(); + + // Draw the line on the left side of this control + inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor()); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theSize.y - 1)); + inRenderer->PopPen(); + + // Draw the highlight + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(1, 0)); + inRenderer->LineTo(CPt(1, theSize.y - 1)); + inRenderer->PopPen(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h new file mode 100644 index 00000000..ac07f7db --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_TOGGLE_BLANK_CONTROL_H +#define INCLUDED_TOGGLE_BLANK_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BlankControl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================= +/** + * Extends the blank control to draw items specific to the tree view side of the + * timeline palette. + */ +class CToggleBlankControl : public CBlankControl +{ +public: + CToggleBlankControl(CColor inColor = CStudioPreferences::GetBaseColor()); + virtual ~CToggleBlankControl(); + void Draw(CRenderer *inRenderer) override; + +protected: +}; + +#endif // INCLUDED_TOGGLE_BLANK_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp new file mode 100644 index 00000000..7abc00d4 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "stdafx.h" + +#include "ToggleControl.h" +#include "Renderer.h" +#include "StateRow.h" +#include "BlankControl.h" +#include "HotKeys.h" +#include "Bindings/ITimelineItemBinding.h" + +CToggleControl::CToggleControl(CStateRow *inStateRow, ITimelineItemBinding *inTimelineItemBinding) + : CBlankToggleControl(inStateRow) + , m_TimelineItemBinding(inTimelineItemBinding) +{ + m_StateRow = inStateRow; + long theLeftOffset = 4; + + m_Shy = new CToggleButton(); + m_Shy->SetName("ShyToggle"); + m_Shy->SetUpImage("Toggle-Empty.png"); + m_Shy->SetDownImage("Toggle-Shy.png"); + m_Shy->SetPosition(CPt(theLeftOffset, 0)); + CPt theShySize = m_Shy->GetSize(); + + m_Visible = new CToggleButton(); + m_Visible->SetName("VisibilityToggle"); + m_Visible->SetUpImage("Toggle-Empty.png"); + m_Visible->SetDownImage("Toggle-HideShow.png"); + m_Visible->SetUpDisabledImage("Toggle-Empty.png"); // show empty if disabled + m_Visible->SetDisabledImage("Toggle-HideShow-disabled.png"); + m_Visible->SetPosition(CPt(theShySize.x + 7, 0)); + CPt theVisibleSize = m_Visible->GetSize(); + + m_Locked = new CToggleButton(); + m_Locked->SetName("LockToggle"); + m_Locked->SetUpImage("Toggle-Empty.png"); + m_Locked->SetDownImage("Toggle-Lock.png"); + m_Locked->SetPosition(CPt(theVisibleSize.x + theShySize.x + 10, 0)); + CPt theLockedSize = m_Locked->GetSize(); + + AddChild(m_Shy); + AddChild(m_Visible); + AddChild(m_Locked); + + SetAbsoluteSize(CPt(theShySize.x + theVisibleSize.x + theLockedSize.x + 1, theShySize.y)); + + // Button down listeners + m_Shy->SigToggle.connect(std::bind(&CToggleControl::OnShyClicked, this, + std::placeholders::_1, std::placeholders::_2)); + m_Visible->SigToggle.connect(std::bind(&CToggleControl::OnVisibleClicked, this, + std::placeholders::_1, std::placeholders::_2)); + m_Locked->SigToggle.connect(std::bind(&CToggleControl::OnLockClicked, this, + std::placeholders::_1, std::placeholders::_2)); + + ITimelineItem *theTimelineItem = m_TimelineItemBinding->GetTimelineItem(); + // Initial toggle state of the eye visibility button + // Note GetViewToggleOff==FALSE means visible + m_Visible->SetToggleState(theTimelineItem->IsVisible()); + + // Initial toggle state of the button + m_Locked->SetToggleState(theTimelineItem->IsLocked()); + + // Initial toggle state of the button + m_Shy->SetToggleState(theTimelineItem->IsShy()); + + // sk - if anything, this should be checked in the data model level, not here. + // The tri-state (on, off, dim) of visibility depends on two bools: + // GetViewToggleOff and IsEnabled. Ensure that any bogus 4th permutation + // is detected ASAP + // ASSERT( !inStateRow->GetState( )->GetViewToggleOff( ) || + // !inStateRow->GetState( )->IsEnabled( ) ); +} + +CToggleControl::~CToggleControl() +{ + delete m_Shy; + delete m_Visible; + delete m_Locked; +} + +//============================================================================== +/** + * Handles clicking on the Shy button. Toggles the shy state on the asset. Shy + * objects can be filtered out of the timeline. + */ +void CToggleControl::OnShyClicked(CToggleButton *, CToggleButton::EButtonState inButtonState) +{ + m_TimelineItemBinding->GetTimelineItem()->SetShy(inButtonState + == CToggleButton::EBUTTONSTATE_DOWN); + + m_StateRow->Filter(*m_StateRow->GetFilter()); + CBaseStateRow *theParentRow = m_StateRow->GetParentRow(); + if (theParentRow != nullptr) + theParentRow->OnChildVisibilityChanged(); +} + +//============================================================================== +/** + * Handles clicking on the Visible button. Toggles the Visible state on the asset. + */ +void CToggleControl::OnVisibleClicked(CToggleButton *inButton, + CToggleButton::EButtonState inButtonState) +{ + Q_UNUSED(inButton); + + m_TimelineItemBinding->GetTimelineItem()->SetVisible(inButtonState + == CToggleButton::EBUTTONSTATE_DOWN); + m_StateRow->Filter(*m_StateRow->GetFilter()); +} + +//============================================================================== +/** + * Handles clicking on the Lock button. Toggles the Lock state on the asset. + */ +void CToggleControl::OnLockClicked(CToggleButton *inButton, + CToggleButton::EButtonState inButtonState) +{ + Q_UNUSED(inButton); + + m_TimelineItemBinding->GetTimelineItem()->SetLocked(inButtonState + == CToggleButton::EBUTTONSTATE_DOWN); + m_StateRow->Filter(*m_StateRow->GetFilter()); +} + +//============================================================================== +/** + * Refreshes the state of this control accd to the asset state + */ +void CToggleControl::Refresh() +{ + CBlankToggleControl::Refresh(); + + ITimelineItem *theTimelineItem = m_TimelineItemBinding->GetTimelineItem(); + m_Shy->SetToggleState(theTimelineItem->IsShy()); + m_Locked->SetToggleState(theTimelineItem->IsLocked()); + + bool theEnabled = m_TimelineItemBinding->IsVisibleEnabled(); + m_Visible->SetEnabled(theEnabled); + if (theEnabled) // only valid to update this if the enabled flag is true. + m_Visible->SetToggleState(theTimelineItem->IsVisible()); + + this->Invalidate(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h new file mode 100644 index 00000000..49caaff8 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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_TOGGLE_CONTROL_H +#define INCLUDED_TOGGLE_CONTROL_H 1 + +#pragma once + +#include "BlankToggleControl.h" +#include "ToggleButton.h" + +class CStateRow; +class CBlankControl; +class ITimelineItemBinding; + +class CToggleControl : public CBlankToggleControl +{ +public: + CToggleControl(CStateRow *inStateRow, ITimelineItemBinding *inTimelineItemBinding); + virtual ~CToggleControl(); + + void OnShyClicked(CToggleButton *inButton, CToggleButton::EButtonState inState); + void OnVisibleClicked(CToggleButton *inButton, CToggleButton::EButtonState inState); + void OnLockClicked(CToggleButton *inButton, CToggleButton::EButtonState inState); + + void Refresh() override; + +protected: + CStateRow *m_StateRow; + + CToggleButton *m_Shy; + CToggleButton *m_Visible; + CToggleButton *m_Locked; + + ITimelineItemBinding *m_TimelineItemBinding; +}; +#endif // INCLUDED_TOGGLE_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp new file mode 100644 index 00000000..7dadde19 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#include "stdafx.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "ToggleToolbar.h" +#include "SIcon.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "TimelineTreeLayout.h" + +//============================================================================= +/** + * Constructor + */ +CToggleToolbar::CToggleToolbar(CTimelineTreeLayout *inTreeLayout) + : CFlowLayout(new CBlankControl(CStudioPreferences::GetTopRowColor())) +{ + m_TreeLayout = inTreeLayout; + + m_Color = CStudioPreferences::GetBaseColor(); + + SetFlowDirection(FLOW_HORIZONTAL); + SetAlignment(ALIGN_TOP, ALIGN_LEFT); + SetLeftMargin(1); + + CProceduralButton<CToggleButton>::SBorderOptions theBorderOptions(false, true, true, true); + + m_FltrShyBtn = new CProceduralButton<CToggleButton>(); + m_FltrShyBtn->SetUpImage("Toggle-Shy.png"); + m_FltrShyBtn->SetDownImage("Toggle-Shy.png"); + m_FltrShyBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrShyBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize()); + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2)); + m_FltrShyBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + AddChild(m_FltrShyBtn); + m_FltrShyBtn->SetToggleState(false); + + m_FltrVisibleBtn = new CProceduralButton<CToggleButton>(); + m_FltrVisibleBtn->SetUpImage("filter-toggle-eye-up.png"); + m_FltrVisibleBtn->SetDownImage("filter-toggle-eye-down.png"); + m_FltrVisibleBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrVisibleBtn->SetAbsoluteSize(m_FltrVisibleBtn->GetSize()); + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2)); + m_FltrVisibleBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + AddChild(m_FltrVisibleBtn); + m_FltrVisibleBtn->SetToggleState(false); + + m_FltrLockBtn = new CProceduralButton<CToggleButton>(); + m_FltrLockBtn->SetUpImage("Toggle-Lock.png"); + m_FltrLockBtn->SetDownImage("Toggle-Lock.png"); + m_FltrLockBtn->SetBorderVisibilityAll(theBorderOptions); + m_FltrLockBtn->SetAbsoluteSize(m_FltrLockBtn->GetSize()); + m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK2)); + m_FltrLockBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this, + std::placeholders::_1, std::placeholders::_2)); + AddChild(m_FltrLockBtn); + m_FltrLockBtn->SetToggleState(false); +} + +//============================================================================= +/** + * Destructor + */ +CToggleToolbar::~CToggleToolbar() +{ + delete m_FltrShyBtn; + delete m_FltrVisibleBtn; + delete m_FltrLockBtn; +} + +//============================================================================= +/** + * Fills in the background color and highlighting for this control. + */ +void CToggleToolbar::Draw(CRenderer *inRenderer) +{ + CRct theRect(0, 0, GetSize().x, GetSize().y - 1); + inRenderer->FillSolidRect(theRect, m_Color); + CFlowLayout::Draw(inRenderer); + inRenderer->Draw3dRect(theRect, CStudioPreferences::GetButtonShadowColor(), + CStudioPreferences::GetButtonShadowColor()); + + // Draw the highlight at the bottom + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CPt(0, theRect.size.y)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y)); + inRenderer->PopPen(); + + // Draw the one pixel on the end of the highlight that has to be dark + // Apparently there's some problems trying to draw one pixel, so clip the excess + inRenderer->PushClippingRect(QRect(0, 0, GetSize().x, GetSize().y)); + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + inRenderer->MoveTo(CPt(theRect.size.x, theRect.size.y)); + inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y)); + inRenderer->PopPen(); + inRenderer->PopClippingRect(); +} + +//============================================================================= +/** + * Handles turning a filter on or off in response to a button being pressed. + * @param inButton button that generated the event + * @param inState new state of the button after being toggled + */ +void CToggleToolbar::OnButtonToggled(CToggleButton *inButton, CButtonControl::EButtonState inState) +{ + bool theFilterNeedsApplied = (inState == CButtonControl::EBUTTONSTATE_UP); + + if (inButton == m_FltrShyBtn) + FilterShy(theFilterNeedsApplied); + else if (inButton == m_FltrVisibleBtn) + FilterVisible(theFilterNeedsApplied); + else if (inButton == m_FltrLockBtn) + FilterLocked(theFilterNeedsApplied); +} + +//============================================================================= +/** + * Turns filtering on and off for shy objects. + * @param inFilter true to filter shy objects out of the timeline, false to show + * shy objects in the timeline. + */ +void CToggleToolbar::FilterShy(bool inFilter) +{ + if (inFilter) + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2)); + else + m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY1)); + + m_TreeLayout->GetFilter()->SetShy(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for visible objects. + * @param inFilter true to filter visible objects out of the timeline, false to show + * visible objects in the timeline. + */ +void CToggleToolbar::FilterVisible(bool inFilter) +{ + if (inFilter) + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2)); + else + m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE1)); + + m_TreeLayout->GetFilter()->SetVisible(inFilter); + m_TreeLayout->Filter(); +} + +//============================================================================= +/** + * Turns filtering on and off for locked objects. + * @param inFilter true to filter locked objects out of the timeline, false to show + * locked objects in the timeline. + */ +void CToggleToolbar::FilterLocked(bool inFilter) +{ + if (inFilter) + m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK2)); + else + m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK1)); + + m_TreeLayout->GetFilter()->SetLocked(inFilter); + m_TreeLayout->Filter(); +} diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h new file mode 100644 index 00000000..a0f95e62 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#ifndef INCLUDED_TOGGLE_TOOLBAR_H +#define INCLUDED_TOGGLE_TOOLBAR_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "FlowLayout.h" +#include "ProceduralButton.h" +#include "ToggleButton.h" + +//============================================================================== +// Forwards +//============================================================================== + +class CRenderer; +class CTimelineTreeLayout; +// class CSIcon; + +//============================================================================= +/** + * Control at the top of the time display and a header for the toggle column. + */ +class CToggleToolbar : public CFlowLayout +{ +public: + CToggleToolbar(CTimelineTreeLayout *inTreeLayout); + virtual ~CToggleToolbar(); + void Draw(CRenderer *inRenderer) override; + + void FilterShy(bool inFilter); + void FilterVisible(bool inFilter); + void FilterLocked(bool inFilter); + void OnButtonToggled(CToggleButton *inButton, CToggleButton::EButtonState inState); + +protected: + // CSIcon* m_ShyIcon; + // CSIcon* m_VisibilityIcon; + // CSIcon* m_LockIcon; + CProceduralButton<CToggleButton> *m_FltrShyBtn; + CProceduralButton<CToggleButton> *m_FltrVisibleBtn; + CProceduralButton<CToggleButton> *m_FltrLockBtn; + CTimelineTreeLayout *m_TreeLayout; + CColor m_Color; +}; + +#endif // INCLUDED_TOGGLE_TOOLBAR_H diff --git a/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp new file mode 100644 index 00000000..b49eabb5 --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TreeBlankControl.h" +#include "Renderer.h" + +//============================================================================= +/** + * Constructor + */ +CTreeBlankControl::CTreeBlankControl(CColor inColor) + : CBlankControl(inColor) + , m_LeftEdgeOffset(0) +{ +} + +//============================================================================= +/** + * Destructor + */ +CTreeBlankControl::~CTreeBlankControl() +{ +} + +//============================================================================= +/** + * Handles custom drawing of the blank control underneath the tree control + * on the timeline palette. + */ +void CTreeBlankControl::Draw(CRenderer *inRenderer) +{ + CBlankControl::Draw(inRenderer); + + // Draw the highlight on the left side of this control + CPt theSize = GetSize(); + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(CStudioPreferences::GetRowSize() + m_LeftEdgeOffset, 0); + inRenderer->LineTo(CStudioPreferences::GetRowSize() + m_LeftEdgeOffset, theSize.y - 1); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * xxx + */ +void CTreeBlankControl::SetVisiblePositionX(long inPosition) +{ + m_LeftEdgeOffset = inPosition; +}
\ No newline at end of file diff --git a/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h new file mode 100644 index 00000000..0d0df3ab --- /dev/null +++ b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2002 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_TREE_BLANK_CONTROL_H +#define INCLUDED_TREE_BLANK_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BlankControl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================= +/** + * Extends the blank control to draw items specific to the tree view side of the + * timeline palette. + */ +class CTreeBlankControl : public CBlankControl +{ +public: + CTreeBlankControl(CColor inColor = CStudioPreferences::GetBaseColor()); + virtual ~CTreeBlankControl(); + void Draw(CRenderer *inRenderer) override; + void SetVisiblePositionX(long inPosition); + +protected: + long m_LeftEdgeOffset; ///< Visibility offset of the left edge in case timeline is scrolled + ///horizontally +}; + +#endif // INCLUDED_TREE_BLANK_CONTROL_H diff --git a/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml b/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml new file mode 100644 index 00000000..0e8bcb55 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml @@ -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$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.3 + +MouseArea { + id: root + + property alias value: value.text + property var activeBrowser + property bool blockShow: false + + signal showBrowser + + Layout.minimumHeight: _controlBaseHeight + Layout.preferredWidth: _valueWidth + + onPressed: { + // Block showBrowser event on the mouse press that makes the browser lose focus + if (activeBrowser && activeBrowser.visible) { + activeBrowser = null; + blockShow = true + } else { + blockShow = false + } + } + + onClicked: { + if (!blockShow) + root.showBrowser() + } + + Rectangle { + anchors.fill: parent + + color: _studioColor2 + + StyledLabel { + id: value + anchors.fill: parent + horizontalAlignment: Text.AlignLeft + rightPadding: 6 + img.width + leftPadding: 6 + } + Image { + id: img + x: parent.width - sourceSize.width - 2 + y: (parent.height - sourceSize.height) / 2 + source: _resDir + "arrow_down.png" + } + } +} diff --git a/src/Authoring/Studio/Palettes/controls/FloatTextField.qml b/src/Authoring/Studio/Palettes/controls/FloatTextField.qml new file mode 100644 index 00000000..bea65443 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/FloatTextField.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.1 +import QtQuick.Layouts 1.3 + +/* Use for: Position, Rotation, Scale, Pivot ... */ + +TextField { + id: floatTextFieldId + property alias decimalValue: validator.decimals + + signal wheelEventFinished + + selectByMouse: true + text: "0.000" + Layout.preferredWidth: _valueWidth / 2 + Layout.preferredHeight: _controlBaseHeight + + topPadding: 0 + bottomPadding: 0 + rightPadding: 6 + + horizontalAlignment: TextInput.AlignRight + verticalAlignment: TextInput.AlignVCenter + validator: DoubleValidator { + id: validator + decimals: 3 + locale: "C" + } + + selectionColor: _selectionColor + selectedTextColor: _textColor + font.pixelSize: _fontSize + color: _textColor + background: Rectangle { + color: floatTextFieldId.enabled ? _studioColor2 : "transparent" + border.width: floatTextFieldId.activeFocus ? 1 : 0 + border.color: floatTextFieldId.activeFocus ? _selectionColor : _disabledColor + } + + MouseArea { + property int _clickedPos + id: mouseAreaBaseId + + anchors.fill: parent + onPressed: { + parent.forceActiveFocus() + _clickedPos = parent.positionAt(mouse.x, mouse.y) + parent.cursorPosition = _clickedPos + } + onDoubleClicked: parent.selectAll() + onPositionChanged: { + parent.cursorPosition = parent.positionAt(mouse.x, mouse.y) + parent.select(_clickedPos, parent.cursorPosition) + } + + onWheel: { + if (!floatTextFieldId.activeFocus) { + wheel.accepted = false + return + } + if (wheel.angleDelta.y > 0) { + floatTextFieldId.text++ + } else { + floatTextFieldId.text-- + } + wheel.accepted=true + floatTextFieldId.wheelEventFinished(); + } + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml b/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml new file mode 100644 index 00000000..ff079f41 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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 QtQuick.Window 2.2 + +ComboBox { + id: control + Layout.preferredHeight: _controlBaseHeight + Layout.preferredWidth: _valueWidth + topPadding: 0 + bottomPadding: 0 + + delegate: ItemDelegate { + id: itemDelegate + + property bool hasSeparator: itemDelegate.text.endsWith("|separator") + + width: parent.width + height: hasSeparator ? _controlBaseHeight + 6 : _controlBaseHeight + padding: 0 + spacing: 0 + text: { + control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] + : model[control.textRole]) + : modelData + } + highlighted: control.highlightedIndex === index + hoverEnabled: control.hoverEnabled + contentItem: ColumnLayout { + anchors.fill: itemDelegate + spacing: 0 + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + color: _studioColor3 + visible: itemDelegate.hasSeparator + } + StyledLabel { + Layout.fillWidth: true + rightPadding: control.indicator.width + 6 + leftPadding: 6 + text: { + hasSeparator ? itemDelegate.text.replace("|separator", "") + : itemDelegate.text + } + visible: itemDelegate.text + horizontalAlignment: Text.AlignLeft + } + } + background: Rectangle { + anchors.fill: itemDelegate + color: hovered ? _selectionColor : _studioColor2 + } + } + + indicator: Image { + x: control.width - width - 2 + y: control.topPadding + (control.availableHeight - height) / 2 + source: _resDir + "arrow_down.png" + sourceSize.width: width + sourceSize.height: height + } + + contentItem: StyledTextField { + text: { + var newText = control.editable ? control.editText : control.displayText; + var hasSeparator = newText.endsWith("|separator"); + hasSeparator ? newText.replace("|separator", "") : newText; + } + + enabled: control.editable + autoScroll: control.editable + readOnly: control.popup.visible + inputMethodHints: control.inputMethodHints + validator: control.validator + opacity: 1 + leftPadding: 6 + horizontalAlignment: Text.AlignLeft + } + + background: Rectangle { + color: control.enabled ? _studioColor2 : "transparent" + border.width: 0 + } + + popup: Popup { + y: control.height + width: control.width + height: Math.min(contentItem.implicitHeight, + control.Window.height - topMargin - bottomMargin) + topMargin: 6 + bottomMargin: 6 + padding: 0 + + contentItem: ListView { + clip: true + implicitHeight: contentHeight + model: control.popup.visible ? control.delegateModel : null + currentIndex: control.highlightedIndex + highlightRangeMode: ListView.ApplyRange + highlightMoveDuration: 0 + ScrollIndicator.vertical: ScrollIndicator { + id: scrollIndicator + contentItem: Rectangle { + id: indicator + + implicitWidth: 2 + implicitHeight: 2 + + color: _studioColor3 + visible: scrollIndicator.size < 1.0 + opacity: 0.75 + } + } + Rectangle { + z: 10 + anchors.fill: parent + color: "transparent" + border.color: _studioColor3 + } + } + + background: Rectangle { + color: _studioColor2 + } + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledLabel.qml b/src/Authoring/Studio/Palettes/controls/StyledLabel.qml new file mode 100644 index 00000000..02016069 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledLabel.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 + +Label { + id: styledLabelId + font.pixelSize: _fontSize + color: _textColor + Layout.preferredHeight: _controlBaseHeight + Layout.preferredWidth: _idWidth + verticalAlignment: Text.AlignVCenter + clip: true +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml b/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml new file mode 100644 index 00000000..361d5876 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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.1 +import QtQuick.Layouts 1.3 + +MenuItem { + id: control + hoverEnabled: true + + contentItem: StyledLabel { + text: control.text + visible: control.text + horizontalAlignment: Text.AlignLeft + color: control.enabled ? _textColor : _disabledColor + } + background: Rectangle { + implicitWidth: _valueWidth + implicitHeight: _controlBaseHeight + color: control.hovered ? _selectionColor : _studioColor1 + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml b/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml new file mode 100644 index 00000000..532fee2c --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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.1 + +MenuSeparator { + id: control + padding: 0 + topPadding: 4 + bottomPadding: 4 + leftPadding: 0 + rightPadding: 0 + contentItem: Rectangle { + width: control.width + implicitWidth: control.parent.width - control.leftPadding - control.rightPadding + implicitHeight: 1 + color: _studioColor3 + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledTextField.qml b/src/Authoring/Studio/Palettes/controls/StyledTextField.qml new file mode 100644 index 00000000..da621314 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledTextField.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.1 +import QtQuick.Layouts 1.3 + +TextField { + id: styledTextFieldId + + property alias backgroundColor: textBackground.color + + Layout.preferredWidth: _valueWidth + Layout.preferredHeight: _controlBaseHeight + horizontalAlignment: TextInput.AlignRight + verticalAlignment: TextInput.AlignVCenter + + topPadding: 0 + bottomPadding: 0 + rightPadding: 6 + + selectByMouse: true + selectionColor: _selectionColor + selectedTextColor: _textColor + + font.pixelSize: _fontSize + color: _textColor + background: Rectangle { + id: textBackground + color: styledTextFieldId.enabled ? _studioColor2 : "transparent" + border.width: styledTextFieldId.activeFocus ? 1 : 0 + border.color: styledTextFieldId.activeFocus ? _selectionColor : _disabledColor + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml b/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml new file mode 100644 index 00000000..51654331 --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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.1 + +ToolButton { + id: control + + property string enabledImage + property string disabledImage + property alias toolTipText: toolTip.text + + hoverEnabled: true + + StyledTooltip { + id: toolTip + visible: control.hovered + } + + background: Rectangle { + color: control.pressed ? _selectionColor : (hovered ? _studioColor1 : "transparent") + border.color: _studioColor1 + } + + contentItem: Image { + source: control.enabled ? _resDir + enabledImage : _resDir + disabledImage + } +} diff --git a/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml b/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml new file mode 100644 index 00000000..cae9c59f --- /dev/null +++ b/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** 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.1 + +ToolTip { + id: control + delay: 500 + contentItem: StyledLabel { + text: control.text + } + + background: Rectangle { + border.color: _studioColor3 + color: _studioColor2 + radius: 2 + } +} |