diff options
Diffstat (limited to 'src/Authoring/Studio')
35 files changed, 785 insertions, 47 deletions
diff --git a/src/Authoring/Studio/Application/FilterVariantsDlg.cpp b/src/Authoring/Studio/Application/FilterVariantsDlg.cpp new file mode 100644 index 00000000..b6213c4a --- /dev/null +++ b/src/Authoring/Studio/Application/FilterVariantsDlg.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "FilterVariantsDlg.h" +#include "StudioPreferences.h" +#include "StudioUtils.h" +#include "FilterVariantsModel.h" + +#include <QAction> +#include <QtCore/qtimer.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlengine.h> + +FilterVariantsDlg::FilterVariantsDlg(QWidget *parent, QAction *action, int actionSize) + : QQuickWidget(parent) + , m_model(new FilterVariantsModel(m_variantsFilter, this)) + , m_action(action) + , m_actionSize(actionSize) +{ + setWindowTitle(tr("Filter variants")); + QTimer::singleShot(0, this, &FilterVariantsDlg::initialize); +} + +void FilterVariantsDlg::initialize() +{ + CStudioPreferences::setQmlContextProperties(rootContext()); + rootContext()->setContextProperty(QStringLiteral("_view"), this); + rootContext()->setContextProperty(QStringLiteral("_model"), m_model); + setSource(QUrl(QStringLiteral("qrc:/Application/FilterVariantsDlg.qml"))); +} + +QString FilterVariantsDlg::filterStr() const +{ + QString ret; + if (!m_variantsFilter.isEmpty()) { + const auto groups = m_variantsFilter.keys(); + for (auto &g : groups) { + const auto group = m_variantsFilter[g]; + for (auto &tag : group) + ret.append(g + QLatin1Char(':') + tag + QLatin1Char(',')); + } + + if (!m_variantsFilter.isEmpty()) + ret.chop(1); + } + + return ret; +} + +int FilterVariantsDlg::actionSize() const +{ + return m_actionSize; +} + +void FilterVariantsDlg::showEvent(QShowEvent *event) +{ + m_model->refresh(); + QQuickWidget::showEvent(event); +} + +void FilterVariantsDlg::focusOutEvent(QFocusEvent *e) +{ + QQuickWidget::focusOutEvent(e); + m_action->setChecked(false); + QTimer::singleShot(0, this, &QQuickWidget::close); +} + +void FilterVariantsDlg::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Escape) { + m_action->setChecked(false); + QTimer::singleShot(0, this, &FilterVariantsDlg::close); + } + + QQuickWidget::keyPressEvent(e); +} diff --git a/src/Authoring/Studio/Application/FilterVariantsDlg.h b/src/Authoring/Studio/Application/FilterVariantsDlg.h new file mode 100644 index 00000000..ed2fd8a4 --- /dev/null +++ b/src/Authoring/Studio/Application/FilterVariantsDlg.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 FILTER_VARIANTS_DLG_H +#define FILTER_VARIANTS_DLG_H + +#include <QtQuickWidgets/qquickwidget.h> + +class FilterVariantsModel; + +class FilterVariantsDlg : public QQuickWidget +{ + Q_OBJECT + +public: + explicit FilterVariantsDlg(QWidget *parent, QAction *action, int actionSize); + + Q_INVOKABLE int actionSize() const; + + QString filterStr() const; + +protected: + void focusOutEvent(QFocusEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + +private: + void showEvent(QShowEvent *event) override; + + void initialize(); + + QHash<QString, QSet<QString> > m_variantsFilter; // key: group, value: tags + FilterVariantsModel *m_model = nullptr; + QAction *m_action = nullptr; + int m_actionSize = 0; // width/height of the action icon +}; + +#endif // FILTER_VARIANTS_DLG_H diff --git a/src/Authoring/Studio/Application/FilterVariantsDlg.qml b/src/Authoring/Studio/Application/FilterVariantsDlg.qml new file mode 100644 index 00000000..1f971509 --- /dev/null +++ b/src/Authoring/Studio/Application/FilterVariantsDlg.qml @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +Rectangle { + id: root + width: 400 + height: 280 + color: _backgroundColor + border.color: _studioColor3 + + // hider for the border segment between the icon and the dialog + Rectangle { + color: _backgroundColor + x: 1 + width: _view.actionSize() - 2 // -1px from each side + height: 1 + } + + Item { + height: 25 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 10 + + Text { + text: qsTr("Select filtering") + color: _studioColor4 + font.pointSize: 10 + anchors.verticalCenter: parent.verticalCenter + } + + Rectangle { // clear button + width: 60 + height: 25 + color: _backgroundColor + border.color: _studioColor4 + anchors.right: parent.right + + Text { + anchors.centerIn: parent + text: qsTr("Clear") + font.pointSize: 10 + color: _studioColor4 + } + + MouseArea { + anchors.fill: parent + onClicked: _model.clearAll(); + } + } + } + + Flickable { + anchors.top: parent.top + anchors.topMargin: 35 + anchors.fill: parent + contentWidth: variantsColumn.width + contentHeight: variantsColumn.height + flickableDirection: Flickable.VerticalFlick + clip: true + + ScrollBar.vertical: ScrollBar {} + + Column { + id: variantsColumn + spacing: 10 + padding: 10 + + Repeater { // groups + id: tagsRepeater + model: _model + property int maxGroupLabelWidth; + + onItemAdded: { + // make all group labels have equal width as the widest one + if (index == 0) + maxGroupLabelWidth = 20; // min group label width + + if (item.groupLabelWidth > maxGroupLabelWidth) { + maxGroupLabelWidth = item.groupLabelWidth; + + if (maxGroupLabelWidth > 150) // max group label width + maxGroupLabelWidth = 150; + } + } + + Row { // a row of a group and its tags + spacing: 5 + + readonly property var tagsModel: model.tags + readonly property var groupModel: model + readonly property int groupLabelWidth: tLabel.implicitWidth + 10 + + Rectangle { // group button + width: tagsRepeater.maxGroupLabelWidth; + height: 25 + color: _backgroundColor + border.color: model.color + + Text { + id: tLabel + text: model.group + color: model.color + elide: Text.ElideRight + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent; + onClicked: _model.toggleGroupState(model.group); + } + } + + Flow { // group tags + width: root.width - tagsRepeater.maxGroupLabelWidth - 15 + spacing: 5 + + Repeater { + model: tagsModel + + Loader { + readonly property var tagsModel: model + readonly property var grpModel: groupModel + sourceComponent: tagComponent + } + } + } + } + } + } + } + + Component { + id: tagComponent + + Rectangle { + property bool toggled: tagsModel ? tagsModel.selected : false + property string grpColor: grpModel ? grpModel.color : "" + + width: Math.max(tLabel.width + 10, 60) + height: 25 + color: toggled ? grpColor : _backgroundColor + border.color: toggled ? _studioColor4 : grpColor; + + Text { + id: tLabel + anchors.centerIn: parent + text: tagsModel ? tagsModel.tag : "" + color: toggled ? _textColor : _studioColor4 + } + + MouseArea { + anchors.fill: parent + onClicked: { + toggled = !toggled; + _model.setTagState(grpModel.group, tagsModel.tag, toggled); + } + } + } + } +} diff --git a/src/Authoring/Studio/Application/FilterVariantsModel.cpp b/src/Authoring/Studio/Application/FilterVariantsModel.cpp new file mode 100644 index 00000000..e7badfd0 --- /dev/null +++ b/src/Authoring/Studio/Application/FilterVariantsModel.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "FilterVariantsModel.h" +#include "VariantsTagModel.h" +#include "StudioApp.h" +#include "Views.h" +#include "MainFrm.h" +#include "Core.h" +#include "VariantTagDialog.h" + +FilterVariantsModel::FilterVariantsModel(VariantsFilterT &variantsFilter, QObject *parent) + : QAbstractListModel(parent) + , m_variantsFilter(variantsFilter) +{ + +} + +void FilterVariantsModel::refresh() +{ + beginResetModel(); + + // delete tag models + for (auto &g : qAsConst(m_data)) + delete g.m_tagsModel; + + m_data.clear(); + + // build the variants data model + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + const auto keys = variantsDef.keys(); + for (auto &group : keys) { + VariantsGroupData g; + g.m_title = group; + g.m_color = variantsDef[group].m_color; + QVector<std::pair<QString, bool> > tags; + for (int i = 0; i < variantsDef[group].m_tags.length(); ++i) { + QString tag = variantsDef[group].m_tags[i]; + bool state = m_variantsFilter.contains(group) && m_variantsFilter[group].contains(tag); + tags.append({tag, state}); + } + g.m_tagsModel = new VariantsTagModel(tags); + m_data.push_back(g); + } + + endResetModel(); +} + +int FilterVariantsModel::rowCount(const QModelIndex &parent) const +{ + // For list models only the root node (an invalid parent) should return the list's size. For all + // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. + if (parent.isValid()) + return 0; + + return m_data.size(); +} + +QVariant FilterVariantsModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == GroupTitleRole) + return m_data.at(index.row()).m_title; + else if (role == GroupColorRole) + return m_data.at(index.row()).m_color; + else if (role == TagsRole) + return QVariant::fromValue(m_data.at(index.row()).m_tagsModel); + + return QVariant(); +} + +void FilterVariantsModel::setTagState(const QString &group, const QString &tag, bool selected) +{ + if (selected) + m_variantsFilter[group].insert(tag); + else + m_variantsFilter[group].remove(tag); + + bool filtered = false; + for (auto &g : qAsConst(m_variantsFilter)) { + if (!g.isEmpty()) { + filtered = true; + break; + } + } + + g_StudioApp.GetViews()->getMainFrame()->updateActionPreviewVariantsState(filtered); +} + +void FilterVariantsModel::toggleGroupState(const QString &group) +{ + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + + if (m_variantsFilter[group].size() < variantsDef[group].m_tags.size()) { + // not all tags selected, select all + const auto tags = variantsDef[group].m_tags; + for (auto &t : tags) + m_variantsFilter[group].insert(t); + } else { + // all tags selected, select none + m_variantsFilter[group].clear(); + } + refresh(); + + bool filtered = false; + for (auto &g : qAsConst(m_variantsFilter)) { + if (!g.isEmpty()) { + filtered = true; + break; + } + } + + g_StudioApp.GetViews()->getMainFrame()->updateActionPreviewVariantsState(filtered); +} + +void FilterVariantsModel::clearAll() +{ + m_variantsFilter.clear(); + refresh(); + g_StudioApp.GetViews()->getMainFrame()->updateActionPreviewVariantsState(false); +} + +QHash<int, QByteArray> FilterVariantsModel::roleNames() const +{ + auto names = QAbstractListModel::roleNames(); + names.insert(GroupTitleRole, "group"); + names.insert(GroupColorRole, "color"); + names.insert(TagsRole, "tags"); + return names; +} + +Qt::ItemFlags FilterVariantsModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + + return Qt::ItemIsEditable; +} diff --git a/src/Authoring/Studio/Application/FilterVariantsModel.h b/src/Authoring/Studio/Application/FilterVariantsModel.h new file mode 100644 index 00000000..86df5377 --- /dev/null +++ b/src/Authoring/Studio/Application/FilterVariantsModel.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 VARIANTSGROUPMODEL_H +#define VARIANTSGROUPMODEL_H + +#include <QtCore/qabstractitemmodel.h> + +class VariantsTagModel; + +using VariantsFilterT = QHash<QString, QSet<QString> >; + +class FilterVariantsModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit FilterVariantsModel(VariantsFilterT &variantsFilter, QObject *parent = nullptr); + + enum Roles { + GroupTitleRole = Qt::UserRole + 1, + GroupColorRole, + TagsRole + }; + + struct VariantsGroupData + { + QString m_title; + QString m_color; + VariantsTagModel *m_tagsModel = nullptr; + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = GroupTitleRole) const override; + + Qt::ItemFlags flags(const QModelIndex& index) const override; + + void refresh(); + + Q_INVOKABLE void setTagState(const QString &group, const QString &tag, bool selected); + Q_INVOKABLE void toggleGroupState(const QString &group); + Q_INVOKABLE void clearAll(); + +protected: + QHash<int, QByteArray> roleNames() const override; + +private: + VariantsFilterT &m_variantsFilter; + QVector<VariantsGroupData> m_data; +}; + +#endif // VARIANTSGROUPMODEL_H diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp index 1bd847e7..b444b2d9 100644 --- a/src/Authoring/Studio/Application/StudioApp.cpp +++ b/src/Authoring/Studio/Application/StudioApp.cpp @@ -1730,6 +1730,7 @@ bool CStudioApp::OnLoadDocument(const QString &inDocument, bool inShowStartupDia m_core->getProjectFile().loadSubpresentationsAndDatainputs(m_subpresentations, m_dataInputDialogItems); m_core->getProjectFile().loadVariants(); + GetViews()->getMainFrame()->updateActionFilterEnableState(); GetViews()->getMainFrame()->getSlideView()->refreshVariants(); getRenderer().RegisterSubpresentations(m_subpresentations); diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp index 0acd00e8..3069304e 100644 --- a/src/Authoring/Studio/MainFrm.cpp +++ b/src/Authoring/Studio/MainFrm.cpp @@ -61,6 +61,7 @@ #include "RowTree.h" #include "WidgetControl.h" #include "SlideView.h" +#include "FilterVariantsDlg.h" #include <QtGui/qevent.h> #include <QtGui/qdesktopservices.h> @@ -91,6 +92,10 @@ CMainFrame::CMainFrame() { m_ui->setupUi(this); + // allow styling this action + m_ui->m_PlaybackToolbar->widgetForAction(m_ui->actionFilterVariants) + ->setObjectName("actionFilterVariants"); + // Register TitilliumWeb as application font in case user doesn't have it already installed QFontDatabase::addApplicationFont(QStringLiteral(":/TitilliumWeb-Light.ttf")); QFontDatabase::addApplicationFont(QStringLiteral(":/TitilliumWeb-Regular.ttf")); @@ -219,8 +224,8 @@ CMainFrame::CMainFrame() m_sceneView.data(), &CSceneView::onToolGroupSelection); // Playback toolbar - connect(m_ui->actionPreview, &QAction::triggered, - this, &CMainFrame::OnPlaybackPreviewRuntime2); + connect(m_ui->actionPreview, &QAction::triggered, this, &CMainFrame::OnPlaybackPreviewRuntime2); + connect(m_ui->actionFilterVariants, &QAction::triggered, this, &CMainFrame::onFilterVariants); connect(m_ui->actionRemote_Preview, &QAction::triggered, this, &CMainFrame::OnPlaybackPreviewRemote); @@ -1040,6 +1045,58 @@ void CMainFrame::OnPlaybackPreviewRuntime2() OnPlaybackPreview(QStringLiteral("q3dsviewer")); } +void CMainFrame::onFilterVariants() +{ + if (m_ui->actionFilterVariants->isChecked()) { + QTimer::singleShot(0, [&] { + QRect actionGeom = m_ui->m_PlaybackToolbar->actionGeometry(m_ui->actionFilterVariants); + if (!m_filterVariantsDlg) { + m_filterVariantsDlg = new FilterVariantsDlg(this, m_ui->actionFilterVariants, + actionGeom.width()); + } + + m_filterVariantsDlg->activateWindow(); + m_filterVariantsDlg->raise(); + m_filterVariantsDlg->move(m_ui->m_PlaybackToolbar->pos() + + QPoint(actionGeom.x(), actionGeom.bottom())); + m_filterVariantsDlg->setFocus(); + m_filterVariantsDlg->show(); + }); + } else { + m_filterVariantsDlg->close(); + } +} + +QString CMainFrame::getVariantsFilterStr() const +{ + if (m_filterVariantsDlg) + return m_filterVariantsDlg->filterStr(); + + return {}; +} + +void CMainFrame::updateActionFilterEnableState() +{ + bool enable = false; + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + const auto keys = variantsDef.keys(); + for (auto &group : keys) { + if (!variantsDef[group].m_tags.isEmpty()) { + enable = true; + break; + } + } + + m_ui->actionFilterVariants->setEnabled(enable); +} + +void CMainFrame::updateActionPreviewVariantsState(bool isFiltered) +{ + m_ui->actionPreview->setIcon(QIcon(isFiltered + ? QStringLiteral(":/images/playplayback-variant.png") + : QStringLiteral(":/images/playback_tools_low-03.png"))); +} + void CMainFrame::OnPlaybackPreviewRemote() { OnPlaybackPreview(QStringLiteral("q3dsviewer"), true); @@ -1927,6 +1984,13 @@ SlideView *CMainFrame::getSlideView() const ->widget()); } +InspectorControlView *CMainFrame::getInspectorView() const +{ + return static_cast<InspectorControlView *>(m_paletteManager + ->GetControl(CPaletteManager::CONTROLTYPE_INSPECTOR) + ->widget()); +} + CRecentItems *CMainFrame::GetRecentItems() { return m_recentItems.data(); diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h index 6c3a2ce7..5f7cd0d0 100644 --- a/src/Authoring/Studio/MainFrm.h +++ b/src/Authoring/Studio/MainFrm.h @@ -57,6 +57,8 @@ class RemoteDeploymentSender; class TimelineWidget; class CStudioPreferencesPropSheet; class SlideView; +class InspectorControlView; +class FilterVariantsDlg; #ifdef QT_NAMESPACE using namespace QT_NAMESPACE; @@ -158,6 +160,7 @@ public: void OnPlaybackPreviewRuntime1(); void OnPlaybackPreviewRuntime2(); void OnPlaybackPreviewRemote(); + void onFilterVariants(); void OnUpdatePlaybackPreview(); void OnUpdateToolMove(); void OnUpdateToolRotate(); @@ -237,6 +240,7 @@ public: TimelineWidget *getTimelineWidget() const; SlideView *getSlideView() const; + InspectorControlView *getInspectorView() const; void EditPreferences(short inPageIndex); @@ -250,6 +254,9 @@ public: void toggleSelectMode(); void showScene(); + QString getVariantsFilterStr() const; + void updateActionFilterEnableState(); + void updateActionPreviewVariantsState(bool isFiltered); Q_SIGNALS: void playStateChanged(bool started); @@ -270,6 +277,9 @@ protected: bool m_playbackFlag = false; bool m_resettingLayout = false; + +private: + FilterVariantsDlg *m_filterVariantsDlg = nullptr; }; #endif // INCLUDED_MAIN_FRAME diff --git a/src/Authoring/Studio/MainFrm.ui b/src/Authoring/Studio/MainFrm.ui index 7c15e262..3a19a548 100644 --- a/src/Authoring/Studio/MainFrm.ui +++ b/src/Authoring/Studio/MainFrm.ui @@ -235,6 +235,9 @@ Project palette using Import functionality.</string> <addaction name="actionWireframe"/> </widget> <widget class="QToolBar" name="m_PlaybackToolbar"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="windowTitle"> <string>Playback</string> </property> @@ -252,6 +255,7 @@ Project palette using Import functionality.</string> </attribute> <addaction name="actionPreview"/> <addaction name="actionRemote_Preview"/> + <addaction name="actionFilterVariants"/> </widget> <action name="action_Reference_Manual"> <property name="text"> @@ -771,6 +775,28 @@ Project palette using Import functionality.</string> <string>F5</string> </property> </action> + <action name="actionFilterVariants"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="icon"> + <iconset resource="images.qrc"> + <normaloff>:/images/filter.png</normaloff> + <disabledoff>:/images/filter-disabled.png</disabledoff>:/images/filter.png</iconset> + </property> + <property name="text"> + <string/> + </property> + <property name="toolTip"> + <string>Filter variants (F7)</string> + </property> + <property name="shortcut"> + <string>F7</string> + </property> + </action> <action name="actionSubpresentations"> <property name="text"> <string>Sub-presentations...</string> @@ -842,6 +868,8 @@ Project palette using Import functionality.</string> <property name="icon"> <iconset> <normalon>:/images/remote.png</normalon> + <disabledoff>:/images/remote-disabled.png</disabledoff> + <disabledon>:/images/remote-disabled.png</disabledon> </iconset> </property> <property name="text"> diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp index 5cf47d1f..8b993c75 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp @@ -109,9 +109,9 @@ static std::pair<bool, bool> getSlideCharacteristics(qt3dsdm::Qt3DSDMInstanceHan } InspectorControlModel::InspectorControlModel(VariantsGroupModel *variantsModel, QObject *parent) - : m_variantsModel(variantsModel) - , QAbstractListModel(parent) + : QAbstractListModel(parent) , m_UpdatableEditor(*g_StudioApp.GetCore()->GetDoc()) + , m_variantsModel(variantsModel) { m_modifiedProperty.first = 0; m_modifiedProperty.second = 0; diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp index be8cdbcf..5b4996a1 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp @@ -78,8 +78,6 @@ InspectorControlView::InspectorControlView(const QSize &preferredSize, QWidget * m_variantsGroupModel(new VariantsGroupModel(this)), m_inspectorControlModel(new InspectorControlModel(m_variantsGroupModel, this)), m_meshChooserView(new MeshChooserView(this)), - m_instance(0), - m_handle(0), m_preferredSize(preferredSize) { setResizeMode(QQuickWidget::SizeRootObjectToView); @@ -484,6 +482,8 @@ void InspectorControlView::showTagContextMenu(int x, int y, const QString &group g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants(); g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants(); m_variantsGroupModel->refresh(); + if (g_StudioApp.GetCore()->getProjectFile().variantsDef()[group].m_tags.size() == 0) + g_StudioApp.GetViews()->getMainFrame()->updateActionFilterEnableState(); }); theContextMenu.exec(mapToGlobal({x, y})); @@ -522,6 +522,7 @@ void InspectorControlView::showGroupContextMenu(int x, int y, const QString &gro projectFile.deleteVariantGroup(group); g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants(); g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants(); + g_StudioApp.GetViews()->getMainFrame()->updateActionFilterEnableState(); m_variantsGroupModel->refresh(); }); diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h index 14936b57..c997721a 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h @@ -61,6 +61,7 @@ class InspectorControlView : public QQuickWidget, Q_OBJECT Q_PROPERTY(QString titleText READ titleText NOTIFY titleChanged FINAL) Q_PROPERTY(QString titleIcon READ titleIcon NOTIFY titleChanged FINAL) + public: explicit InspectorControlView(const QSize &preferredSize, QWidget *parent = nullptr); ~InspectorControlView() override; @@ -69,11 +70,14 @@ public: QAbstractItemModel *inspectorControlModel() const; QString titleText() const; - Q_INVOKABLE QColor titleColor(int instance = 0, int handle = 0) const; QString titleIcon() const; + VariantsGroupModel *variantsModel() const { return m_variantsGroupModel; } + Q_INVOKABLE QColor titleColor(int instance = 0, int handle = 0) const; + Q_INVOKABLE QColor showColorDialog(const QColor &color); Q_INVOKABLE void showContextMenu(int x, int y, int handle, int instance); Q_INVOKABLE void showTagContextMenu(int x, int y, const QString &group, const QString &tag); + Q_INVOKABLE void showDataInputChooser(int handle, int instance, const QPoint &point); Q_INVOKABLE void showGroupContextMenu(int x, int y, const QString &group); Q_INVOKABLE QObject *showImageChooser(int handle, int instance, const QPoint &point); Q_INVOKABLE QObject *showFilesChooser(int handle, int instance, const QPoint &point); @@ -81,20 +85,18 @@ public: Q_INVOKABLE QObject *showObjectReference(int handle, int instance, const QPoint &point); Q_INVOKABLE QObject *showMaterialReference(int handle, int instance, const QPoint &point); Q_INVOKABLE QObject *showTextureChooser(int handle, int instance, const QPoint &point); - Q_INVOKABLE void showDataInputChooser(int handle, int instance, const QPoint &point); - Q_INVOKABLE QColor showColorDialog(const QColor &color); Q_INVOKABLE bool toolTipsEnabled(); - Q_INVOKABLE QString convertPathToProjectRoot(const QString &presentationPath); Q_INVOKABLE bool isRefMaterial(int instance) const; - Q_INVOKABLE QString noneString() const; Q_INVOKABLE bool isEditable(int handle) const; + Q_INVOKABLE QString convertPathToProjectRoot(const QString &presentationPath); + Q_INVOKABLE QString noneString() const; // IDataModelListener void OnBeginDataModelNotifications() override; void OnEndDataModelNotifications() override; void OnImmediateRefreshInstanceSingle(qt3dsdm::Qt3DSDMInstanceHandle inInstance) override; void OnImmediateRefreshInstanceMultiple(qt3dsdm::Qt3DSDMInstanceHandle *inInstance, - long inInstanceCount) override; + long inInstanceCount) override; Q_SIGNALS: void titleChanged(); @@ -143,8 +145,8 @@ private: std::vector<Q3DStudio::CFilePath> m_fileList; MouseHelper m_mouseHelper; - int m_instance; - int m_handle; + int m_instance = 0; + int m_handle = 0; QSize m_preferredSize; QColor m_currentColor; diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml index ab0b8db3..6c806aa2 100644 --- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml +++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml @@ -211,7 +211,7 @@ Rectangle { x: -10 width: delegateItem.width height: 25 - color: "#111111" + color: _inspectorGroupHeaderColor StyledLabel { x: 30 @@ -1143,7 +1143,7 @@ Rectangle { Text { text: qsTr("There are no variant tags yet. Click [+ Group] to add a new tags group and start adding tags.") - color: "#ffffff" + color: _textColor visible: _variantsGroupModel.variantsEmpty } @@ -1242,19 +1242,19 @@ Rectangle { id: tagComponent Rectangle { - property bool toggled: tagsModel.selected + property bool toggled: tagsModel ? tagsModel.selected : false property string grpColor: grpModel ? grpModel.color : "" width: Math.max(tLabel.width + 10, 60) height: 25 - color: toggled ? grpColor : "#2e2f30" - border.color: "#959596" + color: toggled ? grpColor : _backgroundColor + border.color: _studioColor4 Text { id: tLabel anchors.centerIn: parent - text: tagsModel.tag - color: toggled ? "#ffffff" : "#959596" + text: tagsModel ? tagsModel.tag : "" + color: toggled ? _textColor : _studioColor4 } MouseArea { diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp index e31a5876..b98aeae0 100644 --- a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp @@ -30,6 +30,8 @@ #include "VariantsTagModel.h" #include "StudioApp.h" #include "Core.h" +#include "Views.h" +#include "MainFrm.h" #include "Qt3DSDMStudioSystem.h" #include "ClientDataModelBridge.h" #include "IDocumentEditor.h" @@ -63,6 +65,11 @@ void VariantsGroupModel::refresh() qt3dsdm::SValue sValue; if (propertySystem->GetInstancePropertyValue(m_instance, m_property, sValue)) { beginResetModel(); + + // delete tag models + for (auto &g : qAsConst(m_data)) + delete g.m_tagsModel; + m_data.clear(); QString propVal = qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)->toQString(); @@ -83,15 +90,13 @@ void VariantsGroupModel::refresh() g.m_title = group; g.m_color = variantsDef[group].m_color; - VariantsTagModel *m = new VariantsTagModel(this); QVector<std::pair<QString, bool> > tags; - for (int i = 0; i < variantsDef[group].m_tags.length(); ++i) + for (int i = 0; i < variantsDef[group].m_tags.length(); ++i) { tags.append({variantsDef[group].m_tags[i], propTags[group].contains(variantsDef[group].m_tags[i])}); + } - m->init(tags); - g.m_tagsModel = m; - + g.m_tagsModel = new VariantsTagModel(tags); m_data.push_back(g); } @@ -160,6 +165,19 @@ void VariantsGroupModel::addNewTag(const QString &group) if (dlg.exec() == QDialog::Accepted) { g_StudioApp.GetCore()->getProjectFile().addVariantTag(group, dlg.getNames().second); refresh(); + + if (g_StudioApp.GetCore()->getProjectFile().variantsDef()[group].m_tags.size() == 1) + g_StudioApp.GetViews()->getMainFrame()->updateActionFilterEnableState(); + } +} + +void VariantsGroupModel::addNewGroup() +{ + VariantTagDialog dlg(VariantTagDialog::AddGroup); + + if (dlg.exec() == QDialog::Accepted) { + g_StudioApp.GetCore()->getProjectFile().addVariantGroup(dlg.getNames().second); + refresh(); } } @@ -208,16 +226,6 @@ void VariantsGroupModel::exportVariants() StudioUtils::commitDomDocumentSave(file, domDoc); } -void VariantsGroupModel::addNewGroup() -{ - VariantTagDialog dlg(VariantTagDialog::AddGroup); - - if (dlg.exec() == QDialog::Accepted) { - g_StudioApp.GetCore()->getProjectFile().addVariantGroup(dlg.getNames().second); - refresh(); - } -} - QHash<int, QByteArray> VariantsGroupModel::roleNames() const { auto names = QAbstractListModel::roleNames(); diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp index 910b4f09..30f33635 100644 --- a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp +++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp @@ -28,17 +28,13 @@ #include "VariantsTagModel.h" -VariantsTagModel::VariantsTagModel(QObject *parent) +VariantsTagModel::VariantsTagModel(const QVector<std::pair<QString, bool> > &data, QObject *parent) : QAbstractListModel(parent) + , m_data(data) { } -void VariantsTagModel::init(const QVector<std::pair<QString, bool> > &data) -{ - m_data = data; -} - void VariantsTagModel::updateTagState(const QString &tag, bool selected) { for (auto &t : m_data) { diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h index 01bb4e73..392de760 100644 --- a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h +++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h @@ -36,7 +36,8 @@ class VariantsTagModel : public QAbstractListModel Q_OBJECT public: - explicit VariantsTagModel(QObject *parent = nullptr); + explicit VariantsTagModel(const QVector<std::pair<QString, bool> > &data, + QObject *parent = nullptr); enum Roles { TagRole = Qt::UserRole + 1, @@ -48,7 +49,6 @@ public: Qt::ItemFlags flags(const QModelIndex& index) const override; - void init(const QVector<std::pair<QString, bool> > &data); void updateTagState(const QString &tag, bool selected); QString serialize(const QString &groupName) const; diff --git a/src/Authoring/Studio/PreviewHelper.cpp b/src/Authoring/Studio/PreviewHelper.cpp index 18bc6223..ef029ca7 100644 --- a/src/Authoring/Studio/PreviewHelper.cpp +++ b/src/Authoring/Studio/PreviewHelper.cpp @@ -36,6 +36,8 @@ #include "StudioPreferences.h" #include "StudioProjectSettings.h" #include "Core.h" +#include "Views.h" +#include "MainFrm.h" #include "Qt3DSFileTools.h" #include <QtWidgets/qinputdialog.h> @@ -203,7 +205,13 @@ void CPreviewHelper::DoPreviewViaConfig(Q3DStudio::CBuildConfiguration * /*inSel delete connection; cleanupProcess(p, pDocStr); }); - p->start(theCommandStr, { *pDocStr }); + + QStringList args {*pDocStr}; + QString variantsArg = g_StudioApp.GetViews()->getMainFrame()->getVariantsFilterStr(); + if (!variantsArg.isEmpty()) + args << "-v" << variantsArg; + + p->start(theCommandStr, args); if (!p->waitForStarted()) { QMessageBox::critical(nullptr, QObject::tr("Error Launching Viewer"), diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro index 86103a2c..3d35ad58 100644 --- a/src/Authoring/Studio/Qt3DStudio.pro +++ b/src/Authoring/Studio/Qt3DStudio.pro @@ -229,7 +229,9 @@ HEADERS += \ Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.h \ Palettes/Inspector/VariantsGroupModel.h \ Palettes/Inspector/VariantsTagModel.h \ - Palettes/Inspector/VariantTagDialog.h + Palettes/Inspector/VariantTagDialog.h \ + Application/FilterVariantsDlg.h \ + Application/FilterVariantsModel.h FORMS += \ MainFrm.ui \ @@ -409,7 +411,9 @@ SOURCES += \ Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.cpp \ Palettes/Inspector/VariantsGroupModel.cpp \ Palettes/Inspector/VariantsTagModel.cpp \ - Palettes/Inspector/VariantTagDialog.cpp + Palettes/Inspector/VariantTagDialog.cpp \ + Application/FilterVariantsDlg.cpp \ + Application/FilterVariantsModel.cpp RESOURCES += \ MainFrm.qrc \ diff --git a/src/Authoring/Studio/images.qrc b/src/Authoring/Studio/images.qrc index 0c6e16f5..3e1e4192 100644 --- a/src/Authoring/Studio/images.qrc +++ b/src/Authoring/Studio/images.qrc @@ -309,6 +309,12 @@ <file>images/Keyframe-Property-Selected@2x.png</file> <file>images/Keyframe-Property-Normal@2x.png</file> <file>images/Keyframe-Property-Disabled@2x.png</file> + <file>images/filter.png</file> + <file>images/filter@2x.png</file> + <file>images/filter-disabled.png</file> + <file>images/filter-disabled@2x.png</file> + <file>images/playback-variant@2x.png</file> + <file>images/playplayback-variant.png</file> </qresource> <qresource prefix="/startup"> <file alias="open_dialog.png">images/open_dialog.png</file> diff --git a/src/Authoring/Studio/images/filter-disabled.png b/src/Authoring/Studio/images/filter-disabled.png Binary files differnew file mode 100644 index 00000000..019184cd --- /dev/null +++ b/src/Authoring/Studio/images/filter-disabled.png diff --git a/src/Authoring/Studio/images/filter-disabled@2x.png b/src/Authoring/Studio/images/filter-disabled@2x.png Binary files differnew file mode 100644 index 00000000..00a5040a --- /dev/null +++ b/src/Authoring/Studio/images/filter-disabled@2x.png diff --git a/src/Authoring/Studio/images/filter.png b/src/Authoring/Studio/images/filter.png Binary files differnew file mode 100644 index 00000000..e1c04006 --- /dev/null +++ b/src/Authoring/Studio/images/filter.png diff --git a/src/Authoring/Studio/images/filter@2x.png b/src/Authoring/Studio/images/filter@2x.png Binary files differnew file mode 100644 index 00000000..f01cbab7 --- /dev/null +++ b/src/Authoring/Studio/images/filter@2x.png diff --git a/src/Authoring/Studio/images/playback-variant@2x.png b/src/Authoring/Studio/images/playback-variant@2x.png Binary files differnew file mode 100644 index 00000000..ae5a9534 --- /dev/null +++ b/src/Authoring/Studio/images/playback-variant@2x.png diff --git a/src/Authoring/Studio/images/playback_tools_low-02.png b/src/Authoring/Studio/images/playback_tools_low-02.png Binary files differindex 471b2573..c4effffc 100644 --- a/src/Authoring/Studio/images/playback_tools_low-02.png +++ b/src/Authoring/Studio/images/playback_tools_low-02.png diff --git a/src/Authoring/Studio/images/playback_tools_low-02@2x.png b/src/Authoring/Studio/images/playback_tools_low-02@2x.png Binary files differindex 02370d25..7713f19f 100644 --- a/src/Authoring/Studio/images/playback_tools_low-02@2x.png +++ b/src/Authoring/Studio/images/playback_tools_low-02@2x.png diff --git a/src/Authoring/Studio/images/playback_tools_low-03.png b/src/Authoring/Studio/images/playback_tools_low-03.png Binary files differindex 5c5f9018..9c647a4e 100644 --- a/src/Authoring/Studio/images/playback_tools_low-03.png +++ b/src/Authoring/Studio/images/playback_tools_low-03.png diff --git a/src/Authoring/Studio/images/playback_tools_low-03@2x.png b/src/Authoring/Studio/images/playback_tools_low-03@2x.png Binary files differindex e6fe8e10..d2a02f2a 100644 --- a/src/Authoring/Studio/images/playback_tools_low-03@2x.png +++ b/src/Authoring/Studio/images/playback_tools_low-03@2x.png diff --git a/src/Authoring/Studio/images/playplayback-variant.png b/src/Authoring/Studio/images/playplayback-variant.png Binary files differnew file mode 100644 index 00000000..62c3e2ff --- /dev/null +++ b/src/Authoring/Studio/images/playplayback-variant.png diff --git a/src/Authoring/Studio/images/remote-disabled.png b/src/Authoring/Studio/images/remote-disabled.png Binary files differindex a5d7553c..0da8dac9 100644 --- a/src/Authoring/Studio/images/remote-disabled.png +++ b/src/Authoring/Studio/images/remote-disabled.png diff --git a/src/Authoring/Studio/images/remote-disabled@2x.png b/src/Authoring/Studio/images/remote-disabled@2x.png Binary files differindex b7d95c41..dba26e55 100644 --- a/src/Authoring/Studio/images/remote-disabled@2x.png +++ b/src/Authoring/Studio/images/remote-disabled@2x.png diff --git a/src/Authoring/Studio/images/remote.png b/src/Authoring/Studio/images/remote.png Binary files differindex 83b44b84..70e10906 100644 --- a/src/Authoring/Studio/images/remote.png +++ b/src/Authoring/Studio/images/remote.png diff --git a/src/Authoring/Studio/images/remote@2x.png b/src/Authoring/Studio/images/remote@2x.png Binary files differindex fd06be49..21f48873 100644 --- a/src/Authoring/Studio/images/remote@2x.png +++ b/src/Authoring/Studio/images/remote@2x.png diff --git a/src/Authoring/Studio/qml.qrc b/src/Authoring/Studio/qml.qrc index ac1348f0..09d5451f 100644 --- a/src/Authoring/Studio/qml.qrc +++ b/src/Authoring/Studio/qml.qrc @@ -42,5 +42,6 @@ <file>Palettes/Action/HandlerBaseMultilineText.qml</file> <file>Palettes/Action/HandlerGenericFloat.qml</file> <file>Palettes/Inspector/MaterialDropDown.qml</file> + <file>Application/FilterVariantsDlg.qml</file> </qresource> </RCC> diff --git a/src/Authoring/Studio/style.qss b/src/Authoring/Studio/style.qss index e26785c0..3fd39920 100644 --- a/src/Authoring/Studio/style.qss +++ b/src/Authoring/Studio/style.qss @@ -150,6 +150,19 @@ QToolButton:checked, QToolButton:hover { background-color: #262829; } +QToolButton#actionFilterVariants:checked { + min-width: 22px; + max-width: 22px; + min-height: 22px; + max-height: 22px; + background-color: #2e2f30; + border-color: #727476; + border-width: 1px; + border-top-style: solid; + border-right-style: solid; + border-left-style: solid; +} + QToolButton:pressed:!checked { min-width: 22px; max-width: 22px; |